2. MAVLink协议基础:消息格式、消息类型、CRC校验机制

好,咱们正式开始啃协议。MAVLink这东西,说白了就是无人机和地面站之间的“普通话”。你想想看,飞控板上的传感器数据、GPS坐标、姿态角,总得有个统一的格式才能传给QGroundControl或者Mission Planner吧?MAVLink就是干这个的。

我个人习惯把MAVLink协议分成三个层面来理解:消息怎么打包(格式)、消息有哪些种类(类型)、消息怎么防错(CRC)。这三个点搞透了,后面分析SITL数据流就顺风顺水。

2.1 消息格式:每一帧的“骨架”

先看最核心的东西——消息帧结构。MAVLink 2.0是目前的主流版本,它的帧长这样:

| 起始标志 | 载荷长度 | 不兼容标志 | 兼容标志 | 序列号 | 系统ID | 组件ID | 消息ID | 载荷数据 | CRC校验 |
|  0xFD   |   1字节  |   1字节   |   1字节  | 1字节  | 1字节  |  1字节  |  3字节  | 0-255字节| 2字节   |

嗯,这里要注意:MAVLink 1.0的起始标志是0xFE,而2.0是0xFD。我在项目中遇到过有人把这两个版本混用,结果地面站死活收不到数据,排查了半天才发现是起始字节对不上。

每个字段的作用我列个表,方便你对照:

字段 长度(字节) 说明
起始标志 1 0xFD表示MAVLink 2.0,0xFE表示1.0
载荷长度 1 后面payload部分的实际字节数
不兼容标志 1 接收方如果不支持这些标志,必须丢弃整帧
兼容标志 1 接收方如果不支持,可以跳过对应字段继续解析
序列号 1 0-255循环,用于检测丢包
系统ID 1 标识发送设备,比如飞控是1,地面站是255
组件ID 1 标识同一系统内的不同组件,比如GPS模块、IMU
消息ID 3 唯一标识消息类型,比如HEARTBEAT是0
载荷数据 0-255 实际的消息内容
CRC校验 2 对整个帧(不含起始标志)的校验

你可能会问:为什么消息ID要占3个字节?MAVLink 1.0只用了1个字节,最多255种消息,后来发现不够用了。2.0直接扩到3字节,理论上支持1600多万种消息类型,够你用一辈子。

我的小技巧: 在SITL仿真中,我习惯先抓一帧原始数据,用手工对照这个表格逐字节解析一遍。做过一次,后面看任何MAVLink数据包都跟看白纸黑字一样清楚。

2.2 消息类型:从心跳到航点

MAVLink的消息类型多到让人眼花,但常用的其实就那几十种。我把它们分成几大类:

  • 系统状态类: HEARTBEAT(心跳)、SYS_STATUS(系统状态)、POWER_STATUS(电源状态)
  • 定位信息类: GPS_RAW_INT(原始GPS数据)、GLOBAL_POSITION_INT(全局位置)、LOCAL_POSITION_NED(局部位置)
  • 姿态与航向类: ATTITUDE(姿态角)、AHRS(航姿参考系统数据)
  • 传感器数据类: SCALED_IMU(IMU数据)、SCALED_PRESSURE(气压计数据)
  • 任务与控制类: MISSION_ITEM(航点)、COMMAND_INT(带坐标的命令)、MANUAL_CONTROL(手动控制)

其中HEARTBEAT是最重要的消息,没有之一。飞控每秒会发1-2次心跳包,告诉地面站“我还活着”。如果地面站连续几秒收不到心跳,就会触发连接超时报警。

我记得有一次做SITL仿真,飞控启动后地面站一直显示“未连接”。我抓包一看,飞控明明在发数据,但地面站就是不认。后来发现是系统ID和组件ID配置错了——飞控的系统ID设成了2,而地面站默认只监听系统ID为1的设备。这种坑,你不亲自踩一次,光看书是记不住的。

核心要点: 消息ID是MAVLink协议的灵魂。解析任何一帧数据,第一步就是读消息ID,然后才知道后面的payload该怎么拆解。

2.3 CRC校验机制:数据完整性的“守门员”

CRC校验,说白了就是给数据包算一个“指纹”。发送方算一遍,接收方也算一遍,两个指纹对得上,说明数据在传输过程中没被篡改或损坏。

MAVLink用的CRC算法是CRC-16-CCITT,多项式是0x1021。但这里有个关键点:每个消息类型都有自己的额外CRC种子。这个种子是根据消息名字符串算出来的,存在一个叫CRC_EXTRA的表中。

为什么要搞这么复杂?我猜是为了防止不同版本的消息被误解析。比如消息ID都是0,但MAVLink 1.0和2.0的HEARTBEAT载荷长度不一样,如果没有CRC种子做区分,接收方可能用错解析模板。

CRC校验的计算范围包括:

  1. 载荷长度字段
  2. 不兼容标志
  3. 兼容标志
  4. 序列号
  5. 系统ID
  6. 组件ID
  7. 消息ID(3字节)
  8. 载荷数据
  9. CRC种子(仅用于计算,不发送)

注意:起始标志和CRC校验本身不参与计算。

曾经踩过的坑: 我在自己写MAVLink解析器时,忘了把CRC种子加进去,结果算出来的校验码永远对不上。折腾了两个小时才发现,官方文档里写得很清楚:“The CRC is calculated over the entire packet, excluding the magic byte and the CRC itself, and including the CRC_EXTRA byte.” 嗯,从此以后我再也不敢跳过CRC种子了。

2.4 知识体系总览

下面这张图把MAVLink协议的核心逻辑串起来了,你可以把它当作本章的“思维导图”:

MAVLink协议核心知识体系 MAVLink协议核心知识体系 MAVLink 2.0 协议 消息格式 消息类型 CRC校验机制 帧结构 字段含义 HEARTBEAT 定位消息 CRC-16-CCITT CRC种子 核心要点 消息格式决定“怎么发”,消息类型决定“发什么”,CRC校验决定“发对了没” 三者缺一不可,共同构成MAVLink协议的完整通信模型

这张图把本章的三个核心知识点串在了一起。你从中心节点出发,沿着三条线往下看,就能理清MAVLink协议的全貌。

实战建议: 在SITL仿真中,你可以用mavlink-inspector或者mavproxy.py --aircraft=test --console来实时观察这些消息。我每次调试新硬件时,都会先开一个终端盯着HEARTBEAT消息——只要心跳不断,说明底层通信是通的,问题大概率出在上层逻辑。

好了,MAVLink协议的基础就讲到这里。消息格式、消息类型、CRC校验,这三个东西就像盖房子的地基、砖头和水泥,缺一不可。后面章节我们会拿着这些知识,去SITL仿真环境里真刀真枪地抓包分析。