四足机器人平地“翘腿”问题:Reward 调参检查表

问题背景

平地 locomotion 训练里,有时会看到一个很典型的坏习惯:机器人在平地上走着走着,某条腿或某几条腿明显“翘起来”,看起来像在主动抬腿、拖腿、单腿悬空,甚至形成不自然的跳步。

这类现象不一定是 policy “不会走”,更常见是 reward 组合给了它一个可钻的空子:

速度跟踪奖励够高
+ 抬腿/腾空奖励过强或门控太松
+ 接触/滑脚/姿态/能耗约束不够
= 平地上也愿意把腿抬得很夸张

这篇整理一下:如果目标是平地稳定行走,不希望无意义翘腿,四足机器人强化学习里哪些 reward 最值得优先检查和调整。

先看官方基线怎么做

legged_gym / Isaac Lab 的 velocity tracking 任务为参考,常见 reward 结构大概是:

tracking_lin_vel      # xy 线速度跟踪,正奖励
tracking_ang_vel # yaw 角速度跟踪,正奖励
lin_vel_z # base 垂向速度惩罚
ang_vel_xy # roll/pitch 角速度惩罚
orientation # 身体姿态/重力方向惩罚
base_height # 身体高度惩罚,可选
torques # 力矩惩罚
dof_acc # 关节加速度惩罚
action_rate # action 变化惩罚
feet_air_time # 脚腾空时间奖励
collision # 非足端碰撞惩罚
feet_contact_forces # 足端接触力过大惩罚,可选
stand_still # 零速度命令下的关节偏离惩罚,可选

legged_gym 默认 flat/rough locomotion 里,feet_air_time 是一个很关键的项:它奖励“长步幅/有节奏迈步”,但如果权重、阈值、门控条件不合适,也容易鼓励不必要的抬腿。

Isaac Lab 的 Anymal-C flat 配置里也能看到类似思路:平地任务会保留速度跟踪、姿态、力矩、feet air time 等项,同时平地版会关闭高度扫描和地形 curriculum。

一句话结论

如果平地出现“翘腿”,我会按这个优先级调:

1. 降低或重新门控 feet_air_time
2. 增强足端接触稳定性:脚滑、接触力、接触时序
3. 增强姿态/高度约束:orientation、base_height、lin_vel_z、ang_vel_xy
4. 增强动作代价:action_rate、dof_acc、torques、dof_vel
5. 检查速度命令分布和站立命令:不要让低速/零速也被奖励抬腿

1. feet_air_time:最容易导致“翘腿”的 reward

feet_air_time 本意不是让机器人“把腿抬高”,而是避免拖着脚走,让机器人形成有步态周期的迈步。

legged_gym 里,它大致逻辑是:

contact = foot_contact_force_z > threshold
first_contact = feet_air_time > 0 and contact
feet_air_time += dt
reward = sum((feet_air_time - 0.5) * first_contact)
reward *= norm(command_xy) > 0.1
feet_air_time reset when contact

这个设计有几个要点:

  • 只在脚重新落地的瞬间给奖励;
  • 奖励的是“腾空时间超过阈值”的部分;
  • 速度命令很小时不给这个奖励;
  • 接触检测如果噪声大,会影响这个 reward 的真实性。

如果平地翘腿明显,优先检查:

调参建议

1)降低 feet_air_time 权重

如果当前权重比较大,可以先降到原来的 1/2 或 1/4。

例如:

# legged_gym 风格
feet_air_time = 1.0 # 如果翘腿明显,可以先试 0.5、0.25、0.1

Isaac Lab flat 里 Anymal-C 示例曾把 flat 任务的 feet_air_time.weight 设置为 0.5;而通用 velocity rough cfg 中有更保守的 0.125。这说明这个项本来就需要按任务调,不能盲目套默认值。

2)提高触发门槛,而不是奖励无限抬腿

如果 reward 写成“脚越高越好”或“离地越久越好”,policy 很容易学成夸张抬腿。

更稳的写法是只奖励合理区间:

air_time 太短:可能拖脚,少奖励
air_time 合理:奖励
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
reward_feet_air_time *= moving

对于平地低速任务,可以把阈值从 0.1 提到 0.15 ~ 0.25 试试。

2. feet clearance:不要把“抬脚高度”奖励写得过强

很多项目会额外加 feet_clearance,鼓励摆动腿离地,避免拖脚。

这在崎岖地形上有用,但在平地上要小心:如果 clearance reward 太强,就会直接把 policy 推向“高抬腿”。

调参建议

平地建议把 clearance 写成目标区间,而不是越高越好:

目标:摆动腿离地 3~8 cm 足够
超过目标:不给更多奖励,必要时惩罚
支撑腿:不应该因为 clearance 得分

示例思路:

target = 0.05  # 5 cm
swing = foot_not_in_contact
err = torch.square(foot_height - target)
reward_clearance = torch.exp(-err / sigma) * swing * moving

如果已经有 feet_air_time,平地任务里可以先不加 clearance;如果必须加,权重要比速度跟踪、姿态稳定小得多。

3. feet_slide / contact stability:防止用奇怪接触骗速度

翘腿有时不是单独发生,而是伴随:

  • 支撑脚在地上滑;
  • 另一条腿长期悬空;
  • 身体靠几条腿硬拖着走;
  • 接触力尖峰很大。

这时应该补足接触稳定相关惩罚。

推荐检查项

1)脚滑惩罚 feet_slide

逻辑:脚在接触地面时,足端水平速度不应该太大。

contacts = contact_force_z > threshold
feet_xy_vel = torch.norm(feet_vel[:, :, :2], dim=-1)
penalty_feet_slide = torch.sum(feet_xy_vel * contacts, dim=1)

