文章目录
- [技术文档:基于 PPO 的双足机器人行走控制](#技术文档:基于 PPO 的双足机器人行走控制)
-
- [1. 项目概述](#1. 项目概述)
-
- [1.1 背景与目标](#1.1 背景与目标)
- [1.2 主要贡献](#1.2 主要贡献)
- [2. 系统架构](#2. 系统架构)
- [3. 环境设计(Gymnasium 规范)](#3. 环境设计(Gymnasium 规范))
-
- [3.1 仿真环境](#3.1 仿真环境)
- [3.2 观测空间(Observation Space)](#3.2 观测空间(Observation Space))
- [3.3 动作空间(Action Space)](#3.3 动作空间(Action Space))
- [3.4 奖励函数(Reward Function)](#3.4 奖励函数(Reward Function))
- [4. 算法:PPO(近端策略优化)](#4. 算法:PPO(近端策略优化))
-
- [4.1 算法原理](#4.1 算法原理)
- [4.2 GAE(广义优势估计)](#4.2 GAE(广义优势估计))
- [4.3 网络结构](#4.3 网络结构)
- [5. 训练流程与超参数](#5. 训练流程与超参数)
-
- [5.1 训练循环(Stable-Baselines3 实现)](#5.1 训练循环(Stable-Baselines3 实现))
- [5.2 关键超参数表](#5.2 关键超参数表)
- [6. 实验结果与收敛性分析](#6. 实验结果与收敛性分析)
-
- [6.1 训练日志解读(早期阶段)](#6.1 训练日志解读(早期阶段))
- [6.2 预期收敛曲线](#6.2 预期收敛曲线)
- [6.3 模型演示](#6.3 模型演示)
- [7. 部署与演示](#7. 部署与演示)
-
- [7.1 加载训练好的模型](#7.1 加载训练好的模型)
- [7.2 实时可视化](#7.2 实时可视化)
- [8. 未来优化方向](#8. 未来优化方向)
- [9. 总结](#9. 总结)
技术文档:基于 PPO 的双足机器人行走控制
1. 项目概述
1.1 背景与目标
本项目旨在通过近端策略优化(Proximal Policy Optimization, PPO) 算法训练一个双足人形机器人(Humanoid)在物理仿真环境中学会稳定、持续的向前行走。相比传统的 A2C 算法,PPO 通过裁剪(Clipping)机制限制策略更新幅度,大幅提升了训练的稳定性和样本效率,已成为连续控制任务的工业级标准。
1.2 主要贡献
- 基于 Gymnasium 规范构建自定义强化学习环境,无缝对接主流算法库。
- 采用 Stable-Baselines3 的高效 PPO 实现,降低实现复杂度,提升可复现性。
- 设计了一套精细的奖励函数,引导机器人逐步从随机抖动进化为周期性步态。
- 完整的训练、评估、部署流水线,支持实时可视化。
2. 系统架构
项目包含三大核心模块,其交互关系如下:
#mermaid-svg-72enrskjdaVhzprv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-72enrskjdaVhzprv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-72enrskjdaVhzprv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-72enrskjdaVhzprv .error-icon{fill:#552222;}#mermaid-svg-72enrskjdaVhzprv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-72enrskjdaVhzprv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-72enrskjdaVhzprv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-72enrskjdaVhzprv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-72enrskjdaVhzprv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-72enrskjdaVhzprv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-72enrskjdaVhzprv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-72enrskjdaVhzprv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-72enrskjdaVhzprv .marker.cross{stroke:#333333;}#mermaid-svg-72enrskjdaVhzprv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-72enrskjdaVhzprv p{margin:0;}#mermaid-svg-72enrskjdaVhzprv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-72enrskjdaVhzprv .cluster-label text{fill:#333;}#mermaid-svg-72enrskjdaVhzprv .cluster-label span{color:#333;}#mermaid-svg-72enrskjdaVhzprv .cluster-label span p{background-color:transparent;}#mermaid-svg-72enrskjdaVhzprv .label text,#mermaid-svg-72enrskjdaVhzprv span{fill:#333;color:#333;}#mermaid-svg-72enrskjdaVhzprv .node rect,#mermaid-svg-72enrskjdaVhzprv .node circle,#mermaid-svg-72enrskjdaVhzprv .node ellipse,#mermaid-svg-72enrskjdaVhzprv .node polygon,#mermaid-svg-72enrskjdaVhzprv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-72enrskjdaVhzprv .rough-node .label text,#mermaid-svg-72enrskjdaVhzprv .node .label text,#mermaid-svg-72enrskjdaVhzprv .image-shape .label,#mermaid-svg-72enrskjdaVhzprv .icon-shape .label{text-anchor:middle;}#mermaid-svg-72enrskjdaVhzprv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-72enrskjdaVhzprv .rough-node .label,#mermaid-svg-72enrskjdaVhzprv .node .label,#mermaid-svg-72enrskjdaVhzprv .image-shape .label,#mermaid-svg-72enrskjdaVhzprv .icon-shape .label{text-align:center;}#mermaid-svg-72enrskjdaVhzprv .node.clickable{cursor:pointer;}#mermaid-svg-72enrskjdaVhzprv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-72enrskjdaVhzprv .arrowheadPath{fill:#333333;}#mermaid-svg-72enrskjdaVhzprv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-72enrskjdaVhzprv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-72enrskjdaVhzprv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-72enrskjdaVhzprv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-72enrskjdaVhzprv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-72enrskjdaVhzprv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-72enrskjdaVhzprv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-72enrskjdaVhzprv .cluster text{fill:#333;}#mermaid-svg-72enrskjdaVhzprv .cluster span{color:#333;}#mermaid-svg-72enrskjdaVhzprv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-72enrskjdaVhzprv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-72enrskjdaVhzprv rect.text{fill:none;stroke-width:0;}#mermaid-svg-72enrskjdaVhzprv .icon-shape,#mermaid-svg-72enrskjdaVhzprv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-72enrskjdaVhzprv .icon-shape p,#mermaid-svg-72enrskjdaVhzprv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-72enrskjdaVhzprv .icon-shape .label rect,#mermaid-svg-72enrskjdaVhzprv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-72enrskjdaVhzprv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-72enrskjdaVhzprv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-72enrskjdaVhzprv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 状态 s_t
观测空间 & 动作空间
动作 a_t
奖励 r_t, 终止标志
更新策略
保存模型
PyBullet 物理引擎
自定义 Gymnasium 环境
PPO 智能体
训练器
评估与部署
- 环境模块 :封装 PyBullet 的仿真循环,提供标准的
reset()和step()接口,并定义观测/动作空间。 - 智能体模块 :使用 SB3 的
PPO类,包含策略网络(Actor)和价值网络(Critic),通过 MLP 实现。 - 训练模块:负责收集轨迹、计算优势估计(GAE)、执行多轮梯度更新,并周期性评估模型性能。
3. 环境设计(Gymnasium 规范)
3.1 仿真环境
- 物理引擎:PyBullet 3.x(基于 Bullet 物理引擎),支持刚体动力学、碰撞检测、关节控制。
- 机器人模型 :采用 PyBullet 自带的
humanoid.urdf(位于pybullet_data/humanoid/humanoid.urdf)。该模型具有 4 个可动关节(简化双足),分别为左右髋、膝、踝关节,适合快速验证算法。
3.2 观测空间(Observation Space)
状态向量由 身体状态(12 维) 和 关节状态(每个关节 2 维:角度 + 角速度) 拼接而成,总维度为 12 + 4*2 = 20。
| 身体状态(12 维) | 关节状态(8 维) |
|---|---|
| 身体位置 (x, y, z) | 4 个关节角度 |
| 姿态欧拉角 (roll, pitch, yaw) | 4 个关节角速度 |
| 身体线速度 (vx, vy, vz) | - |
| 身体角速度 (wx, wy, wz) | - |
观测空间定义为 Box(low=-inf, high=inf, shape=(20,), dtype=np.float32)。
3.3 动作空间(Action Space)
每个动作向量对应 4 个关节的目标角度(弧度),范围限制在 [-1.5, 1.5],允许较大步幅。控制模式为位置控制(POSITION_CONTROL),施加恒定力矩(force=5.0)。
动作空间定义为 Box(low=-1.5, high=1.5, shape=(4,), dtype=np.float32)。
3.4 奖励函数(Reward Function)
奖励函数是引导策略优化的关键,由以下分量组成(权重见配置):
R = w f ⋅ Δ x + w e ⋅ ( − 1 n ∑ a i 2 ) + w a + w s ⋅ ∣ v x ∣ + R f a l l R = w_f \cdot \Delta x + w_e \cdot (-\frac{1}{n}\sum a_i^2) + w_a + w_s \cdot |v_x| + R_{fall} R=wf⋅Δx+we⋅(−n1∑ai2)+wa+ws⋅∣vx∣+Rfall
| 分量 | 计算公式 | 权重 | 作用 |
|---|---|---|---|
| 前进奖励 | Δ x \Delta x Δx(X 方向位移) | 2.0 | 鼓励向前移动 |
| 能量惩罚 | − 1 n ∑ a i 2 -\frac{1}{n}\sum a_i^2 −n1∑ai2(动作平方均值) | 0.005 | 抑制无效抖动,鼓励节能 |
| 存活奖励 | 常数 0.02 | 0.02 | 防止过早终止,鼓励生存 |
| 速度奖励 | $ | v_x | $(X 方向速度绝对值) |
| 摔倒惩罚 | 若摔倒则 -20.0 | -20.0 | 严厉惩罚摔倒,促使保持平衡 |
终止条件 (触发 terminated=True):
- 身体高度 < 0.3 m(摔倒)
- 滚转或俯仰角 > 57°(约 1 rad)
- 横向偏移 > 2.0 m
- 单回合步数超过
max_episode_steps=500
4. 算法:PPO(近端策略优化)
4.1 算法原理
PPO 是一种基于策略梯度的强化学习算法,通过引入裁剪(Clipping) 机制,在每次更新时限制新旧策略之间的差异,从而避免步长过大导致的性能崩溃。其核心目标函数为:
L C L I P ( θ ) = E t min ( r t ( θ ) A \^ t , clip ( r t ( θ ) , 1 − ϵ , 1 + ϵ ) A \^ t ) L^{CLIP}(\theta) = \mathbb{E}_t \left \\min\\left( r_t(\\theta) \\hat{A}_t, \\text{clip}(r_t(\\theta), 1-\\epsilon, 1+\\epsilon) \\hat{A}_t \\right) \\right LCLIP(θ)=Etmin(rt(θ)A\^t,clip(rt(θ),1−ϵ,1+ϵ)A\^t)
其中:
- r t ( θ ) = π θ ( a t ∣ s t ) π θ o l d ( a t ∣ s t ) r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)} rt(θ)=πθold(at∣st)πθ(at∣st) 为重要性采样比率。
- A ^ t \hat{A}_t A^t 为优势函数估计(使用 GAE 计算)。
- ϵ \epsilon ϵ 为裁剪范围(本项目设为 0.2)。
同时,策略网络和价值网络共享底层 MLP 特征提取器,联合优化策略损失、价值损失和熵正则项。
4.2 GAE(广义优势估计)
优势函数采用 GAE( λ \lambda λ) 形式,平衡偏差与方差:
A ^ t G A E ( γ , λ ) = ∑ l = 0 ∞ ( γ λ ) l δ t + l \hat{A}t^{GAE(\gamma,\lambda)} = \sum{l=0}^{\infty} (\gamma\lambda)^l \delta_{t+l} A^tGAE(γ,λ)=l=0∑∞(γλ)lδt+l
- γ = 0.99 \gamma = 0.99 γ=0.99(折扣因子)
- λ = 0.95 \lambda = 0.95 λ=0.95(GAE 系数)
4.3 网络结构
采用标准 MLP 架构:
| 模块 | 层 | 输入 | 输出 | 激活函数 |
|---|---|---|---|---|
| 共享特征 | 全连接 | 20 | 256 | ReLU |
| 共享特征 | 全连接 | 256 | 256 | ReLU |
| 策略头(均值) | 全连接 | 256 | 4 | 线性(无激活) |
| 策略头(标准差) | 可学习参数 | - | 4 | exp() 保证为正 |
| 价值头 | 全连接 | 256 | 1 | 线性 |
动作采样采用对角高斯分布,标准差可学习,初始值为 1.0。
5. 训练流程与超参数
5.1 训练循环(Stable-Baselines3 实现)
- 环境初始化 :创建
HumanoidGymEnv实例,并包装为DummyVecEnv(支持多环境并行,此处仅单环境)。 - 模型构建 :实例化
PPO类,配置超参数。 - 学习循环 :每轮收集
n_steps=2048步的轨迹,计算 GAE 优势,然后对这批数据进行n_epochs=10轮梯度更新,每轮分为batch_size=64的小批次。 - 评估回调 :每
eval_freq=10000步,在独立的评估环境中运行 5 个回合,记录平均奖励,若为当前最佳则保存模型。 - 模型保存:训练结束后保存最终模型。
5.2 关键超参数表
| 参数 | 值 | 说明 |
|---|---|---|
learning_rate |
3e-4 | Adam 优化器学习率 |
n_steps |
2048 | 每轮收集的步数 |
batch_size |
64 | 小批量大小 |
n_epochs |
10 | 每轮数据重复更新次数 |
gamma |
0.99 | 折扣因子 |
gae_lambda |
0.95 | GAE 系数 |
clip_range |
0.2 | PPO 裁剪范围 |
ent_coef |
0.01 | 熵正则系数(鼓励探索) |
max_grad_norm |
0.5 | 梯度裁剪范数(SB3 默认) |
6. 实验结果与收敛性分析
6.1 训练日志解读(早期阶段)
以下为训练开始后约 8000 步的日志片段:
| time/ | |
| fps | 232 |
| iterations | 4 |
| time_elapsed | 35 |
| total_timesteps | 8192 |
| train/ | |
| approx_kl | 0.009|
| clip_fraction | 0.062|
| entropy_loss | -5.65|
| explained_variance| 0.43|
| policy_gradient_loss| -0.0088 |
| value_loss | 2.33 |
approx_kl≈ 0.009 << 0.2,说明策略更新平稳,未触发严重裁剪。clip_fraction≈ 6%,在合理范围内,表示仅有少量样本被裁剪。explained_variance逐步提升至 0.4~0.7,表明价值函数对回报的拟合能力在增强。entropy_loss稳定在 -5.65(动作标准差 ~0.99),保持高探索性。
6.2 预期收敛曲线
- 0~5 万步:平均奖励为负(-20 ~ -5),机器人随机抖动并频繁摔倒。
- 5~20 万步:奖励逐渐上升,开始出现短暂平衡,偶尔能走几步。
- 20~50 万步:奖励转为正值,形成不稳定但持续的步态。
- 50~100 万步:奖励稳步提升,步态趋于稳定,平均速度约 0.5 m/s。
- 100~200 万步:收敛至最优策略,平均奖励稳定在 100~200 区间(取决于权重设计)。
6.3 模型演示
训练完成后,可通过加载模型进行部署(见第 7 节),机器人能在平坦地面上持续行走,保持良好平衡,并具有一定的抗干扰能力(轻度推力扰动)。
7. 部署与演示
7.1 加载训练好的模型
python
import gymnasium as gym
from stable_baselines3 import PPO
from train_ppo_gymnasium import HumanoidGymEnv # 自定义环境
# 加载模型
model = PPO.load("best_models/best_model.zip")
# 创建环境(带渲染)
env = HumanoidGymEnv(render=True)
obs, _ = env.reset()
while True:
action, _ = model.predict(obs, deterministic=True)
obs, reward, terminated, truncated, _ = env.step(action)
if terminated or truncated:
obs, _ = env.reset()
7.2 实时可视化
通过设置 render=True 即可弹出 PyBullet GUI 窗口,观察机器人实时运动状态。评估回调中的 render=False 可加速评估过程。
8. 未来优化方向
- 更复杂的模型 :替换为 17-DoF 全尺寸人形机器人(如
humanoid_symmetric.urdf),增加关节数量。 - 域随机化:在训练中随机扰动机器人的质量、摩擦力、地面摩擦系数,提升策略的鲁棒性。
- 奖励塑形:引入脚底接触力检测,奖励单脚支撑阶段,生成更自然的步态。
- 并行训练 :使用
SubprocVecEnv并行运行多个环境,大幅提高样本收集速度。 - Sim-to-Real:将训练好的策略迁移至真实机器人,需考虑系统辨识和仿真差距。
9. 总结
本项目成功运用 PPO 算法训练了一个简化双足机器人在 PyBullet 仿真环境中行走。通过合理设计奖励函数和超参数调整,模型能够从零开始学会稳定向前移动。整个流程基于 Gymnasium + Stable-Baselines3 的现代强化学习栈,具有良好的可扩展性和可复现性,可作为更复杂机器人控制任务的基础框架。