GMR 工程实践笔记:把自己的机器人接入动作重定向流程

上一篇理论篇主要聊了 GMR 的方法逻辑:关键体匹配、默认姿态对齐、非均匀局部缩放,以及两阶段 IK。理论上看起来比较清楚,但真正接入自己的机器人时,重点并不是"能不能跑通脚本",而是:如何配置出一套稳定、可复用、质量还不错的 smplx_to_robot 映射表。

本文主要记录一次将自定义机器人接入 GMR 的实践流程和调试经验,不深扒代码细节,重点放在工程配置和一些实际踩坑点上。

理论篇参考上一篇文章:传送门

GMR 项目主页:https://jaraujo98.github.io/retargeting_matters/

代码仓库:https://github.com/YanjieZe/GMR


一、第一次接入自定义机器人的基本流程

第一次给自己的机器人做重定向,大致流程如下:

text 复制代码
1. 放入自己的机器人 URDF
2. 补齐需要参考的连杆点,例如手、头、脚趾等
3. 将 URDF 转为 XML / MJCF 格式
4. 创建对应机器人的 ik_configs 配置文件
5. 在脚本加载项中注册机器人名称和模型路径
6. 根据机器人结构修改 ik_configs,配置映射部位和比例
7. 在两张 IK match 表中配置映射关系、权重、位置偏移和旋转偏移
8. 选择几段代表性动作进行重定向
9. 观察动作质量和匹配误差
10. 根据结果调整权重、offset 和 scale

这里最麻烦的是第一次配置。只要机器人配置稳定下来,后续换新的动作数据时,流程会简单很多,基本就是放入动作、运行重定向、检查结果。

整体上,这也和论文中的流程是一致的:

text 复制代码
1. 找到人体和机器人的对应部位
2. 调整默认姿态和方向
3. 调整缩放比例
4. 配置两阶段 IK 权重
5. 计算得到机器人动作

二、URDF 不一定够,需要补参考连杆

GMR 的匹配对象是人体骨架 body 和机器人 link。

所以有些机器人虽然模型能正常仿真,但未必有足够适合重定向的参考 link。

比较常见需要补的点包括:

text 复制代码
head
left_hand / right_hand
left_toe / right_toe
torso reference point

这些点不一定需要自由度,可以用 fixed joint 加到 URDF 里。它们的作用不是改变机器人运动能力,而是提供更明确的空间参考。

比如脚部,如果只有 ankle,没有 toe 或 foot 参考点,那么脚掌方向的约束会比较弱。对于步行、转身、跑步这类动作,脚掌方向其实非常关键。

一个G1的参考点示意图:


三、核心配置:smplx_to_robot 映射表

GMR 配置里最重要的是人体骨架到机器人 link 的映射表。以 G1 的一段配置为例:

python 复制代码
"left_knee_link": [
    "left_knee",
    0,
    10,
    [
        0.0,
        0.0,
        0.0
    ],
    [
        0.5,
        -0.5,
        -0.5,
        -0.5
    ]
],

这一项从上到下分别是:

text 复制代码
机器人连杆
人体骨架部位
位置权重
旋转权重
xyz 位置偏移
wxyz 四元数旋转偏移

也就是:

字段 含义
left_knee_link 机器人参与 IK 匹配的 link
left_knee 人体骨架中对应的 body
0 位置跟踪权重
10 旋转跟踪权重
[0.0, 0.0, 0.0] 位置偏移
[0.5, -0.5, -0.5, -0.5] 旋转偏移,格式为 wxyz

这个表基本决定了机器人最终会"相信"人体骨架中的哪些点,以及相信到什么程度。


四、权重为 0,就是不跟踪

在 IK match 表中,权重非常直接。

如果某个部位的位置权重和旋转权重都设为 0,那么这个部位实际上就不会参与跟踪。比如把左手肘和左手腕权重都设为 0,可以看到机器人左臂基本保持 URDF 默认姿态,不会主动追踪人体动作。

