开源 | GO2 Backflip:基于相位条件 PPO 的四足机器人后空翻训练与 Sim2Real 部署
项目:Robot-Nav/GO2_backflip,PPO-backflip 分支。
代码:https://github.com/Robot-Nav/GO2_backflip/tree/PPO-backflip
演示:https://www.bilibili.com/video/BV1HbtJ6AENK/
训练框架:Isaac Sim 5.1 + Isaac Lab + RSL-RL + PyTorch。
部署链路:Isaac Lab 训练 → ONNX 导出 → MuJoCo Sim2Sim → Unitree SDK2 真机部署。
1. 项目目标与技术路线
该项目的目标不是让四足机器人简单“跳起来”,而是让 12 自由度四足机器人在约 2 s 的动作窗口内完成一套完整的高动态后空翻动作:
- 站立准备;
- 下蹲蓄力;
- 后腿和全身协同起跳;
- 空中持续产生负俯仰角速度完成后翻;
- 在接近一周旋转后重新对齐机身;
- 四足接触地面;
- 抑制落地冲击并恢复稳定站姿。
项目将后空翻建模为一个相位条件化的连续控制问题。策略并不依赖预先给定的关节轨迹,而是由 PPO 在物理仿真中通过奖励函数学习动作时序。为了保证最终策略能够部署到真机,训练阶段同时引入:
- 可部署的 Actor 观测;
- 带特权信息的 Critic;
- 关节位置 PD 控制;
- 电机力矩-转速包络;
- 动作与观测时延;
- 传感器偏置与随机噪声;
- 摩擦、质量、惯量、质心、电机参数等动力学随机化;
- 逐步收紧的安全课程学习。

图 1 PPO-backflip 训练总体结构。Actor 仅接收真机可获得的 60 维观测,Critic 在训练阶段额外使用 165 维特权信息。
2. 项目目录与各模块作用
项目 PPO 分支中的主要目录可以按训练、算法、模型、Sim2Sim 和真机部署五层理解。
表 1 PPO-backflip 主要目录功能
| 路径 | 作用 |
|---|---|
isaaclab_backflip/ | Isaac Lab 后空翻任务主体,包含环境、奖励、观测、动力学随机化和 PPO 配置 |
isaaclab_backflip/tasks/go2_backflip/go2_backflip_env.py | 后空翻环境核心实现 |
isaaclab_backflip/tasks/go2_backflip/go2_backflip_env_cfg.py | 控制参数、奖励权重、随机化范围、噪声参数 |
isaaclab_backflip/tasks/go2_backflip/agents/rsl_rl_ppo_cfg.py | RSL-RL PPO 网络和超参数 |
train.py | 训练入口 |
play.py | 仿真回放、策略推理及 ONNX 导出 |
rl/ | 兼容早期 Isaac Gym 版本的自定义非对称 PPO 实现 |
legged_gym/ | 原 Isaac Gym 任务参考代码 |
PPO-backflip_gym/ | 旧版 Gym 训练相关工程 |
mujoco/ | ONNX 策略在 MuJoCo 中进行 Sim2Sim 验证 |
deploy_real/ | 真机状态机、500 Hz LowCmd 发布、安全监控与 ONNX 推理 |
resources/ | Go2 URDF、Mesh 与 MuJoCo 模型 |
model_*.onnx | 已导出的策略网络 |
整个项目的关键并不在某一个 PPO 调用函数,而在于环境定义、奖励设计、控制接口、随机化和部署接口保持一致。
3. 后空翻任务的强化学习建模
3.1 马尔可夫决策过程
训练可抽象为连续状态、连续动作的 MDP:
M = ( S , A , P , r , γ ) \mathcal{M}=(\mathcal{S},\mathcal{A},P,r,\gamma) M=(S,A,P,r,γ)
其中:
- S \mathcal{S} S:机器人状态;
- A \mathcal{A} A:12 个关节的动作;
- P ( s t + 1 ∣ s t , a t ) P(s_{t+1}|s_t,a_t) P(st+1∣st,at):Isaac Lab/PhysX 中的动力学;
- r t r_t rt:后空翻奖励;
- γ = 0.99 \gamma=0.99 γ=0.99:折扣因子。
策略目标为:
π θ ∗ = arg max θ E π θ [ ∑ t = 0 T γ t r t ] \pi_\theta^*=\arg\max_\theta \mathbb{E}_{\pi_\theta} \left[ \sum_{t=0}^{T}\gamma^t r_t \right] πθ∗=argθmaxEπθ[t=0∑Tγtrt]
与普通行走不同,后空翻具有极强的时序依赖:同样的机身姿态,在 0.3 s 时可能意味着“继续蓄力”,在 1.5 s 时却意味着“落地恢复”。因此项目额外加入显式的 phase features。
4. 相位条件化 Phase-Conditioned Policy
论文参考:Peng et al., DeepMimic: Example-Guided Deep Reinforcement Learning of Physics-Based Character Skills, SIGGRAPH 2018。
论文:https://arxiv.org/abs/1804.02717
代码:https://github.com/xbpeng/DeepMimic
项目没有使用 DeepMimic 的动作模仿奖励,但采用了与周期/时序动作学习相近的phase conditioning思想:将当前动作执行进度作为策略输入,使网络能够区分“当前处于哪一个动作阶段”。
代码中:
t p = min ( t , 2.0 ) t_p=\min(t,2.0) tp=min(t,2.0)
ϕ = π t p 2 \phi=\frac{\pi t_p}{2} ϕ=2πtp
最终构造 6 维多频率相位特征:
p ( t ) = [ sin ϕ , cos ϕ , sin ϕ 2 , cos ϕ 2 , sin ϕ 4 , cos ϕ 4 ] p(t)= \left[ \sin\phi,\cos\phi, \sin\frac{\phi}{2},\cos\frac{\phi}{2}, \sin\frac{\phi}{4},\cos\frac{\phi}{4} \right] p(t)=[sinϕ,cosϕ,sin2ϕ,cos2ϕ,sin4ϕ,cos4ϕ]

