2、MAVLink核心协议解析:消息格式、心跳包、系统状态与GPS定位数据
各位同学,欢迎来到第二章。上一章我们聊了MAVLink的诞生背景和它在无人机生态里的位置。这一章,咱们直接动手拆协议——把MAVLink的“肉”和“骨头”都翻出来看看。
说实话,我最早接触MAVLink时,觉得它不就是一堆二进制数据嘛,有啥好研究的?直到有一次在野外调试,飞机突然报“GPS丢失”,我盯着地面站上那一串乱码似的十六进制数,才意识到:不懂协议细节,你连故障都定位不了。从那以后,我养成了一个习惯——看原始MAVLink报文,就像看自己的掌纹一样熟悉。
2.1 MAVLink消息帧结构——数据到底怎么装的?
MAVLink 1.0的消息帧,说白了就是一个固定格式的“信封”。每个消息都按这个模板打包,接收方按模板拆包。咱们先看最常用的v1版本,v2版本后面会单独讲。
| 字节偏移 | 字段名 | 长度(字节) | 说明 |
|---|---|---|---|
| 0 | STX(起始标志) | 1 | 固定值 0xFE(v1版本) |
| 1 | LEN(负载长度) | 1 | 后面payload部分的字节数,0~255 |
| 2 | SEQ(序列号) | 1 | 每个组件独立计数,用于检测丢包 |
| 3 | SYS ID(系统ID) | 1 | 标识整个无人机系统(飞控、地面站等) |
| 4 | COMP ID(组件ID) | 1 | 标识系统内的具体模块(飞控、GPS、相机等) |
| 5 | MSG ID(消息ID) | 1 | 标识消息类型,如 0 代表HEARTBEAT |
| 6 ~ 6+LEN-1 | PAYLOAD(负载) | LEN | 具体消息数据,按消息类型定义排列 |
| 6+LEN | CKA(校验和低字节) | 1 | CRC校验,包含整个消息(不含STX) |
| 6+LEN+1 | CKB(校验和高字节) | 1 | CRC校验高字节 |
mavlink_msg_xxx_decode() 函数直接解析,但遇到奇怪问题时,我会手动对照这个表格,逐字节检查原始数据。有一次发现SEQ号跳变,顺藤摸瓜找到了串口缓冲区溢出的bug。
嗯,这里要注意:MAVLink消息是可变长度的。LEN字段告诉接收方payload有多长,接收方读完payload后,再读2字节校验和,一帧消息就完整了。你想想看,如果LEN写错了,整个解析链就全乱了——这也是很多通信故障的根源。
2.2 心跳包(HEARTBEAT)——系统还活着吗?
心跳包是MAVLink里最基础、最重要的消息。没有它,地面站根本不知道天上飞的是什么玩意儿。它的消息ID是 0,payload固定为9字节。
我个人的经验是:调试任何MAVLink系统,第一步就是看心跳包。如果心跳包都不正常,后面的数据全是白搭。
2.2.1 心跳包结构
| 字段名 | 类型 | 说明 |
|---|---|---|
| type | uint8_t | 系统类型,如 MAV_TYPE_QUADROTOR(2) |
| autopilot | uint8_t | 飞控类型,如 MAV_AUTOPILOT_ARDUPILOTMEGA(3) |
| base_mode | uint8_t | 位掩码,表示系统状态(已上锁、已解锁、已连接等) |
| custom_mode | uint32_t | 自定义模式,ArduPilot用它表示飞行模式(Stabilize、Loiter等) |
| system_status | uint8_t | 系统状态,如 MAV_STATE_STANDBY(3) |
| mavlink_version | uint8_t | MAVLink协议版本,固定为3(v1版本) |
base_mode 和 custom_mode 是判断飞机是否解锁、当前飞行模式的核心字段。地面站就是靠这两个字段来显示“已解锁/已上锁”和“Stabilize/Loiter/Auto”等状态的。
2.2.2 实战:解析心跳包
假设你从串口收到一串原始数据,开头是 FE 09 1A 01 01 00 ...。咱们来拆一下:
FE→ STX,v1版本09→ LEN=9,心跳包payload正好9字节1A→ SEQ=26,这是第27个消息(从0开始)01→ SYS ID=1,通常是飞控01→ COMP ID=1,飞控主组件00→ MSG ID=0,确认是心跳包- 后面9字节就是payload,按上面表格顺序解析
我曾经在项目里遇到过一个问题:地面站一直显示“未连接”,但串口明明有数据。后来一查,发现是SYS ID和COMP ID不匹配——地面站只监听SYS ID=1的组件,但飞控配置成了SYS ID=2。你看,一个字节的差异,就能让整个系统“失联”。
2.3 系统状态(SYS_STATUS)——传感器都正常吗?
心跳包告诉你系统“活着”,但SYS_STATUS告诉你系统“健康不健康”。它的消息ID是 1,payload固定为31字节。
说白了,SYS_STATUS就是一张传感器和硬件的“体检报告”。我每次起飞前,都会盯着这个数据看几秒——尤其是 onboard_control_sensors_present 和 onboard_control_sensors_enabled 这两个字段。
2.3.1 关键字段解读
| 字段名 | 类型 | 说明 |
|---|---|---|
| onboard_control_sensors_present | uint32_t | 位掩码,表示系统有哪些传感器(GPS、陀螺仪、磁力计等) |
| onboard_control_sensors_enabled | uint32_t | 位掩码,表示哪些传感器已启用 |
| onboard_control_sensors_health | uint32_t | 位掩码,表示哪些传感器健康(1=健康,0=故障) |
| load | uint16_t | 飞控CPU负载,单位:千分之一(0~1000) |
| voltage_battery | uint16_t | 电池电压,单位:毫伏(mV) |
| current_battery | int16_t | 电池电流,单位:10毫安(10mA) |
| battery_remaining | int8_t | 剩余电量百分比(-1表示未知) |
| drop_rate_comm | uint16_t | 通信丢包率,单位:千分之一(0~1000) |
| errors_comm | uint16_t | 通信错误计数 |
| errors_count1~3 | uint16_t | 其他错误计数 |
onboard_control_sensors_health 显示GPS健康,但实际定位数据是错的。后来发现,飞控的“健康”判断只是检查GPS模块是否在发送数据,并不验证数据质量。所以,别只看健康位,还要看GPS_RAW_INT里的精度字段。
2.4 GPS定位数据(GPS_RAW_INT)——飞机到底在哪?
GPS_RAW_INT是MAVLink里最常用的定位消息,消息ID是 24,payload固定为30字节。它提供的是未经滤波的原始GPS数据(相对于飞控内部融合后的位置估计)。
2.4.1 字段详解
| 字段名 | 类型 | 说明 |
|---|---|---|
| time_usec | uint64_t | 时间戳,单位:微秒(通常用不到) |
| lat | int32_t | 纬度,单位:度×10^7(例如 40.1234567° → 401234567) |
| lon | int32_t | 经度,单位:度×10^7 |
| alt | int32_t | 海拔高度,单位:毫米(mm) |
| eph | uint16_t | 水平定位精度(HDOP),单位:厘米(cm) |
| epv | uint16_t | 垂直定位精度(VDOP),单位:厘米(cm) |
| vel | uint16_t | 地面速度,单位:厘米/秒(cm/s) |
| cog | uint16_t | 航向角(地面航迹),单位:百分之一度(cdeg) |
| fix_type | uint8_t | 定位类型:0=无定位,1=无GPS,2=2D定位,3=3D定位,4=差分GPS,5=RTK浮点解,6=RTK固定解 |
| satellites_visible | uint8_t | 可见卫星数 |
fix_type 和 satellites_visible。如果 fix_type 是3(3D定位)但卫星数少于8颗,我会怀疑GPS信号质量有问题。有一次在峡谷里飞行,卫星数掉到6颗,定位精度(eph)飙到5米以上——幸好提前发现了,没敢飞远。
2.4.2 数据转换示例
假设你从GPS_RAW_INT里读到:
lat = 401234567→ 纬度 = 401234567 / 10^7 = 40.1234567°lon = 1161234567→ 经度 = 1161234567 / 10^7 = 116.1234567°alt = 50000→ 海拔 = 50000 / 1000 = 50米eph = 150→ 水平精度 = 150 / 100 = 1.5米vel = 500→ 速度 = 500 / 100 = 5米/秒cog = 9000→ 航向 = 9000 / 100 = 90.00°(正东方向)
你想想看,如果 eph 是1500(15米),你敢用这个数据做自动降落吗?反正我是不敢。
2.5 本章知识体系图
下面这张图,把本章三个核心消息的关系和关键字段串起来了。建议你保存下来,调试时对照着看。
2.6 本章小结
这一章我们干了三件事:
- 拆了MAVLink消息帧——知道了每个字节的含义,尤其是STX、LEN、MSG ID这三个关键字段。
- 解析了心跳包——它是系统的“身份证”,告诉你谁在说话、什么状态、什么模式。
- 啃下了SYS_STATUS和GPS_RAW_INT——前者是健康报告,后者是定位数据,两者结合才能判断飞机是否真的“安全”。