拆一只开源鸭子(三):仿真里鸭子为什么不走路

“拆一只开源鸭子”系列:(一)硬件、软件和部署 · (二)训练原理 · (三)仿真里鸭子为什么不走路 · (四)自己训一遍

这一篇记录我在本地把 Microduck 的仿真(simulation)跑起来、发现鸭子不走路、再一步步查出原因的过程。仿真用的是机器人上的同一套守护进程(daemon),见第一篇《硬件、软件和部署》;文中说到的 velstand、BAM 舵机(servo)模型和背隙(backlash),第二篇《训练原理》里有解释。

仿真怎么搭的

robotd --sim 把舵机总线(bus)换成一个 TCP 连接,另一头是 MuJoCo 进程(body_server)。控制循环(control loop)、策略(policy)、安全层、IPC 都是机器人上的同一份代码,它分不清对面是真身体还是仿真。

我的机器是 Intel Mac,踩了几个环境坑:

  • Rust 要 ≥ 1.89,用 rustup toolchain install 1.94 单独装一个,不动默认工具链。
  • microduck_rl 锁定的 torch 2.9.1 没有 Intel Mac 的包,uv sync 装不上。好在 body_server 只依赖 mujoco 和 numpy,单独建一个环境就行:mujoco==3.10.0(还有 Intel Mac 包的最新版)加 onnxruntime。
  • macOS 的 Unix socket 路径上限约 104 字符,状态目录别放太深,用默认的 ~/.cache/duck-sim。
  • 查看器要用 mjpython 启动;挪过虚拟环境的话,记得改它的 shebang。

现象和排查

仿真起来后一切正常:1.00 倍实时,控制循环 50 Hz,鸭子能从坐姿站起来,头会东张西望。但发 0.15 m/s 的前进指令,8 秒只挪了 1 cm 左右。robotctl monitor 显示指令已经生效,腿却几乎不动。

我先怀疑是执行器(actuator)模型:训练用 BAM,而 body_server 只用 MJCF 里的简化位置执行器。装上 BAM(要用 uv.lock 锁定的 62bd8ce,分支最新的提交改了接口)、用官方参考脚本跑,鸭子照样不动,这个猜测就排除了。

真正的线索在策略集的 manifest.json 里:负责行走的是 velstand.onnx,而 duck-sim 脚本把行走槽写死成了旧的 alpha_walking.onnx。再加上 velstand 是在带背隙的模型上训练的,body_server 默认的 scene.xml 却不带背隙。

对照实验

6 组对照实验的实际前进速度
# 运行方式(runner) 策略(policy) 执行器(actuator) 场景(scene) 结果(result,指令 0.15 m/s)
1 robotd + body_server alpha_walking 简化位置执行器 scene.xml 不走(8 s 约 1 cm)
2 官方 infer_policy.py alpha_walking BAM scene.xml 不走(0.00 m/s)
3 官方 infer_policy.py velstand BAM scene_backlash.xml 走,约 0.07 m/s
4 官方 infer_policy.py velstand 简化位置执行器 scene_backlash.xml 走,约 0.08–0.09 m/s
5 robotd + body_server velstand 简化位置执行器 scene.xml 不走(10 s 5 mm)
6 robotd + body_server velstand 简化位置执行器 scene_backlash.xml 走,10 s 0.763 m

实验 2 和 4 说明 BAM 不是关键,实验 5 和 6 说明 velstand 需要带背隙的场景。改两处就好:

- walk = "$POLICIES/alpha_walking.onnx"
- stand = "$POLICIES/alpha_stand.onnx"
+ walk = "$POLICIES/velstand.onnx"
RL=<microduck_rl 的路径>
DUCK_SIM_SCENE=$RL/src/mjlab_microduck/robot/microduck/scene_backlash.xml \
  scripts/duck-sim
同样是 0.15 m/s 的前进指令。左:修复前(alpha_walking + scene.xml),基本原地不动;右:修复后(velstand + 背隙场景)。左上角是实时移动距离。

走起来以后,实际速度只有指令的一半左右(0.07~0.09 m/s)。我一开始以为是自己哪里还没配对,后来在官方基准里看到 0.4 m/s 也只能走到 0.17 m/s。看起来速度跟踪不足是策略本身的短板,不是配置问题。

上游已经有人报告了同样的问题(issue #498),修复的 PR #500 也做了这两处改动,写这篇的时候还没合并。

后来我自己从头训练了一遍走路策略和 velstand,还修了慢速不走的问题,见第四篇《自己训一遍》。

请我喝杯咖啡