教一只四足机器人爬梯子,比教它走路难在哪里?本文从 Datawhale 具身智能组队学习的第 6 课出发,用大白话拆解"梯面攀爬"任务中的两个核心工程难点:双策略交接和接触力控制。
一、这节课到底在讲什么?
1.1 任务目标
一句话总结:训练一只叫 MicroDuck 的四足机器人,从地面沿着带横档的斜梯爬上去,翻到桌面上,然后站稳。
整个过程分两个阶段:
阶段1(攀爬):用脚一级一级踩上横档,像攀岩一样往上爬
阶段2(起身):翻到桌面后,从趴着的状态站起来,保持平衡
先来看最终效果——下面是 MicroDuck 从地面到桌面的完整攀爬序列(12 帧抽帧):

完整攀爬序列(12 帧)
从上到下、从左到右,展示了 MicroDuck 从地面到桌面的完整过程:
- 第 1-3 帧:鸭子从地面接近梯子,开始用前脚踩上第一根横档
- 第 4-6 帧:交替踩横档,身体逐渐升高,重心前移
- 第 7-9 帧:接近梯子顶部,身体开始翻向桌面
- 第 10 帧:前脚已经踩到桌面边缘,后脚还在梯子上
- 第 11 帧:身体翻到桌面上,但还在趴着(这是 climber → getup 的交接点)
- 第 12 帧:getup 策略接管,鸭子站起来,稳稳站在桌面上
关键观察:第 10-11 帧之间发生了策略交接。注意鸭子的姿态变化——从"攀爬姿态"(身体前倾)变成"趴着"(身体贴桌面),然后 getup 把它拉起来。
看完效果,你可能好奇:这是怎么做到的?接下来我们一步步拆解。
1.2 为什么这个任务有挑战性?
和之前学过的平地走路、篮球平衡、高跷行走相比,爬梯子有三个本质区别:
| 维度 | 平地走路 | 爬梯子 |
|---|---|---|
| 支撑面 | 连续地面,踩哪都行 | 离散横档,必须踩准(间距约 5cm) |
| 力的方向 | 主要靠垂直支撑力 | 需要摩擦力防止滑下去,需要法向力防止掉下去 |
| 失败后果 | 摔倒,重新走 | 从梯子上掉下来,可能卡住或翻车 |
通俗比喻:平地走路像在操场上走,爬梯子像在攀岩墙上爬——每一步都要精确控制脚的位置和力度。
1.3 整体流程
环境配置 → 加载攀爬策略(climber) → 接触力仿真 →
策略交接(handoff) → 加载起身策略(getup) → 站稳验证 → ONNX导出 → BPU部署
Notebook 共 8 个步骤,从模型检查到板端部署,形成一条完整的可复用流程。
二、需要理解的名词概念
在深入技术细节之前,先统一"语言":
| 概念 | 大白话解释 | 在本文中的角色 |
|---|---|---|
| 策略(Policy) | AI 的"大脑",输入当前状态(61个数字),输出动作(14个关节角度) | 攀爬和起身各有一个策略 |
| ONNX | 一种通用的模型文件格式,让 AI 模型能在不同平台运行 | 把训练好的策略打包成可部署格式 |
| HBM | “Hardware Binary Model”——给 RDK 开发板用的编译后模型 | 相当于把 Python 编译成机器码 |
| BPU | “Brain Processing Unit”——RDK 开发板上的 AI 专用芯片 | 专门跑神经网络推理的小芯片 |
| MuJoCo | 物理仿真引擎,模拟重力、碰撞、摩擦等物理效果 | 充当机器人的"身体"和"世界" |
| 接触力(Contact Force) | 脚和梯子横档之间的力 | 法向力=支撑力,切向力=摩擦力 |
| 策略交接(Handoff) | climber 爬到顶后,自动切换到 getup 的过程 | 本文核心机制之一 |
| 闭环(In-the-loop) | 每个控制周期:读观测→AI推理→执行动作→物理更新→下一周期 | 真实反馈循环 |
| 61维观测 | AI 每次"看到"的信息:身体姿态、速度、关节角度等 61 个数字 | 策略的输入 |
| 14维动作 | AI 每次"做出"的决策:14 个关节的目标角度 | 策略的输出 |
| MDP | “Markov Decision Process”——马尔可夫决策过程,强化学习的数学框架 | 定义状态、动作、奖励 |
| 奖励函数(Reward) | 告诉 AI "什么行为是好的"的评分机制 | 本文核心机制之一 |
| 课程训练(Curriculum) | 先学简单的,再学难的,循序渐进 | 从有支撑板到无支撑板 |
三、攀爬和起身,这两个动作分别是如何学会的?
3.1 不是"一个策略包打天下"
很多人会想:为什么不训练一个策略,让它既能爬梯子又能站起来?
答案是:两个任务的物理状态差异太大。
- 攀爬时:鸭子身体前倾,重心在梯子方向,脚在横档上交替踩踏
- 起身时:鸭子身体从趴着变成直立,重心从低到高,脚从悬空到踩实桌面
如果让一个策略同时学这两件事,它会在两种状态之间"精神分裂"——既学不会爬,也学不会站。
工程上的做法:拆成两个独立策略,各学各的,然后在合适的时机交接。
3.2 攀爬策略(climber)是怎么训练的?
数据来源:社区开源项目 HannesVonEssen/microduck-climb,提供了完整的训练代码、checkpoint 和 ONNX 模型。
训练框架:基于 PPO(Proximal Policy Optimization)算法,在 MuJoCo 仿真环境中训练。
关键参数:
| 参数 | 值 | 说明 |
|---|---|---|
| 观测维度 | 61 | 身体姿态、速度、关节角度等 |
| 动作维度 | 14 | 14 个可控关节的目标角度 |
| 控制频率 | 50 Hz | 每秒做 50 次决策 |
| 仿真频率 | 200 Hz | 每秒推进 200 步物理仿真 |
| 并行环境数 | 64 | 64 个仿真环境同时训练 |
| 训练迭代 | 4000+ | 每轮采样 + 策略优化 |
训练过程:
初始化策略(随机动作)
↓
在 64 个并行环境中同时试错
↓
每步计算奖励(爬得越高越好、脚踩得越准越好)
↓
PPO 算法更新策略参数
↓
重复 4000+ 轮,直到策略稳定
↓
导出 ONNX 模型
3.3 起身策略(getup)是怎么训练的?
训练起点不同:getup 不是从零开始学的,而是用预训练 checkpoint 续训。
预训练 checkpoint(已经学会基本站立)
↓
在"翻到桌面后趴着"的初始状态下续训
↓
奖励函数:身体直立 + 双脚踩实 + 不滑动
↓
训练到稳定起身
↓
导出 ONNX 模型
为什么用预训练? 因为从零学"从趴着到站立"太难了——初始状态离目标状态太远,随机探索几乎不可能碰巧学会。用预训练 checkpoint 相当于"站在巨人的肩膀上",只需要微调就能学会。
3.4 两个策略的接口完全一致
虽然功能不同,但 climber 和 getup 的输入输出完全一样:
输入:obs[1, 61] → 61 维观测向量
输出:action[1, 14] → 14 维关节目标角度
这意味着切换策略时,不需要改变仿真环境的接口——只需要把推理的模型从 climber.onnx 换成 getup.onnx 就行。
四、接触力控制是如何做到的?
4.1 核心原则:不直接控制力,而是引导 AI 学会正确的接触方式
这是很多人容易误解的地方。代码里没有一行代码直接设置"脚和横档之间应该有多大的力"。
取而代之的是:通过奖励函数引导 AI 自己学会正确的接触方式。
4.2 五个奖励函数,五个"老师"
老师 1:路径进度奖励(ladder_path_progress)
# 伪代码
progress = 0.75 × 水平进度 + 0.25 × 垂直进度
reward = 当前progress - 上次progress
大白话:鸭子每往前/往上移动一点,就给奖励。75% 看水平进度,25% 看垂直进度。
效果:鼓励鸭子沿着梯子方向前进,而不是原地打转或往回走。
老师 2:高度进度奖励(ladder_height_progress)
# 伪代码
height_progress = (当前高度 - 起始高度) / (桌面高度 - 起始高度)
reward = 当前progress - 上次progress
大白话:专门奖励"往上爬"。鸭子每升高一点,就给奖励。
效果:和路径进度配合,确保鸭子既往前又往上,而不是只往前不往上(比如沿着地面跑)。
老师 3:脚部对齐奖励(ladder_foot_alignment)——接触控制的核心
这是最复杂也最重要的一个奖励函数:
# 伪代码
# 1. 计算每只脚到最近横档的距离
rung_error = sqrt((沿梯子方向偏差)² + (垂直方向偏差)²)
# 2. 计算三个维度的得分
score = exp(-(横向偏差/0.045)²) # 脚不能偏出梯子两侧(4.5cm以内)
× exp(-(左右偏差/梯宽)²) # 脚不能超出梯子宽度
× exp(-(rung_error/0.065)²) # 脚必须靠近某个横档(6.5cm以内)
# 3. 加一个"门控":只有进入梯子区域才生效
score *= gate # 梯子入口前=0,梯子上=1,桌面后=0
大白话:
这个函数在告诉 AI:“你的脚应该踩在横档上”。怎么判断?
- 横向偏差:脚不能偏出梯子两侧(左右 4.5cm 以内)
- 纵向偏差:脚必须靠近某个横档(6.5cm 以内)
- 门控机制:只有鸭子真正进入梯子区域,这个奖励才生效
效果:AI 通过几万次试错,最终学会"把脚放到横档上"。一旦脚放对了,MuJoCo 物理引擎自然算出正确的接触力。
老师 4:脚部滑动惩罚(foot_slip)
cfg.rewards["foot_slip"].weight = -0.2
大白话:脚在接触面上滑动,扣分。
效果:鼓励 AI 学会"踩稳",而不是"脚底打滑"。
老师 5:脚部离地惩罚(foot_clearance)
cfg.rewards["foot_clearance"].weight = -0.5
大白话:脚抬太高,扣分。
效果:鼓励 AI 学会"贴着横档走",而不是"高抬腿"浪费能量。
4.3 物理引擎的角色
MuJoCo 负责:
- 计算脚和横档之间的真实碰撞(法向力、摩擦力)
- 判断是否滑落(摩擦力不够时自然滑落)
- 判断是否卡住(脚卡在两根横档之间)
AI 负责:
- 输出 14 个关节的目标角度
- 通过奖励函数引导,学会"把脚放到正确位置"
两者配合:
AI 输出动作 → MuJoCo 算物理 → 反馈新的状态 → AI 再输出
↑ ↓
└──────────────── 闭环循环 ────────────────────┘
这就是"闭环"——AI 不是在一开始就知道所有答案,而是在和物理世界的持续互动中,不断调整自己的行为。
4.4 梯子几何的真实建模
V2 版本按参考视频中的空间关系重做了梯子几何:
| 组件 | 描述 | 碰撞属性 |
|---|---|---|
| 两根斜梁 | 矩形截面,沿斜面布置 | 真实碰撞几何 |
| 14 根横档 | 密集排列,间距约 5cm | 真实碰撞几何 |
| 顶部平台(桌面) | 四条腿支撑 | 真实碰撞几何 |
| 梯脚落地木块 | 防止梯子看起来像浮在空中 | 真实碰撞几何 |
| 桌后方的椅子 | 视觉装饰,不影响物理 | 不参与碰撞 |
关键设计:所有梯梁、横档、桌面和梯脚都是真实 MuJoCo 碰撞几何,不是"看起来像"的视觉模型。这意味着 AI 在训练中感受到的物理反馈,和真实世界中是一样的。
五、双策略交接是如何做到的?
5.1 为什么需要交接?
想象你爬梯子到桌面后:
- climber(攀爬策略):擅长一级一级往上踩,但它的"世界观"里只有梯子,不知道到了桌面该怎么办
- getup(起身策略):擅长从趴着变成站着,但它不会爬梯子
所以必须两个策略接力:climber 爬到顶 → 切换 → getup 把鸭子拉起来站稳。
5.2 交接的触发条件
代码里有一个叫 foot_desktop_eligible 的函数,它判断"是否可以交棒了"。条件有三个,必须同时满足:
条件1:脚碰到了桌面
条件2:身体已经在桌面范围内
条件3:持续了至少 1 个控制步(约 0.02 秒)
条件1:脚碰到了桌面
用 MuJoCo 的物理引擎检测:鸭子的左脚或右脚,是否和桌面(tread_31/desktop)发生了真实碰撞(距离 ≤ 0)。
不是"差不多到了",是物理引擎真的算出脚和桌面接触了。
条件2:身体已经在桌面范围内
鸭子的身体重心,必须在桌面的矩形范围内(前后左右都算),而且高度要超过 0.66(说明已经翻上来了,不是还在梯子上)。
条件3:持续了至少 1 个控制步
不能是"一瞬间碰到就切换",必须稳定接触至少 1 步,防止误触发。
5.3 切换的完整流程
关键代码在 OfficialPair.step() 里,用大白话翻译:
# 步骤1:记忆机制
# 把"上一步做了什么动作"塞回输入的 34-48 槽位
observation[34:48] = self.raw
# 这样策略知道"我刚才在干嘛",不会突然懵掉
# 步骤2:状态机切换
self.recovering = self.recovering or eligible
# 一旦 eligible=true,就永久进入 getup 模式
# 不会"切过去又切回来"
# 步骤3:推理
if self.recovering:
self.raw = self.getup.infer(observation) # 用 getup 策略
else:
self.raw = self.climber.infer(observation) # 用 climber 策略
# 步骤4:柔顺过渡
if self.recovering:
# getup 输出不是直接用的,而是和"上一步的动作"做加权平均
self.executed = alpha × self.raw + (1-alpha) × self.executed
# 腿用 alpha=0.7,头颈用 alpha=0.5
# 这样过渡是平滑的,不会"咔"一下突然换动作
四个关键设计:
| 设计 | 作用 | 如果不做会怎样 |
|---|---|---|
| 记忆机制 | 让策略知道上一步做了什么 | 切换后策略"失忆",动作不连贯 |
| 单向切换 | 一旦切换永不回头 | 可能在两个策略之间反复横跳 |
| 柔顺过渡 | 动作平滑过渡 | 突然换动作,鸭子可能摔倒 |
| 不同 alpha 值 | 腿 0.7,头颈 0.5 | 头颈过渡太慢影响视觉,腿过渡太快影响平衡 |
5.4 怎么验证交接成功?
不是"触发了切换"就算成功。代码里还有一个 desktop_standing 函数,要求:
| 条件 | 阈值 | 大白话 |
|---|---|---|
| 双脚都在桌面上 | all(feet) | 两只脚都踩稳了 |
| 身体在桌面范围内 | inside_desktop | 没掉下去 |
| 重力方向朝下 | gravity_z < -0.82 | 身体是直立的,不是歪的 |
| 线速度 < 0.25 | linear_speed | 没在滑动 |
| 角速度 < 2.5 | angular_speed | 没在旋转 |
| 稳定持续 ≥ 2 秒 | stable_seconds >= 2.0 | 不是"碰巧站稳一瞬间" |
大白话:必须"双脚踩稳 + 身体直立 + 不滑动 + 不旋转 + 保持 2 秒以上",才算真正成功。
六、总结与启发
6.1 核心设计哲学
| 机制 | 实现方式 | 设计哲学 |
|---|---|---|
| 双策略交接 | 物理接触检测 + 状态机 + 平滑过渡 | 不硬编码切换时机,让物理世界告诉 AI 何时切换 |
| 接触力控制 | 奖励函数引导 + MuJoCo 物理仿真 | 不直接控制力,而是告诉 AI “脚应该在哪” |
| 成功验证 | 多条件组合 + 持续时间 | 不是"触发了"就算成功,必须"稳定保持" |
6.2 对工程实践的启发
- 拆分比统一好:两个差异大的任务,拆成两个策略比一个策略包打天下更有效
- 引导比控制好:用奖励函数引导 AI 学会正确行为,比硬编码规则更灵活
- 物理真实性很重要:所有几何体都用真实碰撞模型,仿真结果才能迁移到真实世界
- 交接需要平滑:策略切换不是"咔"一下换,而是加权平均的柔顺过渡
- 验证要全面:不是"触发了"就算成功,必须多条件组合 + 持续时间
6.3 下一步
如果你想动手试试:
- 修改梯子间距:测试不同梯级距离对策略的影响
- 添加滑动:模拟湿滑梯面,测试策略的鲁棒性
- 对比不同模型:原模型 vs ONNX vs BPU,看精度和速度差异
- 部署到真机:如果有 RDK 开发板,尝试板端推理
作者:华仔,39 岁技术人,正在探索 AI 赋能个人工作流的第二曲线。
课程来源:Datawhale 具身智能组队学习 — MicroDuck 运动策略与任务开发专题,第 6 课"梯面攀爬"。
模型来源:HannesVonEssen/microduck-climb — 社区开源的攀爬/起身策略、ONNX、PPO 检查点、训练代码和梯子模型。
如果你对具身智能、AI Agent、个人助手建设感兴趣,欢迎交流。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/xiaojia1001/article/details/169269046




