Skip to content

DYNAMIXEL emulation

To a host program, Doppelstep is a DYNAMIXEL XM430-W350 (model number 1020) with one ID, speaking Protocol 2.0. The X430 emulator validates every access exactly as the servo does: ranges and limits, the EEPROM lock, Indirect Addresses, Fast Sync/Bulk Read, the Bus Watchdog. The firmware then maps the registers onto the motor (app/src/joint_bridge.c). This page lists that mapping, the units, and what differs from a real XM430.

Register mapping

Register Mapping
Torque Enable (64) stepper_enable() / stepper_disable(); refused (Result Fail) while the dead time is not set or with a fault
Operating Mode (11) 3 position, 4 extended position, 1 velocity; 0, 5, 16 are refused (Data Range Error)
Goal Position (116) stepper_ctrl_move_to(); limits from Profile Velocity/Acceleration (velocity- or time-based, Drive Mode bit 2), Velocity Limit and the max-velocity / max-acceleration properties of the motor node
Goal Velocity (104) stepper_ctrl_run() or stepper_ctrl_stop() (velocity mode)
Drive Mode (10) bit 0, Homing Offset (20) Direction and offset of the position mapping
Current Limit (38) Run current = min(limit × 2.69 mA, run-current-milliamp)
Present Position (132), Position Trajectory (140) Commanded position (no encoder)
Present Velocity (128), Velocity Trajectory (136) Commanded velocity
Present Current (126) Phase current amplitude √(iA² + iB²)
Present Input Voltage (144) Measured VBUS (0.1 V)
Moving (122), Moving Status (123) From the status of the motor driver
Hardware Error Status (70) Over/undervoltage → Input Voltage; overcurrent, W trip, HAL → Electrical Shock
Bus Watchdog stepper_ctrl_stop()
REBOOT / FACTORY_RESET Outputs off, faults cleared; on the board (MCUboot) REBOOT then resets the MCU: silent for 500 ms plus startup, Present Position restarts (Firmware update)
CLEAR (multi-turn) Position redefined within one turn
Baud Rate (8) USART2 reconfigured after the status packet

Units

The conversions are in app/src/joint.c:

Quantity DYNAMIXEL unit Motor side
Position 4096 pulses per joint revolution 3200 microsteps per motor revolution (200 × 16)
Velocity 0.229 rev/min microsteps per second
Acceleration 214.577 rev/min² microsteps per second²
Current 2.69 mA mA
Gear gear-motor-revs / gear-joint-revs of the servo node (1/1 by default)

Startup position

The motor has no encoder. At power-on the rotor position is reported as Present Position 2048 (start-position of the servo node, 0 rad for dynamixel_hardware_interface): power the joint up in that position. With the torque off the rotor can be moved by hand, and the reported position is then no longer the real one.

Factory values and the EEPROM

Value Doppelstep A real XM430
ID factory-id of the servo node, 1 1
Baud rate factory-baud-code 3 = 1 Mbps, the OpenMANIPULATOR-X bus speed 57600 bps

The factory values apply while no EEPROM block is stored and after FACTORY_RESET. ID, Baud Rate and the other EEPROM registers written over the bus are stored in flash (NVS, the storage partition of the servo node) and survive a power cycle and a firmware update. Flash writes are refused while the power stage is enabled: the MCU has a single flash bank, and an erase stalls the CPU.

Connecting a host program

Host program Port
On the board ST-LINK Virtual COM Port (COM5 on Windows, /dev/ttyACM0 on Linux), 1 Mbps
native_sim on the same Linux machine or Dev Container build-native/ttyDXL
native_sim in Docker, host program on WSL or another Linux machine python3 tools/sim/run_native.py connect --host localhost --port 5555 → /tmp/ttyDXL
native_sim in Docker, smoke test on Windows python tools\sim\dxl_smoke_test.py --tcp localhost:5555

For ROS 2, set the port of the dynamixel_hardware_interface description to /tmp/ttyDXL (or build-native/ttyDXL); the baud rate is accepted and ignored on native_sim. The pseudoterminal driver polls for the first byte of a packet every 10 ms, so an answer can take up to about 10 ms (a real bus: well under 1 ms): keep the host's packet timeout above that.

OpenMANIPULATOR-X

Its ros2_control description expects five XM430-W350 on one bus (IDs 11–15, 1 Mbps, Operating Mode 3, Drive Mode 4 = time-based profile). One Doppelstep answers for one ID, so over the Virtual COM Port the host sees one joint: set factory-id to the joint's ID (for example 11). Fast Sync/Bulk Read answers come only from the IDs of one emulator bus.

The integration tests run this loop against the firmware with the official DynamixelSDK: Sync Read of current, velocity and position, Sync Write of the goal, at 100 Hz (Tests).

Differences from a real XM430-W350

Topic Doppelstep
Position and velocity readings Commanded values: there is no encoder, and lost steps are not detected yet
Operating Modes 0, 5, 16 Refused with Data Range Error
Factory baud rate 1 Mbps instead of 57600 bps
Reboot on the board Resets the MCU: 500 ms of silence plus startup, Present Position restarts at 2048
Present Temperature Keeps its table value: the NTC sensor is not converted yet, no overheating trip
Several IDs on one bus One ID per board

DYNAMIXEL and ROBOTIS are trademarks of ROBOTIS Co., Ltd. Doppelstep is an independent project and is not affiliated with or endorsed by ROBOTIS.