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,别犹豫
我的建议:新项目直接上 v2.0。v1.0 的消息 ID 池太小,我踩过坑——有一次给客户定制功能,发现 255 个 ID 全被占满了,最后只能硬着头皮改协议栈。

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,再处理消息。

避坑指南:如果你自己实现 MAVLink 解析器,千万别忘了 CRC 的「额外种子」机制。每种消息类型都有一个固定的 CRC 额外种子(extra crc),定义在 XML 定义文件中。这个种子用来防止不同版本的消息被误解析。我见过有人直接拿标准 CRC-16 算,结果死活对不上。

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 协议的整体结构,我画了张图:

MAVLink 协议知识体系 MAVLink 协议知识体系 MAVLink 协议 协议概述 消息格式 CRC 校验 常见消息 v1.0 vs v2.0 应用场景 帧结构(10B 头) Payload 0-255B CRC-16-MAVLINK 额外种子机制 HEARTBEAT / SYS_STATUS MISSION_ITEM / COMMAND 核心:理解帧结构 + CRC 校验,是后面设计指令链的基础 常见消息是日常开发中打交道最多的,建议熟记 ID

这张图把本章的知识点串起来了。你可以看到,协议概述、消息格式、CRC 校验、常见消息这四块是并列关系,但都围绕着同一个核心——MAVLink 协议本身。后面的课程,我们会一层层往下挖。