简介双足机器人强化学习项目是一个面向机器人爱好者和强化学习初学者的轻量示例包聚焦双足机器人在环境交互中学习稳定行走与执行任务的核心思路适合快速了解强化学习在足式机器人中的基本应用。压缩包共包含2个文件分别为1个Python脚本和1个Markdown说明文档整体仅485B结构极简便于直接查看与修改。目前已有141人学习该资源。虽然包体小巧但围绕双足机器人强化学习的典型流程提供了简洁的代码入口与文字说明可帮助读者理清模拟环境搭建、算法选择及任务训练的基本逻辑。对于刚接触人形机器人、机器狗等方向的研究者而言是一份低成本、易上手的入门参考有助于后续向深度强化学习、真实硬件部署等方向延伸。1. 双足机器人强化学习从“站都站不稳”到“自己学会走路”双足行走一直是个看上去简单、做起来极其复杂的问题。你给一个机器人写好精确的运动学方程让它按轨迹迈步结果换个地形就摔而强化学习走的是另一条路——不精确建模让机器人自己在仿真环境里摔几万次、试出最优策略。这份双足机器人强化学习项目.zip 里装的就是这么一套东西一个能跑的仿真训练入口、一个 hello.py 的交互脚本和一份 README 说明能让你从空白环境起步复现“从零训练到双足稳定行走”的完整流程。适合手里已经有 Python 和深度学习基础、想把强化学习落到机器人控制上的工程师也适合做毕业设计、课程设计的学生。下文我会拆开它的每个文件、关键参数和实际踩过的坑。2. 环境搭建与文件拆解先让 MuJoCo 跑起来2.1 物理仿真平台怎么选为什么是 MuJoCo 而不是 PyBullet双足机器人强化学习对物理引擎有三个硬性要求接触力求解要稳定、仿真速度要够快、并且能支持大量并行环境。MuJoCo 在这三点的综合表现是目前最成熟的。接触力在双足问题里是核心脚底和地面的交互、落地瞬间的冲击都要靠物理引擎正确处理MuJoCo 的软接触模型在双脚交替支撑的时候不容易出现明显的抖动这对训练收敛影响非常大。相比之下 PyBullet 的接触求解虽然也能用但在高步频、高动态的场景下更容易出现“机器人陷进地面”这类数值问题。pip install mujoco2.3.7 pip install gymnasium0.29.1 pip install stable-baselines32.2.1这是这套项目最常见的一组依赖组合。mujoco 2.3.7 版本对应的是稳定 API后续 3.x 改了不少调用方式gymnasium 0.29.1 和 stable-baselines3 2.2.1 搭配时不会出现gym命名空间冲突。注意不要装最新的 mujoco 3.x否则部分dm_control兼容层会失效。安装之后立刻做一个最小验证。import mujoco import gymnasium as gym # 用 mujoco 自带的人形机器人模型做冒烟测试 env gym.make(Humanoid-v4, render_modeNone) obs, _ env.reset() print(观测空间维度:, obs.shape)能正常输出维度就说明物理引擎和 Gym 接口没问题。这份资源里双足模型的 XML 文件是自定义的需要用 MuJoCo 原生的mujoco.MjModel.from_xml_string()加载而不是直接走 Gym 内置环境跑通这一步后面的训练循环才有基础。提示如果你在 Windows 上运行把 MuJoCo 和 gymnasium 装到同一个 conda 环境里不要把 gym 和 gymnasium 混用否则会出现重复注册 Environment 的错误。2.2 项目文件结构hello.py、README.md 和训练人口各自负责什么zip 包里文件不多但分工很清楚。README.md是入口写了运行顺序、依赖版本和模型文件位置hello.py是交互脚本加载已经训练好的策略在仿真环境里跑一次步态并输出关键状态数据。这个脚本名字起得朴素实际是验证环境是否可用的最小入口建议你第一次运行项目前先跑一遍它确认物理引擎能正常加载机器人模型。import mujoco import numpy as np model_path assets/double_robot.xml model mujoco.MjModel.from_xml_path(model_path) data mujoco.MjData(model) # 初始化仿真 5 秒持续给关节一个小激励观察机器人是否原地站立 for _ in range(int(5.0 / 0.02)): data.ctrl[:] 0.1 # 所有执行器输出 0.1 的扭矩 mujoco.mj_step(model, data) print(躯干高度:, data.qpos[2]) print(俯仰角:, data.qpos[4])这里的控制频率是 50Hz对应mj_step步长 0.02 秒data.ctrl是执行器输入向量0.1 的扭矩不足以让机器人走动但能验证模型有没有明显数值发散。如果躯干高度迅速掉到地面以下说明 XML 里的电机参数或者接触参数有问题先查actuator的gear和地面摩擦系数。完整训练入口通常是一个train.py或 Jupyter Notebook里面核心是三件事定义环境类、构建策略网络、启动 PPO 训练。环境类里最关键的是observation_space和reward定义。观测空间一般包含躯干姿态四元数、关节角度、角速度和上一时刻的执行器输出reward 则把“匀速前进、保持躯干直立、最小化关节力矩”三条子目标加权在一起。你直接打开这份资源里的环境定义文件能看到一个compute_reward函数下面拆开讲。def compute_reward(self, obs): height obs[2] # 躯干高度 pitch obs[4] # 俯仰角弧度制 velocity obs[22] # 前向速度 omega obs[25:28] # 角速度 reward 1.0 penalty 0.0 penalty 2.0 * abs(pitch) # 躯干越倾斜惩罚越重 penalty 0.5 * max(0.0, 1.2 - height) # 高度低于基准线开始惩罚 penalty 0.1 * np.sum(np.abs(omega)) # 转动太快不利于稳定 reward_velocity math.exp(-0.15 * (velocity - 0.6) ** 2) return reward - penalty reward_velocity这个 reward 结构体现的是典型的双足训练思路不直接给“走到某个点”的稀疏奖励而是给连续密集奖励让机器人每走一步都能收到正反馈。velocity目标值设 0.6 m/s是仿真环境里一个偏保守的速度调太高会导致策略变得激进、容易摔。pitch系数 2.0 是经验值太大了机器人会变得“僵硬”——宁可缓慢行进也不愿意迈步因为一迈步躯干必然倾斜太小了则容易前扑翻倒。3. 强化学习算法选型为什么 PPO 是双足机器人默认答案3.1 PPO 与 SAC 的边界连续控制任务怎么选双足机器人是连续动作空间、高维状态空间的问题可选的深度强化学习算法不少但实际跑训练的人最终基本都会回到 PPO 上。SAC 的样本效率更高理论上更适合对数据量敏感的任务但它有个对机器人领域很不友好的特性——最大熵框架会鼓励策略“探索更分散的动作”在仿真环境里表现为双腿乱蹬、动作频率高但方向混乱。双足行走需要的是“小幅修正”而非“大范围探索”SAC 的熵项反而起了反作用。PPO 走的是另一条路用重要性采样做多次更新但用 clip 限制每次更新的步长策略不会在单次迭代里变化过大。这意味着训练过程中即使 reward 曲线有波动策略参数也不容易崩掉。说白了PPO 的平均收敛速度不是最快的但稳定性最好适合双足这种“摔一次整套数据都白跑”的场景。# PPO 更新核心clip 目标函数是稳定性的关键 ratio torch.exp(log_probs_new - log_probs_old) surr1 ratio * advantages surr2 torch.clamp(ratio, 1.0 - clip_epsilon, 1.0 clip_epsilon) * advantages actor_loss -torch.min(surr1, surr2).mean()clip_epsilon一般取 0.2这是 PPO 论文里的默认值。你可以在 0.1 到 0.3 之间调但不要低于 0.05——太小会让策略更新几乎停滞学习速度肉眼可见地变慢也不要大于 0.3——一次迭代直接破坏掉前几千步积累的行走策略双足机器人瞬间回到“学步状态”。我在做实验时会把clip_epsilon从 0.2 调低到 0.15牺牲一点收敛速度换训练曲线更稳。价值网络的 loss 也要关注。PPO 的 critic 负责估计状态价值如果价值网络不收敛advantage 估计就是噪声actor 的训练信号会跟着乱。实践中用value_loss F.mse_loss(value, returns)就够了偶尔会加一个梯度裁剪防止价值网络在少数异常样本上把参数推得太远这个后面训练脚本里能看到。3.2 Actor-Critic 网络结构观测维度要怎么设计双足机器人网络的输入维度直接决定策略能学得多“聪明”。一个典型的观测向量包含躯干四元数4 维、线速度3 维、角速度3 维、关节角度n 维、关节角速度n 维、上一时刻的执行器输出n 维。你的机器人模型如果每条腿有 6 个自由度两条腿一共 12 个执行器那么观测就是4 3 3 12 12 12 46维。网络用三层 MLP 拼一个 GaussianMLP policy输入层接 46 维观测隐藏层 256 和 128输出层是 12 维动作均值加 12 维对数标准差。如果用的是 stable-baselines3这个结构它内部已经封装好了如果从零实现可以在Actor的 forward 里加一个tanh把动作压缩到[-1, 1]区间然后环境内部再把[-1, 1]映射到各关节实际的角度范围。class Actor(nn.Module): def __init__(self, obs_dim, action_dim): super().__init__() self.net nn.Sequential( nn.Linear(obs_dim, 256), nn.ReLU(), nn.Linear(256, 128), nn.ReLU(), nn.Linear(128, action_dim) ) self.log_std nn.Parameter(torch.zeros(action_dim)) def forward(self, obs): mean torch.tanh(self.net(obs)) std torch.exp(self.log_std.clamp(-2.3, 1.6)) return mean, stdlog_std初始为 0对应标准差是 1这个初始值偏大让早期策略足够“乱”以便探索。训练后期log_std会逐渐下降策略趋于确定性。但要注意clamp上限 1.6如果你不设上限极端情况下标准差可能涨到 5 甚至 10动作输出几乎全是噪声机器人会在原地剧烈抖腿、完全无法前进这是很典型的翻车现场。还有一个容易忽略的维度上一时刻执行器输出。这个信息对策略有“惯性记忆”的作用。双足机器人步行时髋关节和膝关节会根据前一步的出力来调整下一步的摆动幅度如果你不给网络上一时刻的动作它就只能靠观测到的关节角速度间接推断逼近精度下降步态会明显僵硬。实现上就是每次 step 时把data.ctrl的值 append 到下一帧的 obs 末尾。4. 训练与避坑从调参新手到稳定行走的血泪经验4.1 训练主循环parall 环境训练与关键超参双足机器人训练的一个核心事实是单环境的 PPO 几乎不可能训练成功。原因很简单——双足行走是稀疏的成功事件机器人前几百次尝试基本都在迈两步就摔倒纯靠单条轨迹收集样本reward 方差极大advantage 估计不准策略更新方向就是噪声。所以训练脚本里一定要用多环境并行采样。vec_env make_vec_env(lambda: BipedEnv(), n_envs16, seed42) model PPO( MlpPolicy, vec_env, n_steps2048, # 每条环境采样 2048 步 batch_size256, n_epochs10, gamma0.99, gae_lambda0.95, clip_range0.2, learning_rate3e-4, ent_coef0.005, # 熵系数很小但保留探索性 ) model.learn(total_timesteps5_000_000)n_envs16是入门级配置。有经验的训练者通常开 64 甚至 128 个并行环境但这要和 GPU 显存匹配——每个环境的观测都要送进网络计算 action显存不够反而会因为 CPU/GPU 同步等待拖慢整体速度。n_epochs10意味着每批样本要被 PPO 复用 10 次更新这也是一个稳定性和样本利用率的折中调大确实能更快吸收样本但超过 15 之后容易出现过拟合式震荡reward 曲线开始周期性上下跳。ent_coef0.005值得单独说。很多教程里把熵系数设成 0.01 甚至 0.1那是给离散动作空间用的连续动作空间下熵对策略的约束能力很强0.005 已经能保证早期足够的探索。如果训练中发现机器人在 50 万步之后频繁摔倒、步态退化往往就是熵系数不够小导致的策略不稳定调到 0.001 往往有奇效。4.2 稳定行走的关键设置Reward 权重表与域随机化训练过程中你会看到一个规律reward 曲线不平稳早期会长时间停留在很低的值然后突然跳升一截再回落再跳升像心电图一样。这种间歇性“跃迁”是正常的——机器人偶然试出一大步的正确步态PPO 抓住这个样本把策略拉向那个方向然后继续摸索。耐心等曲线趋势不要看短期波动。reward 的权重分配是一个需要反复实验的工作。下表是我这套仿真模型上最终调参得到的权重基准奖励项权重说明前向速度匹配0.6目标速度 0.6 m/s高斯核衰减躯干高度保持0.3低于 1.1m 开始惩罚俯仰角限制0.2超过 0.2 rad 惩罚加速关节力矩惩罚0.05防止策略用蛮力硬撑角速度阻尼0.1抑制身体转动过快这个权重表不是一次调出来的。我最初的版本把力矩惩罚设成 0.5结果机器人学会了“僵直站”一动不动反而 score 很高因为没有摔倒、躯干也直立了——策略钻了空子。把力矩惩罚降下来同时把前向速度项加进去策略才被迫去学真正的迈步。这就是 reward hacking 的典型场景你只优化了你写出来的指标而策略找到了一条你没想到的作弊路径。域随机化解决的是仿真到现实的鸿沟问题。双足行走依靠的是脚底与地面的摩擦力不同地材、不同坡度下摩擦力差别巨大。训练期每开一局新 episode 时随机化摩擦系数从 0.6 到 1.4、随机化地面高度起伏、随机化机器人躯干质量密度这样学出来的策略在真实环境里才不至于“只会在实验室光滑地面走路”。4.3 避坑四则现象、原因、解决一条条对照双足机器人 RL 训练是一个问题密度极高的领域。下面这四条是大多数项目会踩到的坑按照“现象 → 原因 → 解决”的顺序逐个说明。坑一训练跑了 200 万步机器人还是原地转圈。现象是策略学会了站立但完全没有前向位移reward 曲线平台期明显。原因是前向速度项太弱机器人只要站稳就能比其他动作拿到更高奖励。解决把前向速度项从 0.6 挪到 reward 的主项位置权重提到 1.0 以上同时加入“前进距离”的稀疏奖励每走过 0.5m 给一个额外 bonus。坑二reward 曲线一度很高但突然断崖式下跌然后长时间恢复不过来。原因是训练后期clip_range0.2的约束仍然允许策略大幅更新一次恰好碰到一组异常样本把策略推过了一个危险边界。解决先降低clip_range到 0.15然后调低learning_rate到 1e-4让每次更新都更保守。这两个参数是策略稳定性的基本盘。坑三训练在 50Hz 控制频率下正常提高频率到 100Hz 后步态退化。原因是高控制频率下每步之间的状态变化幅度变小PPO 在同一批样本里的 advantage 估计差异变小策略对细微偏差的敏感度降低。解决提高频率的同时把n_steps翻倍到 4096保证每一批样本覆盖足够的步态周期——双足行走通常需要 1.5 个完整步态周期以上才能提供有效的梯度和信息。坑四同一次训练器随机种子一变效果差异大。现象是用 seed 0 训练成功换 seed 2024 训练失败。原因是 PPO 的更新本身就带有较大的随机性深层 MLP 初始化权重在不同 seed 下会造成完全不同的早期探索方向。解决不追求单 seed 稳定固定一个训练效果最好的 seed 作为基准后续所有调参实验都在这个 seed 上比较。我以前头铁去追求多 seed 稳定结果大多数时间浪费在随机性上。实际操作里先用seed 42固定确认参数基本正确再花时间在其他 seed 上跑验证。注意PPO 里n_steps和gae_lambda的配合会显著影响训练稳定性。gae_lambda0.95能较好平衡偏差和方差建议只在 0.9 到 1.0 之间微调不要低于 0.9否则优势估计太短视机器人会只看眼前半秒而忽略迈步后躯干的长期稳定。5. 验证与评估衡量“学会了”的三个尺度训练完一个模型怎么确定它是真学会了还是运气好直接看 total reward 是不够的双足机器人至少有四个指标必须单独验证前向速度是否稳定、躯干高度波动幅度、步态周期是否对称、以及在随机地形下是否掉数据。这些指标在hello.py里已经部分实现了——加载策略后重新初始化MjData让机器人从站立状态开始走每 0.2 秒记录一次躯干高度和 x 方向速度。import numpy as np from stable_baselines3 import PPO model PPO.load(policy/final_model.zip) obs, _ env.reset() heights, velocities [], [] for step in range(300): action, _ model.predict(obs, deterministicTrue) obs, reward, terminated, truncated, _ env.step(action) if step % 4 0: # 每 0.08 秒记录一次 heights.append(env.unwrapped.data.qpos[2]) velocities.append(env.unwrapped.data.qvel[0]) if terminated: break print(f平均速度: {np.mean(velocities):.2f} m/s) print(f高度波动标准差: {np.std(heights):.3f} m)注意deterministicTrue是评估时必须设的——训练时策略带有随机噪声评估时必须关掉噪声否则测出来的指标是“带抖动的能力”不是真实水平。平均速度能到 0.4-0.6 m/s、高度波动标准差小于 0.05m说明策略已经能稳定行走。一个我习惯用的评估手段是长短周期对比先让机器人走 30 秒再让它连续走 5 分钟。很多时候 30 秒走得稳、5 分钟就翻车——原因是长时间行走会积累关节角的小幅偏移最终走出一个不平衡姿态。如果出现这种情况要把 reward 里“角速度阻尼”的权重调高 0.05让策略主动抑制每一次微小的姿态偏移。关于策略从仿真到真机的迁移一个经验仿真里往往不控制执行器的响应延迟但真实电机一定存在延迟。你可以在环境里给data.ctrl做一阶低通滤波让执行器变化不要那么突然。这个操作在训练时会把策略逼得更加平滑、不剧烈抖动最终迁移到真机时受益最大。我从那以后每次训练双足策略都会强制在环境里加一步低通滤波哪怕仿真效果看起来略微笨拙也不省略——策略平滑性决定了它能走多远。希望帮到你。本文还有配套的精品资源点击获取