2. MAVLink消息结构:消息帧格式详解、CRC校验机制、消息ID与组件ID、系统ID的概念
好,咱们今天来啃一块硬骨头——MAVLink的消息结构。说实话,我刚开始接触MAVLink的时候,看着那一串十六进制数据也是一头雾水。但后来我发现,只要你搞懂了它的帧格式,整个通信协议就像一张摊开的地图,清晰得很。
MAVLink的消息结构,说白了就是一套“信封”规则。你要寄一封信,总得有个信封吧?信封上写清楚从哪来、到哪去、内容是什么、怎么检查有没有被篡改。MAVLink的帧格式干的就是这个活儿。
2.1 消息帧格式详解
MAVLink有两个版本:v1.0和v2.0。现在主流都用v2.0,但很多老设备还在跑v1.0。我个人建议,新项目直接上v2.0,兼容性更好,扩展性也强。
咱们先看v2.0的帧格式,它长这样:
| STX | LEN | INC | CMP | SEQ | SYS | COMP | MSGID | PAYLOAD | CKA | CKB |
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 3 | 0-255 | 1 | 1 |
每个字段都是字节,我来一个个拆开讲:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| STX | 1 | 起始标志,v2.0固定为0xFD,v1.0是0xFE |
| LEN | 1 | Payload长度,0-255字节 |
| INC | 1 | 需要参与CRC校验的“不兼容标志”字节数 |
| CMP | 1 | 需要参与CRC校验的“兼容标志”字节数 |
| SEQ | 1 | 消息序列号,用于检测丢包 |
| SYS | 1 | 系统ID,标识发送方 |
| COMP | 1 | 组件ID,标识发送方内部的子模块 |
| MSGID | 3 | 消息ID,v2.0扩展到24位 |
| PAYLOAD | 0-255 | 实际数据内容 |
| CKA/CKB | 2 | CRC校验码,16位 |
嗯,这里要注意一个细节:INC和CMP字段。这两个是v2.0新增的,用来做协议扩展。INC字段里的位如果被置1,接收方如果不认识这个位,就必须丢弃整条消息。CMP字段里的位如果被置1,接收方如果不认识,可以忽略这个位,继续处理。说白了,INC是“你必须懂我”,CMP是“你不懂也没关系”。
2.2 CRC校验机制
CRC校验,全称是循环冗余校验。你不需要背它的数学公式,但得理解它的作用——保证消息在传输过程中没有被篡改或损坏。
MAVLink用的CRC算法是CRC-16-IBM,多项式是0x1021。计算范围包括:LEN、INC、CMP、SEQ、SYS、COMP、MSGID、PAYLOAD,以及一个额外的“密钥字节”——这个密钥字节是根据消息ID查表得到的。
为什么要加这个密钥字节?
我曾经在一个项目中遇到过这样的问题:地面站收到了一个看起来合法的消息,CRC校验也通过了,但解析出来的数据完全是乱的。后来排查发现,是消息ID被干扰了,变成了另一个消息ID,但恰好那个消息ID的CRC密钥和原始消息一样,导致校验通过。加了密钥字节后,这种概率就大大降低了。
CRC校验的流程大致如下:
- 初始化CRC寄存器为0xFFFF
- 依次处理LEN、INC、CMP、SEQ、SYS、COMP、MSGID每个字节
- 处理PAYLOAD的所有字节
- 处理消息ID对应的CRC密钥字节(查表获取)
- 得到最终的16位CRC值,填入CKA和CKB
2.3 消息ID与组件ID
这两个ID容易搞混,我分开讲。
消息ID(MSGID):标识这条消息里装的是什么数据。比如,消息ID=0表示心跳包,消息ID=30表示姿态数据。v2.0用了3个字节,所以最多支持16,777,216种消息类型。v1.0只有1个字节,最多256种,所以v2.0的扩展性更好。
组件ID(COMPID):标识同一个系统内部的不同组件。比如,飞控是1号组件,摄像头是2号组件,机械臂是3号组件。这样,地面站就能区分出“这条消息是飞控发的还是摄像头发的”。
我举个例子你就明白了:
系统ID=1, 组件ID=1 → 无人机A的飞控
系统ID=1, 组件ID=2 → 无人机A的摄像头
系统ID=2, 组件ID=1 → 无人机B的飞控
你看,通过系统ID+组件ID的组合,就能唯一确定一个消息来源。
2.4 系统ID的概念
系统ID(SYSID)是整个MAVLink网络中每个节点的唯一标识。一个系统可以是一架无人机、一个地面站、一个机械臂控制器,甚至是一个传感器节点。
系统ID的范围是1-255。0是保留值,255是广播地址。我建议你给每个设备分配一个固定的系统ID,不要动态变化,否则地面站会搞混。
在实际项目中,我一般这样分配:
- 地面站:系统ID=255(广播)
- 无人机1:系统ID=1
- 无人机2:系统ID=2
- 无人机3:系统ID=3
- ……以此类推
为什么地面站用255?因为地面站需要跟所有无人机通信,用广播地址最方便。无人机之间一般不需要直接通信,所以各自用独立ID。
2.5 消息结构总览图
下面这张图把整个消息帧的结构和校验流程串起来了,你一看就明白:
这张图把整个消息帧的骨架画出来了。你从上往下看:先看到完整的帧格式,然后CRC校验范围覆盖了哪些字段,最后是三维坐标的映射关系。接收端拿到一条消息后,就是按照底部那个流程一步步处理的。
好了,这一章的内容就到这儿。消息帧格式是MAVLink的基石,后面的所有内容都建立在这个基础上。你把这个搞透了,后面学飞行模式切换、参数配置什么的,就会轻松很多。