左手肘和左手腕权重设为 0 后的重定向效果:

这点在调试时很有用。

不是所有人体关节都应该强行对齐,尤其是机器人没有对应自由度,或者 link 定义和人体差异较大时,高权重反而容易制造问题。

一个典型例子是 G1 的 torso_link - spine3。即便两者空间位置相差比较大,只要位置权重设为 0,就不会对重定向结果产生强约束。

所以配置映射表时,不要只看有没有对应关系,更要看权重是否合理。


五、人体关节很多,但不需要全都对齐

可用的人体关节很多,例如:

python 复制代码
body_joint_names = [
    "Pelvis", "Left_Hip", "Right_Hip",
    "Spine1", "Left_Knee", "Right_Knee",
    "Spine2", "Left_Ankle", "Right_Ankle",
    "Spine3", "Left_Foot", "Right_Foot",
    "Neck", "Left_Collar", "Right_Collar",
    "Head", "Left_Shoulder", "Right_Shoulder",
    "Left_Elbow", "Right_Elbow",
    "Left_Wrist", "Right_Wrist",
    "Left_Hand", "Right_Hand"
]

但实际配置时,不建议一股脑全部高权重对齐。约束太多容易过拟合,表现出来可能是:

text 复制代码
动作抖动
局部关节异常扭动
腿部或手臂姿态不自然
为了满足某个点导致整体姿态变形

我的理解是,映射选择应该优先考虑三个问题:

text 复制代码
1. 机器人是否真的有这个部位?
2. 这个部位对动作质量是否关键?
3. 机器人是否有能力合理实现这个约束?

比如机器人没有头部自由度,却高权重跟踪 Head 的方向,可能会导致机器人通过扭腰或扭 torso 去代偿头部旋转,结果反而很怪。

脚部则相反,通常值得重点关注。因为脚部不仅影响动作像不像,还直接影响接触、落地和稳定性。

例如,实践中,使用 foot 作为脚部主要参考点,效果通常比只用 ankle 更好一些。

原因大概是:ankle 更像一个点,而 foot 更能表达脚掌方向。虽然 ankle 到 foot 之间可能没有额外自由度,但 foot 的方向信息对步态很有帮助,尤其是转身、跑步、落脚这类动作。

也可以 foot 和 ankle 都用,但权重不要太激进。脚部约束过强时,腿部姿态也可能变僵。

只使用 ankle、只使用 foot的效果对比


六、四元数偏移:本质是坐标系对齐

四元数 offset 是调试中最容易困惑的部分。

比如常见的:

python 复制代码
[0.5, -0.5, -0.5, -0.5]

它并不是经验玄学,而是在做坐标系对齐。

GMR 中四元数格式是 wxyz,这一点要特别注意。

原始动作骨架的默认状态中,关节四元数基本都是:

python 复制代码
[1, 0, 0, 0]

但这只说明它在骨架自己的坐标系下没有旋转,并不代表它和机器人 link 的局部坐标系一致。

观察原始骨架可以看到,它可能是面朝上躺平的大字形态,且轴系大致表现为:

text 复制代码
z 轴朝身体前方
y 轴垂直身体
x 轴朝身体侧方


[1, 0, 0, 0]应用 [0.5, -0.5, -0.5, -0.5] 后,可以看到原本朝前的 z 轴被旋到 x 轴方向,原本朝左的 x 轴被旋到 y 轴方向,这样更接近常见机器人模型的 link 坐标定义。

这里最重要的原则是:

四元数 offset 不是为了让某一帧动作看起来顺眼,而是为了在默认姿态下对齐机器人 link 的局部坐标系。

虽然 [0.5, -0.5, -0.5, -0.5] 在很多位置上有效,但不是所有 link 都适用。

比如 G1 的 hip 部位使用的是 right_hip_roll_link,它的局部轴系并不和 torso 保持一致,所以需要单独配置:

