问题背景
平地 locomotion 训练里,有时会看到一个很典型的坏习惯:机器人在平地上走着走着,某条腿或某几条腿明显“翘起来”,看起来像在主动抬腿、拖腿、单腿悬空,甚至形成不自然的跳步。
这类现象不一定是 policy “不会走”,更常见是 reward 组合给了它一个可钻的空子:
速度跟踪奖励够高 |
这篇整理一下:如果目标是平地稳定行走,不希望无意义翘腿,四足机器人强化学习里哪些 reward 最值得优先检查和调整。
先看官方基线怎么做
以 legged_gym / Isaac Lab 的 velocity tracking 任务为参考,常见 reward 结构大概是:
tracking_lin_vel # xy 线速度跟踪,正奖励 |
legged_gym 默认 flat/rough locomotion 里,feet_air_time 是一个很关键的项:它奖励“长步幅/有节奏迈步”,但如果权重、阈值、门控条件不合适,也容易鼓励不必要的抬腿。
Isaac Lab 的 Anymal-C flat 配置里也能看到类似思路:平地任务会保留速度跟踪、姿态、力矩、feet air time 等项,同时平地版会关闭高度扫描和地形 curriculum。
一句话结论
如果平地出现“翘腿”,我会按这个优先级调:
1. 降低或重新门控 feet_air_time |
1. feet_air_time:最容易导致“翘腿”的 reward
feet_air_time 本意不是让机器人“把腿抬高”,而是避免拖着脚走,让机器人形成有步态周期的迈步。
在 legged_gym 里,它大致逻辑是:
contact = foot_contact_force_z > threshold |
这个设计有几个要点:
- 只在脚重新落地的瞬间给奖励;
- 奖励的是“腾空时间超过阈值”的部分;
- 速度命令很小时不给这个奖励;
- 接触检测如果噪声大,会影响这个 reward 的真实性。
如果平地翘腿明显,优先检查:
调参建议
1)降低 feet_air_time 权重
如果当前权重比较大,可以先降到原来的 1/2 或 1/4。
例如:
# legged_gym 风格 |
Isaac Lab flat 里 Anymal-C 示例曾把 flat 任务的 feet_air_time.weight 设置为 0.5;而通用 velocity rough cfg 中有更保守的 0.125。这说明这个项本来就需要按任务调,不能盲目套默认值。
2)提高触发门槛,而不是奖励无限抬腿
如果 reward 写成“脚越高越好”或“离地越久越好”,policy 很容易学成夸张抬腿。
更稳的写法是只奖励合理区间:
air_time 太短:可能拖脚,少奖励 |
可以把线性奖励改成 clipped reward:
air_time_good = torch.clamp(last_air_time - 0.20, min=0.0, max=0.25) |
也就是只鼓励“离地一小段时间”,不要鼓励一直悬空。
3)低速/零速命令下关闭 feet_air_time
这是非常关键的一条。
如果 command_xy 很小,机器人本来应该站稳或慢走,不应该为了拿 air-time 奖励而原地抬腿。
建议:
moving = torch.norm(commands[:, :2], dim=1) > 0.15 |
对于平地低速任务,可以把阈值从 0.1 提到 0.15 ~ 0.25 试试。
2. feet clearance:不要把“抬脚高度”奖励写得过强
很多项目会额外加 feet_clearance,鼓励摆动腿离地,避免拖脚。
这在崎岖地形上有用,但在平地上要小心:如果 clearance reward 太强,就会直接把 policy 推向“高抬腿”。
调参建议
平地建议把 clearance 写成目标区间,而不是越高越好:
目标:摆动腿离地 3~8 cm 足够 |
示例思路:
target = 0.05 # 5 cm |
如果已经有 feet_air_time,平地任务里可以先不加 clearance;如果必须加,权重要比速度跟踪、姿态稳定小得多。
3. feet_slide / contact stability:防止用奇怪接触骗速度
翘腿有时不是单独发生,而是伴随:
- 支撑脚在地上滑;
- 另一条腿长期悬空;
- 身体靠几条腿硬拖着走;
- 接触力尖峰很大。
这时应该补足接触稳定相关惩罚。
推荐检查项
1)脚滑惩罚 feet_slide
逻辑:脚在接触地面时,足端水平速度不应该太大。
contacts = contact_force_z > threshold |
如果平地走路像“溜冰”或“拖脚”,这个项很重要。
2)接触力过大惩罚 feet_contact_forces
legged_gym 里有类似项:超过 max_contact_force 的部分才惩罚。
penalty = sum(clip(norm(contact_force) - max_contact_force, min=0)) |
这能减少用砸地、跳步换速度的策略。
3)非足端碰撞 collision / undesired_contacts
如果大腿、小腿、机身碰地,应该惩罚或直接 reset。
平地翘腿如果伴随大腿乱甩,这项会很有用。
4. 姿态与高度:让身体没有理由通过翘腿维持奇怪姿态
平地行走的身体应该相对稳定。需要重点看这几项:
lin_vel_z # base 垂向速度惩罚 |
调参建议
1)增强 orientation / flat_orientation_l2
Isaac Lab 的 Anymal-C flat 配置里,flat_orientation_l2.weight = -5.0,比 rough 任务更强调平地姿态稳定。
如果身体晃动很大,或者靠倾斜身体换步态,可以增强这个项。
2)打开或增强 base_height
legged_gym 默认里 base_height 有时权重是 0。若平地出现蹲低、翘腿、跳步,可以加入身体高度目标。
base_height_target = nominal_stand_height |
注意:高度目标不要太死,否则会牺牲自然步态。可以先用小权重。
3)不要只靠高度惩罚解决翘腿
翘腿是足端/步态问题,base_height 只能约束身体,不一定能直接约束腿。更推荐和 feet_air_time、feet_slide、action_rate 一起调。
5. 动作平滑与能耗:抑制“猛抬腿”
如果 policy 抬腿动作很突兀,通常要看:
action_rate # 相邻 action 差分 |
调参建议
1)先调 action_rate
action_rate 对抑制动作跳变很直接。
penalty_action_rate = sum((last_action - action)^2) |
如果机器人突然抽腿、抖腿,可以把权重从 -0.01 往 -0.02、-0.05 试。
2)再调 dof_acc / dof_vel
关节加速度惩罚能让动作更柔和,但过大会让机器人迈不开腿。
建议小步增加,不要一次调太大。
3)torques 不要压得过狠
力矩惩罚太强可能导致机器人不敢支撑,反而出现拖脚、塌陷或奇怪步态。它适合做能耗约束,但不是解决翘腿的第一优先级。
6. 速度跟踪:别让 policy 为了速度牺牲步态
速度跟踪 reward 一般是主任务:
tracking_lin_vel = exp(-lin_vel_error / sigma) |
如果 tracking 权重远大于稳定性和代价项,policy 会优先“速度达标”,哪怕姿态很丑、腿乱抬。
调参建议
- 不要一开始把速度范围开太大;
- 平地先从低速到中速 curriculum;
- 检查是否大量采样横向速度
lin_vel_y,有些机器人会为了横移学出奇怪抬腿; - 低速命令下要有
stand_still或低速稳定约束; - 如果只关心前进,先缩小
lin_vel_y和ang_vel_yaw范围。
7. stand_still:解决“原地也翘腿”
如果机器人在零速度命令下也抬腿,优先检查:
feet_air_time 是否在低速时仍有奖励 |
legged_gym 里 stand_still 的思路是:当速度命令很小时,惩罚关节偏离默认姿态。
penalty = sum(abs(dof_pos - default_dof_pos)) * (norm(command_xy) < 0.1) |
平地任务建议打开这个项,但权重不要太大,否则慢速起步会变迟钝。
推荐调参顺序
不要一次改十几个 reward。建议按下面顺序做 ablation:
Step 1:先看行为视频和每项 reward 曲线
重点看:
rew_feet_air_time 是否异常高 |
Step 2:先降 feet_air_time
推荐试验:
feet_air_time: 1.0 -> 0.5 -> 0.25 -> 0.1 |
同时确保:
feet_air_time *= norm(command_xy) > 0.15 |
Step 3:加脚滑和接触力惩罚
如果没有 feet_slide,建议加。
feet_slide: -0.05 ~ -0.2 |
具体数值要看 reward 的量级,先看 TensorBoard 里每项平均值,保证单项不会压过主任务。
Step 4:增强平地姿态
orientation / flat_orientation_l2: 适度增大 |
Step 5:最后调动作代价
action_rate: -0.01 -> -0.02 / -0.05 |
一个可操作的平地 reward 配方
下面不是标准答案,只是一个 debug 起点:
class rewards: |
如果训练后机器人变得“不敢迈步”,说明约束过强:先放松 stand_still / action_rate / dof_acc / orientation,而不是马上把 feet_air_time 拉很高。
实验记录建议
每次只改一组参数,记录:
1. seed |
推荐对比表:
| 实验 | feet_air_time | stand_still | feet_slide | orientation | 现象 |
|---|---|---|---|---|---|
| A baseline | 1.0 | 0 | 0 | 0/-? | 平地翘腿明显 |
| B lower air time | 0.25 | 0 | 0 | 0/-? | 翘腿是否减少 |
| C add stand still | 0.25 | -0.2 | 0 | 0/-? | 原地是否稳定 |
| D add slide penalty | 0.25 | -0.2 | -0.1 | -2.0 | 是否更自然 |
常见误区
误区 1:看到翘腿就直接加大 torque penalty
不一定有效。翘腿通常是步态奖励/接触奖励的问题,torque penalty 只是间接约束。
误区 2:把 feet_air_time 直接关掉
可以作为 debug,但不一定是最终方案。完全关掉后可能学出拖脚、小碎步。更好的方式是降低权重、加门控、限制奖励区间。
误区 3:平地也使用很强的 clearance reward
崎岖地形需要 clearance,平地不一定需要。平地上 clearance 太强,很容易变成高抬腿。
误区 4:只看总 reward
总 reward 变高不代表步态更好。一定要看每项 reward 和视频。
总结
平地翘腿不是单个参数的问题,通常是 reward balance 出了偏差。最常见原因是:
feet_air_time / clearance 鼓励抬腿 |
我的调参优先级是:
先降 air-time 和 clearance 的激励 |
平地任务的目标不是“腿抬得漂亮”,而是:
速度跟踪准确 |
参考资料
- Nikita Rudin et al., Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning, CoRL 2021 / arXiv:2109.11978.
leggedrobotics/legged_gym:官方 README 说明 reward scale 非零即启用同名 reward function,并给出 base locomotion reward 配置。legged_gym/envs/base/legged_robot_config.py:tracking_lin_vel、tracking_ang_vel、feet_air_time、lin_vel_z、ang_vel_xy、torques、dof_acc、action_rate等默认配置。legged_gym/envs/base/legged_robot.py:_reward_feet_air_time、_reward_tracking_lin_vel、_reward_orientation、_reward_base_height、_reward_feet_contact_forces等实现。- Isaac Lab locomotion velocity task:
RewardsCfg与 Anymal-C flat config 中的flat_orientation_l2、dof_torques_l2、feet_air_time设置。