为什么机器人通信不用 JSON?「固定长度二进制协议」的设计智慧

最近在读一个机器人的通信协议 SDK,一开始很不理解:为什么不用 JSON 这种"人类友好"的格式,偏要搞一堆看不懂的字节、还规定每个字段固定在第几个字节?彻底想明白后,发现这套设计简单、快、可靠,非常适合嵌入式/实时通信。写这篇文章记录一下。

一、先看这套协议长什么样

一个机器人系统有三个"端"要互相通信:上位机(C++)、主控板(ROS)、单片机(C)。它们之间传的数据帧格式是固定的:

AA 55 | ver | len | type | payload | crc16

其中"控制指令"这一帧,payload 里有十几个字段,每个字段固定在某个字节位置:

偏移字段类型说明
0modeuint8运行模式
1enableduint8使能标志
2reserveduint8×2保留
4vxfloat32前后速度
8vyfloat32左右速度
12vzfloat32上下速度

注意"偏移"这一列:vx 固定在第 4 字节,vy 固定在第 8 字节,永远不变。

二、核心概念一:固定偏移(字段位置写死)

payload 就是几十个字节排成的一排,从 0 开始编号。偏移 = “这个字段从第几个字节开始”。

字节编号: 0      1      2    3    4      5      6      7      8
内容:     mode   en    res  res  vx     vx     vx     vx     vy
          ↑      ↑     ↑    ↑    ↑
         偏移0   偏移1  偏移2      偏移4(vx 从这里开始,占 4 字节)

为什么 vx 在偏移 4?因为前面 mode(1字节) + enabled(1字节) + reserved(2字节) = 4 字节,占掉了 0~3,vx 就从第 4 字节开始。

三、核心概念二:全量发送(每次都发完整状态)

这套协议是全量发送:不管字段变没变,每次都把整帧发出去。

比如你只想让机器人前进(改 vx),但 mode、enabled、vy、vz……所有字段都会一起发,没变的就发它当前的值。

对比"增量发送"(只发变化的部分):

全量发送增量发送
接收方要做啥直接读全部字段先记住上次状态,再打补丁
解析难度最简单复杂
丢一帧会怎样下一帧还是完整状态,没事状态错乱(丢了增量)

实时控制场景特别需要全量发送——通信容易受干扰丢包,全量发送丢一帧也无所谓,下一帧又是完整状态。

四、最妙的一点:接收方不需要知道"哪里变了"

一开始我最困惑的是:“每次发全量,解析时不知道哪个字段变了,岂不是很费劲?”

后来想明白:根本不需要知道哪里变了。

接收方拿到一帧,解码后直接就是完整的最新状态:

auto tele = link.recv_frame_as<TelemetryPacket>(...);
tele.position;  // 现在的位置
tele.angle;     // 现在的角度
tele.voltage;   // 现在的电压

你只需要知道"现在 position 是多少",直接显示就行,不用关心它从多少变到了多少。

打个比方:全量发送 = 每次发一张完整的仪表盘截图,你看截图就知道所有指针位置;增量发送 = 只告诉你"哪个指针动了",你还得记住上一张截图才能拼出当前状态。

如果确实要"检测变化"(比如某个状态从 0 变 1 时报警),那是上层应用自己的逻辑,自己比较新旧值就行,协议不负责:

if (tele.alarm == 1 && last_tele.alarm == 0) {
    // 触发报警
}
last_tele = tele;

五、为什么不用 JSON?

同样一条控制指令,用 JSON 长这样:

{"mode":0,"enabled":1,"vx":0.5,"vy":0,"vz":0}

对比固定二进制布局:

JSON(文本协议)固定二进制协议
字节数多(一堆字段名 + 标点)少(全是值,几十字节)
解析慢(逐字符扫、找 key、切字符串)快(按偏移直接读)
字段顺序可能乱,要处理各种情况固定,不可能乱
嵌入式友好差(解析开销大)好(直接 memcpy 到 struct)

数据量其实很小:就算 10Hz 发送,也才约 1~2 KB/秒,而网线带宽是 MB 级,随便发。

六、为什么这套设计适合嵌入式/实时场景

  1. 快:位置固定,接收方直接按偏移读,比解析 JSON 快几个数量级。
  2. 省:不传字段名和标点,字节最少。
  3. 可靠:帧长固定、位置固定,多个端不可能不一致(都用同一张偏移表)。
  4. 嵌入式友好:单片机资源少,收到字节直接 memcpy 到结构体就还原成字段了。
  5. 确定性强:帧长固定,接收方精确知道一帧多长,好做校验。

七、总结

这套协议的设计哲学就一句话:

固定位置 + 全量发送 = 最简单、最快、最可靠。

它牺牲了"只发变化部分"这种省字节的技巧,换来了:

  • 解析不需要任何查找/判断,按位置读就行
  • 接收方不需要关心"哪里变了",直接拿完整状态
  • 多个端(C++/C/ROS)用同一张偏移表,字节级一致

规律:越是底层、越实时、越资源受限的地方,越爱用"固定长度二进制协议";越是 Web、越要给人看的地方,越爱用 JSON 这种"自描述文本协议"。两种没有好坏,只有合不合适。

如果你也在做多端通信、嵌入式、实时控制这类需求,强烈建议理解并尝试这套"固定偏移 + 全量发送"的思路——它简单得优雅。

Logo

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

更多推荐