christiansandberg / canopen

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

Error when using: network.scanner.search() #369

Closed GIT1RWM2AR closed 3 months ago

GIT1RWM2AR commented 1 year ago

Hello to all, I find an error, fixed it with a workaround, but maybe the CAN, CANopen specialists know the correct solution.

network.scanner.reset() network.scanner.search() ---> Error slcan0 75B [1] 7F slcan0 60A [8] 40 00 10 00 00 00 00 00 slcan0 58A [8] 43 00 10 00 00 00 00 00 slcan0 601 [8] 40 00 10 00 00 00 00 00 slcan0 602 [8] 40 00 10 00 00 00 00 00 slcan0 603 [8] 40 00 10 00 00 00 00 00 slcan0 604 [8] 40 00 10 00 00 00 00 00 slcan0 605 [8] 40 00 10 00 00 00 00 00 slcan0 606 [8] 40 00 10 00 00 00 00 00 slcan0 607 [8] 40 00 10 00 00 00 00 00 slcan0 608 [8] 40 00 10 00 00 00 00 00 slcan0 609 [8] 40 00 10 00 00 00 00 00 slcan0 60A [8] 40 00 10 00 00 00 00 00 slcan0 60B [8] 40 00 10 00 00 00 00 00 slcan0 60C [8] 40 00 10 00 00 00 00 00 slcan0 60D [8] 40 00 10 00 00 00 00 00 slcan0 587 [8] 43 00 10 00 00 00 00 00 slcan0 588 [8] 43 00 10 00 00 00 00 00 slcan0 58A [8] 43 00 10 00 00 00 00 00 slcan0 707 [1] 7F File "/home/ar/Schreibtisch/WING-Test-1/Wing-Main-1.py", line 75, in network.scanner.search() File "/home/ar/.local/lib/python3.10/site-packages/canopen/network.py", line 404, in search self.network.send_message(0x600 + node_id, sdo_req) File "/home/ar/.local/lib/python3.10/site-packages/canopen/network.py", line 216, in send_message self.bus.send(msg) File "/home/ar/.local/lib/python3.10/site-packages/can/interfaces/socketcan/socketcan.py", line 774, in send sent = self._send_once(data, channel) File "/home/ar/.local/lib/python3.10/site-packages/can/interfaces/socketcan/socketcan.py", line 791, in _send_once raise can.CanOperationError( can.exceptions.CanOperationError: Failed to transmit: No buffer space available [Error Code 105]

Workaround: time.sleep(0.001)

def search(self, limit: int = 127) -> None:
    """Search for nodes by sending SDO requests to all node IDs."""
    if self.network is None:
        raise RuntimeError("A Network is required to do active scanning")
    sdo_req = b"\x40\x00\x10\x00\x00\x00\x00\x00"
    for node_id in range(1, limit + 1):
        self.network.send_message(0x600 + node_id, sdo_req)
        time.sleep(0.001)

Is there a better solution?

Thank you in advance; You did a great job!

Best regards Armin

@christiansandberg: Can I send you a direct E-Mail for some other questions? Thanks

sveinse commented 1 year ago

The code in search is sending an SDO request to all nodes, which creates a lot of packages. My guess to the root cause is that python-can or the CAN driver is accepting data from canopen faster than it's able to process and fills up. I'm uncertain if this is a canopen issue, unfortunately.

According to the python-can API the self.bus.send() function innetwork.py, Network.send_message() accepts a timeout argument. The docs sais:

    :param timeout:
       If > 0, wait up to this many seconds for message to be ACK'ed or
       for transmit queue to be ready depending on driver implementation.
       If timeout is exceeded, an exception will be raised.
       Might not be supported by all interfaces.
       None blocks indefinitely.

Please try changing this code in Network.send_message(). https://github.com/christiansandberg/canopen/blob/master/canopen/network.py#L213-L214. Does this work at all?

        with self.send_lock:
            self.bus.send(msg, timeout=0.01)
samsamfire commented 1 year ago

GIT1RWM2AR, change your transmit buffer length in socketcan to something like 1000. If you are using can0 this could be something like: sudo ip link set can0 type can txqueuelen 1000

GIT1RWM2AR commented 1 year ago

Hello Svein, hello Samuel, Thank you for your quick responce. I tried to check your improvements, but without success:

  1. Sveins solution, didn't changed the result: --> can.exceptions.CanOperationError: Failed to transmit: No buffer space available [Error Code 105] Even: self.bus.send(msg, timeout=1.01)
    --> No improvements:
  2. Samuels suggestion seems to point to the solution with an increase of the txquelen, but I ended up in the problems of CAN / Linux implementations; and in both I am no expert: --> I try to show my investigations:

    For Info: Here I show the startup-commands for Thomas Fischl: USBtin and Linux-CAN-HW-Interface:

    !/bin/bash

    echo "Start slcan0 interface for /dev/ttyACM0" cd can-utils/ sudo modprobe can sudo modprobe can-raw sudo modprobe slcan echo "Set CAN-Interface to 500kBaud" sudo ./slcan_attach -f -s6 -o /dev/ttyACM0 sudo ./slcand ttyACM0 slcan0 sudo ifconfig slcan0 up candump slcan0

    Here is the suggested improvement: --> sudo ip link set slcan0 type can txqueuelen 1000 This is the error-message: ==> can: unknown option "txqueuelen" Because of: https://www.suse.com/support/kb/doc/?id=000019932

  3. Take note that the name for the txqueuelen setting used by the "ifconfig", "ip" and "systool" commands are "txqueuelen", "qlen" and "tx_queue_len"

I tried: txqueuelen, qlen, tx_queue_len ---> all with the same negative result

To get more information: ip -details -statistic link show slcan0 6: slcan0: <NOARP,UP,LOWER_UP> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10 link/can promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 RX: bytes packets errors dropped missed mcast
28919 28674 0 0 0 0 TX: bytes packets errors dropped carrier collsns
2408 301 0 0 0 0

---> group default qlen 10

---> Under Linux I found:
---> https://elixir.bootlin.com/linux/v4.14/source/drivers/net/can/slcan.c#L443

    dev->[tx_queue_len](https://elixir.bootlin.com/linux/v4.14/C/ident/tx_queue_len)    = 10;

For me, this looks like a hard coded value

--> At this point I ended up, because I am not familiar with Linux driver handling and debugging.

Any further ideas, how to get an easy way of improvement?

Maybe in some future time, I am experienced to do it, additionally to handle lost hardware bus connections (USB/CAN) to do a plug and play reconnect. Until then, I will work with my not so perfect delay time of one millisecond.

Many thanks and Best regards

Armin

samsamfire commented 1 year ago

I'm not really familiar with SLCAN and I don't know if the underlying hardware is very capable. Anyway, my bad the command is without the "type can" as so: sudo ip link set slcan0 txqueuelen 1000 Increasing the txqueuelen is not magic though, if your hardware is not capable of sending at the pace your emitting then you will end up with the same error. This option is only really useful when your sending frames in bursts (like with the scan function) and your driver hasn't got the time to process all tx frames.

GIT1RWM2AR commented 1 year ago

Hello Samuel, now with your help,

sudo ip link set slcan0 txqueuelen 1000

it is working perfectly.

I tested it down till 115. In future I will use 130 because I know: for node_id in range(1, limit + 1):
and limit = 127 (CANopen-Bus can have maximum 128 nodes)

sudo ip link set slcan0 txqueuelen 130

Thank you very much! Armin

PS. Sorry for the bold text, in my last comment: This comment-function did it automatically. How do I set this issue to solved? Is this Christians task?

friederschueler commented 3 months ago

You should be able to close issues you opened yourself. You write a comment and press the "Close with comment" Button.