图 2 PPO-backflip 使用的 6 维谐波相位特征。
相比直接输入一个标量 t t t,正余弦编码具有两个明显优势:
- 输入连续平滑,不会在阶段边界产生硬切换;
- 多个频率可以帮助 MLP 同时表达“粗粒度动作阶段”和“细粒度时序位置”。
因此同一个姿态 q q q 在不同 phase 下可以对应完全不同的控制动作。
5. Actor 观测空间:60 维可部署观测
Actor 只允许使用真机能够获得或内部维护的变量。
o t a c t o r = [ o t s e n s o r , a t , a t − 1 , p t ] ∈ R 60 o_t^{actor} =[ o_t^{sensor}, a_t, a_{t-1}, p_t ] \in\mathbb{R}^{60} otactor=[otsensor,at,at−1,pt]∈R60
其中传感器部分为:
o t s e n s o r = [ 0.25 ω b , g b , q − q 0 , 0.05 q ˙ ] ∈ R 30 o_t^{sensor} =[ 0.25\omega_b,\; g_b,\; q-q_0,\; 0.05\dot q ] \in\mathbb{R}^{30} otsensor=[0.25ωb,gb,q−q0,0.05q˙]∈R30
具体维数为:
表 2 Actor 观测空间
| 观测 | 维数 | 含义 |
|---|---|---|
root_ang_vel_b | 3 | 机体系角速度 |
projected_gravity_b | 3 | 重力方向在机体系中的投影 |
q-q_default | 12 | 关节位置偏差 |
dq | 12 | 关节速度 |
current_action | 12 | 当前策略动作 |
last_action | 12 | 上一拍策略动作 |
phase_features | 6 | 相位编码 |
| 总计 | 60 |
这里没有把世界坐标系中的真实位置、真实线速度、摩擦系数、质量随机量等直接输入 Actor,因此 ONNX 导出后不需要依赖仿真器特权状态。
动作历史的加入也具有重要意义。系统本身存在动力学惯性和策略执行时延,加入 a t , a t − 1 a_t,a_{t-1} at,at−1 后,前馈 MLP 能够从有限历史中隐式判断动作变化趋势。
6. 非对称 Actor-Critic
论文:Pinto et al., Asymmetric Actor Critic for Image-Based Robot Learning, RSS 2018。
论文:https://arxiv.org/abs/1710.06542
非对称 Actor-Critic 的核心思想是:
a t ∼ π θ ( a t ∣ o t ) a_t\sim\pi_\theta(a_t|o_t) at∼πθ(at∣ot)
而 Critic 使用更完整的状态:
V ψ = V ψ ( s t p r i v ) V_\psi=V_\psi(s_t^{priv}) Vψ=Vψ(stpriv)
训练时 Critic 可以访问仿真器的 ground truth,部署时只保留 Actor。
原论文中 Actor 使用部分观测、Critic 使用完整状态。本项目把这一思想改造成适合四足运动控制的形式:Actor 使用 60 维真机可部署观测,Critic 使用 165 维特权观测。

图 3 PPO-backflip 中的非对称 Actor-Critic 数据流。该图依据 Pinto 等人的 Asymmetric Actor-Critic 思想结合本项目观测定义重绘。
Critic 输入由两部分构成:
o t c r i t i c = [ s t s t a t e , s t d y n ] ∈ R 165 o_t^{critic} =[ s_t^{state},s_t^{dyn} ] \in\mathbb{R}^{165} otcritic=[ststate,stdyn]∈R165
其中 state_privileged 包括:
- base 高度;
- yaw frame 下的真实线速度;
- 无噪声角速度;
- 无噪声 projected gravity;
- 无噪声关节位置和速度;
- 当前动作、上一动作;
- phase features。
dynamics_privileged 进一步加入:
- 12 维 torque scale;
- 12 维 motor velocity scale;
- action delay;
- observation delay;
- 各 limb mass scale;
- inertia scale;
- friction;
- restitution;
- contact offset;
- base mass;
- base CoM;
- K p , K d K_p,K_d Kp,Kd;
- motor offset。
其作用不是让真机获得这些量,而是让 Critic 在训练时更准确地解释:
为什么在相同 Actor 观测下,本次 rollout 的未来回报与另一次 rollout 不同?
当质量、摩擦、时延等参数被随机化时,仅靠 60 维观测会产生显著的部分可观测性。Critic 知道这些随机参数,可以降低 Value 估计方差,进而给 Actor 提供更稳定的 advantage。
7. PPO:近端策略优化
论文:Schulman et al., Proximal Policy Optimization Algorithms, 2017。
论文:https://arxiv.org/abs/1707.06347
官方实现参考:https://github.com/leggedrobotics/rsl_rl
PPO 是本项目的主优化算法。
7.1 高斯策略
Actor 输出动作均值 μ θ ( o t ) \mu_\theta(o_t) μθ(ot),策略采用对角高斯分布:
π θ ( a t ∣ o t ) = N ( μ θ ( o t ) , diag ( σ 2 ) ) \pi_\theta(a_t|o_t) =\mathcal{N} \left( \mu_\theta(o_t), \operatorname{diag}(\sigma^2) \right) πθ(at∣ot)=N(μθ(ot),diag(σ2))
项目中 Actor/Critic 均为:
Input
↓
Linear 512 + ELU
↓
Linear 256 + ELU
↓
Linear 128 + ELU
↓
Output
动作标准差初始化为:
σ 0 = 1.0 \sigma_0=1.0 σ0=1.0
并限制在:
0.35 ≤ σ ≤ 1.50 0.35\le\sigma\le1.50 0.35≤σ≤1.50
训练早期较大的 σ \sigma σ 提供探索,训练后期仍保留最低随机性,避免策略过早坍缩为近确定性。
7.2 Importance Sampling Ratio
旧策略产生 rollout 后,新策略需要在同一批数据上更新多次。定义:
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_{old}}(a_t|o_t)} rt(θ)=πθold(at∣ot)πθ(at∣ot)
实际代码通常使用 log probability:
r t ( θ ) = exp ( log π θ ( a t ∣ o t ) − log π θ o l d ( a t ∣ o t ) ) r_t(\theta) =\exp \left( \log \pi_\theta(a_t|o_t) -\log \pi_{\theta_{old}}(a_t|o_t) \right) rt(θ)=exp(logπθ(at∣ot)−logπθold(at∣ot))
若 r t r_t rt 离 1 很远,就意味着新旧策略差异过大。
7.3 PPO Clipped Objective
PPO 使用:
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, \operatorname{clip} (r_t(\theta),1-\epsilon,1+\epsilon)\hat A_t \right) \right] LCLIP(θ)=Et[min(rt(θ)A^t,clip(rt(θ),1−ϵ,1+ϵ)A^t)]
项目设置:
ϵ = 0.2 \epsilon=0.2 ϵ=0.2

