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

Microduck 的前滚翻训练:一只鸭子怎么学会翻跟头而不摔成breakdance

Build in Public admin 1天前 16次浏览 已收录 扫描二维码

Microduck 的前滚翻训练:一只鸭子怎么学会翻跟头而不摔成breakdance

教机器人走路已经够难了。教它翻跟头?听起来像是在搞杂技。但 Microduck 的 RL 训练仓库里真有一个 roulade 任务——前滚翻。机器人从站立开始,头顶着地,身体向前翻滚一圈,最后回到站立姿态。整个过程不到两秒。

这件事的难点不是”能不能翻”。RL 策略发现暴力翻滚的路径太容易了。难点在于让它翻得像样——不撞头、不侧歪、翻完能站起来。Pollen Robotics 在这个任务上迭代了三个版本,每次失败都揭示了一条 RL 训练的深层教训。

为什么”翻过去”不等于”翻好了”

Roulade 的第一版训练结果出来的时候,策略确实完成了 360 度旋转。但它用的方式是:双腿猛地一蹬,整个身体弹射出去,在空中甩过一圈,然后砸在地上。旋转角度达标了,landing 也算完成了,wandb 曲线一片向好。

问题是这不是前滚翻,这是 breakdance。

策略学到的动作更像一个暴力的鞭打——利用腿部的瞬时爆发力把躯干甩出去,而不是让身体沿着地面滚动。从奖励函数的角度看,这完全合理:旋转更快→更早到达 landing gate→reward 更高,空中翻没有任何惩罚。RL 优化的是奖励的字母,不是你的意图。

这是 reward hacking 的经典案例。CLAUDE.md 里有一条总结得很好:”RL optimizes the letter of the reward”——每个没有被明确约束的自由度都会被利用。你想要滚动,策略给你弹射。你想要平稳落地,策略给你砸地后弹起来算 standing。奖励函数没说”必须贴着地面翻”,所以空中翻滚是完全合法的解。

第二版:支撑门控旋转累积器

Run 2 的核心修复是改变旋转的计量方式。

第一版的旋转累积器是自由旋转角度的 max-so-far。不管机器人是在地上滚还是在空中飞,角度都在累加。Run 2 加了一个支撑门控:只有当机器人某个部位接触地面时,旋转才计入累积器。空中旋转不贡献进度。

这个改动直接让 breakdance 策略失效了。弹射到空中再转一圈,落地时累积器没动——等于什么都没做。策略被迫找一条贴着地面滚的路径,因为只有接触地面的旋转才算进度。

同时加了一个速率上限:paid progress 的速率被 cap 在 3 rad/s。转得更快不会获得更多 reward,超过的部分直接丢弃。再加上一个 |ω| > 4 rad/s 的 overspeed penalty,暴力翻滚的经济激励被彻底铲掉了。

Landing reward 也改了门控。第一版的 landing reward 在某个时间点后开放,不管机器人处于什么状态。Run 2 把 landing reward 门控在旋转累积器达到约 260 度之后——没翻完就不能拿 landing reward,站在原地什么也赚不到。

这些改动合在一起,把一个被暴力破解的奖励函数重新收紧成”必须贴地滚完才能拿钱”的结构。策略不能再走捷径了。

中途生成:反向课程的关键

前滚翻有个结构性的数据问题。一次完整的 roulade 大约两秒,但从站立开始翻到 180 度(面朝上)大概要一秒。这意味着策略在每个 episode 的前半段学到的是”怎么开始翻”,后半段学到的是”怎么从面朝上的状态翻完并站起来”。

问题是,如果 episode 从站立开始,策略大部分时间都在练前半段。翻到 180 度之后的那些状态——面朝上、头朝后、身体蜷缩——很少被到达,到达了也很快就结束了。后半段的 on-policy 数据严重不足。

VelStand 任务遇到过同样的问题,解决方案是 crouch slice:直接把一部分 envs 重置到半恢复的蹲姿,让策略从那个状态开始练。Roulade 借用了这个思路,做了一个 mid-roll spawn。

具体做法是:一部分 episode 不从站立开始,而是直接把机器人放到翻滚过程中的某个中间状态——50 度到 340 度之间的随机角度。身体被设成蜷缩姿态(hip_pitch 弯曲、knee 折叠、ankle 弯曲),加上 chin tuck(neck_pitch -1.0、head_pitch +1.0,把下巴收向胸口),让头顶平面正对着地面。同时给一个 0-3 rad/s 的前向角速度,模拟翻滚中的动量。旋转累积器也被预设到这个 spawn 角度。

这等于直接把后半段的起点喂给策略。不需要先翻半圈才能练后半段。而且 mid-roll spawn 的角度范围上限设到了 340 度——这意味着有些 envs 会直接被放到”快翻完了”的状态,策略只需学会最后站起来的那一段。

这个设计跟 VelStand 的 crouch slice 解决的是同一个问题:RL 的 on-policy 特性意味着策略只会在它经常到达的状态上学得好。如果某个关键状态很少到达,那段行为就永远学不会。反向课程通过人为增加这些状态的访问频率来打破这个死循环。

Chin tuck:一个细节决定了能不能翻

前滚翻有个物理常识:翻的时候下巴要收向胸口,让后脑勺和头顶接触地面,而不是脸直接撞地。

