3、MAVLink协议入门:从历史到心跳包

各位同学,今天我们来聊聊MAVLink协议。说实话,这个协议在无人机圈子里几乎是无人不知。我最早接触它是在2015年,那时候还在折腾一个开源飞控项目。当时就觉得,这协议设计得真巧妙——轻量、可靠、还特别容易扩展。

MAVLink全称是Micro Air Vehicle Link,微小型飞行器通信链路。它由苏黎世联邦理工学院的Lorenz Meier在2009年提出,最初是为PX4飞控项目服务的。你想想看,那时候无人机还是个新鲜玩意儿,能有一套专门为它设计的通信协议,确实挺超前的。

核心要点:MAVLink是目前最主流的无人机地面站通信协议,没有之一。无论是PX4、ArduPilot还是其他开源飞控,都把它作为默认通信方式。

3.1 发展历史:从v1.0到v2.0

MAVLink的发展其实挺有意思的。我简单梳理一下关键节点:

  • 2009年:MAVLink v1.0发布,最初只有8字节的消息头,有效载荷最多255字节。说实话,那时候功能很基础,但够用。
  • 2013年:随着无人机功能越来越复杂,v1.0开始显得捉襟见肘。消息ID只有256个,根本不够分。
  • 2017年:MAVLink v2.0正式发布。消息头扩展到12字节,消息ID扩展到24位(约1600万个),还加入了签名机制。

我记得在v2.0刚出来那会儿,很多老项目都不愿意升级。为什么?因为v1.0的兼容性太好了,改起来麻烦。但后来大家发现,v2.0的签名功能对安全太重要了——没有它,你的无人机可能被恶意劫持。嗯,这里要注意,如果你现在做新项目,直接用v2.0吧,别犹豫。

3.2 消息结构:拆开看看里面有什么

MAVLink的消息结构,说白了就是一组字节按照固定格式排列。我习惯把它想象成一个信封:有信封头、正文、还有校验码。

先看v1.0的消息结构:

| 起始标志(1B) | 载荷长度(1B) | 序列号(1B) | 系统ID(1B) | 组件ID(1B) | 消息ID(1B) | 有效载荷(0-255B) | 校验和(2B) |

再看v2.0的:

| 起始标志(1B) | 载荷长度(1B) | 不兼容标志(1B) | 兼容标志(1B) | 序列号(1B) | 系统ID(1B) | 组件ID(1B) | 消息ID(3B) | 有效载荷(0-255B) | 校验和(2B) | 签名(13B可选) |

这里有几个关键字段,我重点说一下:

字段 长度 说明
起始标志 1字节 v1.0是0xFE,v2.0是0xFD。用来识别协议版本。
载荷长度 1字节 有效载荷的实际字节数,不是固定值。
序列号 1字节 每发一条消息就加1,用来检测丢包。我调试时经常看这个值。
系统ID 1字节 标识不同的无人机或地面站。比如飞控是1,地面站是255。
组件ID 1字节 标识同一个系统里的不同组件。比如GPS模块、摄像头等。
消息ID v1:1B / v2:3B 标识消息类型。v2.0扩展到24位,够用很久了。

个人经验:我在做地面站时,经常需要手动解析MAVLink消息。建议你写一个简单的解析器,把每个字段打印出来看看。这样对消息结构的理解会深刻很多。

3.3 消息ID分配:谁是谁的身份证

消息ID是MAVLink里最重要的东西。它就像每个人的身份证号,告诉你这条消息是干嘛的。

MAVLink官方维护了一个消息ID分配表,我挑几个常用的说说:

  • 0-99:基础消息。比如HEARTBEAT(0号)、SYS_STATUS(1号)等。
  • 100-199:飞控相关。比如ATTITUDE(30号)、GLOBAL_POSITION_INT(33号)。
  • 200-299:地面站相关。比如COMMAND_INT(75号)、MANUAL_CONTROL(69号)。
  • 300-399:相机和云台。比如CAMERA_IMAGE_CAPTURED(263号)。
  • 400-499:任务和规划。比如MISSION_ITEM(39号)。

你可能会问:为什么v2.0要把消息ID扩展到24位?说白了,就是原来的256个ID不够分了。我见过一个项目,因为消息ID冲突,导致地面站和飞控互相误解——飞控发的是"电池电压低",地面站却解析成"GPS信号好"。这种bug查起来特别头疼。

避坑指南:如果你要自定义消息,千万别用官方已分配的ID。我曾经犯过这个错,结果和ArduPilot的某个版本冲突了。建议使用MAVLink官方预留的"用户自定义"范围(256-511),或者直接使用v2.0的扩展ID空间。

3.4 心跳包机制:无人机在说"我还活着"

心跳包(HEARTBEAT)是MAVLink里最基础、最重要的消息。它的消息ID是0,优先级最高。

心跳包的作用很简单:告诉对方"我还活着"。飞控每隔1秒发一次心跳包,地面站收到后就知道连接正常。如果连续3秒没收到心跳包,地面站就该报警了——无人机可能失联了。

心跳包的有效载荷只有9个字节,结构如下:

| 自定义模式(1B) | 自动舵类型(1B) | 基础模式(1B) | 自定义状态(4B) | MAVLink协议版本(1B) |

这里有几个关键字段:

  • 自定义模式:飞控自定义的模式。比如PX4的"手动模式"、"定高模式"等。
  • 自动舵类型:飞控的类型。比如MAV_AUTOPILOT_PX4(12)、MAV_AUTOPILOT_ARDUPILOTMEGA(3)。
  • 基础模式:标准化的模式。比如MAV_MODE_STABILIZE_DISARMED(80)、MAV_MODE_AUTO_ARMED(92)。
  • 自定义状态:飞控自定义的状态信息。
  • MAVLink协议版本:v1.0是0,v2.0是1。

我举个例子。假设你收到一个心跳包,解析出来是这样的:

自定义模式: 0
自动舵类型: 12 (PX4)
基础模式: 80 (STABILIZE_DISARMED)
自定义状态: 0
MAVLink协议版本: 1 (v2.0)

这说明什么?说明这是一架PX4飞控的无人机,当前处于"稳定模式、未解锁"状态,使用的是MAVLink v2.0协议。

关键点:心跳包是地面站判断无人机状态的"第一道关卡"。我建议你在地面站里做一个心跳包监控面板,实时显示连接状态、飞控类型、当前模式。这样一旦出问题,能第一时间发现。

嗯,说到心跳包,我想起一个坑。有一次我在调试地面站,发现飞控明明在发心跳包,但地面站就是收不到。查了半天,原来是串口波特率设置错了——飞控是57600,地面站设成了115200。这种低级错误,说出来都是泪。

3.5 知识体系总览

为了让你更直观地理解MAVLink的整体架构,我画了一张图:

MAVLink协议知识体系 MAVLink协议版本 v1.0 (2009年) v2.0 (2017年) 消息结构 起始标志 载荷长度 序列号 系统/组件ID 消息ID 有效载荷+校验 核心机制 消息ID分配 心跳包机制 校验与签名

这张图把MAVLink的知识体系分成了三层:协议版本、消息结构、核心机制。你学习的时候,可以按照这个框架来,先了解整体,再深入细节。

好了,关于MAVLink协议入门,我们就聊到这里。记住,协议这东西,光看文档是不够的。我建议你找个开源地面站(比如QGroundControl),打开串口日志,一条一条地看MAVLink消息。看多了,自然就熟了。


公众号:蓝海资料掘金营,微信deep3321