christiansandberg / canopen

CANopen for Python
http://canopen.readthedocs.io/
MIT License
434 stars 194 forks source link

No SDO response received on one device but works on the other #329

Open TudorMorosanu opened 1 year ago

TudorMorosanu commented 1 year ago

So I've been trying to move some motors using canopen and I have managed to implement everything almost flawlessly when working from my laptop. However, I had to move the control to a RaspberryPi 4, and there I cannot complete setting up the nodes, since I get

Transfer aborted by client with code 0x05040000 Exception in thread Thread-3: Traceback (most recent call last): File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/client.py", line 67, in read_response block=True, timeout=self.RESPONSE_TIMEOUT) File "/usr/lib/python3.7/queue.py", line 178, in get raise Empty _queue.Empty

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner self.run() File "/usr/lib/python3.7/threading.py", line 865, in run self._target(*self._args, **self._kwargs) File "/home/pi/PycharmProjects/python server/CANopen_module.py", line 256, in CANmove setup_node(node, 1) File "/home/pi/PycharmProjects/python server/CANopen_module.py", line 19, in setup_node target_node.sdo['ControlWord'].raw = 15 File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/variable.py", line 89, in raw self.data = self.od.encode_raw(value) File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/variable.py", line 41, in data self.set_data(data) File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/base.py", line 132, in set_data self.sdo_node.download(self.od.index, self.od.subindex, data, force_segment) File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/client.py", line 161, in download fp.close() File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/client.py", line 389, in write response = self.sdo_client.request_response(request) File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/client.py", line 85, in request_response return self.read_response() File "/home/pi/.virtualenvs/pythonProject/lib/python3.7/site-packages/canopen/sdo/client.py", line 69, in read_response raise SdoCommunicationError("No SDO response received") canopen.sdo.exceptions.SdoCommunicationError: No SDO response received

The curious thing is that I've managed to run the code successfully on the RPi4 about 3 or 4 times. After that, without changing anything I started getting this error on different lines almost every time and I cannot understand what is happening. Please help! The code is exactly the same as the one I used on the laptop. I am using a PEAK IPEH-002021 as my CAN module.

TudorMorosanu commented 1 year ago

I have also tried lowering my baud rate in a desperate attempt to make things work but with no success

acolomb commented 1 year ago

You should look at the info collected by the operating system regarding the SocketCAN network device. From the top of my head, something like this:

ip -details -statistics link show can0

Look out for the error counts. On my Pi setup, I had to increase the txqueuelen (sometimes shown as qlen) parameter from 10 to something like 1000.

Are you using the same USB adapter from Peak or some other CAN adapter / shield on the Pi?

TudorMorosanu commented 1 year ago

I am using the same Peak device for both the laptop and the Raspberry. The output of the command says that there are 0 errors. However, on RX there are about 2000-3000 dropped (packages, I assume). I have tried setting up a bigger txqueuelen, but this did not seem to work(I made sure to make it execute on boot, so it is always 10000). I have managed to make the motors execute their tasks correctly over 20 times, then when I run the program again I get the SDO response errror message. Yesterday I have thought that the problem had been solved after I used the setup_402_state_machine() method, since everything worked smoothly after that. Today however, when I powered up the devices and ran the exact same code as yesterday I got the same error. I am not sure what might be causing it since it seems to happen in any given circumstance, I haven't been able to identify a pattern or something to help me locate the source of the problem, I am putting my code here(only the part that uses SDO messages, since this is where I get all my errors)

import canopen
from canopen.profiles.p402 import BaseNode402
import time

def setup_node(target_node, mode_of_op):
    # time.sleep(0.01)
    target_node.nmt.state = 'PRE-OPERATIONAL'
    # time.sleep(0.01)
    target_node.sdo[0x6060].raw = mode_of_op
    # time.sleep(0.01)

    target_node.sdo['ControlWord'].raw = 6
    # time.sleep(0.01)

    target_node.sdo['ControlWord'].raw = 7
    # time.sleep(0.01)

    target_node.sdo['ControlWord'].raw = 15
    # time.sleep(0.01)

def setup_indexes(target_node):
    target_node.nmt.state = 'PRE-OPERATIONAL'
    # time.sleep(0.01)
    target_node.sdo[0x1600][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1601][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1602][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1603][0].raw = 4
    # time.sleep(0.1)

    target_node.sdo[0x1A00][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1A01][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1A02][0].raw = 4
    # time.sleep(0.1)
    target_node.sdo[0x1A03][0].raw = 4

   # target_node.nmt.state = 'OPERATIONAL'

