BeyondMimic——从跳舞好手到通过引导扩散实现多功能控制:基于Diffuse-CLoC构建扩散框架,可模仿动作、导航避障(含我司复现实践)
前言
相比单纯让机器人跳舞之类的locomotion,我个人对人形的loco-manipulation(含manipulation)更感兴趣,毕竟后者才能让机器人更好的干活,而非单纯的娱乐展示
毕竟虽然娱乐展示是不可或缺的,但真正推动社会前进的第一动力还是对生产效率的提升
然找我们做人形舞蹈定制开发的客户实在是有点多,虽然推掉了大部分的舞蹈定制,但还是有小部分盛情难却,这不,如此文的开头所说:25年7月份刚完成一人形舞蹈的交付
- 我在《一文通透ViT——把图片划分成一个个patch块后再做注意力计算,打破CNN在CV领域的统治地位(含Swin Transformer的详解)》的开头有说到,“长沙分部很快 要折腾两个新的具身项目了,到时候就是第二轮、第三轮的突飞猛进,至于第一轮突飞猛进是今25年6.4-7.19日 ”
- 那第二轮将开始于什么时候呢?很快了,因为自从7月份基于客户提供的G1完成一舞蹈的交付后,8月下旬已连签两个合同(一个机械臂、一个人形),客户们将在9月初 把机器寄到长沙分部
25年8月底又来了一个让人形跳舞的需求,客户还希望通过灵活的线上线下的方式,陪跑客户技术团队并让他们尽早具备机器人应用开发的能力(即指导客户的技术团队成员初步跑通训练的流程,包括指导动捕数据采集、模型强化训练等)
故,我还是不得不对人形跳舞之类的单纯locomotion继续予以高关注,并持续研究
于此,则关注到了本文要介绍的BeyondMimic、UniTracker
- 前者BeyondMimic目前已开源
且一朋友反馈,通过beyondmimic 试了一小段查尔斯整体还是比较稳的,至于数据用的宇树的数据集,部署框架他则用宇树的unitree_rl_gym改的
当然,beyondmimic本身集成了rsl_rl——homie便用的这个经典RL框架做的部署,也可以试下
————
我司也对其复现实践了下,详见下文的《1.5 我司七月的复现实践:基于Beyondmimic,实现任意舞蹈任意学》 - 至于后者UniTracker
1 虽然截止到25年8.28日,该项目暂未开源,也不知他们 有无开源计划,但至少作为对本博客中locomotion系列文章的巩固——是有帮助的
2 目前该项目对外发布的视频效果 并未非常流畅,但探索的道路上,这些不完美是不可避免的,期待他们保持迭代吧
PS,如果你在尝试人形的locomotion开发或者跳舞开发,欢迎私我一两句你的简介,邀你加入该交流群:『七月:人形locomotion(含跳舞)』
第一部分 BeyondMimic:从运动追踪到通过引导扩散实现多功能人形控制
1.1 引言、相关工作
1.1.1 引言
如BeyondMimic原论文所说,基于物理的角色动画在近年来的研究中 [1], [2], [3],[4] 已经展现出惊人的进步,能够将人体动作合成到全身控制的动态行为中,从而直接求解下游任务
然而,这些成果目前仍主要局限在仿真环境中,在那里智能体拥有理想化的动力学、无限的驱动力以及完美的观测能力,这与现实世界中的人形机器人截然不同——真实机器人需要面对未建模的动力学、硬件限制以及不完美的状态估计
要在真实硬件上实现与之相当的能力,还缺失两个关键能力
- 一个可扩展的高质量的运动跟踪框架,能够将运动学参考转换为鲁棒的、高度动态的运动,同时避免过度随机化、抖动和动作质量下降等问题;
- 一种有效的sim2real迁移方案,将已学得的运动基元蒸馏为单一策略,使其在测试阶段能够组合技能,实现灵活的、目标驱动的控制,而无需重新训练
对此,来自UC伯克利和斯坦福的研究者提出了BeyondMimic,这是第一个同时解决上述两个挑战的真实世界框架

