机器人ONNX学习
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关节参考。
所以它能跟踪行走动作,但用途不限于行走。模型文件名中的boxing、cmd_combine也进一步支持其全身动作跟踪用途。
它的实际功能
GMR给出理想参考姿态jp
↓
ONNX观察参考动作窗口
+
机器人真实IMU/关节状态历史
↓
预测29维动作修正量act
↓
act × scale + jp
↓
形成更适合真实机器人保持平衡并跟踪动作的目标关节位置
因此它的角色是:
全身模仿策略
+ 稳定控制策略
+ 参考动作跟踪策略
而不是单纯的数据格式转换网络。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)