def setup_device_pos(target_node):
    # time.sleep(0.01)
    target_node.nmt.state = 'PRE-OPERATIONAL'
    # time.sleep(0.01)
    # target_node.sdo[0x1600][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1601][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1602][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1603][0].raw = 4
    # # time.sleep(0.1)
    #
    # target_node.sdo[0x1A00][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1A01][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1A02][0].raw = 4
    # # time.sleep(0.1)
    # target_node.sdo[0x1A03][0].raw = 4

    # time.sleep(0.1)

    target_node.tpdo.read()
    # time.sleep(0.1)
    target_node.rpdo.read()
    # time.sleep(0.1)

    target_node.tpdo[1].clear()
    # time.sleep(0.1)
    target_node.tpdo[2].clear()
    target_node.tpdo[3].clear()
    # time.sleep(0.1)

    target_node.rpdo[1].clear()
    target_node.rpdo[2].clear()
    # time.sleep(0.1)
    target_node.rpdo[3].clear()
    # time.sleep(0.1)

    target_node.rpdo[1].add_variable('ControlWord')
    target_node.rpdo[1].add_variable('Mode of operation')
    target_node.rpdo[2].add_variable('target position')
    # time.sleep(0.1)
    target_node.rpdo[2].add_variable('Profile velocity')
    # time.sleep(0.1)
    target_node.rpdo[3].add_variable('Profile acceleration')
    # time.sleep(0.1)
    target_node.rpdo[3].add_variable('Profile deceleration')
    # time.sleep(0.1)

    target_node.tpdo[1].add_variable('StatusWord')
    target_node.tpdo[1].add_variable('Mode of operation display')
    # target_node.tpdo[1].add_callback(print_sw)

    print(target_node.tpdo_values)

    target_node.rpdo[1].event_timer = 0
    # time.sleep(0.1)
    target_node.rpdo[1].trans_type = 1
    # time.sleep(0.1)
    target_node.rpdo[2].event_timer = 0
    # time.sleep(0.1)
    target_node.rpdo[2].trans_type = 1
    # time.sleep(0.1)
    target_node.rpdo[3].event_timer = 0
    # time.sleep(0.1)
    target_node.rpdo[3].trans_type = 1
    # time.sleep(0.1)

    target_node.tpdo[1].event_timer = 0
    target_node.tpdo[1].trans_type = 1

    target_node.rpdo[2].enabled = True
    # time.sleep(0.1)
    target_node.rpdo[3].enabled = True

    time.sleep(0.1)

    time.sleep(0.1)
    target_node.rpdo.save()
    target_node.tpdo.save()
    target_node.nmt.state = `'OPERATIONAL'`

def set_position(target_node, pos, BT):
    # target_node.nmt.state = 'OPERATIONAL'

    # target_node.sdo[0x6060].raw = 1
    # time.sleep(0.01)

    target_node.rpdo[1]['ControlWord'].raw = 15
    target_node.rpdo[1]['Mode of operation'].raw = 1
    target_node.rpdo[1].transmit()

    target_node.rpdo[2]['target position'].raw = pos
    target_node.rpdo[2]['Profile velocity'].raw = 4000
    target_node.rpdo[3]['Profile acceleration'].raw = 155
    target_node.rpdo[3]['Profile deceleration'].raw = 155
    target_node.rpdo[1]['ControlWord'].raw = BT

    target_node.rpdo[2].transmit()
    target_node.rpdo[3].transmit()
    target_node.rpdo[1].transmit()
    # target_node.sdo['ControlWord'].raw = 31

    # target_node.sdo.wait_for_reception(0.1)
    # time.sleep(0.01)

    # target_node.rpdo[1].start(0.1)
    # target_node.rpdo[2].start(0.1)
    # target_node.rpdo[3].start(0.1)

    # time.sleep(0.1)

def set_velocity(target_node, velocity, BT):

    time.sleep(0.01)

    target_node.rpdo[2]['Target velocity'].raw = velocity
    target_node.rpdo[3]['Profile acceleration'].raw = 255
    target_node.rpdo[3]['Profile deceleration'].raw = 255
    target_node.rpdo[1]['ControlWord'].raw = BT

    target_node.rpdo[2].transmit()
    target_node.rpdo[3].transmit()
    target_node.rpdo[1].transmit()

STATE1 = 1063
STATE2 = 4135
STATE3 = 5159

if __name__ == '__main__':

    node = BaseNode402(1, '/opt/eds_lichuan.eds')
    node2 = BaseNode402(2, '/opt/eds_lichuan.eds')
    node3 = BaseNode402(3, '/opt/eds_lichuan.eds')

    network = canopen.Network()
    # network.sync.stop()

    network.add_node(node)
    network.add_node(node2)
    network.add_node(node3)
    network.connect(channel='can0', bustype='socketcan', bitrate=1000000)
    network.check()

    network.sync.start(0.005)

    setup_node(node, 1)
    time.sleep(0.01)
    setup_node(node2, 1)
    time.sleep(0.01)
    setup_node(node3, 1)
    time.sleep(0.01)

    setup_indexes(node)
    setup_indexes(node2)
    setup_indexes(node3)

    node.setup_402_state_machine()
    node2.setup_402_state_machine()
    node3.setup_402_state_machine()

    setup_device_pos(node)
    setup_device_pos(node2)
    setup_device_pos(node3)