前言
- 近来和师兄交流时,我们谈到了机器人 Sim-to-Real 过程中一个非常关键的问题:系统辨识(System Identification)。
- 在前几期 【四足强化学习经典算法】(一):RMA------盲视运动控制与快速适应模块 中,我们已经介绍过,缩小仿真与现实差距的常见思路主要包括四类:域随机化、系统辨识、鲁棒策略学习以及观测与控制对齐。
- 而本文要介绍的 PACE(Precise Adaptation through Continuous Evolution),则选择了一条更加直接的路线:与其让策略尽可能适应一个不够准确的仿真环境,不如先通过真实机器人数据,把仿真器本身校准得更加准确。
- 它的核心主张可以概括为一句话:
- 利用约 20 至 40 秒的腾空扫频数据,辨识机器人关节层的动力学参数,随后在校准后的仿真环境中训练运动策略,最终实现零样本 Sim-to-Real 部署。
- 本文将围绕 PACE 的核心原理、数学建模与工程实现展开,结合论文和官方源码,逐步分析其从真实机器人数据采集、动力学参数辨识,到仿真环境校准与强化学习策略训练的完整流程,并进一步解读实验结果与关键设计思路。

文章目录
-
- 前言
- [0 Isaac 仿真平台](#0 Isaac 仿真平台)
-
-
- [0-1 介绍](#0-1 介绍)
-
- [1 参数辨识与域随机化](#1 参数辨识与域随机化)
-
-
- [1-1 介绍](#1-1 介绍)
- [1-2 域随机化](#1-2 域随机化)
-
- [1-2-1 定义](#1-2-1 定义)
- [1-2-2 常用方法](#1-2-2 常用方法)
- [1-2-3 优势与局限](#1-2-3 优势与局限)
- [1-3 系统辨识](#1-3 系统辨识)
-
- [1-3-1 介绍](#1-3-1 介绍)
- [1-3-2 常用方法](#1-3-2 常用方法)
- [1-3-3 与域随机化的区别](#1-3-3 与域随机化的区别)
-
- [2 PACE 的方法与实验](#2 PACE 的方法与实验)
-
-
- [2-1 介绍](#2-1 介绍)
- [2-2 整体架构](#2-2 整体架构)
-
- [2-2-1 总览](#2-2-1 总览)
- [2-2-2 关节位置控制链路](#2-2-2 关节位置控制链路)
- [2-3 关节动力学参数辨识](#2-3 关节动力学参数辨识)
-
- [2-3-1 真实机器人数据采集:Chirp 信号](#2-3-1 真实机器人数据采集:Chirp 信号)
-
- [2-3-1-1 Chirp 信号](#2-3-1-1 Chirp 信号)
- [2-3-1-2 数据采集条件](#2-3-1-2 数据采集条件)
- [2-3-1-3 扫频参数](#2-3-1-3 扫频参数)
- [2-3-1-4 扫频轨迹生成](#2-3-1-4 扫频轨迹生成)
- [2-3-1-5 数据采样率](#2-3-1-5 数据采样率)
- [2-3-1-6 PD 增益的选择](#2-3-1-6 PD 增益的选择)
- [2-3-2 辨识参数](#2-3-2 辨识参数)
-
- [2-3-2-1 五个参数](#2-3-2-1 五个参数)
- [2-3-2-2 合理性说明](#2-3-2-2 合理性说明)
- [2-3-3 CMA-ES 优化算法](#2-3-3 CMA-ES 优化算法)
-
- [2-3-3-1 CMA-ES定义](#2-3-3-1 CMA-ES定义)
- [2-3-3-2 参数辨识](#2-3-3-2 参数辨识)
- [2-3-3-2-1 第一步:固定与悬空](#2-3-3-2-1 第一步:固定与悬空)
- [2-3-3-2-2 第二步:扫频激励](#2-3-3-2-2 第二步:扫频激励)
- [2-3-3-2-3 第三步:并行回放](#2-3-3-2-3 第三步:并行回放)
- [2-3-3-2-4 第四步:逐代更新](#2-3-3-2-4 第四步:逐代更新)
- [2-3-3-2-5 总结](#2-3-3-2-5 总结)
- [2-3-3-3 辨识结果](#2-3-3-3 辨识结果)
- [2-3-4 执行器动力学辨识](#2-3-4 执行器动力学辨识)
- [2-3-5 整机腾空状态辨识(In-air)](#2-3-5 整机腾空状态辨识(In-air))
-
- [2-3-5-1 轨迹重合](#2-3-5-1 轨迹重合)
- [2-3-5-2 跨增益泛化](#2-3-5-2 跨增益泛化)
- [2-3-5-3 更强的基线的对照](#2-3-5-3 更强的基线的对照)
- [2-3-5-4 未见轨迹上的泛化](#2-3-5-4 未见轨迹上的泛化)
- [2-3-6 地面运动验证(On-ground)](#2-3-6 地面运动验证(On-ground))
- [2-4 永磁同步电机的物理能量模型](#2-4 永磁同步电机的物理能量模型)
-
- [2-4-1 从关节力矩到电机能耗](#2-4-1 从关节力矩到电机能耗)
- [2-4-2 电机物理能量模型](#2-4-2 电机物理能量模型)
-
- [2-4-2-1 **电气侧:铜损**](#2-4-2-1 电气侧:铜损)
- [2-4-2-2 **机械侧:机械功率**](#2-4-2-2 机械侧:机械功率)
- [2-4-2-3 **重力侧:势能变化率**](#2-4-2-3 重力侧:势能变化率)
- [2-4-2-4 **总功率**](#2-4-2-4 总功率)
- [2-4-3 能量项归一化与模型边界](#2-4-3 能量项归一化与模型边界)
- [2-4-4 执行器饱和与模型边界](#2-4-4 执行器饱和与模型边界)
- [2-5 基于辨识模型的强化学习](#2-5 基于辨识模型的强化学习)
-
- [2-5-1 仿真环境参数更新](#2-5-1 仿真环境参数更新)
- [2-5-2 基于物理能量模型的奖励函数](#2-5-2 基于物理能量模型的奖励函数)
- [2-5-3 PPO 策略训练与 Zero-shot Sim-to-Real](#2-5-3 PPO 策略训练与 Zero-shot Sim-to-Real)
- [2-6 实验结果与分析](#2-6 实验结果与分析)
-
- [2-6-1 多机器人平台验证](#2-6-1 多机器人平台验证)
- [2-6-2 能耗与 Cost of Transport 分析](#2-6-2 能耗与 Cost of Transport 分析)
- [2-6-3 不使用动力学域随机化的迁移效果](#2-6-3 不使用动力学域随机化的迁移效果)
-
- [2-6-3-1 策略层面:三臂对照实验](#2-6-3-1 策略层面:三臂对照实验)
- [2-6-3-2 方法层面:模型误差与适用边界](#2-6-3-2 方法层面:模型误差与适用边界)
-
- [3 部署流程参考](#3 部署流程参考)
-
-
- [3-1 介绍](#3-1 介绍)
- [3-2 从数据采集到零样本部署的步骤](#3-2 从数据采集到零样本部署的步骤)
-
- [3-2-1 环境配置:参数边界与关节顺序](#3-2-1 环境配置:参数边界与关节顺序)
- [3-2-2 数据采集:激励与记录](#3-2-2 数据采集:激励与记录)
- [3-2-3 辨识主循环](#3-2-3 辨识主循环)
- [3-2-4 优化器内部:参数分片、终止与存档](#3-2-4 优化器内部:参数分片、终止与存档)
- [3-2-5 结果校验](#3-2-5 结果校验)
- [3-2-6 迁移到训练环境](#3-2-6 迁移到训练环境)
- [3-3 常见问题](#3-3 常见问题)
-
- 总结
0 Isaac 仿真平台
0-1 介绍

- NVIDIA Isaac 是 NVIDIA 面向机器人研发构建的仿真与开发生态,主要用于机器人模型构建、物理动力学仿真、传感器模拟、机器人算法验证以及强化学习训练等任务。通过在统一的仿真环境中模拟机器人本体、执行器、传感器与外部场景,研究人员可以开展运动控制、机器人导航、视觉感知和操作等方向的算法研究。
- 从技术架构与发展历程来看,Isaac 生态中有三个值得关注的项目:Isaac Gym、Isaac Sim 和 Isaac Lab。
- Isaac Gym:早期面向 GPU 加速物理仿真与强化学习的工具,重点在于大规模并行环境下的机器人运动训练。
- Isaac Sim:基于 NVIDIA Omniverse 构建的通用机器人仿真平台,提供物理引擎、场景管理、传感器模拟和机器人软件集成等能力。
- Isaac Lab:面向机器人学习的开发框架,基于仿真后端封装机器人模型、训练环境和任务接口,支持强化学习与模仿学习等算法。
- 三者的定位并不完全相同:Isaac Gym 代表早期 GPU 并行机器人学习工具,Isaac Sim 提供通用仿真基础设施,而 Isaac Lab 则进一步面向机器人学习任务进行封装。
#mermaid-svg-Wk0GtsUOjZaLh1aC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Wk0GtsUOjZaLh1aC .error-icon{fill:#552222;}#mermaid-svg-Wk0GtsUOjZaLh1aC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Wk0GtsUOjZaLh1aC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .marker.cross{stroke:#333333;}#mermaid-svg-Wk0GtsUOjZaLh1aC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Wk0GtsUOjZaLh1aC p{margin:0;}#mermaid-svg-Wk0GtsUOjZaLh1aC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster-label text{fill:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster-label span{color:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster-label span p{background-color:transparent;}#mermaid-svg-Wk0GtsUOjZaLh1aC .label text,#mermaid-svg-Wk0GtsUOjZaLh1aC span{fill:#333;color:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .node rect,#mermaid-svg-Wk0GtsUOjZaLh1aC .node circle,#mermaid-svg-Wk0GtsUOjZaLh1aC .node ellipse,#mermaid-svg-Wk0GtsUOjZaLh1aC .node polygon,#mermaid-svg-Wk0GtsUOjZaLh1aC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .rough-node .label text,#mermaid-svg-Wk0GtsUOjZaLh1aC .node .label text,#mermaid-svg-Wk0GtsUOjZaLh1aC .image-shape .label,#mermaid-svg-Wk0GtsUOjZaLh1aC .icon-shape .label{text-anchor:middle;}#mermaid-svg-Wk0GtsUOjZaLh1aC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .rough-node .label,#mermaid-svg-Wk0GtsUOjZaLh1aC .node .label,#mermaid-svg-Wk0GtsUOjZaLh1aC .image-shape .label,#mermaid-svg-Wk0GtsUOjZaLh1aC .icon-shape .label{text-align:center;}#mermaid-svg-Wk0GtsUOjZaLh1aC .node.clickable{cursor:pointer;}#mermaid-svg-Wk0GtsUOjZaLh1aC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .arrowheadPath{fill:#333333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wk0GtsUOjZaLh1aC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Wk0GtsUOjZaLh1aC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wk0GtsUOjZaLh1aC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster text{fill:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC .cluster span{color:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Wk0GtsUOjZaLh1aC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Wk0GtsUOjZaLh1aC rect.text{fill:none;stroke-width:0;}#mermaid-svg-Wk0GtsUOjZaLh1aC .icon-shape,#mermaid-svg-Wk0GtsUOjZaLh1aC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wk0GtsUOjZaLh1aC .icon-shape p,#mermaid-svg-Wk0GtsUOjZaLh1aC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Wk0GtsUOjZaLh1aC .icon-shape .label rect,#mermaid-svg-Wk0GtsUOjZaLh1aC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wk0GtsUOjZaLh1aC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Wk0GtsUOjZaLh1aC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Wk0GtsUOjZaLh1aC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Wk0GtsUOjZaLh1aC .gym>*{fill:#E8F1FC!important;stroke:#4285C5!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .gym span{fill:#E8F1FC!important;stroke:#4285C5!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .gym tspan{fill:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .sim>*{fill:#E8F5E9!important;stroke:#43A047!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .sim span{fill:#E8F5E9!important;stroke:#43A047!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .sim tspan{fill:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .lab>*{fill:#FFF3E0!important;stroke:#EF8C32!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .lab span{fill:#FFF3E0!important;stroke:#EF8C32!important;color:#1F2937!important;}#mermaid-svg-Wk0GtsUOjZaLh1aC .lab tspan{fill:#1F2937!important;} 技术能力演进与功能整合
在其基础上构建
Isaac Gym
早期 GPU 物理仿真
强化学习接口
Isaac Sim
Omniverse + PhysX + RTX
通用机器人仿真平台
Isaac Lab
机器人学习框架
并行环境 + RL / IL
说人话:Gym 是早期工具,Sim 负责仿真,Lab 负责机器人训练。
- 本文主要关注 Isaac Sim 与 Isaac Lab,后续将结合 PACE 的官方实现,分析其仿真环境、动力学参数配置以及强化学习训练流程。
1 参数辨识与域随机化
1-1 介绍
- 在机器人 Sim-to-Real 过程中,仿真环境与真实机器人之间始终存在一定差异,而这些差异会直接影响强化学习策略在真实环境中的表现。
- 如何缩小仿真与现实之间的差距,是机器人强化学习中的一个重要问题。围绕这一问题,现有研究主要形成了两种思路:域随机化(Domain Randomization)与系统辨识(System Identification) 。
- 前者侧重于提高策略对环境变化的适应能力,后者则侧重于提高仿真模型本身的准确性。
- PACE 选择了系统辨识这条路线,并进一步关注传统研究中容易被忽略的执行器动力学问题。下面我们分别介绍这两种方法,再进入 PACE 的具体实现。
1-2 域随机化
1-2-1 定义
- 域随机化(Domain Randomization,DR)的核心思想是:不再假设仿真环境中的参数完全准确,而是将参数的不确定性建模为一个概率分布。在训练过程中,每次随机采样一组环境参数,让策略在不同的动力学条件下反复训练,从而提高对未知环境变化的适应能力。
- 从数学上看,传统强化学习通常针对固定环境参数 p p p 优化策略,而域随机化则将优化目标变成不同参数分布下的期望代价: θ ⋆ = arg min θ E p ∼ P J ( θ ; p ) \theta^{\star} = \arg\min_{\theta} \mathbb{E}_{p\sim\mathcal{P}} J(\\theta;p) θ⋆=argθminEp∼PJ(θ;p)其中:
- θ \theta θ:策略网络参数
- p p p:环境参数,例如机器人质量、关节摩擦、电机强度、控制延迟等
- J J J:策略在当前环境参数下的回合代价
- P \mathcal{P} P:人为设定的环境参数分布
- 在实际训练中,通常会为不同参数设置随机化范围。例如,随机改变机器人质量、地面摩擦系数和电机输出强度,使策略在训练过程中不断接触不同的环境条件,而不是只适应某一组固定参数。
- 这样训练出来的策略,不再仅仅追求某个特定仿真模型下的最优表现,而是尽可能在一系列不同的动力学条件下保持稳定。当真实机器人的参数与训练分布足够接近时,策略便有机会直接迁移到真实环境。
说人话:随机化不是把仿真调准,而是让策略学会适应不同的仿真参数,即使真实机器人的动力学和仿真存在偏差,也尽可能能够正常工作
1-2-2 常用方法
- 域随机化并不只有一种实现方式,根据参数采样和分布构建方式的不同,常见方法包括:
- 参数范围随机化: 最常见的方式,为不同环境参数设置上下界,每个环境独立采样。例如机器人质量、质心位置、足端摩擦系数、电机力矩缩放、PD 增益、观测噪声和动作延迟等。
- 课程式随机化: 训练初期采用较窄的随机化范围,随着策略逐渐收敛,再逐步扩大参数范围,避免一开始就面对过大的动力学变化。
- 对抗式随机化: 将参数分布也纳入优化过程,根据当前策略的表现调整随机化分布,使训练环境更多地集中在策略难以应对的区域。
- 数据驱动随机化: 利用少量真实机器人数据估计环境参数的分布,例如通过 BayesSim 等方法进行后验推断,减少完全依赖人工经验设置随机化范围的问题。
- 时序随机化: 针对通信和控制链路中的延迟,在训练时随机改变动作执行延迟或观测时序,使策略能够适应不同的时间响应特性。
1-2-3 优势与局限
- 优势:
- 优势一: 不需要精确辨识全部动力学参数,也不一定需要额外的力矩传感器,通过设置参数随机化范围即可提高策略的鲁棒性,工程改动相对较小。
- 优势二: 能够提高策略对参数变化和部分未建模因素的适应能力,只要相关误差能够被随机化范围合理覆盖,策略就有机会学习到相应的适应能力。
- 局限:
- 局限一:保守性。 随机化范围越大,策略需要适应的环境差异也越大,可能导致运动策略趋于保守,牺牲运动性能与能量效率。
- 局限二:高速运动下的适应难度。 论文图 19 的包络分析表明,在其研究条件下,随着步频提高,为覆盖相同程度的现实差距,需要扩大随机化范围。这意味着高速运动对动力学模型误差更加敏感。
- 局限三:调参与系统偏差问题。 随机化范围通常依赖人工经验,范围过窄可能无法覆盖真实系统,过宽又可能影响训练效果。此外,编码器零位偏差、固定通信延迟等系统性误差并不会因为随机化而被真正消除。
1-3 系统辨识
1-3-1 介绍
- 系统辨识(System Identification,SysID)的核心思想是:通过真实系统的输入与输出数据,反向估计系统模型中的未知参数,使模型能够尽可能准确地描述真实系统的动态响应。
- 从数学上看,可以将参数辨识表示为一个优化问题: p ⋆ = arg min p ∥ y real − y sim ( p ) ∥ 2 p^{\star} = \arg\min_{p} \left\|y_{\text{real}}-y_{\text{sim}}(p)\right\|^2 p⋆=argpmin∥yreal−ysim(p)∥2其中:
- p p p 表示待辨识的模型参数
- y real y_{\text{real}} yreal 表示真实系统的测量输出
- y sim ( p ) y_{\text{sim}}(p) ysim(p) 表示模型在相同输入下产生的输出。
- 通过不断调整参数 p p p,使模型输出逐渐接近真实系统的响应。
- 在机器人领域,常见的辨识对象包括质量、转动惯量、摩擦系数、电机动力学参数以及执行器响应延迟等。具体辨识时,需要根据研究对象选择合适的输入信号和观测量,并构建相应的误差函数。
说人话:系统辨识就是让仿真机器人尽可能表现得像真实机器人。我们给真实机器人输入一组指令,记录它实际产生的运动;再让仿真机器人执行相同的指令,通过调整仿真模型中的参数,让仿真的运动结果尽可能接近真实机器人。这样就能找到一组更符合真实机器人的动力学参数。
1-3-2 常用方法
- 系统辨识有多种实现方式,具体取决于模型形式、可获取的数据以及待辨识参数的特点。常见方法包括:
- 线性最小二乘: 将机器人动力学方程整理为对待辨识参数线性的形式,例如 Y ( q , q ˙ , q ¨ ) π = τ Y(q,\dot q,\ddot q)\pi=\tau Y(q,q˙,q¨)π=τ,再通过最小二乘或极大似然估计求解。该方法通常需要关节力矩、位置、速度和加速度等测量数据,同时要求采集轨迹具有足够丰富的激励。
- 滤波类方法: 将未知参数作为状态变量,通过卡尔曼滤波或其他递推估计方法,根据新采集的数据持续更新参数,适合在线辨识场景。
- 黑盒优化: 当仿真模型复杂、目标函数难以求导时,可以直接将仿真误差作为优化目标,利用 CMA-ES、贝叶斯优化等方法搜索参数空间,不需要显式计算目标函数的梯度。
- 执行器网络: 使用神经网络学习电机控制指令与实际输出力矩之间的映射关系,从而拟合执行器的非线性动力学。代表性工作包括 Hwangbo 等人提出的 Actuator Network,通常需要实际力矩测量数据进行训练。
- 除了上述通用方法,近年来也有研究针对四足机器人的执行器参数和系统动力学开展专门辨识。相关工作与本文后续讨论的方法具有较高关联性,下面选取两项代表性研究进行对比。
| 对比项 | Miller 等(2025) | Sobanbabu 等(2025) | PACE |
|---|---|---|---|
| 硬件数据来源 | 运动策略的 Rollout | 策略与运动先验 | 固定基座的关节激励 |
| 是否需要闭环控制 | 是 | 是 | 否 |
| 采集安全性 | 中 | 中 | 高 |
| 是否需要预训练策略 | 是 | 是 | 否 |
| 轨迹是否漂移 | 是 | 是 | 否 |
| 主要优化参数 | 摩擦、力矩-转速曲线 | 系统级参数 | 惯量、阻尼、摩擦、延迟、偏置 |
| 预先计算、不参与优化的量 | 延迟 | 无 | 力矩-转速曲线 |
| 相似度度量 | Wasserstein、MMD | Fisher 信息奖励 | 关节位置误差 |
| 机器人数量 | 1(Spot) | 2(以 Unitree 为主) | 3 个主平台及 10 个扩展平台 |
- 从表中可以看出,这几种方法在数据采集方式、优化对象和误差度量上存在明显差异。它们的共同点是利用优化算法搜索模型参数,而关键区别在于:采集什么样的数据,以及用什么指标衡量仿真与真实机器人的差异。
- 相比依赖机器人运动策略采集数据的路线,固定基座激励牺牲了一部分运动场景下的数据丰富度,但能够减少接触、姿态变化和轨迹漂移等因素的干扰,使数据采集过程更加可控,也更容易复现。
1-3-3 与域随机化的区别
- 两者不是替代关系,而是处理误差的两种时点:随机化在训练时"绕过"误差,辨识在训练前"消掉"误差
- 经验上可以按误差是否可观测、是否恒定来取舍。质量误差这类分布宽、方向不定的项,随机化更划算;延迟、零点偏置这类恒定项,辨识的收益远大于随机化。这是一条启发式判断,而不是非此即彼的判据,实际取舍还要看数据与算力预算
| 维度 | 域随机化 | 参数辨识 |
|---|---|---|
| 真实数据需求 | 接近零 | 少量(PACE 约 20 秒轨迹) |
| 是否需要力矩传感 | 否 | 否(PACE 只用编码器) |
| 训练时分布 | 宽,参数被随机化 | 窄,参数固定为辨识值 |
| 学到的策略风格 | 保守、鲁棒 | 针对本机最优、效率高 |
| 对未建模非线性的处理 | 靠覆盖 | 靠吸收进有效参数 |
| 主要失效模式 | 分布覆盖不到真机 | 假设被违反(见 2-6-3 节) |
| 迁移到新机器人 | 沿用同一套随机化 | 需要重新辨识一次 |
2 PACE 的方法与实验
2-1 介绍

- PACE(Precise Adaptation through Continuous Evolution)是 ETH Zurich 的 Robotic Systems Lab 提出的一种面向腿式机器人的系统化 Sim-to-Real 迁移框架。
- 其相关论文为 Towards Bridging the Gap: Systematic Sim-to-Real Transfer for Diverse Legged Robots ,作者为 Filip Bjelonic、Fabian Tischhauser 和 Marco Hutter,发表于 2026 年的 The International Journal of Robotics Research(IJRR)。
- 该方法关注的核心问题是:如何通过准确的动力学建模,缩小仿真机器人与真实机器人之间的差异,从而提高强化学习运动策略的迁移效果。
- 与传统域随机化方法通过扩大参数采样范围来提高策略鲁棒性不同,PACE 采用自底向上的系统辨识路线,从执行器和关节动力学入手,利用真实机器人采集的数据,通过进化优化算法辨识关键物理参数,并将辨识结果写入仿真模型。
- 在此基础上,PACE 进一步结合永磁同步电机(PMSM)的物理能量模型设计强化学习奖励函数,使训练过程不仅关注运动跟踪效果,也考虑机械与电气能量损耗。最终,利用校准后的仿真环境训练运动控制策略,并将策略直接迁移至真实机器人,无需针对真实机器人进行额外的策略微调。
- 论文在 TYTAN、ANYmal 和 MINIMAL 三种主要四足机器人平台上进行了验证,并进一步扩展至其他 10 台机器人。实验结果表明,该方法能够在不进行动力学参数随机化的情况下实现可靠的策略迁移,并在 ANYmal 上将完整运输成本(Cost of Transport,CoT)降低约 32%。
- 论文的主要贡献:
- 提出仅依赖固定基座关节激励数据的参数辨识流程,无需预训练运动策略。
- 建立从单执行器到整机运动的分层评估体系,验证辨识参数对机器人运动性能的影响。
- 在三个主要机器人平台及另外十个扩展平台上开展实验,验证方法的跨平台适用性。
- 引入基于 PMSM 物理模型的能量奖励,定量分析并改善机械与电气能量效率。
- 其他工程贡献: 引入带位置饱和限制的关节控制策略以保护硬件,并通过实验验证,仅使用四项奖励函数也能训练出有效的运动策略。
说人话:PACE 的核心思路就是先通过真实机器人的数据,把仿真模型调得更准确,再用它训练强化学习策略,最后直接迁移到真机。同时,它还考虑了电机能耗,让机器狗不仅跑得稳,也跑得省电。
2-2 整体架构
2-2-1 总览
- PACE 的整体框架主要分为三个阶段,论文图 3 展示了完整的数据流与各阶段之间的关系:
- 真实机器人数据采集: 将机器人整机固定,使四条腿处于悬空状态,通过扫频信号(Chirp Signal)对各关节进行激励,并记录关节目标位置与实际位置,为后续参数辨识提供真实系统数据。
- 动力学参数辨识: 在 Isaac Lab 中并行构建仿真实例,重放与真实机器人相同的关节激励轨迹,并采用 CMA-ES 优化算法搜索关节动力学参数,以仿真关节位置轨迹与真实测量轨迹之间的误差作为优化目标,使两者尽可能一致。
- 策略训练与真机迁移: 将辨识得到的动力学参数更新至仿真模型,在校准后的仿真环境中训练盲视运动控制策略,最终将训练好的策略直接部署到真实机器人,实现零样本 Sim-to-Real 迁移。

2-2-2 关节位置控制链路
-
在进入参数辨识之前,先要明确被控对象在控制链路上的位置。PACE 中所有关节都由位置指令驱动:扫频激励轨迹与强化学习策略输出的都是关节位置,而真正作用于关节的物理量是力矩。因此位置指令与力矩之间还隔着一层控制律与一层电流环,这一节把这条链路拆开。
-
完整的链路可以分为四级:
- 位置指令: 上层给出目标关节位置 q d e s q_{des} qdes,经动作项直接作为绝对位置目标下发,不做缩放,也不叠加默认位姿
- PD 律: 以位置偏差与速度偏差为输入,输出目标关节力矩 τ c m d \tau_{cmd} τcmd
- 驱动器电流环: 把力矩指令换算为 q 轴电流指令 i q ∗ = τ c m d / k t i_q^{\ast}=\tau_{cmd}/k_t iq∗=τcmd/kt,再由电流环跟踪
- PMSM 电磁转矩: 电流环产生的电磁转矩驱动关节,扣除惯量、阻尼与摩擦后形成实际运动
-
第二级的 PD 律可以写成 τ c m d = K p ( q d e s − q ) + K d ( q ˙ d e s − q ˙ ) \tau_{cmd}=K_p\left(q_{des}-q\right)+K_d\left(\dot q_{des}-\dot q\right) τcmd=Kp(qdes−q)+Kd(q˙des−q˙)其中 K p K_p Kp 为位置刚度、 K d K_d Kd 为速度阻尼,两者在整段辨识与训练中都是固定增益,不属于待辨识参数。需要强调的是,PD 输出的仍然是力矩:位置进入、力矩输出,属于位置型阻抗控制,位置跟踪是通过力矩间接实现的,链路上并不存在一个直接输出位置的环节。
| 层级 | 输入 | 输出 | PACE 中的处理方式 |
|---|---|---|---|
| 位置指令 | 上层轨迹或策略 | 绝对关节位置目标 | 不辨识,采集时随轨迹一并记录 |
| PD 律 | 位置偏差与速度偏差 | 目标力矩 τ c m d \tau_{cmd} τcmd | 增益固定,通过 2-3-1-6 的频域分析选取 |
| 电流环 | 力矩指令 | 电磁转矩 | 视为带宽足够高,不单独建模 |
| 关节动力学 | 电磁转矩 | 关节运动 | 五个参数在此进入,是辨识的目标 |
- 仿真侧的实现与这一分层一致。动作项只接受位置:
python
# 动作即绝对关节位置目标,scale=1.0 且不使用默认偏置
joint_pos = mdp.JointPositionActionCfg(
asset_name="robot", joint_names=[".*"], scale=1.0, use_default_offset=False
)
- 位置到力矩的转换发生在执行器模型内部,采用显式 PD 而非隐式位置驱动:
python
# 误差由位置目标与当前状态构成,PD 项的乘积即目标力矩
error_pos = control_action.joint_positions - joint_pos
error_vel = control_action.joint_velocities - joint_vel
computed_effort = (
self.stiffness * error_pos + self.damping * error_vel + control_action.joint_efforts
)
applied_effort = self._clip_effort(computed_effort, joint_vel) # 按转矩-转速曲线裁剪
control_action.joint_efforts = applied_effort
control_action.joint_positions = None # 下游只接受力矩
control_action.joint_velocities = None
-
上述代码中有两点值得注意。
- 返回时位置与速度被置为空,交给物理引擎的只有力矩,因此这是显式力矩驱动,而不是由物理引擎内建的位置伺服完成跟踪。隐式伺服无法在执行过程中插入编码器偏置与指令延迟,而这两项正是 PACE 需要辨识的量。
- 上式得到的目标力矩还会被直流电机的转矩-转速曲线裁剪,转速越高,可用力矩越小。ANYmal 的配置取饱和力矩 140 N·m、持续力矩上限 89 N·m、空载转速 8.5 rad/s,与该平台真实驱动器的规格一致。
-
PACE 在标准直流电机模型上又包了一层,把偏置与延迟显式地放进 PD 的输入与输出:
python
def compute(self, control_action, joint_pos, joint_vel):
control_action = self._delay_command(control_action) # 指令延迟
# PD 只看到编码器坐标系下的关节位置
control_action_sim = super().compute(control_action, joint_pos - self.encoder_bias, joint_vel)
control_action_sim.joint_efforts = self._delay_effort(control_action_sim.joint_efforts)
return control_action_sim
-
由此可以看清五个辨识参数分别从哪一级进入系统:编码器偏置 q ~ b \tilde q_b q~b 改变 PD 看到的位置,指令延迟 T d T_d Td 改变参与运算的指令时刻,这两项直接写在力矩表达式里;电枢惯量 I a I_a Ia、粘滞阻尼 d d d 与库仑摩擦 τ f \tau_f τf 则通过关节的物理属性生效,不改变力矩的数值。这也是为什么 2-3-3-2-3 节证据表中的各项能够彼此区分:前两项表现为整段轨迹的偏移与相位差,后三项表现为不同频段的幅值差异。
-
第三级的电流环在辨识模型中被直接略去。这一简化成立的前提是电流环带宽远高于机械频带,即力矩指令到电磁转矩近似为单位增益。论文用 10 kHz 的采样单独测试电流环响应,正是为了支撑这一假设;2-3-1-6 中闭环传递函数把 P τ P_\tau Pτ、 D τ D_\tau Dτ 与 I a I_a Ia、 d d d 放在同一个分式中讨论,也建立在这一前提之上。
-
但电流环并非在所有场合都可以跳过。当目标从运动性能转向能量效率时,电机的电阻、反电动势常数与电流环损耗都会重新进入模型,2-4 节的永磁同步电机能量模型正是在这一级上展开的。
说人话:位置指令只是"告诉关节该去哪",真正让它动起来的是力矩。PD 负责把"还差多少、差得多快"换算成该出多大力,驱动器再把这个力换算成电流交给电机。所以整条链路上,位置在最上面,力矩在中间,电流在最下面。
2-3 关节动力学参数辨识
2-3-1 真实机器人数据采集:Chirp 信号
2-3-1-1 Chirp 信号

- Chirp 信号(线性调频信号)是一种频率随时间连续变化的激励信号。
- 简单来说,就是让电机或关节接受一个频率从低到高(或从高到低)不断变化的振荡指令,而不是始终以固定频率运动。
- 例如:
- 开始:0.1 Hz,缓慢来回摆动。
- 中间:5 Hz,摆动频率逐渐提高。
- 结束:10 Hz,快速来回摆动。
2-3-1-2 数据采集条件
- 数据采集条件: 论文对真实机器人的采集环境提出了三项要求:
- 固定基座: 将机器人固定,避免机身运动带来的额外干扰。
- 完全悬空: 保证腿部不与地面或其他物体接触,避免外部接触力影响关节响应。
- PD 位置控制: 真实机器人与仿真机器人都通过 PD 位置环跟踪同一段参考轨迹。
- 这三个条件的目的,是尽可能排除关节动力学之外的干扰因素,让真实机器人与仿真机器人在相同输入下进行对比。由于两者都跟踪同一条参考轨迹,便可以直接比较每个时刻的关节位置误差,而不必考虑自由运动过程中逐渐累积的轨迹偏差。
2-3-1-3 扫频参数
- 扫频参数: 论文采用线性扫频,单次激励时长约为 20~40 秒。理论上,扫频上限应达到策略控制频率的一半,以覆盖策略可能涉及的动态频率。但实际还受到悬空结构和驱动器能力的限制,因此不同机器人采用了不同的扫频上限:
- ANYmal:2 Hz
- TYTAN:8 Hz
- MINIMAL:10 Hz
- 论文还指出,如果受硬件条件限制,无法达到理想的扫频上限,激励频率至少应覆盖机器人运动过程中最高频率的两倍。对于以 1 m/s 行走的机器人,这一频率约为 1 Hz。
2-3-1-4 扫频轨迹生成
- 扫频轨迹生成: 官方实现中,Chirp 信号的生成非常简单。其核心是对瞬时频率进行积分,得到相位,再通过正弦函数生成位置指令:
python
# 线性扫频:瞬时频率从 f0 线性升至 f1
t = torch.linspace(0, duration, steps=int(duration / sim_dt), device=device)
# 对瞬时频率积分,得到相位
phase = 2 * torch.pi * (
f0 * t + ((f1 - f0) / (2 * duration)) * t ** 2
)
chirp_signal = torch.sin(phase)
# 为不同关节设置偏置、幅值和方向
trajectory = (
chirp_signal.unsqueeze(-1) + trajectory_bias
) * trajectory_directions * trajectory_scale
- 其中,
f0和f1分别表示起始频率与终止频率,duration表示扫频时长。需要注意的是,各关节并不是直接共用完全相同的轨迹,而是在统一扫频信号的基础上,分别设置偏置、缩放系数和运动方向。官方采集配置中,偏置包括 0、0.4、0.8 rad,缩放系数包括 0.25、0.5 和 -2.0,从而让不同关节覆盖不同的工作区间。
2-3-1-5 数据采样率
- 数据采样率: 论文根据不同实验的需求设置了不同采样率:
- 整机日志与底层控制:400 Hz。
- 单驱动机械扫频:2.5 kHz。
- 电流环测试:10 kHz。
2-3-1-6 PD 增益的选择
- PD 增益的选择: 除了激励信号本身,位置控制器的 PD 增益也会影响参数辨识效果。论文通过闭环位置跟踪传递函数分析了这一问题: H q ( s ) = e − s T d P τ I a s 2 + ( d + D τ ) s + P τ H_q(s)=e^{-sT_d} \frac{P_\tau} {I_a s^2+(d+D_\tau)s+P_\tau} Hq(s)=e−sTdIas2+(d+Dτ)s+PτPτ其中:
- T d T_d Td 表示系统延迟
- I a I_a Ia 表示等效惯量
- d d d 表示机械阻尼
- P τ P_\tau Pτ 和 D τ D_\tau Dτ 分别对应位置环的比例与微分增益。
- 该模型建立在内层电流环带宽足够高、执行器未进入饱和等假设之上,主要用于分析闭环系统的频率响应。
- 从公式可以看出,提高 PD 增益会改变系统的闭环极点,使其向更高频率移动。但悬空台架能够提供的激励带宽有限,如果极点超出了实际可激励的频率范围,就难以准确辨识对应的动态特性。
- 因此,PACE 并没有盲目提高 PD 增益,而是选择较低的增益,使系统的主导极点尽可能落在可激励频带内。论文实验也表明,提高增益并没有改善辨识质量,反而可能使关键动态特性超出有效激励范围。
2-3-2 辨识参数
2-3-2-1 五个参数
- 论文只辨识五类量,对 n n n 个驱动关节,参数向量为 p = I a , d , τ f , q \~ b , T d ⊤ ∈ R 4 n + 1 p = \left\\, I_a,\\; d,\\; \\tau_f,\\; \\tilde{q}_b,\\; T_d \\,\\right^{\top} \in \mathbb{R}^{4n+1} p=Ia,d,τf,q\~b,Td⊤∈R4n+1其中:
- I a I_a Ia:有效电枢惯量,把转子、传动与未建模的附加惯量合在一起
- d d d:粘滞阻尼系数
- τ f \tau_f τf:库仑摩擦(在 Isaac Lab 中作为摩擦系数写入)
- q ~ b \tilde{q}_b q~b:关节位置偏置,描述指令零位与真实零位之间的准静态差
- T d T_d Td:全局指令延迟,所有关节共用同一个值
- 其中:
| 参数(LaTeX) | 含义 | 通俗解释 | 参数越大意味着什么? | 相关物理量 / 影响 |
|---|---|---|---|---|
| I a I_a Ia | 有效电枢惯量(Effective Armature Inertia) | 描述关节转动时的惯性,包含电机转子、传动机构及未建模的附加惯量 | 惯量越大,关节越难加速和减速;相同力矩下,角加速度越小,响应越慢 | 转子惯量、传动惯量、角加速度 |
| d d d | 粘滞阻尼系数(Viscous Damping) | 描述关节运动时与速度相关的阻力 | 阻尼越大,相同转速下受到的阻力矩越大,需要更大的力矩才能维持运动 | 关节速度、阻力矩、机械损耗 |
| τ f \tau_f τf | 库仑摩擦(Coulomb Friction) | 描述关节运动时近似恒定的摩擦阻力 | 摩擦越大,关节克服摩擦所需的力矩越大,低速运动和启动越困难 | 摩擦力矩、启动阻力、机械损耗 |
| q ~ b \tilde q_b q~b | 关节位置偏置(Joint Position Bias) | 描述控制指令零位与真实关节零位之间的偏差 | 偏置绝对值越大,零位偏差越明显,相同位置指令下的实际位置误差越大 | 编码器零位、关节安装偏差、位置误差 |
| T d T_d Td | 全局指令延迟(Global Command Delay) | 描述控制指令从发出到真正作用于关节之间的时间差 | 延迟越大,关节响应越滞后,跟踪误差和控制相位滞后通常越明显 | 通信延迟、控制周期、相位滞后 |
- 补充说明:
- 对于 I a I_a Ia、 d d d、 τ f \tau_f τf,参数增大都会让关节运动更难,但影响机制不同:分别对应惯性、速度相关阻力和近似恒定的摩擦阻力。
- 对于 q ~ b \tilde q_b q~b,不能简单说数值越大越差,应该看其绝对值,正负分别代表不同的偏移方向。
- 对于 T d T_d Td,延迟越大,系统相位滞后越明显,可能降低闭环控制性能。
2-3-2-2 合理性说明
- 这五项之所以够用,是因为它们正好决定闭环关节空间的极点位置与稳态偏置。粘滞阻尼与电枢惯量决定二阶系统的两个极点,库仑摩擦刻画低速段的非对称性,偏置与延迟刻画稳态误差与时序误差
说人话: 这五个参数分别描述了关节的惯性、运动阻力、摩擦、零位偏差和指令延迟。通过辨识它们,就能让仿真关节在运动响应和实际表现上尽可能接近真实关节。
- 反过来,很多更低层的参数是结构上不可辨识 的。论文给出了两条具体的论证
- PD 增益不能与动力学一起优化。对任意公共缩放 u c u_c uc(任意的公共缩放因子,非零正数),下面的变换保持方程与轨迹不变,最优解不唯一 u c I a ⋆ q ¨ + u c d ⋆ q ˙ = u c P τ ⋆ Δ q − u c D τ ⋆ q ˙ u_c I_a^{\star} \ddot q + u_c d^{\star} \dot q = u_c P_\tau^{\star} \Delta q - u_c D_\tau^{\star} \dot q ucIa⋆q¨+ucd⋆q˙=ucPτ⋆Δq−ucDτ⋆q˙
- 电机力矩常数 k i k_i ki 在位置控制下只是一个全局力矩缩放,会与惯量、阻尼混在一起,同样不可单独辨识,只能被吸收进有效参数
- 一个容易被忽略的细节是偏置 q ~ b \tilde q_b q~b。它来自编码器零位、装配公差与固件补偿,在辨识与部署之间近似恒定,如果不建模,就会表现为 PD 设定点的稳态偏移,而这个偏移恰好是图 1 里 actuator network 那条约 5 度的位置偏置的来源
- 参数数量随关节线性增长:12 个关节对应 49 个参数。官方实现在 v0.2.0 里额外支持把库仑摩擦拆成静摩擦与动摩擦,用一个 0 , 1 0,1 0,1 的比例表示动摩擦与静摩擦之比,使参数从 49 增至 61,同时保证动摩擦不超过静摩擦
2-3-3 CMA-ES 优化算法
2-3-3-1 CMA-ES定义
- CMA-ES 我们在【模型式强化学习】(四):World Models------从潜在状态建模到梦境中的策略进化 的1-5-3 ES 的基本思想与 CMA-ES 提到过
- 以防你没看过,CMA-ES(Covariance Matrix Adaptation Evolution Strategy)即协方差矩阵自适应进化策略,是一种基于种群的黑盒优化算法。它通过不断采样候选参数、评估适应度,并根据优秀候选解调整搜索分布,逐步逼近最优解。
- 辨识目标定义为逐环境、逐时间步的关节位置误差平方均值
ℓ e = 1 k ∑ i = 1 k ∥ q i real − q i , e sim ∥ 2 , p ⋆ = arg min p E ℓ e \ell_e = \frac{1}{k} \sum_{i=1}^{k} \left\| q_i^{\text{real}} - q_{i,e}^{\text{sim}} \right\|^{2}, \qquad p^{\star} = \arg\min_{p} \; \mathbb{E}\left\\ell_e\\right ℓe=k1i=1∑k qireal−qi,esim 2,p⋆=argpminEℓe
-
选择黑盒优化器的原因:目标是轨迹级的、非凸的,并且因为摩擦、饱和与延迟而不可微,在整条硬件对齐的仿真管线里反传梯度既困难也不必要
- 选 CMA-ES 而不是贝叶斯优化,一个直接的理由是种群结构与并行仿真的匹配:一次 ask 直接给出整批候选,每个候选恰好占一个环境,评估成本就是一次轨迹回放;而协方差自适应让搜索分布在量纲差异很大的参数之间(惯量 10 − 2 10^{-2} 10−2 与偏置 10 − 2 10^{-2} 10−2)保持一致的有效步长
-
官方实现把每个参数按各自的上下界归一化到 − 1 , 1 -1, 1 −1,1,优化器在归一化空间里以零均值和 σ = 0.5 \sigma = 0.5 σ=0.5 初始化。零均值对应物理可行区间的中心,是一个无偏先验; σ = 0.5 \sigma = 0.5 σ=0.5 则在归一化空间里铺开足够的探索宽度
-
种群规模直接等于并行环境数。以 ANYmal 为例,配置中固定的参数上下界为:电枢惯量 10 − 5 10^{-5} 10−5 至 1.0 1.0 1.0、粘滞阻尼 0 0 0 至 7 7 7、摩擦系数 0 0 0 至 0.5 0.5 0.5、偏置 ± 0.1 \pm 0.1 ±0.1、延迟 0 0 0 至 10 10 10 个仿真步
-
下面是优化器的核心循环,省略了日志与存档部分
python
# 归一化坐标映射回物理参数:[-1, 1] 先到 [0, 1],再线性映射到各自上下界
def _params_to_sim_params(self, params):
sim_params = (params + 1.0) / 2.0
sim_params = self.bounds[:, 0] + sim_params * (self.bounds[:, 1] - self.bounds[:, 0])
return sim_params
# 每一代开始:向 CMA-ES 问一批候选,展开成 4096 组物理参数
def _reset_population(self):
for i in range(self.optimizer.population_size):
self.params[i, :] = torch.tensor(self.optimizer.ask(), device=self.device)
self.sim_params = self._params_to_sim_params(self.params)
# 轨迹回放中:逐时间步累加误差,注意先扣掉编码器偏置
def tell(self, sim_dof_pos, real_dof_pos):
err = sim_dof_pos - real_dof_pos - self.sim_params[:, self.bias_idx]
self.scores += torch.sum(torch.square(err), dim=1)
self.scores_counter += 1
# 一条轨迹放完后:时间取平均,交给 CMA-ES 更新分布
def evolve(self):
self.scores /= self.scores_counter
solutions = [(self.params[i].cpu().numpy(), self.scores[i].item())
for i in range(self.optimizer.population_size)]
self.optimizer.tell(solutions) # 排序、加权重组、更新协方差与步长
self._reset_population()
- 代码里有一处值得单独说明:误差计算中减去了偏置项,这是两套坐标系的对齐写法。实机日志记录的是编码器读数,它等于真实关节位置减去偏置,即 q enc = q true − q ~ b q^{\text{enc}} = q^{\text{true}} - \tilde q_b qenc=qtrue−q~b;仿真报告的则是 q true q^{\text{true}} qtrue。两者直接相减会引入一个恒定的 q ~ b \tilde q_b q~b 偏移,必须先补回,否则优化器会把偏置当作待消除的误差,并将其吸收进惯量与摩擦的估计
- 收敛过程如图 7,纵轴是归一化后的误差分数(单位 rad 2 \text{rad}^2 rad2),对数刻度下呈数量级下降。三者的收敛速度不同:MINIMAL 在 30 至 40 代内降至 2 × 10 − 3 2\times10^{-3} 2×10−3 附近并趋于平缓,TYTAN 在 70 代之后基本进入平台期,ANYmal 到 100 代仍在缓慢下降

- 代价方面,论文给出的数字是:4096 个环境、单张 RTX 3080、每个平台端到端 10 至 24 小时,具体取决于轨迹长度、GPU 吞吐与参数边界
2-3-3-2 参数辨识
- 前面分别讲了激励信号、采集条件与优化算法,这一节把它们串成一条完整的辨识链路。整条链路可以概括为四个环节:固定悬空、扫频激励、并行回放、逐代更新
2-3-3-2-1 第一步:固定与悬空
- 第一个环节是固定与悬空。它把被测对象从整机落地的多体系统化简为一组互不耦合的关节链:没有地面接触,就不存在未建模的接触力;
- 基座固定,机身就不会在激励过程中发生位移,惯性耦合与位姿变化也一并消失。
- 此时关节的运动方程里只剩下驱动力矩、自身的惯性项、阻尼项与摩擦项,待辨识的参数与可观测量之间才算建立起一一对应
2-3-3-2-2 第二步:扫频激励
- 第二个环节是扫频激励。阶跃或单频正弦只能在一个时间尺度上激励系统,无法把惯量、阻尼、摩擦与延迟分开;线性扫频则在 20 至 40 秒内把频率从接近直流的 0.1 Hz 连续推到上限,一条轨迹就包含了从准静态到高频的完整响应。再叠加各关节不同的偏置、幅值与方向,使每条腿都经历各自的工作区间
| 扫频阶段 | 系统响应特征 | 主要反映的参数 |
|---|---|---|
| 低频段(接近准静态) | 惯性力与阻尼力较小,跟踪误差主要受伺服刚度与零位偏置影响 | 关节位置偏置 q ~ b \tilde q_b q~b |
| 中频段 | 相位滞后逐渐明显,系统响应开始表现出动态特性 | 粘滞阻尼 d d d、指令延迟 T d T_d Td |
| 高频段 | 加速度项逐渐占主导,惯性效应更加明显 | 电枢惯量 I a I_a Ia |
| 换向区域 | 速度方向发生改变,摩擦力矩随运动方向反转,正反向跟踪误差可能不对称 | 库仑摩擦 τ f \tau_f τf |
- 扫频过程中需要记录的不是完整的机器人状态,而是回放比对所需的三个量:
| 记录量 | 含义 | 作用 |
|---|---|---|
| 时间戳 t t t | 每个采样时刻的时间 | 确定回放步数,以及对应的扫频瞬时频率 |
| 目标位置 q des q_{\text{des}} qdes | PD 位置环实际收到的指令 | 保证仿真回放使用与实机相同的输入 |
| 实测关节位置 q meas q_{\text{meas}} qmeas | 编码器测量的位置 | 作为仿真与真实系统逐时刻比较的目标 |
- 数据记录: 只需记录时间戳、目标位置和实测位置。速度可由位置差分得到,力矩属于执行器模型内部的计算量,无需单独记录;将其作为实测拟合目标反而会引入力矩标定和电流环误差。
- 采样率: 整机日志采用 400 Hz,与底层控制同频。对于 10 Hz 的扫频上限,每个周期约有 40 个采样点,足以描述高频响应。
- 数据格式: 每条轨迹保存为矩阵(行对应采样步数,列对应关节),并记录关节顺序、扫频参数及各关节的偏置、幅值和方向,保证实机数据与仿真回放使用相同输入。
- PD 增益: 需要适当降低,使闭环主导极点落在可激励频带内。否则增益过高会将极点推至扫频上限之外,导致高频辨识信息丢失。具体原因见 2-3-1-6。
2-3-3-2-3 第三步:并行回放
- 第三个环节是并行回放。PACE 在仿真中创建 4096 个相同的机器人环境,每个环境对应一组不同的候选参数 p e p_e pe。所有环境从实机实验对应的初始状态出发,接收同一条实机记录的目标关节位置轨迹。
- 仿真机器人并不是直接照搬实测关节位置,而是将目标位置输入 PD 位置环,根据当前仿真关节位置和速度计算控制力矩,再通过执行器动力学模型计算关节响应。不同环境由于惯量、阻尼、摩擦、位置偏置和延迟等参数不同,最终产生的关节运动也不同。
- 每个环境都完整回放这段轨迹,并记录仿真关节位置 q i , e s i m q_{i,e}^{\mathrm{sim}} qi,esim,再与真实关节位置 q i r e a l q_i^{\mathrm{real}} qireal 逐时刻比较。由于两边使用相同的目标输入,比较重点就落在动力学响应本身,而不是两套系统执行不同轨迹所产生的误差。
2-3-3-2-4 第四步:逐代更新
- 第四个环节是逐代更新。这里由 CMA-ES 负责优化参数,而并行仿真负责评估参数。
- 首先,CMA-ES 根据当前搜索分布采样出一批候选参数,每组参数分配给一个仿真环境。4096 个环境并行完成轨迹回放后,分别计算各自的平均关节位置误差: ℓ e = 1 k ∑ i = 1 k ∥ q i r e a l − q i , e s i m ∥ 2 \ell_e = \frac{1}{k}\sum_{i=1}^{k} \left\| q_i^{\mathrm{real}}-q_{i,e}^{\mathrm{sim}}\right\|^2 ℓe=k1i=1∑k qireal−qi,esim 2
- 误差越小,说明这组参数对应的仿真关节响应越接近真实机器人。随后,CMA-ES 根据候选参数及其误差进行排序,利用表现较好的候选解更新搜索分布的均值和协方差矩阵。
- 其中,均值决定下一代参数主要向哪个方向搜索,协方差矩阵则逐步学习不同参数之间的相关性,调整搜索范围和方向。优化器再从更新后的分布中采样新一代参数,重复上述过程。
- 随着迭代推进,搜索分布逐渐向低误差区域集中,最终找到一组能够较好复现真实关节运动的动力学参数。
2-3-3-2-5 总结
- 四个环节的分工可以这样理解:固定与悬空保证误差只来自关节动力学,扫频保证每个参数都能在某个频段上获得主要的辨识信息,回放保证比较的是同一条输入下的响应,CMA-ES 保证在不可微的目标上仍然能够搜索。四者缺一,辨识结果都会退化成几个参数之间的折中
- 还有一处工程上的取舍:扫频越长,低频段的信息越充分,但机体温升与磨损会在此期间改变电阻与摩擦,使后半段的测量偏离前半段的模型。因此 20 至 40 秒的采集时长也可理解为信息量与参数平稳性之间的一种折中
说人话: 先让真实机器人执行扫频运动,记录它的目标位置和实际运动位置;然后让仿真机器人接收相同的目标位置,使用 PD 控制执行同样的运动。接着通过 CMA-ES 不断调整仿真中的五类动力学参数,让仿真输出的关节位置尽可能接近真实机器人的实测位置,最终得到一组更符合真实机器人的参数。
2-3-3-3 辨识结果
- 论文给出的辨识结果如下,这里摘出左前腿与延迟,完整表格见论文表 6
| 参数 | TYTAN LF HAA(左前髋外展) | TYTAN LF HFE(左前髋屈伸) | TYTAN LF KFE(左前膝屈伸) | ANYmal LF HAA(左前髋外展) | ANYmal LF HFE(左前髋屈伸) | ANYmal LF KFE(左前膝屈伸) |
|---|---|---|---|---|---|---|
| 电枢惯量 I a I_a Ia × 10 − 3 \\times 10\^{-3} ×10−3 kg m 2 \^2 2 | 140 | 106 | 3.3 | 76 | 76 | 67 |
| 粘滞阻尼 d d d N m s rad − 1 \^{-1} −1 | 1.7 | 0.17 | 2.1 | 4.9 | 4.4 | 5.2 |
| 库仑摩擦 τ f \tau_f τf -- | 0.0093 | 0.044 | 0.00025 | 0.0054 | 0.021 | 0.028 |
| 关节偏置 q ~ b \tilde q_b q~b rad | 0.0017 | -0.011 | -0.028 | 0.022 | 0.0057 | -0.003 |
| 全局延迟 T d T_d Td ms | 7.5 | 7.5 | 7.5 | 7.5 | 7.5 | 7.5 |
-
其中:
-
ANYmal:ETH Zurich 与 ANYbotics 开发的四足机器人,面向复杂地形行走和工业巡检,采用高性能关节执行器,具备较成熟的感知与自主导航能力。

-
TYTAN:ETH Zurich RSL 自主设计的高扭矩四足机器人。它结合了 ANYmal 的主体结构与低惯量、高扭矩密度的腿部设计。

-
MINIMAL:ETH Zurich 设计的小型四足机器人,主体大量采用 3D 打印结构,使用高性能准直驱执行器和可变传动比关节。

-
-
这张表里有三条可以直接读出来的事实:同类关节在同类机器人上收敛到相近的惯量;ANYmal 的阻尼显著高于 TYTAN 与 MINIMAL(串联弹性谐波减速器带来的结果);两台机器人都辨识出 7.5 ms 的全局延迟,而 MINIMAL 的延迟辨识为 0

- 图 24 解释了为什么整机辨识出的 I a I_a Ia 会比单驱动台架大一个量级:等效惯量里除了转子,还包含连杆自身的惯量在关节上的折算,以及固件补偿引入的视在惯量
2-3-4 执行器动力学辨识
- 前面介绍了需要辨识的五类参数,以及对应的 CMA-ES 优化方法。接下来,我们先从单个执行器入手,看看 PACE 如何验证动力学参数辨识的准确性。
- 单驱动台架是这套流程里最可控的一层,作用是给"辨识出来的惯量是不是物理真实"提供外部校验。它只用于验证,不是流程的必要环节
说人话:本环节相当于先用一个单独的关节做实验,检查通过参数辨识得到的惯量等参数是否符合真实的物理情况。
-
台架把单个髋关节刚性固定在铝型材上,电机轴竖直,重力项可以忽略;输出端通过锁紧销挂一个 503 g 的质量块,改变挂载半径即可改变输出惯量,范围是 1.65 1.65 1.65 到 6.27 × 10 − 2 6.27 \times 10^{-2} 6.27×10−2 kg m 2 ^2 2

-
按达朗贝尔原理,输出端折算惯量由转子、太阳轮组件、行星轮与输出轴四部分组成
I ~ output = ( 1.14 + 0.511 + 0.00203 + 0.00146 ) × 10 − 2 ≈ 1.65 × 10 − 2 kg m 2 \tilde I_{\text{output}} = (1.14 + 0.511 + 0.00203 + 0.00146) \times 10^{-2} \approx 1.65 \times 10^{-2}\ \text{kg m}^{2} I~output=(1.14+0.511+0.00203+0.00146)×10−2≈1.65×10−2 kg m2
* 这一层只辨识三个参数:电枢惯量、粘滞阻尼与库仑摩擦。偏置在此不产生影响(无重力耦合),延迟可以忽略(微秒级)
- 对应的仿真模型是单连杆单关节,连杆惯量置零,让 I a I_a Ia 吸收全部惯量。需要注意仿真载体的区别:这一层用的是 Isaac Gym,整机辨识与策略训练才在 Isaac Lab 中完成
说人话:这里相当于单独拿出一个关节做实验,把它固定在台架上,再通过悬挂不同重量、改变挂载位置来改变关节需要带动的惯量。随后让仿真关节执行相同的运动,通过 CMA-ES 调整惯量、阻尼和摩擦参数。如果辨识出来的惯量与实际计算值接近,就说明这套参数辨识方法具有一定的物理可信度。
- 实验共 30 组:5 种负载工况乘 3 种 PD 配置,再分固件补偿开启与关闭两套。每组单独拟合,总耗时约 5 小时
- 结果:在关闭固件补偿的模式下,拟合惯量与解析值相比,转子误差 2%、接口件 6%、挂载质量 15%;跨 PD 配置的标准差分别是 0.67%、3.7% 与 14%。有一组高增益加重载的工况导致杠杆机构损坏,被排除在外

- 打开固件补偿后,所有工况的拟合值都出现一个近似恒定的偏移,等效为 8.1 × 10 − 3 8.1 \times 10^{-3} 8.1×10−3 kg m 2 ^2 2 的"虚拟惯量"。这条结论直接给出了工程约束:辨识与部署必须使用同一套固件模式,否则这个偏移会在两边各出现一次

- 电流环是否需要单独建模,论文用电流扫频给了答案:1 至 1250 Hz、幅值 2 A、时长 25 秒,实测传递函数在 100 Hz 以内与解析模型一致,幅值保持 0 dB、相位滞后不超过 5 度直到 25 Hz,推导出控制带宽约 346 Hz、死区约 400 微秒。在这个带宽之下,把电流环当作单位增益是成立的

2-3-5 整机腾空状态辨识(In-air)
- 在整机层,五类参数全部参与辨识:12 个关节的惯量、阻尼、摩擦、偏置,加一个全局延迟,共 49 个
- 这一层没有新的目标函数,仍是同一段扫频轨迹的逐时刻位置误差,只是把台架换成了悬空的整机,接触项全部去掉
说人话:上一节是在单个关节的台架上进行辨识,而这一节则把机器人整机吊起来,让 12 个关节同时执行扫频运动。在不考虑地面接触的情况下,通过 CMA-ES 优化全部 49 个参数,让仿真整机的关节运动尽可能接近真实机器人。
2-3-5-1 轨迹重合
- 结果的第一项证据是轨迹重合。TYTAN 在拟合参数下的重放轨迹与实测几乎重叠

2-3-5-2 跨增益泛化
- 第二项证据是跨增益泛化。用一组 PD 增益辨识出的参数,换另一组增益仍然保持重合,这说明拟合到的是物理模型,而不是对某条轨迹的函数逼近

2-3-5-3 更强的基线的对照
- 第三项证据是与更强的基线的对照。图 1 与图 8 把三种建模方式放在一起:不带执行器模型的 URDF 基线、ANYbotics 的 LSTM 执行器网络,以及 PACE
- 图 1c 的相图把误差画在 ( Δ q , Δ q ˙ ) (\Delta q, \Delta \dot q) (Δq,Δq˙) 平面上,点越靠近原点说明仿真轨迹越接近真实。PACE 的点最集中,URDF 基线大范围发散,执行器网络介于两者之间但存在约 5 度的位置偏置


- 图 8 是放大后的时间序列,可以直接看出无模型的仿真在两个周期内就与实测错开,而 PACE 与实测几乎重合
- 这组对照还要放在数据量的尺度上看:PACE 只用了约 20 秒的腾空位置数据,2019 年的执行器网络用了约 4 分钟的带力矩数据,而厂商部署的 LSTM 很可能训练于更大的数据集。前者的精度更高、数据量却少一个数量级,这是这套方法在工程上最直接的收益
2-3-5-4 未见轨迹上的泛化
- 第四项证据是未见轨迹上的泛化。MINIMAL 上除了扫频,还采集了随机阶跃轨迹,两种轨迹都能被同一组参数复现,而 URDF 基线在两种轨迹上都明显偏离


- 这里有一个必须解释的数值:TYTAN 左前 HFE 整机辨识出的惯量是 10.6 × 10 − 2 10.6 \times 10^{-2} 10.6×10−2 kg m 2 ^2 2,约为单驱动估算值 2.5 × 10 − 2 2.5 \times 10^{-2} 2.5×10−2 的四倍,而阻尼 0.17 N m s rad − 1 ^{-1} −1 与预期一致
- 论文给了三条解释:CAD 低估了连杆惯量(尤其大腿)、固件补偿引入了视在惯量、以及转子惯量本身。附录 C 用单腿段的摆锤实验做了诊断,确认了这个量级
2-3-6 地面运动验证(On-ground)
- 需要先划清一条界线:所有参数辨识都只用腾空数据,地面接触阶段的数据不参与估计。地面实验的角色是下游验证
说人话:前面所有参数都是通过机器人腾空时的数据辨识出来的,并没有使用机器人在地面行走时的数据。这里则是把辨识得到的参数用于仿真,再让仿真机器人和真实机器人在地面执行相同的运动,检查仿真能否复现真机的运动表现。
- 用辨识出的参数训练策略后,TYTAN 的开环基座速度回放如图 6。真实与仿真的绝对运动与相对运动都吻合,线速度与偏航角速度跟踪也一致


- 图 6d 的力矩跟踪给出一个更细的结论:关节层的力矩保真度不需要通过力矩传感器来校准,端到端辨识到关节位置层面,就足以让策略指令的力矩在真机上被复现,误差只在离地瞬间的 KFE 上略有增大
- 这一节的方法论意义在于"分层验证":单驱动验证参数是否物理可解释,整机验证方法能否扩展到系统级,地面运动验证参数是否真的能支撑控制
2-4 永磁同步电机的物理能量模型
- 前面介绍了 PACE 如何通过真实机器人数据辨识动力学参数,并通过单驱动台架、整机腾空和地面运动实验验证辨识结果。接下来,我们来看论文提出的另一项重要内容:基于永磁同步电机(PMSM)的物理能量模型,让强化学习策略在学习运动控制的同时,也能考虑机器人的能耗。
2-4-1 从关节力矩到电机能耗
-
前面介绍过,PACE 在关节层采用 PD 位置控制器。控制器根据目标位置与实际位置之间的误差,计算需要施加的关节力矩: τ c m d = K p ( q d e s − q ) + K d ( q ˙ d e s − q ˙ ) \tau_{\mathrm{cmd}} =K_p(q_{\mathrm{des}}-q) +K_d(\dot q_{\mathrm{des}}-\dot q) τcmd=Kp(qdes−q)+Kd(q˙des−q˙)
-
但这里还有一个问题:关节产生这些力矩,需要消耗多少能量?
-
现代四足机器人的关节通常由永磁同步电机(PMSM,Permanent Magnet Synchronous Motor)驱动。配合磁场定向控制(FOC),电机主要通过 q 轴电流 i q i_q iq 产生转矩。在电机参数确定时,电磁转矩与 q 轴电流近似成正比。
-
因此,从控制到能耗的过程可以理解为: PD 控制器 → 关节力矩 → 电机电流 → 能量损耗 \boxed{ \text{PD 控制器} \rightarrow \text{关节力矩} \rightarrow \text{电机电流} \rightarrow \text{能量损耗} } PD 控制器→关节力矩→电机电流→能量损耗
-
传统强化学习中,常用关节力矩平方 τ 2 \tau^2 τ2 作为能耗的代理指标。但它没有直接考虑电机自身的电阻、电机常数和减速比。PACE 的思路是从电机实际的物理过程出发,建立能量模型,而不是简单地惩罚力矩大小。
2-4-2 电机物理能量模型
2-4-2-1 电气侧:铜损
- 电机绕组存在电阻,电流流过绕组时会产生焦耳热,这部分损耗称为铜损。对第 j j j 个关节,若 q 轴电流为 i q , j i_{q,j} iq,j,关节力矩为 τ j \tau_j τj,减速比为 r j r_j rj,电机转矩常数为 k i , j k_{i,j} ki,j,则: P el = ∑ j = 1 n R j i q , j 2 = ∑ j = 1 n τ j 2 R j r j 2 k i , j 2 P_{\text{el}} =\sum_{j=1}^{n}R_j i_{q,j}^{2} =\sum_{j=1}^{n}\tau_j^{2} \frac{R_j}{r_j^{2}k_{i,j}^{2}} Pel=j=1∑nRjiq,j2=j=1∑nτj2rj2ki,j2Rj可以看到,力矩平方确实与铜损有关,但实际损耗还受到绕组电阻、减速比和电机转矩常数的影响。
- 因此,直接使用 τ 2 \tau^2 τ2 只是一个简化代理,而这里的模型能够进一步考虑不同电机的物理参数。
2-4-2-2 机械侧:机械功率
-
除了电机绕组发热,关节运动本身也涉及机械能量交换。关节机械功率由力矩与关节角速度共同决定: P mech = { τ ⊤ q ˙ , τ ⊤ q ˙ > 0 k regen τ ⊤ q ˙ , τ ⊤ q ˙ < 0 P_{\text{mech}} = \begin{cases} \boldsymbol{\tau}^{\top}\dot{\mathbf q}, & \boldsymbol{\tau}^{\top}\dot{\mathbf q}>0 \\4pt k_{\text{regen}}\boldsymbol{\tau}^{\top}\dot{\mathbf q}, & \boldsymbol{\tau}^{\top}\dot{\mathbf q}<0 \end{cases} Pmech={τ⊤q˙,kregenτ⊤q˙,τ⊤q˙>0τ⊤q˙<0
-
当力矩与速度方向一致时,关节做正功,需要消耗能量;当两者方向相反时,关节做负功,可能产生能量回馈。
- 但实际系统无法回收全部能量,因此引入回馈系数 k regen k_{\text{regen}} kregen,描述能够回灌到母线的能量比例。
2-4-2-3 重力侧:势能变化率
- 第三项考虑机器人整体的重力势能变化。根据各刚体的质量与竖直方向速度,可以计算: P pot = ∑ b = 1 B m b g v b , z P_{\text{pot}}=\sum_{b=1}^{B}m_b g v_{b,z} Ppot=b=1∑Bmbgvb,z其中:
- m b m_b mb 是第 b b b 个刚体的质量
- v b , z v_{b,z} vb,z 是其竖直方向速度。
- 这项不是简单惩罚机器人向上运动,而是反映重力势能的变化:机器人上升时势能增加,下降时势能减少。
2-4-2-4 总功率
- 将电气损耗、机械功率和势能变化率相加,得到总功率: P total = P el + P mech + P pot P_{\text{total}}=P_{\text{el}}+P_{\text{mech}}+P_{\text{pot}} Ptotal=Pel+Pmech+Ppot三项的单位都是瓦特,可以直接相加。
说人话: 前面的 PD 控制器负责计算机器人关节需要输出多大的力矩,而 PMSM 能量模型进一步计算产生这些力矩、完成这些运动需要消耗多少能量。它不再只是简单地惩罚力矩平方,而是考虑电机发热、机械能量交换和重力势能变化,让强化学习策略能够从真实物理过程出发考虑能耗。
2-4-3 能量项归一化与模型边界
- 直接将 P total P_{\text{total}} Ptotal 用作奖励项会带来一个问题:随着基座速度增大,关节运动速度和能量消耗也会增加,能量项可能压过速度跟踪项,导致策略倾向于欠跟踪。
- 为此,论文引入一个只依赖指令速度的归一化系数: γ v = 1 ∣ v ^ B ∣ 2 + 1 , r e = γ v P total \gamma_v=\frac{1}{|\hat{\mathbf v}B|^2+1}, \qquad r_e=\gamma_v P{\text{total}} γv=∣v^B∣2+11,re=γvPtotal这样可以减弱高速指令下能量项对奖励的过度影响。
- 需要注意,这套模型并不是完整的电机驱动损耗模型。它没有包含铁损、逆变器开关损耗、温度相关的电阻变化、电池动态、弱磁行为以及负载相关的传动损耗。因此,其可信度仍受到辨识过的力矩、转速和温度范围限制。
- 论文对该模型的定位是:在强化学习可接受的计算预算内,尽可能捕捉主要且随运动变化的能量损耗,而不是完整模拟电机驱动系统的所有损耗。
2-4-4 执行器饱和与模型边界

-
图 13 展示了执行器饱和的处理方式:力矩上限由最大力矩约束和反电动势对应的力矩约束共同决定,最终取两者中的较小值。
-
饱和在仿真和真实机器人中以相同方式确定性施加,不作为待辨识参数。论文指出,单纯依靠腾空轨迹数据几乎无法可靠辨识这些饱和限值,将其加入优化变量反而容易使辨识问题变得病态。

-
图 14 展示了完整的执行器链路,但它并不是参数辨识的对象。PACE 在关节空间进行端到端辨识,将电流环近似为单位增益,并把固件补偿、滤波和未建模电子学的影响吸收到有效惯量与阻尼等参数中。
-
对于自制机器人,论文还给出了一种一阶估计方法:将电机参数折算到整机重量,得到平台的焦耳加热常数,为黑盒机器人的能量项提供数量级估计。

说人话: PACE 希望建立的不是一个简单的力矩惩罚项,而是一套从关节力矩出发、结合电机电流和机械运动来估计能耗的物理模型。这样,能量奖励就有了明确的物理依据,而不是人为拍出来的一个系数。
2-5 基于辨识模型的强化学习
2-5-1 仿真环境参数更新
- 前面通过真实机器人数据辨识出了动力学参数,并验证了模型在单驱动台架、整机腾空和地面运动中的表现。接下来,需要将这些辨识结果写入仿真环境,使强化学习策略能够在更接近真实机器人的动力学模型中进行训练。
- 在 PACE 的官方实现中,辨识参数并不是统一写入某一个配置项,而是根据参数的物理作用,分别更新三个层级:
- 刚体级(Rigid Body): 写入电枢惯量 I a I_a Ia。
- 关节级(Joint): 写入粘滞阻尼 d d d、静摩擦与动摩擦系数。
- 执行器级(Actuator): 写入编码器位置偏置 q ~ b \tilde q_b q~b 与指令延迟 T d T_d Td。
- 这里有一个需要注意的工程细节:Isaac Lab 不允许静摩擦系数小于动摩擦系数,因此不能直接依次写入两组摩擦参数。官方实现采用了分步更新的方式:先将动摩擦系数置零,再写入静摩擦系数,最后恢复动摩擦系数,从而避免参数更新时违反引擎约束。
python
def update_simulator(self, articulation, joint_ids, initial_position):
env_ids = torch.arange(len(self.sim_params))
# 刚体级:电枢惯量
articulation.write_joint_armature_to_sim(self.sim_params[:, self.armature_idx],
joint_ids=joint_ids, env_ids=env_ids)
# 关节级:粘滞阻尼
articulation.write_joint_viscous_friction_coefficient_to_sim(self.sim_params[:, self.damping_idx],
joint_ids=joint_ids, env_ids=env_ids)
# 关节级:先清空动摩擦,写入静摩擦,再写回动摩擦,避免静摩擦小于动摩擦的非法状态
articulation.write_joint_dynamic_friction_coefficient_to_sim(0.0, joint_ids=joint_ids, env_ids=env_ids)
articulation.write_joint_friction_coefficient_to_sim(self.sim_params[:, self.friction_idx],
joint_ids=joint_ids, env_ids=env_ids)
articulation.write_joint_dynamic_friction_coefficient_to_sim(self.dynamic_friction(),
joint_ids=joint_ids, env_ids=env_ids)
# 执行器级:编码器偏置与指令延迟
for drive in articulation.actuators.values():
drive.update_encoder_bias(self.sim_params[:, self.bias_idx][:, drive_joint_idx])
drive.update_time_lags(self.sim_params[:, self.delay_idx].to(torch.int))
drive.reset(env_ids)
- 偏置与延迟不能靠刚体接口写入,它们属于执行器模型的内部状态,因此需要自定义执行器。
PaceDCMotor在DCMotor之上做了两件事:把关节位置换算到编码器坐标系,以及用延迟缓冲把指令推后若干个仿真步
python
def compute(self, control_action, joint_pos, joint_vel):
# 先把指令整体延迟 Td
control_action = self._delay_command(control_action)
# 控制器看到的是带偏置的编码器读数,而不是真实关节位置
sim_action = super().compute(control_action, joint_pos - self.encoder_bias, joint_vel)
# 延迟模式也可以作用在力矩上,而不是指令上
sim_action.joint_efforts = self._delay_effort(sim_action.joint_efforts)
return sim_action
- 延迟有两种作用位置:延迟指令,或延迟力矩。前者更接近"通信与控制回路的时滞",后者更接近"驱动器内部的计算与调制时滞"。官方实现把
delay_mode暴露成配置项,默认为command
2-5-2 基于物理能量模型的奖励函数
- 论文对"奖励项数量"给了一个明确的定义:按需要手工调节的独立权重个数计。一个目标即使由多个物理分量组成,只要不引入额外的相对缩放,就只算一项
- 按这个定义,PACE 只有四项奖励:速度跟踪与能量两项性能项,碰撞与触地速度两项结构安全项
- 速度跟踪沿用常见形式,前进与横向合在一起算一项,偏航单独一项
r v = exp ( − ∥ v ^ B , x y − v B , x y ∥ 2 σ v ) + exp ( − ( ω ^ B , yaw − ω B , yaw ) 2 σ v ) r_v = \exp\left(-\frac{\left\|\hat{\mathbf{v}}{B,xy} - \mathbf{v}{B,xy}\right\|^{2}}{\sigma_v}\right) + \exp\left(-\frac{(\hat{\omega}{B,\text{yaw}} - \omega{B,\text{yaw}})^{2}}{\sigma_v}\right) rv=exp(−σv∥v^B,xy−vB,xy∥2)+exp(−σv(ω^B,yaw−ωB,yaw)2)
- 能量项取 2-4 节那条总功率,再乘以只依赖指令速度的归一化系数,因此它的量纲仍是功率(W),而不是能量
- 触地项惩罚的是"以冲击方式刹车":在触地时刻,取最近三个时间步内足端速度的最大值作为惩罚量,未触地则为零
v j , ftd = max k ∈ { t − 2 , t − 1 , t } ∥ v j , k foot ∥ , r ftd = ∑ j v j , ftd v_{j,\text{ftd}} = \max_{k \in \{t-2,\, t-1,\, t\}} \left\| \mathbf{v}{j,k}^{\text{foot}} \right\|, \qquad r{\text{ftd}} = \sum_{j} v_{j,\text{ftd}} vj,ftd=k∈{t−2,t−1,t}max vj,kfoot ,rftd=j∑vj,ftd
- 论文说明了为什么不用足端 jerk(加加速度):jerk 的时间尺度由控制步长决定,无法单独调节;而触地速度的窗口长度是一个可以直接调节的物理量
- 碰撞项是示性函数:关节限位处大腿与环境的碰撞发生时取 1,否则取 0
- 四项合成时,能量与触地项带一个随时间衰减的系数 κ \kappa κ,避免训练早期因惩罚过重而无法形成有效步态
r = c v r v + c c r c + κ ( c e r e + c ftd r ftd ) , κ = 1 − e − λ t r = c_v r_v + c_c r_c + \kappa\left(c_e r_e + c_{\text{ftd}} r_{\text{ftd}}\right), \qquad \kappa = 1 - e^{-\lambda t} r=cvrv+ccrc+κ(cere+cftdrftd),κ=1−e−λt
- 论文给的半衰期经验值是 500 次迭代,具体任务需要调整
- 三个平台的权重与 PD 增益如下表,可以看到只有 MINIMAL 的能量权重被单独放大,原因是它是一台轻量的 3D 打印样机
| 项目 | TYTAN | ANYmal | MINIMAL |
|---|---|---|---|
| 速度跟踪权重 | 0.2 | 0.2 | 0.2 |
| 能量权重 × 10 − 5 \\times 10\^{-5} ×10−5 | -16 | -16 | -128 |
| 碰撞权重 | -1.0 | -1.0 | -1.0 |
| 触地速度权重 | -0.1 | -0.1 | -0.1 |
| 位置增益 P τ P_\tau Pτ | 60 | 85 | 4 |
| 速度增益 D τ D_\tau Dτ | 2 | 0.6 | 0.05 |
- 按上面的公式,能量项的 torch 实现可以直接写成
python
def energy_reward(tau, qd, v_bz, mass, motor, cmd_vel):
"""tau: 关节力矩 [Nm],qd: 关节速度 [rad/s],v_bz: 各刚体竖直速度 [m/s]
motor: 每个关节的 (R, r, ki),cmd_vel: 指令基座速度范数"""
R, gear, ki = motor["R"], motor["gear"], motor["ki"]
# 电气侧:铜损,力矩平方除以 (减速比乘电机常数) 的平方,再乘电阻
p_el = torch.sum(tau ** 2 * R / (gear ** 2 * ki ** 2), dim=1)
# 机械侧:先对全部关节求总机械功率,再按总功率的符号决定是否计入回馈
p_mech = torch.sum(tau * qd, dim=1)
p_mech = torch.where(p_mech > 0, p_mech, REGEN * p_mech)
# 势能侧:竖直速度向上为正,上升时势能增加、该项为正
p_pot = torch.sum(mass.view(1, -1) * GRAVITY * v_bz, dim=1)
# 速度归一化:只依赖指令,保证不同速度档位下两项的相对权重稳定
gamma_v = 1.0 / (cmd_vel ** 2 + 1.0)
# 返回的是单个控制步的功率 [W],不是能量
return gamma_v * (p_el + p_mech + p_pot)
-
需要说明的是,上面返回的量是每个控制步的功率,并没有乘以时间步长 Δ t \Delta t Δt。严格意义上的能量应为 E = ∫ P d t E=\int P\,\mathrm{d}t E=∫Pdt,但对固定控制步长, ∑ k P k Δ t \sum_k P_k \Delta t ∑kPkΔt 与 ∑ k P k \sum_k P_k ∑kPk 只差一个常数因子,而该因子会被能量权重 c e c_e ce 一并吸收,因此乘与不乘不影响最优策略。换言之,这里奖励的是带物理量纲的功率,逐项累加后才与能量成正比,直接称其单位为焦耳并不准确
-
与常见做法对比,这套设计有两处不同:
- 其一,能量项没有拆成"力矩平方惩罚""竖直速度惩罚"等多个手调项,而是一项带物理单位的整体;
- 其二,势能项以奖励形式出现,上坡加速、下坡回收,方向性由能量守恒本身给出
说人话:以前是"这几个惩罚我各给一个系数,凑着调";现在是"把电机实际耗掉多少功率算出来,直接按功率罚",换机器人只需换电机参数,不用重调系数
2-5-3 PPO 策略训练与 Zero-shot Sim-to-Real
-
策略训练用非对称的 PPO(Proximal Policy Optimization,近端策略优化):策略只看本体感知,评论家看特权状态
- 策略观测 48 维:基座线速度、角速度、投影重力、三项速度指令、12 个关节位置、12 个关节速度、上一步动作。
- 除指令与上一步动作外都加了独立同分布噪声
-
评论家在此基础上再加无噪声的同样观测、基座外力与力矩、地面摩擦、足端接触二值量与一块 2 m × 3 m 2 \text{ m} \times 3 \text{ m} 2 m×3 m、分辨率 0.15 m 的高度扫描,共 305 维,合计状态 353 维
-
动作是相对默认姿态的关节位置偏置,经 PD 转换成力矩 τ t = P τ ( a t + q 0 − q ) − D τ q ˙ \boldsymbol{\tau}t = P\tau\left(\mathbf{a}_t + \mathbf{q}0 - \mathbf{q}\right) - D\tau \dot{\mathbf{q}} τt=Pτ(at+q0−q)−Dτq˙
-
指令目标在送入驱动器之前还要过一道关节限位饱和:在软限位带内把目标线性地拉向硬限位,使得朝向限位的 PD 力矩在该处归零,而远离限位的方向保留全部力矩
q ^ j = { q ^ j − q j − q j soft q j hard − q j soft ( q ^ j − q j hard ) , q j ∈ Q soft , q ^ j ∉ Q feas q ^ j , otherwise \hat q_j = \begin{cases} \hat q_j - \dfrac{q_j - q_j^{\text{soft}}}{q_j^{\text{hard}} - q_j^{\text{soft}}}\left(\hat q_j - q_j^{\text{hard}}\right), & q_j \in \mathcal{Q}{\text{soft}},\ \hat q_j \notin \mathcal{Q}{\text{feas}} \\8pt \hat q_j, & \text{otherwise} \end{cases} q^j=⎩ ⎨ ⎧q^j−qjhard−qjsoftqj−qjsoft(q^j−qjhard),q^j,qj∈Qsoft, q^j∈/Qfeasotherwise
- 修正项按当前位置在软限位带内的比例加权:关节刚到软限位时修正为零,到硬限位时目标被直接改写成硬限位本身,PD 误差为零,因此不会产生推向限位的力矩
- 这道饱和在仿真与实机上同时执行,作用是保护硬件,而不是约束动作空间;论文明确说明它不构成额外的惩罚项,实验中也没有观察到策略因此产生回避行为
- 训练超参数如下表,其中熵系数按 tanh \tanh tanh 曲线从 2 × 10 − 3 2 \times 10^{-3} 2×10−3 退火到 5 × 10 − 4 5 \times 10^{-4} 5×10−4,转折点在 20000 次迭代
| 参数 | 取值 |
|---|---|
| 经验归一化 | 开启 |
| 迭代次数 | 30000 |
| 学习轮数 N epoch N_{\text{epoch}} Nepoch | 5 |
| 小批量数 N mb N_{\text{mb}} Nmb | 10 |
| 学习率 | 10 − 3 10^{-3} 10−3,自适应 |
| 折扣因子 γ \gamma γ | 0.99 |
| GAE 参数 λ \lambda λ | 0.95 |
| 裁剪系数 ϵ \epsilon ϵ | 0.2 |
| 目标 KL 散度 | 10 − 2 10^{-2} 10−2 |
| 价值损失系数 | 1.0 |
| 梯度范数上限 | 1.0 |
| 网络结构 | 256, 256, 256, 128 |
| 激活函数 | ELU(Exponential Linear Unit,指数线性单元) |
| 初始策略标准差 | 1.5 |
| 每环境步数 | 24 |
| 熵系数(起止) | 2 × 10 − 3 2\times10^{-3} 2×10−3 至 5 × 10 − 4 5\times10^{-4} 5×10−4 |
- 论文强调:由于动力学已经对齐,训练时不做动力学随机化,只随机化任务(推力、地面摩擦)与地形(平地、崎岖、楼梯、箱子、斜坡)
- 熵退火是这套配置中少见的显式调度,其用意是在训练早期维持探索、后期提高精度,这也是 2-6 节中能量效率得以下降的前提之一
2-6 实验结果与分析
2-6-1 多机器人平台验证
- 主平台三台:TYTAN(ETH 自研、准直驱加变比丝杠杠杆)、ANYmal(串联弹性谐波减速、闭源)、MINIMAL(4 kg、3D 打印、变比杠杆)
- 选型是有意为之:覆盖不同的驱动类型、尺度与开放程度。ANYmal 的角色是闭源测试台,用来证明只拿到有限的底层访问权限时方法依然适用;它同时也是"不依赖关节力矩传感器"的对照,因为它要对比的执行器网络基线正需要力矩数据

- 三个平台的几何与驱动基本参数如下表,其中 ANYmal 的部分规格为保密项
| 参数 | TYTAN(髋、膝) | ANYmal | MINIMAL |
|---|---|---|---|
| 整机质量 kg | 52.3 | 52.8 | 4.2 |
| 肩高 m | 0.62 | 0.55 | 0.25 |
| 母线电压 V | 48 | 48 | 18 |
| 回馈系数 k regen k_{\text{regen}} kregen -- | 0.3 | 0.0 | 0.3 |
| 减速比 | 5.6、0.8 至 9 | 未公开 | 7.2 至 16 |
| 最大关节力矩 N m | 140、28 至 315 | 89 | 2.9 至 6.4 |
| 最大关节转速 rad/s | 16.8、3 至 36 | 8.5 | 45 至 99.4 |
- 除三个主平台外,论文还在 AIBO、NAO、ALMA、SPACEHOPPER、LEVA、MAGNECKO v1 与 v2、GR-1、以及两只灵巧手等十余台系统上复用了同一套流程
- ANYmal 上的三臂对照最具说明力,三种策略的训练条件完全相同,只替换执行器模型



- 结果是无模型的一臂在起步约 3 秒后发散,被吊装保护绳接住;执行器网络与 PACE 都能稳定行走,稳态速度约 0.85 m/s,极限环形状接近
- 动态极限的演示进一步说明了模型精度带来的余量:ANYmal 上的两足平衡与奔跑,MINIMAL 上连续爬 20 级 18 cm 楼梯耗时 46 秒

- 其中奔跑一项在仿真中可达到约 4 m/s,真机上受电池 32 A 的限流限制,约为 3 m/s。这一上限来自电源而非模型,属于硬件约束
2-6-2 能耗与 Cost of Transport 分析
- 前面主要验证了 PACE 在不同机器人平台上的运动控制效果,包括稳定行走、动态平衡以及高速奔跑等。但机器人运动得稳定、速度快,并不意味着能量利用效率高。
- 因此,论文进一步从能耗角度评估训练得到的策略。
- 运输代价(CoT,Cost of Transport)是衡量运动效率的常用指标,定义为单位重量、单位距离消耗的能量,无量纲,越低越好
- 论文把它做了一次可加分解,每一项对应一个互不重叠的来源 CoT = CoE + CoD + CoL \text{CoT} = \text{CoE} + \text{CoD} + \text{CoL} CoT=CoE+CoD+CoL其中:
- CoE \text{CoE} CoE:电子学功耗,测量方式是机器人上电但驱动器禁用
- CoD \text{CoD} CoD:逆变器与驱动开销,测量方式是驱动器使能但力矩指令为零
- CoL \text{CoL} CoL:运动相关的损耗,包含机械耗散与焦耳热,是唯一受控制策略影响的项
- 这三项由整机电池的放电时间与荷电状态窗口反推,例如静置与关机两种状态的功率分别为
P rest = E B ( SoC rest max − SoC rest min ) t rest , P off = E B ( SoC off max − SoC off min ) t off P_{\text{rest}} = \frac{E_B \left( \text{SoC}{\text{rest}}^{\max} - \text{SoC}{\text{rest}}^{\min} \right)}{t_{\text{rest}}}, \qquad P_{\text{off}} = \frac{E_B \left( \text{SoC}{\text{off}}^{\max} - \text{SoC}{\text{off}}^{\min} \right)}{t_{\text{off}}} Prest=trestEB(SoCrestmax−SoCrestmin),Poff=toffEB(SoCoffmax−SoCoffmin)
- 一次运动的 CoT 则由该次放电的荷电状态差、整机重量与行驶距离给出, CoE \text{CoE} CoE 与 CoD \text{CoD} CoD 再按静置功率与关机功率折算
CoT = E B ( SoC track max − SoC track min ) m g Δ s , CoE = P off t track m g Δ s , CoD = ( P rest − P off ) t track m g Δ s \text{CoT} = \frac{E_B \left( \text{SoC}{\text{track}}^{\max} - \text{SoC}{\text{track}}^{\min} \right)}{m g\, \Delta s}, \qquad \text{CoE} = \frac{P_{\text{off}}\, t_{\text{track}}}{m g\, \Delta s}, \qquad \text{CoD} = \frac{\left(P_{\text{rest}} - P_{\text{off}}\right) t_{\text{track}}}{m g\, \Delta s} CoT=mgΔsEB(SoCtrackmax−SoCtrackmin),CoE=mgΔsPoffttrack,CoD=mgΔs(Prest−Poff)ttrack
- 400 米跑道上的结果是本文最具分量的实验结果。ANYmal D 的 CoT 从上一代 ANYmal C 的 1.86 降到 1.27,降幅约 32%;TYTAN 达到 0.97
| 指标 | ANYmal C | ANYmal D | TYTAN |
|---|---|---|---|
| 圈数 | 6.6 | 10.3 | 15.25 |
| 距离 m | 2640 | 4120 | 6100 |
| 时长 min | 59 | 82 | 104 |
| 指令速度 m/s | 1.0 | 1.0 | 1.0 |
| 平均速度 m/s | 0.740 | 0.850 | 0.978 |
| 平均功率 W | 723 | 556 | 504 |
- 分解到三项上,运动相关损耗 CoL 从 1.12 降到 0.53,降幅约 53%,而电子学与驱动两项没有变化。按照论文的分解口径,CoT 的改善全部落在 CoL 上,CoE 与 CoD 不随步态改变
- 需要注意归因边界。两行分属不同代际的平台,论文没有做同一台机器人上更换策略的对照实验,因此 32% 只能理解为相对上一代平台与既有方法的整体改善,而不是严格剥离了硬件差异之后的策略增益
| 机器人 | CoE | CoD | CoL | CoT |
|---|---|---|---|---|
| ANYmal C | 0.50 | 0.24 | 1.12 | 1.86 |
| ANYmal D | 0.50 | 0.24 | 0.53 | 1.27 |
| TYTAN | 0.29 | 0.21 | 0.47 | 0.97 |
- 需要说明数据来源:ANYmal C 这一行引自 Bjelonic 等人 2023 年的工作,论文用括号标注;ANYmal D 与 TYTAN 为本次实测。两代的电子学与驱动两项数值相同,因为这两项由硬件决定、与控制策略无关


- 效率改善的机制在论文中给出了具体解释:精确的仿真让策略不必为参数不确定性预留余量,ANYmal 因此在平坦地形上采用了更直的膝关节步态。步态形状的变化可以在膝关节极限环与关节频谱上看到


- 一个反直觉的结论是 TYTAN 的运动损耗 CoL 只比 ANYmal 低约 11%(0.47 对 0.53),尽管它的驱动效率更高、腿的惯量更低。原因是它的膝关节机构无法完全伸直,在平地行走时这个姿态代价抵消了驱动上的优势,这条结论反过来强调了膝关节完全伸展对平地能效的重要性
- 论文用同一张图给出另一个观察:两只机器人的能量预算里,真正用于运动的不到一半,其余是电子学与逆变器开关损耗。这条结论会限制"只靠算法优化"能达到的上限
2-6-3 不使用动力学域随机化的迁移效果
- 前面介绍了 PACE 如何通过系统辨识提高仿真动力学模型的准确性。本节进一步回答一个关键问题:如果不使用动力学域随机化,仅依靠准确的动力学模型,能否实现 Sim-to-Real 迁移?
- 论文首先通过真机对照实验验证策略迁移效果,再结合速度上限分析和方法假设,讨论不使用动力学域随机化的适用条件与局限。
2-6-3-1 策略层面:三臂对照实验
- 先看策略表现:在 ANYmal 上的三臂对照实验中,三种策略采用相同的训练条件,仅替换执行器模型。其中,无模型的一臂在起步约 3 秒后便出现发散,而使用执行器网络和 PACE 模型的两臂都能够保持稳定行走。
- 这一结果说明,在不使用动力学域随机化的情况下,仿真模型的准确性对策略迁移效果至关重要。PACE 通过辨识得到更准确的执行器模型,使策略在仿真中学到的运动行为能够更好地迁移到真实机器人。


- 图 9e 的右半是稳态速度误差的分布,PACE 与执行器网络的分布接近,无模型的一臂已经无法统计
2-6-3-2 方法层面:模型误差与适用边界
- 再看方法层面:论文指出速度上限本身是现实差距的敏感代理。步频越高,同一份模型误差在相位上的累积越快,可达速度也就越早受到限制。这也解释了为什么无模型的策略在低速同样失败,而覆盖这一差距所需的随机化范围会随步频迅速扩大
- 论文对这一点的表述较为谨慎:作者并不认为精确拟合取代了域随机化或在线自适应,两者是互补的,后两者能在未建模的环境与硬件变化下继续提供鲁棒性;同样的结果也并非 PACE 独有,但在这里它来自一个紧凑、物理可解释的执行器层参数集
- 论文同时给出了边界的另一面:这套方法依赖若干假设,包括运动学无误、电流环带宽足够、采集期间温度稳定、激励频带内结构刚度足够。任一假设被违反,辨识结果就不再可信,这是在线自适应或完全无模型方法可能占优的场合
3 部署流程参考
3-1 介绍
- 这一章把论文与官方实现中的操作顺序整理为一套可执行的流程。六个环节各配置一段官方代码的关键片段,逐段说明其作用与必要性,最后汇总若干常见问题
- 先说前提。论文在 Remarks 一节列出五条假设,任一不成立都会使辨识结果不可信,作者同时指出这五条在图 4 的全部平台上都得到了经验验证:
- 运动学正确,URDF 或 USD(Universal Scene Description,通用场景描述)中的连杆长度与关节轴没有错误
- 电流环带宽足够高,或者在激励频带内可以近似为线性时不变系统
- 采集期间温度稳定,避免电阻与摩擦随温漂移
- 激励频带内非线性可控,超出部分能被有效参数吸收
- 悬空状态下结构刚度足够,基座不会在激励中晃动
3-2 从数据采集到零样本部署的步骤
#mermaid-svg-DWKrvloaPjQrHYT9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DWKrvloaPjQrHYT9 .error-icon{fill:#552222;}#mermaid-svg-DWKrvloaPjQrHYT9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DWKrvloaPjQrHYT9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DWKrvloaPjQrHYT9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DWKrvloaPjQrHYT9 .marker.cross{stroke:#333333;}#mermaid-svg-DWKrvloaPjQrHYT9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DWKrvloaPjQrHYT9 p{margin:0;}#mermaid-svg-DWKrvloaPjQrHYT9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster-label text{fill:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster-label span{color:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster-label span p{background-color:transparent;}#mermaid-svg-DWKrvloaPjQrHYT9 .label text,#mermaid-svg-DWKrvloaPjQrHYT9 span{fill:#333;color:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 .node rect,#mermaid-svg-DWKrvloaPjQrHYT9 .node circle,#mermaid-svg-DWKrvloaPjQrHYT9 .node ellipse,#mermaid-svg-DWKrvloaPjQrHYT9 .node polygon,#mermaid-svg-DWKrvloaPjQrHYT9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DWKrvloaPjQrHYT9 .rough-node .label text,#mermaid-svg-DWKrvloaPjQrHYT9 .node .label text,#mermaid-svg-DWKrvloaPjQrHYT9 .image-shape .label,#mermaid-svg-DWKrvloaPjQrHYT9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-DWKrvloaPjQrHYT9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DWKrvloaPjQrHYT9 .rough-node .label,#mermaid-svg-DWKrvloaPjQrHYT9 .node .label,#mermaid-svg-DWKrvloaPjQrHYT9 .image-shape .label,#mermaid-svg-DWKrvloaPjQrHYT9 .icon-shape .label{text-align:center;}#mermaid-svg-DWKrvloaPjQrHYT9 .node.clickable{cursor:pointer;}#mermaid-svg-DWKrvloaPjQrHYT9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DWKrvloaPjQrHYT9 .arrowheadPath{fill:#333333;}#mermaid-svg-DWKrvloaPjQrHYT9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DWKrvloaPjQrHYT9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DWKrvloaPjQrHYT9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DWKrvloaPjQrHYT9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DWKrvloaPjQrHYT9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DWKrvloaPjQrHYT9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster text{fill:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 .cluster span{color:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DWKrvloaPjQrHYT9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DWKrvloaPjQrHYT9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-DWKrvloaPjQrHYT9 .icon-shape,#mermaid-svg-DWKrvloaPjQrHYT9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DWKrvloaPjQrHYT9 .icon-shape p,#mermaid-svg-DWKrvloaPjQrHYT9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DWKrvloaPjQrHYT9 .icon-shape .label rect,#mermaid-svg-DWKrvloaPjQrHYT9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DWKrvloaPjQrHYT9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DWKrvloaPjQrHYT9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DWKrvloaPjQrHYT9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-DWKrvloaPjQrHYT9 .process>*{fill:#E8F1FC!important;stroke:#3973AC!important;color:#183B5B!important;stroke-width:1.5px!important;}#mermaid-svg-DWKrvloaPjQrHYT9 .process span{fill:#E8F1FC!important;stroke:#3973AC!important;color:#183B5B!important;stroke-width:1.5px!important;}#mermaid-svg-DWKrvloaPjQrHYT9 .process tspan{fill:#183B5B!important;} 配置
参数边界、关节顺序、执行器模型
采集
悬空固定、Chirp 扫频、记录目标与实测位置
辨识
4096 个并行环境、CMA-ES 逐代优化
校验
更换增益与轨迹进行重放验证
训练
参数写回仿真、四项奖励训练盲视策略
部署
零样本迁移、从低速跟踪逐级测试至动态极限
-
整套流程由六个环节组成,顺序不能颠倒,后一节都会用到前一节的产物:
- 配置:定义参数边界、关节顺序与执行器模型
- 采集:悬空固定,扫频激励,记录目标与实测
- 辨识:4096 个环境并行重放,CMA-ES 逐代收敛
- 校验:换增益、换轨迹重放,两条都过才继续
- 训练:参数写回仿真,四项奖励训练盲视策略
- 部署:零样本上机,从低速跟踪逐级加到动态极限
-
进入代码之前先说清数据契约。三个数组必须等长、按同一采样率对齐,关节顺序与配置里的
joint_order逐一对应:
| 字段 | 形状 | 含义 |
|---|---|---|
time |
[N] |
采样时刻,等间隔 |
des_dof_pos |
[N, n] |
真正下发给驱动器的目标位置 |
dof_pos |
[N, n] |
编码器实际读数 |
- 还有一处坐标系约定要先讲明白:实机日志记录的是编码器坐标系下的位置,仿真报告的是真实关节位置,两者相差一个偏置 q ~ b \tilde q_b q~b。整条流程里只有辨识的评分函数需要做这个换算,采集、写回、部署三个阶段都各用各坐标系里的量
3-2-1 环境配置:参数边界与关节顺序
- 这一段的代码定义"优化什么"与"优化到哪"。参数边界集中写在一个配置类里,按关节数展开成
4n+1个上下界
python
@configclass
class PaceCfg:
robot_name: str = "anymal_d_sim"
joint_order: list[str] = ["LF_HAA", "LF_HFE", "LF_KFE", ...] # 与真机日志同序
bounds_params: torch.Tensor = torch.zeros((49, 2)) # 4 * 12 + 1
separate_dynamic_friction: bool = False
def __post_init__(self):
n = len(self.joint_order)
self.bounds_params[:n, 0] = 1e-5 # 电枢惯量下界
self.bounds_params[:n, 1] = 1.0 # 电枢惯量上界 [kg m^2]
self.bounds_params[n:2 * n, 1] = 7.0 # 粘滞阻尼 [N m s/rad]
self.bounds_params[2 * n:3 * n, 1] = 0.5 # 库仑摩擦 [N m]
self.bounds_params[3 * n:4 * n, 0] = -0.1
self.bounds_params[3 * n:4 * n, 1] = 0.1 # 关节偏置 [rad]
self.bounds_params[4 * n, 1] = 10.0 # 全局延迟 [仿真步]
-
三处需要特别注意的约定:
- 关节顺序。仿真框架按广度优先遍历给关节编号,与真机控制栈或日志的顺序往往不同,
joint_order用于将两侧对齐;写错不会触发报错,只会导致不同关节的参数互相错配 - 延迟单位。这一项的单位是仿真步而非秒,10 步在 400 Hz 下对应 25 ms,执行器配置中的
max_delay必须不小于这个上界,否则缓冲深度不足 - 动态摩擦。打开
separate_dynamic_friction后,摩擦被拆分为静摩擦与一个 0 , 1 0,1 0,1 的动静态比例,参数从 49 增至 61;比例乘回静摩擦即为动摩擦,因此动摩擦恒不超过静摩擦
- 关节顺序。仿真框架按广度优先遍历给关节编号,与真机控制栈或日志的顺序往往不同,
-
执行器侧对应的是自定义配置类
PaceDCMotorCfg,它在DCMotorCfg之上补了编码器偏置、延迟深度与延迟位置三个字段:
python
ANYDRIVE_PACE_ACTUATOR_CFG = PaceDCMotorCfg(
joint_names_expr=[".*HAA", ".*HFE", ".*KFE"],
stiffness={".*": 85.0}, # 位置增益,单位 N m/rad
damping={".*": 0.6}, # 速度增益,单位 N m s/rad
encoder_bias={".*": 0.0}, # 初值,辨识前一律置零
viscous_friction={".*": 0.0},
friction={".*": 0.0}, # 静摩擦
dynamic_friction={".*": 0.0},
max_delay=10, # 延迟缓冲的深度,单位仿真步
delay_mode="command", # 延迟作用在指令上,而不是力矩上
)
- 这里的 PD 增益必须与真机固件实际使用的值一致,且必须是 SI 单位。它们不参与优化,只决定仿真的闭环极点位置,写错了会让辨识在错误的频带上做拟合
3-2-2 数据采集:激励与记录
- 采集脚本做三件事:把一组已知参数写进仿真(自检模式)或直接驱动真机,以 400 Hz 逐拍下发扫频目标,同时把每拍的编码器读数与真正生效的目标各存一行
python
dof_pos_buffer = torch.zeros(num_steps, n_joints)
dof_target_pos_buffer = torch.zeros(num_steps, n_joints)
for counter in range(num_steps):
# 编码器读数;仿真里注入的偏置要扣掉,剩下的才是编码器坐标系下的位置
dof_pos_buffer[counter, :] = robot.data.joint_pos[0, joint_ids] - injected_bias
# 动作就是绝对位置目标,仿真里其余维度保持为零
actions = trajectory[counter, :].unsqueeze(0).repeat(num_envs, 1)
env.step(actions)
# 回读真正生效的目标,而非假定已下发的目标
dof_target_pos_buffer[counter, :] = robot.data.joint_pos_target[0, joint_ids]
- 三个细节决定这批数据是否可用:
- 目标须从仿真或驱动的内部状态回读。位置饱和与限幅会改写目标,直接记录自行计算的曲线,等价于用一条从未执行过的参考参与对齐
- 初始位置须写成"实测位置 + 偏置"。这样编码器读到的值正好等于实测起点,避免第 0 拍即带入常数误差,该误差随后会被吸收进惯量估计
- 仿真自检与实机采集只差数据来源。轨迹、采样率与记录格式完全相同,同一套下游代码在两侧均可复用,这也是官方示例能够先在仿真中跑通整个流程的原因
3-2-3 辨识主循环
- 主循环的骨架十分简短,复杂度全部集中在"何时打分、何时进化"这两个时机上
python
opt.update_simulator(robot, sim_joint_ids, initial_dof_pos) # 第 0 代参数写进仿真
counter = 0
while simulation_app.is_running():
# 先在当前状态上打分,再执行这一拍的动作
opt.tell(robot.data.joint_pos[:, sim_joint_ids], measured[counter])
actions = torch.zeros(env.action_space.shape)
actions[:, sim_joint_ids] = target_dof_pos[counter]
env.step(actions)
counter += 1
if counter >= time_steps: # 一条真实轨迹放完
counter = 0
opt.evolve() # 时间取平均,更新分布,抽下一代
if opt.finished():
break
env.reset()
opt.update_simulator(robot, sim_joint_ids, initial_dof_pos) # 重新写回
-
四处必须遵循的执行顺序:
- 打分在
env.step之前。tell比较的是"第 t t t 拍的状态"与"真机第 t t t 拍的测量";先 step 再打分会使两侧错开一拍,收敛变慢,且延迟参数会被系统性高估 - 每代结束重新写一次参数。
env.reset()会将关节属性恢复为默认值,写回函数同时更新运行时的仿真状态与data.default_*缓存,两者都更新才能保证 reset 之后参数仍然生效 - 并行环境数等于种群规模。每代开始时向优化器请求 N N N 个候选,每个候选占一个环境;两个数不相等时,多余的环境会重复评估同一候选,降低种群多样性
- 轨迹结束时不立即退出。先
evolve再检查终止条件,否则最后一代新抽出的种群尚未评估即被丢弃
- 打分在
-
写回函数本体的实现在 2-5-1 节已经给过,这里只补它的边界条件:电枢惯量、粘滞阻尼、静摩擦与动摩擦分别落在刚体与关节两级,偏置与延迟落在执行器内部,三类接口不能互换;张量还要按驱动器分组做一次索引映射,因为一条驱动器的关节集合与全部关节的下标集合并不相同
3-2-4 优化器内部:参数分片、终止与存档
- 优化器在初始化时把一维参数向量切分为六段,后续代码均通过这几个切片定位,不再出现硬编码下标
python
n = len(joint_order)
self.armature_idx = slice(0, n) # 电枢惯量
self.damping_idx = slice(n, 2 * n) # 粘滞阻尼
self.friction_idx = slice(2 * n, 3 * n) # 静摩擦
self.bias_idx = slice(3 * n, 4 * n) # 关节偏置
self.delay_idx = 4 * n # 全局延迟
self.friction_ratio_idx = slice(4 * n + 1, 5 * n + 1) # 动静态摩擦比例
- 构造时还有一次长度校验:参数总数必须是
4n+1(开启动静摩擦分离时是5n+1),不匹配则直接抛出异常。这道检查针对的正是"修改了关节数却未同步修改边界"这类常见配置错误,可在参数错配发生之前暴露问题 - 终止条件有两条,满足任一即停止:达到最大迭代数,或者最后一代内各种群的分数极差已经很小
finished ⟺ t ≥ t max ∨ max e ℓ e − min e ℓ e min e ℓ e < ϵ \text{finished} \iff t \ge t_{\max} \;\;\lor\;\; \frac{\max_e \ell_e - \min_e \ell_e}{\min_e \ell_e} < \epsilon finished⟺t≥tmax∨mineℓemaxeℓe−mineℓe<ϵ
- 第二条判据的含义是"当代最优与最差个体已足够接近",此时继续采样只会在同一区域内波动。官方给出的默认阈值是 10 − 2 10^{-2} 10−2
- 每代结束会打印当前最优个体的全部参数与单代耗时,并按固定间隔保存三项内容:当前分布均值、该代最优个体的仿真轨迹,以及完整的运行配置。第三项在下一节校验时使用
- 存档的是分布均值而非最优样本,这是刻意的选择:均值经过加权重组,在参数空间中的噪声比单代最优更小,更适合直接用于训练
3-2-5 结果校验
- 校验只做一件事:将最优参数对应的仿真轨迹与真机轨迹逐点比较,并同时按段打印参数,做一次人工量纲检查
python
mean = torch.load(run_dir / "mean_XXX.pt") # 辨识出的参数
best = torch.load(run_dir / "best_trajectory.pt") # 最优个体的仿真轨迹
config = torch.load(run_dir / "config.pt")
real = config["dof_pos"] # 真机实测轨迹
print(f"mean squared error: {torch.mean(torch.square(best - real)):.2e}")
print(f"armature: {mean[:n].tolist()}")
print(f"delay [sim steps]: {mean[4 * n].item()}")
- 数值判据方面,官方示例给出的经验线是均方误差低于 0.005 即可视为高质量拟合,而 ANYmal 用真实数据辨识的结果低于 0.003。该阈值与机器人尺度有关,仅作量级参考
- 数值之外还需通过两道结构化检查,它们比单一分数更能说明模型是否正确:
- 换增益:用辨识时未使用的 PD 增益重放同一段轨迹,若仍保持重合,说明拟合到的是物理模型
- 换轨迹:用随机阶跃或未参与辨识的扫频重放,若仍保持重合,说明未对某一条曲线过拟合
- 两道检查均通过方可进入训练。仅通过数值判据的模型,典型失效形态是仅在辨识轨迹上高度吻合,更换条件后误差显著增大
3-2-6 迁移到训练环境
- 训练环境不在辨识工程内,需要迁移的有两项:执行器类及其配置类,以及四组关节属性的写入代码
- 执行器的接入只有两步:在配置中将默认的
DCMotor替换为PaceDCMotor,初始化时填入辨识得到的偏置与延迟;四组关节属性则在训练开始前写入一次
python
actuator_cfg = PaceDCMotorCfg(
joint_names_expr=[".*HAA", ".*HFE", ".*KFE"],
stiffness={".*": 85.0},
damping={".*": 0.6},
encoder_bias=dict(zip(joint_names, identified_bias)),
max_delay=int(identified_delay),
delay_mode="command",
)
articulation.write_joint_armature_to_sim(armature)
articulation.write_joint_viscous_friction_coefficient_to_sim(damping)
articulation.write_joint_friction_coefficient_to_sim(static_friction)
articulation.write_joint_dynamic_friction_coefficient_to_sim(dynamic_friction)
- 写入之后还有一步官方强烈建议的自检:将采集到的真机轨迹在训练环境中重放一遍,确认轨迹仍然重合,再开始训练。该步骤开销极小,却可以提前暴露参数维度或顺序错配
- 训练阶段与辨识阶段的差别只有一处:辨识时不做任何随机化,训练时也不对动力学做随机化。电枢惯量、阻尼、摩擦、偏置与延迟均固定为辨识值,随机化只保留在与动力学无关的任务层面
- 这一"不随机化动力学"的做法,正是全文核心主张在工程上的落点:模型足够准确时,无需以随机化覆盖差距
3-3 常见问题
- 固件模式必须一致。固件补偿会引入恒定的虚拟惯量(本机实测折算为 8.1 × 10 − 3 8.1 \times 10^{-3} 8.1×10−3 kg m 2 ^2 2),辨识与部署若使用不同的补偿开关,相当于在模型中多计或少计一项
- PD 增益的单位必须是 SI。非 SI 单位下依然可以辨识出参数,但能量项中的阻尼与欧姆损耗会被错误缩放,也会破坏跨增益的泛化
- PD 增益不应放入优化变量。前述公共缩放的不动点意味着最优解不唯一,优化器会在等价解之间游移,表现为损失持续下降而参数本身不具物理意义
- 参数并非越多越好。论文的经验是 { I a , d , τ f , q ~ b , T d } \{I_a, d, \tau_f, \tilde q_b, T_d\} {Ia,d,τf,q~b,Td} 这五项已跨平台适用;盲目增加参数(尤其是低层电气参数)只会稀释可辨识性
- 驱动器侧的滤波需要留意。关节速度常被 25 至 50 Hz 的低通滤波,位置误差中看不到它的影响,但它会影响 PD 输出的力矩。若影响显著,应将这一滤波一并建入仿真并辨识其参数
- 温度与磨损会引起漂移。长时间运行后,电阻与摩擦均会变化,论文将其列为当前局限,可行的补偿方式是给 { I a , d } \{I_a, d\} {Ia,d} 增加一个缓变的在线缩放
总结
- 本文从域随机化与系统辨识的分工出发,完整拆解了 PACE 这套方法:用 20 至 40 秒的腾空扫频数据辨识 4n+1 个关节动力学参数,在辨识后的仿真中训练四项奖励的盲视策略,再零样本部署
- 核心要点回顾:
- 参数选择:只辨识电枢惯量、粘滞阻尼、库仑摩擦、关节偏置与全局延迟,PD 增益与电机常数因结构不可辨识而被排除
- 优化方式:轨迹级目标非凸不可微,用 CMA-ES 在归一化空间内搜索,种群规模等于并行环境数
- 能量奖励:由 PMSM 的铜损、带回馈的机械功率与重力势能三项合成,按功率计算,量纲由电机物理参数决定,更换机器人无需重调系数
- 实验结论:ANYmal 的运输代价从 1.86 降至 1.27,下降部分全部来自运动损耗项;三个主平台与一批扩展平台完成零样本迁移
- 工程约束:固件模式必须与辨识时一致,PD 增益单位必须是 SI,激励带宽要覆盖策略控制频率的一半
- 对复现工作而言,最有价值的两点是:腾空数据足以支撑地面运动;奖励项可以用物理单位确定,把调参空间从十余个系数压缩到一个能量尺度
- 如有错误,欢迎指出!感谢观看!