- 其对应的paper为:BeyondMimic: From Motion Tracking to Versatile Humanoid Control via Guided Diffusion
其作者包括
Qiayuan Liao∗1 , Takara E. Truong∗2 , Xiaoyu Huang∗1 , Guy Tevet2 ,
Koushil Sreenath†1 and C. Karen Liu†2 - 其对应的项目网址为:beyondmimic.github.io/
其对应的GitHub为:github.com/HybridRobotics/whole_body_tracking
具体而言
- BeyondMimic 首先引入了一条运动追踪流水线,能够在真实的人形机器人硬件上执行高度动态的动作,例如跳跃旋转、冲刺和侧手翻,并且具有最先进的动作质量
超越仅在人形机器人上简单模仿人类动作之外,作者的框架进一步提出了一种引导式扩散策略,将这些动作或技能综合到一个统一的策略中,使其在测试阶段仅使用简单的代价函数即可实现零样本、任务特定的控制,从而在无需额外再训练的情况下灵活地解决下游任务 - 且作者在一个完整的sim-to-real流程上展示了 BeyondMimic 的能力:先训练鲁棒的跟踪策略,再将其蒸馏为一个基于扩散模型的控制器,最后将所得控制器部署到真实硬件上
————
最终,他们的系统能够执行一系列广泛的任务,从航路点导航、摇杆遥操作到避障,同时仍然保持原始人类动作的自然风格和动态特性
且通过弥合在运动跟踪和扩散策略合成这两个方面的 sim-to-real 迁移鸿沟,BeyondMimic 为推动具备泛化能力的全身人形控制提供了一个切实可行的基础
1.1.2 相关工作
首先,对于运动跟踪
- 早期基于学习的足式机器人控制方法主要集中在人工设计特定任务的控制器 [5]、[6]、[7]、[8]。这些控制器虽然能够实现鲁棒的运动能力,但每个任务都需要大量的奖励工程设计,且缺乏自然化的动作表现,并且难以扩展到通用控制所需的多样化技能集合
- DeepMimic [9] 提供了一种替代方案,它通过学习人类运动参考来生成自然、动力学上可行的行为,同时降低了奖励工程的负担,特别适合用于人形机器人
自那以后,出现了许多基于DeepMimic 范式的跟踪框架
早期的动作跟踪方法通常依赖于一小组相似的参考动作来训练单任务策略。这些策略在 DeepMimic 目标的基础上,与任务相关的奖励共同训练,从而得到能够以单一风格执行单一任务的控制器。代表性例子包括四足动物行走 [10] 和守门 [11],以及双足跳跃和奔跑 [12] - 为实现更加动态的技能,ASAP[13] 提出使用一个 real-to-sim 流水线,通过硬件实验学习增量动作模型(delta action model),以提升仿真精度。然而,该方法需要针对每个动作单独训练特定的增量动作模型,且这些模型往往会对特定的短动作发生过拟合
类似地,KungfuBot [14]和 HuB [15] 通过精心设计的域随机化实现了高质量的 sim-to-real 迁移,但同样仅适用于单一动作 - 为了突破单一动作策略的限制,近期研究开始探索可扩展的动作追踪框架,使其能够在单一策略中学习多样化的动作集合
在物理基础动画领域,PHC [16]是此类系统的典型代表,激发了后续机器人学领域构建通用动作追踪器的尝试
机器人学中早期的多动作追踪器如 OmniH2O [18,具体如下图所示]、Exbody [19] 和 HumanPlus[20],证明了这种方法的可行性,但与计算机图形学中的对应方法相比,其动作质量显著下降
- 最近,TWIST [21] 实现了较高质量的动作跟踪,但主要针对静态动作
同样地,CLONE [22] 和UniTracker [23] 主要聚焦于低动态行走动作,同时具备对上半身动作的灵敏追踪
另一方面,GMT [24]能够实现一定的动态运动,但在全局轨迹跟踪方面作出牺牲,转而偏重相对速度跟踪,并对下肢施加强正则化以提升鲁棒性 - Grandia 等人 [25-Design and control of a bipedalrobotic character] 提出了迄今为止可能是质量最高的多动作跟踪方法,但只在一台小型机器人上进行了实验,且未涉及动态运动。直到目前,在真实类人机器人硬件上同时实现高质量动作跟踪并支持高度动态技能的多动作跟踪仍未得到验证
本BeyondMimic研究旨在填补这一空白,对多样的、持续数分钟的人体参考动作进行跟踪,这些参考动作包含大量风格和难度各异的不同动作
其次,对于扩散在机器人技术与角色动画中的应用
去噪扩散模型正在成为机器人与动画领域中强大的策略生成器,因为它们天然适用于处理多模态分布和长时序序列
- 在角色动画中,运动学扩散模型可以通过
文本[26-Human motion diffusion model]
音乐[27-Edge: Editable dance generationfrom music]
几何约束[28-Hierarchical planning and control for box loco-manipulation]
或损失函数[29-GuidedMotionDiffusionforControllableHumanMotionSynthesis]
等方式进行直观的条件控制
这类规划器这类规划器通常会与一个独立的低层控制器配合,用于物理执行[28]、[30-Closd: Closing the loop betweensimulation and diffusion for multi-task character control] - 然而,这种两阶段方法往往会遭受“规划–控制鸿沟”的问题,即规划器产生的动作分布超出了控制器的训练分布,使得控制器难以实现稳健跟踪[3-Diffuse-cloc: Guided diffusionfor physics-based character look-ahead control]
这一脆弱性还因重规划频率选择的难题而进一步加剧:重规划过于稀疏时,系统难以及时适应环境变化
而重规划过于频繁时,又会妨碍智能体坚持执行一个连贯的策略
尽管在线重规划在仿真环境中已经展现出潜力[30-Closd],但其在现实世界中的有效性尚未得到验证
为避免规划与控制之间的鸿沟,另一类研究路线专注于学习一个端到端的单一策略,直接从状态映射到动作分布
- 这一方法,即Diffusion Policy [31],自然而然地扩展到运动控制和角色控制
例如,DiffuseLoco [32] 和 BiRoDiff [33] 学习了统一策略来编码多种技能,从而实现平滑的步态切换,并在四足机器人真实环境部署中表现出很强的鲁棒性
同时,PDP [34-Pdp: Physics-basedcharacter animation via diffusion policy] 将该框架扩展到基于物理的角色,展示了其可以跟随文本提示、执行通用的运动跟踪,并捕捉人类抗推恢复行为中固有的多模态特性 - 近期,HugWBC [34] 通过在线蒸馏将扩散策略适配到类人机器人
但此类策略缺乏在测试时进行灵活引导的机制,例如基于损失的扩散引导。这是因为难以直接将状态空间中定义的任务目标,与以 PD 目标或力矩形式定义的动作序列进行比较
因此,当需要对新的任务进行条件控制时,通常不得不重新训练策略
第三类方法试图通过对状态和动作的联合分布进行扩散,从而将规划器的灵活引导与端到端策略的鲁棒性相结合。这使得在测试时可以通过
基于分类器的奖励[36-Planning with diffusion for flexible behavior synthesis]
或对未来状态目标的条件约束[37-Is conditional generative modeling all you need fordecision-making?]
进行引导
- Diffuser [35] 首次将这一方法应用于离线强化学习,但其鲁棒性表现有限
Decision Diffuser[37]也同样对状态—动作轨迹建模,最终得出结论认为这些动作缺乏鲁棒性,并通过逆动力学后处理将其替换 - 相比之下,Diffuse-CLoC[3] 利用基于 PDP [33] 的鲁棒离线蒸馏,并通过这种联合扩散策略在基于物理的动画中展现出强劲性能
然而,将带有引导的、联合状态-动作扩散模型应用于复杂的真实世界机器人控制仍然是一个尚未解决的挑战,而本工作正旨在解决这一问题
1.2 可扩展的运动追踪
在本节中,作者提出了一条用于训练运动跟踪策略的可扩展流水线。该流水线在仅使用单一的 MDP 配置和一套通用超参数的前提下,就能在给定长达数分钟的参考轨迹时生成高质量的 sim-to-real 策略,从而证明其在多样化动作上的可扩展性
需要注意的是,由于他们的跟踪框架不包含历史信息,为了表述清晰,在公式中省略了时间步 。除非特别说明,本节中的所有量均在世界坐标系下表示
1.2.1 跟踪目标
作者的框架目标是在全局坐标中在机器人硬件上高质量地复现给定的参考动作。然而,仿真到真实(sim-to-real)的差距常常导致不可避免的全局漂移
- 为了在允许全局漂移的同时保持风格,控制器不应跟踪绝对的身体姿态
相反,作者指定一个参考身体,其中
是所有机器人身体的集合,而
通常是根部或躯干,作为锚点
- 为了锚定相对于
的目标躯干
的期望姿态,作者从重定向后的参考运动开始,该运动表示为广义位置和速度的关键帧
利用正向运动学,作者为每个躯干获得其姿态
和扭量
- 然后,作者将躯干
的期望姿态锚定为
其中是参考躯干的当前姿态
而通过保持高度、对齐偏航角以及将
原点平移到机器人下方,将该运动转换到角色的局部坐标系中
具体而言
且 - 期望扭量保持不变,即
注意对于参考躯干同样保持不变
机器人通常具有许多紧密排列的物体。因此,跟踪它们全部是低效且往往没有必要的。相反,作者选择一个目标物体子集,将运动跟踪目标设置为
1.2.2 观测
作者将策略的观测空间表述为由三个部分组成的单步向量
- 参考相位
作者加入来自动作的关节位置和速度,,仅作为相位信息
注意,策略并不打算直接跟踪关节数值 - 锚点姿态跟踪误差
包含锚点主体的姿态跟踪误差,,其由三维位置误差和旋转误差矩阵的前两列组成[38]
由于参考运动是在世界坐标系中预定义的,该项隐含地为平衡提供了朝向信息,并为纠正漂移提供了全局位置信息 - 其他本体感知
作者包含用根坐标系表示的机器人根部扭转、关节位置
和速度
,以及上一时刻的动作
完整的观测空间定义为
请注意,当无需进行位置漂移补偿,或无法获得可靠的状态估计时,可以省略线性分量(即的平移部分和
的线性分量)
此外,作者采用非对称的 actor–critic 方法以提升训练效率。除了策略观测外,critic 还接收相对于锚点的每个身体部分的相对姿态,以使critic能够直接在笛卡尔空间中估算各身体部位的跟踪误差
1.2.3 关节阻抗与动作
在动画和机器人领域,引入力阻抗是一种标准方法
- 许多角色动画研究
[10-Deepmimic]
[17-Perpetual humanoidcontrol for real-time simulated avatar]
[34-Pdp: Physics-basedcharacter animation via diffusion polic]
采用高阻抗以实现精确跟踪,从而将自由空间中的控制有效地简化为一个近乎运动学的问题
然而,在这种高阻抗设置下训练得到的策略往往难以在真实硬件上部署,因为它们会放大传感器噪声,降低吸收冲击所需的被动顺应性,并且阻碍从当前和先前指令中隐式获取的力矩信息的利用 - 相比之下,作者依据 Raibert 等人 [39-Workshop on whole-body controland bimanual manipulation: Applications in humanoids and beyond] 的方法,启发式地设置关节刚度和阻尼:
,
其中为固有频率,
为阻尼比,
为第
个关节的等效惯量关节
作者选择阻尼比(过阻尼),而不是Raibert等人[39]中采用的1 (临界阻尼),因为如果只考虑电机电枢并忽略表观连杆惯量,通常会低估惯量。固有频率被设置为一个相对较低的值10Hz,这在中等增益下有利于实现柔顺
策略动作被设计为归一化的关节位置设定值:,其中
为策略动作输出,
为常数标称关节构型,
,其中
表示关节
的最大允许关节力矩
该启发式方法假设接触通常发生在 附近,并且机器人硬件设计保证最大关节力矩与预期载荷成正比。在低增益下,这些设定值并非作为期望位置目标;相反,它们作为生成期望力矩的中间变量,并且被有意地不受关节运动学极限的裁剪约束
1.2.4 回报函数
作者以简单、直观且通用的方式设计奖励,包括
- 任务回报,作为正向信号,采用统一权重并在任务空间中表达
- 最小化的正则化惩罚项,用于避免损害跟踪性能
任务奖励是DeepMimic 风格的奖励
- 首先,作者基于期望的
和实际的
姿态与扭转,为每个目标刚体
计算误差度量:
以及
其中,假设方向误差较小 - 然后,在所有目标身体上计算均方误差:
接着,每个误差度量都使用高斯形式的指数函数进行归一化
其中是通过经验确定的标称误差
作者将组合后的跟踪奖励定义为:
在正则化方面,作者仅包含三项对仿真到现实对齐至关重要的惩罚项。其中,关节限位惩罚rlimit 鼓励关节位置保持在软限位范围内。动作速率惩罚 rsmooth 鼓励连续动作的平滑性,避免策略产生过度抖动
- 其一是关节限制惩罚项
,用于鼓励关节位置保持在软限制范围内
- 动作速率惩罚项
,用于鼓励连续动作的平滑性,避免策略产生过度抖动
- 为惩罚自碰撞,我们统计自接触力超过预定义阈值的刚体数量,作为末端执行器集合Bee ⊆B 上的总惩罚
最终的总奖励定义为
其中,,定义了奖励权重
可选地,可以为锚体 添加全局跟踪奖励,其结构与
相同,但使用
和
可选地,可以为参考刚体 添加一个全局跟踪奖励,其结构与
相同,但使用误差
和
1.2.5 终止与重置
在两种条件下一个回合会终止,分别表示发生跌倒或跟踪失败
当参考刚体的高度或姿态(仅考虑俯仰和横滚)误差超过预设阈值时
- 或(2)当任何末端执行器体
的高度与参考轨迹有显著偏离时
在每次回合重置时,运动阶段会从整个参考轨迹中自适应采样(下节马上会讲,对应于原论文第 III-F 节)。机器人被初始化到相应的参考构型和速度,同时施加额外的随机扰动以增强鲁棒性
1.2.6 自适应采样
在训练长序列运动时,不可避免地会面对这样一个问题:并非所有片段的难度都相同。因此,在整个轨迹上进行均匀采样——这是以往工作[13][33][16]中的常见做法——往往会对简单片段过度采样,而对困难片段采样不足,从而导致回报方差增大以及训练效率低下
- 因此,自适应地从更困难的区域中进行更高频率的采样是自然而然的选择。为此,我们将整段运动的起始索引划分为 S 个时间箱,每个时间箱长度为一秒,并根据经验失败统计对这些时间箱进行采样
设和
分别为在时间箱
中开始的episode 数量和失败次数。失败率会通过一种随时间平滑的方法进行平滑处理
- 由于一次失败更可能是由终止前不久采取的次优动作导致的,故作者使用一个非因果指数衰减核
,其中
为衰减率,以对过去相近时间的失败赋予更大的权重
然后,从Bin s 中进行采样的最终概率为
其中,是第
个区间的平滑失败率
- 且作者进一步将概率
与均匀分布混合,以保持对较易区间的覆盖并减轻灾难性遗忘,使用
,其中
为均匀采样比例
起始区间随后从中抽取,优先考虑具有挑战性的区域
1.2.7 域随机化
作者采用了三种域随机化参数:地面摩擦系数、关节默认位置 (同时作用于动作与观测,有效地模拟关节零位标定误差),以及躯干的质心位置
此外,作者在训练过程中在环境中加入扰动,以促使机器人学习对环境变化具有鲁棒性的控制策略
1.3 通过引导扩散进行轨迹合成
在本节中,将介绍一种基于状态-动作的运动合成框架,该框架通过引导扩散实现任务特定的控制。顺序上,首先介绍训练过程,然后详细说明引导机制
1.3.1 训练
作者采用Diffuse-CLoC [3] 来创建一种状态-动作协同扩散框架,该框架能够通过在状态空间中的引导采样生成具有物理基础的机器人动作
该模型被训练用于预测未来轨迹,即前瞻时间范围为
个时间步的轨迹,条件是观测历史
,该历史由之前N 步的状态-动作对构成
训练本身遵循标准的去噪扩散过程
- 首先,在前向传播中,逐步向真实轨迹中添加高斯噪声
- 一个去噪网络
随后学习逆转这种损坏。它以含噪轨迹
作为输入,并被训练用于预测原始的、干净的轨迹
- 然后通过最小化与真实值之间的均方误差(MSE)损失来优化网络的参数
在推理过程中,通过从随机噪声开始,并按照所学习到的去噪函数迭代细化,依照 DDPM更新规则 [39] 生成新的轨迹『new trajectories are generated by start-ing with random noise and iteratively refining it using the learned denoising function, following the DDPM update rule』
其中,是根据干净轨迹估计
推导出的预测噪声,
、
和
为DDPM系数
作者为状态和动作分别采用独立的噪声调度,记为
1.3.2 引导Guidance
为了在推理过程中将模型引导至特定目标,作者使用分类器引导。比如通过贝叶斯定理[41-Score-based generative modeling through stochasticdifferential equations],条件分布的评分可以分解为模型学习到的无条件评分和一个单独的引导项
其中为最优轨迹
- 在作者的应用中,该引导项是一个可微分的、任务特定的代价函数
通过在代价与条件似然之间建立关系,即,引导项简化为代价的负梯度:
- 该梯度为采样过程提供了信号,推动其朝向轨迹空间中成本较低的区域
这种方法具有高度的灵活性,使得单一预训练模型能够在推理阶段适配多样化的目标
作者通过在三项具有代表性的任务上评估他们的框架来证明这一点,每项任务均由不同类型的轨迹约束所定义,详见下节
1.3.3 下游任务:以操纵杆转向、航路点导航和障碍物规避为例
作者以操纵杆转向、航路点导航和障碍物规避为例,展示了任务特定的代价函数
- 对于操纵杆转向
将代价函数定义为状态预测与操纵杆输入之间的平方差
其中,是时刻
的预测轨迹,
提取出时刻
的平面根速度,
是来自操纵杆控制器的目标根速度
- 对于航点任务
代价函数在奖励接近目标的同时,随着智能体靠近目标逐渐加大对速度的惩罚,从而确保其到达后能够停下
其中,表示当前与目标
的标量距离,该距离与梯度计算无关
- 在避障任务中
作者构建了有符号距离场SDF,以获取以获取身体位置与最近物体之间的距离和梯度,并将代价函数定义为:
其中,表示在轨迹
下,物体
在时刻
的位置,
是物体
的近似球半径,
是一个松弛的障碍函数[42]
// 待更
1.4 运动跟踪实验与结果
本节通过仿真和在 Unitree G1 仿人机器人上的实际部署,验证了运动跟踪框架的实验效果,展示了高质量、强鲁棒性和高度动态的运动表现。需要注意的是,作者在本节中对所有策略均使用相同的一组超参数进行训练
1.4.1 仿真到仿真性能
作者使用了由Unitree重新定向的LAFAN1数据集[43-Robust mo-tion in-betweening],该数据集包含多样且灵活的人体动作,如冲刺、转身跳跃和爬行,以及来自先前工作[16-Hub: Learning extreme humanoid balance],[14-ASAP]的简短单一动作片段
- LAFAN1数据集包含40个时长数分钟的参考序列,每个序列属于一个广泛的类别,并在该类别中包含许多不同的动作
作者随机选择了其中的25个参考序列,确保每个类别至少包含一个,并发现所有序列在仿真到仿真的评估过程中都能完整完成 - 由于作者的测试场地空间有限,他们特意从这些参考序列中挑选了29个具有挑战性的片段,每个片段都包含动态且富有接触的动作行为,并在硬件上进行测试,以评估仿真到现实的迁移性能
最终在仿真到仿真和仿真到现实迁移中测试过的完整动作列表详见表I
1.4.2 真实环境实验设置
作者将在Unitree G1 人形机器人上部署使用所提出方法训练的运动跟踪策略。所有部署代码均使用C++编写,并针对实时执行进行了优化。通过低级广义动量观测器与卡尔曼滤波器结合,在500 Hz 下提供全状态估计
- 值得注意的是,跟踪过程中未使用任何外部运动捕捉系统
对于极端且接触丰富的行为(如从地面起身),作者要么引入激光雷达-惯性里程计(LIO)[45]进行位置校正,要么完全排除依赖状态估计的观测数据 - 所有策略均在机器人CPU上通过ONNX Runtime[46]本地执行。每次推理步骤耗时不足1.0毫秒,因此能够无缝集成到实时估算与控制环路中
1.5 我司七月的复现实践:基于Beyondmimic,实现任意舞蹈任意学
1.5.1 打通GVHMR + GMR + Beyondmimic全套流程
实话讲,Beyondmimic的效果确实还不错,我们内部(我和同事朝阳带队)也于25年11.14日实际试过,比如训练「人形跳查尔斯顿舞」第二版『PS,如果想学完整的开发流程,可参见该课:《人形二次开发线上营[提供完整仿真框架且送机械臂线上营》』
七月具身:训练「人形跳查尔斯顿舞2」简略版
- 该第二版和今25年6月底 第一版的流程一样,但每个流程中所用的方法有较大不同『且如此文第三部分 此节《25年Q4 不断做更多订单,推动中国具身的更快落地-11.12-12月底,长沙分部开启第四轮加速:侧重人形跳舞、展厅讲解、灵巧操作》中
所说的:“这第二版 相比今25年六月份第一版的升级在于,通过我们打通的这套新流程/新方法,可实现『任意舞蹈任意学』
只需给定对应舞蹈/太极/打拳,或其他任意动作的视频即可 』 - 至于开发周期上,快1-2天 慢3-4天,即可训练、部署皆到位,是人形跳舞走向规模化,即批量生产、批量复制的关键”
至于具体的跳舞开发流程,则为
- 先拍视频,或者直接用宇树开源的LAFAN数据集中的视频
- video2motion,比如GVHMR,即从RGB视频中提取人的SMPL轨迹
- 重定向,比如GMR
- 后仿真中RL训练,比如Beyondmimic(含rsl-RL) + motion_tracking_controller
- 最后sim2sim(比如Isaac lab到mujoco,即isaac lab训练完导出的 onnx,然后在 mujoco 里面验证),和真机部署
————
总之,上述的整个流程,和一浙大具身博士发我的这个很类似
1.5.2 如何把整套新流程/新方法部署在宇树自带的PC2里
再后来,当我们想把这套新流程/新方法,直接部署在宇树pc2里时,然技术合伙人之一的朝阳发现
- 一方面bydmimic项目是基于roshumble
当然了,如同事夏同学所说,“端测的roshumble,这个我也搞了一个镜像,到时候如果需要可以用这个”
另一方面 legged_control2安装,需要从docker安装,但目前没有找到相关的文件
- 几天后,我们改用了夏同学在公司群内发过的这个robojudo框架:https://github.com/HansZ8/RoboJuDo/tree/release
可以通过该框架,直接把整套新流程部署在pc2上,实现无网线下的跳舞
且如文弱所说,是个万金油,twist1,asap的onnx都可以跑
也如夏同学所说,是的,这套没用ros,感觉部署起来容易些
更可以如朝阳所说:还可以切换走路,说白了,行走和跳舞可以切换 - 当然了,如夏同学11.22日所说,robojudo 的输出频率是 50 hz ,ros2是 60hz。可能有些许影响
故有兴趣的 还可以试下地平线这个holomotion框架
https://github.com/HorizonRobotics/HoloMotion
// 待更
第二部分 BeyondMimic 全身追踪项目分析
如上所述,BeyondMimic 是一个基于 Isaac Lab 的人形机器人全身运动追踪框架,用于在仿真环境中训练机器人追踪参考动作的强化学习策略。该项目支持将 LAFAN1 等数据集中的人体动作迁移到人形机器人上(如Unitree G1),实现高质量的动作模仿
且涉及到
- 仿真环境: NVIDIA Isaac Sim 4.5.0 + Isaac Lab 2.1.0
- 强化学习: RSL-RL (PPO算法)
- 编程语言: Python 3.10
- 运动数据管理: WandB (Weights & Biases)
以下是整个系统的核心代码结构
whole_body_tracking/
├── scripts/ # 脚本工具集
│ ├── csv_to_npz.py # 动作预处理:CSV→NPZ转换
│ ├── replay_npz.py # 动作回放工具
│ ├── upload_npz.py # 上传动作到WandB
│ └── rsl_rl/ # 强化学习训练/评估脚本
│ ├── train.py # 训练入口
│ └── play.py # 评估/推理入口
├── source/whole_body_tracking/ # 核心源代码
│ └── whole_body_tracking/
│ ├── assets/ # 机器人资产文件
│ ├── robots/ # 机器人配置
│ │ ├── g1.py # Unitree G1机器人定义
│ │ ├── actuator.py # 执行器配置
│ │ └── smpl.py # SMPL人体模型
│ ├── tasks/ # 任务定义
│ │ └── tracking/ # 追踪任务
│ │ ├── tracking_env_cfg.py # 环境配置基类
│ │ ├── mdp/ # MDP定义(马尔可夫决策过程)
│ │ │ ├── commands.py # 命令生成(参考动作加载)
│ │ │ ├── rewards.py # 奖励函数
│ │ │ ├── observations.py # 观测定义
│ │ │ ├── events.py # 随机化事件
│ │ │ └── terminations.py # 终止条件
│ │ └── config/ # 任务配置
│ │ └── g1/ # G1机器人专属配置
│ │ ├── flat_env_cfg.py # G1环境配置
│ │ └── agents/
│ │ └── rsl_rl_ppo_cfg.py # PPO超参数
│ └── utils/ # 工具模块
│ ├── exporter.py # 模型导出(ONNX)
│ └── my_on_policy_runner.py # 自定义训练循环
2.1 动作预处理、机器人配置、MDP定义模块、环境配置
2.1.1 动作预处理模块(`scripts/csv_to_npz.py`)
该模块将CSV格式的动作数据转换为NPZ格式,并计算完整的物理信息,其核心步骤如下所示:
- 加载CSV数据: 读取关节位置数据(generalized coordinates)
- 插值: 将动作从输入FPS(如30fps)插值到输出FPS(如50fps)
- 正向运动学: 计算所有身体部位的:
- 位置 (body_pos_w)
- 姿态四元数 (body_quat_w)
- 线速度 (body_lin_vel_w)
- 角速度 (body_ang_vel_w) - 上传到WandB: 自动上传到WandB Registry用于版本管理
输出格式 (NPZ文件包含):python { 'fps': 50, 'joint_pos': [T, N_joints], # 关节位置 'joint_vel': [T, N_joints], # 关节速度 'body_pos_w': [T, N_bodies, 3], # 身体位置(世界坐标系) 'body_quat_w': [T, N_bodies, 4], # 身体姿态 'body_lin_vel_w': [T, N_bodies, 3], # 线速度 'body_ang_vel_w': [T, N_bodies, 3], # 角速度 }
2.1.2 机器人配置模块(`robots/g1.py`)
该模块会定义Unitree G1机器人的物理属性和执行器参数,涉及的核心配置包括
- 执行器分组:
- `legs`: 髋关节/膝关节(大扭矩电机 7520系列)
- `feet`: 踝关节(中等扭矩电机 5020系列)
- `waist`: 腰部roll/pitch(5020系列)
- `arms`: 手臂关节(5020/4010系列) - 物理参数计算(基于电机armature):
自然频率 = 10Hz 刚度 (stiffness) = armature × (2π × 10Hz)² 阻尼 (damping) = 2 × damping_ratio × armature × (2π × 10Hz) - 动作缩放** (`G1_ACTION_SCALE`):
scale = 0.25 × effort_limit / stiffness # 确保动作空间在合理范围内
涉及到关键参数包括
- `soft_joint_pos_limit_factor=0.9`: 软关节限制
- `enabled_self_collisions=True`: 启用自碰撞检测
- `replace_cylinders_with_capsules=True`: 几何形状优化
2.1.3 MDP定义模块 (`tasks/tracking/mdp/`):包含命令、奖励、观测、终止条件、随机化
2.1.3.1 命令模块 (`commands.py`)
其中的核心类是 `MotionCommand`,且其实现了如下功能
- 动作加载: 从NPZ文件加载参考动作
- 自适应采样: 根据训练失败率动态调整起始帧采样
- 初始状态随机化: 在参考动作基础上添加噪声
- 误差计算: 实时计算机器人与参考动作的误差
其中的关键机制是自适应采样:
# 将动作分成bins,记录每个bin的失败率
bin_failed_count[bin_idx] = α × current_failed + (1-α) × historical_failed
# 使用失败率作为采样概率(失败多的地方多采样)
sampling_prob = bin_failed_count + uniform_ratio
sampled_frame = sample_from(sampling_prob)
而对于观测属性则包含
- `joint_pos/vel`: 参考关节位置/速度
- `body_pos_w/quat_w`: 参考身体位置/姿态(世界坐标系)
- `anchor_pos_w`: 锚点(通常是躯干)位置
- `body_pos_relative_w`: 相对于锚点的身体位置
2.1.3.2 奖励模块 (`rewards.py`)
首先,是DeepMimic风格奖励函数
# 1. 全局锚点位置误差(躯干位置)
R_anchor_pos = exp(-||p_ref - p_robot||² / σ_pos²) # σ=0.3
# 2. 全局锚点姿态误差
R_anchor_ori = exp(-quat_error(q_ref, q_robot)² / σ_ori²) # σ=0.4
# 3. 相对身体位置误差(手脚等末端)
R_body_pos = exp(-mean(||p_ref - p_robot||²) / σ_pos²) # σ=0.3
# 4. 相对身体姿态误差
R_body_ori = exp(-mean(quat_error(...)) / σ_ori²) # σ=0.4
# 5. 身体线速度误差
R_lin_vel = exp(-mean(||v_ref - v_robot||²) / σ_vel²) # σ=1.0
# 6. 身体角速度误差
R_ang_vel = exp(-mean(||ω_ref - ω_robot||²) / σ_ang²) # σ=3.14
# 惩罚项
R_action_rate = -0.1 × ||a_t - a_{t-1}||² # 动作平滑性
R_joint_limit = -10.0 × violation # 关节限制违反
R_undesired_contact = -0.1 × undesired_contacts # 非期望碰撞
其次,是总奖励
R_total = 0.5×R_anchor_pos + 0.5×R_anchor_ori
+ 1.0×R_body_pos + 1.0×R_body_ori
+ 1.0×R_lin_vel + 1.0×R_ang_vel
+ R_action_rate + R_joint_limit + R_undesired_contact
2.1.3.3 观测模块 (`observations.py`)
首先是Policy观测 (带噪声)
obs_policy = [
command, # 参考关节位置/速度
motion_anchor_pos_b, # 锚点位置(body frame)+ 噪声
motion_anchor_ori_b, # 锚点姿态 + 噪声
base_lin_vel, # 基座线速度 + 噪声
base_ang_vel, # 基座角速度 + 噪声
joint_pos, # 当前关节位置 + 噪声
joint_vel, # 当前关节速度 + 噪声
last_action, # 上一时刻动作
]
其次是Critic观测 (无噪声,包含特权信息)
obs_critic = [
command,
motion_anchor_pos_b, # 无噪声
body_pos, # 所有身体部位位置(特权信息)
body_ori, # 所有身体部位姿态
base_lin_vel,
base_ang_vel,
joint_pos,
joint_vel,
last_action,
]
2.1.3.4 终止条件 (`terminations.py`)
直接贴代码示例
# 1. 超时
time_out: episode_length_s = 10s
# 2. 锚点位置过差(z方向)
bad_anchor_pos: |z_ref - z_robot| > 0.25m
# 3. 锚点姿态过差
bad_anchor_ori: quat_error > 0.8 (约143度)
# 4. 末端身体位置过差(手脚)
bad_ee_pos: |z_ref - z_robot| > 0.25m
2.1.3.5 随机化事件 (`events.py`)
第一,启动时随机化
# 1. 物理材料
static_friction: [0.3, 1.6]
dynamic_friction: [0.3, 1.2]
restitution: [0.0, 0.5]
# 2. 关节默认位置
joint_default_pos += uniform(-0.01, 0.01)
# 3. 躯干质心偏移
COM_offset: x∈[-0.025, 0.025], y∈[-0.05, 0.05], z∈[-0.05, 0.05]
第二,运行时随机化
# 推力干扰(每1-3秒)
push_velocity:
linear: x,y,z ∈ [-0.5, 0.5] m/s
angular: roll,pitch,yaw ∈ [-0.52, 0.78] rad/s
2.1.4 环境配置模块 (`tracking_env_cfg.py` + `g1/flat_env_cfg.py`)
首先是基础环境配置 (`TrackingEnvCfg`):
num_envs: 4096 # 并行环境数
env_spacing: 2.5m # 环境间距
decimation: 4 # 4次物理步对应1次RL步
sim.dt: 0.005s (200Hz) # 物理仿真频率
episode_length: 10s # Episode长度
其次是G1专属配置** (`G1FlatEnvCfg`):
robot: G1_CYLINDER_CFG
action_scale: G1_ACTION_SCALE
anchor_body: "torso_link"
tracked_bodies: [
"pelvis",
"left/right_hip_roll_link",
"left/right_knee_link",
"left/right_ankle_roll_link",
"torso_link",
"left/right_shoulder_roll_link",
"left/right_elbow_link",
"left/right_wrist_yaw_link"
] # 共14个身体部位
2.2 基于经典RL框架rsl_rl的训练配置、训练流程、评估流程
2.2.1 训练配置模块 (`agents/rsl_rl_ppo_cfg.py`)
首先,关于rsl_rl的介绍,详见此文《NaVILA源码解析:从其VLA部分到其low-level部分(涵盖legged-loco、经典RL框架rsl_rl)》的第四部分
第一,PPO超参数如下
# 采样
num_steps_per_env: 24 # 每个环境采样步数
max_iterations: 30000 # 最大迭代次数
# 网络架构
actor_hidden: [512, 256, 128]
critic_hidden: [512, 256, 128]
activation: "elu"
init_noise_std: 1.0
# PPO算法
learning_rate: 1e-3
schedule: "adaptive" # 自适应学习率
clip_param: 0.2 # PPO裁剪参数
entropy_coef: 0.005 # 熵正则化
num_learning_epochs: 5 # 每次迭代训练5轮
num_mini_batches: 4 # 每轮分4个batch
gamma: 0.99 # 折扣因子
lam: 0.95 # GAE lambda
desired_kl: 0.01 # 目标KL散度
max_grad_norm: 1.0 # 梯度裁剪
第二,低频控制变体 (`G1FlatLowFreqPPORunnerCfg`)如下配置
LOW_FREQ_SCALE = 0.5
num_steps_per_env: 24 × 0.5 = 12
decimation: 4 / 0.5 = 8 # 更低的控制频率
gamma: 0.99^(1/0.5) = 0.98
2.2.2 训练流程模块 (`scripts/rsl_rl/train.py`)
详细的执行流程如下所示
- 参数解析:
--task Tracking-Flat-G1-v0 --registry_name {org}/wandb-registry-motions/{motion_name}:latest --num_envs 4096 --headless - 动作加载:
# 从WandB下载参考动作 artifact = wandb.api.artifact(registry_name) motion_file = artifact.download() / "motion.npz" env_cfg.commands.motion.motion_file = motion_file - 环境创建
env = gym.make(task_name, cfg=env_cfg) env = RslRlVecEnvWrapper(env) # 包装为RSL-RL格式 - 训练器初始化:
runner = MotionOnPolicyRunner( env, agent_cfg, log_dir=log_dir, registry_name=registry_name ) - 训练循环:
runner.learn( num_learning_iterations=max_iterations, init_at_random_ep_len=True # 自适应采样初始化 )
对应的日志记录如下所示
logs/rsl_rl/{experiment_name}/{timestamp}_{run_name}/
├── params/
│ ├── env.yaml # 环境配置
│ └── agent.yaml # 训练配置
├── model_*.pt # 模型检查点
├── videos/ # 训练视频(如启用)
└── wandb/ # WandB日志
2.2.3 评估流程模块 (`scripts/rsl_rl/play.py`)
执行流程如下
- 参数解析:
--task Tracking-Flat-G1-v0 --wandb_path {org}/{project}/{run_id} --num_envs 2 --video # 录制视频 - 模型加载:
# 从WandB下载模型 wandb_run = wandb.api.run(wandb_path) model_file = download_latest_model() # model_xxx.pt # 加载参考动作 artifact = wandb_run.used_artifacts(type="motions") motion_file = artifact.download() / "motion.npz" - 推理循环:
policy = runner.get_inference_policy() obs, _ = env.get_observations() while running: actions = policy(obs) obs, _, _, _ = env.step(actions) - 模型导出:
export_motion_policy_as_onnx( env, policy, path=export_dir, filename="policy.onnx" ) # 输出: logs/.../exported/policy.onnx
2.3(选读) 模块间联系与数据流、完整运行流程、常见问题与调试
2.3.1 数据流图
┌─────────────────┐
│ CSV动作数据 │
│ (LAFAN1等) │
└────────┬────────┘
│
▼
┌─────────────────────────┐
│ csv_to_npz.py │
│ - 插值到50Hz │
│ - 正向运动学计算 │
│ - 计算速度/加速度 │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ WandB Registry │
│ motion.npz存储 │
│ (fps, joint_pos, │
│ body_pos_w, ...) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ train.py │
│ 1. 下载motion.npz │
│ 2. 创建环境 │
│ 3. 初始化Runner │
└────────┬────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ ManagerBasedRLEnv (Isaac Lab) │
│ ┌────────────────────────────────────┐ │
│ │ MotionCommand │ │
│ │ - 加载NPZ文件 │ │
│ │ - 自适应采样起始帧 │ │
│ │ - 初始化机器人状态 │ │
│ │ - 提供参考动作 │ │
│ └────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 观测生成 │ │
│ │ - Policy: 带噪声 │ │
│ │ - Critic: 无噪声+特权信息 │ │
│ └────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ PPO Policy │ │
│ │ Actor: obs → action │ │
│ │ Critic: obs → value │ │
│ └────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 动作执行 │ │
│ │ action × scale → PD控制器 │ │
│ │ → 关节扭矩 → PhysX仿真 │ │
│ └────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 奖励计算 │ │
│ │ - 位置/姿态误差 │ │
│ │ - 速度误差 │ │
│ │ - 惩罚项 │ │
│ └────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────┐ │
│ │ 终止条件检查 │ │
│ │ - 超时/倒地/偏离过大 │ │
│ └────────┬───────────────────────────┘ │
└───────────┼──────────────────────────────┘
│
▼
┌─────────────────────────┐
│ PPO优化 │
│ - 计算advantage │
│ - 更新actor/critic │
│ - 自适应学习率 │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 日志记录 │
│ - WandB: 奖励/误差曲线 │
│ - 保存模型检查点 │
│ - 录制视频 │
└─────────────────────────┘
其中涉及的关键交互接口有
- MotionCommand → 环境
# MotionCommand提供 command.joint_pos # [N_env, N_joints] command.body_pos_relative_w # [N_env, N_bodies, 3] command.body_quat_relative_w # [N_env, N_bodies, 4] command.anchor_pos_w # [N_env, 3] command.metrics # 误差字典 - 环境 → PPO
# 每步交互 obs = env.get_observations() # dict{'policy': tensor, 'critic': tensor} reward, done, info = env.step(action) - PPO → 模型保存
# 每500次迭代 runner.save(f"model_{iteration}.pt") # 包含: actor, critic, obs_normalizer
2.3.2 完整运行流程
2.3.2.1 数据准备阶段
- # 步骤1: 下载动作数据(例如LAFAN1)
# 从 HuggingFace 下载: https://huggingface.co/datasets/lvhaidong/LAFAN1_Retargeting_Dataset - 步骤2: 转换为NPZ并上传到WandB
# 自动执行:export WANDB_ENTITY=your-org-name python scripts/csv_to_npz.py \ --input_file dance1_subject2.csv \ --input_fps 30 \ --output_name dance1_subject2 \ --headless
# 1. 读取CSV → 插值到50Hz
# 2. 在Isaac Sim中正向运动学计算
# 3. 保存到/tmp/motion.npz
# 4. 上传到WandB: {org}/wandb-registry-motions/dance1_subject2:latest
其中的内部执行细节为# csv_to_npz.py内部流程 motion_loader = MotionLoader(csv_file, fps=30, output_fps=50) motion_loader._interpolate_motion() # 插值 # 在Isaac Sim中 for t in range(time_steps): robot.set_joint_positions(motion_loader.joint_pos[t]) sim.step() body_pos[t] = robot.get_body_positions() body_quat[t] = robot.get_body_orientations() # 计算速度(数值微分) body_vel[t] = (body_pos[t] - body_pos[t-1]) / dt # 保存并上传 np.savez('motion.npz', fps=50, joint_pos=..., body_pos_w=...) wandb.log_artifact('motion.npz', type='motions')
2.3.2.2 训练阶段
- # 步骤3: 启动训练
python scripts/rsl_rl/train.py \ --task=Tracking-Flat-G1-v0 \ --registry_name your-org/wandb-registry-motions/dance1_subject2 \ --num_envs 4096 \ --headless \ --logger wandb \ --log_project_name beyondmimic \ --run_name dance1_g1
以下是针对训练循环的详解:
# 初始化 (iteration=0)
env.reset() # 调用MotionCommand._resample_command()
# → 自适应采样起始帧
# → 添加噪声到关节位置/基座位置
# → 写入仿真状态
for iteration in range(30000): # max_iterations
# ==== 采样阶段 ====
for step in range(24): # num_steps_per_env
# 1. 获取观测
obs_policy = env.get_obs() # [4096, obs_dim]
obs_critic = env.get_privileged_obs()
# 2. 策略推理
with torch.no_grad():
action, log_prob = policy(obs_policy) # [4096, action_dim]
value = critic(obs_critic)
# 3. 执行动作
env.step(action)
# → action × G1_ACTION_SCALE → 目标关节位置
# → PD控制器: τ = Kp×(q_d - q) + Kd×(v_d - v)
# → PhysX物理仿真4步(decimation=4)
# → 更新MotionCommand时间步 (time_step += 1)
# 4. 计算奖励
reward = compute_rewards(env)
# → 6个跟踪奖励 + 3个惩罚项
# 5. 检查终止
done = check_terminations(env)
# → 如果done,调用_resample_command重新初始化
# 6. 存储transition
rollout_buffer.add(obs, action, reward, value, log_prob)
# ==== 优化阶段 ====
# 7. 计算advantage
advantages = compute_gae(rewards, values, gamma=0.99, lam=0.95)
returns = advantages + values
# 8. PPO更新
for epoch in range(5): # num_learning_epochs
for batch in split_batches(rollout_buffer, num_batches=4):
# Actor loss
new_log_prob, entropy = policy.evaluate(batch.obs, batch.action)
ratio = torch.exp(new_log_prob - batch.old_log_prob)
surr1 = ratio * batch.advantages
surr2 = torch.clamp(ratio, 1-0.2, 1+0.2) * batch.advantages
actor_loss = -torch.min(surr1, surr2).mean() - 0.005*entropy
# Critic loss
value_pred = critic(batch.obs)
value_clipped = batch.old_values + torch.clamp(
value_pred - batch.old_values, -0.2, 0.2
)
value_loss = torch.max(
(value_pred - batch.returns)**2,
(value_clipped - batch.returns)**2
).mean()
# 总损失
loss = actor_loss + 1.0*value_loss
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(parameters, max_norm=1.0)
optimizer.step()
# ==== 自适应学习率 ====
kl_div = compute_kl(old_policy, new_policy)
if kl_div > 0.01 * 1.5: # desired_kl * 1.5
lr *= 0.5
elif kl_div < 0.01 / 1.5:
lr *= 1.5
# ==== 日志记录 ====
if iteration % 500 == 0:
runner.save(f"model_{iteration}.pt")
wandb.log({
'reward': reward.mean(),
'error_anchor_pos': env.command.metrics['error_anchor_pos'].mean(),
'sampling_entropy': env.command.metrics['sampling_entropy'].mean(),
# ...
})
```
**自适应采样机制**:
```python
# 在MotionCommand中
def _adaptive_sampling(self, env_ids):
# 记录失败帧
if episode_failed:
failed_bins = current_frame // bin_size
bin_failed_count[failed_bins] += 1
# 计算采样概率
prob = bin_failed_count + uniform_ratio
prob = conv1d(prob, exponential_kernel) # 平滑
prob = prob / prob.sum()
# 采样起始帧
sampled_bins = multinomial(prob, num_samples=len(env_ids))
start_frames = sampled_bins * bin_size + random(0, bin_size)
# 日志记录熵(衡量探索程度)
entropy = -sum(prob × log(prob))
metrics['sampling_entropy'] = entropy
```
**训练进度示例**:
```
Iteration 0 | Reward: 0.12 | error_pos: 0.45m | entropy: 0.95
Iteration 1000 | Reward: 2.34 | error_pos: 0.15m | entropy: 0.72
Iteration 5000 | Reward: 4.56 | error_pos: 0.08m | entropy: 0.45
Iteration 30000| Reward: 5.89 | error_pos: 0.03m | entropy: 0.38
2.3.2.3 评估阶段
- 步骤4: 评估训练好的策略
python scripts/rsl_rl/play.py \ --task=Tracking-Flat-G1-v0 \ --wandb_path your-org/beyondmimic/abc12345 \ --num_envs 2 \ --video \ --video_length 500
以下是详细的评估流程:
# 1. 从WandB下载模型
model_path = download_model_from_wandb(wandb_path)
# 例如: logs/rsl_rl/temp/model_30000.pt
# 2. 加载模型
runner = OnPolicyRunner(env, cfg)
runner.load(model_path)
policy = runner.get_inference_policy() # 去除探索噪声
# 3. 推理循环
env.reset()
obs = env.get_observations()
for step in range(500):
with torch.inference_mode():
action = policy(obs) # 确定性策略
obs, reward, done, info = env.step(action)
# 录制视频(如启用)
# 4. 导出ONNX
export_motion_policy_as_onnx(
env, policy,
path="logs/.../exported/",
filename="policy.onnx"
)
# 用于部署到真实机器人
```
**ONNX导出详情**:
```python
# exporter.py
def export_motion_policy_as_onnx(env, policy, path, filename):
# 创建包含观测归一化的完整模型
class ExportablePolicy(nn.Module):
def forward(self, obs):
obs_normalized = obs_normalizer(obs)
action = policy(obs_normalized)
return action
# 导出
dummy_input = torch.randn(1, obs_dim)
torch.onnx.export(
ExportablePolicy(),
dummy_input,
f"{path}/{filename}",
input_names=["observation"],
output_names=["action"],
dynamic_axes={"observation": {0: "batch"}}
)
# 添加元数据
attach_onnx_metadata(env, wandb_path, path)
# 包括: 观测维度, 动作维度, 控制频率, 机器人类型等
2.3.2.4 部署阶段(Sim-to-Real)
- # 步骤5: 部署到真实机器人(需额外仓库)
# 参考: https://github.com/HybridRobotics/motion_tracking_controller# 1. 加载ONNX模型 controller.load_policy("exported/policy.onnx") # 2. 实时推理循环(50Hz) while True: obs = get_robot_state() # 从真实机器人读取状态 action = controller.inference(obs) send_joint_commands(action) # 发送到机器人 sleep(0.02) # 50Hz
2.3.3 常见问题与调试
2.3.3.1 训练不收敛
可能导致的原因:
- 动作数据质量差(关节越界)
- 奖励函数权重不合理
- 学习率过大
解决方案则为
- 1. 检查动作数据
python scripts/replay_npz.py --registry_name=...
# 观察是否有抖动/越界 - 调整奖励权重
# 在 flat_env_cfg.py 中
rewards.motion_body_pos.weight = 2.0 # 增加位置权重 - 降低学习率
# 在 rsl_rl_ppo_cfg.py 中
algorithm.learning_rate = 5e-4
2.3.3.2 WandB连接问题
# 确保设置正确的组织名
export WANDB_ENTITY=your-org-name # 不是用户名!
# 登录
wandb login
# 检查权限
wandb artifact get your-org/wandb-registry-motions/motion_name:latest
2.2.3.3 内存不足
# 减少并行环境数
--num_envs 2048 # 默认4096
# 或减少采样步数
# 在 rsl_rl_ppo_cfg.py 中
num_steps_per_env = 12 # 默认24
2.2.3.4 仿真不稳定
# 增加求解器迭代次数
# 在 g1.py 中
articulation_props=sim_utils.ArticulationRootPropertiesCfg(
solver_position_iteration_count=16, # 默认8
solver_velocity_iteration_count=8, # 默认4
)
2.3.4 扩展开发指南
2.3.4.1 添加新机器人
- 创建 robots/my_robot.py
MY_ROBOT_CFG = ArticulationCfg( spawn=sim_utils.UrdfFileCfg(asset_path="..."), actuators={...}, # ... ) - 创建 config/my_robot/flat_env_cfg.py
@configclass class MyRobotFlatEnvCfg(TrackingEnvCfg): def __post_init__(self): self.scene.robot = MY_ROBOT_CFG self.commands.motion.body_names = [...] - 注册环境
gym.register( id="Tracking-Flat-MyRobot-v0", entry_point="isaaclab.envs:ManagerBasedRLEnv", kwargs={...} )
2.3.4.2 添加新奖励项
- 在 mdp/rewards.py 中
def my_custom_reward(env: ManagerBasedRLEnv, ...) -> torch.Tensor: # 计算奖励 return reward_value - 在 tracking_env_cfg.py 中
@configclass class RewardsCfg: my_reward = RewTerm( func=mdp.my_custom_reward, weight=1.0, params={...} )
2.4.3.3 自定义观测
- 在 mdp/observations.py 中
def my_observation(env: ManagerBasedRLEnv, ...) -> torch.Tensor: # 返回观测向量 return obs - 在 ObservationsCfg 中
@configclass class PolicyCfg(ObsGroup): my_obs = ObsTerm(func=mdp.my_observation)
2.3.5 性能优化建议
对于训练加速
- GPU选择: RTX 4090 / A100 推荐
- 并行环境: 尽量使用4096(受限于GPU显存)
- 异步执行: Isaac Sim已内置GPU并行
对于仿真加速
# 禁用不必要的功能
self.sim.render_interval = self.decimation # 降低渲染频率
args_cli.headless = True # 无头模式
# 简化碰撞几何
replace_cylinders_with_capsules=True
对于日志优化
# 减少WandB日志频率
# 在 my_on_policy_runner.py 中
if iteration % 10 == 0: # 每10次迭代记录一次
wandb.log({...})
2.3.6 总结
核心流程总结
- 数据准备: CSV → NPZ → WandB Registry
- 环境配置: 机器人 + MDP + 奖励函数
- 训练: PPO + 自适应采样 + 域随机化
- 评估: 加载模型 → 推理 → 导出ONNX
- 部署: ONNX → 真实机器人控制器
技术亮点包括
- 自适应课程学习: 自动聚焦困难片段
- 充分的域随机化: 提高Sim-to-Real鲁棒性
- 特权信息学习: Critic使用完整状态
- 高效并行仿真: GPU加速4096环境
- 模块化设计: 易于扩展新机器人/任务
第三部分 UniTracker——面向人形全身运动追踪器的学习:为解决师生框架的局限性,将CVAE集成到学生策略架构中
3.1 引言、相关工作、问题表述
3.1.1 引言
如UniTracker原论文所说,近期的研究探索了多种针对人形机器人全身控制器的控制接口,这些接口大致可以分为稠密控制信号和稀疏控制信号
- 稠密信号(如遥操作[1,2,3,4,5,6]、离线动作数据集[7,8,9,10,11,12,13]以及基于视频的动作估计[14,15])能够提供丰富的轨迹级信息
- 相比之下,稀疏信号(如高层任务指令和基于虚拟现实的引导[16,17])仅提供极少的信息,往往导致动作质量下降
在本UniTracker的研究中,作者专注于通用全身动作跟踪任务,其中输入为参考动作序列,目标是通过单一策略实现对该序列的鲁棒且富有表现力的跟踪
广泛采用的一种运动跟踪策略学习范式是教师-学生框架
- 在该范式中,教师策略首先利用完整的特权观测,在仿真环境中精确跟踪参考动作
- 随后,学生策略仅基于部署时可用的部分观测,学习模仿教师策略
尽管该教师-学生框架行之有效,但现有实现方式,特别是采用简单MLP(多层感知机)结构的DAgger架构[18],存在三大显著局限
- 首先,在蒸馏过程中,这些方法常常无法保留原始参考动作中固有的多样性,导致行为趋于平均化且表现力不足
- 其次,受限于其有限的表示能力,此类模型通常在面对未见过的动作序列时泛化能力较差
- 第三,训练过程中缺乏全局上下文信息,导致如方向漂移等问题,以及全局行为上的更大不一致性,这些问题在策略部署到真实人形机器人上时尤为突出
为了解决现有师生框架的上述局限性,来自1 Shanghai Jiao Tong Univeristy, 2 Shanghai Artificial Intelligence Laboratory, 3 Peking University, 4 Zhejiang University, 5 The Hong Kong University of Science and Technology (Guangzhou), 6 ShanghaiTech University的研究者提出了UniTracker——一个统一且具表现力的全身跟踪框架,将条件变分自编码器(CVAE)[19]集成到学生策略架构中

- 其对应的论文为:UniTracker: Learning Universal Whole-Body Motion Tracker for Humanoid Robots
其对应的作者包括
Kangning Yin1,2∗, Weishuai Zeng2,3∗, Ke Fan1,2, Zirui Wang2,4
Qiang Zhang5,Zheng Tian6, Jingbo Wang2, Jiangmiao Pang2, Weinan Zhang1,2 - 其项目网址为:Humanoid-UniTracker/
截止到25年8月底,为开源,且不确定其是否有开源计划,回头我再问下相关作者
通过对受未来运动参考条件约束的结构化潜在空间进行显式建模,UniTracker使策略即使在部分观测条件下,也能生成多样且高保真的行为
- 从概率角度来看,潜在变量捕捉了从观测到动作映射中固有的不确定性,使策略能够对可能的运动行为建模分布,而不仅仅收敛于单一的确定性输出。这一能力增强了运动表现力,并显著提升了在多样且未见过的运动模式下的泛化能力
- 此外,基于CVAE的框架还有效解决了全局上下文缺失这一难题——这一问题在部署过程中常表现为方向漂移及其他全局不一致性
为此,作者在训练阶段采用了任务感知特征建模:编码器利用具有特权的全局信息观测进行训练,以推断结构化的潜在表示;
同时,先验网络则仅基于部署时可用的部分观测数据进行同步训练(相当于基于CVAE的学生策略以实现部分观测下的部署)
总之,这两种分布通过KL散度目标进行对齐。因此,尽管最终部署的策略在部分可观测的环境下运行,但由于训练过程中潜在空间受到了全局上下文的指导,策略依然能从中获益。这种对全局信息的隐式融入,使得在实际环境中表现出的行为更加连贯且具备全局一致性
====
简言之,通过CVAE建模实现多样性感知和全局上下文整合的策略:采用条件变分自编码器(CVAE)以捕捉动作多样性并编码全局上下文,通过将具备全局信息的编码器与部分观测先验对齐,从而实现更具表现力的行为并减少全局不一致性 - 最后,尽管基于CVAE的通用策略在广泛的动作范围内表现出色,但并不需要也不现实地期望它能够完美跟踪所有可能的参考序列——尤其是那些罕见、高度动态或远离训练分布的序列
为应对这些具有挑战性的情况,作者引入了一个快速自适应阶段,以任务为中心对通用策略进行微调
说白了,就是用于特定动作快速微调的轻量级快速自适应阶段
该自适应过程利用基础策略的表达能力和通用性,实现了在极短训练时间内的快速专业化
且他们的框架支持单序列自适应和批量自适应两种方式,从而在处理多个复杂动作时实现可扩展的精细优化。这个最终阶段通过将通用策略的实际适用性扩展到边缘案例,进一步突显了他们三阶段训练框架的模块化和灵活性
3.1.2 相关工作:遥操作、离线运动数据集、基于视频的运动估计、高层任务指令
全身控制对于使人形机器人能够执行各种复杂任务至关重要
- 在强化学习兴起之前,研究人员主要依赖传统的基于优化的控制方法来实现人形机器人的全身控制[31,32,33,34,35,36,37]
这些方法通常需要对机器人及其环境进行明确的数学建模,并通过实时优化来计算机器人的下一个动作。然而,此类方法往往难以适应环境变化,导致鲁棒性有限。此外,它们在在线执行过程中会带来较大的计算负担 - 为克服这些局限性,强化学习(RL)作为一种强有力的替代方案出现,能够通过与环境的直接交互学习自适应、鲁棒的控制策略,而无需依赖显式建模
目前,基于强化学习的人形机器人全身控制器可根据其控制信号的来源进行分类,包括
- 遥操作[1,2,3,4,5,6]
遥操作是指通过人类输入实时直接控制人形机器人,通常借助动作捕捉系统或可穿戴传感器,使机器人能够高保真地模仿人类动作。该领域的代表性工作包括Twist[1]和H2O[4],二者均采用了两阶段的师生框架。主要区别在于策略观测空间的设计 - 离线运动数据集[7,8,10,11]
离线运动数据集由预先收集的人类或人形机器人运动序列组成,这些数据被用作训练控制策略进行动作模仿的参考
代表性工作有Exbody[11]和Exbody2[10],其方法首先精心整理离线运动数据集,然后尽可能将上半身和下半身动作解耦,旨在保持下半身的稳定性,同时鼓励上半身的多样性和表现力
此外,最新的工作GMT[12]首次展示了通过单一统一策略跟踪8,000种动作 - 基于视频的运动估计[14,15][5,6]
基于视频的运动估计方法利用视频中的视觉输入提取人体运动数据,然后用于引导人形机器人控制策略。这一方法使得能够从大规模、多样化的动作来源中进行学习,而无需直接依赖人类示范
具有代表性的工作是 VideoMimic [14],其提出了一个真实-仿真-真实(real-to-sim-to-real)流程,用于建模机器人及其周围环境 - 以及高层任务指令[16,17]
任务指令指的是高层次、稀疏的控制信号,用于指定期望的结果或目标,例如行走方向或目标位置,而非详细的关节级动作,从而通过抽象实现高效的全身控制
代表性工作包括 Hover [16] 和HugWBC [17]Hover 将多种控制模式统一到单一策略中,实现了各模式之间的无缝切换,同时保留了每种模式的优势,因此为类人机器人控制提供了强健且可扩展的解决方案
HugWBC 设计了通用的任务与行为指令空间,并采用了对称损失和干预训练等技术。这使得现实世界中的类人机器人能够执行多种自然步态——包括行走、跳跃和单足跳
3.1.3 问题表述
作者将类人机器人全身运动追踪的问题表述为一个以目标为条件的RL任务,其中
- 策略π 被训练用于在全身层面追踪参考运动
- 状态
包括机器人的本体感知信息
以及目标
,后者指定了所有身体部位的目标状态
- 奖励函数
,以智能体的本体感知和目标状态为定义,提供稠密信号以引导策略优化
为了更好地关注全身层面的运动追踪,作者将29 自由度DoF的Unitree G1 机器人[20] 的手腕关节固定,将动作空间减少至23 维
动作指定目标关节位置,通过PD 控制器执行以驱动机器人。对于策略优化,作者采用近端策略优化PPO[21],以最大化期望的累计折扣奖励
3.2 UniTracker的整体方法论
3.2.1 仿人动作数据集整理
大规模的人形动作数据集为训练通用动作追踪器提供了动力。作者的数据集主要来源于公开可用的AMASS [22] 数据集,经过筛选,去除了包含交互的片段和少于10 帧的序列
- 最终得到的训练集包含11,313 个人体动作,使用SMPL [23] 参数进行表示。SMPL 模型通过形状参数
、姿态参数
和根部平移
来参数化人体
表示SMPL 函数,其中
将SMPL 参数映射为三角形人体网格的顶点位置
且作者为了弥合SMPL 人体模型与人形机器人之间的体现差距,他们采用了受H2O [4] 启发的两阶段重定向方法
- 首先,精心选择了16 个对应的身体连接,并通过最小化静止姿态下所选连接之间的距离,优化人形机器人的形状参数
- 其次,利用优化后的
以及数据集中原始的姿态
和位移
,作者对人形机器人的根部位移、根部朝向和关节位置进行梯度下降,以在整个序列中最小化所选连接之间的距离
且还添加了额外的正则项,以避免激进行为并确保时序平滑
// 待更
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)