第 81 章:轮足 Sim-to-Real 与硬件集成——轮胎、滑移、执行器与实时部署¶
本章定位:把仿真中“能跑”的轮足策略,变成硬件上“可控、可测、可停、可复现”的系统。 前置主线:足式/90 WBC 分层优化,足式/210 RL 与 MPC 混合部署,第 80 章(100_模式切换.md)的轮 / 足 / 混合模式切换。 关键问题:轮足系统的仿真差距,不只来自腿部动力学,还来自轮胎、地面、轮速编码器、执行器带宽和硬件安全逻辑。 难度:⭐⭐⭐。 预计时间:1.5 周,理论 10 小时,硬件接口 10 小时,实验 10 小时。
81.0 前置自测¶
请先回答下面问题。
| # | 问题 | 建议回顾 |
|---|---|---|
| 1 | ros2_control 的 read() -> update() -> write() 实时循环中,哪些操作不能出现? |
机械臂/M12 |
| 2 | 轮子滑移比 \(\kappa\) 和滑移角 \(\alpha\) 分别描述什么? | 复合/60 |
| 3 | 领域随机化的目标是让仿真更真实吗,还是让策略更鲁棒? | 足式/RL |
| 4 | ONNX/LibTorch 策略部署时,延迟和观测归一化为什么常导致失败? | 足式/210 |
| 5 | 轮模式和足模式在硬件命令接口上的最大差异是什么? | 第 80 章(100_模式切换.md) |
自测标准:
- 5/5 正确:直接阅读本章。
- 3-4/5 正确:重点关注硬件接口和随机化表。
- 0-2/5 正确:建议先回顾 ros2_control、轮式约束和 RL 部署章节。
81.1 本章目标¶
学完本章,你应能:
- 解释轮足 Sim-to-Real 的主要误差来源。
- 推导滑移比、滑移角和轮胎侧向力的基本模型。
- 设计轮足领域随机化参数表。
- 区分 Go2-W、B2-W、Tron1-WF、Upkie 等平台的硬件接口差异。
- 编写 ros2_control 风格的轮足硬件接口框架。
- 把 MPC 或策略网络输出映射成腿关节与轮电机命令。
- 设计真机部署前的分级安全测试。
- 调试打滑、延迟、力矩饱和、编码器漂移和控制频率丢失。
81.1b 本章知识导航¶
本章的内容可以组织成一棵知识树。树根是一个问题:仿真里跑得很好的轮足策略,凭什么相信它在真机上也能跑? 围绕这个问题,本章自上而下分四个层次展开,每一层回答一个子问题。
| 层次 | 子问题 | 对应小节 | 知识树定位 |
|---|---|---|---|
| 第一层:差距从哪来 | 轮足比纯腿足多了哪些误差通道? | §81.2 误差通道总览、§81.3 轮地接触最小模型、§81.4 Pacejka 教学版 | 树根:诊断 Sim-to-Real Gap 的来源 |
| 第二层:仿真里怎么补 | 怎样在仿真中重建这些误差,让策略提前见过? | §81.5 三层保真度、§81.6 域随机化表、§81.6b 域随机化为何有效、§81.9 执行器模型、§81.9e 执行器网络、§81.10 延迟建模 | 树干:建模与随机化 |
| 第三层:策略怎么接口 | 策略的观测、动作、部署链路怎样设计才不会在真机上崩? | §81.7 观测、§81.8 动作、§81.16 ONNX/LibTorch 部署、§81.17 schema | 树枝:策略与部署接口 |
| 第四层:硬件怎么落地 | 真机的硬件栈、实时性、标定、安全怎样保证? | §81.11–§81.15 平台与 ros2_control、§81.15b 实时与通信确定性、§81.20–§81.22 标定、§81.18–§81.19 分级与急停、§81.23 日志 | 树枝:硬件与工程化 |
| 闭环与排查 | 出了问题怎么定位?和上下游章节怎么衔接? | §81.24 Sim2Sim、§81.25 与模式切换耦合、§81.26–§81.30 故障案例、§81.38 排查手册 | 果实:调试闭环 |
阅读建议:
- 第一次通读:按 §81.2 → §81.6 → §81.16 → §81.18 的主干顺序,先建立"差距→随机化→部署→分级"的骨架,跳过 §81.4、§81.22b、§81.22c 等⭐⭐⭐进阶小节。
- 做硬件接入:直接看第四层(§81.11–§81.23)加 §81.26 落地故障。
- 做策略训练:重点第二层(§81.6、§81.9、§81.10)加 §81.6b 的随机化原理。
本质洞察:本章的四个层次不是并列的清单,而是一条**因果链**——第一层的每一个误差通道,都必须在第二层被建模或随机化,在第三层被观测或限幅,在第四层被标定或保护。任何一个误差通道在某一层被遗漏,都会在真机上变成一个故障。读本章时始终自问:"我现在看的这段,是在处理哪个误差通道?它在另外三层是怎么被接住的?"
81.2 为什么轮足 Sim-to-Real 比纯腿足更难¶
纯腿足系统的主要接触假设是:脚触地时,接触点近似静止。
轮足系统的主要接触假设是:轮子触地时,接触点沿滚动方向连续运动,横向近似无滑移。
这看似只是把零速度改成滚动速度。
但真实轮胎会变形。
真实地面有微小起伏。
轮胎材料有温度相关摩擦。
高速轮电机有反电动势。
小石子会让轮子短暂失去接触。
轮速编码器测到的是轮轴角速度,不是地面速度。
因此轮足系统多了一个很危险的误差通道:机器人以为自己移动了,世界却没有按这个速度移动。
| 方向 | 纯腿足主要误差 | 轮足额外误差 |
|---|---|---|
| 接触 | 摩擦锥、冲击、软地面 | 滑移比、滑移角、轮胎变形 |
| 执行器 | 关节力矩带宽 | 轮电机反电动势、高速饱和 |
| 状态估计 | 足端接触误判 | 轮里程计与真实速度不一致 |
| 模式切换 | 触地/离地 | 轮/足/混合命令语义切换 |
| 安全 | 跌倒、过流 | 打滑、甩尾、长距离漂移 |
本质洞察:轮足 Sim-to-Real 的核心不是“把摩擦系数调准”,而是让控制器承认轮地接触是一个有不确定性的速度转换器。 轮轴角速度乘轮半径只是期望地面速度,不是真实地面速度。
81.2.1 用四个维度穷举 Sim-to-Real Gap¶
上面的对比表是按"误差出现在哪个子系统"组织的。但要系统地随机化,更有用的是按**误差的物理性质**分类。Sim-to-Real Gap 不是一团模糊的"仿真和真机不一样",而是可以沿四个正交维度穷举的集合。这个分类框架直接决定了 §81.6 域随机化表里每一行该放什么。
| 维度 | 含义 | 轮足的典型表现 | 在仿真中如何重建 |
|---|---|---|---|
| 动力学差距(Dynamics Gap) | 刚体与接触动力学的参数与真机不符 | 质量、质心、惯量、轮半径、纵/横向摩擦、滑移刚度 | 参数随机化(§81.6 上半部) |
| 执行差距(Actuation Gap) | 仿真把执行器当理想力/速度源,真机有带宽、饱和、反电动势、摩擦 | 高速轮电机扭矩下降、关节库仑摩擦、减速器齿隙 | 执行器模型 / 执行器网络(§81.9) |
| 感知差距(Perception Gap) | 仿真观测干净无延迟,真机有噪声、偏置、量化、时间不对齐 | IMU 偏置漂移、轮速量化、视觉里程计延迟 | 噪声 + 延迟随机化(§81.10、§81.22b) |
| 时序差距(Timing Gap) | 仿真是同步定步长,真机有通信延迟、抖动、丢包、频率不稳 | 控制周期抖动、DDS/EtherCAT 延迟、推理阻塞 | 延迟队列 + 周期抖动(§81.10、§81.15b) |
为什么强调"正交"?因为这四个维度对应**不同的建模手段**,混在一起会导致随机化策略失焦。一个常见错误是:发现真机打滑(动力学维度问题),就拼命调高所有随机化范围,结果把执行延迟(时序维度)也无意义地放大,让策略学不到基本动作。正交分解的价值在于:哪个维度的差距导致了故障,就只在那个维度加强随机化。
系统性分类的价值:拿到任何一个真机故障,先问"它属于四个维度中的哪一个"。一落地就乱跑(§81.26)→ 多半是感知维度(IMU/轮速符号、时间对齐);仿真能过坡真机打滑(§81.27)→ 动力学维度(摩擦、滑移刚度);策略输出振荡(§81.28)→ 时序维度(频率、延迟不匹配);高速没劲(§81.9 故障)→ 执行维度(反电动势)。这个映射本身就是一张诊断地图。
81.2.2 一个反直觉的事实:轮足某些维度反而更好迁移¶
轮足比纯腿足难,是就**整体**而言。但分维度看,轮式行驶在某些方面反而**比腿式更容易**迁移:
- 平地巡航的动力学更简单:纯滚动接近一个光滑的非完整约束,没有腿式行走的反复冲击碰撞。冲击是腿式 Sim-to-Real 最难建模的部分(接触刚度、恢复系数高度依赖材料),轮式平地巡航几乎没有冲击。
- 能耗模型更可预测:轮式恒速行驶的功率主要用于克服滚动阻力和电机损耗,比腿式的周期性加减速更平滑,更容易在仿真中匹配。
不是 X 而是 Y:轮足 Sim-to-Real 难,不是因为"轮子这种机构本身难仿真",而是因为**轮足把"高速"和"接触不确定"叠加在了一起**。腿式机器人速度低,即使接触建模不准,误差累积慢、有时间纠正;轮式机器人速度高,轮地速度转换的小误差会被高速放大成大的位置漂移和姿态扰动,留给控制器纠正的时间窗口短得多。难的不是轮子,是速度乘以不确定性。
81.3 轮地接触的最小模型¶
考虑一个半径 \(r\) 的轮子。
轮轴角速度为 \(\omega\)。
接触点沿轮平面方向的地面速度为 \(v_x\)。
理想纯滚动条件:
真实世界中,两者往往不同。
定义滑移比:
\(v_{\mathrm{low}}\) 是低速保护项。
若 \(\kappa>0\),轮子转得比地面运动快,常见于加速打滑。
若 \(\kappa<0\),轮子转得比地面运动慢,常见于制动打滑。
横向速度 \(v_y\) 对应滑移角:
小滑移近似下,纵向力和侧向力可写成:
其中 \(C_\kappa\) 是纵向刚度。
\(C_\alpha\) 是侧偏刚度。
这两个参数取决于轮胎材料、地面、法向载荷和速度。
当滑移变大时,线性模型会失效。
此时力被摩擦圆截断:
如果仿真中只设置一个 Coulomb 摩擦系数 \(\mu\),没有建模滑移刚度,控制器会过度相信轮速命令。
81.4 Pacejka 模型的教学版理解¶
完整轮胎模型很复杂。
教学中常用 Pacejka 魔术公式理解侧向力曲线:
每个参数都有物理含义:
| 参数 | 直觉含义 | 调大后的效果 |
|---|---|---|
| \(B\) | 刚度因子 | 小角度力增长更快 |
| \(C\) | 形状因子 | 曲线形状更陡或更缓 |
| \(D\) | 峰值因子 | 最大侧向力更大 |
| \(E\) | 曲率因子 | 峰值后的下降方式变化 |
真实轮足控制不一定要在线使用完整 Pacejka。
但它提醒我们三件事:
- 轮胎力不是无限随滑移增长。
- 小滑移线性区很窄——对于典型轮足机器人的小轮胎(直径 8-15 cm),线性区可能只有 \(|\alpha| < 3^\circ\),超过这个角度力的增长就开始减缓。
- 峰值以后,继续打滑反而可能降低可控力。这个现象在汽车工程中被称为"不稳定滑移区"——一旦进入这个区域,增大驱动力矩反而让轮胎力下降,形成正反馈,导致完全失控。对轮足机器人而言,这意味着在湿滑地面上突然加速的后果可能比在干燥地面上严重得多。
为什么轮足机器人比汽车更容易进入不稳定滑移区? 汽车的轮胎接触面积大(约 150 cm^2),法向载荷大(约 3000-5000 N/轮),侧偏刚度高。轮足机器人的轮子小(接触面积约 5-15 cm^2),法向载荷低(约 30-100 N/轮),侧偏刚度相应低很多。这意味着从线性区到峰值的过渡发生在更小的滑移角上——汽车可能在 \(\alpha = 8^\circ\) 达到峰值,轮足机器人可能在 \(\alpha = 3^\circ\) 就达到峰值。控制器必须更加保守。
跨领域类比:Pacejka 曲线的形状与电路中二极管的 I-V 特性曲线类似——都有一个线性区、一个饱和区和一个可能的击穿区。线性区内可以用简单的线性模型近似,饱和区需要非线性模型,击穿区意味着系统失稳。轮足控制的目标是始终工作在线性区内,通过限制轮速变化率来避免进入饱和区。
反事实推理:如果把轮胎当成永远满足 \(v=r\omega\) 的理想约束,策略会学会用很大的轮速瞬间改变基座速度。 真机上,这些命令会变成打滑和姿态扰动。 因此训练时必须随机化滑移和限制轮加速度。
81.5 轮足仿真的三层保真度¶
轮足仿真不是越复杂越好。
应按实验目的选择保真度。
| 层级 | 接触模型 | 适合目的 | 不适合目的 |
|---|---|---|---|
| L0 理想滚动 | \(v=r\omega\) 硬约束 | 算法原型、模式逻辑 | 真机迁移 |
| L1 摩擦圆 + 滑移刚度 | 线性滑移 + 摩擦截断 | RL 训练、MPC 调参 | 高速轮胎极限 |
| L2 轮胎变形/地面软化 | 变形接触、Pacejka 或地基模型 | 高速、软地面研究 | 快速大规模训练 |
实用建议:
- MPC 原型先用 L0。
- 策略训练至少用 L1。
- 真机部署前用 L1 加强随机化。
- 高速、湿滑、沙地和长距离配送才需要 L2。
81.6 Domain Randomization 参数表¶
领域随机化不是把所有参数乱改。
它要覆盖真实硬件中不确定而又影响控制的参数。
轮足特有参数如下:
| 参数 | 示例范围 / 典型起点 | 影响 |
|---|---|---|
| 轮半径 \(r\) | 标称值 ±3-8% | 里程计比例误差 |
| 纵向摩擦 \(\mu_x\) | 0.4-1.2 | 加速和制动能力 |
| 横向摩擦 \(\mu_y\) | 0.3-1.0 | 侧滑与转弯稳定 |
| 滑移刚度 \(C_\kappa\) | 0.3-2.0 × 标称 | 轮速到地速的响应 |
| 侧偏刚度 \(C_\alpha\) | 0.3-2.0 × 标称 | 横向抗滑 |
| 轮电机延迟 | 2-20 ms | 高速命令相位滞后 |
| 腿部电机延迟 | 1-10 ms | WBC 跟踪误差 |
| 轮速测量噪声 | 0.5-5% | 里程计漂移 |
| IMU 偏置 | 低频随机游走 | 姿态估计偏移 |
| 质量 | 标称值 ±5-15% | 接触力和加速度 |
| 质心位置 | ±1-5 cm | 坡道与载荷稳定 |
| 关节摩擦 | 0.5-2.0 × 标称 | 腿部跟踪误差 |
| 地形高度噪声 | 0-5 cm | 模式切换误判 |
| 控制周期抖动 | 0-3 ms | 闭环稳定性 |
表中的数值不是通用结论。
它们只适合作为早期仿真覆盖的起点。
真实项目应根据轮胎材料、地面类型、电机带宽、通信链路和传感器日志重新标定。
如果已经有实测数据,应优先用实测分布设定中心值,再把随机化范围向两侧扩展。
随机化要分阶段。
早期训练范围太大,会学不到基本运动。
后期训练范围太小,会迁移失败。
推荐三阶段:
- 基础阶段:只随机化质量、摩擦、观测噪声。
- 鲁棒阶段:加入延迟、轮半径、滑移刚度。
- 部署阶段:加入控制周期抖动、传感器丢包和地形缺失。
81.6b 域随机化为什么有效 ⭐⭐⭐¶
上一节给了"随机化什么"的清单,但没回答一个更根本的问题:为什么把仿真参数随机搅乱,反而能让策略在真机上更稳? 直觉上,让仿真更乱应该让训练更难、效果更差才对。理解这个反直觉的机制,是从"照抄随机化表"升级到"为新平台设计随机化"的分水岭。
81.6b.1 两个互补的视角¶
域随机化(Domain Randomization, DR)的有效性可以从两个角度理解,它们互补而非互斥。
角度一(鲁棒性视角):把随机化参数 \(\xi\)(摩擦、延迟、质量等)看成对抗扰动。训练时策略 \(\pi_\theta\) 见过的不是单一环境,而是一族环境 \(\{M(\xi) : \xi \in \Xi\}\)。优化目标变成在整个参数集合上的期望回报:
策略被迫学一个对 \(\xi\) 不敏感的控制律——因为它无法预知当前 episode 的 \(\xi\) 是多少,只能学一个对所有 \(\xi\) 都还过得去的"鲁棒折中"。真机就是 \(\Xi\) 中的某一个点 \(\xi_{\text{real}}\),只要 \(\xi_{\text{real}} \in \Xi\),策略就"见过类似的"。
角度二(分布覆盖视角):把真机看成从某个真实分布 \(p_{\text{real}}(\xi)\) 采样的结果。Sim-to-Real 失败的本质是**协变量偏移(covariate shift)——训练分布 \(p_{\text{sim}}(\xi)\) 和真实分布 \(p_{\text{real}}(\xi)\) 不重叠,策略在真机遇到训练时从未见过的 \(\xi\),泛化无从谈起。DR 的作用是把 \(p_{\text{sim}}\) 撑大到**包含 \(p_{\text{real}}\):
只要这个包含关系成立,真机参数就落在训练分布内,策略不再外推而是内插。
本质洞察:这两个视角指向同一件事的两面。鲁棒性视角说"策略学会了应付变化",分布视角说"真机的变化已经被训练覆盖"。关键的设计推论是一致的——DR 的目标不是让单个仿真更像真机,而是让仿真的参数分布把真机这个点裹进去。这就是为什么"提高仿真保真度"和"域随机化"是两条不同的路:前者试图把 \(p_{\text{sim}}\) 移到 \(\xi_{\text{real}}\) 上(需要精确辨识,难且脆弱),后者只要求 \(p_{\text{sim}}\) 足够宽以覆盖 \(\xi_{\text{real}}\)(不需要知道 \(\xi_{\text{real}}\) 的精确值)。
81.6b.2 范围的两难:太窄迁移失败,太宽学不动¶
DR 范围不是越宽越好。这里有一个根本的张力,可以用上面两个视角直接解释。
- 太窄(违反分布覆盖):\(p_{\text{sim}}\) 没盖住 \(\xi_{\text{real}}\),真机参数外推,迁移失败。这是 §81.6 说"后期范围太小会迁移失败"的理论根据。
- 太宽(鲁棒折中退化):\(\Xi\) 大到包含大量真机永不出现的极端组合(如摩擦 \(\mu=0.1\) 同时滑移刚度极高),策略为了在这些虚构的极端情形下不崩,被迫牺牲正常工况的性能——这叫**保守性代价(conservatism cost)**。
最优范围是"恰好盖住 \(p_{\text{real}}\) 再留一点安全裕度"。这解释了 §81.6 强调的两条工程纪律:(1)有实测数据时优先用实测分布定中心,再向两侧扩展——这是在让 \(p_{\text{sim}}\) 对准 \(p_{\text{real}}\) 而非盲目放大;(2)分阶段递增范围——早期窄范围让策略先学会基本运动(避免一开始就承受全部保守性代价),后期再撑宽以覆盖真机。
反事实推理:如果对轮足的每个参数都用最宽范围一次性随机化会怎样?→ 策略会花大量容量去应付"摩擦 0.1 的冰面 + 20 ms 大延迟 + 质量偏差 +15%"这种真机几乎不可能同时出现的组合。结果是:仿真里的平均回报看着还行,但正常水泥地上的跟踪精度明显劣于窄范围训练的策略。这就是为什么自动域随机化(见下)要"按需扩张"而不是"一步到位拉满"。
81.6b.3 从手工范围到自动域随机化¶
手工设定每个参数的范围既费力又容易拍脑袋。近年的做法是让范围**自适应**:
- 自动域随机化(Automatic Domain Randomization, ADR):从一个窄分布开始,当策略在当前分布上的表现达标,就自动把某个维度的范围向外扩一点;表现下降则收回。本质是在"策略能力"和"分布宽度"之间做闭环——始终把范围维持在策略刚好能应付的边缘,避免一次性拉满的保守性代价。OpenAI 的机械手在体方块任务上用 ADR 把单一维度范围逐步撑开,是这一思路的代表。
- 真实到仿真辨识(Real-to-Sim / System ID):先用真机数据辨识 \(\xi_{\text{real}}\) 的中心和不确定度,把 DR 中心对准它。对轮足,这意味着先做 §81.20 的轮半径标定、§81.22b 的 Allan 方差噪声标定,把这些实测值喂回随机化范围。近期针对轮式人形的 Real-to-Sim 工作正是先用高保真仿真匹配未知动力学,再训练控制器。
- 可学习接触模型:§81.37 提到的方向——把轮地接触力建成一个从真机数据学出来的网络,只在真正不确定的方向上做鲁棒处理,而不是对所有轮胎参数都宽范围随机化。
理论-工程桥接:ADR 的"按表现自动扩张"在工程上对应一个非常具体的做法——给训练加一个**回退评测集**:固定一组覆盖真机标称工况的环境,每隔若干迭代评测,只有这组评测通过,才允许 curriculum 把随机化范围推宽。这样既享受宽范围带来的鲁棒性,又用评测集守住正常工况不退化。这正是 §81.6 三阶段递增的自动化版本。
81.6b.4 与 Ch80 Wheel-Legged-Gym 的衔接¶
回顾 Ch80(80_Wheel_Legged_Gym_RL.md):在那里我们用 Isaac Gym 风格的并行环境训练轮足策略,随机化逻辑写在环境的 reset 和 step 中——每个 episode reset 时为该并行环境采样一组 \(\xi\)(摩擦、质量、推力扰动等),写进物理引擎。当时我们关注的是"怎么写随机化代码、怎么配 curriculum"。
本节补上的是**那些随机化范围背后的原理**:Ch80 里 friction_range、added_mass_range、push_robot 这些配置项,对应的就是本节的 \(\Xi\);curriculum 逐级放开难度,对应的就是 ADR 的"按表现扩张"。换句话说,Ch80 教你**怎么实现** DR,本节教你**怎么决定 DR 的范围和节奏**。两者合起来,你才能为一个全新平台(而不是照抄 Go2-W 的配置)从零设计随机化方案。
跨领域类比:DR 与机器学习中的**数据增强(data augmentation)高度类似——都是通过人为扩大训练分布来提升泛化。相似之处:两者都不试图精确建模测试分布,而是让训练分布足够丰富以覆盖测试。不同之处:数据增强变换的是输入数据(图像旋转、加噪),DR 变换的是**环境动力学本身,而且变换后还要重新跑物理仿真才能得到新轨迹——代价远高于给图像加噪。不要把这个类比延伸到"DR 像数据增强一样几乎免费"——DR 的每个新 \(\xi\) 都意味着一遍完整的物理 rollout。
81.6c 随机化中心从哪来:参数的逐行辨识 ⭐⭐⭐¶
§81.6 的参数表给了每行的"示例范围",§81.6b 又论证了"有实测数据时优先用实测分布定中心、再向两侧扩展"。但中间缺了一步最关键的工程动作:这些中心值具体怎么从真机量出来? 这一节把随机化表里几个核心行的辨识方法补齐——它直接决定了 §81.6b 说的"让 \(p_{\text{sim}}\) 对准 \(p_{\text{real}}\)"能不能落地。
81.6c.1 为什么"辨识中心 + 随机化宽度"优于"直接拉宽"¶
先讲清动机。一个新手常见的偷懒做法是:跳过辨识,直接对每个参数用 §81.6 表里最宽的范围。这看似省事,但代价在 §81.6b.2 已经分析过——保守性代价。辨识中心值的价值是把随机化的"预算"花在刀刃上:
| 做法 | 摩擦 \(\mu\) 的处理 | 后果 |
|---|---|---|
| 不辨识,直接拉宽 | \(\mu \in [0.3, 1.2]\) 全覆盖 | 策略要同时应付冰面和橡胶地,正常水泥地性能被拖累 |
| 先辨识中心再窄随机化 | 实测水泥地 \(\mu \approx 0.8\),取 \(\mu \in [0.6, 1.0]\) | 分布裹住真机工况,宽度只用来吸收磨损/温度漂移 |
本质洞察:辨识和随机化不是二选一,而是分工——辨识负责把分布的中心对准真机,随机化负责覆盖中心周围的不确定度。辨识越准,随机化宽度就能越窄,保守性代价就越低。这是为什么工业级 Sim-to-Real 流程里,系统辨识(System Identification)和域随机化总是配套出现,而不是用随机化代替辨识。
81.6c.2 三类参数的辨识手段¶
随机化表里的参数按辨识难度分三类,手段完全不同。
第一类:可直接测量的几何/质量参数。 轮半径、连杆长度可用卡尺、卷尺直接量;整机质量可上秤;各连杆质量可在拆解时单独称量。质心和惯量较难直接测,但可以用 CAD 模型导出标称值,再用整机的摆动实验(如三线摆测惯量)校正。这类参数辨识后,随机化宽度只需覆盖批次差异和载荷变化(如 §81.6 表里质心 ±1-5 cm 主要应对载荷重分布)。
第二类:需要激励实验辨识的动力学参数。 摩擦系数、滑移刚度 \(C_\kappa\)、侧偏刚度 \(C_\alpha\) 没法静态量出来,必须让机器人做规定动作、记录响应再反推。以纵向摩擦为例的最小辨识流程:
- 在目标地面让单轮缓慢增大驱动力矩,同步记录轮速 \(\omega\)、基座速度 \(\hat v_x\)(用外部定位或视觉里程计提供地面真值)。
- 算出滑移比 \(\kappa = (r\omega - \hat v_x)/\max(|\hat v_x|, v_{\text{low}})\) 和对应的纵向力 \(F_x\)(由质量乘加速度估计)。
- 在小滑移区对 \((\kappa, F_x)\) 做线性拟合,斜率就是纵向刚度 \(C_\kappa\);继续增大力矩直到 \(F_x\) 不再上升,峰值对应 \(\mu F_z\),反推 \(\mu\)。
这恰好是 §81.3 线性滑移模型和摩擦圆约束的**逆问题**——§81.3 给的是"已知参数求力",辨识是"已知力和滑移求参数"。
第三类:执行器参数。 \(K_t\)、绕组电阻 \(R\)、库仑/粘性摩擦这些参数决定 §81.9 的速度-力矩曲线和关节摩擦行为,辨识方法在 §81.9.6 单独展开,因为它需要电机台架而非整机实验。
理论-工程桥接:注意第二类辨识必须有一个**不受打滑影响的地面速度真值** \(\hat v_x\),否则用轮速自己算滑移比是循环论证(轮速既当被测量又当参考)。这正是 §81.22c 多传感器融合要费力估 \(v_x\) 的原因,也解释了为什么摩擦辨识实验通常要架外部动捕或高精度视觉里程计——辨识阶段舍得用真机上装不起的"贵传感器",把参数量准了再喂回仿真,部署时就不再需要它。
81.6c.3 辨识结果如何写回随机化表¶
辨识完不是把范围改成一个点,而是按"中心 ± 宽度"重写 §81.6 表的对应行。宽度的来源有三个,要分别估计后叠加:
| 宽度来源 | 含义 | 典型量级 |
|---|---|---|
| 辨识本身的不确定度 | 实验噪声、拟合残差导致的中心估计误差 | 由多次重复实验的标准差给出 |
| 真机随时间的漂移 | 轮胎磨损、电机发热、电池电压下降 | 由长时间运行前后的复测差给出 |
| 个体/批次差异 | 同型号不同台机器人的离散 | 由多台机器人横向对比给出 |
反事实推理:如果辨识后把随机化宽度设成零(只用辨识中心,完全不随机化)会怎样?→ 策略会过拟合到辨识那一刻的参数。但轮胎会磨损、电机会发热、换一台机器人参数就变——任何一个偏移都让策略外推失败。所以辨识降低的是中心的偏差,随机化覆盖的是中心周围不可消除的方差,两者缺一不可。这与 §81.9.5 执行器网络"消除系统性偏差、剩余残差再随机化"是同一个分工逻辑。
81.7 观测设计¶
轮足策略常见观测:
base_angular_velocity
projected_gravity
command_velocity
joint_position
joint_velocity
wheel_velocity
previous_action
terrain_features
mode_id
轮足比纯腿足多出轮速。
但直接给轮速不够。
还应给出估计滑移特征:
如果视觉或激光里程计不可用,可以用 IMU 和状态估计器给出粗略 \(\hat v_x\)。
还可以加入:
- 最近 0.5 s 的轮速方差。
- 轮速命令和轮速反馈差。
- 轮电机电流。
- 足端接触力。
- 地形置信度。
陷阱框:不要让策略只看命令,不看执行结果
只看期望轮速,策略会以为命令总能执行。 真机上轮速饱和、延迟和打滑都会破坏这个假设。 观测中必须包含反馈量。
81.7.1 观测设计的三条原则¶
上面的清单容易被当成"抄一遍就行"。但每一项的去留都有原则,理解原则才能为新平台增删观测。
原则一:观测要能区分"命令"和"现实"。 这是上面陷阱框的本质。策略要学会应对 Sim-to-Real Gap,前提是它能**看见** Gap——也就是命令和反馈的差。光给命令轮速,策略无从知道命令有没有被执行;给了反馈轮速、电流、命令-反馈差,策略才能学会"命令发出去但没动,说明打滑了,该收力"。这条原则把 §81.2.1 的四个误差维度和观测设计连了起来:每个维度的差距,都应该有一个观测量让策略感知到。
原则二:观测要补上策略"看不见的状态"。 策略是马尔可夫的——它只根据当前观测决策。但真实系统有隐藏状态(摩擦正处于打滑临界、电机正在过热、延迟正偏大)。这些隐藏状态没法直接测,但可以用**历史**间接暴露:
previous_action:让策略知道上一步发了什么,从而感知动作的连续性、避免抖动。这一项在 Sim-to-Real 中近乎必备——它隐含了"系统有惯性、动作不能突变"的先验。- 最近 0.5 s 的轮速方差:高方差暗示打滑或地面颠簸,是一个比瞬时值更稳的滑移征兆。
- 短历史窗口(如最近 3-5 帧的关节状态):让策略隐式估计速度趋势、接触状态变化——和 §81.9.5 执行器网络用历史捕捉摩擦记忆是同一个道理。
本质洞察:观测设计的隐藏目标,是让一个马尔可夫策略**有能力在内部重建非马尔可夫的真实状态**。单帧观测下的系统对策略是部分可观测的(POMDP);加入历史和反馈,相当于把部分可观测问题"摊平"成近似可观测——策略不需要显式跑一个状态估计器,但观测里要有足够信息让它隐式地估。这解释了为什么几乎所有可部署的本体感受策略都喂历史而非单帧。
原则三:观测里的每一项都要在仿真和真机用同样的方式算出来。 这是最容易栽跟头的一条。projected_gravity(投影重力)在仿真里可以从真实姿态直接算,但真机上只能从 IMU 估计——如果仿真用真值、真机用带噪估计,策略见到的两个分布就不一致。正确做法是**仿真里也用和真机相同的估计管线**(带噪声、带延迟)产生观测,而不是用仿真特权真值。
跨领域类比:原则三与监督学习里的"训练-测试预处理必须一致"如出一辙——训练时用一套归一化、测试时用另一套,模型必然垮。相似之处:都是分布一致性问题。不同之处:监督学习的预处理是确定性变换,这里的"预处理"是一整条带噪声和延迟的状态估计管线,复现成本高得多。不要把类比简化成"减个均值除个方差"——观测的分布一致性还包括噪声特性、延迟、量化这些动态因素的一致。
81.7.2 观测归一化:训练统计必须随策略一起部署¶
策略训练时几乎总会对观测做归一化(减均值、除标准差),让各维度量级一致、加速收敛。但归一化用的**均值和方差是训练数据的统计量**——它们和网络权重一样,是模型的一部分,必须一起导出、一起部署(呼应 §81.16 的"必须一起导出的内容"清单第 3、4 项)。
如果部署端漏掉归一化、或用了错误的 \(\mu_{\text{train}}, \sigma_{\text{train}}\),网络收到的输入分布和训练时完全不同——它不会报错,只会输出垃圾动作。这是 §81.28"策略输出振荡"和 §81.24 Sim2Sim 能抓到的典型错误。
反事实推理:如果部署时用了一组"看起来差不多"的归一化统计(比如手填的整数)会怎样?→ 网络每一维输入都偏移了几个标准差,激活值进入饱和区或异常区,输出动作要么饱和要么乱跳。最隐蔽的是:在结构简单、动作范围小的任务上,错误归一化可能让机器人"看起来还能动",从而骗过架空测试,到了高速工况才暴露。所以归一化统计必须**逐字节**和训练对齐,不能凭感觉填。
81.8 动作设计¶
轮足动作空间常见三种:
| 动作形式 | 内容 | 优点 | 缺点 |
|---|---|---|---|
| 关节目标 + 轮速 | 腿部 PD 目标、轮速目标 | 容易部署 | 动力学能力有限 |
| 关节力矩 + 轮力矩 | 全部力矩 | 表达能力强 | 安全风险高 |
| 残差动作 | 基准控制器 + 策略修正 | 稳健 | 依赖基准控制器 |
实物部署推荐从第一种或第三种开始。
直接输出全部力矩只适合硬件保护完善、频率稳定、策略充分验证的平台。
动作限幅必须按模式变化。
轮模式中允许较高轮速。
足模式中轮速目标应接近零或进入阻尼。
混合模式中轮速上限随地形置信度降低。
81.8.1 三种动作空间的取舍逻辑¶
上表给了三个选项,但没说清"什么时候选哪个"。这背后是一条贯穿 Sim-to-Real 的权衡:表达能力越强的动作空间,Sim-to-Real Gap 越大、安全风险越高。
- 关节目标 + 轮速(位置/速度命令):策略输出期望位置和轮速,底层 PD / 速度环负责跟踪。最容易部署,因为底层环吸收了大部分执行器非理想性——策略不直接面对反电动势、摩擦这些细节,它们被 PD 环"挡"在外面。代价是动力学能力受限:策略无法做需要精确力矩调制的动作(如柔顺接触)。这是绝大多数轮足平台的起点。
- 关节力矩 + 轮力矩(力矩命令):策略直接输出力矩,表达能力最强,能做柔顺、能精确调制接触力。但策略此时**直接面对全部执行差距**——它命令的力矩和真机实际产生的力矩之间隔着反电动势、摩擦、电流环动态(§81.9)。这就是为什么力矩动作"安全风险高":一个在仿真理想执行器下学到的力矩策略,到真机上力矩映射全变了。要走这条路,几乎必须配 §81.9.5 的执行器网络把执行差距压下去。
- 残差动作(基准控制器 + 策略修正):动作 = 一个可靠的基准控制器输出 + 策略的小幅修正。最稳健,因为基准控制器保证了行为下限,策略只需学"在基准之上怎么改进"。
本质洞察:动作空间的选择,本质是在问"让谁来承担执行差距"。位置/速度命令把执行差距甩给底层 PD/速度环;力矩命令让策略自己扛(所以要配执行器网络);残差动作让基准控制器扛大头、策略只补小头。没有免费的午餐——表达能力是用 Sim-to-Real 难度换来的。轮足部署从位置/速度或残差起步,正是因为它们把最难建模的执行差距交给了更可靠的经典模块。
81.8.2 残差动作与 Ch70 轮足 MPC 的衔接¶
回顾 Ch70(70_轮足混合MPC.md):我们用 MPC 求解轮足的接触力和关节力矩,MPC 基于简化模型(如单刚体 + 轮地接触约束)做滚动优化。MPC 的强项是**带约束的前瞻规划**——它显式处理摩擦锥、力矩上下界、动力学约束;弱点是依赖模型精度,对未建模的滑移、地面突变反应迟钝。
残差动作正是把 MPC 的强项和 RL 的强项缝起来的接口:
MPC 提供带约束的、可解释的主控制;策略只学 MPC 处理不好的部分——未建模的滑移补偿、接触瞬间的微调、模型失配的修正。这套思路就是本目录 Ch210(210_RAMBO混合MPC_RL.md)的混合 MPC-RL 主题在动作层面的体现。
理论-工程桥接:为什么残差动作"依赖基准控制器"是优点也是约束?优点:基准 MPC 已经满足了硬约束(摩擦锥、力矩界),策略修正只要幅度受限,整体就不会违反安全约束——这给了 §81.19 安全层一个干净的工作点。约束:如果基准 MPC 本身崩了(比如模型完全失配、QP 无解),残差策略也救不回来。所以残差动作的部署前提是**基准控制器在目标工况内是可靠的**——这正是 Ch70 要先调好 MPC 的原因。
81.8.3 动作平滑:限斜率与低通的必要性¶
§81.28 把"动作低通滤波缺失"列为策略振荡的原因之一。这里讲清为什么。
策略网络是逐帧独立推理的,相邻两帧动作之间**没有平滑性保证**——观测里一点噪声就可能让输出动作跳变。真机执行器无法瞬间响应这种跳变(受 §81.9 的带宽限制),跳变会激起机械振动、加剧磨损、甚至在高速轮足上引发失稳。两种常用平滑手段:
限斜率(rate limiting):约束相邻动作的变化量不超过阈值:
\(\Delta_{\max}\) 应按物理可达性设定——轮速限斜率对应轮电机的最大角加速度,这同时呼应了 §81.4"限制轮加速度避免进入饱和滑移区"和 §81.27"加入轮速限斜率"的排查动作。
一阶低通(EMA 滤波):
\(\beta\) 越大越平滑但响应越慢。两者可叠加:先低通去高频抖动,再限斜率挡住大跳变。
⚠️ 编程陷阱:上一动作字段填错——裁剪前还是裁剪后 错误做法:观测里的
previous_action填策略网络的**原始输出**,而硬件实际执行的是**限幅/平滑后**的动作。 现象:策略以为上一步执行了 \(a^{\text{raw}}\),真机实际执行了被限幅的 \(a\),策略的"自我认知"和现实脱节,输出逐渐发散或振荡(§81.28 的隐蔽诱因)。 根本原因:训练时previous_action用的是哪个,部署时必须用同一个;多数实现训练时存的是**送进环境的最终动作**(裁剪后),部署若回填原始输出就不一致。 正确做法:明确约定previous_action= 实际下发给执行器的动作(裁剪+平滑后),训练和部署一字不差地对齐。这是 §81.16 schema 一致性要求在动作侧的体现。
81.9 执行器模型 ⭐⭐¶
轮电机不是理想速度源。理解执行器的物理限制是 sim-to-real 成功的前提。
81.9.1 BLDC 电机的电气模型¶
常见 BLDC 电机的单相等效电路可以用基尔霍夫电压方程描述:
其中 \(V\) 是端电压,\(I\) 是相电流,\(R\) 是绕组电阻,\(L\) 是绕组电感,\(K_e\) 是反电动势常数(V/(rad/s)),\(\omega\) 是转子角速度。
在稳态下(\(dI/dt = 0\)),简化为:
电磁力矩与电流的关系:
其中 \(K_t\) 是力矩常数(Nm/A)。在理想 BLDC 电机中,\(K_t = K_e\)(单位一致时),这是能量守恒的直接推论:电磁功率 \(P_{\text{elec}} = K_e \omega I\) 等于机械功率 \(P_{\text{mech}} = K_t I \omega\)。
为什么这个模型对轮足控制至关重要? 因为它揭示了速度-力矩的根本权衡。在电压限制下,最大电流随速度上升而下降:
最大力矩对应为:
这是一条从 \(\tau_{\text{stall}} = K_t V_{\max}/R\)(堵转力矩,\(\omega=0\))到零力矩(空载转速 \(\omega_{\text{no-load}} = V_{\max}/K_e\))的线性下降曲线。
| 工作点 | 速度 | 可用力矩 | 物理含义 |
|---|---|---|---|
| 堵转 | \(\omega = 0\) | \(\tau_{\text{stall}} = K_t V_{\max}/R\) | 全部电压用于驱动电流 |
| 半速 | \(\omega = \omega_{\text{no-load}}/2\) | \(\tau_{\text{stall}}/2\) | 一半电压用于克服反电动势 |
| 空载 | \(\omega_{\text{no-load}}\) | 0 | 全部电压用于维持反电动势 |
工程后果:低速时轮电机很有力,高速时轮电机扭矩明显下降。如果仿真中把轮电机最大力矩设成常数,高速策略会过于激进——它会命令轮电机在高速下产生物理上不可能的力矩。
81.9.2 减速器效应¶
轮足机器人的腿关节通常通过行星减速器或谐波减速器放大力矩。减速比为 \(N\) 时:
其中 \(\eta_{\text{gear}}\) 是减速器效率(典型值 0.7-0.95)。减速器引入三个仿真中容易遗漏的效应:
- 齿隙(Backlash):方向反转时存在 0.01-0.1 rad 的死区,导致位置控制在零速附近出现抖动
- 库仑摩擦:与速度方向有关但与速度大小无关的恒定摩擦力矩,约占额定力矩的 3-10%
- 粘性摩擦:与速度成正比的摩擦力矩,\(\tau_{\text{viscous}} = b \cdot \omega\)
完整的关节力矩模型应为:
反事实推理:如果仿真中只建模电机力矩而忽略减速器摩擦和齿隙,策略在低速精细操作时会过度自信。真机上,当策略命令关节缓慢移动时,库仑摩擦会"吃掉"一部分力矩,导致关节响应比仿真中迟钝。这在足模式下的精确站立姿态控制中尤为明显。
81.9.3 电机热模型¶
电机连续运行时温度上升会增大绕组电阻,进一步降低可用力矩。简化的一阶热模型:
其中 \(C_{\text{th}}\) 是热容量,\(R_{\text{th}}\) 是热阻。当温度升高 \(\Delta T\) 时,铜绕组电阻增大约 \(0.4\%/^\circ\text{C}\):
这意味着持续高负载运行时,电机可用力矩会逐渐下降。轮足机器人在长距离行驶(轮电机持续高速)或反复越障(腿电机持续高力矩)后,性能下降的根因往往不是控制算法退化,而是电机过热。
部署安全建议:监测电机温度,当温度超过额定值的 80% 时自动降低最大力矩命令。
81.9.4 轮电机 vs 腿电机的特性差异¶
| 特性 | 轮电机(高速低扭矩) | 腿关节电机(低速高扭矩) |
|---|---|---|
| 典型减速比 | 1:1 或 1:5 | 1:9 至 1:50 |
| 控制模式 | 速度控制为主 | 力矩控制为主 |
| 反电动势影响 | 强(高速运行) | 弱(低速运行) |
| 库仑摩擦影响 | 弱(高速时占比小) | 强(低速精确控制时显著) |
| 热问题 | 持续高速发热 | 持续高力矩发热 |
| 仿真建模优先级 | 速度-力矩曲线 > 摩擦 | 摩擦 > 速度-力矩曲线 |
81.9.5 执行器网络:当解析模型不够用 ⭐⭐⭐¶
前面四小节用解析公式建模执行器:BLDC 电气方程、减速器摩擦、热模型。这条路对轮电机(结构简单、近似速度源)够用。但对**高减速比的腿关节**,解析模型常常不够。
为什么解析模型对腿关节失效? 高减速比(1:9 到 1:50)的关节里,真实力矩响应受一堆难以解析建模的因素影响:减速器内部的弹性形变、随载荷变化的非线性摩擦、电流环控制器本身的动态、串联弹性元件(如果有)的迟滞。把这些一个个建出来既不现实也不准。这正是 ANYmal 团队在 2019 年提出**执行器网络(Actuator Network)**的动机。
核心思想:不去解析推导从命令到实际力矩的映射,而是用一个小神经网络**从真机数据学出来**。回顾本章开头反复强调的"轮电机不是理想速度源"——执行器网络是把这句话量化的工具。它的输入是关节状态的短历史,输出是实际力矩:
即用最近三步的位置误差和速度历史,预测当前实际输出力矩。历史窗口是关键——它让网络能捕捉摩擦的速度依赖、减速器的迟滞这类**有记忆的**效应,而单帧输入做不到。
残差形式(近年改进):直接让网络预测全部力矩,会让网络同时背负"建模理想 PD 部分"和"建模非理想偏差"两个任务,数据效率低。更稳的做法是**残差执行器网络**——解析部分(理想 PD 力矩)照算,网络只学剩下的偏差:
每个关节配一个独立的小网络(通常 2 层前馈)输出残差力矩。这种形式的好处是:理想行为有解析保证,网络只需建模偏差这一小块,数据需求和过拟合风险都大幅下降。一个额外的工程优势是——它**不依赖关节力矩传感器**,残差可以纯靠位置/速度历史和已知 PD 增益推出来,这对没有力矩传感器的廉价轮足平台很重要。
怎么采集训练数据? 在真机上跑多样化的激励轨迹(不同频率的正弦、阶跃、随机运动),同步记录命令、实测位置/速度、以及实测力矩(如果有力矩传感器或电流估计)。然后离线监督训练 \(f_{\text{act}}\)。训练好后,把这个网络**塞进仿真器的执行器环节**——仿真不再用理想 PD,而是用学出来的执行器网络算力矩。
本质洞察:执行器网络把执行差距(§81.2.1 的四维度之一)从"参数随机化问题"变成了"监督学习问题"。域随机化是"我不知道真实参数,所以撑宽范围把它裹进去";执行器网络是"我用真机数据直接学出真实映射,把它装进仿真"。前者处理不确定性,后者消除一部分不确定性。理想的轮足执行器建模往往两者并用——腿关节用执行器网络压掉系统性偏差,剩余的残差不确定性再用域随机化覆盖。
跨领域类比:执行器网络与系统辨识里的**Hammerstein-Wiener 模型**思路相近——都是用"已知结构 + 数据拟合的非线性块"逼近一个难以解析的动态系统。相似之处:都承认纯解析模型不够,用数据补上非线性。不同之处:Hammerstein-Wiener 有固定的串并联结构假设,执行器网络用神经网络做万能逼近器、不假设具体结构。不要把类比延伸到"执行器网络能像辨识那样给出可解释参数"——它是黑箱,换了电机或减速器就得重新采数据训练。
与执行器网络配套的策略训练范式:当仿真里装了高保真执行器网络后,常配合**特权学习(Privileged Learning)/ 教师-学生(Teacher-Student)**框架。教师策略在仿真里能访问特权信息(真实接触力、精确动力学参数、地形真值),先用 RL 学出强策略;学生策略只能看真机可得的带噪本体观测(IMU、关节编码器、轮速),通过模仿教师学会同样的行为。这套范式直接呼应 §81.7 的观测设计——学生网络的输入就是 §81.7 列的那些可部署观测。
理论-工程桥接:为什么轮足部署几乎都用学生策略而非教师策略?因为教师依赖的特权信息(如真实地面速度 \(v_x\)、精确滑移比)在真机上根本测不到——这正是 §81.22c 要费力做多传感器融合才能"估"出滑移的原因。教师在仿真里"开了上帝视角",学生必须学会在没有上帝视角时也能干活。部署到真机的永远是学生。
81.9.6 电机参数辨识实战 ⭐⭐⭐¶
§81.9.1 的速度-力矩曲线、§81.9.2 的摩擦模型都依赖一组电机参数:力矩常数 \(K_t\)、绕组电阻 \(R\)、反电动势常数 \(K_e\)、库仑摩擦 \(\tau_C\)、粘性摩擦系数 \(b\)。仿真要把执行差距建准,第一步就是把这些参数从真机量出来。这一节给出不依赖厂商 datasheet 的台架辨识流程——呼应 §81.6c 把"辨识中心"落到执行器这一类参数上,也是 §81.22b 那条"datasheet 值在真机条件下偏差 2-5 倍"教训在执行器侧的对应。
为什么不直接信 datasheet? 厂商给的 \(K_t\)、\(R\) 是在标称温度、标称电压、新电机条件下测的。装到机器人上以后:绕组温度升高使 \(R\) 增大(§81.9.3)、批次差异使 \(K_t\) 有几个百分点离散、减速器装配引入的摩擦根本不在电机 datasheet 里。辨识的目标是拿到**这台机器人此刻**的参数,而非型号的标称参数。
辨识量 \(K_t\) 与 \(R\)(堵转法)。 把电机轴机械锁死(\(\omega = 0\),反电动势项为零),施加一系列已知电压 \(V\),测量稳态电流 \(I\) 和输出力矩 \(\tau\)(用力矩传感器或已知力臂的称重):
- 由 \(V = IR\) 在多个工作点线性拟合,斜率倒数给出 \(R\)。
- 由 \(\tau = K_t I\) 线性拟合,斜率给出 \(K_t\)。
- 单位一致时 \(K_e = K_t\)(§81.9.1 的能量守恒推论),可用此关系交叉校验辨识质量——若 \(K_e\) 单独辨识值与 \(K_t\) 相差超过 5%,说明实验有系统误差。
辨识反电动势常数 \(K_e\)(空载反拖法)。 用另一台电机或手摇以已知转速 \(\omega\) 反拖被测电机,开路测端电压,\(V_{\text{open}} = K_e \omega\),多点拟合斜率即 \(K_e\)。这一步把 §81.9.1 那条"最大力矩随速度线性下降"曲线的斜率量准了。
辨识库仑与粘性摩擦(恒速扫描法)。 让关节在空载下以一系列恒定速度 \(\dot q\) 匀速运动,记录维持该速度所需的稳态力矩 \(\tau_{\text{ss}}\)。根据 §81.9.2 的摩擦模型,去掉惯性项后:
对正速度段做线性回归:截距是库仑摩擦 \(\tau_C\),斜率是粘性系数 \(b\)。正负速度分别做,可检出 §81.9.2 提到的方向不对称(齿隙、单向预紧导致)。
| 辨识量 | 方法 | 关键控制条件 | 对应仿真模型 |
|---|---|---|---|
| \(R\)、\(K_t\) | 堵转法 | \(\omega=0\) 锁轴 | §81.9.1 \(\tau_{\max}(\omega)\) |
| \(K_e\) | 空载反拖 | 已知 \(\omega\) 开路测压 | §81.9.1 反电动势项 |
| \(\tau_C\)、\(b\) | 恒速扫描 | 匀速、去惯性项 | §81.9.2 摩擦项 |
⚠️ 编程陷阱:用瞬态数据拟合稳态参数 错误做法:电压阶跃后立刻取电流值代入 \(V=IR\),或速度还在变化时就取力矩拟合摩擦。 现象:辨识出的 \(R\) 偏小、摩擦参数离散大,仿真速度-力矩曲线与真机对不上。 根本原因:\(V=IR+L\,dI/dt+K_e\omega\)(§81.9.1)里 \(L\,dI/dt\) 项在瞬态不为零,匀速假设在加减速段不成立。 正确做法:每个工作点等系统进入稳态(电流、速度都平了)再采样,每点多采几十毫秒取均值;用斜坡而非阶跃缓慢扫描工作点。
本质洞察:电机辨识的产物不止是几个数,而是一条**可信的速度-力矩可达边界**——它告诉仿真"在每个速度下,电机最多能给多大力矩"。§81.9.1 说高速力矩会掉,但掉多少由辨识出的 \(K_e\)、\(R\)、\(V_{\max}\) 共同决定。把这条真实边界装进仿真,策略才不会在训练里学到"高速猛给力矩"这种真机做不到的动作——这是把 §81.9 的理论变成可迁移训练的最后一步。
81.10 延迟建模 ⭐⭐¶
延迟是 Sim-to-Real 的核心变量。
总延迟包含:
- 传感器采样延迟。
- DDS 或 CAN 通信延迟。
- 状态估计延迟。
- 策略推理延迟。
- 控制器写入延迟。
- 电机响应延迟。
总延迟可近似:
在训练中常用延迟队列模拟:
class DelayLine:
def __init__(self, max_delay_steps):
self.buffer = []
self.max_delay_steps = max_delay_steps
def push_and_sample(self, value, delay_steps):
# 中文注释:先写入最新值,再读取若干步前的值,模拟观测或动作延迟。
self.buffer.append(value.copy())
if len(self.buffer) <= delay_steps:
return self.buffer[0]
return self.buffer[-1 - delay_steps]
训练时随机化 delay_steps。
部署时测量真实延迟。
若真实延迟超出训练范围,策略表现会明显下降。
如何测量真实延迟? 最直接的方法是"回声测试": 1. 在控制循环开始时记录高精度时间戳 \(t_1\) 2. 发送一个特征性命令(如阶跃力矩) 3. 在传感器回读中检测到响应的时间记为 \(t_2\) 4. 总延迟 \(T_{\text{total}} = t_2 - t_1\)
更精细的分段测量需要在通信链路的每个节点插入时间戳。对于典型的轮足系统(ROS 2 + EtherCAT),各段延迟的经验值如下:
| 延迟分段 | 典型值 | 变异性 |
|---|---|---|
| 传感器采样 | 0.2-0.5 ms | 低 |
| EtherCAT/CAN 通信 | 0.5-2 ms | 中(取决于总线负载) |
| DDS 传输 | 0.5-5 ms | 高(取决于 QoS 配置) |
| 状态估计计算 | 0.1-0.5 ms | 低 |
| 策略推理 | 1-10 ms | 高(取决于网络大小和硬件) |
| 命令写入 | 0.2-1 ms | 低 |
| 电机响应 | 1-5 ms | 中(取决于电机类型) |
| 典型总计 | 4-25 ms |
⚠️ 工程陷阱:训练时只随机化总延迟而不分段随机化,会遗漏一个重要效应——不同传感器的延迟可能不同。IMU 的延迟通常是 1-2 ms,而轮速编码器通过 CAN 总线传输的延迟可能是 3-5 ms。如果训练时假设所有观测同时到达,而真机上 IMU 比轮速编码器早 3 ms,策略看到的是一个"时间不一致"的观测向量——用 IMU 的当前角速度配合轮速的 3 ms 前的值。这种不一致会导致滑移估计出错。
81.10b 控制频率、decimation 与训练-部署对齐 ⭐⭐¶
§81.28 把"控制频率与训练频率不一致"列为策略振荡的头号原因,§81.16 的导出清单里"控制频率"是必须随权重一起带走的项。但前面都没讲清:控制频率到底是策略的什么属性,为什么差一点就会让策略崩? 这一节补上时序维度里最容易被低估的一环——它不是延迟(§81.10),而是策略"心跳"的快慢。
81.10b.1 策略频率是被训练"焊死"的超参数¶
一个 RL 策略不是一个纯函数,它是在某个固定控制周期 \(\Delta t_{\text{ctrl}}\) 下训练出来的。这个周期悄悄进入了策略的每一个假设:
- 动作的物理含义:策略输出"这一拍要达到的关节目标",下一拍才会再决策。周期是 20 ms 还是 50 ms,决定了同一个目标动作对应的实际速度完全不同。
previous_action的时间跨度:§81.7.1 说previous_action隐含"系统有惯性"。这个惯性的尺度就是 \(\Delta t_{\text{ctrl}}\)——上一拍离现在多久,直接决定这一项携带的信息。- 历史窗口的覆盖时长:§81.7.1 的短历史窗口(3-5 帧)在 50 Hz 下覆盖 60-100 ms,在 100 Hz 下只覆盖 30-50 ms。同样的帧数,覆盖的物理时间随频率变。
不是 X 而是 Y:控制频率不是"跑得多快的工程选择",而是**策略动力学假设的一部分**。换频率不是"让同一个策略跑快点或跑慢点",而是把策略丢进了一个它从没见过的时间尺度——所有关于"一拍能改变多少状态""上一拍多久以前"的内部经验全部失效。这就是为什么 §81.28 排查第一步不是调参,而是"确认部署频率严格等于训练频率"。
81.10b.2 decimation:仿真步长与控制周期的解耦¶
训练里有两个不同的时间步长,新手极易混淆:
| 步长 | 符号 | 含义 | 典型值 |
|---|---|---|---|
| 物理仿真步长 | \(\Delta t_{\text{sim}}\) | 物理引擎积分一步的时间 | 0.005 s(200 Hz) |
| 控制周期 | \(\Delta t_{\text{ctrl}}\) | 策略两次决策的间隔 | 0.02 s(50 Hz) |
两者通过 decimation(降采样系数) 联系:
含义是:物理引擎以高频积分(保证接触、积分稳定),但策略每隔 decimation 个物理步才决策一次,中间的物理步用**同一个策略动作**驱动底层 PD。上例 decimation = 4 表示策略 50 Hz、物理 200 Hz,每个策略动作被底层 PD 连续执行 4 个物理步。
为什么要解耦而不让策略直接 200 Hz? 两个原因:(1)物理积分需要小步长才稳(§81.5 接触、§81.9 执行器都对步长敏感),但策略 200 Hz 决策既无必要也训不动——神经网络推理在真机上跑不到 200 Hz(§81.10 推理延迟 1-10 ms);(2)50 Hz 决策 + 200 Hz 底层 PD 跟踪,正好对应 §81.15 的真机分层(策略 50 Hz、WBC/PD 500-1000 Hz)。decimation 在训练里就预演了真机的频率分层。
理论-工程桥接:decimation 把 §81.15b.4 的"频率解耦"提前搬进了训练。真机上策略 50 Hz、控制环 1 kHz,靠双缓冲共享最新动作;训练里策略每 decimation 步决策一次、中间物理步复用同一动作——两者是同一件事在仿真和真机的两个化身。正因为训练时就是"一个策略动作管 decimation 个底层步",部署时"一个策略动作管若干个控制周期"才不会让策略意外。如果训练 decimation 和真机的策略/控制频率比对不上,这个预演就白做了。
81.10b.3 改频率必须同步改什么¶
§81.6 的耦合表里写过"sim.dt 改了必须同步更新 decimation"。这里讲清连锁反应。一旦改动 \(\Delta t_{\text{sim}}\)、decimation 或目标控制频率中的任何一个,下面这些量都要重新对齐:
- decimation 要反向调整,保证 \(\Delta t_{\text{ctrl}}\) 不变——除非你**故意**要改策略频率(那就得重训)。
- 动作限斜率 \(\Delta_{\max}\)(§81.8.3):限斜率是"每个控制周期允许的最大变化量",周期变了,同样的物理加速度上限对应的 \(\Delta_{\max}\) 也要变。
- 延迟的步数表示(§81.10 的
delay_steps):延迟是物理时间(毫秒),换算成步数要除以步长。步长变了,同样 5 ms 延迟对应的步数就变了。 - 奖励里的速率惩罚项:动作变化率、能耗这类按"每步"累加的惩罚,其尺度随频率变。
⚠️ 配置陷阱:只改仿真步长,忘了同步 decimation 错误做法:为了让接触更稳,把 \(\Delta t_{\text{sim}}\) 从 0.005 调到 0.0025(物理 400 Hz),decimation 仍保持 4。 现象:策略控制频率从 50 Hz 悄悄变成 100 Hz,训练曲线看似正常,但导出的策略在真机 50 Hz 下振荡(§81.28),或在真机 100 Hz 下因推理跟不上而周期丢失(§81.30)。 根本原因:\(f_{\text{ctrl}} = f_{\text{sim}}/\text{decimation}\),改了分子不改分母,控制频率被动翻倍,而策略的所有时间尺度假设是按 50 Hz 焊死的。 正确做法:改 \(\Delta t_{\text{sim}}\) 后立刻把 decimation 调到 8 以维持 50 Hz;并把这个值写进 §81.16 导出清单,确保部署端用同一频率。检查方法:导出前打印 \(f_{\text{sim}}/\text{decimation}\),与部署端控制环频率逐位核对。
81.11 轮足硬件平台速览¶
| 平台 | 结构 | 质量 | 速度 | 低级控制 | 教学定位 |
|---|---|---|---|---|---|
| Go2-W | 四足 + 4 轮 | 约 15 kg | 约 2.5 m/s | 版本相关 | 轻量轮足入门 |
| B2-W | 重载四足 + 4 轮 | 约 75 kg | 约 5.5 m/s | 更强 | 工业重载 |
| Tron1-WF | 轮式双足 | 约 20 kg | 中高速 | SDK 完整 | 双足轮腿 |
| Upkie | 开源双轮腿 | 约 5-6 kg | 低中速 | 扭矩可控 | 教学实验 |
| W1 | 四轮足 | 公开资料有限 | 中高速 | 平台相关 | 前沿观察 |
硬件选择原则:
- 学控制理论:Upkie 类开源平台最透明。
- 学商用 SDK:Unitree 生态更接近真实部署。
- 学高速重载:B2-W 类平台更接近工业场景。
- 学双足平衡:Tron1-WF 或 Upkie 更直接。
- 学移动操作:轮足底盘加臂会显著增加安全要求。
81.12 SDK 接口分层¶
任何轮足硬件接口都应分成四层:
硬件通信层
│ CAN / EtherCAT / DDS / UDP
▼
设备抽象层
│ joint state / wheel state / imu / battery
▼
控制接口层
│ torque / velocity / position / mode command
▼
安全与策略层
│ limit / watchdog / emergency stop / policy output
不要让策略节点直接调用厂商 SDK。
策略输出应先经过安全裁剪和控制接口转换。
这样做有三个好处:
- 仿真和真机可以共用上层代码。
- 厂商 SDK 改动不会影响策略。
- 安全层可独立测试。
81.13 ros2_control 轮足接口设计¶
轮足机器人通常用 SystemInterface。
原因是腿关节、轮电机、IMU 和电池状态常通过同一个底层通信栈同步。
状态接口建议:
leg_joint_i/position
leg_joint_i/velocity
leg_joint_i/effort
wheel_i/position
wheel_i/velocity
wheel_i/effort
imu/angular_velocity
imu/linear_acceleration
battery/voltage
motor_i/temperature
命令接口建议:
leg_joint_i/effort
leg_joint_i/position
leg_joint_i/kp
leg_joint_i/kd
wheel_i/velocity
wheel_i/effort
wheel_i/brake
system/mode
system/estop
命令接口不能无限开放。
同一时刻应明确由哪个控制器拥有写权限。
轮速控制器和腿部力矩控制器可以同时运行。
但两个控制器不能同时写同一个关节力矩。
81.14 SystemInterface 框架¶
#include <algorithm>
#include <array>
#include <string>
#include <vector>
class WheelLeggedHardware {
public:
bool configure(const std::string& device_name) {
// 中文注释:非实时路径,连接硬件、分配缓冲、读取参数。
device_name_ = device_name;
connected_ = true;
return connected_;
}
bool activate() {
// 中文注释:使能电机前,先把命令同步到当前状态,避免突跳。
for (size_t i = 0; i < leg_pos_.size(); ++i) {
leg_cmd_pos_[i] = leg_pos_[i];
leg_cmd_tau_[i] = 0.0;
}
for (double& v : wheel_cmd_vel_) {
v = 0.0;
}
active_ = true;
return true;
}
bool read(double now_s, double period_s) {
// 中文注释:实时路径,只做硬件读取和固定大小数组拷贝。
(void)now_s;
(void)period_s;
if (!connected_) {
return false;
}
// 实际工程中这里读取 SDK 帧,并更新 leg_pos_ / wheel_vel_ / imu_。
return true;
}
bool write(double now_s, double period_s) {
// 中文注释:实时路径,发送已经裁剪过的命令。
(void)now_s;
(void)period_s;
if (!active_) {
return false;
}
clampCommands();
// 实际工程中这里打包 SDK 命令帧。
return true;
}
private:
void clampCommands() {
for (double& tau : leg_cmd_tau_) {
// 中文注释:示例限幅,真实数值应来自电机和减速器规格。
tau = std::clamp(tau, -120.0, 120.0);
}
for (double& vel : wheel_cmd_vel_) {
// 中文注释:示例限幅,真实数值应来自轮电机和轮胎安全包络。
vel = std::clamp(vel, -60.0, 60.0);
}
}
std::string device_name_;
bool connected_ = false;
bool active_ = false;
std::array<double, 12> leg_pos_{};
std::array<double, 12> leg_vel_{};
std::array<double, 12> leg_tau_{};
std::array<double, 4> wheel_pos_{};
std::array<double, 4> wheel_vel_{};
std::array<double, 12> leg_cmd_pos_{};
std::array<double, 12> leg_cmd_tau_{};
std::array<double, 4> wheel_cmd_vel_{};
};
这个框架省略了 ros2_control 继承细节。
核心思想是:
- 配置在非实时路径。
- 读写在实时路径。
- 命令发送前必须裁剪。
- 激活时命令同步当前状态。
- 失联时不继续发送旧命令。
81.15 控制器组合¶
常见控制器组合如下:
| 控制器 | 频率示例 / 典型起点 | 输出 | 使用场景 |
|---|---|---|---|
| JointStateBroadcaster | 50-200 Hz | 状态话题 | 可视化和记录 |
| LegTorqueController | 500-1000 Hz | 腿关节力矩 | WBC/MPC |
| WheelVelocityController | 200-1000 Hz | 轮速 | 轮模式 |
| WheelDampingController | 500-1000 Hz | 轮阻尼力矩 | 足模式 |
| PolicyController | 50-200 Hz | 目标或残差 | 学习策略 |
| SafetyController | 500-1000 Hz | 裁剪和急停 | 最终保护 |
这些频率不是硬规则。
最终设置要服从硬件通信周期、状态估计延迟、CPU 预算和控制器稳定性。
控制器频率不必全部相同。
但最终硬件写入频率应稳定。
策略 50 Hz 输出目标。
WBC 500 Hz 跟踪。
硬件 500 Hz 或 1 kHz 写入。
这是常见分层。
81.15b 实时系统与通信确定性 ⭐⭐⭐¶
§81.15 说"硬件写入频率应稳定",§81.30 把"控制周期丢失"列为故障。但这两处都没回答:凭什么一台跑着 Linux、ROS 2、还要做神经网络推理的计算机,能保证每 1 ms 准时发一帧控制命令? 这一节补上时序维度(§81.2.1 四维度之一)的工程根基。
81.15b.1 实时不是"快",是"准时"¶
初学者最大的误解:以为实时系统 = 高性能系统。
不是 X 而是 Y:实时(real-time)不是"算得快",而是"在确定的时间窗口内一定完成"。一个平均延迟 0.1 ms 但偶尔卡 50 ms 的系统,**不如**一个稳定 1 ms 永不超过 1.2 ms 的系统适合做控制。控制律的稳定性分析假定采样周期 \(T\) 是常数;周期一旦抖动,相当于在闭环里注入了时变延迟,相位裕度被悄悄吃掉。一次 50 ms 的卡顿,对 1 kHz 环就是丢了 50 个控制周期——足以让一个高速轮足甩出去。
关键指标因此不是吞吐量,而是**最坏情况延迟(Worst-Case Execution Time / 抖动 jitter)**。我们要的是延迟分布的**长尾**够短,而不是均值够小。这就是 §81.30 排查第一步要"记录每周期耗时直方图"的原因——均值骗人,直方图的右尾才是真相。
81.15b.2 三个延迟来源与对策¶
把一个控制周期拆开,确定性可能在三处被破坏。
| 来源 | 为什么破坏确定性 | 对策 |
|---|---|---|
| 操作系统调度 | 普通 Linux 内核不可抢占,控制线程可能被内核态长任务(如网络中断、缺页)推迟 | PREEMPT_RT 实时内核 + 实时优先级(SCHED_FIFO)+ CPU 隔离 |
| 内存管理 | 缺页中断、动态分配(malloc/new)触发不可预测的内核操作 |
启动时预分配 + mlockall 锁内存 + 实时路径零分配(呼应 §81.14) |
| 通信总线 | 命令到达各电机的时刻不一致、有抖动 | EtherCAT 分布式时钟(DC)/ CAN-FD 时间触发 |
PREEMPT_RT 把 Linux 内核的大部分不可抢占段改造成可抢占,使高优先级实时线程能及时获得 CPU。配合 CPU 隔离(isolcpus 把某个核从普通调度器划走,只跑控制线程)和中断亲和性(把网卡中断绑到别的核),可以把控制线程的调度抖动压到微秒级。开源的 IgH EtherCAT Master 协议栈正是依赖 PREEMPT_RT 内核才能发挥低抖动潜力;在 CPU 隔离下,1 ms 和 125 µs 同步周期都能做到微秒级通信抖动控制。
理论-工程桥接:§81.14 反复强调"实时路径不能动态分配内存",这里给出根因——
new/malloc在最坏情况下会向内核要新内存页,触发缺页处理,耗时不可预测。控制律推导假设的常数周期 \(T\),在实现层面就是靠"实时路径零分配 + 锁内存 + 实时调度"这三件事共同兑现的。任何一件没做,直方图右尾就会冒出来。
81.15b.3 EtherCAT 分布式时钟:让所有电机同一时刻动作¶
多电机系统有一个容易被忽视的确定性问题:即使主控准时发出命令,命令**到达每个电机的时刻**也未必一致——总线上离主站近的从站先收到,远的后收到。对高速轮足,左右轮命令差几百微秒就可能引入可观的偏航扰动。
EtherCAT 的**分布式时钟(Distributed Clocks, DC)**解决这个问题:所有从站维护一个同步的本地时钟(同步精度优于 100 ns),命令里带一个"在哪个时刻执行"的时间戳,所有从站到点同时动作。这把"通信顺序"和"执行时刻"解耦——不管帧先到后到,执行都对齐到同一个 DC 时刻。实测在 1 kHz 下,DC 模式可把同步误差压到纳秒级。
跨领域类比:EtherCAT DC 和分布式系统里的**逻辑时钟同步(如 PTP/NTP)**思路一致——都是让物理上分离的节点对"现在几点"达成共识,再据此协调动作。相似之处:都靠一个主时钟分发、从节点补偿传播延迟和漂移。不同之处:EtherCAT DC 工作在微秒-纳秒尺度且硬件辅助,PTP/NTP 在毫秒尺度且纯软件。不要把类比延伸到"用 NTP 同步就能做电机控制"——NTP 的毫秒级精度对 1 kHz 控制环远远不够。
81.15b.4 推理与控制解耦——为什么 50 Hz 策略能配 1 kHz 硬件¶
回到 §81.15 的分层:"策略 50 Hz,WBC 500 Hz,硬件 1 kHz"。为什么频率可以不同?因为神经网络推理的延迟**长尾很重**(§81.10 表里推理延迟 1-10 ms,变异性"高"),绝不能放进硬实时路径。正确架构是**生产者-消费者解耦**:
- 策略推理线程(非实时或软实时):慢慢算,算完把最新动作写进一个**无锁双缓冲**。
- 硬实时控制线程(1 kHz、
SCHED_FIFO、CPU 隔离):每周期只**读**双缓冲里的最新策略快照,做插值/WBC 跟踪,发命令。绝不等待推理完成。
这样推理偶尔卡 8 ms,控制线程照样 1 kHz 准时跑——它只是连续几个周期读到同一个略旧的策略动作,而不是被推理阻塞。这正是 §81.30 排查里"把策略推理放到独立线程、控制线程只读最新策略快照"的架构依据。
本质洞察:高频硬实时和重计算软件之间的矛盾,不靠"把推理优化得更快"来解决(再快也有长尾),而靠**频率解耦 + 共享最新快照**来解决。控制环的确定性来自它"从不等待任何不确定的东西"——它只读已经算好的结果。理解这一点,就理解了为什么所有真机部署架构都把"快但抖"的推理和"慢但准"的控制环分到两个线程。
81.16 ONNX/LibTorch 部署流程¶
策略部署链路:
训练环境
│ 导出网络权重、归一化统计、动作尺度
▼
离线验证
│ 对比 PyTorch 与 ONNX 输出
▼
sim2sim
│ Isaac/MuJoCo/Gazebo 之间交叉验证
▼
硬件空载回放
│ 机器人架空,轮子离地
▼
低速平地
│ 限速、保护绳、急停
▼
复杂地形
│ 渐进扩大速度和地形难度
必须一起导出的内容:
- 网络结构。
- 权重。
- 观测均值。
- 观测方差。
- 动作均值或比例。
- 观测顺序。
- 动作顺序。
- 控制频率。
- 延迟假设。
- 模式编码。
陷阱框:观测顺序错误比网络精度低更危险
如果训练时第 10 维是左前轮速,部署时第 10 维变成右后轮速,网络不会报错。 它会输出看似合理但物理含义错误的动作。 因此观测向量必须有机器可读的 schema。
81.17 观测 schema 示例¶
observation_schema:
frequency_hz: 100
fields:
- name: base_ang_vel_x
unit: rad/s
index: 0
- name: base_ang_vel_y
unit: rad/s
index: 1
- name: base_ang_vel_z
unit: rad/s
index: 2
- name: projected_gravity_x
unit: none
index: 3
- name: projected_gravity_y
unit: none
index: 4
- name: projected_gravity_z
unit: none
index: 5
- name: command_vx
unit: m/s
index: 6
- name: command_vyaw
unit: rad/s
index: 7
- name: mode_id
unit: enum
index: 8
动作 schema 也同样需要。
不要只在代码中隐式约定。
81.18 轮足真机部署分级¶
分级测试可降低风险。
| 等级 | 条件 | 目标 | 通过标准 |
|---|---|---|---|
| L0 | 无硬件 | 离线推理 | 输出无 NaN |
| L1 | 仿真 | 策略闭环 | 不跌倒 |
| L2 | 架空 | 轮和腿空载 | 命令方向正确 |
| L3 | 支撑架 | 部分接地 | 力矩不过流 |
| L4 | 低速平地 | 保护绳 | 可急停 |
| L5 | 中速平地 | 人员隔离 | 跟踪误差可控 |
| L6 | 坡道/碎石 | 限速 | 无打滑失控 |
| L7 | 综合任务 | 完整安全流程 | 可复现 |
不要跳级。
尤其不要从仿真直接进入中高速复杂地形。
81.19 急停与看门狗¶
轮足机器人速度高。
急停设计必须覆盖软件和硬件。
软件看门狗:
class CommandWatchdog {
public:
void tick(double now_s) {
if (now_s - last_command_s_ > timeout_s_) {
safe_stop_ = true;
}
}
void receiveCommand(double now_s) {
last_command_s_ = now_s;
safe_stop_ = false;
}
bool shouldStop() const { return safe_stop_; }
private:
double last_command_s_ = 0.0;
double timeout_s_ = 0.05;
bool safe_stop_ = true;
};
硬件急停:
- 物理按钮切断驱动使能。
- 远程急停通道独立于主控制网络。
- 电机驱动器过流保护独立存在。
- 电池 BMS 保护独立存在。
- 机器人倾倒检测直接进入制动或断使能。
软件急停不能替代硬件急停。
硬件急停不能替代软件降级。
两者职责不同。
81.20 标定:轮半径¶
轮半径误差会直接变成速度比例误差。
若真实半径为 \(r+\Delta r\),而控制器使用 \(r\),轮速里程计速度误差:
相对误差:
半径误差 5% 意味着里程计速度误差 5%。
标定方法:
- 在平整高摩擦地面直行固定距离。
- 用外部定位或卷尺测量真实距离。
- 记录轮编码器积分角度。
- 估计:
- 多次往返取平均。
- 分左右轮分别估计。
81.21 标定:轮速方向与关节方向¶
方向错误是最常见的硬件接入错误之一。
测试步骤:
- 机器人架空。
- 单独给左前轮正速度。
- 确认轮子向预期方向旋转。
- 记录编码器是否正增长。
- 逐个轮子重复。
- 给每个腿关节小幅正目标。
- 确认运动方向与 URDF 关节轴一致。
- 若方向不一致,优先修正 URDF 或硬件映射,不要在策略里临时取负。
方向错误会在闭环中表现为:
- 一给速度就原地旋转。
- 轮速反馈与命令符号相反。
- 策略输出迅速饱和。
- WBC 关节力矩反向增大误差。
81.22 标定:IMU 外参¶
IMU 方向错误会破坏姿态反馈。
投影重力观测常用于策略输入:
若 IMU 外参错了,策略会以为机器人在倾斜。
测试方法:
- 机器人静止平放。
- 读取加速度方向。
- 抬起前端,检查 pitch 符号。
- 抬起左侧,检查 roll 符号。
- 原地转动,检查 yaw 角速度符号。
- 与 URDF 中 imu link 的坐标系对齐。
81.22b Allan 方差与传感器噪声表征 ⭐⭐⭐¶
为什么需要 Allan 方差¶
轮足机器人的状态估计依赖 IMU 和轮速编码器。这些传感器的噪声不是简单的白噪声——它们包含多种频率成分,每种成分对控制的影响不同。Allan 方差(Allan Variance)是表征惯性传感器噪声特性的标准工具,它能把不同类型的噪声分离出来。
回顾 SLAM 章节的 IMU 噪声模型:陀螺仪和加速度计的误差通常分为两类——角度/速度随机游走(高频白噪声积分产生)和偏置不稳定性(低频偏置漂移)。在 SLAM 中,这些参数用于初始化状态估计器(如 EKF 的过程噪声矩阵 \(\mathbf{Q}\))。在轮足控制中,它们同样重要——偏置漂移会导致姿态估计缓慢偏移,而白噪声会导致力矩命令抖动。
Allan 方差的计算方法¶
给定传感器在静止条件下采集的 \(N\) 个样本 \(\{y_1, y_2, \ldots, y_N\}\),采样间隔 \(\tau_0\),Allan 方差定义为:
其中 \(\bar{y}_k\) 是第 \(k\) 个长度为 \(\tau = m \tau_0\) 的时间段内的平均值,\(M = \lfloor N/m \rfloor\) 是段数。
在 \(\log \sigma_A\) vs \(\log \tau\) 的图上,不同噪声类型表现为不同斜率:
| 噪声类型 | 斜率 | 物理来源 | 对控制的影响 |
|---|---|---|---|
| 角度/速度随机游走 (ARW/VRW) | \(-1/2\) | 传感器内部热噪声 | 高频力矩抖动 |
| 偏置不稳定性 (BI) | 0(谷底) | 电子元件漂移 | 长时间姿态偏移 |
| 速率随机游走 | \(+1/2\) | 温度变化等环境因素 | 超长时间偏置发散 |
实用标定流程¶
- 将机器人静止放置在平坦地面上,启动 IMU 数据记录
- 记录至少 2 小时的静态数据(越长越好,能观察到更低频的噪声)
- 用 Python 的
allan_variance库或 MATLAB 的allanvar函数计算 Allan 方差 - 在对数坐标图上读取 ARW(\(\tau = 1\) s 处的值)和 BI(谷底值)
- 将 ARW 和 BI 填入状态估计器的噪声参数
"""
Allan 方差计算示例(教学版,省略数据加载细节)。
"""
import numpy as np
def compute_allan_variance(data, dt, max_cluster_size=None):
"""
中文注释:计算 Allan 方差。
data: 静态采集的传感器数据序列。
dt: 采样间隔(秒)。
返回: (tau, sigma_a) 用于绘制 Allan 方差图。
"""
N = len(data)
if max_cluster_size is None:
max_cluster_size = N // 4
taus = []
sigmas = []
m = 1
while m < max_cluster_size:
tau = m * dt
# 中文注释:把数据分成长度为 m 的段,计算每段均值。
n_segments = N // m
segments = data[:n_segments * m].reshape(n_segments, m)
averages = segments.mean(axis=1)
# 中文注释:Allan 方差 = 相邻段均值差的方差的一半。
diff = np.diff(averages)
sigma_sq = 0.5 * np.mean(diff ** 2)
taus.append(tau)
sigmas.append(np.sqrt(sigma_sq))
m = int(m * 1.2) + 1 # 对数均匀采样
return np.array(taus), np.array(sigmas)
轮速编码器的 Allan 方差¶
Allan 方差不仅适用于 IMU,也适用于轮速编码器。轮速编码器的主要噪声来源包括:
- 量化噪声:编码器分辨率有限,低速时速度估计跳变
- 电磁干扰:电机高速运行时产生的 EMI 可能引起编码器计数错误
- 机械振动:减速器齿轮啮合产生的周期性振动叠加在编码器信号上
通过 Allan 方差分析,可以确定轮速编码器在不同时间尺度上的噪声水平,从而合理设置轮速里程计在多传感器融合中的权重。
⚠️ 工程陷阱:很多轮足项目直接复用 IMU 厂商给出的噪声参数(datasheet 值)。但 datasheet 值是在理想条件下测量的——恒温、无振动、无电磁干扰。轮足机器人运行时,电机振动和电磁干扰会使实际噪声比 datasheet 高 2-5 倍。必须在机器人实际运行条件下重新标定。
81.22c 滑移估计的多传感器融合 ⭐⭐⭐¶
问题定义¶
轮足控制需要实时估计滑移状态:轮子是在正常滚动,还是在打滑?打滑有多严重?哪个方向在打滑?
直接测量滑移比需要地面速度 \(v_x\),但地面速度不能直接测量(没有传感器安装在接触点上)。因此必须通过多传感器融合间接估计。
可用传感器及其信息¶
| 传感器 | 直接测量量 | 与滑移的关系 | 缺点 |
|---|---|---|---|
| 轮速编码器 | 轮轴角速度 \(\omega\) | \(v_{\text{wheel}} = r\omega\),打滑时偏大 | 不能区分滚动和打滑 |
| IMU 加速度计 | 基座加速度 \(a_b\) | 积分得速度,不受打滑影响 | 漂移快,不适合长时间积分 |
| IMU 陀螺仪 | 基座角速度 \(\omega_b\) | 转弯时提供偏航速率 | 偏置漂移影响长时间估计 |
| 视觉里程计 | 基座位移/速度 | 不受打滑影响,提供地面真值 | 延迟大(30-100 ms),遮挡时丢失 |
| LiDAR 里程计 | 基座位移/速度 | 不受打滑影响 | 计算量大,结构化环境依赖 |
| 足端力传感器 | 接触力 | 侧向力突增暗示打滑 | 只在足模式下可用 |
简单融合方案:轮速 + IMU 互补滤波¶
最实用的方案是把轮速里程计(低频可靠)和 IMU 积分(高频可靠)做互补滤波:
其中 \(\alpha\) 是融合权重。正常滚动时 \(\alpha\) 接近 1(信任轮速);打滑检测触发时 \(\alpha\) 降低(更信任 IMU)。
打滑检测的简单指标:
当 \(\text{slip\_indicator}\) 超过阈值时,降低 \(\alpha\)。阈值应根据 Allan 方差分析的传感器噪声水平来设定——太低会频繁误报,太高会漏检真实打滑。
本质洞察:滑移估计的核心不是"精确计算滑移比",而是"判断轮速里程计还能不能信"。一旦判断不能信,状态估计器应该降低轮速权重,让 IMU 和视觉接管。这个判断的时效性比精度更重要——晚 100 ms 检测到打滑,控制器可能已经发出了错误的命令。
81.23 日志设计 ⭐⭐¶
真机调试的生命线是日志。
最小日志字段:
| 类型 | 字段 |
|---|---|
| 时间 | 控制周期时间戳、实际周期 |
| 状态 | 关节位置、关节速度、轮速、IMU |
| 命令 | 策略动作、裁剪后动作、硬件命令 |
| 模式 | 当前模式、目标模式、切换原因 |
| 安全 | 急停、过流、过温、通信状态 |
| 估计 | 基座速度、滑移估计、里程计误差 |
| 地形 | 坡度、粗糙度、置信度 |
日志频率:
- 控制内环关键量:200-1000 Hz。
- 策略输入输出:策略频率。
- 地形和视觉特征:10-30 Hz。
- 诊断状态:1-10 Hz。
不要把所有数据都发 ROS topic 后再录。
高频控制量应使用实时安全的环形缓冲或二进制日志。
81.24 Sim2Sim 验证¶
策略不要只在训练仿真器中验证。
常见流程:
- 在训练环境评估。
- 导出策略。
- 在 MuJoCo 中回放。
- 在 Gazebo 或 Isaac Sim 中回放。
- 对比轨迹、速度、关节命令和轮速。
Sim2Sim 能发现:
- URDF/MJCF 惯量不一致。
- 关节轴方向不一致。
- 轮半径配置不一致。
- 控制频率不一致。
- 接触参数过度依赖某个引擎。
- 观测归一化在部署端漏掉。
Sim2Sim 不是为了证明真机一定成功。
它是为了在上机前消灭显而易见的接口错误。
81.25 与模式切换的耦合¶
第 80 章(100_模式切换.md)讲轮 / 足 / 混合模式切换。
本章解释为什么硬件会反过来影响切换。
轮电机温度高时,轮模式应被限制。
轮速编码器异常时,轮模式应被禁用。
地面摩擦估计低时,轮模式速度包络应降低。
腿部电机过温时,足模式连续越障能力应降低。
电池电压低时,最大加速度应降低。
这说明模式选择不是纯地形问题。
它是地形、任务、硬件健康和能量状态的联合决策。
81.26 常见故障:一落地就乱跑¶
现象:
- 架空测试正常。
- 落地后机器人突然向一侧冲。
- 轮速命令不大,但真实运动异常。
原因:
- 轮速方向映射错误。
- 左右轮半径或符号不一致。
- IMU yaw 角速度符号错误。
- 策略动作顺序和硬件命令顺序不一致。
- 轮模式下腿部姿态目标导致接触法向偏斜。
排查:
- 架空逐轮测试方向。
- 低速开环直行 1 m。
- 比较左右轮编码器积分。
- 用外部定位测量实际轨迹。
- 检查动作 schema 和硬件映射。
- 固定腿姿态,只测轮控。
- 再加入腿部姿态控制。
81.27 常见故障:仿真能过坡,真机打滑¶
原因:
- 仿真摩擦过高。
- 没有随机化横向摩擦。
- 轮胎接触面积与点接触差异大。
- 坡道材料不同。
- 轮速加速度过大。
- 策略没有滑移观测。
排查:
- 降低仿真摩擦重跑。
- 添加轮速限斜率。
- 记录滑移比估计。
- 加入 IMU 加速度与轮速不一致检测。
- 坡道低速开始,逐步增速。
- 若坡道湿滑,切换 HYBRID 或 LEG。
81.28 常见故障:策略输出振荡¶
原因:
- 控制频率和训练频率不一致。
- 观测延迟超出训练范围。
- 动作低通滤波缺失。
- 观测归一化统计错误。
- 上一动作字段没有正确填充。
处理:
- 确认部署频率等于训练频率。
- 打印策略输入向量前 10 秒统计。
- 对比训练环境的均值和方差。
- 添加动作限斜率。
- 检查上一动作是否使用裁剪前还是裁剪后动作。
- 在仿真中复现真实延迟。
81.29 常见故障:轮速里程计漂移¶
原因:
- 轮半径未标定。
- 地面打滑。
- 编码器分辨率或比例错误。
- 轮胎磨损。
- 载荷变化导致轮胎有效半径变化。
处理:
- 标定轮半径。
- 与视觉/激光里程计对比。
- 根据滑移估计调整轮里程计权重。
- 低摩擦地面降低轮里程计信任度。
- 长距离任务必须融合外部定位。
81.29b 常见故障:轮足接触切换抖动与突发打滑¶
这是轮足**独有**、纯腿足和纯轮式都不会单独出现的故障——它发生在轮接触和足接触的边界上。§81.25 讲了模式切换受硬件健康影响,§81.8 讲了动作限幅按模式变化,本节把这两者在真机上的失败形态摊开。
现象:
- 在轮模式和足模式的过渡瞬间(如轮抬起转为足支撑、或足落地转为轮滚动),机器人姿态突然抖一下,严重时甩尾或前扑。
- 混合模式下走过软硬交界(水泥到地毯、平地到碎石),轮子瞬间打滑后又抓地,基座速度出现尖峰。
- 日志里接触力在切换帧出现脉冲,轮速估计和 IMU 速度在切换前后短暂背离。
原因(按 §81.2.1 四维度归类):
- 动力学维度:切换瞬间接触模型从"滚动约束"突变为"静摩擦点接触"(或反向),\(v=r\omega\) 假设在这一帧失效——轮还在转,接触却已变成足式静止点,残余轮速直接转化为冲击。
- 时序维度:接触状态的检测有延迟(力传感器/接触估计滞后几毫秒),控制器在"已经切换"和"以为还没切换"之间用错了接触假设。
- 感知维度:切换帧轮速里程计和 IMU 速度的融合权重(§81.22c 的 \(\alpha\))没及时调整,状态估计在切换点跳变。
- 执行维度:足模式要求轮进入阻尼/接近零速(§81.8),但轮电机从高速降到零有带宽限制(§81.9),降速不够快时残余轮速破坏足接触。
排查:
- 在日志里对齐"接触状态切换时刻"和"姿态抖动时刻",确认抖动是否锁定在切换帧——若是,问题在切换逻辑而非地形。
- 检查切换是否瞬时硬切:硬切(接触假设一帧突变)几乎必然抖。改为带过渡窗口的软切——在若干毫秒内把轮速目标线性压到零、把接触权重平滑过渡。
- 切换前强制轮速进入阻尼并等待轮速反馈确实降下来,再允许进入足接触;不要只发降速命令就假设已降速(§81.8 陷阱的同源问题)。
- 在仿真里专门随机化"切换时刻的残余轮速"和"软硬地面交界",让策略提前见过切换瞬态——这是 §81.6 随机化表之外、轮足特有的一类随机化。
- 切换帧把轮速里程计权重 \(\alpha\) 临时下调,让 IMU 在不确定窗口内主导速度估计(§81.22c)。
- 若软硬交界打滑频繁,按 §81.27 降低交界处速度包络,或提前由地形感知触发限速。
本质洞察:轮足接触切换的危险,本质是**两个不相容的接触假设在同一时刻争夺同一个轮子**——滚动约束说"轮速对应地速",足式点接触说"接触点静止"。这两个假设在切换帧同时部分成立,谁都不完全对。可靠切换的关键不是"切得快",而是"在切换窗口内不让任何一个假设被当成确定真理"——轮速平滑压零、接触权重渐变、状态估计降低对轮速的信任。这与 §81.15b.3 用分布式时钟"让所有电机同一时刻动作"的精神相反却互补:那里要的是同步对齐,这里要的是**过渡解耦**。
81.30 常见故障:控制周期丢失¶
现象:
- 目标 500 Hz,实际周期偶发 10 ms。
- 机器人偶发顿挫。
- 日志显示推理或通信阻塞。
原因:
- 实时循环中有动态内存。
- 实时循环中有日志打印。
- SDK 调用阻塞。
- DDS 回调和控制线程抢 CPU。
- 策略推理放在硬实时路径。
处理:
- 记录每周期耗时直方图。
- 把策略推理放到独立线程。
- 控制线程只读最新策略快照。
- 避免实时路径日志。
- 使用固定大小缓冲。
- 检查 CPU 亲和性和线程优先级。
- 对 SDK 调用设置超时。
81.31 部署安全表¶
- 001 急停按钮可触达。
- 002 远程急停通道独立。
- 003 保护绳或支撑架已准备。
- 004 电池电量足够。
- 005 电机温度正常。
- 006 轮胎固定无松动。
- 007 轮胎无明显破损。
- 008 地面无人员进入安全区。
- 009 控制频率稳定。
- 010 日志路径可写。
- 011 策略输入无 NaN。
- 012 策略输出无 NaN。
- 013 观测 schema 与训练一致。
- 014 动作 schema 与硬件一致。
- 015 轮速方向逐个验证。
- 016 关节方向逐个验证。
- 017 IMU 方向验证。
- 018 轮半径参数验证。
- 019 电机限幅生效。
- 020 轮速限斜率生效。
- 021 腿部力矩限幅生效。
- 022 模式 ID 映射一致。
- 023 安全层可禁用轮模式。
- 024 安全层可进入故障态。
- 025 通信丢失进入安全停止。
- 026 上位机崩溃进入安全停止。
- 027 策略推理超时进入保持或停止。
- 028 低电压触发限功率。
- 029 高温触发降级。
- 030 倾倒触发急停。
- 031 架空测试完成。
- 032 低速直行测试完成。
- 033 低速转向测试完成。
- 034 低速制动测试完成。
- 035 轮到足模式切换测试完成。
- 036 足到轮模式切换测试完成。
- 037 混合模式低速测试完成。
- 038 坡道低速测试完成。
- 039 碎石低速测试完成。
- 040 日志回放工具可用。
81.32 练习¶
练习 A:轮胎滑移仿真¶
实现一个二维轮胎模型。
要求:
- 输入轮速、车体速度、法向力。
- 计算滑移比和滑移角。
- 用线性刚度加摩擦圆输出 \(F_x,F_y\)。
- 比较理想纯滚动和滑移模型下的加速距离。
- 改变 \(\mu\) 和 \(C_\kappa\),观察控制效果。
练习 B:领域随机化表¶
为 Go2-W 或 Upkie 设计随机化配置。
要求:
- 至少包含 15 个参数。
- 每个参数写明单位和范围。
- 区分基础阶段、鲁棒阶段和部署阶段。
- 说明每个参数影响哪个故障模式。
练习 C:硬件接口空载测试¶
实现一个轮足硬件接口 mock。
要求:
- 支持腿关节状态和轮速状态。
- 支持腿力矩命令和轮速度命令。
- 支持看门狗超时。
- 支持命令裁剪。
- 写出架空测试脚本。
练习 D:策略部署一致性¶
导出一个简单 MLP 策略。
要求:
- 在 PyTorch 中输出动作。
- 导出 ONNX。
- 在 C++ 或 Python ONNXRuntime 中加载。
- 对同一批观测比较输出误差。
- 验证观测归一化一致。
81.33 累积项目:轮足策略从仿真到低速真机¶
项目目标:完成一个低速、安全、可回放的轮足部署闭环。
模块:
- 仿真训练或 MPC 原型。
- 轮胎滑移随机化。
- 延迟随机化。
- 策略或 MPC 导出。
- Sim2Sim 验证。
- ros2_control 或 SDK 硬件接口。
- 安全裁剪和看门狗。
- 架空测试。
- 低速平地测试。
- 日志分析。
交付:
- 一份参数随机化表。
- 一份观测和动作 schema。
- 一段 Sim2Sim 对比曲线。
- 一段架空轮速测试曲线。
- 一段低速直行日志。
- 一份故障排查记录。
- 一份安全检查表。
成功标准:
- 机器人可以低速直行和转向。
- 策略输出不振荡。
- 急停和看门狗生效。
- 轮速里程计误差可解释。
- 日志能重放关键状态。
81.33b 本章常见误解汇总¶
| 常见误解 | 正确理解 | 相关小节 |
|---|---|---|
| "把摩擦系数调准,仿真就接近真机了" | 真机的不确定性是分布而非单点。目标不是调准一个 \(\mu\),而是让随机化分布覆盖真机可能的参数范围 | §81.2、§81.6b |
| "域随机化是让仿真更逼真" | DR 是让策略更鲁棒 / 让训练分布裹住真机这个点。逼真(提保真度)和鲁棒(撑分布)是两条不同的路 | §81.6b.1 |
| "随机化范围越宽越安全" | 太宽会付出保守性代价——策略为永不出现的极端组合牺牲正常工况性能。最优是恰好盖住真机分布再留裕度 | §81.6b.2 |
| "轮电机最大力矩是个常数" | 反电动势使最大力矩随速度线性下降,高速时大幅减小。仿真用常数会让高速策略过激进 | §81.9.1 |
| "实时系统就是性能强的系统" | 实时 = 准时,不是快。稳定 1 ms 胜过均值 0.1 ms 但偶发 50 ms。关注延迟长尾而非均值 | §81.15b.1 |
| "把策略推理优化得足够快就能放进控制环" | 再快也有长尾。正解是频率解耦——推理线程算,控制线程只读最新快照,从不等待 | §81.15b.4 |
| "观测给命令值就够了" | 必须给反馈,否则策略看不见 Sim-to-Real Gap,会以为命令总能执行 | §81.7、§81.7.1 |
| "单帧观测足够,策略是马尔可夫的" | 真实系统部分可观测。需要历史 + 反馈让马尔可夫策略隐式重建隐藏状态 | §81.7.1 |
| "归一化统计是预处理细节,部署时随便填" | 归一化的 \(\mu,\sigma\) 是模型的一部分,必须与权重一起导出。填错网络不报错但输出垃圾 | §81.7.2、§81.16 |
| "仿真里跑通就等于真机能用" | Sim-to-Real Gap 普遍存在。仿真是迭代工具不是真机替代,必须随机化训练 + 分级测试 + 渐进放开 | §81.2、§81.18 |
| "解析公式能建好所有执行器" | 高减速比腿关节的摩擦/弹性/迟滞难解析,需执行器网络从真机数据学 | §81.9.5 |
| "仿真里用真实姿态算投影重力就行" | 真机只能从带噪 IMU 估,仿真也必须用同样的带噪估计管线产生观测,否则分布不一致 | §81.7.1 |
| "随机化只要拉宽就行,不用辨识中心" | 辨识把分布中心对准真机、随机化只补不确定度宽度;辨识越准宽度越窄、保守性代价越低 | §81.6c |
| "控制频率只是跑多快的工程选择" | 频率是策略动力学假设的一部分,被训练焊死;改频率=把策略丢进没见过的时间尺度,必振荡 | §81.10b、§81.28 |
| "改仿真步长不影响别的" | \(f_{\text{ctrl}}=f_{\text{sim}}/\text{decimation}\),改步长不同步改 decimation 会让控制频率被动改变 | §81.10b.3 |
| "电机参数照抄 datasheet 就行" | datasheet 是标称/新机/恒温值,真机受温度、批次、装配偏差,须台架实测 | §81.9.6 |
81.33c 术语速查表¶
| 术语(中文) | 英文 / 缩写 | 一句话定义 |
|---|---|---|
| 滑移比 | Slip Ratio, \(\kappa\) | 轮速与地速之差相对地速的比值,描述纵向打滑 |
| 滑移角 | Slip Angle, \(\alpha\) | 横向速度与纵向速度的夹角,描述横向打滑 |
| 纵向刚度 | Longitudinal Stiffness, \(C_\kappa\) | 小滑移区纵向力对滑移比的斜率 |
| 侧偏刚度 | Cornering Stiffness, \(C_\alpha\) | 小滑移区侧向力对滑移角的斜率 |
| 摩擦圆 | Friction Circle | 纵横向力合力的上界约束 \(\sqrt{F_x^2+F_y^2}\le\mu F_z\) |
| 魔术公式 | Pacejka Magic Formula | 用经验参数 \(B,C,D,E\) 拟合轮胎力曲线的半经验模型 |
| 域随机化 | Domain Randomization, DR | 训练时随机化环境参数,使策略对参数变化鲁棒 |
| 自动域随机化 | Automatic Domain Randomization, ADR | 按策略表现自动扩张随机化范围的 curriculum |
| 协变量偏移 | Covariate Shift | 训练分布与测试分布不一致导致泛化失败 |
| 反电动势 | Back-EMF | 电机转动产生的反向电压,限制高速可用力矩 |
| 力矩常数 | Torque Constant, \(K_t\) | 电流到力矩的比例系数(Nm/A) |
| 反电动势常数 | Back-EMF Constant, \(K_e\) | 转速到反电动势的比例系数(V/(rad/s)) |
| 执行器网络 | Actuator Network | 从真机数据学出的命令到实际力矩映射的神经网络 |
| 残差执行器网络 | Residual Actuator Network | 解析 PD + 网络只学偏差的执行器建模形式 |
| 特权学习 | Privileged Learning | 教师用仿真特权信息学,学生用可部署观测模仿 |
| 教师-学生 | Teacher-Student | 上述范式的别称,部署的是学生策略 |
| 分布式时钟 | Distributed Clocks, DC | EtherCAT 让各从站时刻同步、命令到点同时执行的机制 |
| 实时内核补丁 | PREEMPT_RT | 使 Linux 内核可抢占、保证实时线程及时调度的补丁 |
| CPU 隔离 | CPU Isolation, isolcpus | 把某核划出普通调度、专跑实时控制线程 |
| 最坏情况执行时间 | Worst-Case Execution Time, WCET | 任务在最坏情况下的执行耗时,实时系统的关键指标 |
| Allan 方差 | Allan Variance | 分离惯性传感器不同噪声成分的标准工具 |
| 角度随机游走 | Angle Random Walk, ARW | 陀螺仪白噪声积分项,Allan 图斜率 \(-1/2\) |
| 偏置不稳定性 | Bias Instability, BI | 传感器低频偏置漂移,Allan 图谷底值 |
| 互补滤波 | Complementary Filter | 按频段融合低频可靠源与高频可靠源的轻量融合 |
| 系统辨识 | System Identification | 用激励实验从真机响应反推动力学/执行器参数 |
| 降采样系数 | Decimation | 物理步数与控制周期之比,\(f_{\text{ctrl}}=f_{\text{sim}}/\text{decimation}\) |
| 堵转法 | Stall Test | 锁轴使反电动势为零、由 \(V=IR\) 与 \(\tau=K_tI\) 辨识 \(R,K_t\) |
| 看门狗 | Watchdog | 命令超时未更新即触发安全停止的保护机制 |
81.34 本章速查¶
- 轮足 Sim-to-Real 的关键误差来自轮地速度转换。
- 纯滚动条件 \(v=r\omega\) 只在理想情况下成立。
- 滑移比描述纵向打滑。
- 滑移角描述横向打滑。
- 小滑移模型可用线性刚度近似。
- 大滑移必须受摩擦圆约束。
- 完整 Pacejka 模型适合理解轮胎非线性。
- 策略训练至少应包含滑移和延迟随机化。
- 轮半径误差会直接变成里程计比例误差。
- 高速轮电机的最大力矩随速度下降。
- 反电动势是高速扭矩下降的重要原因。
- 延迟要用队列建模。
- 观测 schema 必须机器可读。
- 动作 schema 必须和硬件命令一致。
- 架空测试只能验证接口方向,不能证明接触稳定。
- Sim2Sim 能发现 URDF/MJCF 和部署接口错误。
- ros2_control 的实时路径不能动态分配内存。
- 软件急停不能替代硬件急停。
- 硬件急停不能替代软件降级。
- 轮模式和足模式的命令语义不同。
- 模式切换必须影响硬件接口。
- 轮速方向错误会导致落地瞬间失控。
- IMU 外参错误会破坏姿态观测。
- 观测归一化错误会导致策略输出异常。
- 上一动作字段必须和训练时一致。
- 控制频率不一致会导致闭环振荡。
- 策略推理应与硬实时写入解耦。
- 低置信地形应触发限速。
- 轮编码器失效时应禁用轮模式或降级。
- 真机部署必须分级。
81.35 延伸阅读路线¶
建议阅读顺序:
- 轮式非完整约束。
- 滑移比和滑移角。
- 轮胎力模型。
- 领域随机化。
- ros2_control 硬件接口。
- 策略部署和 ONNX。
- 真机安全和日志。
- 模式切换与硬件健康耦合。
与后续章节的关系:
- 第 82 章(120_底盘臂联合规划.md)会把轮式底盘与机械臂联合规划。
- 第 83 章(130_OCS2_mobile_manipulator.md)会把 OCS2 的移动操作示例拆成动力学、代价和约束。
- 本章的硬件接口经验会在底盘臂系统中继续使用。
81.36 小结¶
轮足 Sim-to-Real 的难点在于接触、执行器和软件部署同时变化。
轮胎不是理想几何约束,轮电机不是理想速度源,状态估计也不能永远相信轮速。
可靠部署要靠三件事:充分随机化、分级测试、完整日志。
当这些基础做好后,轮足系统的高速度和低能耗优势才能在真实硬件上稳定体现。
81.37 轮足 Sim-to-Real 的前沿趋势 ⭐⭐⭐¶
轮足系统的 Sim-to-Real 近年出现几个值得关注的方向。
自适应轮地接触模型¶
传统 DR 用固定范围随机化轮胎参数。更先进的做法是在训练中使用可学习的接触模型,例如把轮地接触力表达为神经网络,训练时从真机数据在线估计。这让策略不需要对所有参数都做宽范围随机化,而是只在实际不确定的方向上做鲁棒处理。
反事实推理:如果仍然用宽范围均匀随机化所有轮胎参数,训练分布中大量组合在真实世界中从未出现。策略会为不存在的极端组合牺牲正常工况的性能。自适应接触模型通过缩小不确定集合,让策略更专注于真实可能遇到的条件。
多模态地形感知¶
轮足机器人在结构化环境(仓库、医院)中运行时,地面类型会突然变化:水泥、瓷砖、地毯、金属板和湿滑地面。2025 年以来的趋势是把深度相机或足端力信号与轮速反馈融合,在线估计地面类型并切换滑移模型参数。
这一方向与第 80 章(100_模式切换.md)的模式切换直接相关。地面类型变化会触发轮足模式切换,而不仅仅是速度包络调整。
能量效率优化¶
轮式行驶的能量效率远高于腿式行走。2025-2026 年的工程趋势是把能量指标显式加入训练奖励或 MPC 代价。例如惩罚不必要的腿部运动、鼓励轮式巡航、在平坦区域自动切换到纯轮模式。
这要求状态估计器能可靠判断地形平坦度,否则错误切换到纯轮模式会在碎石上失控。
跨章综合练习¶
结合第 80 章(100_模式切换.md)的模式切换框架和本章的硬件接口经验,设计一个自动化测试方案:
- 机器人从平地出发(WHEEL 模式),通过坡道(HYBRID 模式),进入碎石区(LEG 模式)。
- 要求每段地形至少持续 10 m。
- 记录每次模式切换的触发条件、延迟和速度变化。
- 分析哪个切换最容易失败,并给出改进建议。
- 日志需包含轮速、关节力矩、IMU、滑移估计和模式 ID。
81.38 🔧 故障排查手册¶
| 症状 | 可能原因 | 排查步骤 | 相关小节 |
|---|---|---|---|
| 一落地就乱跑 | 轮速方向映射错误或 IMU 符号反 | 1. 架空逐轮测试 2. 检查动作 schema 3. 比较编码器符号 | 81.26 |
| 仿真能过坡真机打滑 | 仿真摩擦过高或缺少滑移随机化 | 1. 降低仿真摩擦 2. 加入轮速限斜率 3. 记录滑移比 | 81.27 |
| 策略输出振荡 | 控制频率与训练频率不一致 | 1. 确认部署频率 2. 对比均值方差 3. 检查上一动作字段 | 81.28 |
| 轮速里程计漂移 | 轮半径未标定或地面打滑 | 1. 标定轮半径 2. 与外部里程计对比 3. 降低轮信任度 | 81.29 |
| 控制周期丢失 | 实时循环中有动态内存或阻塞 | 1. 记录耗时直方图 2. 策略推理放独立线程 3. 检查 CPU 亲和性 | 81.30、81.15b |
| 高速时轮电机无力 | 反电动势导致可用力矩下降 | 1. 检查速度-力矩曲线 2. 降低高速命令 3. 加入速度相关限幅 | 81.9 |
| 正常工况性能不如预期,仿真回报却不低 | 域随机化范围过宽,付出保守性代价 | 1. 收窄非关键维度范围 2. 用实测值对准 DR 中心 3. 加回退评测集守正常工况 | 81.6b.2 |
| 真机命令准时发出但多电机动作不齐、轻微甩尾 | 命令到达各电机时刻不一致 | 1. 启用 EtherCAT 分布式时钟 2. 校验 DC 同步误差 3. 命令带执行时间戳 | 81.15b.3 |
| 架空正常,低速能动,高速突然乱跳 | 观测归一化统计与训练不一致 | 1. 逐字节核对导出的 \(\mu,\sigma\) 2. 打印部署端归一化后输入 3. 与训练统计对比 | 81.7.2、81.16 |
| 低速精细站立姿态发飘、响应迟钝 | 减速器库仑摩擦/齿隙未建模,或缺执行器网络 | 1. 检查解析摩擦模型 2. 考虑残差执行器网络 3. 加关节摩擦随机化 | 81.9.2、81.9.5 |
| 轮/足切换瞬间姿态抖动或甩尾 | 接触假设硬切、切换帧残余轮速、估计权重未及时调整 | 1. 对齐切换时刻与抖动时刻 2. 改软切+轮速平滑压零 3. 切换帧下调轮速里程计权重 | 81.29b、81.25 |
| 仿真速度-力矩曲线与真机对不上,高速行为异常 | 电机参数用 datasheet 未实测,或用瞬态数据辨识 | 1. 堵转法重测 \(K_t,R\) 2. 空载反拖测 \(K_e\) 3. 等稳态再采样 | 81.9.6、81.6c |
81.39 版本信息速查¶
本章涉及的工具/库/框架版本汇总。轮足 Sim-to-Real 链路横跨训练、部署、实时通信三个生态,版本不匹配是隐性故障的常见根源——尤其是 ROS 2 发行版与 ros2_control 的对应、ONNX opset 与 Runtime 的对应。
| 组件 | 推荐版本 | 最低版本 | 最高测试版本 | 备注 |
|---|---|---|---|---|
| Python | 3.10 | 3.8 | 3.11 | 训练侧;3.12 部分 RL 库未跟进 |
| PyTorch | 2.2 | 1.13 | 2.4 | 导出 ONNX 时须与 opset 匹配 |
| ONNX opset | 17 | 11 | 19 | 部署端 Runtime 须支持对应 opset |
| ONNX Runtime | 1.17 | 1.12 | 1.18 | C++ 部署用同版本头文件与库 |
| LibTorch | 与 PyTorch 同版本 | — | — | 必须与训练 PyTorch 主版本一致,否则权重加载失败 |
| ROS 2 | Humble (LTS) | Foxy | Jazzy | Humble 与 ros2_control 生态最成熟 |
| ros2_control | 与 ROS 2 发行版绑定 | — | — | 不可跨发行版混用 |
| Isaac Sim / Isaac Lab | 4.x / 2.x | — | — | 训练侧,见 Ch80 环境配置 |
| MuJoCo | 3.x | 2.3 | 3.x | Sim2Sim 交叉验证用 |
| IgH EtherCAT Master | 1.5.2 | 1.5.0 | 1.6 | 配 PREEMPT_RT 内核 |
| Linux 内核(PREEMPT_RT) | 6.1-rt | 5.15-rt | 6.6-rt | 实时控制必须打 RT 补丁 |
🔧 配置陷阱:LibTorch 与训练 PyTorch 版本不一致 错误做法:训练用 PyTorch 2.2,部署侧随手装了 LibTorch 2.0。 现象:
torch::jit::load报序列化格式错误,或加载成功但推理结果与训练端不一致。 根本原因:TorchScript / 权重序列化格式在主版本间不保证兼容。 正确做法:部署侧 LibTorch 必须与训练 PyTorch 同主版本;更稳的做法是统一走 ONNX——ONNX 的 opset 版本契约比 TorchScript 跨版本兼容性更明确。检查方法:torch.__version__与 LibTorch 头文件版本逐位核对,并跑 §81.16 的 PyTorch vs 部署端输出对比。
本章文档元信息 许可证:CC BY 4.0|出品:达妙科技 · 机器人体系化教学项目 类型:工程实践教学|难度:⭐⭐⭐|前置:Ch60 轮式运动学、Ch70 轮足混合 MPC、Ch80 Wheel-Legged-Gym、第 80 章模式切换 后续:第 82 章 底盘臂联合规划、第 83 章 OCS2 移动操作