bnjmnp / pysoem

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

the return of config_map() and send_overlap_processdata() #54

Closed tom9672 closed 2 years ago

tom9672 commented 2 years ago

Hi @bnjmnp , config_map(): return IO map size (sum of all PDO in an out data). Does that mean it returns the count of pdo mapping? but it returns me the same number, after i sdo_write to 1601-1603 and 1A01-1A03, cuz i only need to use 1600 and 1A00. I do the sdo_write in the config_func

def dev3_config_func(slave_pos):
    dev3.sdo_write(0x6083,0x0,bytes(ctypes.c_uint32(100000)))
    dev3.sdo_write(0x6084,0x0,bytes(ctypes.c_uint32(100000)))
    dev3.sdo_write(0x607F,0x0,bytes(ctypes.c_uint32(500000)))
    dev3.sdo_write(0x6080,0x0,bytes(ctypes.c_uint32(3000)))
    # not use pdos
    dev3.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))

dev1.config_func = dev1_config_func
dev2.config_func = dev2_config_func
dev3.config_func = dev3_config_func

print(master.config_map())

I know write pdos need to be done in pre op state. so i also tried to do

if master.state_check(pysoem.PREOP_STATE, 50_000) == pysoem.PREOP_STATE:
    dev1.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))

else:
    print('no in pre op')
dev1.config_func = dev1_config_func
dev2.config_func = dev2_config_func
dev3.config_func = dev3_config_func

master.config_map()

the return of master.config_map() is always 144, and the send_overlap_processdata() is always 172. My purpose is to reduce the pdo data in every send and receive process. Do you have any suggestions

tom9672 commented 2 years ago

BTW, the 'sum of all pdo in an out data' mean the count of pdos or the byte of pdo? and how to get the sum of pdo in an in data. In the above code, Is the way of disable the tpdos and rpdos right?

tom9672 commented 2 years ago

I have this issue because, I have a motor, it runs well on twincat3, but the status word often changed from 4663 to 568 in while running, as a result it stops.

my whole code of this test:

from turtle import pd
import pysoem
import ctypes
import time
from JASD_PDO_conf import OutputPdo
from JASD_PDO_conf import InputPdo

modes_of_operation = {
    'No mode': 0,
    'Profile position mode': 1,
    'Velocity mode':2,
    'Profile velocity mode': 3,
    'Homing mode': 6,
    'Cyclic synchronous position mode': 8,
    'Cyclic synchronous velocity mode': 9,
    'Cyclic synchronous torque mode': 10,
}

master = pysoem.Master()
master.open('\\Device\\NPF_{267091CF-E38D-4EED-AAC8-1A0692194D59}') 
master.config_init()
dev1 = master.slaves[0]
# dev2 = master.slaves[1]
# dev3 = master.slaves[2]

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

def dev1_config_func(slave_pos):
    dev1.sdo_write(0x6083,0x0,bytes(ctypes.c_uint32(100000)))
    dev1.sdo_write(0x6084,0x0,bytes(ctypes.c_uint32(100000)))
    # dev1.sdo_write(0x6060,0x0,bytes(ctypes.c_int8(1)))
    dev1.sdo_write(0x607F,0x0,bytes(ctypes.c_uint32(500000)))
    dev1.sdo_write(0x6080,0x0,bytes(ctypes.c_uint32(3000)))
    dev1.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))

    dev1.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev1.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))

def dev2_config_func(slave_pos):
    dev2.sdo_write(0x6083,0x0,bytes(ctypes.c_uint32(100000)))
    dev2.sdo_write(0x6084,0x0,bytes(ctypes.c_uint32(100000)))
    # dev1.sdo_write(0x6060,0x0,bytes(ctypes.c_int8(1)))
    dev2.sdo_write(0x607F,0x0,bytes(ctypes.c_uint32(500000)))
    dev2.sdo_write(0x6080,0x0,bytes(ctypes.c_uint32(3000)))
    dev2.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))

    dev2.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev2.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))
def dev3_config_func(slave_pos):
    dev3.sdo_write(0x6083,0x0,bytes(ctypes.c_uint32(100000)))
    dev3.sdo_write(0x6084,0x0,bytes(ctypes.c_uint32(100000)))
    # dev1.sdo_write(0x6060,0x0,bytes(ctypes.c_int8(1)))
    dev3.sdo_write(0x607F,0x0,bytes(ctypes.c_uint32(500000)))
    dev3.sdo_write(0x6080,0x0,bytes(ctypes.c_uint32(3000)))
    dev3.sdo_write(0x1601,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1602,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1603,0x0,bytes(ctypes.c_uint16(0)))

    dev3.sdo_write(0x1A01,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A02,0x0,bytes(ctypes.c_uint16(0)))
    dev3.sdo_write(0x1A03,0x0,bytes(ctypes.c_uint16(0)))

