资讯动态

分层强化学习实战:四足机器人多步态学习与避坑指南

发布时间:2026/10/13 2:39:11 来源:尧图企业网站定制
简介面向机器人运动控制与强化学习研究者的四足机器人步态学习实战项目基于分层强化学习框架实现包含步行、跑步、爬楼梯等场景的多步态训练适合高校学生、算法工程师及竞赛选手作为算法复现与二次开发的参考基准。压缩包共50个文件整体约3.77MB其中包含24个Python脚本PPO算法、环境封装及辅助工具、9个hpp与3个cpp文件仿真接口与奖励函数实现、4个yaml配置文件参数与任务设定、4个gif步态演示动画及README说明可对照代码与动效快速理解训练流程。内容上并非简单demo而是从环境构建到策略学习的完整工程既有stable_baselines3、RaisimGym等常用依赖的封装模块也有trot、bound、pace、multiple_gait等步态的仿真验证结果。目前已有230人学习浏览适合具备一定强化学习基础、希望将理论落地到四足机器人运动控制的读者研究学习。1. 用分层强化学习学四足机器人步态难在哪给四足机器人调步态最让人头疼的不是让它走出某一种步态而是让它在一个策略里同时学会多种步态并且能在不同步态之间切换。单层强化学习策略在这个任务上经常翻车训练初期还能看到几种步态的雏形训练中后期就全坍缩成同一种或者切换到另一个步态时关节抖振、直接摔砸。分层强化学习把步态学习拆成“高层决定此刻该用哪种步态、低层负责把关节轨迹跟踪到位”两个层次正好对症这一任务。这篇文章的目标读者是准备动手复现这类项目的工程师和学生。我会按我实际做四足步态研究时的路径来写先讲清楚分层强化学习为什么能解决多步态问题再给出仿真环境、状态动作空间、reward 设计和训练过程中的关键参数最后是几组让我印象深刻的踩坑记录。你照着这个思路去读源码包会比自己从头啃省一半时间。2. 分层强化学习拆解步态决策为什么单层 RL 在这里会翻车2.1 单层策略的梯度冲突多种步态为什么不能共享一套关节参数先摆一个反直觉的结论单层策略在数学上完全有能力拟合多种步态但在实际训练时几乎必然失败问题出在梯度冲突。四足机器人的三种常用步态——对角小跑trot、爬行crawl、弹跳bound——各自的关节轨迹差异很大。trot 是对角腿成对落地crawl 是单腿依次抬起bound 是前后腿分别成对离地。单层策略网络把这些轨迹全塞进同一组权重里每次环境返回的 reward 信号都在朝不同方向拉扯权重。一次更新希望髋关节在 0.1 秒内完成摆腿另一次更新又希望它稳定承重两次梯度方向接近垂直。我见过最典型的现象是训练 300 万步时trot 已经收敛得很稳然后你加入 crawl 的奖励条件再训练 100 万步trot 的步频开始紊乱两条前腿落地时序越拉越近。这不是超参数没调好而是单层策略的容量和优化路径在根本上不适合“多模式行为”学習。你需要的不是更大的网络而是把“做什么”和“怎么做”拆开。2.2 高层选步态、低层跟关节HRL 的层次分工与训练节奏分层强化学习在四足步態上的标准做法是把策略分成两层两层的时间尺度不同。高层策略也叫 meta-controller元控制器每隔 N 步决策一次输出一个步态标签或目标速度区间。它不关心关节角度只看躯干状态和任务目标。低层策略也叫 sub-policy子策略接收高层的指令作为条件输入再把自身观测映射成 12 个关节的动作频率和机器人控制频率一致一般是 3050 Hz。这样高层在一个慢时间尺度上选“用什么步态”低层在快时间尺度上执行“关节怎么动”。训练节奏上比较可靠的顺序是先单独预训练低层策略让它分别学会几种步态然后冻结低层机制里的步态参数只训练高层。如果从零开始同时训两层低层还没学会走路高层就在频繁切换步态整个训练过程会陷入双盲探索reward 曲线长期上不去。我一般会给低层 200 万步左右的预训练预算再让高层接手。2.3 什么场景下 HRL 才是划算的选择不是所有四足控制问题都需要分层强化学习。判断标准很简单如果任务只需要一种固定步态单层 PPO 跑半小时就能拿到能用的策略没必要引入两层训练的复杂度和调参成本。需要上 HRL 的典型场景是三种第一任务要求机器人根据地形或速度指令自动切换步态比如平地用 trot、上坡用 crawl第二单次训练要同时产出多种步态且要求切换平滑第三高层决策本身带有时间延展性比如“先用 crawl 爬过障碍物再切 trot 冲刺”这类序列决策在单层框架下很难表达。HRL 的代价也很明确多一层策略就多一组超参数多一个训练阶段。如果项目只要求演示单一步态我建议直接跳过 HRL把精力放 reward 调优上性价比更高。3. 仿真环境搭建与状态动作空间定义从零把四足机器人立起来3.1 仿真器选型高速并行训练优先还是物理精度优先四足步态学習的仿真器当前从业者主要就在 Isaac Gym 和 MuJoCo 之间选。两者的取舍很清晰。Isaac Gym 的优势是 GPU 并行——同一个仿真场景可以同时跑几千个机器人实例这对强化学习训练极其有利。PPO 这类 on-policy 算法需要大量采样单机并行 4096 个环境能把每小时采样量推到百万步级别。代价是物理引擎的接触模型偏“理想化”仿真到实体的 sim2real 迁移需要额外做域随机化。MuJoCo 的优势是接触动力学精度高、仿真出的足端力和关节力矩更接近真实硬件网上许多公开的四足行走 demo 都跑在它上面。缺点是单核只能并行少量环境训练速度快不起来需要配合多进程采样。如果你手头没有团队维护的仿真平台我的建议是以 Isaac Gym 类方案起步因为步态学習的核心矛盾是“如何让策略在大规模采样中收敛”而不是“关节摩擦系数到底设多少”。等策略在仿真里稳定了再针对实体机器人的特性做参数调整。3.2 状态空间和动作空间定义让低层策略拿到该拿到的信息四足机器人的关节自由度一般是 12 个——每条腿 3 个关节分别是横滚髋关节HAA、前摆髋关节HIP、膝关节KNEE。状态空间的常见设计是把以下信息拼接成一个向量状态组维度说明躯干姿态3横滚/俯仰/偏航角躯干速度3线速度世界系躯干角速度3机体系下的角速度关节位置1212 个关节的当前角度关节速度1212 个关节的角速度上一时刻动作12用于平滑连续动作高层步态指令1当前启用的步态编号合计 46 维。这个维度不绝对,但信息完备性很重要——低层策略如果拿不到躯干偏航角就永远学不会直线行走。动作空间有两种常见选择。位置控制策略输出 12 维关节目标位置增量底层 PD 控制器去跟踪输出的是位置增量而不是绝对位置避免策略学会“僵直撑地”。力矩控制策略直接输出 12 维关节力矩弹性更大但对奖励函数和物理参数非常敏感。我一般建议从位置控制起步。力矩控制的成功率太低起步阶段很容易让人怀疑算法写错了。等整个流程指标达标后再考虑尝试力矩控制提升动态性能。3.3 步态参数化不同步态的相位矩阵怎么构造多种步态的分层强化学习实现方式最重要的细节是步态本身不能用 enum 标签硬编码。硬编码的问题在于低层策略收到“步态1”这样的输入时无法从中推断出“此时该哪条腿着地”。正确的做法是把步态参数化为占空比duty factor和相位偏移矩阵高层输出的是步态参数的连续向量低层基于这个向量计算目标足端轨迹。一个简化的代码骨架如下import numpy as np # 四条腿的索引: 0FL(前左), 1FR(前右), 2RL(后左), 3RR(后右) # 步态参数: [占空比, 相位偏移(FL, FR, RL, RR 各自相对于基准的延迟)] # 基准相位: FL 始终为 0, 其他腿依次延迟 GAIT_LIBRARY { trot: {duty: 0.5, phases: [0.0, 0.5, 0.5, 0.0]}, crawl: {duty: 0.75, phases: [0.0, 0.25, 0.5, 0.75]}, bound: {duty: 0.4, phases: [0.0, 0.0, 0.5, 0.5]}, } def compute_swing_phase(gait_name: str, leg_idx: int, t: float) - float: 计算指定腿在 t 时刻的摆动相位(0~1)。 0 - 摆动相开始, duty - 支撑相开始。 g GAIT_LIBRARY[gait_name] period 0.4 # 步态周期单位秒 phase (t / period g[phases][leg_idx]) % 1.0 # 当 phase 落在 [0, 1-duty] 区间时为摆动相 swing_phase phase / (1.0 - g[duty]) if phase (1.0 - g[duty]) else 1.0 return swing_phase这段代码的逻辑是每种步态用两个参数描述占空比决定每条腿在周期内支撑相占比相位偏移决定四条腿之间的落地时序关系。高层策略输出一个 one-hot 或连续权重向量选择当前使用哪种步态参数低层策略把这个参数向量和自身观测拼接作为输入。参数说明duty越大机器人的支撑相越长稳定性越高但速度上限越低。crawl 用 0.75 就是典型的低速稳定步态bound 用 0.4两条腿同时离地时间长动态性高。phases中各腿的偏移量差异决定了机器人走起来像“爬”还是像“跑”。trot 里 FL 与 RR 相位一致、FR 与 RL 一致就是对角步态的本质。4. 分层强化学习策略实现reward 设计、网络结构与训练代码骨架4.1 低层策略的 reward 设计速度跟踪优先关节惩罚兜底低层策略的职责是“把高层给的步态参数执行出来”所以它的 reward 必须要踩在物理量上。我常用的 reward 项和默认权重如下奖励项公式权重作用速度跟踪exp(-2.0 * vx_error)1.0推动机器人跟随目标速度姿态稳定exp(-5.0 * roll_error^2)0.5抑制侧倾关节加速度惩罚-0.001 * sum(action_diff^2)0.1抑制高频抖振能耗惩罚-0.002 * sum(torque^2)0.05减少无意义耗力这里的核心思想速度跟踪用指数函数而不用线性距离是因为指数函数在误差接近 0 时梯度更平滑策略不会为了“追到精确速度”而牺牲稳定性。姿态稳定和能耗惩罚是辅助项权重不能太大否则机器人会“蹲在原地不动——因为不动就没有任何惩罚源”。一个可直接用的 reward 计算函数def low_level_reward(state, action, last_action, target_speed): state: 包含躯干速度和姿态角 action: 当前动作(12维关节增量) last_action: 上一时刻动作 target_speed: 高层下发的目标速度 vx state[base_lin_vel][0] roll state[base_rot][0] # 速度跟踪奖励 vx_error abs(vx - target_speed) reward_vx np.exp(-2.0 * vx_error) # 姿态稳定性奖励 reward_roll np.exp(-5.0 * roll**2) # 动作平滑惩罚 action_diff np.sum((action - last_action) ** 2) reward_smooth -0.001 * action_diff # 总奖励 reward 1.0 * reward_vx 0.5 * reward_roll 0.1 * reward_smooth return reward逻辑说明这个函数让策略在“跑得准”和“迈得稳”之间做权衡。速度误差的指数衰减意味着只要误差稍微变大奖励就快速下降所以策略会被强烈激励去盯住目标速度。姿态稳定项的输入是躯干横滚角四足在 trot 步态下横滚天然有周期性波动指数系数设成 5 相对温和设成 10 会让策略变得过于保守。4.2 高层策略的 reward 设计切换要付“切换成本”高层策略的 reward 不能直接复用低层那套。高层的动作是步态切换它需要判断的是“当前步态在当下的地形和速度任务下是否让低层执行得够好”。一个简单的做法是高层每 N 步决策一次它的 reward 等于这一个决策周期内低层平均 reward 的累计另外加一个切换惩罚项。def high_level_reward(gait_switch_count, low_level_reward_sum, switch_cost0.2): high_level_reward: 高层决策周期内的累计奖励 gait_switch_count: 本周期内步态切换次数 switch_cost: 每次切换的固定成本 # 切换成本能防止高层策略以极高频率震荡 penalty switch_cost * gait_switch_count return low_level_reward_sum - penalty这里switch_cost很关键。如果设成 0高层策略会倾向于每步都切换因为它发现切换到某个步态能瞬间获得更高的低层奖励。设太大高层又不敢换训练出的机器人永远用一种步态。我见过最能稳定工作的区间是 0.10.3。更低的话加上训练噪声切换频率会失控。4.3 低层/高层的网络结构与训练循环骨架低层策略网络输入包含两部分自身 46 维观测和高层下发的步态参数比如占空比相位向量 5 维拼接后是 51 维。中间层两层 MLP隐藏层 256 和 128 个神经元激活函数用 ELU——ReLU 在动作控制任务里容易死掉。高层策略网络的输入只有高层自身的观测躯干速度、地形坡度、任务目标约 10 维输出是可选步态的概率分布最后采样得到一个步态编号再映射到步态参数。训练循环骨架# 伪代码省略了具体 PPO 更新细节 for update in range(total_updates): # 1. 采样阶段: 用当前高层/低层策略跑仿真环境 trajectories rollout(high_policy, low_policy, env) # 2. 低层更新: 用轨迹数据更新低层策略 low_policy.update(trajectories[low_obs], trajectories[low_actions], trajectories[low_rewards]) # 3. 高层更新: 按决策周期聚合 reward 后更新高层策略 high_rewards aggregate_by_decision_cycle(trajectories) high_policy.update(trajectories[high_obs], trajectories[gait_actions], high_rewards - switch_cost * trajectories[switch_count])训练参数低层策略学习率 3e-4高层策略学习率 1e-4。低层更新的 batch size 是 4096 条轨迹高层因为决策频率低batch size 通常只有低层的十分之一。GAE广义优势估计的 lambda 设 0.95gamma 设 0.99。4.4 拿到带源码的项目包先看哪几个文件这类四足步态学習的源码包结构上通常包含 environment、algorithms、train、config 四个部分。我拿到手一般按这个顺序看首先是 config 文件。这里能看到 reward 各项的权重、状态空间维度、PPO 超参数——这些决定了项目作者认为什么重要。其次是环境文件里奖励函数和步态参数两部分对照 4.1 和 4.2 的框架理解作者做了哪些取舍。最后才是训练脚本。如果先看训练脚本你很容易被 1000 多行的参数初始化代码淹没。有一个重点提醒不要试图一次就跑通源码包里的完整训练。这类项目的完整训练时间普遍在一小时以上中途任何一个参数不匹配都会静默失败。我常用的方式是先把训练步数砍到原来的十分之一只跑 5 分钟确认数据流是通的再恢复完整预算。5. 四足机器人步态训练避坑指南4 个让训练崩盘的典型问题5.1 现象一好几种步态在训练中后期开始互相污染现象训练前期 trot 和 crawl 都能稳定跑出来训练到中期后两种步态的足端轨迹逐渐趋同最终所有步态都变成同一种走法而且往往是里最简单的那种。原因低层策略是共享参数的不同步态的数据在优化时互相干扰。crawl 的支撑相交大它的梯度会把 trot 里已经形成的“对侧腿同时摆动”的时序慢慢拉向“单腿依次摆动”两种模式之间矩离不大策略最终落到一个中间的折中状态。解决在低层策略的观测中加入一个步态 one-hot 向量同时把步态参数从共享网络的前几层独立出来——即每条步态各自保留几层专属网络只在最后两层共享。这是分层强化学习里常见的 “shared trunk with per-gait heads” 结构。代价是参数量增加但步态独立性显著提升。5.2 现象二步态切换瞬间关节出现明显抖振现象机器人能执行每种步态但高层一发出切换命令切换瞬间关节角度出现 10 Hz 左右的快速振荡有时候直接把机器人抖倒。原因低层策略训练时用的是固定的步态参数它只在稳态数据上见过这些参数。高层突然给出一个新参数组合时低层策略的输入分布超出训练分布策略给出无意义的高频动作。解决在低层训练时对步态参数做插值扰动——不要每次都喂训练完整的步态参数而是随机把两个步态参数线性插值让低层见过“中间态”。另一个更有效的手段是给切换过程加一个时间窗高层发出切换指令后步态参数在 0.3 秒内线性过渡而不是瞬间跳变。过渡期的动作会在低层网络里生成平滑的中间输出抖振基本消失。5.3 现象三训练几百轮后 reward 突然掉到接近 0日志里全是 NaN现象reward 曲线前期正常上升200 轮之后突然崩盘训练日志里出现大量 NaN。原因大部分情况下是状态信息里出现了极端值躯干角速度或关节速度字段在数值上发散之后策略更新的梯度也跟着发散整个网络权重变成 NaN。解决先看是哪个状态量爆了。在训练循环里对每个状态分量加一个有限性检查一旦发现超过 10 倍合理范围就截断——但这是被动修复。更主动的做法是检查仿真环境里有没有“机器人被弹飞”的情况足端接触模型在某些地形拼接处会产生异常接触力把机器人弹射到空中状态量直接爆。给躯干高度设置一个合理上限超过就截断本回合reward 归零而不是让异常状态传入网络。5.4 现象四仿真里走得完美换到真实机器人或新地形就摔现象仿真里 trot 步态已经能跟随 1.5 m/s 的目标速度挪到真实四足上机器人在第三步就直接砸地。原因这就是 sim2real gap主要来自两个地方。第一是仿真里的地面刚度和摩擦系数是理想值真实地面上每一个微小的凸起都会带来足端碰撞第二是低层策略在仿真里学到了“用力推地”的动作真实关节电机响应跟不上这个力矩请求。解决最实用的手段是域随机化训练时把地面摩擦力在 0.4 到 1.0 之间随机扰动把电机力矩上限在 ±20% 范围内随机缩放。如果换到新地形才摔那就需要检查步态切换逻辑——上坡时默认的 trot 步态占空比太低支撑相不足换个更高占空比的步态基本能解决。6. 验证多种步态是否真的学到评估指标与导出前检查训练完成之后不要只看训练曲线的 reward 数值那个数字在多种步态任务里具有很强的欺骗性——策略可能在 trot 上表现极好、在 crawl 上完全失效但平均 reward 仍然在上升。我习惯用下面的评估表逐一检查指标建议通过线说明步态保持时间≥5 秒不退化同一指令下步态参数稳定执行切换延迟≤0.3 秒指令发出到步态参数完成过渡的时间速度跟踪误差≤0.15 m/s不同目标速度下稳定运行姿态角最大偏差≤15°躯干不出现激烈倾斜足端轨迹一致性标准差 0.02 m每个步态周期内落地位置不漂移评估时有一个技巧把高层策略的探索噪声关闭固定输出每种步态然后分别测量指标。如果固定输出场景下某种步态不达标说明低层学习不充分如果固定输出都达标但自由切换后开始退化问题出在高层的切换逻辑去看 5.2 的过渡时间窗。导出到真实机器人之前还有一个容易忽略的检查项把训练日志里的动作差分统计打出来看每个关节是否存在超过 30% 的瞬间动作跳变。如果有说明策略在仿真里依赖了高频抖动来维持平衡这种策略导出去必摔。需要回去调大 4.1 里的动作平滑惩罚权重重新训练。我自己的习惯是每次改完一个参数都把评估指标表存一份带时间戳的副本。两周后你绝对不记得 gym_lr 从 3e-4 改成 2e-4 对切换延迟带来了什么影响但指标表一对比就知道答案。这不是什么高级技巧是我在这个项目里吃过最多亏的地方——把训练当黑匣子把调参当玄学最后只能靠翻日志重新推导。希望这些避坑思路和参数底线能帮你的四足机器人少摔几次也别再为了“什么时候切换”这层逻辑熬夜调参。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