图 4 PPO clipped surrogate objective。超过 1 + ϵ 1+\epsilon 1+ϵ 后,对正 advantage 动作继续增加概率不再获得额外优化收益。
PPO 的关键不是简单“裁剪动作”,而是裁剪策略概率比,限制单次策略更新幅度。
8. GAE:广义优势估计
论文:Schulman et al., High-Dimensional Continuous Control Using Generalized Advantage Estimation, ICLR 2016。
论文:https://arxiv.org/abs/1506.02438
TD residual:
δ t = r t + γ V ( s t + 1 ) ( 1 − d t ) − V ( s t ) \delta_t =r_t+\gamma V(s_{t+1})(1-d_t)-V(s_t) δt=rt+γV(st+1)(1−dt)−V(st)
GAE:
A ^ t = δ t + γ λ ( 1 − d t ) A ^ t + 1 \hat A_t =\delta_t+ \gamma\lambda(1-d_t)\hat A_{t+1} A^t=δt+γλ(1−dt)A^t+1
项目配置:
γ = 0.99 , λ = 0.95 \gamma=0.99,\qquad\lambda=0.95 γ=0.99,λ=0.95
λ \lambda λ 在偏差与方差之间进行折中:
- λ \lambda λ 较小:更接近一步 TD,方差低但偏差较大;
- λ \lambda λ 接近 1:更接近 Monte-Carlo return,偏差低但方差较大。
对后空翻这种高动态、强时序任务,GAE 能把“完成翻转”和“稳定落地”的远期奖励有效传播回起跳阶段。
9. PPO 总损失
Policy objective、Value loss 和 entropy regularization 共同组成更新目标。
Value function:
L V = 1 N ∑ t ( V ψ ( s t ) − R t ) 2 L_V=\frac{1}{N} \sum_t \left( V_\psi(s_t)-R_t \right)^2 LV=N1t∑(Vψ(st)−Rt)2
Entropy:
H ( π ) = − E a ∼ π [ log π ( a ∣ s ) ] H(\pi) =-\mathbb{E}_{a\sim\pi} [\log\pi(a|s)] H(π)=−Ea∼π[logπ(a∣s)]
可写成优化目标:
J = L C L I P − c v L V + c e H ( π ) J =L^{CLIP} -c_vL_V +c_eH(\pi) J=LCLIP−cvLV+ceH(π)
项目中:
c v = 1.0 , c e = 0.005 c_v=1.0,\qquad c_e=0.005 cv=1.0,ce=0.005
并启用 clipped value loss。
10. PPO 训练超参数
表 3 PPO 训练配置
| 参数 | 值 |
|---|---|
| 并行环境 | 4096 |
| rollout steps / env | 24 |
| 最大训练迭代 | 5000 |
| learning epochs | 5 |
| mini-batches | 4 |
| actor hidden dims | [512,256,128] |
| critic hidden dims | [512,256,128] |
| activation | ELU |
| learning rate | 10 − 3 10^{-3} 10−3,adaptive |
| desired KL | 0.01 |
| clip ratio | 0.2 |
| γ \gamma γ | 0.99 |
| λ \lambda λ | 0.95 |
| entropy coefficient | 0.005 |
| max grad norm | 1.0 |
每轮采样量约为:
4096 × 24 = 98304 4096\times24=98304 4096×24=98304
个 transition。
GPU 并行仿真是这种高动态技能训练能够实际可行的重要前提。
11. 自适应 KL 学习率
PPO 仍可能因为学习率过大而造成策略突变,因此项目利用 mean KL divergence 控制学习率。
设:
D K L ( π θ o l d ∥ π θ ) D_{KL} \left( \pi_{\theta_{old}}\|\pi_\theta \right) DKL(πθold∥πθ)
目标值为:
D K L t a r g e t = 0.01 D_{KL}^{target}=0.01 DKLtarget=0.01
若实际 KL 明显高于目标,降低学习率;若明显低于目标,可增大学习率。
因此这里存在两层约束:
- PPO clip 在 loss 层限制概率比;
- adaptive KL 在 optimizer 层调整学习率。
12. 动作空间与关节 PD 控制
Actor 输出:
a t ∈ R 12 a_t\in\mathbb{R}^{12} at∈R12
每一维并不是直接力矩,而是关节目标位置偏移量。
目标关节位置:
q t d e s = q 0 + s a a t + Δ q m o t o r q_t^{des} =q_0+s_a a_t+\Delta q_{motor} qtdes=q0+saat+Δqmotor
其中:
s a = 0.5 s_a=0.5 sa=0.5
控制器使用:
τ P D = K p ( q d e s − q ) − K d q ˙ \tau_{PD} =K_p(q^{des}-q)-K_d\dot q τPD=Kp(qdes−q)−Kdq˙
项目配置:
K p = 40 , K d = 1 K_p=40,\qquad K_d=1 Kp=40,Kd=1
这是典型的 RL joint-position target + low-level PD 控制结构。
优势在于策略不需要直接学习高频力矩波形,而只需要学习具有一定物理意义的关节目标,PD 层负责快速抑制跟踪误差。
13. 动作目标变化率限制
项目不是允许 q d e s q^{des} qdes 在相邻仿真步之间任意跳变,而是根据目标速度上限限制 action slew rate。
若最大目标关节速度为 q ˙ m a x \dot q_{max} q˙max,则一个 physics step 允许的动作增量为:
Δ a m a x = q ˙ m a x Δ t s a \Delta a_{max} =\frac{\dot q_{max}\Delta t}{s_a} Δamax=saq˙maxΔt
因此:
a t l i m = a t − 1 l i m + clip ( a t − a t − 1 l i m , − Δ a m a x , Δ a m a x ) a_t^{lim} =a_{t-1}^{lim} + \operatorname{clip} ( a_t-a_{t-1}^{lim}, -\Delta a_{max}, \Delta a_{max} ) atlim=at−1lim+clip(at−at−1lim,−Δamax,Δamax)
项目设置目标变化率对应约:
13.5 rad/s 13.5\ \text{rad/s} 13.5 rad/s
该限制能够显著减少 ONNX 策略在真机上产生瞬时极端位置目标。
14. 电机 Torque-Speed Envelope
后空翻中最危险的错误之一,是在仿真中允许电机高速状态仍输出不现实的峰值力矩。
项目显式建模 Go2HV 的 torque-speed envelope。
设:
ω 1 = 13.5 rad/s , ω 2 = 30 rad/s \omega_1=13.5\ \text{rad/s}, \qquad \omega_2=30\ \text{rad/s} ω1=13.5 rad/s,ω2=30 rad/s
低速区:
∣ ω ∣ < ω 1 |\omega|<\omega_1 ∣ω∣<ω1
可使用最大驱动力矩约:
τ d r i v e = 20.2 N⋅m \tau_{drive}=20.2\ \text{N·m} τdrive=20.2 N⋅m
最大制动力矩约:
τ b r a k e = 23.4 N⋅m \tau_{brake}=23.4\ \text{N·m} τbrake=23.4 N⋅m
高速区按线性比例降额:
η ( ω ) = clip ( ω 2 − ∣ ω ∣ ω 2 − ω 1 , 0 , 1 ) \eta(\omega) =\operatorname{clip} \left( \frac{\omega_2-|\omega|} {\omega_2-\omega_1}, 0,1 \right) η(ω)=clip(ω2−ω1ω2−∣ω∣,0,1)
最终:
τ m a x ( ω ) = η ( ω ) τ p e a k \tau_{max}(\omega)= \eta(\omega)\tau_{peak} τmax(ω)=η(ω)τpeak

