XGO Duck è un’anatra robot open source, stampabile in 3D, che Luwu Dynamics ha costruito partendo da Microduck di Pollen Robotics. Del progetto originale riprende il corpo, la disposizione dei 15 servo e l’ordine dei giunti, ma cambia tutta l’elettronica. Al posto della scheda di Pollen Robotics c’è un Arduino UNO Q, che fa girare policy neurali di camminata, rialzo da terra e pick. Quindi non serve aspettare un robot commerciale: chi ha una stampante 3D può costruirselo.
Il cuore del sistema è proprio l’Arduino UNO Q, che ospita due computer in una sola scheda. Da una parte c’è un host con processore Qualcomm che gira Linux, dall’altra un MCU STM32U585 con Zephyr. Questa divisione dei compiti è la scelta architetturale più interessante del progetto. L’host si occupa delle policy neurali, l’MCU del controllo motori in tempo reale. Inoltre il link tra i due è un Bridge a 2 Mbps, quindi i due mondi restano sincronizzati senza che Linux debba mai aspettare il bus servo.
Due computer, due loop: 50 Hz per le policy e 100 Hz per il bus
L’host esegue le policy ONNX a 50 Hz su un thread dedicato, con la web UI in ascolto sulla porta 9527. L’MCU, invece, gira un loop di bus a 100 Hz e non aspetta Linux. Pubblica uno snapshot duck_state da 240 byte a 100 Hz; l’host filtra ogni snapshot all’arrivo e il thread a 50 Hz legge l’ultimo disponibile, saltando i cicli in ritardo. Così il robot non si blocca se l’host è occupato.
Il bus servo indirizza sempre tutti e 15 i servo nell’ordine ID 10-14, 20-24, 30-34. L’ordine nell’azione 14-D della policy è invece 10-14, 30-33, 20-24. Il bus servo è su Serial1 a 1 Mbps, mentre l’IMU QMI8658 è su Wire a 400 kHz, con indirizzo I2C 0x6A poi 0x6B. Le posizioni dei servo sono saturate all’intervallo encoder 0-4095, con posizione raw di centratura a 2047.
- 15 servo FeeTech 1910 su bus seriale
- Arduino UNO Q con host Qualcomm e MCU STM32U585
- IMU QMI8658 su bus Wire a 400 kHz
- link Bridge host-MCU a 2 Mbps
- bus servo su Serial1 a 1 Mbps
Le policy neurali: osservazione [1, 61], azione [1, 14] e get-up automatico
Le policy aspettano un’osservazione [1, 61] ed emettono un’azione [1, 14]. Sono tre: xgoduck_walk.onnx per la camminata, xgoduck_getup.onnx per il rialzo da terra e xgoduck_pick.onnx per il pick, che dura 4 s. Il tilt sopra 55° per 0.15 s attiva il modello di get-up, poi l’azione è forzata a 0 per 1 s. Quando il tilt scende sotto 15° per 1 s, il robot torna alla camminata.
La posa di home ha hip e ankle a ±24°, knee a 0°, hip roll a ±5°, neck e head pitch a 20°, mouth a 0°. L’action_scale è 1. I comandi di camminata sono vx ±0.4, vy ±0.3 e ωz ±1.0, con zona morta del joystick a 0.1. I quattro canali della testa stanno in ±1 radiante. La bocca è comandata dalla web UI da 0° a 30°, e nel ciclo di pick si apre a 30° e si chiude quando φ ≥ 0.4.
Lo smoothing dell’azione usa α = 0.45 sulle slice [0:5], [5:10] e [10:14], quello del giro α = 0.5 e quello della velocità dei giunti α = 0.4. Il filtro complementare della gravità usa τ = 0.3 s, con correzione dell’accelerometro che cala quando la norma si discosta da 1 g di più del 20% circa. Il controllo di posizione si ferma se i comandi mancano per 250 ms o se l’IMU manca per 100 ms; un feedback host più vecchio di 150 ms disarma.
Il firmware Zephyr, la calibrazione servo e la web UI sulla porta 9527
Il firmware è un’app CLI con Arduino Zephyr core 1.0.0, costruita sopra RouterBridge 0.4.3, RPClite 0.3.1 e MsgPack 0.4.2. Una patch a RouterBridge 0.4.3 porta lo stack del thread RPC da 500 a 4096 byte, e il router seriale è impostato a 2 Mbps. La calibrazione e il setup servo usano un heartbeat di 2 s. I guadagni temporanei per il movimento di centratura sono KP = 6 e KD = 20, con KP temporaneo = 10 per il servo con ID 34. In calibrazione i guadagni diventano KP = 3 e KD = 0, e ogni servo è comandato a 2047.
La pagina di setup servo parte con valori predefiniti KP = 5 e KD = 20. La scrittura dell’ID sblocca il registro 0x37 e poi scrive 0x05; la scrittura di KP/KD sblocca 0x37 e memorizza entrambi i byte a 0x15. Il comando duck_command inviato dall’host è di 80 byte. Chiudere la pagina o lasciarla in background per più di 1 s disattiva il controllo di posizione, quindi la web UI non è solo un pannello di comodo.
Il repository di Luwu Dynamics raccoglie il codice del progetto: sketch, configurazioni, modelli ONNX e script di supporto. Tra gli strumenti ci sono tools/prepare-bridge.py, tools/router-2m.sh, tools/reuse-toolchain.py, tools/verify-elf.py e tools/measure.py, che misura per 60 secondi. Ci sono anche python/rl_core.py, python/requirements.txt, sketch/sketch.yaml, app.yaml, data/zero_pos.json e sketch/duck_config.h. Chi vuole rifarlo trova lì tutto il necessario per partire.
Per l’host serve un ambiente Linux con ONNX Runtime e Python, mentre l’MCU gira su Zephyr. L’errore del loader UNO Q in caso di tail-call è ENOEXEC (−8), un dettaglio che chi compila firmware conosce bene. Il rate di default di Bridge.begin() di un’altra app è 115200, quindi va alzato a 2 Mbps per far girare il bus come serve. Se si vuole partire con l’hardware giusto, un Arduino UNO Q con kit completo di accessori copre la parte host e MCU in una sola scheda.
Fonte: https://github.com/LuwuDynamics/xgoduck_runtime_arduino