python 复制代码
"right_hip_roll_link": [
    "right_hip",
    0,
    10,
    [
        0.0,
        0.0,
        0.0
    ],
    [
        0.4267755048530407,
        -0.5637931078484661,
        -0.5637931078484661,
        -0.4267755048530407
    ]
],

hip 使用特殊offset 后的效果:

可以发现,这套偏移是更符合机器人的坐标系设定的,这说明 offset 要看机器人 link 自己的坐标系,而不是无脑都套用同一套偏移。

手臂也类似。人体骨架通常是大字型姿态,而机器人默认一般是垂手姿态,G1 的手肘还带有一定弯曲。因此肩部配置会使用类似:

python 复制代码
"left_shoulder_yaw_link": [
    "left_shoulder",
    0,
    10,
    [
        0.0,
        0.0,
        0.0
    ],
    [
        0.70710678,
        0.0,
        -0.70710678,
        0.0
    ]
],

在这个配置下,如果把机器人 shoulder roll 调到 90°,让手臂打直,会发现这个偏移量和机器人坐标系是匹配的,包括后续的小臂和手部也同理。

不过这里还有一个我暂时没有完全确认的问题:目前这种"手动旋转机器人后再观察匹配"的方式,更像是一个工程辅助验证方法,而不一定是严格的代码设计逻辑。仓库中并没有明确说明需要先旋转机器人再匹配,因此这里还需要继续研究坐标变换的真实顺序。


七、xyz offset 和 scale:直观,但最费时间

相比四元数,xyz offset 和 scale 更直观,但更依赖具体机器人和动作数据。

影响因素包括:

text 复制代码
人体骨架身高和比例
机器人腿长、臂长、躯干比例
机器人 link 原点定义
foot / ankle / toe 的选择
不同动作库的骨架差异
root 缩放比例

目前比较有效的方法还是构建可视化脚本,反复观察:

text 复制代码
原始人体骨架
偏移后的目标骨架
机器人 FK 后的实际 link
关键点位置误差
关键点旋转误差

对于一些怎么都对不齐的点,不建议死磕。可以降低位置权重,保留旋转约束,或者干脆弱化这个部位。

本质上,GMR 不是要让每个点都完美贴合,而是要让关键部位合理贴合。

原始动作骨架、未偏移结果、偏移后结果(但骨架保留原始效果以便表达区别)三图对比:


八、两阶段 IK:表一粗对齐,表二细对齐

GMR 中通常会有两张 IK match 表,对应两阶段 IK。

第一阶段主要是粗对齐。重点是:

text 复制代码
root / pelvis 方向位置合理
torso 方向合理
双足位置合理
主要 end-effector 大致到位
其他关节旋转方向不要太离谱

第一阶段的目标不是精修动作,而是得到一个比较稳定的初始姿态。

如果第一阶段已经跑偏,第二阶段很容易在错误姿态附近继续优化。

第二阶段是细对齐。一般会加入更多 key body,并适当提高部分旋转或位置约束,让动作更贴近源动作。

可以简单理解为:

text 复制代码
表一:先把机器人摆对
表二:再把动作修细

所以两张表不要配置成完全一样。

表一应该抓重点,表二可以更细,但也不能过度激进。否则动作细节可能更像了,但抖动、自碰撞和关节突变也更容易出现。


九、个人调试经验

整理一些目前比较有用的经验:

1. foot 通常比 ankle 更适合作为脚部主约束

foot 对脚掌方向更敏感,步行和转身效果会更好。ankle 可以辅助,但单独用 ankle 时脚掌方向约束偏弱。

2. 没有自由度的部位,权重要低

比如没有头部自由度,就不要高权重跟踪 Head 的方向。否则机器人可能通过 torso 或腰部去代偿,动作会变得很奇怪。

3. 不同动作库可能需要不同 scale 或 offset

不同动作库的骨架定义、身高比例、坐标系和帧率都可能不同。不要默认一套参数可以适配所有来源的数据。

4. 不要只用一个动作验证配置

