XGO Duck: the open source robot duck that walks with neural policies
XGO Duck is an open source, 3D-printable robot duck that Luwu Dynamics built starting from Pollen Robotics’ Microduck. From the original project it keeps the body, the layout of the 15 servos and the joint order, but replaces all of the electronics. In place of the Pollen Robotics board there is an Arduino UNO Q, which runs neural policies for walking, getting up from the ground and picking. So there is no need to wait for a commercial robot: anyone with a 3D printer can build one.
The heart of the system is the Arduino UNO Q itself, which hosts two computers on a single board. On one side there is a host with a Qualcomm processor running Linux, on the other an STM32U585 MCU running Zephyr. This division of tasks is the most interesting architectural choice in the project. The host handles the neural policies, the MCU handles real-time motor control. On top of that, the link between the two is a 2 Mbps Bridge, so the two worlds stay synchronised without Linux ever having to wait on the servo bus.
Two computers, two loops: 50 Hz for the policies and 100 Hz for the bus
The host runs the ONNX policies at 50 Hz on a dedicated thread, with the web UI listening on port 9527. The MCU, on the other hand, runs a 100 Hz bus loop and does not wait for Linux. It publishes a 240-byte duck_state snapshot at 100 Hz; the host filters every snapshot on arrival and the 50 Hz thread reads the latest available one, skipping late cycles. That way the robot does not stall if the host is busy.
The servo bus always addresses all 15 servos in the order ID 10-14, 20-24, 30-34. The order in action 14-D of the policy is instead 10-14, 30-33, 20-24. The servo bus is on Serial1 at 1 Mbps, while the QMI8658 IMU is on Wire at 400 kHz, with I2C address 0x6A then 0x6B. Servo positions are saturated to the encoder range 0-4095, with a raw centre position of 2047.
- 15 FeeTech 1910 servos on a serial bus
- Arduino UNO Q with Qualcomm host and STM32U585 MCU
- QMI8658 IMU on the Wire bus at 400 kHz
- Bridge host-MCU link at 2 Mbps
- servo bus on Serial1 at 1 Mbps
The neural policies: observation [1, 61], action [1, 14] and automatic get-up
The policies expect an observation [1, 61] and output an action [1, 14]. There are three: xgoduck_walk.onnx for walking, xgoduck_getup.onnx for getting up from the ground and xgoduck_pick.onnx for the pick, which lasts 4 s. A tilt above 55° for 0.15 s triggers the get-up model, then the action is forced to 0 for 1 s. When the tilt drops below 15° for 1 s, the robot goes back to walking.
The home pose has hip and ankle at ±24°, knee at 0°, hip roll at ±5°, neck and head pitch at 20°, mouth at 0°. The action_scale is 1. The walking commands are vx ±0.4, vy ±0.3 and ωz ±1.0, with a joystick dead zone of 0.1. The four head channels sit within ±1 radian. The mouth is driven from the web UI from 0° to 30°, and in the pick cycle it opens to 30° and closes when φ ≥ 0.4.
Action smoothing uses α = 0.45 on the slices [0:5], [5:10] and [10:14], yaw smoothing uses α = 0.5 and joint speed smoothing uses α = 0.4. The gravity complementary filter uses τ = 0.3 s, with accelerometer correction dropping when the norm deviates from 1 g by more than about 20%. Position control stops if commands are missing for 250 ms or if the IMU is missing for 100 ms; a host feedback older than 150 ms disarms it.
The Zephyr firmware, servo calibration and the web UI on port 9527
The firmware is a CLI app built with Arduino Zephyr core 1.0.0, on top of RouterBridge 0.4.3, RPClite 0.3.1 and MsgPack 0.4.2. A patch to RouterBridge 0.4.3 raises the RPC thread stack from 500 to 4096 bytes, and the serial router is set to 2 Mbps. Calibration and servo setup use a 2 s heartbeat. The temporary gains for the centring movement are KP = 6 and KD = 20, with a temporary KP = 10 for the servo with ID 34. During calibration the gains become KP = 3 and KD = 0, and every servo is commanded to 2047.
The servo setup page starts with default values KP = 5 and KD = 20. Writing the ID unlocks register 0x37 and then writes 0x05; writing KP/KD unlocks 0x37 and stores both bytes at 0x15. The duck_command sent by the host is 80 bytes. Closing the page or leaving it in the background for more than 1 s disables position control, so the web UI is not just a convenience panel.
The Luwu Dynamics repository collects the project code: sketch, configurations, ONNX models and support scripts. Among the tools are tools/prepare-bridge.py, tools/router-2m.sh, tools/reuse-toolchain.py, tools/verify-elf.py and tools/measure.py, which measures for 60 seconds. There are also python/rl_core.py, python/requirements.txt, sketch/sketch.yaml, app.yaml, data/zero_pos.json and sketch/duck_config.h. Anyone who wants to rebuild it will find everything needed to get started there.
The host needs a Linux environment with ONNX Runtime and Python, while the MCU runs on Zephyr. The UNO Q loader error in case of a tail-call is ENOEXEC (−8), a detail familiar to anyone who compiles firmware. The default rate of Bridge.begin() in another app is 115200, so it has to be raised to 2 Mbps to run the bus as needed. If you want to start with the right hardware, an Arduino UNO Q with a complete accessory kit covers the host and MCU side on a single board.
Source: https://github.com/LuwuDynamics/xgoduck_runtime_arduino
Related products
The post XGO Duck: the open source robot duck that walks with neural policies appeared first on Open Electronics.



















