项目名称:Legbot Lab
项目仓库:https://github.com/Robot-Nav/legbot_lab
默认分支:
PPO扩展分支:
PPO-CTS-MOE核心算法:PPO、非对称 Actor-Critic、历史观测、并发教师---学生学习、Mixture of Experts
仿真平台:NVIDIA Isaac Sim / Isaac Lab、MuJoCo
部署方式:TorchScript / ONNX、C++17、CycloneDDS、串口网关
开源许可证:Apache License 2.0
相关论文:Combining Teacher-Student with Representation Learning: A Concurrent Teacher-Student Reinforcement Learning Paradigm for Legged Locomotion
1. 项目定位
Legbot Lab 是一套面向自研四足机器人的强化学习运动控制工程。它并不是单独的 PPO 训练脚本,而是把机器人模型、并行仿真、奖励设计、域随机化、策略导出、MuJoCo 复现、C++ 控制器、DDS 通信和实物串口网关串成了一条完整链路。
项目主要解决三个问题。
第一,四足机器人在真实环境中很难准确获得完整状态。基座线速度、地形高度、足端接触力和实际关节力矩在仿真中容易获取,但在实物上往往需要额外传感器或复杂估计器。项目通过非对称 Actor-Critic 和教师---学生结构,使训练阶段可以利用特权信息,部署阶段只依赖 IMU、关节编码器、速度命令和历史观测。
第二,仿真模型与真实机器人存在差异。质量、质心、惯量、地面摩擦、编码器零位、电机响应、控制延迟和通信周期都会影响策略迁移。项目通过域随机化、电机力矩---速度曲线、摩擦模型、动作延迟和 Sim2Sim 检查降低 Sim2Real 风险。
第三,强化学习策略需要进入真实控制系统。项目没有停留在 Python 推理,而是提供 ONNX/TorchScript 导出、C++ 控制器、有限状态机、安全限制、DDS 抽象层和串口协议网关,使同一套高层控制逻辑能够连接 MuJoCo 或真实机器人。

2. 两个分支分别包含什么
2.1 PPO 分支
PPO 是默认分支,重点是完整工程闭环。
其核心内容包括:
- 基于 Isaac Lab 和 RSL-RL 的速度跟踪 PPO 训练;
- 10 帧历史观测与非对称 Actor-Critic;
- 质量、惯量、质心、摩擦、PD 增益、零位偏移和推扰随机化;
- TorchScript、ONNX 与
deploy.yaml导出; - C++ 有限状态机和 ONNX Runtime 推理;
- MuJoCo DDS 仿真器;
serial_dds_gateway串口---DDS 网关;- 控制器与仿真器、真实机器人共用 DDS 接口。
从工程角度看,这个分支更适合研究"怎样把训练策略可靠地放到真实四足机器人上"。
2.2 PPO-CTS-MOE 分支
该分支在 PPO 基础上加入并发教师---学生学习和专家混合网络,重点是提高仅依赖本体感知时的地形适应能力。
其核心内容包括:
- 教师环境与学生环境并行采样;
- 教师编码器使用特权观测;
- 学生编码器只使用可部署观测;
- 学生侧使用 8 个专家网络及门控网络;
- 教师、学生共享 Actor 与 Critic;
- PPO 损失、潜变量蒸馏损失和专家负载均衡损失联合训练;
- 导出时仅保留学生编码器和 Actor;
- 提供 MuJoCo 平地、楼梯、箱体和坡道场景验证。
这个分支更适合研究"如何利用仿真特权信息训练出只依赖本体传感器的实物策略"。
2.3 为什么需要分开说明
两个分支的主要差异如下。
| 项目 | PPO 分支 |
PPO-CTS-MOE 分支 |
|---|---|---|
| 任务名称 | Unitree-Legbot-Velocity |
RobotLab-Legbot-v0 |
| 核心算法 | PPO | PPO + CTS + MoE |
| 训练源码 | legbot_rl_lab/source/unitree_rl_lab |
source/robot_lab 与 source/rsl_rl |
| 策略输入 | 10 帧历史观测 | 历史观测进入学生编码器,Actor 还拼接单帧观测 |
| 部署重点 | C++、DDS、串口网关、实物闭环 | Python MuJoCo Sim2Sim 与学生策略导出 |
| 典型依赖 | Isaac Lab 2.2.0、RSL-RL 2.3.1 | Isaac Lab 2.3.2.post1、自定义 RSL-RL |
| 策略导出 | ONNX、TorchScript、部署 YAML | 学生分支 TorchScript/ONNX,内部维护历史缓存 |
3. 项目总体架构
完整系统可分为训练层、策略层、仿真验证层和硬件执行层。
3.1 训练层
Isaac Lab 负责物理仿真、并行环境、传感器、地形和 MDP 管理。RSL-RL 负责 PPO 采样、GAE、策略更新、模型保存和日志记录。
训练时默认创建 4096 个并行环境。物理仿真步长为 0.005 s,即 200 Hz;decimation=4,每 4 个物理步调用一次策略,因此策略控制频率为:
f p o l i c y = 1 0.005 × 4 = 50 H z f_{\mathrm{policy}}=\frac{1}{0.005\times4}=50\ \mathrm{Hz} fpolicy=0.005×41=50 Hz
这里需要注意,仓库部分注释把 4 倍降采样写成了"80 ms",但根据 sim.dt=0.005 和 decimation=4 计算,实际控制周期是 0.02 s,即 20 ms。
3.2 策略层
策略网络接收机器人本体观测和速度命令,输出 12 维关节动作。动作不是直接力矩,而是相对于默认关节角的偏移量。
策略输出经过动作缩放后得到目标关节角,再由 PD 控制器计算关节力矩。训练中的电机模型进一步加入力矩---速度限幅、摩擦和延迟。
3.3 验证层
策略在 Isaac Lab 中完成训练后,需要在另一套物理引擎中验证。项目使用 MuJoCo 进行 Sim2Sim 测试,主要检查:
- URDF/MJCF 关节顺序是否一致;
- 四元数顺序和坐标系是否一致;
- 默认关节角与动作缩放是否一致;
- 策略频率、PD 频率和物理仿真频率是否一致;
- 地面接触模型变化后策略是否仍能稳定运行;
- ONNX/TorchScript 推理结果是否与 Python 训练端一致。
3.4 硬件层
默认 PPO 分支在实物端使用 Orange Pi 6。控制器运行有限状态机和策略推理,串口网关负责 RobStride 电机和自制 IMU 协议,再通过 DDS 与控制器交换低层状态和命令。
控制器与硬件之间通过通信抽象层解耦,便于将 MuJoCo 对端替换为真实串口网关。
4. 目录结构与模块职责
4.1 PPO 分支主要目录
text
legbot_lab/
├── env_cfg.py
├── legbot/
├── legbot_rl_lab/
│ ├── source/unitree_rl_lab/
│ │ └── unitree_rl_lab/
│ │ ├── assets/robots/
│ │ ├── tasks/locomotion/
│ │ │ ├── agents/
│ │ │ ├── mdp/
│ │ │ └── robots/legbot/
│ │ └── utils/
│ ├── scripts/rsl_rl/
│ ├── deploy/
│ └── unitree_ros/
├── simulate/
├── serial_dds_gateway/
├── terrain_tool/
├── unitree_sdk2/
├── sim2real要求.md
└── 项目详解.md
其中:
env_cfg.py:根目录汇总环境配置,包含场景、观测、动作、奖励、随机化、课程和终止条件;assets/robots:机器人 URDF、关节参数和执行器模型;tasks/locomotion/agents:PPO 网络与训练超参数;tasks/locomotion/mdp:奖励、观测、命令、课程和事件函数;tasks/locomotion/robots/legbot:Legbot 任务配置;scripts/rsl_rl/train.py:训练入口;scripts/rsl_rl/play.py:推理、模型加载和策略导出;deploy:C++ 控制器、FSM、安全限制和 ONNX Runtime 推理;simulate:MuJoCo 与 DDS 桥接仿真器;serial_dds_gateway:真实电机和 IMU 的协议转换;terrain_tool:地形生成工具;legbot:另一套独立的 NumPy/MuJoCo 任务实验代码,不是主 PPO 训练入口。
4.2 PPO-CTS-MOE 分支主要目录
text
legbot_lab/
├── scripts/rsl_rl/
├── source/
│ ├── robot_lab/
│ │ └── robot_lab/
│ │ ├── assets/
│ │ └── tasks/
│ │ ├── go2/
│ │ └── legbot/
│ └── rsl_rl/
│ └── rsl_rl/
│ ├── algorithms/moe_cts.py
│ ├── modules/actor_critic_moe_cts.py
│ ├── networks/moe.py
│ ├── runners/on_policy_runner_cts.py
│ ├── storage/rollout_storage_cts.py
│ └── utils/exporter_cts.py
├── deploy/deploy_mujoco/
├── resources/legbot/
├── src/
└── TECHNICAL_DOC_zh.md
关键文件作用如下。
| 文件 | 作用 |
|---|---|
moe_cts.py |
PPO 与学生蒸馏的联合优化 |
actor_critic_moe_cts.py |
教师编码器、学生编码器、Actor 和 Critic 组合 |
moe.py |
专家网络、门控网络和专家加权 |
on_policy_runner_cts.py |
采样、回报计算、更新和保存 |
rollout_storage_cts.py |
区分教师与学生样本的轨迹存储 |
exporter_cts.py |
导出仅保留学生侧的部署策略 |
env_cfg.py |
观测、动作、奖励、随机化和地形配置 |
rsl_rl_cfg.py |
网络结构、教师比例、专家数和 PPO 超参数 |
deploy_legbot.py |
MuJoCo 推理与 PD 控制循环 |
5. Legbot 机器人模型
5.1 自由度和关节结构
Legbot 为 12 自由度四足机器人,每条腿包含 3 个关节:
- Hip:髋关节侧摆;
- Thigh:大腿关节前后摆;
- Calf:小腿关节屈伸。
四条腿按前左、前右、后左、后右排列。不同分支和不同模型文件中可能采用 FL/FR/RL/RR 或 FR/FL/RR/RL 顺序,因此部署前必须以导出的关节映射为准,不能仅依靠文件名猜测。
默认站立关节角通常为:
q d e f a u l t = 0 , 0.9 , − 1.8 × 4 q_{\mathrm{default}}= 0,\\ 0.9,\\ -1.8\times4 qdefault=0, 0.9, −1.8×4
即每条腿的 Hip、Thigh、Calf 分别为 0、0.9 和 -1.8 rad。
5.2 机器人参数
默认 PPO 分支 README 给出的当前模型参数包括:
| 参数 | 数值 |
|---|---|
| 总质量 | 约 14 kg |
| 基座质量 | 6.584 kg |
| 自由度 | 12 |
| 大腿长度 | 0.1985 m |
| 小腿长度 | 0.214 m |
| 足端半径 | 0.021 m |
| 髋/大腿峰值力矩 | 约 ±16 N·m |
| 小腿峰值力矩 | 约 ±32 N·m |
| 板载计算机 | Orange Pi 6 |
| 控制器频率 | 1 kHz |
| 串口网关频率 | 500 Hz |