一个动作调得很好,不代表配置稳定。建议在同一个动作库/作者下,至少准备几类动作:

text 复制代码
普通步行
转身
跑步
上肢动作
大幅度动态动作

多动作都能接受,配置才比较可信。


十、几个待研究问题

目前还有一些问题没有完全搞清楚,后续值得继续看。

1. 权重和 scale 的影响能否量化?

现在调参主要依赖观察和枚举,成本比较高。后面可以考虑引入一些自动指标:

text 复制代码
key body position error
rotation error
foot sliding
ground penetration
self-intersection
joint velocity spike

如果这些指标能自动统计,调参效率会高很多。

2. 其他动作格式效果如何?

目前主要关注现有仓库主力支持的smplx格式数据。对于遥操数据、视频恢复动作、其他 mocap 格式,还需要单独测试。

3. 动作频率对训练效果有什么影响?

GMR 脚本里写死了 30 fps,而宇树官方动作数据可能是 50 Hz,bymimic仓库里则是区分了高频低频的训练环境。这里需要继续确认:

text 复制代码
retarget 后是否需要插值?
频率变化如何影响 tracking 效果?

这个问题对后续训练很关键。

4. 是否需要为每个动作库单独配置 scale?

不同动作库录制者体型、骨架标准可能不同。理论上可能需要不同 scale,但也可能动作数据内部已经做了统一标准化。这个需要更多动作源验证。

5. table2 里的 rot_offset 是否真的生效?

代码分析时发现,第二阶段表里的 rot_offset 似乎没有被实际套用。这里还不能确定是论文设计如此,还是代码实现遗漏。

十一、SMPL-X 到机器人动作重定向工程流程

最后,我们再快速过一下重定向过程中都干了什么。

输入数据

输入是一个 SMPL-X 动作 .npz 文件,通常来自 AMASS/OMOMO 等数据集。脚本主要使用其中的:

  • pose_body: 每帧身体关节轴角姿态,形状通常为 (N, 63)
  • root_orient: 每帧根节点全局朝向,形状为 (N, 3)
  • trans: 每帧根节点全局平移,形状为 (N, 3)
  • betas: 人体形状参数。
  • gender: SMPL-X body model 性别选择。
  • mocap_frame_rate: 原始动作帧率。

这些参数本身还不是"骨架点位序列",而是 SMPL-X 参数化人体模型的输入。

SMPL-X 前向计算

load_smplx_file() 会根据输入文件中的 genderbetas 创建 SMPL-X body model,并把 root_orientpose_bodytrans 输入模型,得到每一帧的人体关节位置和完整姿态。

之后 get_smplx_data_offline_fast() 将 SMPL-X 输出整理成重定向系统使用的格式:

python 复制代码
{
    "pelvis": (position, quaternion),
    "left_hip": (position, quaternion),
    "left_knee": (position, quaternion),
    ...
}

其中四元数格式为 [w, x, y, z]。这个阶段也会根据目标帧率进行时间对齐或重采样,并返回实际使用的 aligned_fps

逐帧重定向

脚本逐帧取出 SMPL-X 处理后的人体数据:

python 复制代码
smplx_data = smplx_data_frames[i]
qpos = retarget.retarget(smplx_data)

retarget() 内部主要做几件事:

  1. 将人体骨架按目标机器人尺度进行缩放。
  2. 对人体匹配点应用位置偏移和旋转偏移。
  3. 将处理后的人体点位和朝向设置为 IK 任务目标。
  4. 使用 mink.solve_ik() 求解机器人当前帧的 qpos

返回的 qpos 是 MuJoCo 机器人状态,通常包含:

  • qpos[:3]: 机器人根节点位置。
  • qpos[3:7]: 机器人根节点四元数,格式为 [w, x, y, z]
  • qpos[7:]: 机器人各关节角度。

输出数据

最后脚本会把所有帧的机器人动作保存为 .pkl。输出结构如下:

