canopen icon indicating copy to clipboard operation
canopen copied to clipboard

Continuous Synchronous mode send synchronization

Open Cdfghglz opened this issue 3 years ago • 3 comments

Hi there

I am controlling a motor in Continuous Synchronous Position mode with a period of 25ms:

network.connect(channel='can0', bustype='socketcan', bitrate=500000)
network.sync.start(1.0/40)

With candump I measured the jitter of the sync message at about 1.2ms.

In the code I use

node.tpdo[1].wait_for_reception()

as a synchronization event for computing and sending a new value. Below is the plot of tpdo reception times (orange), computation finished times (green) and new message sent times (red) along with a reference "scale" of 25ms (blue x).

Screenshot from 2021-11-26 15-07-35

The motor controller often does not receive the data in time, making the control jittery. What could be the reason for such an irregular reception of the data from the motor on the master side? Is this on the limit of the python implementation or am I just using wrong synchronization mechanism?

Cdfghglz avatar Nov 26 '21 14:11 Cdfghglz

If you use the last TPDO reception time as your base for sending the next SYNC, then naturally any delay from the motor controller will also delay your cycle. I usually have a Python scheduler object (https://docs.python.org/3/library/sched.html) where checking for TPDO reception, any calculations, RPDO sending and finally SYNC sending are done in a specified order with the time.monotonic() clock as the time source. At the end of the cycle, it does a final task to enter new scheduled tasks for the next cycle. But the scheduled times for that are based on the last scheduled times, not the the last cycle's actual sending times. That's how I avoid drifting off from the regular 25 ms cycle (which is 40 ms in my case).

Hope that helps to get your timing under control.

What operating system are you using? I noticed my code ran flawlessly on a Linux laptop with a USB2CAN adapter, but became rather jittery on a Windows laptop with PCAN adapter.

acolomb avatar Jan 15 '22 12:01 acolomb

Thanks @acolomb for your reply.

As long as I understood, the network.sync.start(1.0/40) will run a background thread which takes care of the periodic sync message. We actually checked with candump and measured a jitter of ~1ms. Since I don't send the sync manually, the delay is not natural to me. Based on the relatively accurate signal, I would expect my controller to send the TPDO back in some reasonable time, based on which i do the computation, send data and then wait again.

As a temporary workaround I actually run network.sync.stop() just before I start the loop, then take over the sync manually with network.sync.transmit() in my loop running with 40Hz. This makes the sending buttery smooth, I have not verified the delays of TPDO reception though. Do you use the wait_for_reception() or any other?

Just for the reference: Ubuntu 18.04, Jetson TX2 dev kit over the 'native' onboard CAN bus.

Cdfghglz avatar Jan 15 '22 20:01 Cdfghglz

I don't use wait_for_reception(), but keep a dictionary mapping each expected CAN ID to a boolean, which gets set to True when receiving the respective object. Then at a fixed time after sending SYNC, I check if all entries in the dict are true.

The SYNC sending is also handled in that scheduled cycle, precisely because having a separate background thread that sends it makes synchronization of other (local) tasks to it harder.

Note that if you have only one controller to communicate with, this might be overkill. I use it with at least 8 motors that should run synchronized. For what it's worth, here is my class definition including a small testing example usage: https://gist.github.com/acolomb/a583b05b3389cb57a406bc979e2f4f3e

acolomb avatar Jan 15 '22 21:01 acolomb