5.3 惯量和质心为什么重要
四足机器人策略对质心和惯量十分敏感。基座质心偏差会改变支撑多边形中的重力投影位置,惯量偏差会改变相同关节动作对应的机身角加速度。
若仿真中质心偏前,而实物质心偏后,策略可能表现为:
- 启动时前腿下压;
- 前髋关节长期输出较大力矩;
- 后腿摆动幅度不足;
- 加速和刹停时俯仰振荡;
- 平地可运行,但楼梯或推扰下迅速失稳。
因此,Sim2Real 前应重新测量整机质量、各连杆质量、基座质心和主要惯量,并在 URDF、MJCF、Isaac Lab 资产和部署配置中保持一致。
6. 强化学习任务的 MDP 建模
四足速度跟踪可写成部分可观测马尔可夫决策过程。完整系统状态记为 s t s_t st,实物能够获得的观测记为 o t o_t ot,动作记为 a t a_t at,奖励记为 r t r_t rt。
策略目标是最大化期望折扣回报:
J ( θ ) = E π θ ∑ t = 0 ∞ γ t r t J(\theta)=\mathbb{E}{\pi\theta}\left\\sum_{t=0}\^{\\infty}\\gamma\^t r_t\\right J(θ)=Eπθt=0∑∞γtrt
其中 γ \gamma γ 为折扣因子。
6.1 为什么是部分可观测问题
实物通常不能直接获得以下状态:
- 精确的基座世界系线速度;
- 脚下地形高度图;
- 足端真实接触力;
- 每个关节的真实输出力矩;
- 精确的摩擦系数、负载和电机温度状态。
但策略可以从一段历史观测中推断部分隐状态。例如,连续 10 帧 IMU 和关节状态可以反映身体加速度、支撑相变化和地形冲击。因此项目在 Actor 侧使用历史观测,缓解单帧观测的不可观问题。
7. PPO 算法原理
PPO 是一种 on-policy Actor-Critic 算法。它先用当前策略采集轨迹,再使用这批数据更新策略。旧数据在策略明显变化后不再反复使用。

