• 欢迎访问少将全栈,学会感恩,乐于付出,珍惜缘份,成就彼此、推荐使用最新版火狐浏览器和Chrome浏览器访问本网站。
  • 吐槽,投稿,删稿,交个朋友
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏少将全栈吧

Microduck 的策略热切换:一只鸭子怎么同时学会走、坐、翻滚还不打架

Build in Public admin 8小时前 12次浏览 已收录 扫描二维码

大多数人以为 Microduck 就一个 walk 策略——训好、导出 ONNX、塞进去、完事。实际上这只鸭子同时在跑七个策略,而且它们可以在不重启、不停循环的前提下互相切换。

你跟鸭子说”坐下”,sitstand 策略接管。你说”站起来”,stand 策略上。推一下让它翻滚,roulade 接管。这些切换全在 50Hz 循环里实时发生,一拍都不漏。

这背后的设计叫 Policy Channel——一个独立于 daemon 版本的策略分发和管理系统。它解决的不是”怎么训策略”,而是”策略训好了之后怎么到鸭子手上、怎么换、怎么撤”。

七个 slot,三条来路

Microduck 定义了七个策略槽位:walk、stand、sitstand、ground_pick、kick_left、kick_right、roulade。每个 slot 在任意时刻只跑一个策略,但策略本身可以来自三个不同来源。

official 来自 pollen-robotics 自己的 HuggingFace 仓库,带签名、带 semver 版本号,随 release 自动更新。community 来自任何人发布的 HF 仓库,不签名、不自动更新,但记录 commit sha 作为溯源。local 是板子上的文件路径——训完直接 scp 过来试,没有 provenance。

