Closed stlehmann closed 2 years ago
This is actually in the docs:
I've used this to read single plc variables from an array before.
I just tried again now by looping through an array and pyads seems to have no trouble reading this. TwinCAT 4024.10 python 3.6.
I've just run though a range of scenarios to try and replicate the error.
I don't think its a case of trying to access an item that is not in the array (e.g. wrong range in example) as if you do that you get the following error:
Or the wrong symbol/variable name as then you get:
Or the wrong pyads plc datatype:
I noticed the user is using python 3.9, I'll have to download that to give it a go, but this seems to be an ADS error. But I can't replicate it and not sure what "invalid parameter value" means.
@chrisbeardy Thanks for trying to replicate this error. I just finally got my TwinCAT up and running on Windows 10 and gave it a try with an array of integers and an array of structs. Both worked well enough.
I also noticed, looking at the variable names in the example ".stLogErrorArray". This must be a TwinCat 2 System. As TwinCat 2 Global vars can be address with just the .
at the fron whereas TC3 needs the full name. Maybe this is a TC2 issue with arrays.
Thanks @chrisbeardy. I encouraged the original questioneer to join this Github discussion. Also I will give him a short note that it might be related to TwinCAT2.
Hi
I am the questioneer and i can give you some more details. It's correct that i use TwinCat2 with a CX5010-0111 which is running with a Windows Embedded CE 6 and TwinCAT-2-PLC-Runtime. My notebook is running with Windows 10.
Every array position includes a struct with a timestamp (type DT) and an error (type string). The array is 201 elements long (0..200) and is from type VAR_GLOBAL RETAIN PERSISTENT. I made several tests. With array dimensions < 43 elements (0..41), everything is working correct and no error occure. But if the array is >= 43 elements (0..42 and higher) the exception occured. The exception occured everytime 17 elements before the end of the array and it occured only at the string-elements. I can read the DT-elements up to element 200 without an exception.
As a test i tried to read a region of the array. If i read the elements 180..185 of an array[0..200] the error occure at element 183 as well.
I asked the Beckhoff Support Switzerland if something is wrong with my code or if they have an idea, what the problem could be. They could not found a problem in the PLC-code and told me it must be a problem with pyads.
I made a small test project. You can find it in the zip-file below. (python-script and TwinCat-project) ADS_Test.zip
I hope I could give some information to narrow down the error.
Hi, @mfischlin, thanks for posting.
I have not managed to try your exact code as I do not have TwinCat2, however I tried to replicate with TC3 as best as possible did not manage to get any errors.
I know this does not solve the problem, but is it possible to circumvent the issue by reading the whole structure array and then iterating over the it in python to append what you want.
e.g.
structure_def = (
("tErrortime", pyads.PLCTYPE_DT, 1),
("sErrorString", pyads.PLCTYPE_STRING, 1),
)
error_dict = plc.read_structure_by_name(".stLogErrorArray", structure_def, array_size=201)
for i in range(minRange,maxRange):
error_time = error_dict....
error_string = error_dict...
sArrPos_Time.append(error_time)
sArrPos_Text.append(error_string)
The format you would get back is an OrderedDict of OrderedDicts. This can esaaily be converted to normal dictionaries by using the json module error_dict = json.loads(json.dumps(error_dict ))
Depending on the PLC code requirments, sometimes I actually invert it so I have a structure of arrays, then it comes back a bit nicer into python, as you have a dictionary of arrays or errors so can iterate over them more easily.
Differecnces are in this example I have from somewhere else:
import pyads
import json
single_struct_def = (
("timestamp", pyads.PLCTYPE_STRING, 1),
("force", pyads.PLCTYPE_REAL, 1),
("pos", pyads.PLCTYPE_REAL, 1),
("someInt", pyads.PLCTYPE_INT, 1),
("aBool", pyads.PLCTYPE_BOOL, 1),
)
size_of_single = pyads.size_of_structure(single_struct_def)
array_struct_def = (
("timestamp", pyads.PLCTYPE_STRING, 11),
("force", pyads.PLCTYPE_REAL, 11),
("pos", pyads.PLCTYPE_REAL, 11),
("someInt", pyads.PLCTYPE_INT, 11),
("aBool", pyads.PLCTYPE_BOOL, 11),
)
size_of_array = pyads.size_of_structure(array_struct_def)
def main():
plc = pyads.Connection("169.254.198.195.1.1", 851)
plc.open()
array_of_struct = plc.read_structure_by_name("DATALOG.arrayOfStruct", single_struct_def, array_size=11,
structure_size=size_of_single * 11)
struct_of_array = plc.read_structure_by_name("DATALOG.structOfArray", array_struct_def,
structure_size=size_of_array)
plc.close()
print(array_of_struct)
print(struct_of_array)
array_of_struct = json.loads(json.dumps(array_of_struct)) # using json because of nested ordered dicts
print(array_of_struct)
struct_of_array = dict(struct_of_array)
print(struct_of_array)
if __name__ == '__main__':
main()
Thank you for your help @chrisbeardy. I will read the structure array like you describe.
Thank you for your help @chrisbeardy. I will read the structure array like you describe.
That's ok 😁 I hope it works out ok for you.
This issue was reported by mail to me. It seems that it is possible to address array elements with
read_by_name
directly. I honestly didn' t know this works. Also I don't know if it makes sense because it increases the traffic if you read all members of an array separately instead of reading the whole array at once.This will lead to the following error:
I couldn't verfify this issue myself because I currently got other issues with TwinCAT but will try to do so soon. Any thoughts?