浮基动力学 → 单刚体化简 → Convex MPC 的二次规划构建 → RL 的 MDP 形式化与域随机化 → MPC+RL 混合仲裁的状态机 —— 以及把它们全部置于同一套推力恢复协议下的量化对比。
本项目的核心方法论是一条纪律:每个控制器组件都必须先有形式化定义、再有一个 量化验收协议,协议通过之前不进入下一个组件。没有度量就没有组件。
| 组件 | 工件(代码) | 验收判据 | 实测结果 |
|---|---|---|---|
| MPC 全栈 | convex_mpc.py + run_go2_mpc.py | 16 s 剧本:站立 4 s 内 roll/pitch 误差 < 0.2°,trot 4 s 稳定,0.5 m/s 前进 8 s 不摔 | 通过;速度跟踪 100% |
| 推力套件 | test_push_recovery.py | 无推力对照组 100% 通过(防误报) | 三方均通过 |
| RL 环境 | train_go2_rl.py | --smoke 368k 步管线验证:奖励上升、obs 结构 (47,) 与部署端逐维一致 | 通过 |
| BC 初始化 | collect_demos.py + bc_bootstrap.py | MSE 收敛 + MuJoCo sim2sim 复现步态极限环 | MSE 0.00042,步态复现 |
| 混合仲裁 | run_go2_hybrid.py | --no-push 对照:全程 0 次误交棒;有推力时恰在推力时刻交棒 | 通过(1 次交棒恰在推力时刻) |
| 决赛 | 统一套件入口 | 72 试验全表 + 对照组 | §5.2 |
三种控制器(MPC、RL、混合)输出统一到同一执行器接口,因此可以被同一套推力协议(§5)逐格对表。
视频 1 · 混合控制器演示实录(26 s,record_video.py 离屏渲染,剧本可复现;
模型 Unitree Go2,mujoco_menagerie)。
机身橙红 = 仲裁器交棒 RL 救援(§4),原色 = MPC 行驶;三脚 18/20/22 N·s 全部救回,零摔倒,共 6 次换脑决策:
同一台机器人需要三个层次的模型:全量浮基动力学(仿真真值与低层前馈)、 单刚体(SRB)化简(MPC 的决策模型)、执行器与接触模型(两条栈共用的底层约定)。
广义坐标 \(q \in \mathbb{R}^{19}\)(自由基 7 + 关节 12),广义速度 \(v \in \mathbb{R}^{18}\), 关节力矩 \(\tau \in \mathbb{R}^{12}\)。含接触的运动方程:
$$M(q)\dot{v} + C(q,v)\,v + g(q) = S^\top \tau + \sum_{i \in \mathcal{C}(q)} J_i(q)^\top \lambda_i$$其中 \(\mathcal{C}\) 为当前接触集(足端球与地面),\(J_i\) 是接触点雅可比,\(\lambda_i\) 接触冲量, \(S \in \mathbb{R}^{12 \times 18}\) 关节选择矩阵。MuJoCo 以半隐式欧拉(\(q_{t+h} = q_t + h\,v_{t+h}\))积分, 接触为软约束(solimp/solref 参数化的弹簧-阻尼近似刚性)。MJX 是同一模型在 XLA 上的 逐元素重实现——两者共享 MJCF,但接触求解的实现路径不同,这正是本项目把 MuJoCo 实测 作为迁移判据的原因(工作流 W5)。
convex MPC 把机器人压缩为单刚体,决策状态取 \(x = [\,\theta,\; p,\; \omega,\; v\,]^\top \in \mathbb{R}^{12}\): \(\theta\) 为机身 ZYX 欧拉角(world),\(p\) 质心位置(world),\(\omega\) 角速度(body),\(v\) 质心速度(world)。 化简假设与实际影响如实列出:
| 假设 | 内容 | Go2 上的真实误差 |
|---|---|---|
| A1 复合惯量冻结 | 惯量取 home 姿态下全机复合惯量,视为常数 | 腿占总质量 55%(8.28/15.21 kg),摆腿时惯量时变——SRB 对 Go2 是粗近似 |
| A2 忽略陀螺项 | \(\omega \times I\omega\) 不进角动力学 | 小角速度下二阶小量 |
| A3 点接触 | 每足接触简化为足端球一点 3 维力 | 足端球半径仅 0.022 m,合理 |
A1 的误差部分被低层补偿:500 Hz 内层使用全量模型的重力+科氏前馈
(MuJoCo qfrc_bias,逐关节精确),SRB 只负责净力/净力矩的分配(§2.7)。
连续时间 SRB 动力学:
其中 \(r_i = p_i^{\text{foot}} - p\) 是足到质心矢径,\(I_w = R_z(\psi)\, I\, R_z(\psi)^\top\), \(f_i \in \mathbb{R}^3\) 为 world 系足端接触力(决策变量)。旋转部分做 yaw 线性化:\(R_z\) 取当前偏航角处的常值旋转——这是"凸化"的关键, 动力学对 \(f_i\) 保持严格线性,QP 因此成立。
结点间隔 \(h = 0.02\) s,前向欧拉离散化(实现使用显式欧拉而非矩阵指数, 一阶精度换取 15 步预测的构造简单性):
$$x_{k+1} = A\,x_k + B_k\,u_k + c, \qquad A = \begin{bmatrix} I_3 & 0 & h\,R_z(\psi) & 0 \\ 0 & I_3 & 0 & h\,I_3 \\ 0 & 0 & I_3 & 0 \\ 0 & 0 & 0 & I_3 \end{bmatrix}, \quad c = h\,[\,0,\,0,\,0,\,g\,]^\top$$ $$B_k\text{ 的第 } i \text{ 足块:}\quad \begin{bmatrix} 0 \\ 0 \\ h\,I_w^{-1}\,\mathrm{skew}(r_i) \\ \tfrac{h}{m} I_3 \end{bmatrix}, \qquad u_k = [f_1^\top, f_2^\top, f_3^\top, f_4^\top]^\top \in \mathbb{R}^{12}$$堆叠 \(N = 15\) 步预测(行块 \(k\) 对应状态 \(x_{k+1}\)):
$$X = S\,x_0 + G\,U + d, \qquad S_k = A^{k+1}, \quad G_{k,j} = A^{\,k-j}\,B_j \;\; (j \le k), \quad d_k = \sum_{j \le k} A^{\,k-j}\, c$$Apow[k-1-j],
在 \(k=0\) 时 Python 负索引取到 \(A^{-1}\to A^{N}\)(列表环绕),静态站立时垂直力只达体重的 40%
而无任何报错。教训:预测矩阵必须用从 \(I\) 起的显式幂表 Apow=[I, A, A², …],
并用"站立时 \(\sum f_z = mg\)"做单元断言。下表全部常数由脚本从 MJCF 与 MuJoCo 模型运行时提取(非手抄),是三条控制栈的 唯一事实来源:
| 常数 | 值 | 来源/用途 |
|---|---|---|
| 全机质量 \(m\) | 15.206 kg | 复合惯量计算(home 姿态) |
| 躯干质量 | 6.921 kg(腿占 55%) | SRB 假设 A1 的量化背景 |
| 复合惯量对角 \(I\) | (0.2554, 0.4826, 0.4513) kg·m² | 关于总质心,world 系,home 姿态 |
| 广义坐标 | \(n_q = 19\), \(n_v = 18\), \(n_u = 12\) | 浮基 + 每腿 3 关节(外展/大腿/小腿)×4 |
| 腿几何 | 大腿 = 小腿 = 0.213 m;大腿体原点 y = ±0.142 m;足端球半径 0.022 m | IK 与落脚点参考(§2.5/2.6) |
| home 关节角 | \((0,\, 0.9,\, -1.8)\) × 4,站立高度 0.27 m | keyframe 0;RL 默认姿态同源 |
| 执行器(MPC 栈) | 直力矩,限幅 ±23.7 N·m | go2_mpc_scene.xml |
| 执行器(RL/混合栈) | 位置伺服 \(k_p = 50\), \(k_d = 0.5\)(rad 域) | scene_mjx.xml / hybrid_scene.xml |
| 接触摩擦 | 足端滑动摩擦 0.8,地面 1.0;QP 取 \(\mu = 0.4\)(§2.2 余量) | geom_friction |
| 仿真步长 | 2 ms(MuJoCo 与 MJX 同);MPC 重解 10 ms;RL 训练策略周期 8 ms、部署 20 ms(§3.7) | opt.timestep |
| 接触硬度(MPC/混合栈) | 足端 solimp 覆写 (0.9, 0.95, 0.001),近刚性;RL 栈保持 menagerie 默认软接触 | 两栈有意不同,见 §3.7 注记 |
决策模型为 §1.2 的 SRB。整个控制器 = 一个滚动时域 QP(100 Hz)+ 步态机与摆动轨迹生成 + Raibert 落脚点 + 数值 IK + 500 Hz 力矩内层。
决策变量 \(U = [u_0; \dots; u_{N-1}] \in \mathbb{R}^{12N}\)(\(N = 15\) 个结点上四足 × 3 维力, 时域 0.3 s)。目标:
$$\min_U \;\; (X - X^{\text{ref}})^\top \bar{Q} (X - X^{\text{ref}}) \; + \; U^\top \bar{R}\, U \qquad \text{s.t.} \quad X = S x_0 + G U + d, \;\; \text{接触约束(下)}$$展开为 OSQP 标准形 \(\min \tfrac12 U^\top P U + q^\top U\): \(P = 2(G^\top \bar Q G + \bar R)\),\(q = 2\,G^\top \bar Q\,(S x_0 + d - X^{\text{ref}})\)。 权重(逐结点状态对角阵,末结点放大 3 倍近似终端代价):
| 状态分量 | 权重(rpy, p, ω, v 逐项) | 设计含义 |
|---|---|---|
| 姿态 \(Q_{\theta}\) | (60, 120, 15) | 俯仰权重最高——前向行走的主要不稳定模式 |
| 位置 \(Q_p\) | (12, 12, 100) | 水平 12 是推力恢复实测调优值(原始 2 太弱,位移后不回拉);高度 100 |
| 角速度 \(Q_\omega\) | (2, 2, 0.5) | 阻尼 |
| 线速度 \(Q_v\) | (6, 6, 8) | 速度跟踪 |
| 力正则 \(\bar R\) | \(2\times10^{-5} I\) | 最小范数倾向,保证 QP 严格凸 |
接触约束(对每足 \(i\)、每结点 \(k\);摆动足 \(f_{i,k} = 0\) 为等式约束):
$$|f_x| \le \mu f_z, \quad |f_y| \le \mu f_z, \quad 0 \le f_z \le f_{\max}, \qquad \mu = 0.4,\;\; f_{\max} = 130\,\text{N}$$摩擦约束采用外接金字塔线性化(4 面体近似二阶锥,角点处可超真实锥 \(\sqrt2\) 倍), \(\mu = 0.4\) 对仿真真实摩擦 0.8~1.0 留出的余量同时吸收线性化误差与实现误差 (实测:贴真实摩擦边缘取 \(\mu\) 时,支撑足在姿态修正中滑出 14 cm)。 求解器 OSQP(eps_abs/rel 1e-3,max_iter 2000,adaptive_rho,不 polish); 求解失败时回退为支撑足平摊体重的静态分配。每 10 ms 重解,取首结点力 \(u_0\) 执行。
位置参考锚点 \(p_{\text{cmd}}\) 按指令速度积分推进,指令变化瞬间重锚到当前质心 (接受阶跃、不做长时回拉);第 \(k\) 结点参考:
$$x_k^{\text{ref}} = [\,0,\, 0,\, \psi_{\text{cmd}};\;\; p_{\text{cmd}} + v_{\text{cmd}}\,t_k,\; z_{\text{des}};\;\; 0;\;\; v_{\text{cmd}}\,]$$其中 \(z_{\text{des}} = 0.27\) m 与 home 高度一致,\(\psi_{\text{cmd}}\) 锁定初始偏航
(本项目不测试转向机动)。步态预测矩阵 stance_pred[k][i] 由 §2.3 的相位函数
向前展开生成,喂给 QP 的约束切换。
相位 \(\phi \in [0,1)\) 以周期 \(T = 0.6\) s 推进(\(\phi \gets (\phi + h/T) \bmod 1\))。 对角组 \(\mathcal{A} = \{\text{FL}, \text{RR}\}\)、\(\mathcal{B} = \{\text{FR}, \text{RL}\}\), 摆动占比 \(s_f = 0.4\),占空比 0.6:
$$\text{swing}(\mathcal{A}) \Leftrightarrow \phi \in [0,\, s_f), \qquad \text{swing}(\mathcal{B}) \Leftrightarrow \phi \in [0.5,\, 0.5 + s_f)$$摆动进度 \(s \in [0,1) = \phi / s_f\)(组内归一)。两个设计不变量: (i) \(s_f < 0.5\) 保证存在四足全支撑重叠窗(\([0.4,0.5) \cup [0.9,1)\), 每窗 0.06 s)——纯 50% 占空比时任意时刻仅两足着地,绕对角轴的力矩不可控; (ii) 摆动窗必须设上界——无上界时进度外插 \(s > 1\),足端目标被规划进地面以下。
原地模式的自适应恢复时序(迟滞状态机):倾角 > 18° 进入恢复模式, < 10° 退出;恢复模式且仅原地时:有足在摆动则 1.8× 加速落地,已停住(\(\|v\| < 0.5\)) 且仍大倾角则冻结步态保持四足。行走中冻结步态被数据证伪并禁用(§5.4)。
起摆点 \(p_0\) → 落点 \(p_1\),水平面用五次多项式平滑步 \(\sigma(s) = 6s^5 - 15s^4 + 10s^3\)(\(\sigma'\)、\(\sigma''\) 在端点为 0); 高度用 \(\sin^3\) 拱线并带提前触地停等:
$$p_{\text{foot}}(s) = p_0 + \sigma(s)\,(p_1 - p_0), \qquad z(s) = (1-\sigma)\,p_{0z} + \sigma\,p_{1z} + h\,\sin^3\!\big(\pi \min(s/0.9,\, 1)\big)$$高度 \(h = 0.05\) m。剖面选择的依据是端点导数性质:摆动腿对机身的反作用力 由 z 剖面端点加速度决定(SRB 未建模此项)—— \(\sin(\pi s)\) 端点速度非零(触地垂直速度达峰 1.26 m/s,等于命令摆动足砸向地面); \(\sin^2\) 端点加速度达 ~4g(把机身周期性踹沉);\(\sin^3\) 的端点速度与加速度同时为零 (\(\sin^3 x \sim x^3\) 在 0 处二阶平坦)。\(s/0.9\) 的截断使足端在 \(s = 0.9\) 即到地面等待, 足端因重力超前于剖面时目标已在地面等它。
标称落点(Raibert 1986):
$$p^{\text{land}} = p_{\text{hip}} + \tfrac{T_{\text{st}}}{2}\, v_{\text{cmd}} + k\,(v - v_{\text{cmd}}), \qquad T_{\text{st}} = T(1 - s_f) = 0.36\,\text{s},\;\; k = 0.18$$\(p_{\text{hip}}\) 取大腿体原点(y = ±0.142 m,腿实际悬挂处)而非髋关节锚点 (y = ±0.0465 m)——用错参考点会把落点内收 9.5 cm,四腿在机身下交叉导致侧翻。 \(k\) 从 0.05 提到 0.18 是本项目 MPC 从 18% 到 40% 恢复率的主要单项贡献: 被推后主要靠"迈步接住"(capture stepping)而非力微调恢复(Raibert 1986 的经典结论)。
仅原地模式且大倾角时叠加倾角捕获项(向倾倒方向跨步):
$$\Delta x = \mathrm{clip}\big(0.20\,(\theta_p + 0.15\,\omega_y),\, \pm 0.15\big), \quad \Delta y = \mathrm{clip}\big(-0.30\,(\theta_r + 0.15\,\omega_x),\, \pm 0.15\big)$$侧向落点半宽夹在 \([0.10, 0.24]\) m(工作空间边界),总落点偏移限幅 0.28 m—— 无夹幅时原始捕获位移可达 0.5 m,超出工作空间后 IK 钳位到关节极限,伸直的腿撑地 反而加速倾倒。行走中的捕获步被数据证伪并默认关闭(§5.4)。
每腿 3 连杆解析 IK 存在但本实现选择与模型解耦的数值 DLS 解 (独立 MjData 做正运动学,不污染仿真状态):
$$q^{(j+1)} = \mathrm{clip}\!\big(q^{(j)} + J^\top (J J^\top + \lambda^2 I_3)^{-1} e,\;\; q_{\min},\, q_{\max}\big), \qquad e = p^{\text{target}} - p^{\text{foot}}(q^{(j)}),\;\; \lambda = 0.01$$\(J \in \mathbb{R}^{3\times3}\) 为足端对腿 3 关节的雅可比(mj_jacGeom),
支撑腿迭代 3 次、摆动腿 4 次,收敛阈 1e-5 m,全程关节限位内夹持。
支撑腿(虚功原理:足端外力 \(f\) 与关节力矩 \(\tau\) 对任意虚位移做功相等 \(\Rightarrow \tau = -J^\top f\),负号因 \(f\) 是足端受到的外力):
$$\tau_{\text{stance}} = -J^\top f^{\text{MPC}} + k_p^{\text{st}} (q_{\text{ref}} - q) - k_d^{\text{st}}\, \dot q + \tau_{\text{bias}}$$其中 \(q_{\text{ref}}\) 为"钉地"构型(IK 解向触地时刻记录的钉地点,随机身运动连续更新),
弱 PD(\(k_p^{\text{st}}=30\), \(k_d^{\text{st}}=1.5\))锚定该构型;
\(\tau_{\text{bias}}\) = MuJoCo qfrc_bias 的腿块——全量模型的重力+科氏项,
逐关节精确,这就是 §1.2 假设 A1 误差的低层补偿。
摆动腿:
$$\tau_{\text{swing}} = k_p^{\text{sw}} (q_{\text{ref}} - q) + k_d^{\text{sw}} (\dot q_{\text{ref}} - \dot q) + \tau_{\text{bias}}, \qquad k_p^{\text{sw}} = 80,\; k_d^{\text{sw}} = 4$$近地阻尼:足端进入地面 3 cm 内时附加 \(-J^\top K_{\text{cart}}\, v_{\text{foot}}\)(\(K_{\text{cart}} = 40\) N·s/m), 直接耗散足端垂直动量,打断"足端超前剖面撞地→弹飞机身"的冲击环。 惯性前馈 \(M\ddot q_{\text{ref}}\) 经 A/B 测试无收益,置 0(§5.4)。 全部力矩裁剪至 ±23.7 N·m 执行器限幅。
RL 栈把同一个 MJCF 交给 MJX 做批量物理,控制器是 MLP 策略 \(\pi_\theta(a \mid o)\),PPO 训练。BC(行为克隆)提供初始化, 域随机化提供迁移性。
观察 \(o \in \mathbb{R}^{47}\)(全本体感知,无全局真值,无视觉):
| 块 | 维 | 定义 |
|---|---|---|
| 步态时钟 | 2 | \([\sin 2\pi\phi_c,\; \cos 2\pi\phi_c]\),\(\phi_c\) 以 \(T_c = 0.6\) s 推进(与 MPC 步态周期同源),随机初相 |
| 重力方向 | 3 | \(R^\top [0,0,1]\)(机体系上方向量;直立时 z ≈ 1) |
| 速度指令 | 3 | \([c_x, c_y, c_\omega]\),每回合采样一次 |
| 机身角速度 | 3 | \(\omega\)(body 系) |
| 关节角偏差 | 12 | \(q - q_{\text{def}}\)(默认姿态 (0, 0.9, −1.8)×4) |
| 关节角速度 | 12 | \(\dot q\) |
| 上一动作 | 12 | \(a_{t-1}\)(一阶动力学记忆) |
动作 \(a \in \mathbb{R}^{12}\),部署控制律(与训练环境同式):
$$q^* = q_{\text{def}} + 0.4 \cdot \mathrm{clip}(a, \pm 1.5), \qquad \tau = k_p (q^* - q) - k_d \dot q, \;\; k_p = 50,\, k_d = 0.5$$奖励(全部显式项,逐项与代码一致):
$$r_t = r_{\text{vel}} + r_{\text{ang}} + r_z + r_{\text{att}} + 0.2 + c_{\text{act}} + c_{\dot q} + c_{\text{dev}} - 5\,\mathbb{1}[\text{done}]$$ $$r_{\text{vel}} = 2.5\,e^{-\frac{(v_x^b - c_x)^2}{0.12}} + 0.5\,e^{-\frac{(v_y^b - c_y)^2}{0.12}} + 0.5\,\mathrm{clip}(1 - |v_x^b - c_x|, 0, 1)$$ $$r_{\text{ang}} = 0.25\,e^{-\frac{(\omega_z - c_\omega)^2}{0.25}}, \quad r_z = 0.35\,e^{-100 (z - 0.28)^2}, \quad r_{\text{att}} = 0.5\,e^{-10 (g_x^2 + g_y^2)}$$ $$c_{\text{act}} = -0.01 \textstyle\sum_j (a_j - a_{j,t-1})^2, \quad c_{\dot q} = -2\times10^{-4} \textstyle\sum_j \dot q_j^2, \quad c_{\text{dev}} = -0.02 \textstyle\sum_j (q_j - q_{\text{def},j})^2$$\(v^b = R^\top v^{\text{world}}\)(机体系线速度,由四元数显式展开计算)。 速度项用"高斯核 + 线性远场项"双结构:高斯核提供近目标稠密梯度,线性项保证 远处仍有梯度。存活奖励 0.2/步。终止(done):
$$z < 0.16 \;\;\lor\;\; z > 0.45 \;\;\lor\;\; g_z < 0.5 \;(\text{倾斜} > 60°)$$回合随机化(训练分布,reset 抽样):初始位置 xy ±0.1 m、z +[0.01, 0.05] m、 姿态四元数 σ0.02、关节 σ0.15 rad;初速基座 σ0.2 m/s、关节 σ0.3 rad/s; 指令 \(c_x \sim U(-0.3, 1.0)\)、\(c_y \sim U(-0.3, 0.3)\)、\(c_\omega \sim U(-0.8, 0.8)\); 观察加性噪声 σ0.02; 速度冲量推力:每 \(U[100, 250]\) 步对基座 xy 加 \(\Delta v \sim U[-v_p, v_p]^2\) (课程决定 \(v_p\),与 §5 协议的 N·s 同标度:\(m \Delta v = J\))。
标准 PPO 截断代理目标 + 价值回归 + 熵正则(Brax v2 实现):
$$L(\theta) = \mathbb{E}\big[\min\big(\rho_t A_t,\; \mathrm{clip}(\rho_t, 1\pm\epsilon) A_t\big)\big] - c_v \big(V_\theta(o_t) - \hat V_t\big)^2 + c_e\, \mathbb{H}[\pi_\theta(\cdot \mid o_t)]$$\(\rho_t = \pi_\theta / \pi_{\text{old}}\),GAE(λ=0.95) 计算优势并归一化。 网络:策略 MLP (128, 128) tanh,价值 MLP (256, 256);观察用运行统计(Welford) 标准化(\(o \gets (o - \mu) / \sigma\),在训练前向内部完成)。超参与课程:
| 参数 | 从头训练 | BC 后温柔精调 |
|---|---|---|
| 并行环境 / 回合长度 | 512 / 1000 步 | 同 |
| unroll / minibatch / 每批更新 | 20 / 32 / 4(每次更新的数据量 ×4 以降梯度噪声) | |
| 折扣 γ / GAE λ / 截断 ε | 0.97 / 0.95 / 0.3 | |
| 学习率 | 2e-4 | 5e-5 |
| 熵代价 | 2e-3 | 1e-4 |
| 物理域随机化 | 开(每回合重抽样,§3.4) | |
课程(STAGES):s1 12M 步(指令域 \(c_x \in [0.4, 1.0]\) 逼出行走,无推力)→ s2 15M 步(全指令域,无推力)→ s3 8M 步(推力 \(\Delta v \le 0.9\) m/s,间隔 5~10 s)→ s4 8M 步(推力 \(\Delta v \le 1.8\) m/s,间隔 3~7 s)。BC 链跳过 s1 直接从 bc_init 进 s2。 推力课程的依据是实测负结果:一上来就用目标难度会让策略陷进"蹲下保命"局部最优 (速度奖励低于站立基线)。
示范:MPC 控制器在 MuJoCo 中跑 12 回合,采 13,190 个 \((o, a)\) 对 (采集时 MPC 步态相位锁定到部署时钟,保证相位确定对应)。 BC 目标是分布众数的 MSE(确定性复现):
$$\mathcal{L}_{\text{BC}}(\theta) = \big\| \mathrm{mode}(\pi_\theta(o)) - a_{\text{demo}} \big\|^2, \qquad \text{Adam } 10^{-3},\; \text{batch } 256,\; 150 \text{ epochs}$$收敛 MSE 0.00042(动作尺度 0.4 rad 下 ~0.01 rad 级)。 相位时钟必要性(形式化):步态目标映射 \(a(o, \varphi)\) 是未观察相位 \(\varphi\) 的周期函数;无时钟时,MSE 最优预测器是条件期望 \(a^*(o) = \mathbb{E}[a \mid o] = \int a(o, \varphi)\, dP(\varphi \mid o) \mathrm{d}\varphi\) ——对相位取平均把周期解坍缩为相位均值姿态(≈静止)。 观察加入 \((\sin 2\pi\varphi, \cos 2\pi\varphi)\) 后映射对 \(\varphi\) 可逆,极限环可复现。
价值网预训练:对示范回报(return-to-go \(R_t^{\to} = \sum_{t' \ge t} \gamma^{t'-t} r_{t'}\)) 做 MSE 监督(Adam 1e-3,100 epochs)。动机:随机初始化的价值网让 PPO 早期的优势 估计系统性错误,第一步大更新就摧毁 BC 精度——实测首轮精调(熵 2e-3、lr 2e-4、无价值预训) 即把克隆步态完全打散。产出 \((\text{统计}, \pi, V)\) 三元组直接作为 PPO restore 起点。
每回合 reset 抽样一次缩放系数,step 内以 sys.replace 重建 brax 物理系统
(System 是 flax PyTreeNode,纯函数替换):
| 物理量 | 分布(相对标称缩放) | 作用面 |
|---|---|---|
| 滑动摩擦 | \(\times\, U[0.6, 1.4]\)(标量) | geom_friction[:, 0] |
| 连杆质量 | \(\times\, U[0.85, 1.15]\)(逐 body 独立) | body_mass |
| 关节阻尼 | \(\times\, U[0.7, 1.3]\)(逐 DoF 独立) | dof_damping |
| 电机强度 | \(\times\, U[0.7, 1.3]\)(标量,\(k_p, k_d\) 同乘) | actuator gainprm/biasprm |
连同 §3.1 的初始状态/观察噪声/冲量推力三类随机化,训练分布覆盖 "物理参数不定"这一 sim2real 的主要现实。机理:物理定值时策略可以过拟合 单一引擎的接触细节(本项目实测:无 DR 精调越过 11.8M 步甜点后 MuJoCo 迁移性单调退化,18M 最终策略 4 s 翻倒,§5.3);物理随机后过拟合不再有收益, 策略被迫收敛到对参数族鲁棒的行为。
三方各持一角(§5.2):MPC 强在速度跟踪,RL-BC 强在抗扰。 混合 = MPC 常态驾驶 + RL 危机接管 + 仲裁器决定每个瞬间谁在开车。
两脑必须驱动同一组位置伺服(\(\tau = k_p(q^* - q) - k_d \dot q\))。MPC 输出的是力矩, 令伺服输出等于 MPC 力矩,解出位置目标:
$$k_p\,(q^* - q) - k_d \dot q = \tau_{\text{MPC}} \;\;\Longrightarrow\;\; q^* = q + \frac{\tau_{\text{MPC}} + k_d\,\dot q}{k_p}, \qquad k_p = 50,\; k_d = 0.5$$一行公式把力控栈嵌入位置伺服,MPC 全栈零改动。代价:位置伺服的 ctrlrange 是关节 位置域,MPC 原有的力矩限幅(±23.7)在该域被误用——实现中禁用 MPC 侧力矩裁剪, 统一在位置域夹持。
状态集 \(\{\text{MPC}, \text{RL}\}\),逐 2 ms 步评估。记 \(\mathrm{tilt} = \max(|\theta_r|, |\theta_p|)\), \(\mathrm{dv} = \|v_{xy} - \tilde v_{\text{cmd}}\|_2\) (\(\tilde v_{\text{cmd}}\) 为斜坡滤波后的指令,见下),\(z\) 为质心高度。
交棒(MPC → RL):
$$z < 0.17 \;\;\lor\;\; \Big( t - t_{\text{hb}} > 0.6\,\text{s} \;\land\; \big(\mathrm{dv} > 0.45 \;\lor\; \mathrm{tilt} > 14° \;\lor\; z < 0.19 \big) \Big)$$接回(RL → MPC)(救援时长 \(t_r\)):
$$t_r \ge 0.8\,\text{s} \;\land\; \Big( \underbrace{\big(\mathrm{tilt} < 15° \,\land\, z > 0.20 \,\land\, \|v_{xy}\| < 0.40\big)_{\text{持续} \ge 0.3\,\text{s}}}_{\text{脱离危机}} \;\lor\; \underbrace{(t_r > 2.5\,\text{s} \,\land\, z > 0.19)}_{\text{超时强制}} \Big)$$指令斜坡滤波(仅用于 dv 的参考,不改变 MPC 实际指令):每步沿指令误差方向 推进至多 \(0.8 \times 0.002\) m/s:
$$\tilde v \gets \tilde v + \min\Big(1,\, \frac{0.8\,h}{\|v_{\text{cmd}} - \tilde v\|}\Big)\,(v_{\text{cmd}} - \tilde v)$$存在性证明式的实测教训决定了每条阈值:
输出为两脑位置目标的凸组合,混合系数 \(\alpha\) 每步(2 ms)向目标推进 0.05 (全过渡 40 ms):
$$\alpha \gets \mathrm{clip}(\alpha^{*} - \alpha, \pm 0.05) + \alpha, \qquad u = \alpha\, q^*_{\text{MPC}} + (1 - \alpha)\, q^*_{\text{RL}}$$RL 策略全程影子运行(50 Hz obs-action 链保持连续),交棒时无观察跳变。 接回时重锚 MPC 内部状态:步态相位清零、钉地点重新触地检测、位置参考锚到当前质心 (不往回拽),恢复模式标志复位。
每次试验:keyframe 复位并抬高基座使足端恰好触地 → 站立 4 s → 进入工况 → 在窗口内随机时刻对基座施加 0.1 s 水平脉冲力 \(\to\) 观察至终点。
| 参数 | 取值 |
|---|---|
| 冲量 \(J = \|f\| \cdot 0.1\text{s}\) | \(\{10, 20, 30\}\) N·s ⇒ \(\Delta v = J/m = \{0.66, 1.32, 1.97\}\) m/s |
| 方向 | 8 个(0°~315°,步进 45°) |
| 工况 | trot(原地小跑;推力窗 5.5~6.5 s,观察至 11 s;种子 {1,2});walk(0.5 m/s 行走;推力窗 10~11 s,观察至 14 s;种子 {3}) |
| 总试验数 | 3 冲量 × 8 方向 × (2 + 1) 种子 × 2 工况 = 72 |
| 摔倒判定 | 任意时刻 \(z < 0.16\) m |
| 通过判定 | 无摔倒 ∧ 终点 \(z > 0.20\) ∧ \(|\theta_r|, |\theta_p| < 20°\) |
| 恢复时间 | 推力结束后 \(\|v_{xy}\| < 0.15\) 且 \(|\theta_r|, |\theta_p| < 15°\) 持续 0.2 s 的时刻 |
| 对照组 | 无推力必须 100% 通过且混合版 0 次交棒(防仲裁误报) |
| 工况 / 冲量 | MPC | RL-BC | Orthrus 混合 |
|---|---|---|---|
| trot 10 N·s | 88% | 88% | 100% |
| trot 20 N·s | 44% | 56% | 100% |
| trot 30 N·s | 12% | 25% | 81% |
| walk 10 N·s | 62% | 88% | 100% |
| walk 20 N·s | 0% | 75% | 100% |
| walk 30 N·s | 13% | 38% | 88% |
| 总恢复率 | 40% | 60% | 94%(68/72) |
读法:逐格支配——混合在每一格都不劣于两个父母,多数格严格更优; 平均恢复时间 0.66 s 与单控制器持平(无代价);对照组零误报。 剩余 4 个失败全部是 30 N·s 纯侧向(±90°):2 m/s 侧向捕获点超出单步工作空间, 是单步捕获架构的物理天花板,由双方父母共同继承(§6)。 速度跟踪:MPC 单独 0.5 m/s 跟踪 100%;混合版 ~0.3 m/s;RL-BC ~0.07 m/s(观察无 线速度的代价,§3.1)。
无 DR 精调链(物理定值)在 MuJoCo 上的迁移曲线——训练侧指标全程向好, 部署侧从 11.8M 起单调退化:
| 训练步数 | MJX 评估奖励 | MuJoCo 实测(无 DR) | MuJoCo 实测(带 DR) |
|---|---|---|---|
| 0(BC 起点) | 1103 | ✅ 走,净速 −0.06 m/s | — |
| 11.8M(无 DR 峰值) | 1604 | ✅ 走,净速 +0.14 m/s | ✅ 走,+0.07,姿态有界 |
| 3.93M / 5.9M / 9.8M | 1532(早期峰) | 健康区(未逐点测) | ✅ 全部存活:−0.06 / +0.04 / +0.09 |
| 13.76M | 1414 | ⚠️ 走,净速 −0.14 m/s | ✅ +0.17 m/s(本项目最佳 RL 步行者) |
| 15.73M | 1103 | ⚠️ 走,净速 −0.20 m/s | ✅ +0.12 m/s |
| 17.7M(最终) | 1334 | ❌ 4 s 内翻倒 | ✅ 存活行走,−0.04,姿态有界 |
| s3 推力 0.9 m/s(0→8.85M) | 950~1080 | ❌ 最终躺平(z=0.079) | ❌ 9/9 检查点全部趴地(z=0.081) |
| s4 推力 1.8 m/s(0→8.85M) | 768 | ❌ 最终躺平 | ❌ 全部检查点含最终趴地(roll 178°) |
终局判定(链 15:29→17:39 完成):域随机化的判决是分裂的。
results/dr_finetune_verdict.json。| 尝试 | 结果 | 处置 |
|---|---|---|
| 从零 PPO 40M 步 | 回合长度 2→800 但净位移始终为零("站立"是奖励结构下的近最优解) | 转向 BC 引导 |
| 首轮精调(熵 2e-3,lr 2e-4,无价值预训) | 克隆步态被 PPO 第一步更新打散 | 温柔配方(1e-4 / 5e-5 / 价值预训) |
| MPC:0.5 s 更长视野 + 摆动中落点重规划 + 倾角捕获步 + 角速度触发 | 推力测试零收益甚至负收益(walk@10N·s 5/8→0/8) | 全部回退,仅保留原地模式自适应时序 |
| 摆动惯性前馈 \(M\ddot q_{\text{ref}}\)(A/B) | 无收益 | 置 0 |
| 无 DR 精调越过甜点继续训练 | sim2sim 单调退化(上表) | 域随机化重训(本节) |
git clone https://github.com/weiwei-gu/Orthrus && cd Orthrus
python3 -m venv .venv && .venv/bin/pip install mujoco "jax==0.9.2" mujoco-mjx brax osqp
# 交互演示(变橙红 = RL 接管救场)
.venv/bin/mjpython show_go2_hybrid.py
# 复现三方决赛(各 ~15 分钟)
.venv/bin/python run_go2_hybrid.py --push # 混合: 94%
.venv/bin/python test_push_recovery.py # MPC: 40%
.venv/bin/python eval_go2_rl.py policies/bc_init.pkl --push # RL-BC: 60%
# 重训 RL 脑(含 §3.4 域随机化,约 3 小时 CPU)
bash run_gentle_finetune.sh
| 文件 | 本文档对应章节 | 作用 |
|---|---|---|
convex_mpc.py | §1.2–1.3, §2.1 | SRB 模型、堆叠预测、QP 构建与求解 |
go2_utils.py | §2.3–2.6 | 步态相位机、sin³ 摆动轨迹、Raibert 落脚点、DLS IK |
run_go2_mpc.py | §2.2, §2.7 | MPC 全栈(参考轨迹、500 Hz 内层、自适应时序) |
train_go2_rl.py | §3.1–3.4 | MJX 环境(obs/奖励/DR)+ PPO 课程训练 |
collect_demos.py / bc_bootstrap.py | §3.3 | MPC 示范采集 → BC + 价值网预训练 |
eval_go2_rl.py | §3.5, §5.1 | RL 策略的 MuJoCo sim2sim 评估(行走 + 推力套件) |
run_go2_hybrid.py | §4 | 混合仲裁器 + 决赛入口 |
test_push_recovery.py | §5.1 | 72 试验协议(三方共用的尺子) |
results/*.json | §5 | 全部试验原始数据,负结果也在 |
models/go2/ | §1.4 | vendor 的 MJCF(场景 ×3 + 完整模型) |
record_video.py | §0 | 演示视频离屏渲染录制(→ docs/demo.mp4,剧本可复现) |
docs/claude-history.txt | — | 7,800 行完整开发会话记录 |