
训练02我写的是怎么把四足机器人模型在 MuJoCo 里调稳、调准当时就有读者在评论区问站住以后是不是直接上强化学习就能会跑我的回答是会跑但跑得千奇百怪。训练03这篇我打算把四足机器人强化学习训练这条完整链路拆开讲动作空间怎么选、观测向量怎么搭、奖励函数怎么写、训练日志怎么读还有那些训练中途出现的“高频抖腿”“僵尸步”“突然崩坏”到底怎么排查。这篇不是理论课更像是我这段时间反复调模型的一份实操记录。适合已经会基本 MuJoCo 操作、正准备开始跑四足 RL 训练的开发者。如果你当前正卡在“训练半天不收敛”或者“一收敛就是怪步态”那这篇文章应该能帮你少走不少弯路。我想解决的最直接问题就是大家常说的“训练半天不收敛”和“一收敛就是怪步态”。这类问题十有八九不是因为网络结构不够深而是你把动作空间、观测向量、奖励函数当成独立模块在调忽略了它们是一个闭环。这篇的训练目标定得很具体让四足机器人跟随 0.5~1.2 m/s 的速度指令躯干俯仰角和横滚角都控制在 10 度以内关节力矩不超过电机限制并且没有明显的高频关节振荡。1. 从“原地站稳”到“按指令行走”训练03要重新定义问题1.1 为什么站立策略不能直接拿来当运动初值我试过把站立任务的策略直接作为运动训练初值结果是直立姿态确实没崩但它根本不知道怎么把脚抬起来。原因其实很好理解站立任务的奖励函数主要惩罚姿态误差和关节误差策略学到的是“收紧所有关节、保持固定扭矩输出”。一旦你给它更大的探索范围和速度奖励它更倾向于用力蹬地而不是组织起有节奏的四足步态。所以训练03我的第一个建议是放弃“让策略从站立策略微调”的想法直接用一个空白策略加上运动任务奖励从头开始训。有些做迁移学习的资料会建议先让上层网络学小范围扰动但四足 locomotion 这种强周期任务我还是建议从头训。初始探索过程虽然看起来低效但策略会逐渐建立“哪只脚在什么时候该承重”的底层认知这是站立策略很难迁移过来的。1.2 训练03的验收标准不只看能不能动在开始调参之前先写一份环境测试清单这会让你后面排查问题时有据可依。我对训练03的验收设定是这样的初始状态随机躯干朝前腿部姿态有随机偏移初始速度为 0。指令随机每 5~8 秒切换一次目标前向速度采样范围 0.5~1.2 m/s。终止条件躯干倾角超过 0.5 rad或者连续几帧足底接触出现异常。验收指标分五个维度维度指标说明速度阶跃响应0.5→1.0 m/s 变化能在 2~3 秒内跟上对应实际场景中的加减速稳态误差速度稳态误差 15%避免策略只会“接近”指令速度姿态稳定躯干俯仰、横滚扰动 10 度防止动作幅度过大关节安全关节力矩不超过电机额定限制后续迁移真机才有意义步态对称无拖脚、无同侧双支撑异常视觉上很玄学但很重要这张表会在后面所有的奖励函数调整、超参测试里反复用到。每改动一个权重都要拿这五个指标重新打分而不是只看总奖励曲线上升。1.3 开始训练前再检查一遍的前置条件四足 RL 的调试链路比普通倒立摆长很多如果你基础条件没准备好后面排查难度会成倍增加。我建议至少满足这几条能从 MuJoCo 里稳定读取并写入关节传感器数据而不只是会打开渲染窗口。清楚自己的执行器类型位置式、速度式还是力矩式。这个直接决定动作空间设计。理解 PPO 算法里的 clip、GAE、value loss 含义不要求能手推数学但至少要能看懂训练日志。有保存和恢复 checkpoint 的习惯最好每固定步数自动存一版策略。如果这些条件里有缺失不要硬上。趁着训练前先把环境读数和模型控制链路摸清楚比训练到一半再去查 API 要快得多。2. 动作空间和观测空间训练能不能收敛一半取决于这里2.1 关节位置增量、绝对目标角度、还是力矩我在这轮训练里最早踩的坑就是动作空间选错。MuJoCo 里常见的执行器定义有 motor、position、velocity 三类对应的 RL 动作空间也分成了三种思路动作空间含义优点风险关节力矩直接输出 tau动态上限高贴近物理新手极易振荡训练方差大绝对目标角度输出关节绝对角度直观容易约束范围初始姿态变化时策略容易失稳关节位置增量输出目标角度的增量平滑、天然适合分步控制需要设置合理的限幅我优先推荐第一版本使用“关节位置增量”。理由很朴素四足机器人的 12 个关节如果直接输出力矩策略在早期探索时会把腿甩到限位附近训练曲线几乎是瞬间爆掉的。而输出绝对角度的话每个关节的初始角度都会被编码进策略里——可你的初始状态是随机化的策略学到的“保持某个绝对角度”到了新初始状态就失效了。位置增量的做法是动作输出 delta_q目标角度 当前关节角 delta_q再把 delta_q 限制在 ±0.3~0.5 rad。这样策略学的是“在当前位置上往哪个方向转多少角度”天然与初始状态解耦也方便后续做动作限速。2.2 观测向量不仅要“看见”还要给策略“节拍感”观测向量的设计往往决定了策略能不能形成步态。我见过有人只给躯干速度和关节角训练几千步后策略原地踏步一个主要原因就是策略根本不知道自己当前处于步态周期里的哪个阶段。我习惯的观测分组是这样的躯干姿态四元数或旋转矩阵推荐旋转矩阵避免四元数双覆盖问题。躯干线速度与角速度前向速度、侧向速度、偏航角速度等。重力向量投影到躯干坐标系相当于 IMU 的加速度计信息。关节角度与角速度12 个关节的角度和角速度这是必须的。足底接触状态4 个触地标志位告诉策略当前哪只脚在支撑。上一步动作把上一时刻的动作也加进观测相当于给策略一个短暂的“惯性”提示。指令向量vx、vy、yaw_rate 的当前目标值。步态相位编码每个腿一个相位用 cos(phi) 和 sin(phi) 两组值表示。相位编码是四足任务里很容易被忽略的一环。四足步态本质上是一种周期性运动如果策略只能看到瞬时状态就很难推理“我这条腿现在应该进入摆动相还是支撑相”。我的做法是在仿真开始时初始化四条腿的相位将它们均匀错开每步按歩频更新相位然后把 cos 和 sin 丢进观测。下面是一个简化的伪代码示例具体 API 取决于你用的环境接口# 伪代码构建观测向量片段 obs np.concatenate([ base_orientation_matrix, # 3x3 摊平为 9 维 base_lin_vel, # 3 维 base_ang_vel, # 3 维 joint_angles, # 12 维 joint_vels, # 12 维 foot_contact_bools, # 4 维 last_action, # 12 维 command_vector, # 3 维vx, vy, yaw_rate phase_encoding, # 8 维每条腿 cos/sin ])这样搭出来的观测向量大约 66~70 维对不同任务的扩展性都还不错。2.3 观测归一化别用固定假设值四足机器人足底接触状态会让状态分布变化很大刚开始训练时策略可能在乱跳躯干速度分布很宽训练一段时间后策略学会了比较稳定的步态速度分布又会急剧变窄。如果你用固定假设值做归一化训练后期会出现一种很隐蔽的问题某些维度长期处于归一化后的“边缘区域”奖励梯度异常策略性能突然下降。我的建议是在训练早期就加入 running mean / running std 机制并持续更新统计量。不要只在环境初始化时算一次就固定住。如果训练中途出现间歇性漂移优先检查归一化统计量有没有在某个阶段被异常样本污染。3. 奖励函数设计不要一把抓要分层3.1 把奖励分成三个“口袋”很多入门教程喜欢把所有约束揉成一个 reward结果就是权重冲突策略选择“摆烂”。我在调四足任务时习惯把奖励拆成三个口袋目标奖励告诉策略要做什么比如速度跟踪。约束惩罚告诉策略什么不能做比如关节越限、姿态过度倾斜。风格奖励告诉策略怎么做得更“自然”比如动作变化率、步态对称性。每个口袋内部的量纲尽量一致然后再为三个口袋分别设定权重比例。这样做的一个额外好处是日志里可以清楚地看到是哪个口袋在主导训练而不是面对一个混合后的数字瞎猜。3.2 速度跟踪奖励为什么我用指数函数而不是线性误差速度跟踪是最核心的目标奖励我采用的是指数形式# 伪代码速度跟踪奖励 def velocity_reward(vx, cmd_vx, sigma0.5): error (vx - cmd_vx) ** 2 return math.exp(-error / (2 * sigma * sigma))用指数形式而不是线性误差核心原因是梯度形状更合理。当策略离目标速度很远时指数函数梯度不会无限大策略可以安心先解决稳定性问题当策略接近目标速度时梯度变得更平坦策略不会为了多压榨 0.1 m/s 的速度误差而牺牲姿态平衡。sigma 的取值会影响惩罚强度。sigma 越大速度误差对奖励的影响越小。我一般从 sigma0.5 起步如果训练后期速度跟踪效果不佳再把 sigma 调到 0.3 左右。侧向速度和偏航角速度也可以用类似形式但权重可以适当降低因为四足的前向移动仍然是主任务。3.3 约束惩罚关节越限、姿态倾斜和能耗权重约束部分我按下面的方式处理姿态稳定性惩罚 roll 和 pitch 的平方权重在 1.0~2.0。注意不要把它设得太大否则策略会倾向于“宁可不走也不能倒”出现僵尸步。关节越限只惩罚越限部分而不是惩罚关节偏离中心位置。如果惩罚“偏离中心”策略会被迫保持四腿缩在中间无法形成大步幅。能耗惩罚对关节力矩的平方求和作为惩罚权重在 0.005~0.02 量级。关于这个量级我要多说一句能量项的数值单位与速度误差完全不同如果你不先打印出各项奖励的实际数值就乱配权重很容易出现“速度奖励 60 分、能耗惩罚 600 分”的局面策略就会选择什么都不做最划算。我习惯在开始训练前先跑一个随机策略打印所有奖励分项的平均值把每个分项的量级控制在同一个水平附近。这一步很多文章不会提但实际调参时几乎能救半条命。3.4 步态先验用相位变量给策略“节拍感”奖励函数里也可以引入步态先验而不仅仅是靠观测里的相位编码。一个比较简单有效的做法是“相位—接触一致性”奖励如果当前相位应该处于支撑相却出现了脚离地就做轻微惩罚反之如果应该处于摆动相脚却一直贴地也做轻微惩罚。四条腿的相位关系与步态模式强相关。一个简单的对角步态设置是左前和右后为一组右前和左后为一组两组相位相差 pi。这样策略在奖励信号中能感受到“哪只脚应该配合哪只脚承重”。这个奖励的权重不宜太大否则会强制策略走特定步态碰到不同地面材质时反而做不到自适应。我一般把它控制在总奖励的 5%~10% 左右。4. 完整训练闭环从环境到日志到回放4.1 最小训练闭环由这几块组成四足训练的最小闭环并不复杂环境输出观测和奖励策略网络产出动作采样器收集经验优化器更新网络权重然后回放验证。真正复杂的是怎么让这个闭环变得“可诊断”。我给环境的接口上额外做了一层“奖励分解”封装每一个奖励分项都单独输出比如 velocity_reward、posture_penalty、joint_limit_penalty、energy_penalty、phase_prior_penalty。这样训练日志里可以看到每一项的曲线而不是只有一个总奖励。这个改动大概只要 20 行代码但它让我后续定位问题的时间节省了三分之二。4.2 算法选择与超参数为什么我默认先上 PPO四足 locomotion 任务里PPO 依然是我最常用的起点算法。倒不是说它一定比别的算法好而是它对奖励尺度的鲁棒性明显好于直接做策略梯度超参数数量又比 SAC 少更容易排查问题。下面是我在 4096 并行环境规模下实测比较稳定的一组配置你可以作为起点参数数值说明gamma0.99折扣因子太小会让策略只关注眼前几步gae_lambda0.95GAE 参数越小策略更新越保守clip_ratio0.2PPO 裁剪范围太大更新不稳定learning_rate3e-4后期可以降到 1e-4entropy_coef0.005~0.01太小探索不足太大收敛慢num_envs1024~4096并行环境数取决于显存mini_batch_size2048~4096与并行环境数相关update_epochs5~10过大容易过拟合当前策略四足运动探索空间很大单环境采样的方差太高训练曲线基本没法读。如果你没有多卡 GPU可以把并行环境降到 32~64这时候模型网络也相应改小一点比如 [128, 128]否则训练时间会明显拉长。4.3 训练日志不要只盯着总奖励训练日志里最容易被忽略的就是总奖励曲线因为它把信息压缩掉了。我看日志的习惯是关注四个东西total_reward前 10% 震荡是正常的但如果到 30% 还没有上升趋势说明奖励信号或者探索配置有问题。奖励分项曲线如果某个分项长期占总奖励 90% 以上说明权重失衡需要重新配比。policy_entropy如果几千步内从初始值急剧掉到接近 0策略过早确定后续很难恢复此时要调大 entropy 系数。value_loss / policy_loss出现 NaN 或持续发散优先检查观测或奖励里是否出现了非有限值。另外一定要养成定期保存 checkpoint 的习惯。训练中断是一件小事但如果你没有 checkpoint之前几万步的探索就全浪费了那种感觉我不想再经历一次。4.4 回放验证渲染流畅不等于合格训练完成后我会先用渲染窗口看一遍策略但那只用来排除明显的物理异常。真要评估我会把策略放到测试环境里跑一组固定指令序列然后把速度曲线和关节力矩曲线画出来。渲染流畅但力矩曲线反复冲击上限这种情况我见过不止一次。如果发现策略在回放时和训练时表现不一致优先检查训练环境与回放环境是不是同一个。比如训练时设了随机初始姿态回放时固定了初始姿态这本身就足以造成策略崩坏。5. 踩坑实录三种典型故障的完整排查链路5.1 故障一关节高频抖动画面里腿像在发抖我最早遇到高频抖动时第一反应是加大动作变化率惩罚但加了半天没什么效果。后来我把问题一步一步拆开才发现抖动来源不止一个。完整排查顺序是这样的先降低 PD 增益看抖动频率是否明显下降。我把 stiffness 从 300 降到 150抖动立刻缓解不少。检查动作限幅。如果 delta_q 的限幅是 ±0.5 rad策略早期探索时很容易在相邻控制步之间疯狂反转限幅改到 ±0.2 之后高频成分少了很多。在奖励里加入动作变化率惩罚-k * mean((action_t - action_prev)^2)k 从 0.05 开始往上试。确认策略控制频率和仿真频率是否匹配。比如仿真 dt0.002策略每 5 步更新一次是合理的如果策略每一步都更新而电机刚度又很高相当于给一个快速系统加入了持续噪声激励。最终我的解决组合是stiffness180damping3delta_q 限幅 ±0.25动作变化率权重 0.1。高频振荡基本消失速度跟踪也保持在了 12% 以内的稳态误差。5.2 故障二僵尸步和原地踏步策略“学会了不动”僵尸步是我遇到过最让人头大的问题渲染画面上策略看起来在迈步但躯干几乎没有前向位移。或者四条腿同步伸缩身体在原地上下起伏。这里我的排查思路是先看奖励分解日志是哪一项在主导策略。如果能量惩罚占总奖励的比例过高策略会认为“少动”就是最优策略。此时把能耗权重从 0.01 降到 0.002策略才开始尝试迈步。如果姿态惩罚过高策略会非常小心不敢把重心往前压。我把姿态惩罚权重从 2.0 降到 0.8 后情况明显改观。其次要检查相位先验。如果你没有在观测里提供相位编码策略很难自行发现“对角步态”这个解。它可能让四条腿同时伸缩因为这样也能维持一定的稳定。我加入相位编码和相位—接触一致性奖励之后训练出来的步态明显变得有节奏感。最后还有一个技巧速度课程。一开始目标速度从 0.3 m/s 起步让策略先理解“向前移动有额外的正奖励”然后逐步把速度指令范围拉宽到 0.5~1.2 m/s。这种方法在四足任务里非常常用相当于帮策略做了一个可行的次优解做引导。5.3 故障三训练后期突然崩坏前面的成果全部归零有一种让人很崩溃的情况前几万步训练曲线一直在涨突然某次评估性能掉到接近零而且再也训练不回来。我复盘之后发现这类问题往往是“策略变得过于确定”导致的。一种典型原因是熵系数被设成了随训练步数线性衰减的调度器衰减到接近 0 之后策略在几乎所有状态都输出了确定的动作。这时一旦遇到一个训练分布边缘的状态它没有足够的随机性去探索恢复路径整个估值就崩了。我的处理方式是不再让熵系数线性衰减到 0而是设一个下限比如 0.001当策略熵值低于下限时强制把它调回 0.005。另一种隐蔽原因是观测归一化统计量被异常样本污染。比如训练过程中策略撞到边界状态产生了一个极端速度值这个值把 running std 拉得很大。之后策略面对正常速度时归一化后的观测数值都变得非常小价值网络输入分布突变自然就崩了。解决方法是改用滑动窗口策略或者把归一化统计量的更新率设得更保守。如果崩坏已经发生不要浪费时间继续训练直接回滚到之前保存的 checkpoint通常回滚到崩坏点前 5 万步的状态可以重新恢复。6. 从 MuJoCo 走出去迁移到真机之前要查的四件事6.1 延迟注入仿真里很稳真机上疯狂摇摆很多人做完仿真验证一上真机就发现策略完全失控最容易被忽略的原因就是延迟。仿真环境通常假设策略动作立即生效但真实电机和通信链路存在 20~100 ms 的延迟。我的建议是在训练时就做延迟注入每个环境给一个随机延迟区间比如 10~30 ms动作在这个延迟窗口内保持上一次的值。仿真测试里不注入延迟和注入延迟后的成功率对比会非常明显。我测过的经验是原本成功率 90% 的策略加 20 ms 固定延迟后可能掉到 60% 以下训练阶段加入随机延迟后对延迟的鲁棒性会显著提升。6.2 域随机化摩擦系数和质量的合理范围Sim-to-Real 迁移必做的一步是域随机化但要注意不要一开始就全范围拉满。拉满的结果往往是训练难度翻好几倍策略连仿真里都收敛不了。推荐从这两个参数开始摩擦系数 0.4~1.8机身质量倍率 0.8~1.2。这两个参数对四足运动影响最显著而且物理上容易理解。训练稳定后再加入电机增益 0.9~1.1 的随机化。关节摩擦可以在 0.05~0.2 之间随机但权重不要一开始就加否则早期训练会非常困难。参数建议范围说明地面摩擦系数0.4~1.8覆盖光滑地板和粗糙路面机身质量倍率0.8~1.2模拟不同负载电机增益0.9~1.1模拟电机老化差异关节摩擦0.05~0.2模拟关节密封和润滑油差异初始姿态偏差0.05~0.15 rad模拟安装误差和启动姿态差异6.3 动作平滑和指令限制增加低通滤波在真实机器人上直接执行策略输出的每一个目标角度是一件危险的事因为策略输出的动作序列往往含有高频成分。就算仿真里没出现抖动真机电机的响应特性也会放大小幅高频变化。我建议在策略输出后加一阶低通滤波# 伪代码动作低通滤波 def smooth_action(prev_action, target_action, alpha0.3): return alpha * target_action (1 - alpha) * prev_actionalpha 取 0.2~0.5 之间越小动作越平滑但响应也越慢。注意这是一个需要在训练时就要加入的操作而不是迁移真机时才临时加。如果在训练时完全没有低通滤波测试时突然加入策略面对的动态环境相当于变了表现反而会变差。同时要对动作变化速率做限制比如每个控制周期动作变化不超过 0.2~0.4 rad。这两个措施叠加后策略输出的执行序列会更适合真机电机。6.4 最基础的落地测试先悬挂再半负重最后才是自由站立如果你有实体设备我的建议是不要一上来就松开安全绳直接跑。一个比较稳妥的流程是先做悬挂测试机器人大部分重量由吊带承担策略正常输出动作观察电机是否异常发烫、关节是否撞击限位然后逐渐降低吊带让部分重量落在脚上最后才尝试完全自由站立并从小速度指令开始。每次测试只改变一个变量这个原则非常重要。如果同时换了地面材质、又加了负载、又改了延迟参数一旦出了问题你根本不知道是哪个参数导致的。记录电流、关节温度和实际速度与仿真速度的差距这些数据会成为下一轮域随机化范围调整的重要参考。我自己的一个习惯是每次训练开始之前打印一次所有奖励分项的初始量级确认没有哪一项在数值上碾压其他项。这个习惯帮我规避了大量“策略学会躺平不动”的问题。希望这份训练03的记录也能让你在四足机器人强化学习的路上少踩几个同样的坑。