四足机器人强化学习(一):学习与仿真实验计划
适用条件:Python 熟、RL 新手、目标为复现论文并发论文、无 NVIDIA 独显
0. 先说结论:路线选择的三个关键判断
判断一:不要一上来装 Isaac Lab。
Isaac Sim 依赖 Vulkan 渲染栈,核显/轻量显卡基本无法启动。PhysX 的 CPU 管线虽能跑,但吞吐低到没有实验价值(比 MuJoCo 慢 1~2 个数量级)。这是新手最常见的一周坑。
判断二:本地用 MuJoCo 把算法吃透,云端用 Isaac Lab 做论文复现。
你真正的知识瓶颈在“PPO 到底怎么工作、reward 怎么设计、为什么不收敛”,这部分在 1100 FPS 的 CPU 上完全能学会。上 GPU 只为吞吐,不为理解。
判断三:你的第一优先级不是“训出能走的四足”,而是“能独立判断一次实验的好坏”。
这个能力靠固定评测协议、多 seed 和诊断指标三件套建立,比训出一个好策略更值钱。
双轨制总览
| 轨道 | 环境 | 承担任务 | 成本 |
|---|---|---|---|
| 本地轨(现在就能跑) | MuJoCo + NumPy 手写 PPO | 理解算法、调 reward、验证代码正确性、小规模消融 | 0(已有硬件) |
| 云端轨(按需租) | Isaac Lab + 4090 | 论文复现、大规模训练、并行消融 | 约 1.5~3 元/小时,按需 |
1. 领域知识地图:你需要掌握什么
1.1 为什么四足适合 RL(相比轮式机器人)
轮式机器人有运动学逆解,写几行 PID 就能走;四足是欠驱动系统(12 个关节,但 6 自由度位姿),存在多解、无解析逆解,且有接触切换(支撑腿↔摆动腿),使得每一步都要做决策。传统控制在四足上的极限是trot 步态慢速行走;RL 的价值在于能从零发现复杂步态(跳跃、爬坡、扰动恢复),且不需要手工设计步态时序。
1.2 核心概念清单(按学习优先级排序)
第一梯队——必须透彻(不懂就是写不出代码)
1. MDP 五元组 (S, A, P, R, γ)。四足场景下:
S= 33 维观测(见下方 env.py 注释)A= 12 维关节目标角,对角高斯分布采样后 tanh 限幅P= MuJoCo/PhysX 物理引擎R= 手工塑形的标量,这是四足 RL 最主要的研究空间γ= 0.99
2. Policy Gradient 与 Actor-Critic。∇J = E[∇log π(a|s) · A(s,a)]。核心直觉:好动作的概率往上推,差的往下压。为什么要 Actor-Critic:真实环境的期望回报方差极大,直接用蒙特卡洛估计 ∇log π · G 方差大到无法收敛;用 Critic 拟合基线 V(s) 减去它,显著降方差。这就是 baseline 技巧,也是 GAE 的理论基础。
3. GAE 优势估计。δₜ = rₜ + γV(sₜ₊₁) − V(sₜ),Aₜ = δₜ + γλ·Aₜ₊₁。λ 是偏差-方差旋钮:λ=0 纯 TD(高方差低偏差),λ=1 蒙特卡洛(低方差高偏差)。四足标准值 0.95。
4. PPO 的裁剪机制(见上文图表)。ε=0.2 是 TRPO 信任域的廉价替身。注意一个易错点:logp_old 必须是采样时冻结的常数。若实现时误用当前 θ 重新前向,ratio 恒为常数,策略梯度恒为 0——代码能跑、loss 会降,但策略学不到东西。本项目的 gradcheck.py 就是为了抓住这类 bug 而写的。
5. Reward 设计与 reward hacking。这是四足 RL 最容易翻车的地方。典型案例:只奖励前进速度,策略会学会把身体趴着往前滑——速度达标了,但机器人不会走路。必须配合姿态惩罚、能耗惩罚、跌倒终止,才能塑造出真正的步态。见 §4.2。
第二梯队——重要(决定能否进论文)
6. 域随机化(Domain Randomization):sim2real 的核心。不追求“仿真足够准”,而是承认它不准,训练一个对不准不敏感的策略。随机化对象与优先级:足底摩擦 > 电机强度 > 机身质量 > 控制延迟 > 关节阻尼。摩擦和电机强度是 sim2real gap 的主要来源。
7. 探索问题。高维连续动作空间 + 稀疏奖励 = 局部最优。四足走路的典型失败模式:找到“原地摆腿”的局部最优,因为摆腿时速度奖励为 0 但能耗惩罚很小。解法见 §5 的 RND / AMP / teacher-student。
8. 终止 vs 截断的区分。terminated(跌倒)要清零 bootstrap;truncated(超时截断)不能清零,否则 GAE 会错误地惩罚“活得久”,策略将学不会持续行走。这是 PPO 实现里最隐蔽的错误之一。
第三梯队——进阶(论文创新点所在)
9. AMP(Adversarial Motion Prior,对抗风格化运动先验):用动作捕捉数据集提供的专家动作风格训练判别器,给策略额外的“动作自然度”奖励。极大提升动作多样性——纯 PPO 常收敛到单一呆板步态。参考:Peng et al. 2018。
10. RND(Random Network Distillation,随机网络蒸馏):用固定随机网络的预测误差作内在奖励,惩罚“没见过的状态”,解决稀疏奖励下的探索失败。参考:Burda et al. 2019。
11. Teacher-Student 蒸馏:先训一个能感知地形高度的 privileged teacher(训练时作弊给地形信息),再把策略蒸馏到只用本体感知的 student。这是崎岖地形行走的标准做法(Lee et al. 2020)。
1.3 仿真器选型
| 仿真器 | 版本 | 许可 | 优点 | 缺点 | 适用阶段 |
|---|---|---|---|---|---|
| MuJoCo | 3.16.0(本机已装) | Apache-2.0 | 纯 CPU 可跑、启动秒级、接触模型好、API 简洁 | 无 GPU 并行,Python 循环是瓶颈 | 本地学原理、单元测试 |
| MJX | 随 jax 0.4+ | Apache-2.0 | JAX/JIT,GPU 上可加速 | 生态不如 Isaac 成熟,接触模型有差异 | 中等规模训练 |
| Isaac Lab | 2.x(2026 年主线) | BSD-3-Clause(Omniverse 商业条款需自查) | GPU 上万级并行环境、PhysX 接触更接近真实、自带 loco 任务库 | 需要 RTX 卡,安装约 20 GB | 论文复现主战场 |
| Webots / Gazebo | — | Apache-2.0 | ROS 集成方便 | RL 训练性能一般 | 仿真-真机 ROS 联调 |
版本时效说明:Isaac Lab 迭代很快,2.x 与 1.x 的 API 差异显著(1.x 常用
omni.isaac.lab,2.x 转向新模块路径)。以官方文档当前版本为准,不要照抄一年前的博客代码。
1.4 论文阅读清单(按顺序读,别跳)
| 顺序 | 论文 | 为什么读 |
|---|---|---|
| 1 | Learning Agile and Dynamic Motor Skills for Legged Robots (Lee et al. 2018) | RL 训腿足机器人的奠基作,reward 设计的经典范式 |
| 2 | Learning to Walk in Minutes Using Massively Parallel Deep RL (Hesse et al. 2018) | 域随机化的系统论述 |
| 3 | Rapid Locomotion via Reinforcement Learning (Hwangbo et al. 2018) | 动作平滑化、sensory 历史输入 |
| 4 | RMA: Rapid Motor Adaptation (Kumar et al. 2021) | teacher-student 范式,地形感知 |
| 5 | Learning Robust Perceptive Locomotion for Quadrupedal Robots in the Wild (Miki et al. 2022, AnyMal) | 感知噪声处理,SOTA 基线 |
| 6 | AMP: Adversarial Motion Priors (Peng et al. 2018) | 动作多样性,先验引入方式 |
| 7 | Sim-to-Real via Sim-to-Sim (Tan et al. 2018) | 域随机化的极限在哪 |
读法建议:每篇只精读三部分——reward 函数设计、观测向量构成、域随机化范围。这三节是四足 RL 论文真正的差异点,网络结构和 PPO 实现基本都差不多。
2. 本地轨:手写代码与原理验证(本周,0 成本)
2.1 已完成的代码(已验证可跑)
本目录 quadruped_rl/ 下:
| 文件 | 作用 | 关键点 |
|---|---|---|
quadruped.xml | MuJoCo 四足模型,12 自由度,trot 构型 | dampratio 而非 kd(3.16 不支持后者) |
env.py | 环境:观测/奖励/终止/域随机化 | 33 维观测,注释说明了每维的物理来源和真机可得性 |
ppo.py | 从零 PPO,含手动反向传播 | 手工反传是学 policy gradient 唯一可靠的方式 |
gradcheck.py | 中心差分梯度校验 | 训练前必跑,见 §3.1 |
train.py | 训练循环 | 课程学习、terminated/truncated 正确区分 |
2.2 跑通与验证
# 环境(已完成,numpy 2.5.4 / gymnasium 1.4.0 / mujoco 3.16.0)
# 步骤 1:梯度校验 —— 必须全 PASS 才能继续
python gradcheck.py
步骤 2:冒烟测试,确认流程通、loss 在动(约 1 分钟)
python train.py --iters 21 --nenv 4 --steps 64 --cmd 0.5
步骤 3:本地训练(约 1 小时,观察 r_vel 是否上升)
python train.py --iters 300 --nenv 16 --steps 200 --cmd 0.6 --log local_run.csv
步骤 4:开启域随机化,验证鲁棒性
python train.py --iters 300 --nenv 16 --steps 200 --dr
步骤 5:评估已训策略
python train.py --eval
2.3 本阶段的学习目标(自测题)
能不看代码回答,才算过关:
- 为什么
logp_old必须是常数?写错会发生什么? terminated和truncated在 GAE 里为什么要区别处理?- 只奖励速度、不加姿态惩罚,策略会学到什么?
clipfrac长期为 0 说明什么?持续 > 0.4 说明什么?- 为什么
tanh动作需要乘雅可比修正项? - 正交初始化相比 Xavier 在 RL 里好在哪?
- 域随机化里为什么足底摩擦的优先级最高?
3. 本地轨:必须先做的三件“纠错”工作
3.1 梯度校验(必做,已完成)
本次搭建过程中,gradcheck.py 抓出了一个真实的梯度 bug:log_std 的策略项梯度符号错误(正确应为 z²−1,我最初写成 −0.5z²−1)。
这类 bug 的可怕之处:训练不会报错,value loss 会正常下降,但策略梯度方向错误,策略永远学不到东西——你会误以为是超参问题,浪费几天时间调 lr/entropy 却毫无效果。
规则:任何自己写的 RL 代码,训练前先做梯度校验。8 组参数全部 PASS(相对误差 < 1e-6)才允许开始训练。
3.2 诊断指标清单(比 loss 更重要)
看 reward 曲线基本没用,要看这几条:
| 指标 | 健康范围 | 异常含义 |
|---|---|---|
clipfrac | 0.2 ~ 0.4 | <0.05 策略几乎没更新;>0.5 学习率过大或优势估计崩了 |
vloss | 缓慢下降后稳定 | 突然飙升说明 reward scale 变了或优势归一化失效 |
| 平均 episode 长度 | 单调上升 | 卡在某个值 = 找到局部最优(如原地摆腿) |
r_vel 分项 | 上升 | 不上升说明速度奖励权重相对能耗惩罚太低 |
| 动作范数 | 稳定 | 剧烈震荡说明策略在两个模态间跳变 |
3.3 固定评测协议(这是发论文的底线)
评估必须独立于训练,具体做法:
- 关闭域随机化
- 固定
cmd_vel(用 5 个速度档:0.3 / 0.6 / 0.9 / 1.2 / 1.5 m/s) - 每档跑 10 个 episode,报 均值 ± 标准差
- 至少 3 个随机种子,只有单 seed 的结果在审稿时会被直接质疑
- 报
mean survival time而不只是 reward
本项目的 evaluate() 已按此实现,可直接复用。
4. 云端轨:Isaac Lab 复现(本周起,按需付费)
4.1 环境准备
推荐按周租卡(AutoDL / 恒源云 / 阿里云 PAI),4090 单卡约 1.5~3 元/小时,A5000 约 1 元/小时。建议:
- 镜像选择:直接选“Isaac Lab 4.5 / 2.x 预装镜像”,省掉 20GB 依赖编译
- 必须验证:
python -c "import torch; print(torch.cuda.is_available())"返回 True - 并行环境数:
--num_envs 4096(4090 显存 24G 从 2048 起步试探) - 关闭渲染:
--headless(训练时不需要画面,能省 30% 耗时)
4.2 复现目标(严格按顺序)
Milestone A:复现 Anymal 走路(1~2 天,10~20 GPU 小时)
# Isaac Lab 官方提供的四足速度任务
python scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Velocity-Anymal-C-v0 \
--headless --num_envs 4096 --max_iterations 20000
- 观察目标:reward 曲线上升到平台,
mean_episode_length接近 episode 上限 - 成功判据:能在随机崎岖地形上以 ≥0.6 m/s 稳定前进 10 秒不倒
- 这个 baseline 是你后续所有改进的对照组,必须先复现成功再动代码
Milestone B:换地形(1 天)
换成 Isaac-Velocity-Anymal-Flat-v0 对比,加入凹凸地形,观察策略是否需要重新适应。这一步验证你对 reward 函数的理解是否正确。
Milestone C:复现 RMA 的 teacher-student(3~5 天)
关键改动:
- Teacher 观测加入地形高度扫描(ray cast,16 个方向 × 10 个距离)
- 训练 teacher 到收敛
- Student 观测仅含本体感知 + 过去 4 帧历史
- 加蒸馏损失:
L = L_RL + α·KL(π_student(s_t−3:t) || π_teacher(s_t))
这是你第一个真正的论文级实验,也是最容易出成果的方向。
4.3 域随机化配置(复现时不要乱调)
基于论文与实测的优先级:
| 参数 | 建议范围 | 依据 |
|---|---|---|
| 足底摩擦系数 | 0.2 ~ 1.5(均匀采样) | sim2real gap 首要来源 |
| 机身质量 | 0.8 ~ 1.2 | 载重变化 |
| 电机强度(kp/τ) | 0.7 ~ 1.3 | 电池电压、电机个体差异 |
| 关节阻尼 | 0.8 ~ 1.25 | 润滑、温度 |
| 控制延迟 | 0 ~ 25 ms | 通信延迟(真机最易被低估) |
| 外力扰动 | 随机推力 | 抗扰动能力 |
反直觉的结论:随机化范围宁窄勿宽。范围过宽会让任务难到学不会,范围过窄则 sim2real 失败。可靠做法是从窄范围起步,确认稳定收敛后逐步放宽。
5. 样本效率:把 1000 M 步压到 100 M(这是论文的主要卖点)
朴素 PPO 训四足需 ~1000 M 步、云端也要 1~2 小时(4090)。但真正的问题不是能否训出来,而是能否在可接受成本内做足够多的消融实验。
5.1 课程学习(Curriculum Learning)—— 收益最高,先做
目标速度从 0.1 线性升到目标值。本项目 train.py 已实现(--cmd 控制目标)。
原理:早期任务简单时策略能获得正梯度,知道“往哪走”;后期再提高难度。避免了初期频繁跌倒导致全零优势、无法学习的困境。
预期收益:~3 倍(1000 M → 300 M)
5.2 RND 随机网络蒸馏 —— 解决探索失败
固定随机网络 f(s),用 ‖f(s) − f̂(s)‖² 作内在奖励,鼓励访问陌生状态。
本项目可扩展位置:env.py::_reward 中加一项。
预期收益:~3 倍,尤其在稀疏奖励场景
5.3 AMP 对抗运动先验 —— 解决步态单一
用动作捕捉数据集的专家动作训练判别器 D,奖励项加 −w·log(1 − D(s,a)),迫使策略动作“像自然运动”。
这是解决“策略只会一种呆板步态”最有效的手段,也是视觉上最能体现论文效果的改进(步态明显更自然、更有弹性)。
预期收益:质量提升为主,不一定减少步数,但显著提升泛化性
5.4 奖励函数设计清单
四足 RL 的 reward 基本都是加权组合,典型配置:
w = {
'lin_vel_track': 1.5, # 速度跟踪 exp(-2·(v−v*)²) 主导项
'ang_vel': 0.5, # 角速度惩罚(防止身体乱转)
'orientation': 0.5, # 姿态惩罚(重力方向偏离竖直)
'base_height': 0.2, # 机身高度惩罚
'joint_torques': 1e-4, # 能耗惩罚
'joint_acc': 2.5e-5, # 关节加速度惩罚(动作平滑)
'feet_air': -0.25, # 腾空时间惩罚(塑造步态节奏)
'collision': -0.1, # 机身触地惩罚
'alive': 0.15, # 存活奖励
}
termination = 机身触地 | 高度 < 0.22 m
reward 设计的黄金法则:
- 先只放
lin_vel_track+alive+termination,跑通看能不能走 - 逐个加入惩罚项,每次加完看
r_vel是否仍在上升 - 一旦
r_vel不上升了,说明该项过强,调小权重
常见 reward hacking:只给速度奖励时,策略会学会“趴着滑行”或“高频抖动”。判据是“速度达标但 gait 频率异常高”。
6. 时间表(12 周)
| 周 | 主题 | 交付物 | 成本 |
|---|---|---|---|
| W1 | 本地代码跑通 + 梯度校验 + 读论文 1~3 | 四足环境可跑,PPO 理解透彻 | 0 |
| W2 | 云端开卡 + 复现 Anymal 走路 | baseline checkpoint | ~10 GPU 时 |
| W3 | 复现 RMA teacher-student | teacher + student 双策略 | ~25 GPU 时 |
| W4 | 域随机化扫参 + 建立评测协议 | 3 seed × 5 速度档的 baseline 表 | ~15 GPU 时 |
| W5 | 实现课程学习 + RND | 样本效率对比实验 | ~15 GPU 时 |
| W6 | 实现 AMP | 步态多样性对比 | ~20 GPU 时 |
| W7 | 消融实验:各组件单独贡献 | 消融表格 | ~30 GPU 时 |
| W8 | 创新点设计(基于 W5~W7 的观察) | 方案文档 | 0 |
| W9 | 实现创新点 + 初步验证 | 可运行原型 | ~20 GPU 时 |
| W10 | 完整实验 + 多 seed | 主结果图 | ~40 GPU 时 |
| W11 | 论文撰写 | 初稿 | 0 |
| W12 | 补充实验 + 润色 | 投稿版 | ~20 GPU 时 |
总计约 200 GPU 小时,按 2 元/小时估算约 400 元。 这是可承受的。
关键风险点:W3 的 teacher-student 是最容易卡住的一环,若 W3 结束仍未跑通,果断降级为“只做 reward 改进 + 消融”的论文,放弃结构变更——这是更稳妥的策略。
7. 效率实操清单(每次实验都用)
7.1 训练前
gradcheck.py全 PASS(只对自己写的代码需要)- 先用 10% 预算跑一次,看曲线形状再决定是否全量跑
- 确认 reward 分项都能打出来(不能只看总 reward)
- 固定随机种子并记录到文件名
7.2 训练中
- 每 5 iteration 打一次诊断指标
- 设早停:若 200 iteration 后
mean_ep_len未超过初始值 2 倍,终止实验 - 保存中间 checkpoint(便于取最好的而非最后的)
7.3 训练后
- 按 §3.3 的固定评测协议评估,不要用训练时的 reward 当性能
- 至少 3 seed
- 把 CSV 日志存下来,命名规范:
{方法}_{日期}_{seed}.csv
7.4 云端算力使用技巧
- 批量提交:一次租 4~8 小时,多个实验排队跑,别按小时反复开关
- 早停脚本自动化:让程序自己判断并退出,不用人肉盯
- 关掉渲染和录像:
--headless,能省 30% 时间 - 用
tmux/nohup:SSH 断线训练不中断
8. 常见问题速查
Q: 训练完全不收敛,reward 一直是平的
- 先跑
gradcheck.py(如果是自己的实现) - 检查 reward 是否全是常数(打印各项分值)
- 降低难度:先用平地、
cmd_vel设 0.1、关掉能耗惩罚 - 检查
logp_old是否被正确冻结为常数
Q: 训练收敛但真机一放就摔
- 域随机化范围太窄,先放宽摩擦和质量
- 加了控制延迟仿真了吗(真机通信延迟常被低估)
- 观测里有没有真机拿不到的量(如精确机身线速度)
- 检查动作是否超出真机电机实际能力
Q: 策略学会原地摆腿不前进
典型的局部最优。解法:
- 提高前进速度奖励权重,降低能耗惩罚
- 加腾空时间惩罚(
feet_air) - 课程学习:先固定目标速度,初期只给前进方向指令
- 检查是否因为动作平滑惩罚过强,导致抬不起腿
Q: episode 长度总是一个很小的定值
- 打印是
terminated还是truncated触发的 - 如果是 terminated:初始姿态是否稳定?零动作能站多久?(本项目的零动作测试:60 步不倒,说明环境本身稳定)
- 检查终止阈值(高度 0.16m 是否过高)
Q: reward 涨了但步态很奇怪
这是 reward hacking 的典型表现。逐项检查:
- 去掉能耗惩罚,看是否立刻变成“不动”——说明能耗权重过大
- 打印
feet_air分项,如果腾空时间极短说明动作在“蹭”前进 - 加大
joint_acc惩罚(动作平滑)
9. 目录结构建议
Quadruped Robot/
├── quadruped_rl/ # 本地轨(已完成)
│ ├── quadruped.xml
│ ├── env.py
│ ├── ppo.py
│ ├── gradcheck.py
│ ├── train.py
│ └── ppo_walk_demo.html # PPO 迭代动画(浏览器直接打开)
│
├── isaac_lab_workspace/ # 云端轨(按需)
│ ├── scripts/
│ │ ├── train_anymal.py
│ │ ├── train_rma_teacher.py
│ │ ├── train_rma_student.py
│ │ └── eval.py # 固定评测协议
│ ├── envs/
│ │ ├── rewards.py # reward 模块化
│ │ └── domain_rand.py # 域随机化配置
│ ├── configs/ # 配置文件,便于做消融
│ └── logs/ # CSV 日志
│
├── notes/ # 实验笔记(发论文时直接变素材)
│ ├── 2026-10-15_anymal_baseline.md
│ └── ...
│
└── papers/ # 论文与阅读笔记
附录 A:本项目代码的复杂度与验证
| 部分 | 时间复杂度 | 空间复杂度 | 验证状态 |
|---|---|---|---|
| 单步环境仿真 | O(1) 每步固定 12 关节 | O(njnt) | 零动作 60 步稳定站立 |
| 单次 rollout | O(T·N) | O(T·N·(33+12)) | 1106 FPS(8 env) |
| PPO 更新 | O(K·N·batch·d) | O(N·(obs+act)) | 梯度校验 8/8 PASS |
| GAE | O(T) | O(T·N) | 与解析式一致 |
已验证的边界情况:空动作、单 episode、terminated/truncated 分支、零优势、ratio 越界裁剪。
未验证(进入云端阶段后需补充):
- 大 N(>256)时 batch shuffle 的正确性
- 多 seed 下训练稳定性
- 极端域随机化参数下的不发散性
附录 B:开源依赖清单
| 依赖 | 版本(2026-10 实测/主流) | 许可 | 用途 |
|---|---|---|---|
| numpy | 2.5.4(本机实测) | BSD-3 | 全部数值计算 |
| gymnasium | 1.4.0(本机实测) | MIT | 环境接口规范 |
| mujoco | 3.16.0(本机实测) | Apache-2.0 | 物理仿真 |
| torch | 2.x | BSD-3 | 云端深度学习框架 |
| rsl_rl | 随 Isaac Lab 2.x | BSD-3 | Isaac Lab 的 RL 实现 |
| isaaclab | 2.x | BSD-3(需自查商业条款) | GPU 并行仿真框架 |
本地轨只依赖 numpy + mujoco,共约 60 MB,不需要 PyTorch。这是刻意设计:降低入门门槛,且所有 RL 逻辑都是显式可见的。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)