Day7 unitree_G1人形机器人“身外化身”通信优化思路

一、最开始我们面对的是什么

原始目标是让穿动捕服的人控制G1机器人,或者先控制MuJoCo里的G1模型。

原始设想的数据链路是:

动捕服
  ↓
Axis Studio / Noitom
  ↓
人体骨骼数据
  ↓
GMR IK重定向
  ↓
G1 29自由度动作
  ↓
gRPC
  ↓
机器人控制器
  ↓
ONNX
  ↓
LowCmd
  ↓
电机

原系统希望把人体动作转换成G1能够执行的29自由度关节动作,然后通过网络发送出去。

最初认为主要问题是gRPC:

  • gRPC运行在HTTP/2和TCP之上。
  • 接口模型偏RPC,不完全适合连续动作流。
  • 线程、Stream和缓存机制比较复杂。
  • 网络或接收端变慢时,可能积压旧动作。
  • 机器人可能正在执行已经过时的动作。

因此,最初目标是:

保留动作数据结构、GMR、ONNX和控制算法,只替换通信层。


二、最初为什么选择ZeroMQ

人体动作不是典型的“请求—响应”数据。它不是:

电脑问机器人一个问题
机器人返回一个答案

而是:

电脑不断产生动作帧
机器人不断接收动作帧

所以ZeroMQ比gRPC更适合做轻量动作流通信。

当时最初设计为:

protobuf MocapFrame
        ↓
ZeroMQ PUB
        ↓
ZeroMQ SUB
        ↓
机器人

最开始的需求偏向低延迟,因此提出:

  • HWM=1
  • ZMQ_CONFLATE
  • 只保留最新动作
  • 丢弃旧的 frame_id
  • 网络慢时不排队

这个方案的原则是:

机器人最关心当前动作,不关心已经过去的历史动作。

如果收到:

Frame 100
Frame 101
Frame 102
Frame 103

但机器人只能及时处理一帧,就直接使用:

Frame 103

这适合“低延迟、最新状态优先”的控制系统。


三、为什么后来不能继续使用PUB/SUB和CONFLATE

后来需求发生了根本变化:

可以慢,可以等待,但电脑发出的每一帧必须全部收到,不能主动丢弃。

这个需求和“最新帧优先”是冲突的。

ZMQ_CONFLATE的作用就是主动覆盖旧帧:

Frame 1
Frame 2
Frame 3
Frame 4

最终队列可能只剩:

Frame 4

这显然不满足“所有帧都要拿到”。

所以我们重新确定了优先级:

第一优先级:完整性
第二优先级:顺序
第三优先级:实时性

也就是说:

如果程序处理不过来,就让帧排队、让延迟增加,但不能为了降低延迟而扔掉数据。

因此通信架构从最初的:

PUB/SUB
HWM=1
CONFLATE
最新帧覆盖旧帧

调整成了现在的:

PUSH/PULL
阻塞发送
FIFO顺序队列
不主动丢弃

这不是简单改了一个参数,而是系统目标发生变化后,重新选择了正确的通信模型。


四、为什么保留protobuf

我们没有修改原来的 MocapFrame

原因很简单:

MocapFrame是动作数据内容,而gRPC、ZeroMQ只是运输工具。

可以把它理解成:

MocapFrame = 箱子里的货物
gRPC/ZMQ   = 运货的卡车

我们只换卡车,不动货物。

这样有几个好处:

  • 不需要重写GMR输出数据。
  • 不需要重写机器人接收后的解析逻辑。
  • 保持C++和其他语言之间兼容。
  • 以后改DDS、共享内存或者其他通信方式时,仍可以继续使用。
  • 避免动作数据结构和通信改造同时变化,降低风险。

现在的逻辑是:

GMR输出
  ↓
生成MocapFrame protobuf
  ↓
protobuf序列化成二进制
  ↓
加传输Header
  ↓
ZMQ发送

接收端反过来:

ZMQ收到数据
  ↓
检查Header
  ↓
检查CRC
  ↓
解析protobuf
  ↓
得到原来的MocapFrame

五、为什么增加MotionFrameHeader

protobuf里有动作内容,但通信层仍需要自己的管理信息。

因此增加了传输Header,包含:

magic
version
message_type
frame_id
capture_timestamp
send_timestamp
payload_size
joint_count
crc32

每个字段都有明确作用。

1. magic

用于判断收到的数据是不是我们的动作协议,如果magic不正确,说明可能是:

  • 连接到了错误端口。
  • 收到了错误数据。
  • 数据内容损坏。
  • 发送端和接收端协议不一致。

这种数据不能送进机器人。

2. version

标识协议版本。

以后增加字段或者改变格式时,可以判断新旧程序是否兼容。

3. message_type

区分消息类型,例如:

动作帧
机器人状态
心跳

现在主要使用动作帧,但协议保留扩展能力。

4. frame_id

给电脑实际发送的每个动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值