origin 的判定简单粗暴:pollen-robotics/* 就是 official,其他全是 community。这不是一个配置项——官方明确写了”a robot that can be told which org to trust is a robot whose official badge means nothing”。一个常量,一个判断,没有灰色地带。

社区策略为什么不验签名

这是整个设计里最有争议的决定。所有其他组件(daemon、firmware)都必须验签名才能安装,唯独策略文件不强制。

官方的论证逻辑是这样的:策略不是二进制可执行文件,它只是 obs[1,61] → actions[1,14] 的映射。robotd 在策略和电机之间架了三层保护——关节角度钳制、跌倒检测自动 limp、intent deadman 开关。一个恶意策略能做的最糟糕的事,就是让鸭子走得很丑,但它无法绕过 safety 层直接驱动电机。

所以 sandbox 本身就是边界,签名是多余的。一个 daemon binary 没有这种 sandbox,所以必须验签。这个判断的前提是 safety 层确实可靠——Rust 的 borrow checker 保证只有 safety 模块持有 RobotIo,编译器级别的保证,不是运行时约定。

热切换的精确流程

策略切换不是”停掉旧策略、加载新策略、启动新策略”这种粗暴流程。它分两种情况处理。

如果切换不影响当前正在驱动机器人的那个策略:比如鸭子在 walk,你 load 了一个新的 stand 策略——walk 还是 walk,stand 换了文件但鸭子没感知。新 controller 在 worker thread 上加载+预热,然后在下一个 tick 无缝替换。鸭子的位置、速度、滤波器状态全部继承过来。

如果切换影响了正在驱动的策略:比如鸭子在 walk,你 reset 了 walk slot。鸭子先回到 home pose(力矩保持,不会瘫),等新策略加载完毕再接管。这个判断逻辑是对比”这个 tick 在跑的策略路径”和”切换后的策略路径”是否相同。

有个真实案例推动了这个设计:第一次测试时,有人在鸭子坐着(sitstand)的时候 reset 了 walk slot——结果鸭子直接 ramp 回 home 站起来了。问题在于 reset 只改了 walk 的配置,没碰 sitstand,但旧逻辑不看”当前谁在驱动”,直接一刀切回 home。修复后,loop 会比对当前驱动的策略路径,只有真正换了的才回 home。

换策略不重启:config 是持久化的

policy.walk 是 robotd.toml 里的一个 Option。load 一个策略就是写这个 key,reset 就是删这个 key。重启鸭子后配置还在——这意味着你 load 的社区策略在断电重启后依然生效。

这里有个反直觉的设计决策:官方明确拒绝了”临时模式”(try until reboot)。表面上临时模式更安全——烂策略重启即消。但它引入了第二个真相来源:config 文件说一套,内存里记一套。reset 也变得没意义——重启就自动 reset 了,那手动 reset 到底干了啥?

官方选择了一个持久化答案加一个一键撤销。policy load 写 config + 热加载,policy reset 删 config + 回官方默认。简单粗暴,但没有歧义。

社区策略加载失败不会卡住 daemon 更新

这是持久化设计带来的一把双刃剑。你 load 了一个本地策略,然后删了那个文件、或者重刷了板子。下次开机 robotd 找不到文件,报 unhealthy。updaterd 的 health gate 看到 unhealthy 就拒绝 daemon 更新——但这个 unhealthy 跟 daemon 没半毛钱关系,回滚 daemon 也修不好。

解决方案是一个精巧的降级逻辑:community/local 策略加载失败 → 自动回退到该 slot 的 official 默认,状态标记为 degraded 而非 unhealthy。 degraded 不触发 daemon 回滚。official 策略加载失败则保持 unhealthy——因为那确实意味着 bundle 坏了。

注意它不会静默修 config。被 override 的配置行还在,robotctl health 会告诉你哪个文件找不到。你看到了,手动 policy reset 清掉就行。一个会偷偷改 config 的 daemon 比一个明确告诉你状态坏了的 daemon 更吓人。

策略版本检查:不假装所有人用 semver

社区策略的版本展示方式取决于发布者实际提供了什么。repo 有 v* tag 就显示 tag;tracking branch 就显示 short sha + date;local 文件就显示 local。policy check 是唯一的检查入口——official slot 问 updaterd,community slot 直接问 HuggingFace Hub。

定期检查每 6 小时跑一次,覆盖 community 策略。但关键规则是:只报告,不自动安装。 这跟 official 的 auto_apply 策略一致——availability 是事实,installing 是决策。你可以知道”你的 walk 有新版本了”,但不会在不知情的情况下被换掉。

复刻者能拿走什么

如果你在做自己的机器人策略管理系统,这个设计有三条特别值得抄:

第一,策略和 daemon 独立版本。 九个 ONNX 文件塞在 daemon artifact 里意味着改一行 daemon 代码要重传 6MB 权重,而一次 gait retrain 要发一个 daemon release。拆开后两边各走各的版本,各自更新各自回滚。

第二,sandbox 是签名的前提。 如果你给策略设了 safety sandbox(角度钳制+跌倒检测+deadman),那签名就不是安全边界——sandbox 才是。没有 sandbox 的 artifact(daemon binary)必须验签,有 sandbox 的可以放宽。这个判断比”全部验签”或”全部不验签”都更准确。

第三,持久化+一键撤销 > 临时模式。 临时模式看起来安全(重启即消),实际上引入双真相来源、让 reset 语义模糊。持久化配置 + policy reset 一键回官方默认,语义清晰、行为可预测。风险由 safety 层兜底,而不是由”重启就好”兜底。

七张 ONNX 图在一只 25cm 的鸭子身上实时切换,听起来很复杂。但拆开看,每个决策背后都是被真实场景教训出来的:reset 坐着鸭子的 walk 把它搞站起来了、社区策略丢失卡住了 daemon 更新、临时模式让 reset 没意义。Policy Channel 的价值不在于它复杂,在于每个简单选择都挡掉了一个真实的坑。

—

参考来源:

  • Pollen Robotics. microduck 仓库 docs/design/policy-channel-design.md:slot/origin 架构、社区策略不验签论证、热切换流程、持久化与 reset 语义、degraded vs unhealthy 降级逻辑、版本检查设计。GitHub.
  • Pollen Robotics. microduck 仓库 docs/design/robotd-design.md §2.4:safety 层设计、RobotIo borrow checker 保证、跌倒检测与 deadman。GitHub.
  • Pollen Robotics. microduck_rl 仓库 scripts/export.py:ONNX 导出与归一化烙入。GitHub.
喜欢 (0)赏
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。