Closed Michaelicious closed 7 months ago
I'm trying to read/write SDO's. can find a documentation on the proper way to initialize a network.
One (proper) way of initializing a network is showcased in the examples/basic_example.py, look for the run()
function in there.
The cause for the SdoInfoError
, I don't understand for now, but maybe you don't need it at all. Did you try to add a little delay (via time.sleep()
) between config_dc()
and config_map()
to get rid of the ConfigMapError
?
Coming to the sdo_read()
, you probably need to do the unpack like this:
sdo_decode = struct.unpack('b', sdo)
Object 0x6060
is probably just a two byte integer (SINT) therefore you need the b
as format character. (You also mixed up you code with 0x6040 a bit)
Did you also read through the Reading and Writing CoE Objects section in the readthedocs documentation?
- What's master.send_processdata() and master.recieve_processdata() ? how to use them ?
master.send_processdata()
is used to send the PDO EtherCAT frame (that contains output PDO data) into the network, and master.recieve_processdata()
is used to wait for frame to return (and it copies the input PDO data into a buffer). Check out this video https://youtu.be/z2OagcHG-UU?si=0f4zRq4R60QrrOFI, master.send_processdata()
makes the "telegram" leave the master, and master.recieve_processdata()
collects the retuning "telegram".
- And what's up with the 4 bit error ? how do I verify I decoded the frame correctly ?
This is about the 4 byte error, we might have already solved with the b
as format character?
- Is there a way to upload an SDO map XML file ?
No. But I admit it would be nice if reading-in the object directory from the XML file would be possible, to reduce the trouble converting bytes returned by sdo_read()
to a equivalent Python data type.
If you are about to operate a servo drive, check out #89 there I point to other issues that should contain valuable information and reference code.
Thank you for your quick response, you helped me a lot.
SdoInfoError
error was due to my slave wasn't working with CIA 402 apparently. once I switched to other type of slave, it worked and i got the slave.od
Another question, how could I verify connection if I'm working in a ring topography ? (Master will be connected to slave 's 1 input, and slave's N output ). My only plan currently is to open both interfaces, doing dc_config() and hope it will get it by itself - verifying with wireshark. Is there something i've missed ? @bnjmnp
Sharing in case it will help anyone. for helping out with SDO decoding, based on read_sdo_info.py, i've created custom read/write functions on a customSlave class.
from ecat_helpers import _convert_to_binary, _convert_from_binary
from ethercat_helpers import _convert_to_binary, _convert_from_binary
class customSlave():
def __init__(self,slave, slave_pos = None):
self.my_slave = slave
self.slave_pos = slave_pos #Probably not needed
self.my_od = {}
def _getObjectDictionary(self,try_count=0):
self.my_od = {}
try:
temp_od = self.my_slave.od
print('OD Found')
except pysoem.SdoInfoError as e:
if try_count < 10:
print(f'SdoInfoError {try_count}:\t{e}')
try_count += 1
self._getObjectDictionary(try_count)
else:
print(self.my_slave.name+'Creating OD')
for obj in temp_od:
self.my_od[obj.index] = obj
print(self.my_slave.name+'OD Created')
def _sdo_data_from_od(self,index,subindex):
if not self.my_od:
self._getObjectDictionary()
coe_obj = self.my_od[index]
if coe_obj.entries :
data_type = coe_obj.entries[subindex].data_type
bit_length = coe_obj.entries[subindex].bit_length
else :
data_type = coe_obj.data_type
bit_length = coe_obj.bit_length
return data_type, bit_length
def readSDO(self,index,subindex): # Read & Decode SDO from slave
sdo = self.my_slave.sdo_read(index,subindex)
# data from dictionary for decoding
data_type, bit_length = self._sdo_data_from_od(index,subindex)
return _convert_from_binary(sdo,data_type,bit_length)
def writeSDO(self,index,subindex,value): # Decode & Write SDO to slave
# data from dictionary for decoding
data_type, bit_length = self._sdo_data_from_od(index,subindex)
# data to binary
binary_data = _convert_to_binary(value,data_type,bit_length)
# Write SDO
try:
self.my_slave.sdo_write(index,subindex,binary_data)
except pysoem.SdoError: print('SDO write error')
else: print(f'SDO ({index},{subindex}) wrote {value} successfuly')
than I'm using following functions from ethercat_helpers.py to make read & write more easy.
import ctypes
def _choose_ctypes_object(data_type, bitsize):
""" Returns a ctypes object based on the data type and bitsize from slave.od
dataType Ctype object
1 only 2 sync object subindexes 32
2 INT8
3 INT16
4 DINT / INT32
5 UINT8
6 UINT16
7 UINT32
8 None has been found
9 String / c_char_p
32 has enteries
42 has enteries
"""
data_type = int(data_type)
bitsize = int(bitsize)
match (data_type, bitsize):
case (2, 8): # INT8
return ctypes.c_int8
case (3, 16): # INT16
return ctypes.c_int16
case (4, 32): # DINT / INT32
return ctypes.c_int32
case (5, 8): # UINT8
return ctypes.c_uint8
case (6, 16): # UINT16
return ctypes.c_uint16
case (7, 32): # UDINT
return ctypes.c_uint32
case (9, _): # VISIBLE_STRING
return ctypes.c_char_p
case _:
raise ValueError("Unsupported data type or bitsize")
def _convert_from_binary(binary_data, data_type, bitsize):
ctypes_type = _choose_ctypes_object(data_type, bitsize)
if (data_type != 9): data = ctypes_type.from_buffer_copy(binary_data).value
else: data = ctypes_type(binary_data).value.decode() # Decode getting rid of b'...'
return data
def _convert_to_binary(data, data_type, bitsize):
ctypes_type = _choose_ctypes_object(data_type, bitsize)
binary_data = bytes(ctypes_type(data))
return binary_data
I'm having 2 issues:
I'm trying to read/write SDO's. can find a documentation on the proper way to initialize a network.
raises
SdoInfoError: Sdo List Info read failed
due tood = master.slaves[0].od
Without calling OD, Sometimes
master.config_map()
raisesConfigMapError: [MailboxError(1, 19, 'Unknown'), MailboxError(1, 19, 'Unknown'), MailboxError(1, 19, 'Unknown'), ...
Hard reboot of the slave solves the ConfigMapError, and I'm able to read an SDO as following:
output:
so
sdo_decode
is after converting from bytes. BUT ITS AN ETHERNET FRAME.master.send_processdata()
andmaster.recieve_processdata()
? how to use them ?write_sdo()
in my case ? (since none of the examples addresses the 4 bit buffer error )I'm stuck on it for days now, I would love some brief explanation on setting up an eCat network properly. Help would be very helpful.