本文档属于 Robotics Tutorial 项目,作者:Pengfei Guo,达妙科技。采用 CC BY 4.0 协议,转载请注明出处。
第 59 章 优化驱动的落脚与接触规划——Contact-Implicit TO / 互补松弛 / 双层分解 / 学习融合¶
难度: ⭐⭐⭐~⭐⭐⭐⭐ | 前置: 足式/60_QP_NLP建模 NLP/QP, 足式/80_接触力学与约束优化 接触力学与互补约束, 足式/100_DDP家族与Crocoddyl DDP, 足式/140_落脚点规划经典方法 落脚点经典方法 | 学时: 20-25 小时
前置自测¶
📋 前置自测(答不出 >= 2 题 → 先回对应章节复习)
- 互补约束 \(0 \le \phi \perp \lambda \ge 0\) 的三个组成条件分别是什么?其几何含义是什么?(→ 足式/80_接触力学与约束优化)
- **NLP 的 KKT 条件**中,互补松弛条件 \(\mu_i g_i(x) = 0\) 的物理含义是什么?为什么它会导致数值困难?(→ 足式/60_QP_NLP建模)
- DDP 的 backward pass 中,\(Q_{xx}, Q_{xu}, Q_{uu}\) 矩阵分别代表什么?为什么 \(Q_{uu}\) 必须正定?(→ 足式/100_DDP家族与Crocoddyl)
- Raibert 落脚启发式 \(\boldsymbol{p}_f = \boldsymbol{p}_{\text{hip}} + \frac{T_s}{2}\dot{\boldsymbol{p}} + k(\dot{\boldsymbol{p}} - \dot{\boldsymbol{p}}_{\text{ref}})\) 中每一项的物理意义是什么?它在什么场景下会失效?(→ 足式/140_落脚点规划经典方法)
- LICQ(线性独立约束品性) 失效时,NLP 求解器会出现什么问题?(→ 足式/60_QP_NLP建模)
本章目标¶
学完本章,你应能:
- 理解"接触作为决策变量"这一范式转变——从 足式/110_OCS2完整栈与双线程MPC-58 的预定义步态到让优化器自主发现接触
- 完整写出 Contact-Implicit TO 的 NLP 公式——包括互补约束嵌入、变量结构、约束雅可比
- 掌握互补约束的三大数值处理方法——松弛法、Fischer-Burmeister 函数、增广拉格朗日法——并理解各自的收敛性与适用场景
- 精读 Posa 2014 IJRR 论文——理解 time-stepping + LCP 嵌入的技术细节
- 理解变分接触隐式优化——Manchester 2019 如何利用变分积分器提高物理忠实度
- 从双层优化视角统一理解接触规划——上层选接触序列、下层优化轨迹
- 了解学习驱动的前沿方法——RL、扩散模型、基础模型在接触规划中的应用
- 在 Towr 上实践 CITO 工程实现——Winkler 的 phase-duration 参数化
本章知识导航¶
本章的逻辑主线是一条从"问题为什么难"到"怎么把它解出来"再到"怎么把它跑快"的递进链。下图给出全章的知识结构与依赖关系:
┌─────────────────────────────────────────┐
│ 59.1 范式转变:接触从"输入"变为"决策变量" │ ← 动机层
└────────────────────┬────────────────────┘
│
┌────────────────────────────┼────────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 59.2 CITO 公式 │ ──依赖──▶│ 59.3 互补约束数值 │ ──应用──▶│ 59.4 Posa 2014 │ ← 理论层
│ 时间步进/雅可比 │ │ 松弛/FB/ALM/MPCC │ │ 奠基论文精读 │
└───────┬───────┘ └──────────────────┘ └──────────────────┘
│ │
▼ ▼
┌───────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 59.5 变分 CITO │ │ 59.6 质心轨迹优化 │ │ 59.7 双层优化 │ ← 降维/分解层
│ 辛结构/二阶精度 │ │ 降维加速 │ ──分解──▶│ MIQP+NLP / GCS │
└───────────────┘ └──────────────────┘ └──────────────────┘
│ │
└────────────┬───────────────┘
▼
┌──────────────────────────────────────┐
│ 59.8 学习驱动 + 59.9 Towr 工程实现 │ ← 加速/落地层
│ RL/扩散/warm-start Ifopt+Ipopt │
└──────────────────────────────────────┘
四个认知层次:
| 层次 | 小节 | 解决的核心问题 | 关键认知 |
|---|---|---|---|
| 动机层 | 59.1 | 为什么启发式不够用? | 接触是决策变量而非输入 |
| 理论层 | 59.2–59.5 | 怎么把接触编码进优化? | 互补约束 + 它带来的数值噩梦及解法 |
| 分解层 | 59.6–59.7 | 全身 CITO 太慢怎么办? | 降维(质心)+ 分层(双层/GCS) |
| 加速/落地层 | 59.8–59.9 | 怎么逼近实时、怎么落地? | 学习 warm-start + Towr 工程实现 |
两条推荐阅读路径:
- 理论研究路径(想做 CITO 方向博士):59.1 → 59.2 → 59.3(精读三种方法)→ 59.4(Posa 精读)→ 59.5(变分)→ 59.7(双层 + GCS)。重点啃透互补约束的 MPCC 理论(59.3.5)。
- 工程落地路径(想在机器人上跑通):59.1 → 59.2.1(只看 NLP 结构)→ 59.6(质心降维)→ 59.9(Towr 实操)→ 59.8.2(学习 warm-start)。59.3/59.5 可速读。
前置知识桥接¶
本章是整个足式优化控制栈的"集大成"章节,几乎复用了前面所有理论章的工具。下表把每个前置概念的核心要点重述一遍,并说明本章如何复用——这样你不必翻回前章也能跟上:
| 前置章节 | 你需要记住的核心要点 | 本章如何复用 |
|---|---|---|
| 足式/60_QP_NLP建模 | NLP 的 KKT 条件由"驻点 + 原始可行 + 对偶可行 + 互补松弛"四部分组成;LICQ(约束梯度线性独立)是 KKT 成立的前提 | 59.3 的全部内容建立在"互补约束破坏 LICQ"这一观察上;理解 KKT 才能理解为什么 Ipopt 会崩 |
| 足式/80_接触力学与约束优化 | 接触建模为互补条件 \(0 \le \phi \perp \lambda \ge 0\);摩擦用库仑锥 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\);质心动量方程把全身动力学投影到 6 维 | 59.2 把这些互补条件"展平"为 NLP 约束;59.6 直接用质心动量方程做降维优化 |
| 足式/100_DDP家族与Crocoddyl | DDP 的 backward pass 计算 \(Q_{xx},Q_{ux},Q_{uu}\);\(Q_{uu}\) 须正定才能求控制增量;shooting 法的决策变量只有控制序列 | 59.4 对比 shooting(DDP)与 direct collocation(Posa);ACAL-iLQR(小结)把 ALM 嵌入 DDP backward pass |
| 足式/110_OCS2完整栈与双线程MPC | MPC 的接触序列 ModeSchedule 是**输入**;双线程架构 1 Hz 重规划 + 高频 MPC | 59.1 的范式转变正是把 ModeSchedule 从输入变为决策变量;全章的"离线 CITO + 在线 MPC"分层正是 OCS2 双线程的推广 |
| 足式/140_落脚点规划经典方法 | Raibert 启发式 \(\boldsymbol{p}_f = \boldsymbol{p}_{\text{hip}} + \frac{T_s}{2}\dot{\boldsymbol{p}} + k(\dot{\boldsymbol{p}}-\dot{\boldsymbol{p}}_{\text{ref}})\) 是逐腿独立、无全局视野的工程折中 | 59.1 用 stepping stones 场景展示 Raibert 的天花板,引出优化驱动 |
如果跳过本章会怎样¶
| 场景 | 不学本章的后果 |
|---|---|
| 让四足跨越 stepping stones | 只会用 Raibert + 感知修正,落脚点频繁落到石头边缘或空地,机器人踉跄摔倒——因为你不知道"接触位置本身应该被优化" |
| 读到一篇 CITO 论文(如 Posa 2014 / Winkler TOWR) | 看到 \(\phi \cdot \lambda = 0\) 一脸茫然,不理解为什么作者要花半篇论文讲"松弛"——因为你不知道互补约束会破坏 LICQ |
| 调一个不收敛的轨迹优化器 | 看到 Ipopt 报 "Restoration Failed" 只会随机调参,不知道根因可能是互补约束的数值病态,也不知道换 FB 函数或 ALM |
| 设计一个跨越障碍的运动规划系统 | 试图用单个 NLP 同时优化"踩哪 + 怎么走",陷入组合爆炸,永远收敛不到全局最优——因为你不知道双层分解 / GCS 这条路 |
预计阅读时间¶
| 模式 | 时间 | 覆盖范围 |
|---|---|---|
| 精读(动手推公式 + 跑代码) | 20–25 小时 | 全章 + 累积项目 M1–M4 + 跨章综合题 |
| 速读(理解思路,不抠每步推导) | 6–8 小时 | 59.1–59.4、59.6–59.7 正文 + 所有"本质洞察"和"陷阱" |
| 速查(用时回查) | 1 小时 | 方法选择决策树 + 三种互补方法对比表 + 故障排查手册 + API 速查表 |
59.1 从经典到优化:为什么需要优化驱动 ⭐¶
动机:启发式方法的天花板¶
本节解决的问题:足式/110_OCS2完整栈与双线程MPC-58 构建了一套完整的足式运动控制栈——步态管理器给定接触时序、Raibert 启发式计算落脚点、MPC 优化连续轨迹、WBC 输出关节扭矩。这套架构在平坦或轻度不平坦地形上工作良好。但当任务复杂度超过一定阈值时,这套"人类预设规则 + 优化器填细节"的范式就会触及根本性的天花板。
让我们用一个具体场景感受这个天花板:
场景:四足机器人穿越 stepping stones
Raibert 启发式的困境:
| 困境 | 原因 | 后果 |
|---|---|---|
| 不知道踩哪块石头 | Raibert 公式只管"步幅",不管"地形" | 可能落脚到空地上 |
| 不知道哪条路径最优 | 启发式没有全局视野 | 可能选了一条走不通的路 |
| 不知道何时切换步态 | 步态是预定义的 trot/walk | 某些间距需要 gallop 才能跨过 |
| 不知道如何协调四条腿 | Raibert 对每条腿独立计算 | 四条腿的落脚点可能导致动力学不可行 |
反面推演:如果强行用 Raibert + MPC
Step 1: Raibert 计算落脚点 → 落在空地上(没有石头)
Step 2: 感知修正 → 找最近的石头,但离得远 → 需要拉伸步幅
Step 3: MPC 发现步幅太大 → 接触力不够(摩擦锥约束违反)
Step 4: 机器人踉跄 → 重新规划 → 但下一步更远
Step 5: 级联失效 → 机器人摔倒
根因:每一步独立决策,没有全局最优性
优化驱动的核心思想¶
让优化器同时决定"何时接触"、"在哪接触"、"接触力多大",把离散的接触选择和连续的运动轨迹统一在一个优化问题中。
这个思想可以用一句话总结:
在 足式/110_OCS2完整栈与双线程MPC-58 中,接触序列(ModeSchedule)是 MPC 的**输入**。而在本章中,接触序列是优化问题的**决策变量**——这是根本性的范式转变。
什么时候需要优化驱动?¶
并非所有场景都需要这个重型工具。下表给出决策指南:
| 场景 | 推荐方法 | 理由 |
|---|---|---|
| 平坦地面 trot 行走 | Raibert + MPC | 简单高效,实时性好 |
| 轻度不平坦地形 | 感知修正 Raibert + MPC | 启发式修正足够 |
| stepping stones | MIQP / CITO | 需要全局规划接触位置 |
| 未知地形跳跃 | CITO | 需要发现新颖的接触策略 |
| 非周期动作(翻越障碍) | CITO + 学习 | 无预定义步态可用 |
| 多接触操作(抓取+行走) | CITO | 手/脚/物体接触耦合 |
历史脉络:从动画到机器人¶
接触优化的思想并非起源于机器人学,而是**计算机图形学**。2012 年,Mordatch、Todorov 和 Popovic 在 SIGGRAPH 发表了开创性的 Contact-Invariant Optimization(CIO),展示了仿真角色仅通过优化就能"发现"爬行、站立、翻身等复杂行为——完全不需要人类设计步态。
历史演进:
2005 ─ Stewart & Trinkle ─ LCP time-stepping 成为标准接触仿真方法
│
2012 ─ Mordatch et al. ─ Contact-Invariant Optimization (SIGGRAPH)
│ → 证明优化可以发现复杂接触行为
│
2014 ─ Posa, Cantu, Tedrake ─ Contact-Implicit TO (IJRR)
│ → 将 LCP 嵌入 NLP,奠定 CITO 数学基础
│
2018 ─ Winkler et al. ─ TOWR (RA-L)
│ → phase-duration 参数化,工程可用
│
2020 ─ Manchester, Kuindersma ─ 变分 CITO (IJRR)
│ → 变分积分器提高物理忠实度
│
2023 ─ Pang et al. ─ Quasi-Dynamic Smoothing (T-RO)
│ → 局部光滑化,10x 加速
│
2024 ─ ACAL-iLQR ─ Contact-Implicit iLQR + 增广拉格朗日
│ → 无需固定接触序列的 iLQR
│
2025 ─ Diffusion + CITO ─ 扩散模型生成接触计划初值
→ 学习与优化融合前沿
本章的四条技术路线¶
┌─────────────────────────────┐
│ 接触规划问题 │
│ "何时何地接触?" │
└──────────┬──────────────────┘
┌──────────┬───────┴───────┬──────────┐
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ CITO │ │ 双层优化 │ │ 质心轨迹 │ │ 学习驱动 │
│ 互补约束 │ │ MIQP+NLP │ │ 协同优化 │ │ RL/扩散 │
│ 嵌入 NLP │ │ 分层解耦 │ │ 连续松弛 │ │ 端到端 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
§59.2-59.5 §59.7 §59.6 §59.8
⚠️ 概念误区:CITO 可以实时运行
新手想法:"CITO 能自动发现接触,那就直接替代 MPC 吧!"
实际上:当前最快的 CITO 在四足机器人上仍需 1-10 秒求解(Posa 2014 报告 10-100 秒;Pang 2023 在操作任务上约 1 分钟;ACAL-iLQR 2024 对简单系统约 1 秒)。MPC 要求 5-50 毫秒。两者差 2-3 个数量级。
正确理解:CITO 是**离线规划**工具,生成的轨迹交给在线 MPC 跟踪。或者 CITO 在 1 Hz 重规划层运行,MPC 在 50 Hz 跟踪层运行。
唯一例外:Aydinoglu 2023 在低自由度机械臂上实现了约 50 ms 的 Contact-Implicit MPC,但四足机器人的维度(37 维状态)远超目前能力。
练习¶
练习 59.1a(⭐):列举三个 Raibert 启发式无法处理但 CITO 可以处理的场景,并解释为什么启发式会失败。
练习 59.1b(⭐⭐):如果 CITO 求解需要 5 秒,MPC 跟踪频率 50 Hz,地形每 2 秒变化一次,设计一个分层架构来融合两者。画出架构图并标注每层的频率和输入/输出。
59.2 Contact-Implicit TO 数学基础 ⭐⭐⭐¶
动机:为什么要把接触"隐含"在优化中?¶
本节解决的问题:如何把"何时接触"和"接触力多大"统一编码为一个 NLP,让求解器同时决定接触模式和运动轨迹?
**传统方法(显式接触)**的做法:人类指定接触序列(如 trot 步态的摆动/支撑时序),然后在每个模式段内分别优化。这等价于枚举所有可能的接触模式序列,对每种序列解一个 NLP,再选最好的——组合爆炸。
反面推演:枚举为什么不可行?
一条四足机器人的腿有两种状态: 支撑(1) 或 摆动(0)
四条腿 → 每个时间步有 2^4 = 16 种模式
10 个时间步 → 16^10 ≈ 10^12 种模式序列
每种序列解一个 NLP (假设 1 秒) → 需要 31,000 年
即使只考虑"合理"的序列,仍然是 NP-hard
CITO 的核心洞察:不枚举模式,而是**把接触力和距离作为连续决策变量**,让互补约束自动决定"有没有接触":
- 如果优化器发现 \(\lambda_k > 0\)(有接触力),则互补约束迫使 \(\phi_k = 0\)(脚在地面上)
- 如果优化器发现 \(\phi_k > 0\)(脚离地),则互补约束迫使 \(\lambda_k = 0\)(无接触力)
接触模式从**输入**变成了**输出**——由优化器自主发现。
59.2.1 完整 NLP 公式 ⭐⭐⭐¶
CITO 将接触动力学轨迹优化问题写成如下 NLP:
其中: - \(\mathbf{x}_k = [\mathbf{q}_k^T, \dot{\mathbf{q}}_k^T]^T\) 是广义位置和速度 - \(\mathbf{u}_k\) 是关节扭矩 - \(\boldsymbol{\lambda}_k = [\lambda_1^n, \boldsymbol{\lambda}_1^t, \dots, \lambda_{n_c}^n, \boldsymbol{\lambda}_{n_c}^t]\) 是所有潜在接触点的法向力和切向力(连续时间公式中 \(\boldsymbol{\lambda}\) 为力;离散时间步进公式中 \(\boldsymbol{\lambda}\) 常指冲量 \(\boldsymbol{\Lambda} = h\mathbf{f}\),详见 59.2.2) - \(\mathcal{C}\) 是**所有潜在**接触点的集合(不仅仅是当前接触的点) - \(\phi_i(\mathbf{x}_k)\) 是第 \(i\) 个接触点到地面的有符号距离 - \(\mu_i\) 是摩擦系数 - \(\gamma_i\) 是最大耗散原理中的辅助变量 - \(\mathbf{v}_i^t\) 是接触点的切向滑移速度
这个公式要解决什么问题? 它把传统轨迹优化中"给定接触序列,优化连续变量"的范式,推广为"同时优化接触决策和连续轨迹"。关键创新是把互补约束 \(\phi \cdot \lambda^n = 0\) 作为 NLP 约束——这个约束**隐式地**编码了接触模式的切换。
它是怎么被推导出来的? 起点是 Stewart-Trinkle 的 LCP 接触仿真公式(足式/80_接触力学与约束优化)。在正向仿真中,给定状态 \(\mathbf{x}_k\) 和控制 \(\mathbf{u}_k\),接触力 \(\boldsymbol{\lambda}_k\) 通过求解 LCP 得到。Posa 的洞察是:不在内层求解 LCP,而是把 LCP 的条件"展平"为 NLP 的约束——这样接触力变成了与状态、控制地位平等的决策变量。
如果没有互补约束会怎样? 没有 \(\phi \cdot \lambda^n = 0\) 的话,优化器可以自由地在 \(\phi > 0\)(脚在空中)时施加接触力 \(\lambda^n > 0\)——等于"隔空推力",物理上不可能。互补约束正是排除了这种非物理解。
变量规模分析:
| 变量类别 | 维度 | ANYmal 示例 |
|---|---|---|
| 状态 \(\mathbf{x}_k\) | \(2n_q\) | \(2 \times 19 = 38\)(含浮动基座) |
| 控制 \(\mathbf{u}_k\) | \(n_u\) | \(12\)(12 个关节) |
| 接触力 \(\boldsymbol{\lambda}_k\) | \(3 n_c\) | \(3 \times 4 = 12\)(4 个足端) |
| 每步决策维度 | \(2n_q + n_u + 3n_c\) | \(38 + 12 + 12 = 62\) |
| N=50 步总维度 | \(N \times (2n_q + n_u + 3n_c) + 2n_q\) | \(\approx 3138\) |
对比 足式/100_DDP家族与Crocoddyl 的 DDP(不含接触力变量):\(N \times (2n_q + n_u) + 2n_q = 2538\)。CITO 多了 \(N \times 3n_c = 600\) 个接触力变量,代价是约 24% 的维度增长——但带来了接触自主决策的能力。
59.2.2 离散动力学:时间步进法(Time-Stepping) ⭐⭐⭐¶
CITO 的离散动力学不是简单的欧拉或 RK4 积分。因为接触力可能在一个时间步内突然出现或消失(碰撞),需要专门的**时间步进(time-stepping)**格式。
为什么需要专门的格式? 碰撞在数学上是一个**不连续事件**——速度在碰撞瞬间发生跳变。标准 ODE 积分器(欧拉、RK4)假设右端函数连续,无法正确处理速度跳变。时间步进法的核心思想是:在每个时间步内,允许速度不连续,用冲量(而非瞬时力)来描述接触效应。
Stewart-Trinkle 时间步进公式(1996):
其中 \(h\) 是时间步长,\(\mathbf{M}\) 是质量矩阵,\(\mathbf{J}_c\) 是接触雅可比。
为什么用半隐式(semi-implicit)格式?
注意上式先更新速度,再用新速度更新位置——这是半隐式欧拉。对比三种选择:
| 积分格式 | 速度更新 | 位置更新 | 稳定性 | 能量守恒 |
|---|---|---|---|---|
| 显式欧拉 | \(\dot{q}_{k+1} = \dot{q}_k + h a_k\) | \(q_{k+1} = q_k + h \dot{q}_k\) | 差(发散) | 能量增长 |
| 半隐式 | \(\dot{q}_{k+1} = \dot{q}_k + h a_k\) | \(q_{k+1} = q_k + h \dot{q}_{k+1}\) | 好 | 近似守恒 |
| 隐式欧拉 | 需解方程 | 需解方程 | 很好 | 能量耗散 |
半隐式欧拉是 CITO 的事实标准,因为它在**稳定性**和**计算成本**之间取得了最佳平衡。显式欧拉在接触问题中会因为能量增长而发散(想象一个弹跳球越弹越高);隐式欧拉虽然稳定但需要在每步内部解一个非线性方程,计算代价太高。
关键细节:接触力是冲量
在时间步进公式中,\(\boldsymbol{\lambda}_k\) 实际上是**冲量**(impulse),不是瞬时力。这是因为碰撞在 \(h \to 0\) 时力趋于无穷、持续时间趋于零,但冲量有限。对于持续接触,\(\boldsymbol{\lambda}_k \approx h \cdot \mathbf{f}_{\text{contact}}\)。这个区别在编程时很重要——如果你需要从 CITO 的解中提取接触力(而非冲量),需要除以时间步长 \(h\)。
59.2.3 约束雅可比的结构 ⭐⭐⭐¶
NLP 求解器(如 Ipopt)需要约束对决策变量的雅可比矩阵。CITO 的约束雅可比有特殊的**块稀疏**结构:
约束雅可比矩阵 J 的结构(N=4 步,3 个约束类型):
x0 u0 λ0 x1 u1 λ1 x2 u2 λ2 x3
dyn_0 [ Fx0 Fu0 Fλ0 -I ]
dyn_1 [ Fx1 Fu1 Fλ1 -I ]
dyn_2 [ Fx2 Fu2 Fλ2 -I ]
comp_0 [ ∂(φλ) ]
comp_1 [ ∂(φλ) ]
comp_2 [ ∂(φλ) ]
fric_0 [ ∂(μλn-||λt||) ]
fric_1 [ ∂(μλn-||λt||) ]
fric_2 [ ∂(μλn-||λt||) ]
→ 带状稀疏!每行只有 2-3 个非零块
→ Ipopt 可以利用稀疏性加速
稀疏性为什么重要?
CITO 的总决策维度约 3000,如果约束雅可比是稠密的,存储需要 \(3000^2 \approx 10^7\) 个元素。但由于带状稀疏,实际非零元素只有 \(O(N \cdot n^2) \approx 10^5\)——减少两个数量级。Ipopt 使用 MA57 或 MUMPS 稀疏分解器,能高效处理这种结构。
⚠️ 编程陷阱:忘记提供稀疏模式给 Ipopt
错误做法:在 Ipopt 的
eval_jac_g回调中返回稠密矩阵。症状:求解时间从几秒变成几分钟,内存占用暴增。
根因:Ipopt 默认假设雅可比是稀疏的。如果不提供稀疏模式(
iRow,jCol),Ipopt 会退化为稠密运算。正确做法:在
eval_jac_g的第一次调用(values == nullptr)时返回非零元素的行列索引;后续调用只填充非零值。Ifopt 框架(Towr 使用的 NLP 接口)会自动处理稀疏模式。💡 概念误区:CITO 的 NLP 维度"太大"所以不实用
新手想法:"3000 维的 NLP?这不可能解得动吧!"
实际上:现代 NLP 求解器(Ipopt 2025 版)配合稀疏线性代数库(MA57, MUMPS)可以在几秒内解 10000+ 维的 NLP——前提是利用了稀疏性。CITO 慢的原因不是维度大,而是互补约束导致的**非凸性**和**LICQ 失效**。去掉互补约束的标准轨迹优化在同样维度下只需 0.1 秒。
练习¶
练习 59.2a(⭐⭐):对于一个 2D 单腿弹跳机器人(\(n_q = 3\):水平位置、竖直位置、腿长;\(n_u = 1\):腿力;\(n_c = 1\):足底接触),写出完整的 CITO NLP 公式,包括所有约束。计算 \(N = 20\) 时的总决策变量数。
练习 59.2b(⭐⭐⭐):证明 CITO 的互补约束 \(\phi_i \cdot \lambda_i^n = 0\) 违反了 LICQ。提示:考虑 \(\phi_i = 0, \lambda_i^n = 0\) 的情况(同时为零),计算此点处约束梯度的线性相关性。
练习 59.2c(⭐⭐):为什么时间步进法用半隐式欧拉而不用 RK4?列举至少两个技术原因。
59.2.4 摩擦锥的 LCP 线性化与最大耗散原理 ⭐⭐⭐¶
本节解决的问题:59.2.1 的 NLP 公式(行内式)写了一条最大耗散约束 \(\boldsymbol{\lambda}_i^t + \gamma_i \frac{\mathbf{v}_i^t}{\|\mathbf{v}_i^t\|} = 0\),但没说它从哪来、为什么长这样。这一条约束是整个接触摩擦建模的灵魂——它决定了"脚滑动时摩擦力指向哪里"。本节把它彻底讲清,并解释 Stewart-Trinkle 为什么要把光滑的摩擦锥"切成多面体"。
动机:库仑摩擦不只是"力的大小有上限"¶
回顾 足式/80_接触力学与约束优化:库仑摩擦给出的约束是 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\)——切向力的模长不超过法向力的 \(\mu\) 倍。很多初学者以为这就是摩擦的全部,于是直接把它当作一条不等式塞进 NLP。
反面推演:只用 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\) 会漏掉什么?
考虑一只脚正在地面上**向右滑动**(切向速度 \(\mathbf{v}^t\) 指向右)。物理上,动摩擦力必须满足两个条件:
- 大小:滑动时摩擦力取到最大值,即 \(\|\boldsymbol{\lambda}^t\| = \mu\lambda^n\)(**等号**成立,落在锥面上,不是锥内部);
- 方向:摩擦力必须**反向**于滑动速度,即指向左。
只写 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\) 完全没有约束方向——优化器可以让一只向右滑的脚受到一个**向右**的摩擦力(顺着滑动方向推),这会凭空给系统注入能量,是物理上荒谬的解。这就是为什么必须额外引入一条约束来锁定摩擦力的方向。
最大耗散原理(Maximum Dissipation Principle)¶
锁定方向的原理叫**最大耗散原理**:在所有满足摩擦锥约束 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\) 的切向力中,真实的摩擦力是使**摩擦功率耗散最大**的那一个。形式化为一个内层优化:
其中 \(-\boldsymbol{\lambda}^t \cdot \mathbf{v}^t\) 是摩擦力做的负功率(耗散的功率)。
推导这个 argmax 的解:目标 \(-\boldsymbol{\lambda}^t \cdot \mathbf{v}^t\) 关于 \(\boldsymbol{\lambda}^t\) 是线性的,可行域是一个半径为 \(\mu\lambda^n\) 的圆盘。线性函数在凸集上的最大值必在边界取得,且最优 \(\boldsymbol{\lambda}^t\) 与梯度方向 \(-\mathbf{v}^t\) 同向、模长顶到边界:
这正是"摩擦力反向于滑动、大小取满"的数学表达。
怎么把这个内层 argmax 变成 NLP 约束? 内层是一个凸优化,写出它的 KKT 条件:引入乘子 \(\gamma \ge 0\) 对应约束 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\),则驻点条件给出
这就是 59.2.1 出现的那条约束的来历——它是最大耗散内层优化的一阶最优性条件。乘子 \(\gamma\) 有清晰的物理意义:它正是**滑动速率的代理**——只有当脚真的在滑(\(\|\mathbf{v}^t\|>0\))时 \(\gamma>0\),此时互补条件 \(\gamma(\mu\lambda^n-\|\boldsymbol{\lambda}^t\|)=0\) 迫使 \(\|\boldsymbol{\lambda}^t\|=\mu\lambda^n\)(力顶到锥面);脚不滑(黏滞)时 \(\gamma=0\),力可以落在锥内部。
本质洞察:摩擦不是一条"力的大小上限"约束,而是一个**嵌套的优化问题**——大自然在每个接触点都在悄悄解一个"最大耗散"的小优化。CITO 把这个内层优化的 KKT 条件展平到外层 NLP 里,于是接触点的"滑/不滑"决策和机器人的整体运动被统一求解。这与 59.2.1 把 LCP"展平"成 NLP 是同一种思想的两次运用:把内层求解器替换为内层约束。
Stewart-Trinkle 的多面体摩擦锥(Faceted Friction Cone)¶
上面的最大耗散约束含有 \(\frac{\mathbf{v}^t}{\|\mathbf{v}^t\|}\) —— 一个在 \(\mathbf{v}^t=0\) 处奇异、且本质非线性的项。Stewart-Trinkle time-stepping 为了把整个接触问题写成一个**线性互补问题(LCP),做了一个关键工程近似:**用多面体(棱锥)逼近光滑的二阶锥摩擦锥。
怎么做? 在切向平面内取 \(d\) 个均匀分布的方向向量 \(\mathbf{d}_1,\dots,\mathbf{d}_d\)(例如 3D 接触取 \(d=4\) 或 \(d=8\),对应"东南西北"等方向),把切向力分解为这些方向的非负组合:
摩擦锥约束 \(\|\boldsymbol{\lambda}^t\| \le \mu\lambda^n\) 被近似为线性约束:
最大耗散原理则离散化为:每个方向分量 \(\beta_j\) 与"该方向上的滑动趋势"互补。引入辅助变量 \(\zeta\)(所有方向共享,代表滑动速率的下确界代理),得到 LCP 形式:
这组互补条件在说什么? 第一行:方向 \(\mathbf{d}_j\) 上只有当它最"逆着"滑动速度时(\(\mathbf{d}_j^T\mathbf{v}^t\) 最负)才激活力分量 \(\beta_j\);第二行:只要有任何滑动(\(\zeta>0\)),切向力就顶满摩擦锥(\(\sum\beta_j=\mu\lambda^n\))。这恰好是离散化的"反向 + 取满"。
为什么要做这个近似?代价是什么?
| 方面 | 光滑二阶锥(true cone) | 多面体近似(faceted) |
|---|---|---|
| 数学形式 | 二阶锥约束(SOCP / 非线性) | 线性约束 + LCP |
| 求解器 | 需要 SOCP 或 NLP | 可用纯 LP/LCP 求解器(Lemke 算法) |
| 摩擦方向 | 连续任意方向 | 只能取 \(d\) 个离散方向的组合 |
| 误差 | 精确 | 摩擦力被高估/低估,最大相对误差约 \(1-\cos(\pi/d)\) |
| \(d\to\infty\) | —— | 收敛到真锥 |
近似误差随 \(d\) 增大而减小:\(d=4\) 时摩擦各向异性可达约 30%(沿对角方向摩擦偏大),\(d=8\) 降到约 8%。工程权衡:\(d\) 越大越精确,但 LCP 维度随 \(d\) 线性增长。多数仿真器(含早期 MuJoCo、Bullet)默认 \(d=4\) 或在金字塔锥(pyramidal cone)与椭圆锥(elliptic cone)之间提供选项。
💡 概念误区:CITO 里一定要用多面体锥
新手想法:"Posa 用了 Stewart-Trinkle,所以 CITO 必须把摩擦锥切成多面体。"
实际上:多面体化是**LCP time-stepping 仿真**的需要——因为 LCP 求解器只吃线性约束。但在 CITO 里,我们用的是**NLP 求解器(Ipopt),它本来就能处理非线性约束。因此现代 CITO 实现(如 Drake、CALIPSO)常常**直接保留光滑二阶锥 \(\|\boldsymbol{\lambda}^t\|\le\mu\lambda^n\),避免多面体化带来的各向异性误差。Posa 2014 沿用多面体锥更多是历史原因(直接继承 Stewart-Trinkle 公式)。
正确理解:是否多面体化取决于**下游求解器吃什么**——LCP 求解器要线性,NLP/SOCP 求解器可以非线性。
⚠️ 编程陷阱:\(\frac{\mathbf{v}^t}{\|\mathbf{v}^t\|}\) 在零速度处除零
错误做法:直接在最大耗散约束里写
lambda_t + gamma * v_t / v_t.norm()。症状:脚处于黏滞(stick)状态、切向速度恰好为零时,
v_t.norm()为 0,约束求值返回 NaN,整个 NLP 雅可比污染为 NaN,Ipopt 立即报 "Invalid number in NLP function evaluation"。根因:黏滞与滑动的过渡点 \(\mathbf{v}^t=0\) 是约束的奇异点——这正是多面体化(用 LCP 形式避开归一化)或软化(下式)要解决的。
正确做法:要么改用多面体 LCP 形式(无归一化项),要么对范数做软化 \(\|\mathbf{v}^t\|\approx\sqrt{\|\mathbf{v}^t\|^2+\varepsilon^2}\),要么直接用光滑锥 \(\|\boldsymbol{\lambda}^t\|\le\mu\lambda^n\) 配合 Ipopt(推荐)。
练习¶
练习 59.2.4a(⭐⭐):对一个 2D 接触点(切向只有一维),最大耗散原理退化为什么形式?写出 \(\boldsymbol{\lambda}^t,\gamma,\mathbf{v}^t\) 之间的关系,并解释为什么 2D 情形不需要多面体化。
练习 59.2.4b(⭐⭐⭐):取 \(d=4\) 的多面体摩擦锥,方向向量为 \(\pm\mathbf{e}_x,\pm\mathbf{e}_y\)。证明这个金字塔锥的内切圆半径为 \(\mu\lambda^n/\sqrt{2}\)、外接情况下沿对角方向可表示的最大切向力为 \(\sqrt{2}\,\mu\lambda^n\)。由此估计 \(d=4\) 时摩擦力的各向异性误差。
练习 59.2.4c(⭐⭐⭐):从最大耗散的内层优化 \(\max_{\|\boldsymbol{\lambda}^t\|\le\mu\lambda^n}(-\boldsymbol{\lambda}^t\cdot\mathbf{v}^t)\) 出发,用 Lagrange 乘子法完整推导出 59.2.1 中的约束 \(\boldsymbol{\lambda}^t+\gamma\frac{\mathbf{v}^t}{\|\mathbf{v}^t\|}=0\) 与互补条件 \(\gamma(\mu\lambda^n-\|\boldsymbol{\lambda}^t\|)=0\)。
59.3 互补约束的数值处理 ⭐⭐⭐¶
动机:互补约束为什么是数值噩梦?¶
本节解决的问题:CITO 的核心困难不在于动力学约束(那是标准的 NLP),而在于互补约束 \(\phi \cdot \lambda = 0\)。这个看似简单的约束为什么让所有标准 NLP 求解器头疼?如何处理它?
为什么互补约束这么难?
考虑一维互补约束 \(a \ge 0, b \ge 0, a \cdot b = 0\)。这个约束定义了一个"L 形"可行域——只有 \(a\) 轴和 \(b\) 轴上的点是可行的。
三个致命问题:
| 问题 | 数学描述 | 后果 |
|---|---|---|
| 非凸性 | \(\{(a,b): a \ge 0, b \ge 0, ab = 0\}\) 不是凸集 | 局部最优不等于全局最优 |
| LICQ 失效 | 在 \(a = b = 0\) 处,\(\nabla(ab) = [b, a]^T = [0, 0]^T\) | KKT 条件不适用,Lagrange 乘子不唯一 |
| 非光滑性 | 可行域在原点处"弯折" | 梯度不连续,Newton 法收敛性丧失 |
为什么 LICQ 失效是致命的? LICQ(Linear Independence Constraint Qualification)是 KKT 条件成立的前提。在互补约束的"退化点"\(\phi = \lambda = 0\) 处(即接触恰好开始/结束的瞬间),约束 \(\phi \cdot \lambda = 0\) 的梯度为零向量——与其他约束的梯度线性相关。此时 Lagrange 乘子不唯一,Ipopt 的内点法步长计算会失败。
Ipopt 遇到互补约束会怎样?
Ipopt 是内点法求解器,它把不等式约束转化为等式约束加障碍项:\(\min f(x) - \mu \sum \ln(s_i)\), s.t. \(g(x) + s = 0\)。但互补约束 \(ab = 0\) 作为**等式约束**会导致约束雅可比在可行域上秩亏——Ipopt 的线性系统会变得病态,迭代震荡不收敛。
59.3.1 方法一:松弛法(Relaxation) ⭐⭐⭐¶
核心思想:把精确互补 \(\phi \cdot \lambda = 0\) 松弛为 \(\phi \cdot \lambda \le \epsilon\),其中 \(\epsilon > 0\) 是小量。
这个方法要解决什么问题? 把 MPCC(Mathematical Program with Complementarity Constraints)——一类结构上病态的优化问题——转化为标准的 NLP——可以用 Ipopt 等成熟求解器处理。
为什么这能帮助?
- 松弛后的可行域从"L 形"变成了一个包含 L 形的"厚 L 形"——在原点附近有一个 \(\epsilon\) 大小的"缓冲区"
- 在缓冲区内,LICQ 恢复——约束雅可比满秩
- Ipopt 可以正常工作
如果不做松弛会怎样? 直接把 \(\phi \cdot \lambda = 0\) 作为等式约束传给 Ipopt,求解器会在接触切换点附近反复震荡——线性系统条件数爆炸(\(10^{10}\) 以上),Newton 步方向错误,最终报 "EXIT: Restoration Failed" 或 "EXIT: Converged to a point of local infeasibility"。
续延策略(Continuation / Homotopy):
逐步减小 \(\epsilon\),让解从松弛问题"滑"向精确问题:
Algorithm: Relaxation with Continuation
────────────────────────────────────
Input: 初始猜测 z0, 松弛序列 ε₁ > ε₂ > ... > ε_final
Output: CITO 解 z*
for k = 1, 2, ... do
z* ← Ipopt.solve(NLP(εk), warm_start = z_{k-1})
if εk <= ε_final:
return z*
end if
end for
续延策略的选择:
| 策略 | \(\epsilon\) 更新 | 优点 | 缺点 |
|---|---|---|---|
| 固定比率 | \(\epsilon_{k+1} = 0.1 \cdot \epsilon_k\) | 简单 | 可能跳过解 |
| 自适应 | 根据 KKT 残差调整 | 稳健 | 实现复杂 |
| Ipopt 内置 | 利用 Ipopt 的 barrier parameter | 代码量最少 | 收敛可能慢 |
Posa 2014 用的就是这个方法——初始 \(\epsilon = 10^{-1}\),最终 \(\epsilon = 10^{-4}\),通常需要 3-5 轮续延。
59.3.2 方法二:Fischer-Burmeister 函数 ⭐⭐⭐¶
来龙去脉:Fischer-Burmeister (FB) 函数是 1992 年 Andreas Fischer 提出的一种**非线性互补问题(NCP)函数**。它能把互补约束 \(a \ge 0, b \ge 0, ab = 0\) 等价地转化为一个**等式约束**——消除了 LICQ 失效的问题。
它是怎么被发明的? 互补问题 (NCP) 的研究可以追溯到 1960 年代的线性规划和博弈论。数学家们一直在寻找一种函数 \(\psi(a, b)\),满足 \(\psi(a, b) = 0 \iff a \ge 0, b \ge 0, ab = 0\)。这样的函数称为 NCP 函数。Fischer 1992 年发现了一个优雅的构造——利用欧几里得范数。
定义:
性质(为什么它能替代互补约束?):
\(\psi_{\text{FB}}(a, b) = 0\) 当且仅当 \(a \ge 0, b \ge 0, ab = 0\)。
推导(完整证明):
同时,\(\sqrt{a^2 + b^2} = a + b\) 要求 \(a + b \ge 0\)(因为左边非负),加上 \(ab = 0\),必然 \(a \ge 0, b \ge 0\)。
反向验证:若 \(a = 3, b = 0\),则 \(\psi_{\text{FB}} = \sqrt{9} - 3 - 0 = 0\) ✓。若 \(a = 0, b = 5\),则 \(\psi_{\text{FB}} = \sqrt{25} - 0 - 5 = 0\) ✓。若 \(a = 1, b = 1\),则 \(\psi_{\text{FB}} = \sqrt{2} - 2 \approx -0.586 \ne 0\) ✓(不满足互补)。\(\square\)
直觉理解:\(\sqrt{a^2 + b^2}\) 是 \((a, b)\) 到原点的距离,\(a + b\) 是沿 45 度线到原点的距离。只有当 \((a, b)\) 落在坐标轴上时,两者相等——这恰好是互补条件的几何含义。
FB 函数相比松弛法的优势:
| 方面 | 松弛法 | FB 函数 |
|---|---|---|
| 约束类型 | 不等式 \(\phi\lambda \le \epsilon\) | 等式 \(\psi_{\text{FB}} = 0\) |
| LICQ | 仍然可能有问题 | 总是满足(梯度在 \(a=b=0\) 处非零) |
| 续延 | 需要多轮 | 不需要 |
| 梯度 | 在 \(\phi = \lambda = 0\) 处有问题 | 在 \(a = b = 0\) 处梯度存在但不光滑 |
光滑化 FB 函数:原始 FB 函数在 \(a = b = 0\) 处不可微(\(\sqrt{a^2 + b^2}\) 的梯度不存在)。光滑化版本:
其中 \(\sigma > 0\) 是光滑化参数。\(\psi_{\text{FB}}^{\sigma}\) 处处可微,且 \(\sigma \to 0\) 时收敛到原始 FB 函数。
梯度(供 NLP 求解器使用):
注意这两个偏导数在 \(a = b = 0\) 时为 \(-1\)(而非 0),因此 LICQ 恢复。
59.3.3 方法三:惩罚法与增广拉格朗日法 ⭐⭐⭐¶
惩罚法:把互补约束作为惩罚项加入目标函数:
当 \(\rho \to \infty\) 时,惩罚项迫使互补约束趋于满足。
惩罚法的来龙去脉:惩罚法是约束优化的最经典方法之一,可追溯到 1960 年代 Courant 的外点惩罚法。思想很简单:不满足约束就"罚钱",罚得越多,解就越接近可行域。
惩罚法的问题:
- \(\rho\) 太小 → 互补约束违反严重
- \(\rho\) 太大 → NLP 数值病态(Hessian 条件数 \(\propto \rho\),达到 \(10^{8}\) 以上)
- 需要逐步增大 \(\rho\)(外层循环),每轮 \(\rho\) 翻倍直到满足精度
增广拉格朗日法(ALM)——惩罚法的改良版:
其中 \(\mu_{k,i}\) 是拉格朗日乘子的估计值。相比纯惩罚法,多了一个**线性项** \(\mu \cdot c\)——这是精妙之处。
为什么线性项使 \(\rho\) 不需要趋于无穷?
纯惩罚法的最优性条件:\(\nabla J + \rho \cdot c \cdot \nabla c = 0\)。要使 \(c \to 0\),需要 \(\rho \to \infty\)。
ALM 的最优性条件:\(\nabla J + (\mu + \rho c) \cdot \nabla c = 0\)。如果 \(\mu\) 趋近真实 Lagrange 乘子 \(\mu^*\),则即使 \(c = 0\),最优性条件仍然满足(\(\nabla J + \mu^* \nabla c = 0\) 正是 KKT 条件)。因此 \(\rho\) 只需要"足够大"使外层迭代收敛,不需要趋于无穷。
ALM 的更新规则:
Algorithm: Augmented Lagrangian for Complementarity
────────────────────────────────────
Input: 初始猜测 z0, mu0 = 0, rho0 = 1
Output: CITO 解 z*
for k = 0, 1, 2, ... do
z_{k+1} ← solve min L_aug(z; mu_k, rho_k) // 内层 NLP
// 更新乘子
for each complementarity constraint i:
mu_i ← mu_i + rho * (phi_i * lambda_i^n)
// 自适应更新 rho
if ||violation|| > 0.25 * ||prev_violation||:
rho ← 10 * rho // 收敛太慢,加大惩罚
if ||violation|| < tolerance:
return z_{k+1}
end for
2024 年前沿:CALIPSO 求解器
CALIPSO(Conic Augmented Lagrangian Interior-Point SOlver)是 Taylor Howell 等人在 2022 年(ISRR)提出的求解器,专门为带互补约束和锥约束的轨迹优化设计。它结合了增广拉格朗日法(处理互补约束)和内点法(处理锥约束),在 CITO 问题上比 Ipopt 快 5-10 倍。CALIPSO 已集成在 Julia 的 ContactImplicitMPC.jl 包中。
59.3.4 三种方法的对比 ⭐⭐¶
| 方法 | 数学原理 | 优点 | 缺点 | 代表实现 |
|---|---|---|---|---|
| 松弛法 | \(\phi\lambda \le \epsilon\) | 简单,与 Ipopt 无缝集成 | 需要续延,\(\epsilon\) 调参 | Posa 2014 |
| FB 函数 | \(\psi_{\text{FB}} = 0\) | 不需续延,LICQ 恢复 | 需要光滑化 | 学术研究 |
| 增广拉格朗日 | \(\min J + \mu c + \frac{\rho}{2}c^2\) | \(\rho\) 不需趋于 \(\infty\),条件好 | 外层循环,实现复杂 | CALIPSO |
实用建议: - 入门/原型:用松弛法 + Ipopt,最简单 - 研究级别:用 ALM + 定制求解器(CALIPSO) - 如果你的 NLP 已经不收敛:先检查初值,再换 FB 函数试试
💡 概念误区:互补约束等价于 if-else 分支
新手想法:"\(\phi \cdot \lambda = 0\) 不就是
if (contact) lambda > 0 else phi > 0吗?直接 if-else 不就好了?"实际上:if-else 在优化中是不可微的。NLP 求解器需要目标和约束对所有决策变量的梯度。if-else 分支在切换点梯度不存在——Newton 法无法通过切换点。互补约束把 if-else 编码为一个**连续**(虽然不光滑)的等式,使得通过上述三种方法可以光滑化后求解。
类比:ReLU 函数 \(\max(0, x)\) 也是 if-else(\(x > 0\) 时输出 \(x\),否则输出 0),但在深度学习中我们直接对它求梯度(虽然 \(x = 0\) 处次梯度不唯一),效果很好。互补约束的处理思路类似。
🧠 思维陷阱:认为松弛就是"近似",不是精确解
新手想法:"松弛后 \(\phi\lambda \le \epsilon\) 不是零,解不准确吧?"
实际上:续延策略让 \(\epsilon \to 0\),最终得到的解满足 \(\phi\lambda = O(10^{-4})\)——在工程上等价于精确互补。而且,即使有微小违反,物理上只意味着"脚离地面有 \(10^{-4}\) m 的间隙时仍有微小接触力"——完全可接受。
真正的问题不是精度,而是收敛性:松弛法可能收敛到**错误的局部最优**——比如所有接触力都是零(机器人"飞"起来)。这才是需要担心的。
练习¶
练习 59.3a(⭐⭐):手推 Fischer-Burmeister 函数在以下三个点的值和梯度:\((a, b) = (0, 5)\)、\((3, 0)\)、\((0.01, 0.01)\)。验证前两个点确实满足互补条件。
练习 59.3b(⭐⭐⭐):用 Python/CasADi 实现一个 1D 互补约束问题:\(\min (a - 2)^2 + (b - 3)^2\), s.t. \(a \ge 0, b \ge 0, ab = 0\)。分别用松弛法和 FB 函数求解,比较解和迭代次数。
练习 59.3c(⭐⭐⭐):解释为什么增广拉格朗日法的 \(\rho\) 不需要趋于无穷就能精确满足约束。提示:写出 ALM 的最优性条件,说明乘子 \(\mu\) 在迭代中会收敛到真实 Lagrange 乘子。
59.3.5 MPCC 的平稳性理论:为什么"LICQ 失效"不是末日 ⭐⭐⭐⭐¶
本节解决的问题:前面我们反复说"互补约束破坏 LICQ,所以 KKT 条件失效"。这听起来像是判了死刑——既然 KKT 都不成立,我们求出来的"最优解"还有意义吗?本节给出否定这个悲观结论的严谨理论:带互补约束的优化(MPCC,又称 MPEC)有**自己的一套最优性理论**,把标准 KKT 替换为 C-/M-/S-平稳性(stationarity)。这是理解"为什么三种数值方法收敛到不同质量的解"的理论根基。
动机:标准 NLP 理论为什么在这里集体失效¶
把 CITO 的互补约束写成抽象形式,得到的优化问题叫 MPCC(Mathematical Program with Complementarity Constraints)或 MPEC(Mathematical Program with Equilibrium Constraints):
其中 \(G(x)\perp H(x)\) 是逐分量互补 \(G_i(x)H_i(x)=0\)(在 CITO 里 \(G=\phi\)、\(H=\lambda^n\))。
为什么 MPCC 在任何可行点都违反 LICQ(甚至更弱的 MFCQ)? 把互补 \(G_iH_i=0\) 当作等式约束 \(c_i(x)=G_i(x)H_i(x)=0\)。它的梯度是
在任意可行点上,互补意味着 \(G_i,H_i\) 中至少一个为零。
- 若 \(G_i=0,H_i>0\):\(\nabla c_i = H_i\nabla G_i\),方向由 \(\nabla G_i\) 决定;
- 若 \(G_i>0,H_i=0\):\(\nabla c_i = G_i\nabla H_i\);
- 若 \(G_i=H_i=0\)(退化点 / biactive):\(\nabla c_i = 0\) —— 梯度恒为零向量。
退化点上一条约束的梯度是零向量,它必然与其它约束梯度线性相关——LICQ 在此处一定失效。可以进一步证明,即便不在退化点,把 \(G_i\ge 0,H_i\ge 0,G_iH_i=0\) 三条放在一起,它们的积极约束梯度也无法线性独立。结论很强:MPCC 在每一个可行点都不满足 LICQ、MFCQ。这意味着标准 NLP 的 KKT 必要条件理论**根本不能直接套用**。
本质洞察:互补约束的"病"不是数值精度问题,而是**约束品性(constraint qualification)层面的结构性缺陷**。这就是为什么单纯"调小容差""换更好的线性求解器"治标不治本——病根在可行集的几何(两条射线的并,在拐点处无法被光滑约束良好刻画),不在浮点运算。三种数值方法(松弛 / FB / ALM)本质上都是在**重构约束的几何或品性**:松弛把拐点"充气"成有内点的区域从而恢复 MFCQ;FB 把两条射线编码成一条处处梯度非零的曲线;ALM 把约束移进目标函数从而完全绕开约束品性的要求。
MPCC 的专属约束品性:MPEC-LICQ¶
为了挽救理论,学界定义了一个**放宽后**的约束品性——把互补约束"拆开看"。定义 MPCC 的 Tightened NLP(TNLP):在一个可行点 \(x^*\) 处,按 \(G_i,H_i\) 谁为零,把互补约束替换为对应的等式:
- \(\mathcal{I}_G=\{i: G_i(x^*)=0<H_i(x^*)\}\) → 保留 \(G_i(x)=0\);
- \(\mathcal{I}_H=\{i: H_i(x^*)=0<G_i(x^*)\}\) → 保留 \(H_i(x)=0\);
- \(\mathcal{I}_{GH}=\{i: G_i(x^*)=H_i(x^*)=0\}\)(退化集)→ **同时**保留 \(G_i(x)=0\) 与 \(H_i(x)=0\)。
MPEC-LICQ 的定义:如果上述 TNLP 在 \(x^*\) 处满足标准 LICQ,就说原 MPCC 满足 MPEC-LICQ。换句话说,把互补约束"按当前激活情况固定下来"之后,剩下的约束系统梯度线性独立——这是一个**可以被满足**的条件(不像原始 LICQ 必然失效)。CITO 实践中只要退化集 \(\mathcal{I}_{GH}\) 不太"病态",MPEC-LICQ 通常成立。
三级平稳性:W- / C- / M- / S-stationarity¶
在 MPEC-LICQ 下,存在乘子使最优解满足一组替代 KKT 的条件。关键的差别全部落在**退化集 \(\mathcal{I}_{GH}\) 上两个乘子 \(\nu_i^G,\nu_i^H\) 的符号要求**上。由弱到强排成一个谱:
| 平稳性 | 退化集上的乘子条件 | 强度 | 含义 |
|---|---|---|---|
| W-stationary(弱) | 无符号要求 | 最弱 | 只是拉格朗日驻点,可能不是局部极小 |
| C-stationary(Clarke) | \(\nu_i^G \cdot \nu_i^H \ge 0\) | 弱 | 两乘子乘积非负(同号或有零) |
| M-stationary(Mordukhovich) | \(\nu_i^G\nu_i^H=0\) 或(\(\nu_i^G>0\) 且 \(\nu_i^H>0\)) | 中 | 排除了一象限 |
| S-stationary(强) | \(\nu_i^G \ge 0\) 且 \(\nu_i^H \ge 0\) | 最强 | 等价于把 MPCC 当普通 NLP 的 KKT 点 |
S-stationarity 是我们真正想要的——它等价于原问题的 B-稳定(Bouligand)局部极小的一阶条件。但不同数值方法收敛到的平稳性强度不同,这直接决定了解的质量:
| 数值方法(59.3) | 典型收敛到 | 后果 |
|---|---|---|
| 松弛法(\(\epsilon\to 0\),Scholtes 正则化) | C-stationary(一般情形);额外二阶条件下可达 M-/S- | 可能停在 C-平稳但非局部极小的"伪解" |
| Fischer-Burmeister(光滑化) | C-stationary(光滑参数 \(\to 0\)) | 与松弛类似,依赖收敛路径 |
| 增广拉格朗日 / 精确罚 | 适当条件下 M-stationary | 比纯松弛强,排除更多伪解 |
这解释了一个一直困扰你的现象:59.3 末尾的思维陷阱说"松弛法可能收敛到错误局部最优(所有力为零)"。从平稳性理论看,那个"飞起来"的平凡解往往是一个 **C-平稳但非 S-平稳**的点——它满足放宽后的一阶条件,但不是真正的局部极小。这就是为什么需要好的初值、续延策略、二阶充分条件检查来把解"推"向更强的 S-平稳性。
🧠 思维陷阱:以为求解器"收敛了"就等于找到了局部最优
新手想法:"Ipopt 报 'Optimal Solution Found',那一定是局部最优了。"
实际上:对松弛后的 MPCC,求解器报告的"最优"是**松弛问题**的 KKT 点。当 \(\epsilon\to 0\),这串解的极限只保证是**C-平稳**——这是比局部最优弱的条件。C-平稳点可能是鞍点甚至局部极大方向上的驻点。
根因:MPCC 的最优性理论与标准 NLP 不同,"收敛"和"局部最优"之间隔着 W-/C-/M-/S- 四级阶梯。
正确做法:(1) 多初值重启取最优;(2) 检查解处的二阶充分条件(MPEC-SOSC);(3) 优先选 ALM 类方法(更易达 M-平稳);(4) 用物理先验(如重力补偿项)排除平凡 C-平稳解。
工程启示:理论怎样指导调参¶
这套理论不是纯数学游戏,它给出可操作的调试指南:
| 你观察到 | 平稳性解读 | 行动 |
|---|---|---|
| 解收敛但物理上荒谬(飞起来 / 穿地) | 停在了 C-平稳的伪解 | 换 ALM、加物理先验、多初值 |
| 续延 \(\epsilon\to 0\) 时解剧烈跳变 | 退化集 \(\mathcal{I}_{GH}\) 大,MPEC-LICQ 临界 | 减小续延步长、warm-start |
| 不同松弛参数得到本质不同的解 | C-平稳点不唯一 | 报告解时附上 \(\epsilon\) 与多次重启统计 |
练习¶
练习 59.3.5a(⭐⭐⭐):对一维 MPCC \(\min (a-1)^2+(b-1)^2\) s.t. \(0\le a\perp b\ge 0\),几何上求出全局最优解。验证最优点处 \(a,b\) 哪个在退化集 \(\mathcal{I}_{GH}\) 中,并写出该点的 TNLP,检查 MPEC-LICQ 是否成立。
练习 59.3.5b(⭐⭐⭐⭐):构造一个二维 MPCC 的可行点,使其为 C-平稳但不是 S-平稳(提示:让退化集上两个乘子异号)。说明一个只检查"梯度范数 < tol"的求解器为什么会在此点错误停机。
59.4 Posa 2014 IJRR 精读 ⭐⭐⭐¶
动机:CITO 奠基论文为什么重要?¶
本节解决的问题:Posa, Cantu, Tedrake 2014 年发表在 IJRR 的 "A Direct Method for Trajectory Optimization of Rigid Bodies Through Contact" 是 CITO 领域的奠基性工作。理解这篇论文对于理解后续所有 CITO 变体都是必要的。
论文要解决什么问题?
在 Posa 2014 之前,轨迹优化处理接触的标准方法是**先指定接触模式序列,再优化连续轨迹**。例如:
传统方法(已知模式序列):
Phase 1: 双脚支撑 → 优化 NLP_1
Phase 2: 右脚摆动 → 优化 NLP_2
Phase 3: 双脚支撑 → 优化 NLP_3
...
约束: 相邻 phase 的边界状态匹配
问题: 模式序列本身是人类给定的,无法发现新颖接触
Posa 的核心贡献是**消除对模式序列的先验假设**——让一个统一的 NLP 自动决定模式。
它是怎么被发现的? Posa 的导师 Russ Tedrake 一直在 MIT 研究 underactuated robots(欠驱动机器人),这类系统的轨迹优化天然需要处理接触(如被动行走器的脚与地面碰撞)。Tedrake 实验室注意到 Stewart-Trinkle 的 LCP 时间步进公式——用于接触仿真——可以被"反过来用":不是给定状态求接触力,而是把接触力作为待优化变量。这个"反转"的洞察催生了 Posa 2014。
59.4.1 Posa 方法的技术细节 ⭐⭐⭐¶
动力学离散化:半隐式时间步进
Posa 采用 Stewart-Trinkle time-stepping 作为动力学约束。离散化后的接触动力学:
其中 \(\mathbf{B}\) 是控制输入选择矩阵(对于欠驱动系统,\(\mathbf{B}\) 不是方阵),\(\mathbf{c}\) 包含科氏力和重力。
符号约定:此处 \(\lambda_n, \boldsymbol{\lambda}_t\) 为接触**力**(单位 N),整个右侧乘以步长 \(h\) 得到冲量。与 59.2.2 节的冲量约定不同——59.2.2 节直接将 \(\boldsymbol{\lambda}\) 定义为冲量。两种约定在文献中都常见,关键是**检查 \(h\) 是否已被吸收**。
互补约束的松弛处理
Posa 把原始 MPCC(Mathematical Program with Complementarity Constraints)松弛为 NLP:
同时保留: - \(\phi_i(\mathbf{q}_k) \ge 0\)(非穿透) - \(\lambda_{i,k}^n \ge 0\)(法向力非负)
直接配置法(Direct Collocation)
Posa 使用直接配置法(不同于 DDP 的 shooting 方法)。这个方法选择的**原因**至关重要——理解它有助于理解 CITO 的架构设计。
| 方面 | Shooting(DDP) | Direct Collocation(Posa) |
|---|---|---|
| 决策变量 | 只有 \(\mathbf{u}_{0:N-1}\) | \(\mathbf{x}_{0:N}, \mathbf{u}_{0:N-1}, \boldsymbol{\lambda}_{0:N-1}\) |
| 动力学 | 前向积分得到 \(\mathbf{x}_{1:N}\) | 作为等式约束 |
| 优点 | 变量少 | 初值不需要满足动力学,更鲁棒 |
| 缺点 | 初值敏感,混沌系统不稳定 | 变量多,NLP 维度大 |
| 对 CITO 的关键影响 | 接触力无法作为决策变量 | 接触力自然成为决策变量 |
为什么 Direct Collocation 对 CITO 是自然选择? 在 shooting 方法中,给定 \(\mathbf{u}_k\),前向积分会在内部求解 LCP 得到 \(\boldsymbol{\lambda}_k\)——接触力是积分器的"副产品",不是优化的自由度。这意味着优化器无法直接控制接触力,只能通过调整 \(\mathbf{u}_k\) 间接影响接触。而 direct collocation 把 \(\boldsymbol{\lambda}_k\) 从积分器中"提升"为一等决策变量,使优化器可以**直接**优化接触力的大小和时机。
59.4.2 Posa 的关键实验结果 ⭐⭐¶
Posa 论文展示了三个关键实验:
实验 1:2D 弹跳球
| 设置 | 结果 |
|---|---|
| 目标 | 球从地面弹跳到指定高度 |
| 接触模式 | 优化器自动发现"着地 → 弹起 → 飞行"模式 |
| 互补违反 | \(\phi \cdot \lambda < 10^{-4}\) |
| 求解时间 | 约 1 秒 |
实验 2:2D 双足行走
| 设置 | 结果 |
|---|---|
| 目标 | 从静止开始行走 5 步 |
| 自由度 | 5-link planar biped,10 维状态 |
| 接触模式 | 自动发现左右交替步态 |
| 求解时间 | 约 30 秒 |
实验 3:3D 四足运动
| 设置 | 结果 |
|---|---|
| 目标 | 四足前进 2 米 |
| 自由度 | 完整四足模型 |
| 接触模式 | 自动发现 trot 步态 |
| 求解时间 | 数分钟 |
关键发现: 1. 优化器能**自动发现**合理的接触模式,不需要人类指定 2. 发现的模式与直觉一致(双足交替、四足 trot) 3. 求解时间随系统维度**急剧增长**——3D 四足需要数分钟,远离实时 4. 初值敏感——差的初始猜测容易收敛到"所有力为零"的平凡解
59.4.3 论文的局限与后续影响 ⭐⭐¶
Posa 2014 的局限:
| 局限 | 原因 | 后续解决方案 |
|---|---|---|
| 求解慢 | NLP 维度大 + 续延迭代 | Manchester 2019(结构保持),Pang 2023(光滑化) |
| 初值敏感 | 非凸 + 多局部最优 | Mordatch 2012(接触指示器放松),学习初值 |
| 摩擦模型简化 | 只有库仑摩擦,无滚动 | 后续扩展到软接触模型 |
| 不处理碰撞反弹 | 纯非弹性碰撞 | 需要恢复系数建模 |
| 不考虑机器人运动学 | 纯刚体动力学 | Towr 加入运动学约束 |
Posa 2014 的深远影响:
这篇论文建立了 CITO 的**标准数学框架**——后续几乎所有 CITO 工作都是在 Posa 的公式基础上做改进: - Manchester 2019:换积分器(变分积分器) - Mordatch 2012(虽然时间在前):换互补约束处理方式 - Pang 2023:换接触模型(准静态光滑化) - ACAL-iLQR 2024:换求解算法(iLQR + ALM)
🧠 思维陷阱:因为 Posa 2014 求解慢就否定 CITO
新手想法:"CITO 需要几分钟才能解,没有实用价值。"
实际上: 1. 离线规划**不需要实时——花 1 分钟规划一个动作库,MPC 在线选择并跟踪 2. **研究价值:CITO 能验证"理论最优"的接触策略,作为学习方法的训练数据或 baseline 3. 速度在持续改善:从 2014 年的几分钟到 2024 年的约 1 秒(特定系统),10 年加速了约 100 倍 4. 硬件在进步:GPU 并行 + 稀疏求解器加速未来可期
练习¶
练习 59.4a(⭐⭐):解释 Posa 为什么选择 Direct Collocation 而不是 Shooting 方法。如果用 DDP 做 CITO,接触力变量应该放在哪里?
练习 59.4b(⭐⭐⭐):阅读 Posa 2014 论文的 Section III-B(互补约束松弛),回答:为什么 \(\epsilon\) 不能一步到位设为 \(10^{-8}\),而必须从 \(10^{-1}\) 逐步减小?从 NLP 的可行域几何角度解释。
59.5 变分接触隐式优化 ⭐⭐⭐⭐¶
动机:为什么 Posa 的时间步进法不够好?¶
本节解决的问题:Posa 2014 使用 Stewart-Trinkle 时间步进格式,这是一种一阶精度的离散化。Manchester 和 Kuindersma 2019(IJRR)提出的变分 CITO 用**变分积分器**替换时间步进,获得更高精度和更好的结构保持性。为什么这很重要?
时间步进法的精度问题
半隐式欧拉(Posa 使用的)只有一阶精度:\(\mathbf{x}_{k+1} = \mathbf{x}_k + h \mathbf{f}(\mathbf{x}_k) + O(h^2)\)。这意味着:
- 时间步长 \(h = 0.01\) s 时,每步误差 \(O(10^{-4})\)
- \(N = 100\) 步后累积误差 \(O(10^{-2})\)——可能导致轨迹漂移
能不能用高阶积分器(如 RK4)? 不能直接用。原因是接触力在碰撞瞬间是**冲量**(Dirac delta 函数),不满足 RK4 要求的"被积函数连续"前提。RK4 在每个时间步内部有 4 个评估点(\(k_1, k_2, k_3, k_4\)),如果碰撞发生在两个评估点之间,RK4 无法正确处理速度的不连续跳变。
变分积分器提供了第三条路:不需要对力显式积分,而是从**离散化的 Hamilton 原理**出发,自动得到高精度、能量守恒的离散方程。
59.5.1 变分原理回顾 ⭐⭐⭐¶
Hamilton 原理(最小作用量原理):物理系统的真实运动使作用量取极值:
其中 \(L = T - V\) 是拉格朗日量(动能减势能)。
这个原理为什么对计算有用? 传统方法是先从 Hamilton 原理推导出 Euler-Lagrange 方程(连续 ODE),然后用数值方法离散化 ODE。但离散化过程中可能破坏物理系统的结构(能量守恒、辛结构)。变分积分器的思想是**颠倒顺序**:先离散化作用量积分,再对离散化后的作用量取变分——得到的离散方程自动保持物理结构。
变分积分器的思想:
传统方法:
连续 Hamilton 原理 → 连续 Euler-Lagrange 方程 → 离散化(可能破坏结构)
变分积分器:
连续 Hamilton 原理 → 离散 Hamilton 原理 → 离散 Euler-Lagrange 方程
↑ 自动保持结构!
离散 Lagrangian:
最简单的近似(梯形规则):
离散 Euler-Lagrange 方程:对离散作用量 \(S_d = \sum_k L_d(\mathbf{q}_k, \mathbf{q}_{k+1})\) 取变分 \(\delta S_d / \delta \mathbf{q}_k = 0\),得到:
其中 \(D_1, D_2\) 是对第一、第二个参数的偏导数,\(\mathbf{f}_k^{\pm}\) 是离散外力(包括控制力和接触力)。
59.5.2 Manchester 2019 的关键创新 ⭐⭐⭐⭐¶
Manchester 和 Kuindersma 的论文全称是 "Contact-Implicit Trajectory Optimization Using Variational Integrators"(IJRR 2019,内容基于 ISRR 2017 报告)。
创新 1:二阶精度的接触离散化
通过使用梯形规则的离散 Lagrangian,Manchester 获得了二阶精度的时间步进——比 Posa 的一阶半隐式欧拉高一个数量级。关键是**接触力的离散化方式**:
接触力在每个时间步的开头和结尾分别有一个分量(\(\lambda^+\) 和 \(\lambda^-\)),这提供了更精确的冲量分配。为什么这比 Posa 的方法好?因为一阶方法在每个时间步只有一个接触力变量(相当于把力集中在时间步的中点),而梯形规则在两端各有一个,等价于对力做线性插值——精度自然提升。
创新 2:辛结构保持
变分积分器自动保持**辛结构**(symplecticity)——这意味着离散系统的相空间体积守恒。
什么是辛结构?为什么重要?
在 Hamiltonian 力学中,系统的演化保持辛形式 \(\omega = \sum_i dp_i \wedge dq_i\)(相空间中的"面积元素")。这意味着: - 能量误差有界(不会单调增长或衰减) - 轨迹不会发散到非物理区域 - 长时间仿真的定性行为正确
非辛积分器(如显式欧拉)在长时间仿真中能量会系统性漂移——对 CITO 来说,这意味着优化器可能利用"数值泄漏"的能量产生非物理轨迹(如弹跳球越弹越高)。辛积分器从根本上避免了这个问题。
创新 3:与 Stewart-Trinkle 的理论联系
Manchester 证明了他的二阶变分积分器在特定参数选择下**退化为** Stewart-Trinkle 的一阶时间步进。这意味着 Posa 2014 的方法是 Manchester 方法的一个特例——建立了优雅的理论统一。
59.5.3 变分 CITO 的实验验证 ⭐⭐⭐¶
Manchester 论文的关键实验:
实验:四足微型机器人(Harvard HAMR)
| 方面 | 一阶时间步进(Posa) | 二阶变分积分器(Manchester) |
|---|---|---|
| 精度 | \(O(h)\) | \(O(h^2)\) |
| 同等精度所需步数 | \(N = 200\) | \(N = 50\) |
| 求解时间 | 约 120 s | 约 30 s |
| 能量误差 | 累积增长 | 有界振荡 |
关键结论:二阶精度使得可以用**更少的时间步**达到同等精度,NLP 维度更低,求解更快。在 HAMR 微型机器人上,优化出的轨迹直接在实物上运行,验证了方法的实用性。
⚠️ 编程陷阱:变分积分器中的位形更新
错误做法:对于 SO(3) 上的旋转,用 \(\mathbf{q}_{k+1} = \mathbf{q}_k + h\dot{\mathbf{q}}_k\) 更新四元数。
症状:四元数范数不是 1,旋转矩阵不正交,仿真发散。
根因:SO(3) 不是向量空间,加法不封闭。\(\mathbf{q} + \delta\) 可能不再是单位四元数。变分积分器中必须用**指数映射更新**:\(\mathbf{q}_{k+1} = \mathbf{q}_k \otimes \exp(\frac{h}{2}\boldsymbol{\omega}_k)\),其中 \(\otimes\) 是四元数乘法。
正确做法:使用 Lie 群积分器(足式/50_空间向量与浮动基座动力学 的知识),把变分积分器推广到 SE(3)。Manchester 的实现中用了 Cayley 映射作为替代(计算更快,精度略低)。
💡 概念误区:变分积分器"总是"比普通积分器好
新手想法:"变分积分器既高精度又保结构,为什么不总是用它?"
实际上:变分积分器有两个代价:(1) 隐式格式需要在每步解非线性方程(半隐式欧拉不需要);(2) 实现复杂度更高(需要推导离散 Lagrangian 的梯度和 Hessian)。对于短时域问题(MPC 的 0.5 秒窗口),一阶精度通常足够——用变分积分器是"杀鸡用牛刀"。变分积分器的优势在**长时域**规划(如 10 秒的步态优化)中才充分体现。
练习¶
练习 59.5a(⭐⭐⭐):对于一维自由落体 \(L = \frac{1}{2}m\dot{q}^2 - mgq\),用梯形规则写出离散 Lagrangian \(L_d(q_k, q_{k+1})\),然后推导离散 Euler-Lagrange 方程。验证它与半隐式欧拉一致。
练习 59.5b(⭐⭐⭐⭐):解释为什么变分积分器是辛的。提示:从离散 Legendre 变换出发,定义离散动量 \(p_k^+ = D_2 L_d(q_k, q_{k+1})\), \(p_{k+1}^- = -D_1 L_d(q_k, q_{k+1})\),说明离散流映射 \((q_k, p_k^+) \mapsto (q_{k+1}, p_{k+1}^-)\) 保持辛形式 \(dp \wedge dq\)。
59.6 质心轨迹优化与接触规划 ⭐⭐⭐¶
动机:全身 CITO 太慢,有没有折中?¶
本节解决的问题:Posa/Manchester 的全身 CITO(状态维度约 40)求解太慢,不适合在线使用。质心轨迹优化(Centroidal Trajectory Optimization)用 6 维质心动力学代替全身动力学,大幅降维,同时保留接触规划能力。
从全身到质心:降维的代价与收益
| 方面 | 全身 CITO | 质心轨迹优化 |
|---|---|---|
| 状态维度 | 约 40(浮动基座 + 12 关节) | 约 12(CoM 位置、速度、角动量) |
| 接触力维度 | \(3 n_c\)(每接触点 3 维) | \(3 n_c\)(相同) |
| NLP 总维度(N=50) | 约 3000 | 约 900 |
| 求解时间 | 分钟级 | 秒级 |
| 物理忠实度 | 高(全身约束) | 中(忽略运动学限制) |
| 可行性保证 | 全身可行 | 可能运动学不可行 |
这个降维是怎么来的? 全身动力学方程 \(\mathbf{M}\ddot{\mathbf{q}} + \mathbf{c} = \boldsymbol{\tau} + \mathbf{J}_c^T \boldsymbol{\lambda}\) 有 \(n_q\) 个方程(约 18 维)。质心动力学只保留其中 6 维——线动量和角动量的变化率。这等价于把关节角度"积掉"(边缘化),只关注 CoM 的运动。代价是丢失了关节层面的信息——优化出的质心轨迹可能因为运动学约束(腿长有限、关节限位)而不可执行。
质心动力学回顾:足式/80_接触力学与约束优化 从 Newton-Euler 方程出发,将全身多体动力学投影到质心空间,得到了质心动量方程——外力(接触力 + 重力)的合力和合力矩等于质心动量的变化率。这个方程的关键价值在于它只有 6 维(3 维线动量 + 3 维角动量),却完整捕获了整个多体系统的宏观运动。在 足式/80_接触力学与约束优化 中我们用它分析了接触力如何维持平衡;这里我们用同样的方程,但目标变为**同时优化接触力和接触位置**:
其中 \(\mathbf{c}\) 是 CoM 位置,\(\mathbf{p}_i\) 是第 \(i\) 个接触点位置,\(\mathbf{f}_i\) 是接触力,\(\mathbf{k}\) 是角动量,\(\mathbf{l}\) 是线动量。
59.6.1 质心+接触协同优化的 NLP 公式 ⭐⭐⭐¶
决策变量:
其中 \(\mathbf{p}_i\) 是足端位置(也是决策变量),\(\mathbf{f}_i\) 是接触力。
约束:
非线性项:角动量方程中的 \((\mathbf{p}_i - \mathbf{c}) \times \mathbf{f}_i\) 是**双线性**的(两个决策变量的乘积),使问题非凸。这比 LIPM(足式/70_腿足简化模型理论)多了角动量维度,但比全身动力学少了关节维度。
59.6.2 接触时序的连续松弛 ⭐⭐⭐¶
在质心优化中,可以用 Mordatch 2012 的**接触指示器**来处理接触时序:
引入连续变量 \(c_{i,k} \in [0, 1]\): - \(c_{i,k} = 1\):第 \(i\) 条腿在时间步 \(k\) 支撑 - \(c_{i,k} = 0\):第 \(i\) 条腿在时间步 \(k\) 摆动 - \(c_{i,k} \in (0, 1)\):过渡状态
约束修改为:
这个方法是怎么被想到的? Mordatch 2012 的洞察来自计算机图形学——在动画中,人物的运动是连续生成的,角色的手脚是否接触环境是一个"创作决策"。Mordatch 把这个创作决策编码为连续变量 \(c \in [0, 1]\),让优化器"渐变"地决定接触——从"轻微触碰"(\(c \approx 0\)) 过渡到"完全支撑"(\(c = 1\))。
优势:不需要预定义步态——优化器自动决定每条腿何时支撑、何时摆动。Mordatch 2012 用这个方法在 SIGGRAPH 中展示了仿真人物自动发现爬行、站立、倒立等复杂动作。
劣势:\(c_{i,k}\) 可能停留在 0.5 附近("半接触"),物理上无意义。需要后处理舍入,或加惩罚项鼓励 \(c_{i,k}\) 趋向 0 或 1:
这个惩罚项在 \(c = 0\) 或 \(c = 1\) 时为零,在 \(c = 0.5\) 时最大。
59.6.3 代表工作:分阶段方法 ⭐⭐¶
许多实用工作将质心轨迹优化和接触序列规划分成两阶段:
阶段 1: MIQP
─────────────
输入: 环境地图 (stepping stones)
决策: 每步踩哪个 stone (离散), 步序
输出: 接触序列 + 粗略 CoM 轨迹
阶段 2: NLP
─────────────
输入: 阶段 1 的接触序列
决策: CoM 轨迹细化, 接触力
输出: 可执行的质心轨迹
→ MIQP 解决组合问题 (秒级)
→ NLP 解决连续优化 (秒级)
→ 总共约 10 秒,比全身 CITO 快 10-100 倍
这种分阶段方法是工程中最常用的——ANYmal parkour 的规划层就采用类似架构。
⚠️ 编程陷阱:角动量方程中的叉积方向
错误做法:写成 \(\dot{\mathbf{k}} = \sum_i \mathbf{f}_i \times (\mathbf{p}_i - \mathbf{c})\)(力叉乘力臂)。
症状:角动量符号相反,机器人旋转方向错误。
根因:力矩 = 力臂 \(\times\) 力,即 \(\boldsymbol{\tau} = \mathbf{r} \times \mathbf{f}\),不是 \(\mathbf{f} \times \mathbf{r}\)。叉积不满足交换律:\(\mathbf{a} \times \mathbf{b} = -\mathbf{b} \times \mathbf{a}\)。
正确做法:\(\dot{\mathbf{k}} = \sum_i (\mathbf{p}_i - \mathbf{c}) \times \mathbf{f}_i\)。
练习¶
练习 59.6a(⭐⭐):写出四足机器人质心轨迹优化的完整 NLP 公式(不用互补约束,假设步态时序已知)。计算 \(N = 30\) 时的总决策变量数,与全身 CITO 比较。
练习 59.6b(⭐⭐⭐):角动量方程中的双线性项 \((\mathbf{p}_i - \mathbf{c}) \times \mathbf{f}_i\) 使问题非凸。提出一种线性化策略(如 SQP),说明如何在每次 SQP 迭代中处理这个项。提示:把 \(\mathbf{p}_i, \mathbf{c}, \mathbf{f}_i\) 分别在当前迭代点展开。
59.7 双层优化视角 ⭐⭐⭐⭐¶
动机:CITO 为什么收敛困难?¶
本节解决的问题:单一 NLP 同时优化离散决策(接触序列)和连续轨迹,这是一个混合整数非线性规划(MINLP)——NP-hard。双层优化把问题分解为上层(接触序列)和下层(轨迹优化),降低单层问题的难度。
CITO 作为单层 NLP 的困境:
单层 CITO:
min J(x, u, lambda)
s.t. 动力学 + 互补约束 + 摩擦锥
问题 1: 互补约束使可行域非凸 → 很多局部最优
问题 2: 接触模式改变 = 拓扑变化 → 梯度信息无法跨模式传递
问题 3: 初值必须"猜对"接触模式 → 几乎不可能
为什么拓扑变化导致梯度失效? 考虑一个简单例子:从"两脚支撑"变为"一脚支撑"。这个变化是**离散**的——不存在"1.5 脚支撑"。NLP 的梯度是连续变化的,它无法"跳过"模式切换。结果是:如果初值在"两脚支撑"模式中,梯度下降只会在这个模式内优化,永远无法发现"单脚跳"可能是更优策略。
59.7.1 双层优化的数学公式 ⭐⭐⭐⭐¶
其中 \(\sigma\) 是接触序列(哪条腿在什么时候接触),\(\Sigma\) 是所有可能的接触序列集合,\(J^*(\sigma)\) 是给定接触序列下的最优代价。
物理直觉:上层像"教练"决定战术(步态和落脚策略),下层像"运动员"在给定战术下发挥最优表现。整个双层结构好比餐厅运营——经理(上层)决定菜单上有哪些菜品(接触序列),厨师(下层)在给定菜单下把每道菜做到最好(轨迹优化)。经理不需要知道每道菜的烹饪细节,厨师也不需要操心菜品组合是否合理——分工使两边的问题都变简单了。
为什么双层比单层好?
| 方面 | 单层 CITO | 双层优化 |
|---|---|---|
| 上层问题 | 不存在 | MIQP(组合但凸) |
| 下层问题 | NLP + 互补约束(非凸、LICQ 失效) | NLP(无互补约束,标准) |
| 初值敏感性 | 极高 | 上层不敏感,下层温和 |
| 可保证性 | 局部最优 | 上层全局最优(MIQP),下层局部最优 |
59.7.2 上层:MIQP 接触序列优化 ⭐⭐⭐¶
MIQP 公式
对于 stepping stones 场景,上层可以用 MIQP:
Big-M 方法详解:
Big-M 方法是混合整数规划中编码"选择性约束"的标准技巧。核心思想:用一个大常数 \(M\) 使得当对应的二值变量为 0 时,约束被"打开"(自动满足)。
推导:第 \(i\) 步的落脚点 \(\mathbf{p}_{f,i}\) 必须在所选石头 \(j\) 的内部。石头 \(j\) 定义为凸多边形 \(\{\mathbf{x}: \mathbf{A}_j \mathbf{x} \le \mathbf{b}_j\}\)。
- 当 \(z_{i,j} = 1\)(踩石头 \(j\)):\(\mathbf{A}_j \mathbf{p}_{f,i} \le \mathbf{b}_j + M \cdot 0 = \mathbf{b}_j\) → 约束生效
- 当 \(z_{i,j} = 0\)(不踩石头 \(j\)):\(\mathbf{A}_j \mathbf{p}_{f,i} \le \mathbf{b}_j + M\) → 约束自动满足(\(M\) 足够大)
\(M\) 的选择是一门"调参艺术": - \(M\) 太大 → LP 松弛变弱,branch-and-bound 需要更多节点,求解变慢 - \(M\) 太小 → 可行域被错误截断,可能排除最优解 - 经验法则:\(M = 10 \times \max(\|\mathbf{b}_j\|)\) - 更好的方法:用 indicator constraints(Gurobi 支持),完全避免 Big-M
MIQP 求解器:
| 求解器 | 类型 | 许可证 | 典型性能 |
|---|---|---|---|
| Gurobi | 商业 | 免费学术 | 最快,支持 indicator constraints |
| CPLEX | 商业(IBM) | 免费学术 | 接近 Gurobi |
| SCIP | 开源 | ZIB | 比商业慢 2-5x |
| HiGHS | 开源 | MIT | 持续改进中,LP 部分已很强 |
59.7.3 下层:给定接触序列的轨迹优化 ⭐⭐⭐¶
给定上层输出的接触序列 \(\sigma\),下层就是 足式/100_DDP家族与Crocoddyl-55 的标准轨迹优化——DDP/SQP/FDDP,不需要互补约束。
上层输出(接触序列 sigma):
腿 RF: 支撑 [0, 0.3s], 摆动 [0.3, 0.5s], 支撑 [0.5, 0.8s]
腿 LF: 摆动 [0, 0.2s], 支撑 [0.2, 0.6s], 摆动 [0.6, 0.8s]
...
落脚点: RF→石2, LF→石3, ...
下层 NLP:
min Sigma l(x_k, u_k)
s.t. 动力学
摩擦锥(仅在支撑相)
足端位置 = 指定落脚点(仅在支撑相)
运动学约束
→ 标准 TO,足式/100_DDP家族与Crocoddyl 的 DDP 或 足式/110_OCS2完整栈与双线程MPC 的 SQP 可解
59.7.4 上下层的耦合与迭代 ⭐⭐⭐⭐¶
上下层并非完全独立——上层选的接触序列可能在下层不可行(运动学不可达、动力学不足)。需要**迭代**:
Algorithm: Bilevel Contact Planning
────────────────────────────────────
1. 上层: 求解 MIQP → 接触序列 sigma_1
2. 下层: 求解 NLP(sigma_1) → 最优轨迹 or 不可行
3. if 不可行:
添加不可行性反馈 (cuts) 到上层
回到 1
4. if 可行但代价不满意:
修改上层目标 (warm start with J*)
回到 1
5. 收敛 → 输出最终轨迹
Benders 分解的思想:每次下层失败,告诉上层"这种接触序列不行"(添加 Benders cut),上层在缩小的可行域中重新选择。理论上有限步收敛(因为 \(\Sigma\) 是有限集)。
什么是 Benders cut? 假设下层在接触序列 \(\sigma_1\) 下不可行,我们添加一个线性约束到上层:\(\sum_{(i,j) \in \sigma_1} z_{i,j} \le |\sigma_1| - 1\)。这个约束排除了 \(\sigma_1\)(因为 \(\sigma_1\) 需要所有对应的 \(z_{i,j} = 1\),但约束要求至少有一个为 0)。更精细的 cut 可以只排除导致不可行的"子集"——这需要分析下层不可行的原因(哪个约束被违反)。
59.7.5 2024 前沿:双层优化的实时化 ⭐⭐⭐¶
2024 年的研究(Aydinoglu et al.)提出了将双层优化实时化的方法:
- 上层用轻量级 MIP 求解器(warm-started),利用上一时刻的接触序列作为初值
- 下层用 iLQR(单次迭代,利用上一时刻的解)
- 总计约 50 ms/cycle,接近实时
这标志着双层优化从纯离线方法向在线方法的转变。关键技术是**极致的 warm-starting**——在上下两层都利用时间连续性。
💡 概念误区:双层优化就是"两次优化"
新手想法:"先解上层,再解下层,一共两次就行。"
实际上:双层优化需要**迭代**——上层的选择可能在下层不可行,需要反馈修正。而且上层的目标函数 \(J^*(\sigma)\) 是下层最优值函数——这个函数通常没有解析表达式,只能通过求解下层来评估。每评估一次 \(J^*\) 就需要解一个完整的 NLP。
计算代价:如果上层有 \(K\) 种接触序列候选,每种需要解一个下层 NLP(约 1 秒),那么最坏情况需要 \(K\) 秒。这就是为什么上层的搜索空间缩减(剪枝、warm-start、可行性预筛选)非常重要。
练习¶
练习 59.7a(⭐⭐):对于一个有 5 块 stepping stones、3 步 horizon 的 MIQP,计算二值决策变量的数量和可能的组合数。如果 MIQP 求解每个组合需要 1 ms,穷举需要多久?
练习 59.7b(⭐⭐⭐):解释 Big-M 方法中 \(M\) 的值如何影响 MIQP 的 LP 松弛质量。为什么 \(M\) 太大会导致 branch-and-bound 效率下降?提示:LP 松弛的可行域如何随 \(M\) 变化?
练习 59.7c(⭐⭐⭐⭐):设计一个简单的 Benders cut:假设下层在接触序列 \(\sigma_1 = \{(\text{RF}, \text{石}2), (\text{LF}, \text{石}4)\}\) 下不可行,构造一个线性不等式添加到上层 MIQP,排除 \(\sigma_1\)。
59.7.6 凸优化图(GCS):接触规划的第三种范式 ⭐⭐⭐⭐¶
本节解决的问题:59.7 的双层优化把"离散接触序列 + 连续轨迹"拆成两层迭代求解,但上下层耦合(Benders cut、warm-start)实现复杂,且 MIQP 与下层 NLP 各自仍可能陷入次优。2022 年以来 Marcucci、Tedrake 等人提出的 Graph of Convex Sets(GCS,凸集图) 提供了第三种范式:把"选哪个接触模式"和"在该模式下怎么动"统一编码为一张图上的最短路径问题,再用一个**紧凸松弛**一次性求解——既不枚举模式,也不做双层迭代。这是 2024–2025 接触规划最受关注的方向之一,也填补了本章开放方向里"GCS + 腿足"留下的空白。
动机:MIQP 与 CITO 各自的"原罪"¶
回顾本章两条主线各自的根本困难:
| 范式 | 根本困难 |
|---|---|
| CITO(59.2–59.5) | 互补约束使**单个连续问题非凸**,对初值极度敏感,只能保证局部最优 |
| 双层 MIQP(59.7) | 上层是组合问题(指数多模式),Big-M 松弛松,上下层耦合需迭代 |
有没有一种表述,既不在连续空间里被非凸性折磨,又不在离散空间里组合爆炸? GCS 的回答是:把问题搬到一个**图**上——离散结构由图的拓扑承载,连续优化由每个顶点上的凸集承载,二者在"最短路径"这一个问题里自然耦合。
GCS 的核心构造¶
一张凸集图 \(\mathcal{G}=(\mathcal{V},\mathcal{E})\) 由三件东西定义:
- 顶点 \(v\in\mathcal{V}\):每个顶点配一个**凸集** \(\mathcal{X}_v\subseteq\mathbb{R}^n\),以及一个定义在其上的连续变量 \(x_v\in\mathcal{X}_v\)。在接触规划里,一个顶点 = 一个固定接触模式(如"左脚支撑右脚摆"),凸集 \(\mathcal{X}_v\) 描述该模式下的**准静态动力学可行域**(物体位姿、接触点、接触力的可行组合)。
- 边 \(e=(u,v)\in\mathcal{E}\):每条边配一个**凸的边代价** \(\ell_e(x_u,x_v)\) 和凸的边约束。边表示"接触模式 \(u\) 可以切换到模式 \(v\)",连续性约束(切换瞬间状态匹配)写成边约束。
- 源点 \(s\)、汇点 \(t\):起始模式与目标模式。
关键洞察:从 \(s\) 到 \(t\) 的一条**路径**就对应一个**接触模式序列** \(\sigma\);路径上每个顶点的连续变量 \(x_v\) 就是该模式段内的轨迹。于是
左边是 59.7 的双层结构,右边是 GCS——把上层的离散选择和下层的连续优化压进同一个数学对象。
为什么 GCS 能高效求解:紧凸松弛¶
朴素地看,"在图上找最短路径**且**优化路径上的连续变量"仍是一个混合整数凸规划(MICP)——给每条边一个二值变量 \(y_e\in\{0,1\}\) 表示是否走这条边。GCS 的突破在于它的 MICP 表述有一个**异常紧的凸松弛**:
- 把二值 \(y_e\in\{0,1\}\) 松弛为 \(y_e\in[0,1]\);
- 用**透视函数(perspective function)**重写每条边的代价与约束——透视运算 \(\tilde\ell_e(x,y)=y\,\ell_e(x/y)\) 保持凸性,且在 \(y\in\{0,1\}\) 处恢复原问题;
- 加上流守恒约束(进每个顶点的流 = 出的流)。
结果:松弛后的凸问题(通常是 SOCP 或 SDP)的最优值与原 MICP 极其接近——实验中常常在全局最优的几个百分点以内,且松弛解可以被**快速舍入**(rounding)为一条可行路径。这与 59.7 的 Big-M MIQP 形成鲜明对比:Big-M 的 LP 松弛往往很松(间隙大),GCS 的透视松弛则很紧。
本质洞察:GCS 的威力来自一个表述层面的选择——用透视函数而非 Big-M 来编码"开关"约束。Big-M 用一个大常数把约束"撑开",松弛后可行域被严重放大;透视函数则让连续变量的尺度随二值变量"成比例收缩",松弛后的可行域紧贴整数可行域的凸包。这再次印证本章反复出现的主题:接触规划的难易,极大程度上取决于你如何把离散决策编码进连续优化——同一个组合结构,Big-M、互补约束、透视函数给出难度迥异的松弛。
应用到接触规划:Graesdal–Marcucci–Tedrake 2024¶
Graesdal 等人在 RSS 2024 的 "Towards Tight Convex Relaxations for Contact-Rich Manipulation"(arXiv:2402.10312)把 GCS 用于**接触丰富的操作**(以平面推物 planar pushing 为例),其构造对足式接触规划有直接借鉴意义:
| GCS 要素 | 在接触规划中的实例化 |
|---|---|
| 顶点(接触模式) | 物体与机械手/地面的一组接触激活组合(哪些面接触、黏滞还是滑动) |
| 顶点上的凸集 | 该模式下**准静态动力学**的可行域——位姿、接触位置、接触力同时满足力平衡 |
| 非凸 → 凸 | 同时优化位姿、接触位置、接触力时出现的**双线性项**(力 \(\times\) 力臂,正是 59.6.1 角动量方程里的非凸源)用 **SDP 松弛**为凸 |
| 边(模式切换) | 接触的建立 / 断开 / 黏滑转换 |
| 求解 | 最短路径凸松弛 + 舍入,无需初值,常达全局最优的小百分比内 |
与双层方法(59.7)的对比:
| 维度 | 双层 MIQP+NLP(59.7) | GCS |
|---|---|---|
| 离散与连续 | 分两层,需迭代耦合 | 单层,图上统一 |
| 凸松弛紧度 | Big-M,间隙大 | 透视/SDP,间隙小 |
| 初值依赖 | 下层 NLP 依赖初值 | 无需初值 |
| 全局性 | 上层全局、下层局部 | 松弛 + 舍入,接近全局 |
| 成熟度 | 工程成熟(ANYmal parkour) | 新兴(2022–2025),腿足应用刚起步 |
| 主要代价 | 迭代次数 | SDP 规模随模式数增长,大问题仍吃力 |
局限与开放问题¶
GCS 不是银弹。当前主要瓶颈:
- 模式数爆炸进入图规模:双层方法的组合爆炸在 GCS 里转化为**图的顶点数**,足式 4 腿 \(\times\) 多接触面时图很大,SDP 求解成本高;
- SDP 可扩展性:半定松弛对大问题(高维、长时域)求解慢,目前更适合**操作**(低自由度物体)而非**全身足式**;
- 动态接触:现有 GCS 接触工作多基于**准静态**假设(忽略惯性),把它推广到含完整动力学的动态足式运动是活跃的开放问题。
💡 概念误区:GCS 让 CITO/MIQP 都过时了
新手想法:"GCS 又凸又全局又不要初值,那 CITO 和双层 MIQP 不就被淘汰了?"
实际上:GCS 目前主要在**准静态、低自由度操作**任务上验证了优势。对**高维动态全身足式**运动,SDP 松弛的规模与求解时间还不实用——这正是 CITO(处理完整动力学)和双层 MIQP(工程成熟、实时化版本已上机器人)仍是主力的原因。
正确理解:GCS 是接触规划工具箱里的**第三件工具**,与 CITO、双层优化**互补**。它在"需要全局最优、无好初值、问题维度中等"的场景(很多操作任务、部分 stepping-stone 落脚规划)最有价值。
练习¶
练习 59.7.6a(⭐⭐⭐):对 stepping stones 落脚规划(5 块石头、3 步),把它建模为一个 GCS:说明顶点(接触模式)、凸集(每块石头的凸多边形 + 落脚点变量)、边(相邻两步的连接 + 步长约束)分别是什么。与 59.7.2 的 Big-M MIQP 表述对比,指出二者编码"选哪块石头"的方式差异。
练习 59.7.6b(⭐⭐⭐⭐):透视函数 \(\tilde\ell(x,y)=y\,\ell(x/y)\)(\(y>0\))对凸 \(\ell\) 保持凸性。以 \(\ell(x)=x^2\) 为例写出 \(\tilde\ell(x,y)\),验证它在 \(\{(x,y):y>0\}\) 上凸,并说明 \(y\in\{0,1\}\) 时它如何恢复原代价(含 \(y=0\) 的极限行为)。解释为什么这比 Big-M 给出更紧的松弛。
59.8 学习驱动的接触规划 ⭐⭐⭐¶
动机:优化太慢,学习能帮忙吗?¶
本节解决的问题:CITO 和双层优化在求解速度上都有局限。能否用机器学习方法(RL、模仿学习、扩散模型)来加速甚至替代基于优化的接触规划?
59.8.1 RL 用于接触时序决策 ⭐⭐⭐¶
核心思想:训练一个神经网络策略 \(\pi_\theta(\text{接触决策} \mid \text{状态, 地形})\),直接输出接触时序和落脚点。
为什么 RL 适合接触规划? 接触规划的本质是一个**序贯决策问题**——每一步的落脚选择影响后续所有步。这恰好是 RL(马尔可夫决策过程)的建模对象。而且接触切换是离散的——RL 天然处理离散动作空间(如 DQN)或混合动作空间(如 SAC-Hybrid)。
形式化为 MDP:
| MDP 元素 | 定义 |
|---|---|
| 状态 \(s\) | 机器人状态(CoM 位置/速度/朝向 + 关节角度) + 地形高度图(局部 \(1 \times 1\) m 网格) |
| 动作 \(a\) | 下一步的落脚点偏移 \(\Delta\mathbf{p}_f \in \mathbb{R}^2\) + 接触时长 \(\Delta t \in [0.1, 1.0]\) |
| 奖励 \(r\) | 前进距离 \(- 0.01 \times\) 能耗 \(- 100 \times\) 摔倒惩罚 |
| 环境 | MuJoCo / Isaac Gym 物理仿真器 |
代表工作:
-
ContactNet(Melon & Hutter, 2022, RA-L):用 GNN(Graph Neural Network)预测可行的接触序列,比 MIQP 快 100 倍。GNN 的输入是 stepping stones 的图结构,输出是每步的石头选择概率。
-
DiffuseLoco(2024):扩散策略生成多样的运动轨迹,包含隐式的接触规划——不直接输出"踩哪里",而是生成完整的运动轨迹,接触信息隐含在轨迹中。
-
Parkour with RL(Zhuang et al., 2023, RSS):端到端 RL 学习 parkour,自动发现跳跃、攀爬等接触策略。在 Unitree Go1 上实物部署。
RL vs CITO 的互补性:
| 维度 | CITO | RL |
|---|---|---|
| 需要模型 | 是(精确动力学) | 否(model-free)或粗略模型 |
| 可解释性 | 高(KKT 条件) | 低(神经网络黑盒) |
| 单实例效率 | 一次求解(秒~分钟) | 需数百万仿真训练(小时~天) |
| 推理速度 | 慢(NLP 在线求解) | 快(神经网络前向约 1 ms) |
| 泛化 | 弱(per-instance) | 强(训练后对新地形泛化) |
| 最优性 | 局部最优保证 | 无保证 |
| 处理高维 | 难(>50 维吃力) | 易(百维可训练) |
59.8.2 CITO + 学习的融合策略 ⭐⭐⭐¶
策略 1:CITO 生成训练数据 → 模仿学习
离线阶段:
for 1000 种地形:
sigma*, x*, u* ← CITO.solve(地形) // 每个约 10 秒
→ 得到 10000 条 (地形, 最优轨迹) 对
在线阶段:
pi_theta(a | s) ← 训练策略网络模仿 CITO 的最优决策
→ 在线推理约 1 ms,接近 CITO 质量
代表工作:MPC-Net(Carius et al., ICRA 2020)用这个思路学习 MPC 的最优策略。
策略 2:学习 warm-start → CITO 精化
在线:
z0 ← pi_theta(state, terrain) // 学习的初值猜测, 约 1 ms
z* ← CITO.solve(z0) // 从好初值出发, 1-3 次迭代, 约 100 ms
→ 总计约 100 ms,比冷启动 CITO 快 10-100 倍
为什么 warm-start 能加速这么多? NLP 求解器(Ipopt、iLQR)的收敛速度取决于初值距离最优解的远近。Newton 法在最优解附近有二次收敛速度——也就是说,如果初值误差为 \(\delta\),经过 \(k\) 次迭代后误差为 \(O(\delta^{2^k})\)。从 \(\delta = 0.1\)(好初值)出发,3 次迭代误差降到 \(10^{-8}\);从 \(\delta = 10\)(坏初值)出发,需要 20+ 次迭代。
策略 3:分层——RL 高层 + 优化低层
RL 策略 (10 Hz):
输出: 步态选择, 粗略落脚点, 接触时长
→ 替代 MIQP 的上层
MPC (50 Hz):
输入: RL 给定的接触序列
优化: 连续轨迹 (DDP/SQP)
→ 替代 NLP 的下层
WBC (500 Hz):
输出: 关节力矩
这是目前工业界和学术界最热门的架构——ETH 的 ANYmal parkour、MIT 的 Cheetah 3、Unitree 的 Go2 都在探索这条路线。
59.8.3 扩散模型在接触规划中的应用(2024-2025 前沿) ⭐⭐⭐⭐¶
**扩散模型(Diffusion Models)**在机器人学中的应用正在迅速扩展。对于接触规划,扩散模型有两个关键优势:
- 多模态输出:stepping stones 问题可能有多条可行路径,扩散模型可以生成**多样化**的接触计划——而 RL 策略通常只输出一个(mode-seeking)
- 条件生成:可以条件在地形、目标、约束上生成——类似于"画一条满足物理约束的轨迹"
DIAL-MPC(Diffusion-Inspired Annealing for Legged MPC, 2024):
将扩散过程的"去噪"思想融入 MPC 的求解过程: - 初始:在策略空间中随机采样(高噪声)→ 覆盖多个接触模式 - 逐步去噪:每步根据代价函数梯度修正采样 → 集中到好的模式 - 最终:收敛到高质量的轨迹
这种方法在全局搜索(找到正确的接触模式)和局部精化(在该模式下优化轨迹)之间取得了良好平衡——解决了传统 MPC 容易陷入局部最优的问题。
开放问题:
| 问题 | 难度 | 当前状态 |
|---|---|---|
| 约束满足 | 高 | 扩散模型不保证物理约束,需后处理或投影 |
| 实时性 | 中 | 当前约 100 ms/sample,需降至约 10 ms |
| 安全性 | 高 | 无理论保证,需要 safety filter |
| 与 MPC 的集成 | 中 | DIAL-MPC 是初步尝试 |
🧠 思维陷阱:认为 RL 可以完全替代 CITO
新手想法:"RL 训练好后推理只需 1 ms,比 CITO 快几千倍,为什么还需要 CITO?"
实际上: 1. RL 训练数据从哪来? 如果没有 CITO 提供高质量 demonstration,纯 RL 需要更多探索(reward shaping 困难) 2. RL 无法保证最优性——它可能学到一个"还行"的策略,但不是最优的 3. RL 难以处理硬约束——关节限位、摩擦锥等物理约束在 RL 中只能用惩罚项近似,无法严格保证 4. RL 的泛化有限——训练分布外的地形可能完全失败(如训练时没见过冰面) 5. 可解释性——CITO 的解有 KKT 条件支撑,可以分析为什么选择某个接触;RL 的策略是黑盒
最佳实践:CITO 和 RL 是互补工具。CITO 用于离线分析、验证最优性、生成训练数据;RL 用于在线快速推理。两者结合优于任何单一方法。
练习¶
练习 59.8a(⭐⭐):设计一个简单的 MDP 来训练 RL 策略选择落脚点。定义状态空间、动作空间、奖励函数。讨论奖励工程(reward shaping)的难点——为什么"到达目标"的稀疏奖励不够?
练习 59.8b(⭐⭐⭐):解释为什么 CITO warm-start + 少量 NLP 迭代可以比冷启动快 10-100 倍。用 Newton 法的二次收敛性给出定量估计:如果冷启动初值误差为 \(\delta_0 = 10\),warm-start 初值误差为 \(\delta_0 = 0.1\),收敛到 \(\delta < 10^{-6}\) 各需多少次迭代?
59.9 工程实现:Ifopt + Towr ⭐⭐¶
动机:理论到代码的桥梁¶
本节解决的问题:前面几节讲了 CITO 的数学理论。Winkler 的 Towr 是目前最易上手的 CITO 工程实现——它用 Ifopt + Ipopt 求解足式机器人的轨迹优化,支持 phase-duration 作为决策变量。
59.9.1 Towr 的架构 ⭐⭐¶
Towr 的代码结构:
─────────────────────────────
towr/
├── include/towr/
│ ├── models/ ← 机器人模型 (质量, 惯量, 腿长)
│ │ ├── endeffector_mappings.h
│ │ └── robot_model.h
│ ├── variables/ ← NLP 决策变量
│ │ ├── spline_holder.h ← 样条参数
│ │ ├── phase_durations.h ← 相位时长(核心创新!)
│ │ └── nodes_variables.h ← 样条节点
│ ├── constraints/ ← NLP 约束
│ │ ├── dynamic_constraint.h ← 动力学 (LIP / centroidal)
│ │ ├── range_of_motion_constraint.h ← 运动学
│ │ ├── terrain_constraint.h ← 地形
│ │ └── total_duration_constraint.h ← 总时长
│ ├── costs/ ← NLP 代价
│ └── nlp_formulation.h ← 顶层: 组装变量+约束+代价
└── src/
└── ...
Towr 的核心设计决策:
| 决策 | 选择 | 理由 |
|---|---|---|
| NLP 框架 | Ifopt | 轻量、与 Ipopt/Snopt 集成、纯 Eigen |
| 轨迹参数化 | 三次 Hermite 样条 | 光滑、导数解析可用、参数少 |
| 动力学模型 | 单刚体 / 质心 | 降维,加速求解 |
| 接触处理 | Phase-based(非 CITO) | 避免互补约束的数值困难 |
重要澄清:Towr 不是严格的 CITO
Towr 不直接使用互补约束。它用 **phase-based 参数化**来处理接触时序——这是一个工程上的折中:
CITO 方式:
互补约束 phi * lambda <= epsilon → 优化器自由选择接触/不接触
→ 完全自由,但数值困难
Towr 方式:
预定义 phase 结构 (支撑/摆动交替)
但 phase 的持续时间是决策变量
→ 优化器可以调整"每步走多久",但不能改变"先左后右"的顺序
→ 数值稳定,但自由度受限
这是一个**折中**:放弃了 CITO 的完全自由度(不能发现全新的接触模式),换取数值稳定性和求解速度。对于大多数实用场景(已知步态类型,只需优化时机和落脚点),这个折中是值得的。
59.9.2 Phase-Duration 参数化 ⭐⭐¶
Winkler 2018 (RA-L) 的核心创新是让 phase duration 成为决策变量。
传统方法(固定时序):
// 固定: 每个 phase 0.3 秒
// trot 步态: [支撑, 摆动, 支撑, 摆动, ...]
std::vector<double> phase_durations = {0.3, 0.3, 0.3, 0.3, 0.3};
// → 总时间 1.5 秒, 不可优化
Towr 方法(可优化时序):
// towr/include/towr/variables/phase_durations.h (简化)
class PhaseDurations : public ifopt::VariableSet {
public:
// 每个 phase 的时长都是决策变量
VecBound GetBounds() const override {
VecBound bounds;
for (int i = 0; i < n_phases_; i++) {
// 每个 phase 时长在 [0.1, 1.0] 秒之间
bounds.push_back(ifopt::Bounds(0.1, 1.0));
}
return bounds;
}
Eigen::VectorXd GetValues() const override {
return phase_durations_; // 当前的 phase 时长
}
void SetVariables(const Eigen::VectorXd& x) override {
phase_durations_ = x; // Ipopt 更新 phase 时长
}
};
为什么这样设计? 关节角度和足端位置用三次 Hermite 样条参数化——每段样条的时间跨度由 phase duration 决定。当 phase duration 改变时,样条会"拉伸"或"压缩",从而改变运动的时间节奏。这意味着优化器可以通过调整 phase duration 来隐式地改变步频和步幅的平衡。
效果:优化器可以自动发现非对称步态。例如,上坡时前腿支撑时间更长(需要更大的推力),下坡时后腿支撑时间更长(需要制动)。
约束:总时间固定
// towr/include/towr/constraints/total_duration_constraint.h
class TotalDurationConstraint : public ifopt::ConstraintSet {
Eigen::VectorXd GetValues() const override {
double total = phase_durations_->GetValues().sum();
return Eigen::VectorXd::Constant(1, total - T_total_);
// total - T = 0 → 总时间等于指定值
}
};
59.9.3 用 Towr 实现四足轨迹优化 ⭐⭐¶
完整使用流程:
// 简化的 Towr 使用流程 (基于 towr 官方示例)
#include <towr/nlp_formulation.h>
#include <ifopt/ipopt_solver.h>
int main() {
// 1. 定义地形
auto terrain = std::make_shared<towr::FlatGround>(0.0);
// 2. 定义机器人模型
towr::RobotModel model = towr::RobotModel(towr::RobotModel::Anymal);
// 3. 设置初始和目标状态
towr::NlpFormulation formulation;
formulation.terrain_ = terrain;
formulation.model_ = model;
formulation.initial_base_.lin.at(towr::kPos) << 0.0, 0.0, 0.5;
formulation.final_base_.lin.at(towr::kPos) << 2.0, 0.0, 0.5;
// 4. 设置步态 (trot, 4 个 phases)
auto gait_gen = towr::GaitGenerator::MakeGaitGenerator(4);
gait_gen->SetCombo(towr::GaitGenerator::C0); // trot
formulation.params_.ee_phase_durations_ =
gait_gen->GetPhaseDurations();
formulation.params_.ee_in_contact_at_start_ =
gait_gen->GetContactSchedule();
// 5. 组装 NLP
ifopt::Problem nlp;
for (auto c : formulation.GetVariableSets(formulation.params_))
nlp.AddVariableSet(c);
for (auto c : formulation.GetConstraints(formulation.params_))
nlp.AddConstraintSet(c);
for (auto c : formulation.GetCosts())
nlp.AddCostSet(c);
// 6. 求解
ifopt::IpoptSolver solver;
solver.SetOption("linear_solver", "ma57");
solver.SetOption("max_cpu_time", 20.0);
solver.Solve(nlp);
// 7. 提取结果
// formulation.GetTrajectory() 返回 base motion + EE motion + forces
return 0;
}
为什么这段代码能工作? 逐步解释设计选择:
| 步骤 | 做了什么 | 为什么这样做 |
|---|---|---|
| 地形 | FlatGround |
定义高度函数 \(z = h(x, y)\),约束足端在地面上 |
| 模型 | RobotModel::Anymal |
提供质量、惯量、腿长等参数 |
| 变量 | 样条节点 + phase durations | 用少量节点参数化连续轨迹 |
| 约束 | 动力学 + 运动学 + 地形 + 总时间 | 确保物理可行 |
| 求解器 | Ipopt + MA57 | 稀疏非线性规划求解 |
⚠️ 编程陷阱:Towr 的初始猜测
错误做法:让 Ipopt 从全零初始值开始求解。
症状:Ipopt 报 "restoration failed" 或收敛到静止解(机器人不动)。
根因:Towr 的 NLP 高度非凸。从全零出发,优化器找不到"行走"这个局部最优——它会收敛到"站着不动"这个平凡解(代价为零的局部最优)。
正确做法:Towr 内部会根据初始/终端状态和步态生成一个合理的初始猜测(线性插值基座轨迹 + 默认足端位置)。如果自定义场景,确保初始猜测至少"大致正确"——比如基座轨迹是从起点到终点的直线。
💡 概念误区:Towr 是实时控制器
新手想法:"Towr 能在 100 ms 内求解,可以做 MPC!"
实际上:Towr 求解的 100 ms 是**冷启动**时间。每次环境变化都需要重新求解。真正的 MPC 需要 warm-start(利用上一步的解),但 Towr 的样条参数化在时间步移动时需要重新参数化——warm-start 不够自然。
正确用法:Towr 用于**离线**或**低频**规划(约 1 Hz),生成的轨迹交给 OCS2/Crocoddyl 等在线 MPC 跟踪。
练习¶
练习 59.9a(⭐⭐):安装 Towr(GitHub: ethz-adrl/towr)并运行默认的四足 trot 示例。对比固定 phase durations 和可优化 phase durations 的结果——观察优化器自动调整的步频。
练习 59.9b(⭐⭐⭐):修改 Towr 示例,将终端高度从 0.5 m 改为 0.8 m(抬高 30 cm),观察优化器是否自动发现需要的动作。如果结果不理想,分析原因并尝试调整约束或初始猜测。
🔧 故障排查手册¶
接触优化问题的非凸性和互补约束使调试尤为困难。以下是 CITO / MIQP 工程实践中最常见的故障场景。
| 症状 | 可能原因 | 排查步骤 | 相关章节 |
|---|---|---|---|
| MIQP 求解超时(>10 s)或 Branch-and-Bound 不收敛 | 整数变量过多(候选区域 > 20)、Big-M 值过松导致 LP 松弛间隙过大 | 1. 减少候选接触区域(只保留运动学可达的) 2. 收紧 Big-M 至约束真实上界的 1.5 倍 3. 用上一次解做 warm-start 4. 设置求解器时间上限并接受次优整数解 | 59.7 |
| CITO 收敛到"所有接触力为零"的平凡解(机器人"飞"起来) | 初始猜测远离物理可行解,优化器找到了满足互补约束但无物理意义的局部最优 | 1. 用静态平衡姿态作为初始猜测 2. 在代价函数中加入重力补偿先验项 \(\|\sum f_i + mg\|^2\) 3. 对接触力加下界惩罚 4. 尝试多个随机初值取最优 | 59.2, 59.4 |
| Ipopt 报 "Restoration Failed" 或 "Converged to local infeasibility" | 互补约束在接触切换点导致 LICQ 失效,约束雅可比秩亏 | 1. 检查松弛参数 \(\epsilon\) 是否过小(建议从 \(10^{-1}\) 开始续延) 2. 切换到 Fischer-Burmeister 函数 3. 打印 KKT 残差定位是哪类约束出问题 4. 检查是否提供了稀疏模式 | 59.3 |
| 凸松弛间隙过大(松弛解与整数解目标差 >50%) | 接触区域形状高度非凸、Big-M 过松、或松弛后的连续问题与原整数问题结构差异过大 | 1. 用 IRIS 或 CSPACE 对区域做更精细的凸分解 2. 增加 cutting plane(Benders cut)收紧松弛 3. 考虑用 GCS 替代传统 MIQP | 59.7 |
| Towr 优化出的轨迹在仿真中不可执行(关节超限或滑脚) | 质心轨迹优化忽略了全身运动学约束、或摩擦系数设置与仿真不一致 | 1. 检查 Towr 的运动学约束是否匹配实际机器人 URDF 2. 对比 Towr 的摩擦系数与仿真器设置 3. 在 Towr 解上跑逆运动学验证关节角度范围 | 59.9 |
| 提取出的接触力随时间剧烈震荡(chattering) | 互补约束的数值刚性:松弛参数 \(\epsilon\) 或光滑化参数 \(\sigma\) 过小,求解器在接触切换点反复横跳 | 1. 适度增大 FB 光滑化参数 \(\sigma\)(如从 \(10^{-6}\) 提到 \(10^{-4}\)) 2. 在代价中加入接触力变化率惩罚 \(\sum_k \|\boldsymbol{\lambda}_{k+1}-\boldsymbol{\lambda}_k\|^2\) 3. 检查时间步长 \(h\) 是否过大导致冲量分配跳变 | 59.3, 59.5 |
| 变分积分器长时域仿真出现系统性能量漂移 | 时间步长 \(h\) 过大,或位形更新未走流形(SO(3) 上用了加法而非指数映射) | 1. 减小 \(h\) 或改用更高阶辛格式 2. 在 SE(3) 上用指数映射更新位形(见 59.5.3 陷阱) 3. 监控系统总能量 \(E_k = T_k + V_k\),辛积分器应表现为有界振荡而非单调漂移 | 59.5 |
59.10 本章小结¶
知识点总结¶
| 小节 | 核心知识点 | 难度 | 关键公式/概念 |
|---|---|---|---|
| 59.1 | 优化驱动的动机 | ⭐ | 启发式天花板,接触作为决策变量 |
| 59.2 | CITO 数学基础 | ⭐⭐⭐ | 完整 NLP 公式,时间步进,约束雅可比稀疏性 |
| 59.3 | 互补约束处理 | ⭐⭐⭐ | 松弛法,Fischer-Burmeister,增广拉格朗日 |
| 59.4 | Posa 2014 精读 | ⭐⭐⭐ | Direct collocation + MPCC 松弛 |
| 59.5 | 变分 CITO | ⭐⭐⭐⭐ | 变分积分器,辛结构保持,二阶精度 |
| 59.6 | 质心轨迹优化 | ⭐⭐⭐ | 质心动力学 + 接触协同,接触指示器 |
| 59.7 | 双层优化 | ⭐⭐⭐⭐ | MIQP + NLP 分解,Big-M,Benders cut |
| 59.8 | 学习驱动 | ⭐⭐⭐ | RL/扩散模型,CITO + 学习融合 |
| 59.9 | Towr 工程实现 | ⭐⭐ | Phase-duration 参数化,Ifopt + Ipopt |
方法选择决策树¶
需要接触规划?
/ \
是 否
/ \
地形已知? → 足式/110_OCS2完整栈与双线程MPC 标准 MPC
/ \
是 否
/ \
离线可以? → RL 端到端策略
/ \
是 否
/ \
CITO/Towr 双层优化(实时化版本)
本质洞察: Contact-Implicit TO 的数学本质是**用连续优化框架求解离散组合问题**。互补约束 \(\phi \cdot \lambda = 0\) 把"接触/不接触"的二值决策编码为连续变量之间的乘积等于零。这种编码虽然在数学上优雅(避免了枚举 \(2^{n_c \times N}\) 种模式组合),但代价是可行集变成了两个正象限的并集——一个根本性非凸的集合。所有 CITO 方法的核心技巧,无论是松弛、FB 函数还是 ALM,本质上都是在"近似凸化"这个非凸可行集。松弛法把 L 形可行集"充气"为一个凸区域;FB 函数把 L 形可行集"光滑化"为一条曲线;ALM 把约束违反"罚入"目标函数,让优化器在不可行域中也能定义梯度。理解这一点,就理解了为什么 CITO 对初值敏感、为什么会收敛到局部最优、为什么不同松弛方法在不同问题上表现迥异。
本质洞察: 双层优化(59.7)揭示了接触规划的一个深层结构:离散决策(哪里接触)和连续优化(力和轨迹)之间存在天然的层次分离。上层的离散决策定义了下层连续问题的约束结构;下层的连续优化结果反过来评估上层决策的质量。这种层次结构不是人为强加的,而是问题本身的数学结构——接触模式一旦确定,剩下的就是一个标准的(相对容易的)轨迹优化问题。双层分解的智慧在于:与其在一个巨大的非凸问题中同时搜索离散和连续变量,不如把它们分开处理——用组合搜索(MIQP/MCTS)处理离散部分,用连续优化(NLP/DDP)处理连续部分。
Contact-Implicit MPC 最新进展(2023-2025) ⭐⭐⭐⭐¶
传统观点认为 CITO 只能离线使用,但 2023 年以来,多个团队在推动 Contact-Implicit MPC 的实时化:
Dojo (Howell et al. 2022, RSS):Dojo 是一个可微接触仿真器,核心创新是用**光滑化接触动力学(smoothed contact dynamics, randomized smoothing)**替代传统的 LCP 来处理接触。光滑化方法在接触点处提供平滑的梯度(而非传统 LCP 的不连续梯度),使得基于梯度的 MPC 求解器可以直接优化穿过接触切换的轨迹。在 2D 推箱子任务上,Dojo + iLQR 实现了约 50 ms 的在线重规划。
ContactNets (Pang et al. 2023, T-RO):提出了"准静态光滑化"(Quasi-Dynamic Smoothing)方法。核心思想:在接触点附近用可微的"软接触"模型替代硬互补约束,使得整个动力学方程在接触切换处连续可微。这使得 Newton 型求解器可以二次收敛,比传统 CITO 快 10-50 倍。
ACAL-iLQR (Chen et al. 2025, Advanced Intelligent Systems):将增广拉格朗日法(ALM)嵌入 iLQR 的 backward pass 中,实现了"无需固定接触序列的 iLQR"。在简单系统(弹跳球、单腿跳)上实现了约 1 秒求解,是目前最接近实时的全身 CITO 方法之一。
| 方法 | 求解时间(四足) | 接触模型 | 可微性 | 成熟度 |
|---|---|---|---|---|
| Posa 2014 (IPOPT) | 10-100 s | LCP 嵌入 NLP | 不可微(松弛近似) | 高(经典) |
| Dojo 2022 | 0.05-1 s (低维) | 光滑化接触(randomized smoothing) | 可微 | 中 |
| ContactNets 2023 | 1-10 s | 准静态光滑化 | 可微 | 中 |
| ACAL-iLQR 2025 | 0.5-5 s | ALM + iLQR | 近似可微 | 低(新) |
Gap 分析: 从上表可以看出,最快的 CITO 在四足上仍需约 0.5 秒(低维简化模型)到数十秒(全身模型)。与 MPC 要求的 5-50 ms 仍有 1-2 个数量级的差距。缩小这个差距的三条路径是:(1) GPU 并行化(见下),(2) 学习型 warm-start(59.8 节),(3) 更高效的求解器定制(如 CALIPSO)。
GPU-Accelerated CITO ⭐⭐⭐¶
GPU 加速是 CITO 实时化的最有前景的方向之一。核心思路:CITO 中最耗时的部分是约束雅可比的计算和 KKT 系统的求解,两者都有大量的并行结构。
MuJoCo MJX (2024-2025):MuJoCo 的 JAX 后端(MJX)允许在 GPU 上批量并行运行可微物理仿真。结合 JAX 的自动微分,可以在 GPU 上同时计算数千条轨迹的梯度——这是 CITO 的 shooting method 所需要的。在 NVIDIA A100 上,MJX 可以以 >10 万步/秒的速度仿真四足机器人,比 CPU 快 100-1000 倍。
cuHPIPM / GPU QP 求解器:HPIPM 目前是纯 CPU 实现。将 block-sparse QP 求解移植到 GPU 上是一个活跃的研究方向。cuHPIPM (非官方社区项目) 尝试将 HPIPM 的 Riccati recursion 并行化,但对 CITO 中的变结构 QP(约束集合随接触模式变化)支持有限。
工程前景: 乐观估计,GPU 加速的 Contact-Implicit MPC 有望在 2027-2028 年达到 50-100 ms 级别的求解速度(在高端 GPU 如 Orin/Jetson Thor 上)。这将使得"实时 CITO"从理论走向实践——MPC 在每个控制周期都能重新发现最优的接触策略,而非依赖预定义步态。
关键 takeaway¶
- 接触规划是混合优化问题——离散选择(哪里接触)+ 连续优化(力和轨迹),本质上 NP-hard
- 互补约束是核心数学挑战——三种处理方法(松弛、FB、ALM)各有优劣,没有银弹
- 全身 CITO 目前仍是离线工具——与实时 MPC 之间存在 1-2 个数量级的速度差距,但差距正在快速缩小
- 分层/双层架构是工程最佳实践——MIQP/CITO 离线规划 + MPC 在线跟踪 + WBC 实时执行
- 学习是加速 CITO 的关键方向——warm-start、模仿学习、扩散模型正在缩小优化与学习之间的差距
- GPU 并行化是硬件层面的加速路径——MuJoCo MJX + JAX 使得可微 CITO 的 GPU 实现成为可能
累积项目:本章新增模块¶
累积项目:从零构建四足轨迹优化器
本章在累积项目中新增以下模块:
项目进度:
足式/50_空间向量与浮动基座动力学: 加载 URDF, 前向运动学 [完成]
足式/60_QP_NLP建模: NLP 框架 (Ifopt + Ipopt) [完成]
足式/70_腿足简化模型理论: 简化模型 (LIPM, SRBD) [完成]
足式/80_接触力学与约束优化: 接触力学约束 [完成]
足式/90_WBC分层优化与TSID: WBC 基础 [完成]
足式/100_DDP家族与Crocoddyl: DDP 实现 [完成]
足式/110_OCS2完整栈与双线程MPC: OCS2 MPC [完成]
足式/140_落脚点规划经典方法: Raibert 落脚 [完成]
足式/150_优化驱动落脚与接触规划: ← 本章新增
├── [M1] 互补约束求解器: 用 CasADi 实现松弛法 + FB 函数
├── [M2] 2D CITO: 单腿弹跳的 Contact-Implicit 优化
├── [M3] Towr 集成: 安装 Towr, 运行四足 trot 优化
└── [M4] Phase-duration 实验: 对比固定/可变 phase 的效果
M1: 互补约束求解器(Python + CasADi)
目标:实现一个通用的互补约束求解器,支持松弛法和 FB 函数,作为后续 CITO 的基础组件。验证标准:在 1D 互补问题上,两种方法的解误差 < \(10^{-6}\)。
M2: 2D CITO(Python + CasADi + Ipopt)
目标:对一个 2D 单腿弹跳机器人实现完整的 CITO——从地面跳到目标高度,自动发现起跳时机。验证标准:优化器输出的接触时序应该在物理上合理(先蓄力 → 起跳 → 飞行 → 着陆)。
M3: Towr 集成(C++ + ROS)
目标:安装 Towr,运行四足 trot 示例,可视化轨迹。验证标准:能成功运行并看到合理的行走轨迹。
M4: Phase-duration 实验(C++)
目标:对比 Towr 中固定 phase duration 和可优化 phase duration 的结果差异。验证标准:记录两种设置的求解时间、最终代价、步频变化。
延伸阅读¶
必读经典(⭐⭐)¶
| 论文/资源 | 年份 | 核心贡献 | 难度 |
|---|---|---|---|
| Posa, Cantu, Tedrake. "A direct method for trajectory optimization of rigid bodies through contact" — IJRR | 2014 | CITO 奠基论文,MPCC 松弛,direct collocation | ⭐⭐⭐ |
| Mordatch, Todorov, Popovic. "Discovery of complex behaviors through contact-invariant optimization" — SIGGRAPH | 2012 | 接触指示器,复杂行为自动发现 | ⭐⭐⭐ |
| Winkler et al. "Gait and trajectory optimization for legged systems through phase-based end-effector parameterization" — RA-L | 2018 | Towr, phase-duration 参数化 | ⭐⭐ |
| Manchester, Kuindersma. "Contact-implicit trajectory optimization using variational integrators" — IJRR | 2019 | 变分积分器 CITO,二阶精度,辛结构 | ⭐⭐⭐⭐ |
近期前沿(⭐⭐⭐)¶
| 论文/资源 | 年份 | 核心贡献 | 难度 |
|---|---|---|---|
| Pang et al. "Global planning for contact-rich manipulation via local smoothing of quasi-dynamic contact models" — T-RO | 2023 | 准静态光滑化 CITO,采样 + 优化融合 | ⭐⭐⭐⭐ |
| Howell et al. "CALIPSO: A differentiable solver for trajectory optimization with conic and complementarity constraints" — ISRR | 2022 | ALM + 内点法定制求解器 | ⭐⭐⭐⭐ |
| "Bilevel optimization for real-time control with application to locomotion gait generation" | 2024 | 实时双层优化,warm-started MIQP + iLQR | ⭐⭐⭐⭐ |
| "A novel contact-implicit trajectory optimization framework for quadruped locomotion" — Adv. Intell. Syst. | 2025 | ACAL-iLQR,无需固定接触序列 | ⭐⭐⭐⭐ |
教材与综述¶
| 资源 | 内容 | 难度 |
|---|---|---|
| Wensing et al. "Optimization-based control for dynamic legged robots" — 综述 | 2023 综述,全面覆盖足式优化控制 | ⭐⭐⭐ |
| Tedrake. "Underactuated Robotics" — 在线教材 Ch12-14 | Contact dynamics + CITO 教学 | ⭐⭐ |
| Towr GitHub: ethz-adrl/towr | 最易上手的 CITO 代码 | ⭐⭐ |
| Drake documentation: Contact planning tutorials | 工业级 CITO/GCS 实现 | ⭐⭐⭐ |
开放研究方向(博士选题参考)¶
| 方向 | 核心问题 | 难度 | 活跃度 |
|---|---|---|---|
| 实时 CITO | 如何把 CITO 从秒级降到毫秒级?GPU 并行?定制求解器? | ⭐⭐⭐⭐ | 极高 |
| CITO + 感知 | 如何将不确定的地形感知融入 CITO?鲁棒优化?随机规划? | ⭐⭐⭐⭐ | 高 |
| 扩散模型 + 接触 | 扩散模型如何保证物理约束满足?投影?引导? | ⭐⭐⭐⭐ | 极高(2025 热点) |
| 多接触 loco-manipulation | 手脚协同的接触规划,接触模式组合爆炸更严重 | ⭐⭐⭐⭐ | 高 |
| GCS + 腿足 | Graph-of-Convex-Sets 用于足式接触序列,凸松弛的理论保证 | ⭐⭐⭐ | 中(新兴) |
[跨章综合题] 练习 59.X:从互补约束到 MPC 部署的完整管线¶
本题需要综合 足式/80_接触力学与约束优化(接触力学)、足式/100_DDP家族与Crocoddyl(DDP)和本章(CITO)的知识。
场景: 你要为一个单腿弹跳机器人设计 CITO,使其从地面跳到 0.5m 高的平台上。
- (足式/80_接触力学与约束优化) 写出地面接触的互补约束。弹跳机器人在起跳瞬间,法向力 \(\lambda_n\) 从正值跳到零——这个不连续性对优化器意味着什么?为什么 LICQ 在这个点失效?
- (本章 59.3) 分别用松弛法(\(\epsilon = 0.01\))和 Fischer-Burmeister 函数处理这个互补约束,写出修改后的 NLP 约束。用 Python/CasADi 实现两种方法,对比收敛迭代次数和最终约束违反量。
- (足式/100_DDP家族与Crocoddyl) 如果用 ACAL-iLQR(DDP 嵌入 ALM)替代 IPOPT 直接求解,DDP 的 backward pass 中如何处理互补约束?提示:增广拉格朗日项 \(\frac{\rho}{2}\|\phi \cdot \lambda\|^2 + \mu(\phi \cdot \lambda)\) 加入 running cost 后,\(Q_{uu}\) 矩阵如何变化?
- (综合) CITO 规划出的跳跃轨迹要交给在线 MPC 跟踪(足式/110_OCS2完整栈与双线程MPC)。设计一个分层架构:CITO 离线生成参考轨迹(包括接触时序和接触力) → OCS2 MPC 在线跟踪。MPC 需要知道哪些来自 CITO 的信息?如何将 CITO 的接触序列转化为 OCS2 的 ModeSchedule?
本章常见误解汇总¶
下表汇总全章出现的高频误解,把散落在各节"概念误区/思维陷阱"里的要点集中成一张速查表,便于复习时一次性自检:
| 误解 | 正确理解 | 出处 |
|---|---|---|
| CITO 能替代 MPC、可以实时跑 | 全身 CITO 是**离线/低频规划**工具(秒~分钟级),与 MPC(5–50 ms)差 1–3 个数量级;生成的轨迹交给在线 MPC 跟踪 | 59.1 |
互补约束 \(\phi\lambda=0\) 就是 if(contact)...else... 分支 |
if-else 在切换点不可微,Newton 法无法穿过;互补约束把它编码为**连续但不光滑**的等式,再光滑化后可微求解 | 59.3 |
| 松弛只是"近似",所以解不准 | 续延让 \(\epsilon\to 0\),最终违反 \(O(10^{-4})\) 工程上等价精确;真正的风险不是精度而是**收敛到错误局部最优** | 59.3 |
| 求解器报 "Optimal" 就等于找到局部最优 | 对松弛后的 MPCC,"收敛"只保证 C-平稳,比局部最优弱;C-平稳点可能是伪解 | 59.3.5 |
| 摩擦约束就是 \(\|\boldsymbol{\lambda}^t\|\le\mu\lambda^n\) 一条不等式 | 还需**最大耗散原理**锁定摩擦力方向(反向于滑动),否则优化器会"顺着滑动方向推" | 59.2.4 |
| CITO 必须把摩擦锥切成多面体 | 多面体化是 LCP 仿真**的需要;用 NLP 求解器的 CITO 可直接保留**光滑二阶锥,避免各向异性误差 | 59.2.4 |
| 变分积分器总比普通积分器好 | 它需隐式求解 + 实现复杂;短时域(MPC 窗口)一阶足够,优势只在**长时域**规划体现 | 59.5 |
| 双层优化就是"先上层再下层两次搞定" | 上层选的序列可能在下层不可行,需 Benders cut 迭代;上层目标 \(J^*(\sigma)\) 每评估一次就要解一个下层 NLP | 59.7 |
| Towr 是严格的 CITO,能做实时 MPC | Towr 用 phase-based 参数化而非互补约束(不发现全新接触模式);其 100 ms 是**冷启动**,warm-start 不自然,应离线/低频用 | 59.9 |
| GCS 让 CITO 和 MIQP 都过时了 | GCS 目前主要在**准静态低自由度操作**上验证优势;高维动态全身足式仍靠 CITO / 双层 MIQP | 59.7.6 |
| RL 可以完全替代 CITO | RL 无最优性保证、难处理硬约束、泛化有限;CITO 提供训练数据与 baseline,二者**互补** | 59.8 |
本章与后续章节的关系¶
| 后续章节 | 关系 | 本章铺垫的知识点 |
|---|---|---|
| 足式/160_感知驱动落脚规划 | 直接延续 | 本章假设地形已知;160 章把**地形感知(高度图、可踏区分割)**接入落脚规划,回答"GCS/MIQP 的凸接触区域从哪来"。本章开放方向"CITO + 感知"是其引子 |
| 足式/170_实时CPP工程 | 工程落地 | 本章的 NLP/Ifopt 求解、稀疏雅可比、warm-start 都需要高效 C++ 实现;170 章讲实时约束下的代码组织 |
| 足式/210_RL与MPC混合范式 | 范式融合 | 本章 59.8(学习驱动)是其核心动机之一——CITO 生成 demonstration、学习 warm-start、RL 高层 + 优化低层的分层架构在 210 章系统展开 |
| 足式/230_Perceptive_MPC | 综合应用 | 本章"离线 CITO + 在线 MPC"分层 + 160 章感知,共同构成感知-规划-控制全栈,230 章把它们整合 |
| 足式/240_legged_control精读 / 250_Mini-Legged综合实战 | 源码与实战 | 本章的接触序列、摩擦锥、质心动力学是这些实战章里 MPC/WBC 模块的理论前提 |
API 速查表¶
本章涉及的核心库与 API(按出现顺序)。括号内为所属库:
| API / 类 | 所属 | 作用 | 关键参数 / 说明 |
|---|---|---|---|
ifopt::VariableSet |
Ifopt | NLP 决策变量基类 | 重写 GetValues/SetVariables/GetBounds;Towr 的 PhaseDurations、NodesVariables 继承它 |
ifopt::ConstraintSet |
Ifopt | NLP 约束基类 | 重写 GetValues/FillJacobianBlock;**必须提供稀疏模式**否则退化为稠密 |
ifopt::CostTerm |
Ifopt | NLP 代价基类 | 重写 GetCost/FillJacobianBlock |
ifopt::Problem |
Ifopt | 组装变量 + 约束 + 代价 | AddVariableSet / AddConstraintSet / AddCostSet |
ifopt::IpoptSolver |
Ifopt→Ipopt | 调用 Ipopt 求解 | SetOption("linear_solver","ma57")、SetOption("max_cpu_time", T) |
eval_jac_g(iRow,jCol,values) |
Ipopt C 接口 | 约束雅可比回调 | values==nullptr 时返回稀疏模式(行列索引),否则填非零值(见 59.2.3 陷阱) |
towr::NlpFormulation |
Towr | 顶层 NLP 组装器 | terrain_ / model_ / initial_base_ / final_base_ / params_ |
towr::RobotModel |
Towr | 机器人模型(质量/惯量/腿长) | RobotModel::Anymal 等预置型号 |
towr::GaitGenerator |
Towr | 生成 phase 时序与接触表 | MakeGaitGenerator(n_ee)、SetCombo(C0)(C0=trot) |
towr::FlatGround / HeightMap |
Towr | 地形高度函数 \(z=h(x,y)\) | 约束足端落在地面上 |
casadi::SX / MX |
CasADi | 符号变量(构造 NLP) | 用于累积项目 M1/M2 实现互补约束求解器 |
casadi::nlpsol("solver","ipopt",...) |
CasADi | 构造 Ipopt 求解器对象 | Python 端最简 CITO 原型路径 |
GRBaddgenconstrIndicator |
Gurobi | indicator 约束 | 替代 Big-M,松弛更紧(见 59.7.2) |
环境提示:Ipopt 的高性能线性求解器 MA57/MA27 来自 HSL,需单独申请学术许可;开源替代是 MUMPS(
linear_solver=mumps),性能略低但免授权。Towr 仓库:ethz-adrl/towr;GCS 参考实现见 Drake 的GraphOfConvexSets。
研究实践建议¶
按你的目标分层给出建议:
如果你是初次接触 CITO(入门): - 不要一上来啃 Posa 2014 原文。先用 Python + CasADi 实现累积项目 M1(1D 互补求解器)和 M2(2D 单腿弹跳 CITO),亲手感受"松弛 \(\epsilon\) 一调小就不收敛"。 - 跑通 Towr 的四足 trot 示例(M3),对照 59.9 理解 phase-based 与 CITO 的区别。这是性价比最高的"看得见结果"的起点。
如果你要做 CITO 方向的研究(进阶): - 精读 59.3.5(MPCC 平稳性)+ Scholtes 正则化原文,理解你的求解器到底收敛到哪一级平稳性——这决定了论文里"我们的解是最优的"这句话能不能写。 - 复现 Posa 2014 的 2D 弹跳球 + 双足,再读 Manchester 2019 理解变分积分器的增量。基准要在同一系统上对比一阶 vs 二阶精度(59.5.3 的表)。 - 关注 2022 年以来的实时化路线:Dojo(光滑化)、Pang 2023(准静态光滑化)、GCS(凸松弛)、ACAL-iLQR。选一个 gap(59 章小结的 Gap 分析表)作为切入。
如果你要把接触规划落地到真机(工程): - 优先选**双层架构**而非单层全身 CITO:上层 MIQP/GCS 离线或 1 Hz 规划接触序列与落脚点,下层用 OCS2/Crocoddyl 的 MPC(足式/100、110)在线跟踪,WBC(足式/90)500 Hz 执行。 - 把 59 章故障排查手册贴在工位上:90% 的"不收敛"来自初值差、\(\epsilon\) 过小、忘记稀疏模式、摩擦系数与仿真不一致这四类。 - 上真机前务必在 Towr/CITO 解上跑一遍逆运动学校验关节范围(59.9 最后一条陷阱),质心优化的解很可能运动学不可行。
共同的元建议:本章所有方法的成败都系于一个问题——你把离散接触决策编码成了什么(互补约束 / Big-M / 透视函数 / phase 结构)。遇到新问题时,先问"我的编码让松弛变紧还是变松",再选求解器。这条主线串起了全章。