图 5 PPO-backflip 训练和部署中采用的 Go2HV 力矩-转速包络。
最终实际施加:
τ = clip ( τ P D , − τ m a x , τ m a x ) \tau= \operatorname{clip} ( \tau_{PD}, -\tau_{max}, \tau_{max} ) τ=clip(τPD,−τmax,τmax)
这个模块对于 Sim2Real 极其关键。否则仿真策略很容易利用真实电机不存在的“无限高速大力矩”。
15. 后空翻奖励设计
奖励函数是整个项目最核心的工程部分之一。
总体形式:
r t = ∑ i w i r i r_t =\sum_i w_i r_i rt=i∑wiri
项目不是只使用“转够 2 π 2\pi 2π 就奖励”,而是把动作拆成:
- 准备;
- 起跳;
- 旋转;
- 落地;
- 恢复;
- 安全正则。

图 6 后空翻奖励函数的主要时序窗口。
15.1 起跳阶段
向上速度奖励
在:
0.50 < t < 0.75 0.50<t<0.75 0.50<t<0.75
阶段奖励:
r v z = clip ( v z , v z , m a x ) r_{v_z} =\operatorname{clip}(v_z,v_{z,max}) rvz=clip(vz,vz,max)
权重为 20。
其目的不是让机器人一直跳高,而是只在起跳窗口内鼓励产生足够竖直动量。
15.2 后翻角速度奖励
使用机体系 pitch rate:
r ω y = − ω y r_{\omega_y} =-\omega_y rωy=−ωy
并限制最大有效角速度。
项目采用负号,是因为坐标定义下后翻对应负的 y y y 轴角速度。
15.3 姿态控制
项目构造随时间变化的期望后翻姿态:
θ d ( t ) = − 4 π clip ( t − t t a k e o f f , 0 , 0.5 ) \theta_d(t) =-4\pi \operatorname{clip} (t-t_{takeoff},0,0.5) θd(t)=−4πclip(t−ttakeoff,0,0.5)
再将该姿态转换成期望重力方向 g d g_d gd,使用:
r o r i = ∥ g b − g d ∥ 2 r_{ori} =\|g_b-g_d\|^2 rori=∥gb−gd∥2
作为惩罚。
这种写法避免直接处理 Euler angle wrap-around,并利用 projected_gravity 表示当前姿态。
15.4 旋转进度奖励
项目不只看最终角度,还维护累计后翻角:
Θ t = Θ t − 1 + clip ( − ω y ) Δ t \Theta_t =\Theta_{t-1} + \operatorname{clip}(-\omega_y)\Delta t Θt=Θt−1+clip(−ωy)Δt
仅在机器人已经确认离地、尚未落地且未发生头部接触时累计。
每一步的正向旋转增量:
Δ Θ t = max ( Θ t m a x − Θ t − 1 m a x , 0 ) \Delta\Theta_t =\max (\Theta_t^{max}-\Theta_{t-1}^{max},0) ΔΘt=max(Θtmax−Θt−1max,0)
作为:
r r o t a t i o n = Δ Θ t r_{rotation} =\Delta\Theta_t rrotation=ΔΘt
权重达到 50。
这属于典型的potential/progress shaping:机器人每多完成一点正确方向的旋转都会得到连续反馈。
15.5 Flip Completion 与 Flip Success
项目设置两个阈值:
Θ c o m p l e t i o n = 5.50 rad \Theta_{completion}=5.50\ \text{rad} Θcompletion=5.50 rad
Θ s u c c e s s = 5.80 rad \Theta_{success}=5.80\ \text{rad} Θsuccess=5.80 rad
分别对应约:
315 ∘ , 332 ∘ 315^\circ,\qquad332^\circ 315∘,332∘
达到 completion 后给予一次性事件奖励:
r c o m p l e t e = 1 r_{complete}=1 rcomplete=1
权重 500。
满足更严格的成功条件后再给:
r s u c c e s s = 1 r_{success}=1 rsuccess=1
权重 500。
这两个 sparse bonus 与连续 rotation progress 配合,可以同时解决:
- 纯稀疏奖励难探索;
- 纯 dense shaping 可能学到“看似旋转但不真正完成”的局部最优。
16. 落地与恢复奖励
动作完成旋转并不代表任务成功。项目还要求机器人能够恢复。
恢复阶段主要包含:
直立
e u p r i g h t = g x 2 + g y 2 e_{upright} =g_x^2+g_y^2 eupright=gx2+gy2
r u p r i g h t = exp ( − 4 e u p r i g h t ) r_{upright} =\exp(-4e_{upright}) rupright=exp(−4eupright)
机身高度
r h = exp [ − ( z − z d 0.1 ) 2 ] r_h =\exp \left[ -\left( \frac{z-z_d}{0.1} \right)^2 \right] rh=exp[−(0.1z−zd)2]
默认姿态
r q = exp ( − mean [ ( q − q 0 ) 2 ] 0.09 ) r_q =\exp \left( -\frac{\operatorname{mean}[(q-q_0)^2]}{0.09} \right) rq=exp(−0.09mean[(q−q0)2])
静止
r s t i l l = exp [ − 1 2 ( ∥ ω b ∥ 2 + 0.25 ∥ v y a w ∥ 2 ) ] r_{still} =\exp \left[ -\frac{1}{2} \left( \|\omega_b\|^2 + 0.25\|v_{yaw}\|^2 \right) \right] rstill=exp[−21(∥ωb∥2+0.25∥vyaw∥2)]
足端接触
根据四个足端中满足接触力阈值的比例:
r c o n t a c t = N c o n t a c t 4 r_{contact} =\frac{N_{contact}}{4} rcontact=4Ncontact
这些奖励只有在已经完成翻转且检测到落地后激活,避免策略在起跳前通过“保持站立”刷恢复奖励。
17. 平滑性与对称性正则
高动态技能的 reward 不能只关注任务完成,否则容易出现极端关节动作。
17.1 Action Rate
r Δ a = ∥ a t − a t − 1 ∥ 2 r_{\Delta a} =\|a_t-a_{t-1}\|^2 rΔa=∥at−at−1∥2
17.2 Action Jerk
项目使用离散二阶差分:
j a = a t − 2 a t − 1 + a t − 2 j_a =a_t-2a_{t-1}+a_{t-2} ja=at−2at−1+at−2
r j e r k = ∥ j a ∥ 2 r_{jerk} =\|j_a\|^2 rjerk=∥ja∥2
它抑制动作变化率本身的快速变化,使动作更加平滑。
17.3 左右腿动作对称
例如左右 hip:
r s y m = ( a R + a L ) 2 r_{sym} =(a_R+a_L)^2 rsym=(aR+aL)2
或根据关节安装方向使用:
r s y m = ( a R − a L ) 2 r_{sym} =(a_R-a_L)^2 rsym=(aR−aL)2
项目分别对 hip、thigh、calf 设置不同符号,保证约束的是物理镜像动作而不是数值简单相等。
18. 安全奖励与安全课程学习
直接从第一轮训练就施加完整硬件安全限制,往往会让机器人根本探索不到后空翻。因此项目使用 curriculum。
定义安全因子:
c ( k ) = c 0 + ( 1 − c 0 ) clip ( k − k w a r m u p k r a m p , 0 , 1 ) c(k) =c_0+(1-c_0) \operatorname{clip} \left( \frac{k-k_{warmup}}{k_{ramp}}, 0,1 \right) c(k)=c0+(1−c0)clip(krampk−kwarmup,0,1)
项目中:
- 前约 1000 个 PPO update:主要探索后空翻;
- 接下来约 3000 个 update:逐渐增加安全约束;
- 最后约 1000 个 update:完整安全包络。
安全因子会同时放大或收紧:
- joint velocity penalty;
- joint position limit penalty;
- action jerk;
- rear-leg action rate;
- head clearance;
- undesired body contact;
- landing impact;
- termination threshold。
因此训练过程可以理解为:
先学会翻
↓
再学会在硬件限制内翻
↓
最后强化安全落地与恢复
这是整个项目中非常重要的设计。
19. Joint Velocity Limit
有效软速度限制:
q ˙ s o f t = 0.8 q ˙ m a x s v \dot q_{soft} =0.8\, \dot q_{max}\, s_v q˙soft=0.8q˙maxsv
若:
∣ q ˙ ∣ > q ˙ s o f t |\dot q|>\dot q_{soft} ∣q˙∣>q˙soft
则惩罚相对超限:
e v = max ( ∣ q ˙ ∣ q ˙ s o f t − 1 , 0 ) e_v =\max \left( \frac{|\dot q|}{\dot q_{soft}}-1, 0 \right) ev=max(q˙soft∣q˙∣−1,0)
并使用平方:
r v e l − l i m i t = c ( k ) ∑ i e v , i 2 r_{vel-limit} =c(k)\sum_i e_{v,i}^2 rvel−limit=c(k)i∑ev,i2
终止阈值则从:
1.5 × q ˙ m a x 1.5\times \dot q_{max} 1.5×q˙max
逐渐收紧到:
1.0 × q ˙ m a x 1.0\times \dot q_{max} 1.0×q˙max
20. 关节位置安全
训练开始时允许真实关节位置短时间超出 URDF hard limit 一定 margin:
m 0 = 0.30 rad m_0=0.30\ \text{rad} m0=0.30 rad
随后逐渐收紧到:
m = 0 m=0 m=0
这样做是为了避免在策略尚未学会起跳时被过早终止,同时确保最终策略不能依赖超出真实机械范围的姿态。
21. 落地冲击惩罚
若落地峰值足端力超过:
F t h = 200 N F_{th}=200\ \text{N} Fth=200 N
则:
e F = max ( F − F t h F t h , 0 ) e_F =\max \left( \frac{F-F_{th}}{F_{th}}, 0 \right) eF=max(FthF−Fth,0)
r i m p a c t = c ( k ) e F 2 r_{impact} =c(k)e_F^2 rimpact=c(k)eF2
该项只在落地后的有限窗口内激活。
它约束的是如何落地,而不仅仅是“最终有没有站住”。
22. Domain Randomization
论文:Tobin et al., Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World, IROS 2017。
论文:https://arxiv.org/abs/1703.06907
Domain Randomization 的基本目标是:
ξ ∼ p ( ξ ) \xi\sim p(\xi) ξ∼p(ξ)
其中 ξ \xi ξ 表示仿真参数。策略优化:
max θ E ξ ∼ p ( ξ ) [ J ( π θ ; ξ ) ] \max_\theta \mathbb{E}_{\xi\sim p(\xi)} \left[ J(\pi_\theta;\xi) \right] θmaxEξ∼p(ξ)[J(πθ;ξ)]
不是训练一个只适配名义模型 ξ 0 \xi_0 ξ0 的策略,而是在大量不同动力学模型上同时学习一个鲁棒策略。
本项目使用的是动力学随机化而不是视觉随机化。
表 4 Domain Randomization 参数
| 参数 | 随机范围 |
|---|---|
| friction | [0.5, 1.25] |
| restitution | [0.0, 0.05] |
| contact offset | [0.0075, 0.0125] m |
| rest offset | [-0.001, 0.001] m |
| base added mass | [-0.5, 1.0] kg |
| base CoM | [-0.015, 0.015] m |
| limb mass scale | [0.95, 1.05] |
| limb inertia jitter | [0.90, 1.10] |
| torque scale | [0.75, 1.00] |
| motor velocity scale | [0.85, 1.00] |
| K p K_p Kp scale | [0.8, 1.2] |
| K d K_d Kd scale | [0.8, 1.2] |
| motor offset | [-0.02, 0.02] rad |
它们分别覆盖:
- 地面接触误差;
- 质量与惯量建模误差;
- 质心位置误差;
- 电机真实输出能力差异;
- 控制增益误差;
- 零位误差。
对后空翻而言,质量、惯量、力矩能力和地面摩擦的微小误差都会直接改变起跳角动量和空中姿态,因此 domain randomization 比普通行走任务更加重要。
23. 动作时延与观测时延
项目随机:
action_delay_steps ∈ {0,1,2}
observation_delay_steps ∈ {0,1,2}
策略周期:
T π = 20 ms T_\pi=20\ \text{ms} Tπ=20 ms
因此最大随机策略级延迟约:
40 ms 40\ \text{ms} 40 ms
动作时延通过 action history buffer 实现:
a t e x e c = a t − d a a_t^{exec} =a_{t-d_a} atexec=at−da
观测时延:
o t a c t o r = o t − d o s e n s o r o_t^{actor} =o_{t-d_o}^{sensor} otactor=ot−dosensor
这比单纯加入 Gaussian noise 更接近真实系统,因为真机中的网络、DDS、Python 调度、状态估计和执行器链路都会带来时间延迟。
24. 传感器噪声与偏置
Actor 观测还加入两类误差:
- episode 级固定 bias;
- step 级随机 noise。
例如:
ω ~ = ω + b ω + ϵ ω \tilde\omega =\omega+b_\omega+\epsilon_\omega ω~=ω+bω+ϵω
b ω ∼ U ( − 0.05 , 0.05 ) b_\omega\sim U(-0.05,0.05) bω∼U(−0.05,0.05)
噪声则在每个控制步重新采样。
Bias 模拟长期零偏,随机 noise 模拟瞬时测量扰动。两者同时存在,比仅加入白噪声更符合真实 IMU 和编码器误差。
25. 起飞、旋转与落地状态判定
项目内部维护一套“事件检测状态”,用于计算奖励,而这些内部变量不是 Actor 观测。
起飞确认
至少连续若干步无足端接触,并且:
z b a s e ≥ 0.25 m z_{base}\ge0.25\ \text{m} zbase≥0.25 m
才确认真正 takeoff。
累计翻转角
仅在:
- 已离地;
- 尚未落地;
- 未发生头部接触;
期间积分 pitch rate。
落地
一旦此前已经 airborne,而当前再次检测到足端接触,则标记 landing。
这种事件状态机主要用于 reward shaping 和成功判据,部署 Actor 并不依赖这些仿真标签。
26. 训练频率与控制频率
Physics timestep:
Δ t p h y s i c s = 0.005 s \Delta t_{physics}=0.005\ \text{s} Δtphysics=0.005 s
即:
200 Hz 200\ \text{Hz} 200 Hz
decimation:
N = 4 N=4 N=4
因此 Actor:
f p o l i c y = 200 4 = 50 Hz f_{policy} =\frac{200}{4} =50\ \text{Hz} fpolicy=4200=50 Hz
也就是说:
Actor 计算一次动作
↓
PD/torque controller 连续执行 4 个 physics step
↓
读取新观测
↓
Actor 再计算下一动作
安全峰值监测在 200 Hz physics substep 级执行,可以捕获 50 Hz policy 采样点之间的关节超速或越界峰值。
27. Isaac Lab → ONNX
训练完成后:
python play.py \
--device cuda:0 \
--num_envs 1 \
--checkpoint logs/rsl_rl/go2_backflip/<run>/model_<N>.pt
导出:
python play.py \
--headless \
--device cuda:0 \
--num_envs 1 \
--steps 1 \
--export \
--checkpoint logs/rsl_rl/go2_backflip/<run>/model_<N>.pt
ONNX 中只保留 Actor:
R 60 → R 12 \mathbb{R}^{60} \rightarrow \mathbb{R}^{12} R60→R12
Critic 以及 165 维 privileged state 不进入部署网络。
28. MuJoCo Sim2Sim
官网:MuJoCo Physics。
网站:https://mujoco.org/
项目在真机之前增加第二物理引擎验证:
python mujoco/go2/play_onnx.py \
--joint-target-margin 0.0 \
--onnx logs/rsl_rl/go2_backflip/<run>/exported/policy.onnx \
--mjcf mujoco/go2/go2_isaac.xml
Sim2Sim 的意义是检查策略是否只在 Isaac/PhysX 的特定数值特性上成立。
若策略从:
Isaac Lab / PhysX
迁移到:
MuJoCo
后仍能完成动作,说明策略对:
- contact solver;
- integration;
- friction handling;
- actuator modeling;
具有一定鲁棒性。
它不能证明真机一定成功,但可以提前暴露大量明显的 simulator overfitting。
29. 真机部署总体结构
代码:https://github.com/Robot-Nav/GO2_backflip/tree/PPO-backflip/deploy_real
部署中存在两个控制频率:
- Actor:50 Hz;
- LowCmd:500 Hz。

