I didn’t see any guides or discussion here, so I thought I would put together some quick items form my experience attempting to use modbus rtu with a dynamixel pro actuator.
All tests were preformed with the following:
OS: Ubuntu 18.04 (Linux)/ROS 2 (Dashing)
Serial-USB devices: Robotis U2D2, and FTDI USB-RS485-WE-1800-BT
For simplicity I used a copy of the libmodbus open source modbus library: GitHub - stephane/libmodbus: A Modbus library for Linux, Mac OS X, FreeBSD, QNX and Windows
with very slight modifications to add to 2Mbps buad rate.
For the test setup, the input connection used the left connector on the PM42-010 motor with data being read between the D+ and D- connection on the right connector (assuming you are using the connection diagram at PM42-010-S260-R)
A 120ohm resistor was also connected between the D+ and D- leads at the measurement side to prevent issues with signal reflection.
The first note that I discovered from the emanual document is that the registers listed at PM42-010-S260-R indicate that the addresses are between 40001 and 40304. This simply indicates that we are dealing with holding registers, however this doe not indicate the the starting address to send. Instead we send the offset based on the function code.
Example: I want to read the model number and only the model number (address 40001) from a dynamixel pro actuator with id set to 1. Then I would construct my message to be
0x01 0x03 0x0000 0x0001 crc16
So, 0x01 (the id of the dynamixel), 0x03 (read holding registers), 0x0000 (first register which is 40001), 0x0001 (read only one register).
So a simple way to ready the determine the starting register to send is to subtract 40001 from the Modbus Address section of the emanual.
The second note is to remember your Endianness as it holds across some of the registers which have multiple functions.
Example. to send Torque Enable (40457 LO) with no LED Red color (40257 HI) to the same device as before. Then we would send
0x01 0x06 0x0100 0x0001 crc16
0x01 (actuator id), 0x06 (write single holding register), 0x0100 (offset of 256 or 40257th register), 0x0001 (0x00 hi bit, 0x01 low bit). Which will result in torque on.
Another note is to remember to set the latency of the linux usb-serial interface. For this I use the setserial command (setserial(8): get/set serial port info - Linux man page). Specifically, if the device registers on ttyUS0, then we use the command
sudo setserial /dev/ttyUSB0 low_latency
What this does is reduce the time that Linux holds the serial line preventing reuse. As an example, running an io code at 4Mbps, I see the following request-response from a read request:
If low latency is not set, then Linux will hold the serial device for 10ms, meaning calling 2 consecutive serial commands looks like:
But, but setting low latency, then we reduce that from 10ms to 1ms. So the same consecutive 2 requests instead will look like:
The main thin I find missing with modbus is if the device enters a hardware error state (e.g. due to something like it not being able to reach a commanded position) then there does not appear to be any software based recourse as with the SDK.
Some sample code that I used for testing is available here: Files · feature/libmodbus_copy · Frank Mathis / robotis_modbus_interface · GitLab
Although it does use ROS2 (ament) to build the c++ package.
I am curious if anyone else has tested/worked with the modbus rtu interface on the dynamixel pro actuators, and would love to hear more