dev1.config_func = dev1_config_func
# dev2.config_func = dev2_config_func
# dev3.config_func = dev3_config_func

master.config_map()

def pdo_process():
    master.send_processdata()
    master.receive_processdata(1_000)
    time.sleep(0.01)

if master.state_check(pysoem.SAFEOP_STATE, 50_000) == pysoem.SAFEOP_STATE:
    master.state = pysoem.OP_STATE
    master.send_processdata()
    master.receive_processdata(1_000)
    master.write_state()
    master.state_check(pysoem.OP_STATE, 5_000_000)
    if master.state == pysoem.OP_STATE:
        output_data = OutputPdo()
        # init
        output_data.Control_Word = 15
        dev1.output = bytes(output_data) 
        # dev2.output = bytes(output_data) 
        # dev3.output = bytes(output_data) 
        pdo_process()
        # set mode
        output_data.Mode_Operation = 1
        dev1.output = bytes(output_data) 
        # dev2.output = bytes(output_data) 
        # dev3.output = bytes(output_data) 
        pdo_process()
    else:
        print('failed to got to op state')
else:
    print('failed to got to safeop state')

def pp_relavite(device,output_data,target_pos,speed):
    device.sdo_write(0x6081,0x0, bytes(ctypes.c_uint32(speed)))

    output_data.Target_Position = target_pos
    device.output = bytes(output_data) 
    pdo_process()

    output_data.Control_Word = 95
    device.output = bytes(output_data) 
    pdo_process()

    output_data.Control_Word =79
    device.output = bytes(output_data) 
    pdo_process()

    # convert_input_data(device.input).Status_word != 1591
    curr_pos = convert_input_data(device.input).actual_position
    while convert_input_data(device.input).actual_position not in range(curr_pos+target_pos-100,curr_pos+target_pos+100):
        pdo_process()
        #print(convert_input_data(device.input).Status_word)

def pp_absolute(device,output_data,target_pos,speed):
    device.sdo_write(0x6081,0x0, bytes(ctypes.c_uint32(speed)))

    output_data.Target_Position = target_pos
    device.output = bytes(output_data)
    pdo_process()

    output_data.Control_Word = 31
    device.output = bytes(output_data) 
    pdo_process()

    output_data.Control_Word = 15
    device.output = bytes(output_data) 
    pdo_process()

    # convert_input_data(device.input).Status_word != 1591
    while convert_input_data(device.input).actual_position not in range(target_pos-100,target_pos+100):
         pdo_process()
         #print(convert_input_data(device.input).Status_word)

try:
    for i in range(50):
        pp_relavite(dev1,output_data,100000,200000)
        # pp_relavite(dev2,output_data,100000,200000)
        # pp_relavite(dev3,output_data,100000,200000)
        pp_absolute(dev1,output_data,0,200000)
        # pp_absolute(dev2,output_data,0,200000)
        # pp_absolute(dev3,output_data,0,200000)

except KeyboardInterrupt:
    print('stopped')

dev1.output = bytes(len(dev1.output)) 
# dev2.output = bytes(len(dev2.output)) 
# dev3.output = bytes(len(dev2.output)) 
master.send_processdata()
master.receive_processdata(1_000)
master.state = pysoem.PREOP_STATE
master.write_state()
master.close()

To avoid the possible of the effect from other two motor, i commented out the code and not connected them. I tested the motor on twincat3, it seems all good, the twincat seems in scp mode. In the above code. the motor will stopped in pdo loop sometimes, the motor supplier told me maybe the pdo size too large. but it seems the pdo is not large at all. Is there something wrong with the code.

tom9672 commented 2 years ago

Finally, I figured it out, maybe the motor is form a very small company and its driver can't handle large pdo data. It always stopped suddenly while running... I tried to change its default 1600 and 1A00 by https://github.com/bnjmnp/pysoem/issues/50#issue-1152842201 Now the problem never happened.

Thank you so much!!! BTW, I followed the miniexample, cuz I'm not very understand the basicexample, the code looks more complex. I'd like to know can the basicexample make the devices run better? if so, i will try more effort to learn it.