bnjmnp / pysoem

Cython wrapper for the Simple Open EtherCAT Master Library
MIT License
101 stars 37 forks source link

CIA 402 engine #33

Closed bolp70 closed 1 year ago

bolp70 commented 3 years ago

Hi, i am using your library to communicate with a CIA 402 type engine. I can communicate with, retrieve the encoder value. But impossible to make it turn. I think we should use processdata but I don't quite understand the principle.

Do you have an example of an engine or a bit of time to help me?

bnjmnp commented 3 years ago

Hi @bolp70,

take a look at issue #30, I guess reading through this will get you a bit further. The TMCM-1617 and TMCM-3213 discussed there also implement the CiA 402 device profile.

bolp70 commented 3 years ago

Hi bnjmnp, thank you for your help. This is the program I am using. In fact, I do not understand the principle of Rx.PDO and Tx.PDO well. How to switch from TxPD1 and RxPD1 (0x1600 0x1A00) to TxPD2 and RxPD2 (0x1601 0x1A01)? I attach you the modified program, the XML of the engine, and the config recover it with -map

By giving a speed and in operation mode 2, the motor runs but I don't think it uses the PDO.

Le lun. 3 mai 2021 à 22:48, bnjmnp @.***> a écrit :

Hi @bolp70 https://github.com/bolp70,

take a look at issue #30 https://github.com/bnjmnp/pysoem/issues/30, I guess reading through this will get you a bit further. The TMCM-1617 and TMCM-3213 discussed there also implement the CiA 402 device profile.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bnjmnp/pysoem/issues/33#issuecomment-831524179, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQJ7TTIDDLD3YEK2Z2LHTETTL4D2PANCNFSM44AH4ODQ .

bnjmnp commented 3 years ago

Sorry I didn't get you attachment. You can attach files if you answer directly on GitHub (at issue https://github.com/bnjmnp/pysoem/issues/33).

The TMCM-1617 from my example has only RxPD1 and TxPD1, so the PDO selection object 0x1C12 and 0x1C13 is fixed (to 0x1600 and 0x1A00).

It seems that you can select other PDO configurations, thus you can write for example 0x1601 into subindex 1 of object 0x1C12. In one of the examples you can see how to do this for a Beckhoff device: https://github.com/bnjmnp/pysoem/blob/7dbc6c2aec9f26c7cff911c3aeef0fc73f6c71cc/examples/minimal_example.py#L31

There I set 0x1C12 to 0. With that I don't have any RxPDO as I don't want to send any commands to the device in this example.

Note: It is really the best to update 0x1C12/0x1C13 in these setup-functions.

In your code you could try something like this:

        map_1c12_bytes = struct.pack('BxH', 1, 0x1601)
        slave.sdo_write(0x1c12, 0, map_1c12_bytes, True)

        map_1c13_bytes = struct.pack('BxH', 1, 0x1A01)
        slave.sdo_write(0x1c13, 0, map_1c13_bytes, True)

These SDO-writes update subindex 0 and subindex 1 at the same time.

bnjmnp commented 3 years ago

Hi @bolp70,

were you able to solve this?

bolp70 commented 3 years ago

Hi bnjmnp, I went on a trip I will come back to June I will keep you posted.

Le sam. 29 mai 2021 à 16:00, bnjmnp @.***> a écrit :

Hi @bolp70 https://github.com/bolp70,

were you able to solve this?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bnjmnp/pysoem/issues/33#issuecomment-850838341, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQJ7TTNTL67XQYIO6Y6DB4LTQDXPXANCNFSM44AH4ODQ .

bolp70 commented 3 years ago

hi bnjmnp I tried with your code, it works. As you can see I am using PDO RTx 2. It seems to me that we can use several PDOs at the same time?

map_1c13_bytes = struct.pack('BxH', 1, 0x1A00) slave.sdo_write(0x1c13, 0, map_1c13_bytes, True) to map_1c13_bytes = struct.pack('BxH', 1, 0x1A01) slave.sdo_write(0x1c13, 1, map_1c13_bytes, True)

if i do this, how does it work for class InputPdo and class OutputPdo ?


class InputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        # PDO_0 0x1A00
        #('Position_actual_value', ctypes.c_int32),
        #('digital_input', ctypes.c_uint32),
        #('statusword', ctypes.c_uint16),

        # PDO_0 0x1A01
         ('Position_actual_value', ctypes.c_int32),
         ('velocity_actual_consigne', ctypes.c_int32),
         ('couple_actual_consigne', ctypes.c_int16),
         ('statusword', ctypes.c_uint16),

    ]

class OutputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        # PDO_0 0x1600
        #('Axe_target_position', ctypes.c_int32),
        #('digital_output', ctypes.c_uint32),
        #('controlword', ctypes.c_uint16),

        # PDO_0 0x1601
         ('Axe_target_velocity', ctypes.c_int32),
         ('controlword', ctypes.c_uint16),

    ]

def convert_input_data(data):
    return InputPdo.from_buffer_copy(data)

class BasicExample:

    ZERRO_DRIVER_ID = 0x5a65726f #id du fabricant 
    axes = 0x00029252 #id des moteur 
    EL1259_PRODUCT_CODE = 0x04eb3052

    def __init__(self, ifname):
        self._ifname = "enp3s0"
        self._pd_thread_stop_event = threading.Event()
        self._ch_thread_stop_event = threading.Event()
        self._actual_wkc = 0
        self._master = pysoem.Master()
        self._master.in_op = False
        self._master.do_check_state = False
        SlaveSet = namedtuple('SlaveSet', 'name product_code config_func')
        self._expected_slave_layout = {0: SlaveSet('Axe1', self.axes, self.axes_setup),
                                       1: SlaveSet('Axe2', self.axes, self.axes_setup),
                                       2: SlaveSet('Axe3', self.axes, self.axes_setup),
                                       3: SlaveSet('Axe4', self.axes, self.axes_setup),
                                       4: SlaveSet('Axe5', self.axes, self.axes_setup),
                                       5: SlaveSet('Axe6', self.axes, self.axes_setup)}
                                       #2: SlaveSet('EL1259', self.EL1259_PRODUCT_CODE, self.axes_setup)

    def axes_setup(self, slave_pos):
        slave = self._master.slaves[slave_pos]

        map_1c12_bytes = struct.pack('BxH', 1, 0x1601)
        slave.sdo_write(0x1c12, 0, map_1c12_bytes, True)

        map_1c13_bytes = struct.pack('BxH', 1, 0x1A01)
        slave.sdo_write(0x1c13, 0, map_1c13_bytes, True)

thank you for your help

bnjmnp commented 3 years ago

Hi @bolp70 ,

I'm not 100% sure what you like to do. But if you want to select 0x1A00 and 0x1A01 in 0x1C13 you need to do it this way:

map_1c13_bytes = struct.pack('BxHH', 1, 0x1A00, 0x1A01)
slave.sdo_write(0x1c13, 0, map_1c13_bytes, True)

It is just one write to 0x1c13. Note it is now 'BxHH' instead of 'BxH'.

I don't know how your ESI looks but from your input you could do something like this (for the InputPdo):

class InputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        # PDO_0 0x1A00
        ('Position_actual_value_DUMMY', ctypes.c_int32),
        ('digital_input', ctypes.c_uint32),
        ('statusword_DUMMY', ctypes.c_uint16),

        # PDO_0 0x1A01
         ('Position_actual_value', ctypes.c_int32),
         ('velocity_actual_consigne', ctypes.c_int32),
         ('couple_actual_consigne', ctypes.c_int16),
         ('statusword', ctypes.c_uint16),

    ]

Problem here is that you have names twice, but you could give each a unique name like I did above (notice the statusword_DUMMY).

Second option would be nested "Structures".

class InputPdo0x1A00(ctypes.Structure)
    _pack_ = 1
    _fields_ = [
        # PDO_0 0x1A00
        ('Position_actual_value', ctypes.c_int32),
        ('digital_input', ctypes.c_uint32),
        ('statusword', ctypes.c_uint16),
    ]

class InputPdo0x1A01(ctypes.Structure)
    _pack_ = 1
    _fields_ = [
        # PDO_0 0x1A01
         ('Position_actual_value', ctypes.c_int32),
         ('velocity_actual_consigne', ctypes.c_int32),
         ('couple_actual_consigne', ctypes.c_int16),
         ('statusword', ctypes.c_uint16),
    ]

class InputPdo(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('pdo_0', InputPdo0x1A00),
        ('pdo_1', InputPdo0x1A01),
    ]

And access the elements like this:

input = InputPdo.from_buffer_copy(slave.input)
print(input.pdo_0.Position_actual_value)
print(input.pdo_1.velocity_actual_consigne)

But I did not test this.

bnjmnp commented 3 years ago

Hi @bolp70, did you had any success with the project you were working on here? I would be happy to hear.

bnjmnp commented 1 year ago

Closed due to inactivity of the OP.