Microduck 的 61 维观测契约:为什么换脑不需要重启
搞过机器人控制的人都知道,切换行为模式是个麻烦事。传统做法是写一个状态机,walk 状态跑一套控制器,fall 状态跑另一套,切换时还得重新初始化观测缓冲区。Microduck 的做法不太一样:它把行走、起身、坐下、踢球、翻滚这些完全不同的行为,全部训成独立的 ONNX 策略,但共享同一个 61 维观测向量。运行时换策略不需要重启任何东西,新的 ONNX 文件一加载,下一个 20ms 周期就生效。
61 个数字到底是什么
Microduck 的观测向量有 61 维。这个数字不是随便选的,是把所有策略可能需要的信息都塞进去的结果。大致分几块:关节位置和速度(15 个舵机各有位置和速度,共 30 维)、IMU 姿态和角速度(若干维)、指令速度(前后/左右/转向)、头部姿态指令、上一帧动作的历史(让策略有点记忆)、以及一些状态标志位。
关键设计决策在这里:不管你跑的是行走策略还是踢球策略,观测向量的结构完全一样。行走策略可能只看其中 40 维,踢球策略可能只看 35 维,但它们读的是同一块内存。这意味着运行时不需要在切换策略时重新组织数据,只要把同一个观测向量喂给新的 ONNX 模型就行。
热切换在代码里长什么样
microduck_rl 仓库里有个 infer_policy.py 脚本,它做的事就是模拟真机上的热切换过程。你可以同时加载多个 ONNX 文件:
uv run scripts/infer_policy.py --walking walk.onnx \
--standing stand.onnx --sitstand sitstand.onnx \
--roulade roulade.onnx --new-cmd-obs
键盘按 W 切到行走,按 Y 切到坐站,按 R 触发翻滚,按 K 踢球。切换的瞬间没有任何缓冲——上一个 tick 还在走路,下一个 tick 就开始执行新策略的输出。能做到这一点,正是因为观测向量是共享的。
这在真机上的意义更大。robotd 的 50Hz 控制循环每 20ms 读一次传感器、组装观测向量、调 ONNX 推理、写舵机指令。换策略只是把推理那一步的 ONNX 文件指针换掉,其余流程完全不动。不需要停循环,不需要重置 PID,不需要重新校准 IMU。
为什么所有策略能用同一套观测
这其实是训练阶段就设计好的约束。microduck_rl 里每个任务——从 Mjlab-Velocity-Flat-MicroDuck 到 Mjlab-BallKick-Flat-MicroDuck——都基于同一个 MJCF 机器人模型,使用同一组关节定义。训练时观测向量的组装逻辑是共享的,区别只在于奖励函数和初始状态分布。
踢球策略训练时机器人面前有个 70mm/15g 的球,但策略本身是”球盲”——观测向量里没有球的位置信息。它靠的是训练中见过的足部接触模式和身体姿态变化来推断球在哪。这个设计看起来奇怪,但它保证了踢球策略的观测向量和其他策略完全兼容。
翻滚(Roulade)策略也一样。它需要机器人前滚翻越过头部再回到脚上,听起来和走路毫无关系。但它的输入仍然是那 61 维:关节状态、IMU、指令。只不过训练时的初始状态是各种摔倒姿态,奖励函数鼓励翻滚动作。推理时给它同样的 61 维输入,它自然执行翻滚行为。
策略切换的安全边界
热切换听起来很方便,但也有风险。如果当前机器人正在单脚站立,你突然切到一个只会翻滚的策略,它肯定摔。Microduck 的架构文档里把这个安全问题放在 robotd 的安全层处理。robotd 是七个守护进程中唯一能碰舵机的进程,客户端发送的是”意图”而不是直接的控制指令。
安全层会判断当前状态是否允许切换到目标策略。比如机器人正在走路且姿态正常,可以切到踢球;但如果机器人在跌倒过程中,可能只允许切到起身策略。这个判断逻辑在 robotd 内部,不在 ONNX 策略里,所以即使策略文件有 bug,安全层仍然能拦住危险动作。
这也是为什么 Microduck 的架构把 mediad、tofd 这些进程和 robotd 分开。如果摄像头进程崩了,robotd 照样跑控制循环,照样能切策略。观测向量里缺了视觉信息?没关系,大部分策略本来就不依赖视觉——它们靠的是关节状态和 IMU。
一个观测向量管 14 种行为
microduck_rl 的任务列表里有 14 个不同的 task id。从基础的平地行走到复杂的前滚翻,从轮滑模式到蹲下捡东西,全部共享同一个 61 维观测契约。训练时每个策略独立优化自己的奖励函数,部署时通过同一个接口接入运行时。
这种设计的好处不只是切换方便。更重要的是,任何新策略只要遵守观测契约,就能直接插进现有系统。Pollen Robotics 甚至提供了 publish 命令让用户分享自己训的策略:
uv run publish --onnx output.onnx --repo user/microduck-name \
--kind episodic --duration-s 4.0
别人下载你的 ONNX 文件,加载到自己的 Microduck 上,不用改一行代码就能用。因为观测向量是标准化的,策略文件就是即插即用的。
小结:标准化观测比标准化接口更难
做个标准 API 让不同模块通信,这事软件工程里很常见。但让 14 种行为截然不同的 RL 策略共享同一组输入,需要在训练阶段就做好约束。观测向量多了浪费算力,少了某个策略可能训不出来。61 维是 Microduck 在算力、通用性和训练效果之间找到的平衡点。
对于想复刻或者自己训策略的人来说,这里最大的启示是:观测契约一旦定下来就很难改。改一维可能意味着所有已训好的策略都要重训。所以设计观测向量时要想清楚你的机器人未来可能需要什么信息,一开始就留好位置。Microduck 选了 61 维,你的机器人可能需要更多或更少,但原则是一样的:所有策略读同一块内存,换脑不需要重启。