图 7 PPO-backflip 真机推理与低层控制链。
50 Hz 主循环负责:
- 读取最新
LowState; - 拼接 60 维 Actor observation;
- ONNX inference;
- 保持训练一致的动作历史更新顺序;
- action slew rate limiting;
- 生成新的 12 维目标关节角。
500 Hz 线程负责:
- 读取最新 q , q ˙ q,\dot q q,q˙;
- 计算 PD torque;
- 应用 torque-speed envelope;
- 发送完整 LowCmd;
- 执行 watchdog 与紧急阻尼停机。
30. 真机为什么使用 500 Hz LowCmd
若把 50 Hz Actor 直接当作电机控制频率:
T = 20 ms T=20\ \text{ms} T=20 ms
对于后空翻这类高动态动作过慢。
项目采用:
50 Hz policy + 500 Hz low-level PD 50\ \text{Hz policy} + 500\ \text{Hz low-level PD} 50 Hz policy+500 Hz low-level PD
即网络只负责慢一层的目标更新,高频线程负责闭环电机控制。
这也是分层机器人控制中常见的结构:
Policy → q d e s → PD → τ → Motor \text{Policy} \rightarrow q^{des} \rightarrow \text{PD} \rightarrow \tau \rightarrow \text{Motor} Policy→qdes→PD→τ→Motor
31. 真机 RL 阶段为什么直接发送 torque
RL 接管后,部署程序先在 500 Hz 层计算:
τ r a w = K p ( q d e s − q ) − K d q ˙ \tau_{raw} =K_p(q^{des}-q)-K_d\dot q τraw=Kp(qdes−q)−Kdq˙
然后:
τ c m d = TorqueSpeedClip ( τ r a w , q ˙ ) \tau_{cmd} =\operatorname{TorqueSpeedClip} (\tau_{raw},\dot q) τcmd=TorqueSpeedClip(τraw,q˙)
最终设置:
motor.q = POS_STOP_F
motor.dq = VEL_STOP_F
motor.kp = 0
motor.kd = 0
motor.tau = limited_tau
也就是将训练中等效的 PD + torque-speed clipping 放在主机侧完成,然后给电机发送最终力矩。
这样避免出现:
主机计算一次 PD
+
电机固件又根据 q_target 再计算一次 PD
造成控制模型不一致。
32. 部署状态机
真机不是程序启动后立即后空翻。
状态流为:
DDS 初始化
↓
STARTUP
↓
平滑进入 default pose
↓
ARM
↓
START 启用 RL
↓
WAIT:phase = 0
↓
按 A 且满足触发条件
↓
FLIP:phase 0 → 2.0 s
↓
RECOVERY:phase 固定 2.0 s
↓
恢复稳定
↓
允许下一次触发
关键点在于:
按 A 只重置 phase,不重置机器人真实状态和动作历史。
因此:
( q , q ˙ , IMU , a t , a t − 1 ) (q,\dot q,\text{IMU},a_t,a_{t-1}) (q,q˙,IMU,at,at−1)
都是连续的。
这保证真机执行链和训练中的连续轨迹一致。
33. 训练与真机的一拍动作延迟对齐
部署中 ONNX 每 20 ms 产生一次 next_action,但当前拍实际执行旧的 current_action,然后再更新动作历史。
本质上:
a t e x e c = a t − 1 p o l i c y a_t^{exec}=a_{t-1}^{policy} atexec=at−1policy
这与训练环境中的 action delay 建模相一致。
高动态动作中“差一拍”就是:
20 ms 20\ \text{ms} 20 ms
在角速度达到数 rad/s 时,20 ms 足以导致明显姿态误差,因此训练和部署的动作历史更新顺序必须严格匹配。
34. 真机安全机制
部署代码包含多层 safety watchdog:
LowState超时;- ONNX 输出 NaN/Inf;
- Actor 动作异常;
- 关节速度异常;
- 低电压持续;
- 电机
lost计数; - 温度字段异常;
- 50 Hz policy loop timeout;
- 500 Hz LowCmd loop timeout;
- 手柄
SELECT急停; - Ctrl-C;
- 触发后空翻前的直立、低速度、足端接触检查。
异常后不会只发送一帧 stop,而是进入持续阻尼模式。
35. 为什么这个项目能够从仿真迁移到真机
从算法角度,Sim2Real 不是由某一个单独模块实现,而是由以下机制共同构成:
Sim2Real robustness ≈ Domain Randomization + Observation Noise + Delay Modeling + Actuator Envelope + Asymmetric Critic + Safety Curriculum + Sim2Sim Validation \text{Sim2Real robustness} \approx \text{Domain Randomization} + \text{Observation Noise} + \text{Delay Modeling} + \text{Actuator Envelope} + \text{Asymmetric Critic} + \text{Safety Curriculum} + \text{Sim2Sim Validation} Sim2Real robustness≈Domain Randomization+Observation Noise+Delay Modeling+Actuator Envelope+Asymmetric Critic+Safety Curriculum+Sim2Sim Validation
其中最值得注意的是:项目不仅随机物理参数,还显式模拟了电机能力和时延,这些因素对于后空翻比普通低速步态更加关键。
36. 整体算法流程
完整训练闭环可以写成:
随机化环境参数
↓
重置 4096 个并行 Go2
↓
读取真机可部署观测
↓
加入 bias / noise / observation delay
↓
拼接动作历史 + phase features
↓
Actor 输出 Gaussian action
↓
action delay + slew-rate limit
↓
目标关节角
↓
PD torque
↓
Go2HV torque-speed envelope
↓
PhysX 运行 4 个 5 ms physics step
↓
计算起跳、旋转、落地、恢复与安全 reward
↓
Critic 使用 165-D privileged state 估值
↓
GAE
↓
PPO clipped update
↓
adaptive KL learning rate
↓
迭代训练
↓
ONNX
↓
MuJoCo Sim2Sim
↓
50 Hz Actor + 500 Hz LowCmd 真机部署
37. 项目的核心技术点
37.1 后空翻不是轨迹回放
项目没有给 Actor 一条固定后空翻关节轨迹。
策略学习的是:
a t = π ( o t , ϕ t ) a_t=\pi(o_t,\phi_t) at=π(ot,ϕt)
只要机器人状态发生变化,网络就可以根据观测进行反馈修正。
37.2 phase 提供“动作时钟”,状态提供“反馈修正”
phase 决定:
现在大致应该处于蓄力、起跳、旋转还是恢复。
机器人状态决定:
实际执行是否偏离,需要如何调整。
因此最终策略是:
feedforward timing + feedback correction \text{feedforward timing} + \text{feedback correction} feedforward timing+feedback correction
而不是纯 open-loop motion sequence。
37.3 Critic 可以“作弊”,Actor 不可以
Critic 使用质量、摩擦、时延等 ground truth 是训练技巧,不会造成部署依赖。
Critic 的作用是:
s t p r i v → V ( s t ) → A ^ t → ∇ θ J s_t^{priv} \rightarrow V(s_t) \rightarrow \hat A_t \rightarrow \nabla_\theta J stpriv→V(st)→A^t→∇θJ
部署时仅执行:
o t a c t o r → π θ → a t o_t^{actor} \rightarrow \pi_\theta \rightarrow a_t otactor→πθ→at
37.4 安全不是部署后再加
项目将安全约束前移到训练环境:
- 电机 torque-speed;
- joint speed;
- joint position;
- body contact;
- landing impact;
- action jerk。
这比“先训练一个很暴力的策略,再在真机外面强行 clamp”更合理,因为策略本身会学习在可实现空间中完成动作。
38. 复现顺序
建议严格按以下顺序复现:
# 1. 安装 PPO-backflip Isaac Lab task
pip install -e . --no-deps
# 2. 小规模 smoke test
python train.py \
--headless \
--device cuda:0 \
--num_envs 16 \
--trainer rsl_rl \
--max_iterations 1 \
--run_name smoke
# 3. 完整训练
python train.py \
--headless \
--device cuda:0 \
--num_envs 4096 \
--seed 1 \
--trainer rsl_rl \
--max_iterations 5000 \
--run_name gym_finetuned
# 4. Isaac Lab replay
python play.py \
--device cuda:0 \
--num_envs 1 \
--checkpoint <checkpoint>
# 5. ONNX export
python play.py \
--headless \
--device cuda:0 \
--num_envs 1 \
--steps 1 \
--export \
--checkpoint <checkpoint>
# 6. MuJoCo Sim2Sim
python mujoco/go2/play_onnx.py \
--joint-target-margin 0.0 \
--onnx <policy.onnx> \
--mjcf mujoco/go2/go2_isaac.xml
# 7. 真机部署前离线检查
python deploy_real/deploy_real_backflip.py \
--check \
--onnx <policy.onnx>
39. 总结
PPO-backflip 的核心不是单纯“使用 PPO 训练一个四足后空翻”,而是围绕真实机器人高动态动作建立了一套完整闭环:
- 用 phase-conditioned observation 明确动作时序;
- 用 PPO + GAE 完成连续动作策略优化;
- 用 asymmetric Actor-Critic 在不增加部署传感器的前提下利用仿真特权状态提升训练;
- 用精细的 take-off / rotation / landing / recovery reward shaping 解决后空翻探索难题;
- 用 safety curriculum 先允许策略探索,再逐步收紧硬件约束;
- 用 domain randomization、noise 和 delay modeling 提升鲁棒性;
- 用 PD + torque-speed envelope 将策略动作限制在接近真实电机能力的空间;
- 用 MuJoCo Sim2Sim 提前检查对 PhysX 的过拟合;
- 用 50 Hz Actor + 500 Hz LowCmd 完成真机高频闭环部署。
最终得到的不是一条固定关节轨迹,而是一个由时间相位提供动作先验、由机器人本体状态提供反馈修正的动态后空翻控制策略。
40. 参考论文与网站
论文:Schulman et al., Proximal Policy Optimization Algorithms, 2017。
论文:https://arxiv.org/abs/1707.06347
论文:Schulman et al., High-Dimensional Continuous Control Using Generalized Advantage Estimation, ICLR 2016。
论文:https://arxiv.org/abs/1506.02438
论文:Pinto et al., Asymmetric Actor Critic for Image-Based Robot Learning, RSS 2018。
论文:https://arxiv.org/abs/1710.06542
论文:Tobin et al., Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World, IROS 2017。
论文:https://arxiv.org/abs/1703.06907
论文:Peng et al., DeepMimic: Example-Guided Deep Reinforcement Learning of Physics-Based Character Skills, SIGGRAPH 2018。
论文:https://arxiv.org/abs/1804.02717
代码:Robot-Nav/GO2_backflip。
代码:https://github.com/Robot-Nav/GO2_backflip/tree/PPO-backflip
代码:RSL-RL。
代码:https://github.com/leggedrobotics/rsl_rl
代码:Isaac Lab。
代码:https://github.com/isaac-sim/IsaacLab
网站:MuJoCo。
网站:https://mujoco.org/
网站:NVIDIA Isaac Lab Documentation。
网站:https://isaac-sim.github.io/IsaacLab/
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)