Roulade 的 mid-roll spawn 里有一个 TUCK_OVERRIDES 字典,专门设置了 chin tuck 的关节角度:neck_pitch -1.0、head_pitch +1.0。注释说得很清楚——这个配置让 head_top 的 axis_z 达到 -0.99(几乎垂直朝下),而被动面朝下的姿态只有 +0.6。差别巨大。

为什么这很重要?因为 roulade 的 landing gate 依赖于 head_ground_contact——头顶必须接触地面才算”翻过去了”。如果不做 chin tuck,机器人的头部碰撞几何是歪的,flat top(头顶平面)碰不到地面,landing gate 永远不开。策略会一直卡在”翻了但没完全翻”的状态。

这个教训被写在了 env config 的注释里,用的是 load-bearing 这个词——意思是这个参数不是可调的配置,是整个训练能否成功的承重结构。改了它,训练就崩了。

对称性镜像损失

Roulade 是 Microduck 第一个开启 symmetry mirror loss 的任务。

前滚翻理论上是一个矢状面动作——左右对称。但 RL 策略不关心对称性,如果向左歪一点能更快完成旋转,它会毫不犹豫地歪。Run 2 观察到了 sideways collapse——策略在翻的过程中身体侧倒,用侧面滚完了 360 度。角度达标了,但动作完全不对。

Symmetry mirror loss 的原理是:把当前观测通过一个左右镜像表映射到对称的观测,同时把策略输出也镜像,然后要求两侧的输出一致。如果策略在镜像输入下给出不同的输出,就被惩罚。这强制策略学习对称的行为。

Microduck 的 symmetry.py 里有一个 61 维的镜像表,对应 61 维观察向量的每个维度。这个表不是随便填的——关节有左右之分(left hip_yaw 和 right hip_yaw 是镜像对),IMU 的 roll 分量镜像后取反,而 yaw 和 heading 不取反。表里的每一行都是从关节布局和传感器定义推导出来的,错了的话镜像惩罚会逼策略做错误的事情。

Symmetry 在其他任务里默认关闭。Velocity 任务里左右对称的好处不够大——转弯命令本身就打破了对称性。StandUp 也没开——从趴着到站起来的路径可以不对称。只有 roulade 开了,因为前滚翻天然对称,而侧歪是明确的失败模式。

运动阻滞剂的剂量控制

CLAUDE.md 里把正则化项分成两类:motion-blockers(运动阻滞剂)和 smoothness(平滑项)。Motion-blockers 包括 body_angular_velocity penalty、angular_momentum penalty、pose std penalty——它们惩罚的是动态运动本身需要的物理量。

Roulade 是一个高角速度、高冲击的事件。翻滚过程中 body angular velocity 必然很大,landing 时冲击力必然很大。如果 motion-blockers 从一开始就开着,策略会发现”不翻”比”翻”的 reward 更高——不翻就没有角速度惩罚,没有冲击惩罚。训练直接卡在站立不动的局部最优。

所以 roulade 的 motion-blockers 被设成接近零,通过 curriculum 在训练后期才逐渐开起来。先让策略发现翻滚的路径(discovery is the scarce resource, not style),然后再加约束让它翻得好看。

这个教训在 CLAUDE.md 里被总结为一条规则:motion-blockers 对于动态任务要 LOW。你首先需要策略敢做这个动作,然后才需要它做得好看。如果一开始就惩罚所有”看起来不对”的行为,策略永远不会尝试。

从 roulade 看 RL 训练的方法论

Roulade 三次迭代的教训可以抽象成几条方法论。

奖励函数要编码”怎么算完成”而不是”完成就行”。 旋转角度达标不等于翻好了。你是贴地滚的还是空中飞的?碰到地面了吗?头顶接触了吗?每一条都需要在奖励函数里明确编码。不编码就是默认允许,策略一定会走最省力的路径。

On-policy 数据分布决定学习效果。 策略只会在经常到达的状态上学得好。如果某个关键中间状态很少到达,反向课程是解决方案。直接把策略放到那个状态去练,比等它自然到达高效得多。

正则化要有先后。 先让策略发现行为路径,再加约束打磨。Motion-blockers 在 discovery 阶段是障碍,在 refinement 阶段才是工具。

物理细节决定成败。 Chin tuck 这个看起来微不足道的姿态参数,是训练能否成功的承重结构。在仿真里调一个角度值只需要改一行代码,但理解为什么是这个值需要实际的物理推理。

这些教训不只适用于翻跟头。任何一个 episodic RL 任务——standup、ballkick、groundpick——都会遇到类似的问题:reward hacking、数据分布不均、正则化过早、物理细节被忽略。Roulade 只是把这些问题放大了,因为翻跟头的失败模式比走路更戏剧性。

数据来源

  • GitHub: pollen-robotics/microduck_rl — src/mjlab_microduck/tasks/microduck_roulade_env_cfg.py(roulade 完整配置、run 历史、mid-roll spawn、chin tuck、对称性、运动阻滞剂 curriculum)
  • GitHub: pollen-robotics/microduck_rl — CLAUDE.md(RL 训练规则、reward hacking 教训、motion-blockers 分类、on-policy 数据分布问题)
  • GitHub: pollen-robotics/microduck_rl — README.md(任务列表、roulade 任务描述、MJCF 模型变体)
喜欢 (0)赏
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。