ONNX 本质上是一个已经训练好的神经网络模型文件,它主要负责机器人控制策略推理,ONNX 在这里通常是一个模型文件,不是主程序。

  • 文件扩展名:.onnx
  • 内容:训练完成的神经网络参数和计算结构
  • 性质:数据/模型文件,本身不能直接运行
  • 运行者:C++ 主程序通过 ONNX Runtime 加载并执行它

可以这样理解:

Controller_onnx.cpp / xsens_core.exe = 主程序和执行框架
*.onnx                            = 神经网络“大脑”
ONNX Runtime                      = 让程序运行这个“大脑”的引擎

运行过程一般是:

主程序启动
→ 加载 .onnx 文件
→ 整理机器人状态和目标动作
→ 输入 ONNX 模型
→ 模型计算
→ 输出关节目标
→ 主程序发送控制命令

所以它类似于“游戏程序读取存档/资源文件”:ONNX 文件保存训练成果,但负责通信、循环控制、动捕接收和机器人命令发送的仍然是 .exe 主程序。

补充区别:

  • ONNX:一种通用神经网络模型格式,全称 Open Neural Network Exchange。
  • .onnx:具体模型文件。
  • ONNX Runtime:加载和计算模型的运行库。
  • Controller_onnx.cpp:调用模型的 C++ 源代码。
  • .exe:编译出来的可执行主程序。

整体关系大致是:

Noitom 动捕
→ Axis 的 BVH/TCP 数据
→ 人体骨架姿态
→ GMR 动作重定向
→ G1 关节参考动作
→ ONNX 控制策略
→ 机器人最终关节指令

ONNX 通常会接收:

  • G1 当前关节位置、速度
  • IMU 姿态和角速度
  • 上一帧控制指令
  • GMR 给出的目标动作或运动命令

然后输出:

  • 各关节的目标位置或动作量
  • 后续由控制器换算为电机控制指令

所以它:

  • 不负责接收 Axis/BVH 数据;
  • 不决定 InputFps
  • 不负责人体骨架解析;
  • 主要负责“让 G1 稳定、自然地执行目标动作”。

可以把 GMR 理解为“人体动作翻译器”,把 ONNX 理解为“机器人学会如何执行这些动作的大脑”。

我已经直接解析了工程中现存的3个ONNX,并结合实际机器人控制器代码核对。结论是:它们都是同一接口、不同权重检查点的G1全身动作跟踪/模仿策略,不是GMR重定向网络,也不是单纯速度指令行走策略。


输入1766维的具体组成

完整计算关系:

1766
= 21 × 38
+ 38
+ 10 × 93

= 798 + 38 + 930

第一部分:动作参考窗口,798维

控制器使用:

FURTHER_STEP_NUM  = 10
FURTHER_STEP_SIZE = 1

从动作FIFO中取:

过去10帧 + 当前1帧 + 未来10帧
= 21帧

每个参考帧38维:

内容 维度
参考根部线速度,机器人局部坐标系 3
参考根部角速度,机器人局部坐标系 3
参考重力方向 3
参考G1关节位置 29
合计 38

因此:

21 × 38 = 798

对应代码:

result.segment(..., 3) = base_lin;
result.segment(..., 3) = base_ang;
result.segment(..., 3) = gravity;
result.segment(..., 29) = jp;

第二部分:当前参考命令,38维

21帧参考窗口后,又拼接了一份当前参考状态:

内容 维度
当前参考根部线速度 3
当前参考根部角速度 3
当前参考重力方向 3
当前参考关节位置 jp 29
合计 38

对应代码:

command_actor
    << future_posvel,
       base_lin,
       base_ang,
       motion_gravity,
       jp;

所以命令部分为:

798 + 38 = 836维

第三部分:机器人历史观测,930维

历史长度:

HISTORY_LEN = 10;
SINGLE_OBS_DIM = 93;

每帧机器人观测:

内容 维度
机器人IMU重力方向 3
机器人IMU角速度 3
机器人29关节位置相对默认姿态 29
机器人29关节速度 29
上一次网络动作 29
合计 93

历史部分:

10 × 93 = 930维

最终:

动作参考命令 836
+ 机器人历史状态 930
= 1766

4. 是否包含历史帧

包含,而且有两种不同意义的时间序列。

机器人本体历史:10帧

输入中包含连续10个控制周期的机器人状态:

gravity
ang_vel
qpos
qvel
last_action

控制周期20ms,因此历史覆盖约:

10 × 20ms = 200ms

更准确地说,更新后队列通常包含:

当前机器人观测 + 之前9帧

程序刚启动时,历史队列会使用全零初始化,所以最开始几个周期并不是全部真实历史。

动作参考窗口:21帧

还包含:

过去10帧 + 当前帧 + 未来10帧

在50Hz下对应:

过去约200ms
当前
未来约200ms

因此这个策略并非只根据当前动捕帧反应,它利用未来动作参考进行前馈控制。

缓冲区长度说明

真正构建ONNX输入时,需要21帧:

buff_len_ = 1 + 2 * 1 * 10 = 21

gRPC模式进入跟踪状态前,代码另外要求:

0.5 / 0.02 + 1 = 26帧

所以:

  • 进入跟踪前的门槛约26帧;
  • 每次网络输入实际使用前21帧;
  • 每个控制周期从FIFO弹出1帧;
  • 窗口随后向前滑动1帧。

这正是你之前提到“约26帧buffer、一帧一帧向前推”的来源。


5. 控制频率

配置和控制循环都是:

control_dt: 0.02
const std::chrono::milliseconds cycle_time(20);

所以ONNX推理与目标关节更新频率是:

1 / 0.02 = 50Hz

需要区分两个频率:

环节 频率
读取动作窗口、构造1766维输入 50Hz
ONNX推理 50Hz
产生新的29维目标关节位置 50Hz
low_cmd_write DDS重复下发线程 500Hz

DDS发送线程创建参数是:

CreateRecurrentThreadEx(..., 2000, ...)

周期2000微秒,即500Hz。

但它不是500Hz运行ONNX,而是将最近一次50Hz生成的控制指令重复发送给机器人。


6. 输出29维的含义

模型输出:

output float32[1,29]

读取方式:

act = onnxPtr->outVec[0];

它不是直接输出力矩,也不是直接输出电机绝对位置。最终目标位置为:

target_pos[i]
    = act[i] * action_scales[i]
    + jp[i];

其中:

  • act[i]:网络输出;
  • action_scales[i]:每个关节的动作缩放;
  • jp[i]:GMR/动捕传入的当前参考关节位置。

所以网络输出本质上是:

相对于参考动作jp的29维关节修正量

最终下发:

q  = target_pos[i];
kp = kps[i];
kd = kds[i];
dq = 0;
tau = 0;

因此这是关节位置目标策略,使用PD控制执行。


7. 输出对应的G1关节

当前控制器直接使用:

motor_cmd()[i]

没有在在线控制器里使用额外的idx_out重排。因此29维输出顺序就是G1 29自由度控制顺序:

输出索引 G1关节
0 left_hip_pitch_joint
1 left_hip_roll_joint
2 left_hip_yaw_joint
3 left_knee_joint
4 left_ankle_pitch_joint
5 left_ankle_roll_joint
6 right_hip_pitch_joint
7 right_hip_roll_joint
8 right_hip_yaw_joint
9 right_knee_joint
10 right_ankle_pitch_joint
11 right_ankle_roll_joint
12 waist_yaw_joint
13 waist_roll_joint
14 waist_pitch_joint
15 left_shoulder_pitch_joint
16 left_shoulder_roll_joint
17 left_shoulder_yaw_joint
18 left_elbow_joint
19 left_wrist_roll_joint
20 left_wrist_pitch_joint
21 left_wrist_yaw_joint
22 right_shoulder_pitch_joint
23 right_shoulder_roll_joint
24 right_shoulder_yaw_joint
25 right_elbow_joint
26 right_wrist_roll_joint
27 right_wrist_pitch_joint
28 right_wrist_yaw_joint

8. 它到底是什么网络

结论:

这是G1全身动作模仿/动作跟踪控制策略,更准确地说是“带未来参考窗口和本体历史观测的全身动作跟踪策略”。

它不是重定向网络

人体到G1动作的重定向发生在ONNX之前:

人体Mocap
→ GMR/IK
→ G1参考关节位置和速度
→ ONNX控制策略

ONNX输入已经包含29维G1关节参考jp,所以网络不负责:

人体骨架 → G1关节

这个工作由GMR完成。

它不是单纯行走策略

普通行走策略通常输入:

期望vx、vy、yaw速度
+ 机器人本体状态

而这里输入的是:

21帧完整全身参考动作
+ 当前全身参考动作
+ 10帧机器人历史状态

并且包括:

  • 双腿;
  • 腰部;
  • 双臂;
  • 双手腕;
  • 根部运动;
  • 完整29关节参考。

所以它能跟踪行走动作,但用途不限于行走。模型文件名中的boxingcmd_combine也进一步支持其全身动作跟踪用途。

它的实际功能

GMR给出理想参考姿态jp
        ↓
ONNX观察参考动作窗口
        +
机器人真实IMU/关节状态历史
        ↓
预测29维动作修正量act
        ↓
act × scale + jp
        ↓
形成更适合真实机器人保持平衡并跟踪动作的目标关节位置

因此它的角色是:

全身模仿策略
+ 稳定控制策略
+ 参考动作跟踪策略

而不是单纯的数据格式转换网络。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