1. MAVLink协议基础:协议概述、消息格式、CRC校验机制、常见消息类型
各位同学好,我是老张。做无人机飞控系统十几年了,MAVLink 协议几乎天天打交道。说实话,刚入行那会儿我也被它的各种消息类型搞得头晕。但搞懂了基础,后面就顺了。
这一章,咱们先把 MAVLink 的底裤扒清楚。协议概述、消息怎么打包、CRC 怎么算、常见消息有哪些——这些是后面设计指令链的根基。
1.1 协议概述
MAVLink,全称 Micro Air Vehicle Link。说白了,就是无人机和地面站、机载计算机之间聊天用的「黑话」。
它最早由苏黎世联邦理工的 Lorenz Meier 在 2009 年捣鼓出来。现在已经是无人机行业的事实标准了。我参与过的项目,从几十块钱的飞控玩具到几百万的工业无人机,底层通信几乎都跑 MAVLink。
目前主流有两个版本:
| 版本 | 特点 | 我个人的看法 |
|---|---|---|
| v1.0 | 简单、轻量,消息 ID 只有 8 位(0-255) | 适合资源受限的老飞控,但扩展性差 |
| v2.0 | 消息 ID 扩展到 24 位,支持签名、多目标 | 现在新项目我基本都用 v2,别犹豫 |
1.2 消息格式
MAVLink 的消息格式,其实就是一个精心设计的二进制帧。每一帧都是固定结构,解析起来非常快。你想想看,飞控每秒要处理几百条消息,要是用 JSON 或者 XML,CPU 早烧了。
v2.0 的消息帧结构如下:
+------+------+------+------+------+------+------+------+------+------+------+
| STX | LEN | INC | CMP | SEQ | SYS | COMP | MSG ID (3B) | PAYLOAD | CRC |
| 1B | 1B | 1B | 1B | 1B | 1B | 1B | 3B | 0-255B | 2B |
+------+------+------+------+------+------+------+------+------+------+------+
每个字段的含义:
- STX (0xFD):帧起始标志。v1.0 是 0xFE,v2.0 是 0xFD。解析器看到这个字节就知道新消息来了。
- LEN:Payload 长度。注意,不包括 CRC。
- INC:v2.0 新增的标志位,表示后面是否包含签名等扩展。
- CMP:兼容性标志。我一般直接填 0。
- SEQ:消息序列号。用来检测丢包。我在做中继链路时,就靠这个字段判断哪条路径丢了包。
- SYS / COMP:系统 ID 和组件 ID。用来区分不同的飞控、传感器、地面站。
- MSG ID (3B):消息 ID。v2.0 支持 0 到 16777215,基本够用了。
- PAYLOAD:消息体。长度可变,0 到 255 字节。
- CRC (2B):校验和。后面细说。
关键点:MAVLink 的帧头只有 10 字节(v2.0),加上 Payload 和 CRC,总开销非常小。这也是为什么它能跑在 9600 波特率的低速链路上。
1.3 CRC校验机制
CRC 校验,说白了就是给消息加个「指纹」。接收方收到后重新算一遍,跟发来的指纹比对。不一样?说明消息在传输中被篡改或损坏了。
MAVLink 用的 CRC 算法是 CRC-16-MAVLINK,基于 CCITT 标准但做了修改。具体来说:
- 多项式:
0x1021(x^16 + x^12 + x^5 + 1) - 初始值:
0xFFFF - 结果异或值:
0x0000(不额外异或) - 输入数据不反转,结果也不反转
嗯,这里要注意:MAVLink 的 CRC 计算范围包括 整个帧头 + Payload,但不包括 STX 和 CRC 本身。另外,v2.0 还会把 INC 和 CMP 字段也纳入计算。
我曾经在调试一个数传链路时,发现地面站老是报 CRC 错误。查了半天,原来是数传模块的缓冲区溢出了,把最后两个字节截掉了。从那以后,我写解析器时都会先检查 CRC,再处理消息。
CRC 计算的伪代码示例:
uint16_t crc_calculate(const uint8_t* buf, uint16_t len, uint8_t extra_crc) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc = _crc_ccitt_update(crc, buf[i]);
}
crc = _crc_ccitt_update(crc, extra_crc);
return crc;
}
1.4 常见消息类型
MAVLink 定义了上百种消息类型。但日常航点任务中,常用的其实就十几条。我把它们分成几类:
| 类别 | 消息 ID | 消息名 | 作用 |
|---|---|---|---|
| 心跳与状态 | 0 | HEARTBEAT | 告诉对方「我还活着」,附带飞控类型、状态 |
| 1 | SYS_STATUS | 电池电量、传感器健康度、负载情况 | |
| 24 | GPS_RAW_INT | GPS 经纬度、海拔、速度、卫星数 | |
| 航点任务 | 43 | MISSION_ITEM | 单个航点:位置、动作、参数 |
| 44 | MISSION_ACK | 任务上传/下载的确认 | |
| 45 | MISSION_REQUEST | 请求某个航点数据 | |
| 指令与控制 | 76 | COMMAND_LONG | 发送指令:起飞、降落、返航、设置模式 |
| 84 | RC_CHANNELS_OVERRIDE | 遥控器通道覆盖,用于手动干预 |
这里我重点提一下 HEARTBEAT。它是 MAVLink 里最重要的消息,没有之一。地面站靠它判断飞控是否在线,飞控靠它广播自己的类型和状态。我见过有人把心跳间隔设成 10 秒,结果地面站频繁报「连接丢失」。我的习惯是设 1 秒,稳定又省带宽。
另外,MISSION_ITEM 是航点任务的核心。它包含:
- 经纬度、海拔
- 动作类型(悬停、拍照、投掷等)
- 参数(悬停时间、拍照间隔等)
- 坐标系(WGS84、相对海拔等)
后面几章我们会深入拆解 MISSION_ITEM 的每个字段,以及如何把它们串成一条完整的指令链。
1.5 本章知识体系
为了让你更直观地理解 MAVLink 协议的整体结构,我画了张图:
这张图把本章的知识点串起来了。你可以看到,协议概述、消息格式、CRC 校验、常见消息这四块是并列关系,但都围绕着同一个核心——MAVLink 协议本身。后面的课程,我们会一层层往下挖。