python 复制代码
{
    "fps": aligned_fps,
    "root_pos": root_pos,
    "root_rot": root_rot,
    "dof_pos": dof_pos,
    "local_body_pos": None,
    "link_body_list": None,
}

其中:

  • root_pos: (T, 3),机器人根节点位置。
  • root_rot: (T, 4),机器人根节点四元数。保存时会从 MuJoCo 的 [w, x, y, z] 转为 [x, y, z, w]
  • dof_pos: (T, robot_dof),机器人关节位置序列。
  • fps: 动作播放帧率。

这里的 dof_pos 是关节角,单位为 rad。以 G1 29DoF 为例,dof_pos 的形状是 (T, 29),每一帧包含 29 个关节角,列顺序由机器人 XML 中的 joint 顺序决定。

这个 .pkl 就是后续播放、训练或进一步转换的机器人动作数据。

技术要点

  • SMPL-X 负责从参数化人体动作恢复人体关节位置和朝向。
  • MuJoCo 提供目标机器人运动学模型。
  • mink 将人体目标点和机器人 link 之间的匹配关系转化为 IK 优化问题。
  • IK 配置负责定义人体部位到机器人 link 的映射、权重、缩放和坐标系校准。
  • 输出结果不是力控或轨迹控制命令,而是逐帧机器人运动学状态。

整体流程可以概括为:

text 复制代码
SMPL-X .npz
  -> SMPL-X body model 前向计算
  -> 人体关节位置/姿态序列
  -> 缩放与坐标系校准
  -> 机器人 IK 求解
  -> 机器人 root + joint motion
  -> .pkl 动作文件

总结

把自己的机器人接入 GMR,核心工作不是跑脚本,而是配置好 smplx_to_robot 映射表。

这张表里最重要的是:

text 复制代码
映射哪个机器人 link
参考哪个人体 body
位置权重是多少
旋转权重是多少
xyz offset 如何设置
quaternion offset 如何设置

其中,映射关系决定机器人"看哪里",权重决定机器人"有多在意",offset 和 scale 决定人体动作目标是否真的适合当前机器人。

我的整体感受是,GMR 的工程配置本质上是在做一次折中:

既不能让机器人完全无视人体动作,也不能让它死追所有人体关节。比较好的结果通常来自合理取舍:关键部位强约束,非关键部位弱约束;可实现的部位认真跟踪,不可实现的部位适当放过。

当这套配置稳定之后,GMR 就会变成一个比较实用的动作数据生产工具。对于后续 motion tracking、模仿学习或者遥操作数据处理来说,前面这一步调得越稳,后面的训练就越省心。

相关推荐
深蓝学院4 小时前
Science Robotics重磅 | 如何用运动学智能,实现跨机器人技能复用?
机器人·具身智能
xiaoduo AI4 小时前
智能客服机器人能精准预判用户疑问提前主动应答吗?能大幅缩短客户咨询沟通时长吗?
运维·服务器·机器人
guygg884 小时前
四足液压机器人设计程序MATLAB实现
开发语言·matlab·机器人
xiaoduo AI4 小时前
智能客服机器人能实时监控会话风险规避服务纠纷吗?能规范服务话术守住门店口碑吗?
大数据·人工智能·机器人
AGV算法笔记5 小时前
【具身智能研究进展】RoboBrain 2.5:让机器人真正理解“空间”和“时间”的大脑模型
算法·3d·机器人·具身智能·感知算法
kali_yao5 小时前
openclaw/workbuddy机器人绑定通道后只能默认自己使用问题解决
人工智能·机器人
鲁邦通物联网5 小时前
架构实战:高安全非侵入式采集的分布式机器人梯控系统设计
机器人·机器人梯控·agv梯控·非侵入式采集·机器人乘梯·机器人自主乘梯·agv机器人梯控
kobesdu6 小时前
【ROS2实战笔记-14】多机器人系统的三层工具箱:从零基础集群到跨仿真实现
笔记·机器人·ros
若尘7977 小时前
数学idea的重构
算法·职场和发展·机器人