如果平地走路像“溜冰”或“拖脚”,这个项很重要。

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 垂向速度惩罚
ang_vel_xy # roll/pitch 角速度惩罚
orientation # 身体倾斜惩罚
base_height # 身体高度偏离惩罚

调参建议

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
base_height = -k * (base_height - target)^2

注意:高度目标不要太死,否则会牺牲自然步态。可以先用小权重。

3)不要只靠高度惩罚解决翘腿

翘腿是足端/步态问题,base_height 只能约束身体,不一定能直接约束腿。更推荐和 feet_air_timefeet_slideaction_rate 一起调。

5. 动作平滑与能耗:抑制“猛抬腿”

如果 policy 抬腿动作很突兀,通常要看:

action_rate  # 相邻 action 差分
dof_acc # 关节加速度
dof_vel # 关节速度
torques # 力矩/能耗

调参建议

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_ang_vel = exp(-ang_vel_error / sigma)

如果 tracking 权重远大于稳定性和代价项,policy 会优先“速度达标”,哪怕姿态很丑、腿乱抬。

调参建议

  • 不要一开始把速度范围开太大;
  • 平地先从低速到中速 curriculum;
  • 检查是否大量采样横向速度 lin_vel_y,有些机器人会为了横移学出奇怪抬腿;
  • 低速命令下要有 stand_still 或低速稳定约束;
  • 如果只关心前进,先缩小 lin_vel_yang_vel_yaw 范围。

7. stand_still:解决“原地也翘腿”

如果机器人在零速度命令下也抬腿,优先检查:

feet_air_time 是否在低速时仍有奖励
stand_still 是否开启
默认关节姿态是否合理

legged_gymstand_still 的思路是:当速度命令很小时,惩罚关节偏离默认姿态。

penalty = sum(abs(dof_pos - default_dof_pos)) * (norm(command_xy) < 0.1)

平地任务建议打开这个项,但权重不要太大,否则慢速起步会变迟钝。

推荐调参顺序

不要一次改十几个 reward。建议按下面顺序做 ablation:

Step 1:先看行为视频和每项 reward 曲线

重点看:

rew_feet_air_time 是否异常高
rew_tracking_lin_vel 是否已经很好
penalty_action_rate / dof_acc 是否太小
orientation / base_height 是否几乎不起作用
feet contact 是否有长期单脚悬空

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
feet_contact_forces: -0.005 ~ -0.05

具体数值要看 reward 的量级,先看 TensorBoard 里每项平均值,保证单项不会压过主任务。

Step 4:增强平地姿态

orientation / flat_orientation_l2: 适度增大
lin_vel_z: 保持较强惩罚
ang_vel_xy: 适度增大
base_height: 从小权重开始打开

Step 5:最后调动作代价

action_rate: -0.01 -> -0.02 / -0.05
dof_acc: 小步增加
torques: 小步增加,不要过强

一个可操作的平地 reward 配方

下面不是标准答案,只是一个 debug 起点:

class rewards:
class scales:
tracking_lin_vel = 1.0
tracking_ang_vel = 0.5

lin_vel_z = -2.0
ang_vel_xy = -0.05
orientation = -2.0 # 平地可适度增强
base_height = -0.5 # 从小权重开始试

feet_air_time = 0.25 # 先比默认更保守
feet_slide = -0.1 # 如果框架里没有,需要自己加
feet_contact_forces = -0.01
collision = -1.0

torques = -1e-5
dof_acc = -2.5e-7
action_rate = -0.02
stand_still = -0.2 # 低速/零速防止原地乱抬腿

如果训练后机器人变得“不敢迈步”,说明约束过强:先放松 stand_still / action_rate / dof_acc / orientation,而不是马上把 feet_air_time 拉很高。

实验记录建议

每次只改一组参数,记录:

1. seed
2. reward scales diff
3. 命令速度范围
4. 训练迭代数
5. 是否出现翘腿
6. 是否脚滑
7. 是否速度跟踪变差
8. 视频链接或截图

推荐对比表:

实验 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 鼓励抬腿
但 contact stability / posture / smoothness 没有把动作拉回自然范围

我的调参优先级是:

先降 air-time 和 clearance 的激励
再补 feet_slide / contact force / undesired contact
再增强 orientation / base_height / lin_vel_z / ang_vel_xy
最后小步调 action_rate / dof_acc / torques

平地任务的目标不是“腿抬得漂亮”,而是:

速度跟踪准确
脚不拖、不滑、不乱悬空
身体稳定
动作平滑省力

参考资料

  • 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.pytracking_lin_veltracking_ang_velfeet_air_timelin_vel_zang_vel_xytorquesdof_accaction_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_l2dof_torques_l2feet_air_time 设置。
algorithms axis-angle bang-bang bode calibration chrome cmake cmakelists cnn colcon conan control cpp cpu d435i data_struct db design-pattern dots economics eigen factory-pattern fcpx figure finance forge fov gazebo gdb git gnu ibus interest isaac gym isaac lab isaaclab kdl latex launch learning-notes legged locomotion legged-robot life linux linux-kernel mac math matlab matrix memory mlp money motion-control motor moveit mpc mujoco network ocs2 ode operator optimal algorithm optimal-control perf performance personal-finance ppo profiling python qos quadrotor realsense reinforcement learning reward tuning rnn robot robotics ros ros2 rtb security shell simulation socket stairs stl tcp-ip thread tools twist ubuntu uml unitree urdf vae valgrind vcxsrv velocity vim web wifi work wsl 中文输入 交叉编译 依赖管理 分支管理 四足机器人 实验诊断 强化学习 机器人视觉 构建系统 深度学习 深度相机 点云 版本控制 神经网络 训练曲线 输入法 配置类 飞控
知识共享许可协议