7.1 概率比
旧策略为 π θ o l d \pi_{\theta_{\mathrm{old}}} πθold,新策略为 π θ \pi_\theta πθ。同一动作在新旧策略下的概率比为:
r t ( θ ) = π θ ( a t ∣ o t ) π θ o l d ( a t ∣ o t ) r_t(\theta)= \frac{\pi_\theta(a_t|o_t)} {\pi_{\theta_{\mathrm{old}}}(a_t|o_t)} rt(θ)=πθold(at∣ot)πθ(at∣ot)
当 r t > 1 r_t>1 rt>1 时,新策略更倾向于选择该动作;当 r t < 1 r_t<1 rt<1 时,新策略降低了该动作的概率。
7.2 裁剪代理目标
PPO 使用裁剪限制单次更新幅度:
L C L I P ( θ ) = E t min ( r t ( θ ) A \^ t , clip ( r t ( θ ) , 1 − ϵ , 1 + ϵ ) A \^ t ) L^{\mathrm{CLIP}}(\theta)= \mathbb{E}_t \left \\min \\left( r_t(\\theta)\\hat A_t,\\ \\operatorname{clip} \\left( r_t(\\theta),1-\\epsilon,1+\\epsilon \\right)\\hat A_t \\right) \\right LCLIP(θ)=Etmin(rt(θ)A\^t, clip(rt(θ),1−ϵ,1+ϵ)A\^t)
项目常用:
ϵ = 0.2 \epsilon=0.2 ϵ=0.2
优势为正时,策略希望提高该动作概率;优势为负时,策略希望降低该动作概率。裁剪项避免概率比偏离 1 过远,从而降低训练崩溃概率。
7.3 TD 残差
值函数 V ϕ ( s t ) V_\phi(s_t) Vϕ(st) 估计从当前状态出发的期望回报。单步 TD 残差为:
δ t = r t + γ V ϕ ( s t + 1 ) − V ϕ ( s t ) \delta_t= r_t+\gamma V_\phi(s_{t+1})-V_\phi(s_t) δt=rt+γVϕ(st+1)−Vϕ(st)
7.4 广义优势估计
项目使用 GAE 平衡偏差与方差:
A ^ t = ∑ l = 0 T − t − 1 ( γ λ ) l δ t + l \hat A_t= \sum_{l=0}^{T-t-1} (\gamma\lambda)^l\delta_{t+l} A^t=l=0∑T−t−1(γλ)lδt+l
其中:
γ = 0.99 , λ = 0.95 \gamma=0.99,\qquad \lambda=0.95 γ=0.99,λ=0.95
7.5 目标回报
R ^ t = A ^ t + V ϕ ( s t ) \hat R_t=\hat A_t+V_\phi(s_t) R^t=A^t+Vϕ(st)
7.6 价值函数损失
L V F ( ϕ ) = E t ( V ϕ ( s t ) − R \^ t ) 2 L^{\mathrm{VF}}(\phi)= \mathbb{E}_t \left \\left( V_\\phi(s_t)-\\hat R_t \\right)\^2 \\right LVF(ϕ)=Et(Vϕ(st)−R\^t)2
RSL-RL 还可使用裁剪值函数损失,限制新旧价值估计变化。
7.7 策略熵
高斯策略的熵用于保持探索:
H π θ = − E a ∼ π θ log π θ ( a ∣ o ) H\\pi_\\theta= -\mathbb{E}{a\sim\pi\theta} \left \\log \\pi_\\theta(a\|o) \\right Hπθ=−Ea∼πθlogπθ(a∣o)
7.8 总损失
训练时最小化的损失可写为:
L = − L C L I P + c v L V F − c e H π θ L= -L^{\mathrm{CLIP}} +c_v L^{\mathrm{VF}} -c_e H\\pi_\\theta L=−LCLIP+cvLVF−ceHπθ
典型参数为:
c v = 1.0 , c e = 0.01 c_v=1.0,\qquad c_e=0.01 cv=1.0,ce=0.01
7.9 一次迭代包含多少数据
默认并行环境数量为 4096,每个环境采集 24 个控制步,因此一次 rollout 包含:
N s a m p l e = 4096 × 24 = 98304 N_{\mathrm{sample}}=4096\times24=98304 Nsample=4096×24=98304
这些样本被分成 4 个 mini-batch,并训练 5 个 epoch。需要区分三个概念:
- rollout:用当前策略采集一批数据;
- mini-batch:一次梯度计算使用的数据子集;
- epoch:对同一批 rollout 数据完整遍历一次。
8. 非对称 Actor-Critic
项目的 Actor 和 Critic 使用不同观测。
8.1 Actor 观测
单帧策略观测共 45 维:
| 观测项 | 维度 | 典型缩放 | 典型噪声 |
|---|---|---|---|
| 基座角速度 | 3 | 0.25 | U ( − 0.2 , 0.2 ) U(-0.2,0.2) U(−0.2,0.2) |
| 投影重力 | 3 | 1.0 | U ( − 0.05 , 0.05 ) U(-0.05,0.05) U(−0.05,0.05) |
| 速度命令 | 3 | 1.0 | 无 |
| 相对默认关节位置 | 12 | 1.0 | U ( − 0.03 , 0.03 ) U(-0.03,0.03) U(−0.03,0.03) |
| 关节速度 | 12 | 0.05 | U ( − 2 , 2 ) U(-2,2) U(−2,2) |
| 上一动作 | 12 | 1.0 | 无 |
PPO 分支设置 10 帧历史并展平,因此 Actor 输入为:
45 × 10 = 450 45\times10=450 45×10=450
历史观测能够帮助策略隐式推断线速度、接触状态、动作延迟和地形变化。
8.2 Critic 特权观测
Critic 在训练阶段额外使用:
- 基座线速度;
- 关节加速度;
- 关节力矩;
- 足端接触力;
- 地形高度扫描。
Critic 不加观测噪声,有利于稳定价值估计。部署时 Critic 不参与动作输出,因此这些特权信息不需要在实物端提供。
8.3 投影重力
世界坐标系重力方向为:
g w = 0 0 − 1 T g_w= \begin{bmatrix} 0&0&-1 \end{bmatrix}^{\mathrm T} gw=00−1T
利用基座旋转矩阵 R w b R_{wb} Rwb,重力在机体系中的表示为:
g b = R w b T g w g_b=R_{wb}^{\mathrm T}g_w gb=RwbTgw
当机身水平时, g b g_b gb 接近 0 , 0 , − 1 T 0,0,-1^{\mathrm T} 0,0,−1T。其 x x x 和 y y y 分量能够反映俯仰和横滚倾斜。
9. 动作空间与底层 PD 控制
策略输出 12 维动作:
a t ∈ R 12 a_t\in\mathbb{R}^{12} at∈R12
动作映射到目标关节角:
q d e s = q d e f a u l t + s a a t q_{\mathrm{des}}= q_{\mathrm{default}}+ s_a a_t qdes=qdefault+saat
其中动作缩放:
s a = 0.25 r a d s_a=0.25\ \mathrm{rad} sa=0.25 rad
因此,当策略输出为 1 时,对应关节目标相对默认角增加 0.25 rad。
PD 控制器计算力矩:
τ P D = K p ( q d e s − q ) + K d ( q ˙ d e s − q ˙ ) \tau_{\mathrm{PD}}= K_p(q_{\mathrm{des}}-q) + K_d(\dot q_{\mathrm{des}}-\dot q) τPD=Kp(qdes−q)+Kd(q˙des−q˙)
位置策略通常令:
q ˙ d e s = 0 \dot q_{\mathrm{des}}=0 q˙des=0
不同配置文件中训练增益和部署站立增益不完全相同。当前 README 中常见设置包括训练 K p = 50 K_p=50 Kp=50、 K d = 3 K_d=3 Kd=3,FixStand 状态使用 K p = 60 K_p=60 Kp=60、 K d = 4 K_d=4 Kd=4。实际部署必须读取导出的配置和 C++ 控制器参数,不能只参考文章中的示例值。
10. 电机模型
仅用理想 PD 力矩会高估真实电机能力。项目在仿真中加入摩擦、力矩---速度曲线和延迟。
10.1 摩擦模型
实际力矩可写为:
τ a c t u a l = τ P D − F s tanh ( q ˙ V a ) − F d q ˙ \tau_{\mathrm{actual}}= \tau_{\mathrm{PD}} -F_s\tanh\left(\frac{\dot q}{V_a}\right) -F_d\dot q τactual=τPD−Fstanh(Vaq˙)−Fdq˙
其中:
- F s F_s Fs:库仑摩擦幅值;
- F d F_d Fd:粘性摩擦系数;
- V a V_a Va:零速附近的平滑过渡参数。
双曲正切函数避免符号函数在零速度附近不连续。
10.2 力矩---速度限幅
低速时电机可输出接近峰值力矩,速度超过拐点后,允许力矩逐渐下降。简化表达为:
τ max ( ω ) = { Y , ∣ ω ∣ < X 1 Y X 2 − ∣ ω ∣ X 2 − X 1 , X 1 ≤ ∣ ω ∣ ≤ X 2 0 , ∣ ω ∣ > X 2 \tau_{\max}(\omega)= \begin{cases} Y, & |\omega|<X_1 \\ Y\dfrac{X_2-|\omega|}{X_2-X_1}, & X_1\le|\omega|\le X_2 \\ 0, & |\omega|>X_2 \end{cases} τmax(ω)=⎩ ⎨ ⎧Y,YX2−X1X2−∣ω∣,0,∣ω∣<X1X1≤∣ω∣≤X2∣ω∣>X2
PPO-CTS-MOE 分支 README 给出的 Go2 HV 示例参数为:
| 参数 | 数值 |
|---|---|
| X 1 X_1 X1 | 13.5 rad/s |
| X 2 X_2 X2 | 30 rad/s |
| Y 1 Y_1 Y1 | 20.2 N·m |
| Y 2 Y_2 Y2 | 23.4 N·m |

10.3 电机延迟
电机层设置 0~4 个控制步延迟。控制周期为 20 ms 时,对应:
T d e l a y ∈ 0 , 80 m s T_{\mathrm{delay}}\in0,80\ \mathrm{ms} Tdelay∈0,80 ms
需要确认延迟究竟施加在策略动作、目标位置还是执行器内部。仓库说明该延迟位于电机模型层,而不是简单地对策略输出做全局延迟。
11. 奖励函数设计
总奖励为多项加权和:
r t = ∑ i w i r i , t r_t=\sum_i w_i r_{i,t} rt=i∑wiri,t
奖励设计并不是奖励项越多越好。每个奖励项都在塑造运动风格,多个项可能相互冲突。
11.1 线速度跟踪
r l i n = exp ( − ∥ v c m d x y − v b a s e x y ∥ 2 σ 2 ) r_{\mathrm{lin}}= \exp \left( -\frac{ \left\| v_{\mathrm{cmd}}^{xy} -v_{\mathrm{base}}^{xy} \right\|^2 }{\sigma^2} \right) rlin=exp(−σ2∥vcmdxy−vbasexy∥2)
项目常用:
σ = 0.5 \sigma=0.5 σ=0.5
指数核在误差较小时给出较高奖励,误差增大后奖励快速下降。
11.2 偏航角速度跟踪
r y a w = exp ( − ( ω c m d z − ω b a s e z ) 2 σ 2 ) r_{\mathrm{yaw}}= \exp \left( -\frac{ (\omega_{\mathrm{cmd}}^z-\omega_{\mathrm{base}}^z)^2 }{\sigma^2} \right) ryaw=exp(−σ2(ωcmdz−ωbasez)2)
11.3 垂直速度惩罚
r v z = − ( v b a s e z ) 2 r_{v_z}= -\left(v_{\mathrm{base}}^z\right)^2 rvz=−(vbasez)2
用于抑制机身上下跳动。
11.4 横滚和俯仰角速度惩罚
r ω x y = − ∥ ω b a s e x y ∥ 2 r_{\omega_{xy}}= -\left\| \omega_{\mathrm{base}}^{xy} \right\|^2 rωxy=−∥ωbasexy∥2
11.5 关节力矩惩罚
r τ = − ∑ i τ i 2 r_{\tau}= -\sum_i\tau_i^2 rτ=−i∑τi2
11.6 关节功率惩罚
r p o w e r = − ∑ i ∣ τ i q ˙ i ∣ r_{\mathrm{power}}= -\sum_i \left| \tau_i\dot q_i \right| rpower=−i∑∣τiq˙i∣
该项比单独惩罚力矩更直接地约束机械功率。
11.7 动作变化率
r Δ a = − ∥ a t − a t − 1 ∥ 2 r_{\Delta a}= -\left\| a_t-a_{t-1} \right\|^2 rΔa=−∥at−at−1∥2
11.8 二阶动作平滑
r s m o o t h = − ∥ a t − 2 a t − 1 + a t − 2 ∥ 2 r_{\mathrm{smooth}}=-\left\|a_t-2a_{t-1}+a_{t-2} \right\|^2 rsmooth=−∥at−2at−1+at−2∥2
该项抑制动作的高频变化,减少电机抖动。
11.9 基座高度
基座高度不直接使用世界系 z z z,而是利用高度扫描估计局部地面:
h b a s e = z b a s e − mean ( z r a y h i t ) h_{\mathrm{base}}=z_{\mathrm{base}} -\operatorname{mean}(z_{\mathrm{rayhit}}) hbase=zbase−mean(zrayhit)
高度惩罚为:
r h = − ( h b a s e − h t a r g e t ) 2 r_h= -\left( h_{\mathrm{base}}-h_{\mathrm{target}} \right)^2 rh=−(hbase−htarget)2
目标高度约为:
h t a r g e t = 0.28 m h_{\mathrm{target}}=0.28\ \mathrm m htarget=0.28 m
11.10 足端调节
项目参考 CTS 论文加入足端调节项,使摆腿不总是贴地走最短路径。一个常见表达为:
r f o o t = − ∑ i ∥ v i x y ∥ 2 exp ( − h i k h h t a r g e t ) r_{\mathrm{foot}}= -\sum_i \left\| v_{i}^{xy} \right\|^2 \exp \left( -\frac{h_i} {k_h h_{\mathrm{target}}} \right) rfoot=−i∑∥vixy∥2exp(−khhtargethi)
当足端高度较低时,水平滑动受到更强惩罚;足端抬高后,水平运动惩罚减弱,从而形成更合理的摆腿轨迹。
11.11 当前分支常见权重
| 奖励项 | 典型权重 | 作用 |
|---|---|---|
| 线速度跟踪 | +1.0~+1.5 | 跟踪前后和横向速度 |
| 偏航角速度跟踪 | +0.5~+0.75 | 跟踪转向命令 |
| 垂直速度 | -2.0,课程可趋近 0 | 抑制上下振荡 |
| 横滚/俯仰角速度 | -0.05 | 抑制机身摆动 |
| 基座高度 | -1.0 到 -10.0 | 保持目标高度 |
| 关节加速度 | -1e-7 | 抑制高频关节变化 |
| 关节功率 | -2e-5 | 降低能耗 |
| 关节力矩 | -1e-4 | 防止大力矩 |
| 动作变化率 | -0.01 | 平滑控制 |
| 二阶动作平滑 | -0.01 | 抑制动作抖动 |
| 不期望接触 | -1.0 | 防止大腿和小腿撞地 |
| 关节限位 | -2.0 | 避免越界 |
| 足端调节 | -0.05 | 抑制低高度滑动 |
奖励权重在仓库不同提交中有变化。复现实验时应以训练日志保存的 Hydra 配置为准,而不是以 README 表格为唯一依据。
12. 域随机化
域随机化的目标不是让仿真"更乱",而是在合理范围内覆盖真实系统的不确定性。
12.1 质量和惯量
| 参数 | 模式 | 范围 |
|---|---|---|
| 基座附加质量 | startup | − 1 , 1 -1,1 −1,1 kg |
| 其他连杆质量 | startup | 标称值的 0.9~1.1 倍 |
| 转动惯量 | startup | 标称值的 0.9~1.1 倍 |
| 基座质心 | startup | 各方向厘米级偏移 |
质量和惯量应联动更新。若只改变质量而不重算惯量,随机模型可能不符合真实刚体分布。
12.2 摩擦和恢复系数
项目对静摩擦、动摩擦和碰撞恢复系数进行随机化,以覆盖地砖、地毯、木板和粗糙地面等差异。
摩擦下界设为 0 会产生接近无摩擦的极端环境。若策略训练长期不稳定,可先将下界提高,再逐步放宽。
12.3 执行器参数
- K p K_p Kp 和 K d K_d Kd 缩放;
- 编码器零位偏移;
- 电机力矩上限;
- 关节摩擦;
- 电机延迟。
零位偏移随机化能够模拟装配误差和编码器标定误差,但范围过大时会改变默认站姿。应保证随机姿态仍在机械限位内。
12.4 初始状态
每个 episode 重置时随机化:
- 基座平面位置;
- 偏航角;
- 基座线速度和角速度;
- 关节位置;
- 关节速度;
- 基座高度。
随机初始状态能够提高恢复能力,但若初始姿态过于困难,策略会在早期大量摔倒,导致有效采样不足。
12.5 周期性推扰
项目每隔约 4 s 给机器人施加速度扰动,典型范围为:
Δ v x y ∈ − 0.4 , 0.4 m / s \Delta v_{xy}\in-0.4,0.4\ \mathrm{m/s} Δvxy∈−0.4,0.4 m/s
Δ ω ∈ − 0.6 , 0.6 r a d / s \Delta\omega\in-0.6,0.6\ \mathrm{rad/s} Δω∈−0.6,0.6 rad/s
推扰训练能提高抗冲击能力,但不能替代准确的动力学建模。
12.6 观测噪声
Actor 侧加入 IMU 和关节观测噪声,Critic 侧保持无噪声。这样既训练传感器鲁棒性,又避免价值网络估计过度抖动。
13. 课程学习
一次性把机器人放到最复杂地形和最大速度范围,容易导致训练早期全是失败样本。项目使用课程学习逐步增加难度。
13.1 地形课程
根据机器人在当前地形中的移动距离调整地形等级:
- 移动距离超过地形长度的一半,提高难度;
- 移动距离明显低于目标距离,降低难度;
- 平地、坡面、粗糙地形、楼梯和离散障碍按等级组织。
13.2 奖励权重课程
例如:
- 垂直速度惩罚从 -2.0 逐渐变到 0;
- 基座高度惩罚从 -1.0 逐渐增强到 -10.0。
这样可以让策略先学会移动,再逐步收紧姿态和高度要求。
13.3 命令范围课程
速度范围随训练迭代扩大。PPO-CTS-MOE 分支文档给出的示例为:
text
20,000 次迭代:
lin_vel_x = [-1, 1]
lin_vel_y = [-1, 1]
ang_vel_z = [-1.5, 1.5]
50,000 次迭代:
lin_vel_x = [-2, 2]
lin_vel_y = [-1, 1]
ang_vel_z = [-2, 2]
实际自研机器人能否达到该速度取决于腿长、电机能力、减速比、供电和机械强度。不能因为训练命令允许 2 m/s,就直接在实物上给出同样命令。
14. MoE-CTS 算法

14.1 传统两阶段教师---学生方法
传统做法通常分两步:
- 教师策略使用特权信息训练;
- 固定教师,再用监督学习训练学生模仿教师动作。
问题是学生训练阶段不会继续影响教师,教师也无法适应学生的表示能力。两阶段训练还需要分别保存、加载和调试两套过程。
14.2 并发教师---学生
CTS 把并行环境分成教师组和学生组。项目中教师环境比例为 0.75,学生环境比例为 0.25。
教师潜变量:
z t = L2Norm ( E t ( o c r i t i c ) ) z_t= \operatorname{L2Norm} \left( E_t(o_{\mathrm{critic}}) \right) zt=L2Norm(Et(ocritic))
学生潜变量:
z s = L2Norm ( E s ( o h i s t o r y ) ) z_s= \operatorname{L2Norm} \left( E_s(o_{\mathrm{history}}) \right) zs=L2Norm(Es(ohistory))
教师和学生共享同一个 Actor:
a ∼ π θ ( a ∣ z , o s i n g l e ) a\sim\pi_\theta \left( a\midz,o_{\\mathrm{single}} \right) a∼πθ(a∣z,osingle)
Critic 使用特权观测估值:
V = V ϕ ( z d e t a c h , o c r i t i c ) V= V_\phi \left( z_{\\mathrm{detach}},o_{\\mathrm{critic}} \right) V=Vϕ(zdetach,ocritic)
潜变量在进入 Critic 时停止梯度,可避免价值损失直接改变编码器表示。
14.3 潜变量蒸馏
学生编码器逼近教师编码器输出:
L l a t e n t = ∥ z s − stopgrad ( z t ) ∥ 2 2 L_{\mathrm{latent}}= \left\| z_s- \operatorname{stopgrad}(z_t) \right\|_2^2 Llatent=∥zs−stopgrad(zt)∥22
stopgrad 表示教师输出作为监督目标,不通过该损失反向更新教师编码器。
14.4 Mixture of Experts
学生编码器使用多个专家。门控网络输出专家权重:
g = Softmax ( G ( o h i s t o r y ) ) g= \operatorname{Softmax} \left( G(o_{\mathrm{history}}) \right) g=Softmax(G(ohistory))
第 i i i 个专家输出:
e i = E i ( B ( o h i s t o r y ) ) e_i= E_i \left( B(o_{\mathrm{history}}) \right) ei=Ei(B(ohistory))
学生潜变量为:
z s = L2Norm ( ∑ i = 1 N g i e i ) z_s= \operatorname{L2Norm} \left( \sum_{i=1}^{N}g_i e_i \right) zs=L2Norm(i=1∑Ngiei)
项目设置:
N = 8 N=8 N=8
不同专家可以分别对平地、坡面、楼梯、冲击恢复或不同运动模式形成差异化响应。门控不是硬切换,而是对专家输出进行连续加权。
14.5 专家负载均衡
如果门控长期只使用一个专家,其余专家将无法学习。项目加入负载均衡损失:
L b a l a n c e = ∥ mean ( g ) − 1 N 1 ∥ 2 2 L_{\mathrm{balance}}=\left\|\operatorname{mean}(g) -\frac{1}{N}\mathbf 1 \right\|_2^2 Lbalance= mean(g)−N11 22
学生总损失:
L s t u d e n t = L l a t e n t + α L b a l a n c e L_{\mathrm{student}}= L_{\mathrm{latent}} + \alpha L_{\mathrm{balance}} Lstudent=Llatent+αLbalance
其中:
α = 0.01 \alpha=0.01 α=0.01
14.6 联合优化目标
MoE-CTS 的总优化可概括为:
L t o t a l = L P P O + λ s L s t u d e n t L_{\mathrm{total}}= L_{\mathrm{PPO}} + \lambda_s L_{\mathrm{student}} Ltotal=LPPO+λsLstudent
PPO 负责提高任务回报,蒸馏损失负责让学生从本体历史观测中恢复教师潜变量。
14.7 部署时保留什么
部署阶段不保留:
- 教师编码器;
- Critic;
- 特权观测;
- 地形高度扫描;
- 仿真中的真实线速度和接触力。
部署阶段保留:
- 观测归一化;
- 历史缓存;
- 学生 MoE 编码器;
- Actor;
- 动作缩放和关节映射。
15. 训练超参数
15.1 PPO 分支常用参数
| 参数 | 数值 |
|---|---|
| 并行环境数 | 4096 |
| 每环境 rollout 步数 | 24 |
| PPO epoch | 5 |
| mini-batch 数 | 4 |
| 学习率 | 1 × 10 − 3 1 \times 10^{-3} 1×10−3 |
| 折扣因子 γ \gamma γ | 0.99 |
| GAE 参数 λ \lambda λ | 0.95 |
| 裁剪参数 ϵ \epsilon ϵ | 0.2 |
| 熵系数 | 0.01 |
| 价值损失系数 | 1.0 |
| 最大梯度范数 | 1.0 |
| 目标 KL | 0.01 |
| 物理步长 | 0.005 s |
| 控制降采样 | 4 |
| 策略频率 | 50 Hz |
| Episode 时长 | 25 s |
15.2 MoE-CTS 扩展参数
| 参数 | 数值 |
|---|---|
| 教师环境比例 | 0.75 |
| 学生环境比例 | 0.25 |
| 专家数量 | 8 |
| 潜变量维度 | 32 |
| 历史长度 | 10 |
| 学生编码器学习率 | 1 × 10 − 3 1 \times 10^{-3} 1×10−3 |
| 负载均衡系数 | 0.01 |
| 最大训练迭代 | 300000 |
| 模型保存间隔 | 500 |
16. 软件依赖
16.1 PPO 分支
仓库 README 给出的主要版本为:
| 类别 | 依赖 |
|---|---|
| 操作系统 | Linux,推荐 Ubuntu |
| Python | 与 Isaac Lab 2.2.0 环境一致 |
| 仿真 | Isaac Sim 5.0.0 |
| 训练框架 | Isaac Lab 2.2.0 |
| 强化学习 | RSL-RL 2.3.1 |
| 深度学习 | PyTorch + CUDA |
| 配置 | Hydra、YAML |
| 模型导出 | TorchScript、ONNX |
| C++ 推理 | ONNX Runtime 1.22.0 |
| 编译 | CMake、C++17 |
| 通信 | CycloneDDS、Unitree SDK2 |
| Sim2Sim | MuJoCo |
| 实物接口 | USB-CAN、USB 串口、自制 IMU 协议 |
Python 工程中还会使用:
- NumPy;
- SciPy;
- Gymnasium;
- Matplotlib;
- PyYAML;
- tqdm;
- psutil;
- trimesh;
- h5py;
- prettytable。
这些名称在仓库 pyproject.toml 的代码检查配置中出现,但并不等同于完整的固定版本依赖清单。以 Isaac Lab 环境和包内 setup.py 为准。
16.2 PPO-CTS-MOE 分支
该分支 README 给出的安装组合为:
bash
conda create -n legbot_lab python=3.11
conda activate legbot_lab
pip install --upgrade pip
pip install isaaclab[isaacsim,all]==2.3.2.post1 \
--extra-index-url https://pypi.nvidia.com
pip install -U torch==2.7.0 torchvision==0.22.0 \
--index-url https://download.pytorch.org/whl/cu128
python -m pip install -e source/robot_lab
python -m pip install -e source/rsl_rl
pip install mujoco pygame
这组版本与 PPO 分支不同。切换分支时建议单独创建 Conda 环境,避免 Isaac Lab、PyTorch、CUDA 和自定义 RSL-RL 相互覆盖。
16.3 C++ 侧常见系统库
实物部署通常还需要:
bash
sudo apt update
sudo apt install -y \
build-essential \
cmake \
git \
pkg-config \
libyaml-cpp-dev
CycloneDDS、Unitree SDK2 和 ONNX Runtime 的安装位置需要与 CMake 配置一致。aarch64 板载计算机必须使用 aarch64 版本的 ONNX Runtime,不能复制 x86_64 动态库。
17. PPO 分支运行步骤
17.1 获取代码
bash
git clone https://github.com/Robot-Nav/legbot_lab.git
cd legbot_lab
git checkout PPO
确认分支:
bash
git branch --show-current
输出应为:
text
PPO
17.2 激活 Isaac Lab 环境
bash
conda activate env_isaaclab
检查 Python:
bash
which python
python --version
17.3 安装训练包
在仓库根目录执行:
bash
pip install -e legbot_rl_lab/source/unitree_rl_lab
检查任务是否注册:
bash
python legbot_rl_lab/scripts/rsl_rl/train.py --help
17.4 启动训练
bash
python legbot_rl_lab/scripts/rsl_rl/train.py \
--task Unitree-Legbot-Velocity \
--headless \
--num_envs 4096 \
--max_iterations 50000
显存不足时先降低环境数:
bash
python legbot_rl_lab/scripts/rsl_rl/train.py \
--task Unitree-Legbot-Velocity \
--headless \
--num_envs 1024 \
--max_iterations 50000
17.5 指定随机种子
bash
python legbot_rl_lab/scripts/rsl_rl/train.py \
--task Unitree-Legbot-Velocity \
--headless \
--seed 42
正式对比实验至少使用 3~5 个随机种子,并报告均值和标准差。
17.6 恢复训练
自动恢复最新运行:
bash
python legbot_rl_lab/scripts/rsl_rl/train.py \
--task Unitree-Legbot-Velocity \
--resume \
--headless
手动指定:
bash
python legbot_rl_lab/scripts/rsl_rl/train.py \
--task Unitree-Legbot-Velocity \
--resume \
--load_run 2026-06-25_17-11-16 \
--checkpoint model_108.pt \
--headless
17.7 推理与导出
bash
python legbot_rl_lab/scripts/rsl_rl/play.py \
--task Unitree-Legbot-Velocity
典型导出目录:
text
logs/rsl_rl/unitree_legbot_velocity/<run_name>/exported/
├── policy.pt
├── policy.onnx
└── deploy.yaml
17.8 编译串口网关
bash
cd serial_dds_gateway
mkdir -p build
cd build
cmake -S .. -B .
cmake --build . -j$(nproc)
17.9 编译控制器
bash
cd legbot_rl_lab/deploy/robots/legbot
mkdir -p build
cd build
cmake -S .. -B .
cmake --build . -j$(nproc)
17.10 启动实物通信
终端 1:
bash
cd serial_dds_gateway
./build/dds_to_serial_gateway \
--serial-port-a /dev/myttyCAN0 \
--serial-port-b /dev/myttyCAN1 \
--imu-port /dev/myttyIMU \
--network lo \
--tick-hz 500 \
--joint-bias-load-file config/joint_prone_bias.fatu.txt \
--send-disable-on-exit
终端 2:
bash
cd legbot_rl_lab/deploy/robots/legbot
./build/legbot_ctrl --network lo
17.11 FSM 状态切换
项目状态机大致为:
text
Passive --LT+A--> FixStand --Start--> Velocity
^ ^ |
| | |
+------ LT+B -----+------ LT+B ------+
建议严格按以下顺序:
- 悬空或支撑状态检查电机方向;
- 进入 Passive,确认阻尼有效;
- 进入 FixStand,确认默认站姿与关节零位;
- 小幅速度命令测试;
- 再进入完整 RL 速度控制。

18. PPO-CTS-MOE 分支运行步骤
18.1 切换分支
bash
git checkout PPO-CTS-MOE
git branch --show-current
18.2 建立独立环境
bash
conda create -n legbot_moe_cts python=3.11
conda activate legbot_moe_cts
18.3 安装 Isaac Lab 和 PyTorch
bash
pip install --upgrade pip
pip install isaaclab[isaacsim,all]==2.3.2.post1 \
--extra-index-url https://pypi.nvidia.com
pip install -U torch==2.7.0 torchvision==0.22.0 \
--index-url https://download.pytorch.org/whl/cu128
CUDA 版本必须与显卡驱动兼容。安装前可检查:
bash
nvidia-smi
18.4 安装本地包
bash
python -m pip install -e source/robot_lab
python -m pip install -e source/rsl_rl
18.5 训练
bash
python scripts/rsl_rl/train.py \
--task=RobotLab-Legbot-v0 \
--headless
自定义参数:
bash
python scripts/rsl_rl/train.py \
--task=RobotLab-Legbot-v0 \
--headless \
--num_envs 4096 \
--max_iterations 300000 \
--experiment_name legbot_moe_cts \
--run_name seed42
18.6 评估和导出
bash
python scripts/rsl_rl/play.py \
--task=RobotLab-Legbot-v0 \
--checkpoint logs/rsl_rl/legbot_moe_cts/<run_name>/model_<iter>.pt
导出的学生策略内部维护历史缓存,因此部署端只需要持续输入当前单帧观测。
18.7 MuJoCo Sim2Sim
安装:
bash
pip install mujoco pygame
在配置中设置策略路径:
yaml
policy_path: "{ROOT_DIR}/logs/rsl_rl/legbot_moe_cts/<timestamp>/exported/policy.pt"
运行:
bash
python deploy/deploy_mujoco/deploy_legbot.py
切换场景可修改:
yaml
xml_path: "{ROOT_DIR}/resources/legbot/flat.xml"
可选场景包括:
text
flat.xml
stairs.xml
boxes.xml
stairs_and_slope.xml
19. Sim2Real 数据链路
19.1 训练端输出
训练端需要导出:
- 网络权重;
- 观测归一化参数;
- 观测顺序;
- 历史长度;
- 动作缩放;
- 默认关节角;
- 关节映射;
- 策略控制周期;
- 动作和观测裁剪范围。
缺少任何一项,都可能导致部署端输入与训练端不一致。
19.2 部署端输入构造
部署端单帧观测应严格按训练顺序拼接:
text
base_ang_vel
projected_gravity
velocity_commands
joint_pos_rel
joint_vel_rel
last_action
关节位置应使用:
q r e l = q − q d e f a u l t q_{\mathrm{rel}}=q-q_{\mathrm{default}} qrel=q−qdefault
关节速度应乘训练时相同缩放。投影重力必须采用相同四元数顺序和旋转方向。
19.3 历史缓存
对于 10 帧历史,部署端要明确:
- 新观测放在缓存头部还是尾部;
- 初始缓存填零还是重复第一帧;
- episode 重置时是否清空;
- 输入展平顺序是"按时间"还是"按特征";
- ONNX 导出是否已在模型内部维护缓存。
PPO-CTS-MOE 导出器说明策略内部维护历史,而 PPO 分支通常需要依据部署配置确认。
19.4 动作输出
推理输出需要经过:
- 动作裁剪;
- 动作缩放;
- 默认关节角偏置;
- 关节顺序映射;
- 机械限位;
- PD 控制;
- 电机侧力矩和速度限制。
20. 安全保护
真实机器人不能只依赖策略奖励约束。项目提供 FSM 和多级安全限制。
建议至少包含:
20.1 关节位置限制
q i min ≤ q i ≤ q i max q_i^{\min}\le q_i\le q_i^{\max} qimin≤qi≤qimax
20.2 关节速度限制
∣ q ˙ i ∣ ≤ q ˙ i max |\dot q_i|\le \dot q_i^{\max} ∣q˙i∣≤q˙imax
20.3 力矩限制
∣ τ i ∣ ≤ τ i max ( q ˙ i ) |\tau_i|\le \tau_i^{\max}(\dot q_i) ∣τi∣≤τimax(q˙i)
20.4 姿态保护
当横滚或俯仰超过阈值时,退出 RL 状态并进入阻尼或失能状态。
20.5 通信超时
若连续若干周期未收到新状态,应停止发送运动命令,不能继续复用旧动作。
20.6 温度、电压和电流保护
真实电机应监测:
- 绕组或驱动器温度;
- 母线电压;
- 电流;
- 通信错误码;
- 编码器异常。
20.7 急停
硬件急停必须独立于 RL、DDS 和主控软件,能够直接切断使能或进入安全阻尼。
21. 常见问题与排查方法
21.1 训练一启动就摔倒
重点检查:
- 默认关节角是否与模型一致;
- 重力方向和坐标系;
- 关节正方向;
- 初始基座高度;
- 足端碰撞体;
- 电机增益;
- 动作缩放;
- 关节顺序。
21.2 训练奖励增长,但机器人只抖动
可能原因:
- 跟踪奖励过大,平滑惩罚过小;
- 策略通过高频动作利用物理引擎误差;
- 控制频率与动作延迟不匹配;
- 关节加速度惩罚权重过小;
- 电机模型过于理想;
- 接触参数不合理。
21.3 Isaac Lab 能走,MuJoCo 不能走
依次检查:
- 关节顺序;
- 默认角;
- 动作缩放;
- PD 增益;
- 控制频率;
- 四元数顺序;
- IMU 坐标系;
- 质量和惯量;
- 足端摩擦;
- 策略输入归一化。
21.4 MuJoCo 能走,实物前倾
常见原因:
- 实物质心与 URDF 不一致;
- 前后腿电机零位不同;
- 小腿减速比映射错误;
- IMU 安装姿态未补偿;
- 实物电机力矩不足;
- 电池电压下降;
- 通信延迟大于训练随机化范围。
21.5 ONNX Runtime 找不到动态库
先查找:
bash
find /usr /usr/local /opt "$HOME" \
-name "libonnxruntime.so*" 2>/dev/null
临时加入:
bash
export LD_LIBRARY_PATH=/path/to/onnxruntime/lib:$LD_LIBRARY_PATH
长期配置可写入 /etc/ld.so.conf.d/onnxruntime.conf 后执行:
bash
sudo ldconfig
必须确认架构:
bash
file /path/to/libonnxruntime.so
uname -m
aarch64 系统不能加载 x86-64 动态库。
21.6 显存不足
降低:
--num_envs;- 相机或高度扫描分辨率;
- 地形数量;
- 渲染开销;
- 网络宽度;
- 历史长度。
训练时使用 --headless。
21.7 训练速度异常慢
检查:
- 是否误启用渲染;
- GPU Pipeline 是否启用;
- 环境数是否过少;
- CPU 是否成为地形生成瓶颈;
- 日志写盘是否过于频繁;
- 高度扫描射线数量是否过大;
- 是否在每步执行 Python 循环。
22. 配置修改入口
22.1 修改机器人模型
PPO 分支:
text
legbot_rl_lab/source/unitree_rl_lab/unitree_rl_lab/assets/robots/
legbot_rl_lab/unitree_ros/robots/legbot_description/
PPO-CTS-MOE 分支:
text
source/robot_lab/robot_lab/assets/
resources/legbot/
legbot_description/
22.2 修改观测和动作
查找:
text
ObservationsCfg
ActionsCfg
JointPositionActionCfg
history_length
22.3 修改奖励
查找:
text
RewardsCfg
rewards.py
track_lin_vel
action_rate
base_height
feet_regulation
22.4 修改域随机化
查找:
text
EventCfg
randomize_rigid_body_mass
randomize_rigid_body_com
randomize_actuator_gains
push
friction
22.5 修改 PPO 参数
查找:
text
rsl_rl_ppo_cfg.py
rsl_rl_cfg.py
num_steps_per_env
num_learning_epochs
num_mini_batches
clip_param
desired_kl
22.6 修改 MoE-CTS
查找:
text
teacher_env_ratio
expert_num
latent_dim
load_balance_coef
student_encoder_lr
22.7 修改部署
PPO 分支重点文件:
text
deploy/robots/legbot/config/config.yaml
State_RLBase.cpp
Types.h
deploy_safety.h
serial_dds_gateway/
PPO-CTS-MOE 分支重点文件:
text
deploy/deploy_mujoco/configs/legbot.yaml
deploy_legbot.py
exporter_cts.py
23. 项目价值
23.1 对算法研究的价值
项目覆盖了四足强化学习中的关键问题:
- PPO 的并行采样与稳定更新;
- 历史观测下的隐状态推断;
- 非对称 Actor-Critic;
- 教师---学生蒸馏;
- Mixture of Experts;
- 课程学习;
- 域随机化;
- 真实电机模型;
- Sim2Sim 和 Sim2Real。
23.2 对工程落地的价值
很多开源项目只提供训练环境,Legbot Lab 进一步提供:
- 策略导出;
- C++ 推理;
- 状态机;
- DDS 接口;
- 串口网关;
- 真实电机和 IMU 接入;
- 安全保护;
- 日志与诊断。
这使其更接近一套机器人控制系统,而不是单纯的强化学习示例。
23.3 对自研四足平台的参考意义
自研机器人最困难的部分往往不是训练 PPO,而是统一以下内容:
- URDF 与实物质量;
- 仿真和实物关节顺序;
- 电机方向和减速比;
- IMU 安装坐标;
- 控制周期;
- 通信延迟;
- 默认关节角;
- PD 增益;
- 动作和观测缩放。
该项目的主要参考价值正是在这些接口层。
24. 可继续改进的方向
24.1 统一配置体系
text
algorithm:
type: ppo | moe_cts
deployment:
backend: onnx_cpp | torchscript_python
这样能共享机器人模型、奖励、域随机化和部署接口。
24.2 加入自动一致性检查
训练导出时自动生成:
- 观测维度哈希;
- 关节顺序哈希;
- 默认角;
- 缩放系数;
- 控制周期;
- 网络输入输出维度;
- 模型质量和惯量摘要。
部署启动时进行校验,不一致则拒绝进入 RL 状态。
24.3 增加多随机种子评估
至少统计:
- 平均速度跟踪误差;
- 摔倒率;
- 推扰存活率;
- 单位距离能耗;
- 足端滑移;
- 峰值力矩;
- 不同摩擦和负载下的成功率。
24.4 加入实物系统辨识
可对以下参数做离线或在线辨识:
- 电机摩擦;
- 力矩常数;
- 延迟;
- 关节零位;
- 基座质心;
- 足地摩擦;
- IMU 偏置。
辨识结果用于缩小域随机化范围,提高策略有效容量。
24.5 MoE 专家可解释性
记录不同地形下门控权重:
g 1 , ... , g 8 g_1,\ldots,g_8 g1,...,g8
分析是否存在专家塌缩,以及某些专家是否与楼梯、坡面、推扰恢复等状态相关。
24.6 安全策略外壳
在 RL 动作外增加安全过滤器,例如:
- 关节可达性约束;
- 力矩---速度约束;
- 基座姿态预测;
- 控制屏障函数;
- 异常动作变化率检测。
25. 参考资料
-
Robot-Nav, legbot_lab
-
Hongxi Wang, Haoxiang Luo, Wei Zhang, Hua Chen, Combining Teacher-Student with Representation Learning: A Concurrent Teacher-Student Reinforcement Learning Paradigm for Legged Locomotion
-
John Schulman et al., Proximal Policy Optimization Algorithms
-
Nikita Rudin et al., Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning
-
NVIDIA, Isaac Lab Documentation
-
leggedrobotics, rsl_rl
-
Google DeepMind, MuJoCo
-
Eclipse Foundation, Cyclone DDS
-
wty-yy Tianyang Wu, 开源大佬
26. 总结
Legbot Lab 的核心意义不只在于"用 PPO 训练四足机器人走路",而在于建立一条可复现的工程链路:
text
机器人建模
→ MDP 定义
→ 4096 环境并行训练
→ 历史观测与特权信息
→ 域随机化与课程学习
→ TorchScript/ONNX 导出
→ MuJoCo Sim2Sim
→ C++ FSM 与 DDS
→ 串口电机和 IMU
→ 实物安全运行
默认 PPO 分支更强调部署闭环,PPO-CTS-MOE 分支进一步利用并发教师---学生和专家混合网络,在训练阶段使用完整状态,在部署阶段只依赖可获得的本体观测。