4、MAVLink协议基础:消息结构、常见类型与uORB关系

做SITL仿真联调,绕不开MAVLink。说白了,它就是无人机和地面站之间的“通用语言”。我最早接触MAVLink时,觉得不就是个通信协议嘛,后来踩了几个坑才明白——不理解消息结构,你连日志都读不懂。

这一节,我们就把MAVLink的底裤扒开看看。消息怎么组装的?心跳包长什么样?GPS数据怎么塞进去的?还有那个uORB,它和MAVLink到底是什么关系?

4.1 MAVLink消息结构:一个数据包的解剖

MAVLink的消息结构其实很简洁。每个数据包都遵循固定格式,就像快递包裹一样——有包裹单、有内容、有校验码。

我习惯把MAVLink v1的消息结构画成一张表,这样一眼就能看明白每个字节的用途:

字节偏移 字段名 长度(字节) 说明
0 STX(起始标志) 1 固定值0xFE(v1版本)
1 LEN(负载长度) 1 后面payload的字节数
2 SEQ(序列号) 1 每个组件独立计数,检测丢包用
3 SYS ID(系统ID) 1 标识是哪个无人机/设备
4 COMP ID(组件ID) 1 标识是飞控、GPS还是相机
5 MSG ID(消息ID) 1 标识消息类型,比如心跳是0
6 ~ 6+LEN-1 Payload(负载) LEN 真正的数据内容
6+LEN CKA(校验码低字节) 1 CRC校验,保证数据完整性
7+LEN CKB(校验码高字节) 1 同上

我的小经验:调试时如果地面站收不到数据,先看STX对不对。0xFE是v1,0xFD是v2。我曾经花了一下午排查,结果发现是v1和v2混用了——地面站用v2解析v1的包,直接丢掉了。

嗯,这里要注意:MAVLink v2比v1多了个“不签名标志”和“签名”字段,但核心结构没变。你搞SITL仿真时,默认用的就是v2,兼容v1。

4.2 常见消息类型:心跳、GPS和姿态

MAVLink定义了上百种消息类型。但说实话,日常仿真联调,你打交道最多的就那几种。我挑三个最核心的讲。

4.2.1 HEARTBEAT(心跳包)

心跳包是MAVLink的“我在呢”信号。飞控每隔1秒发一次,告诉地面站:我还活着,模式是什么,有没有问题。

它的MSG ID是0。payload里最关键的是这几个字段:

  • type:飞行器类型,比如MAV_TYPE_QUADROTOR(四旋翼)
  • autopilot:飞控类型,比如MAV_AUTOPILOT_PX4
  • base_mode:飞行模式,比如是否上锁、是否在自动模式
  • system_status:系统状态,比如STANDBY、ACTIVE、EMERGENCY

你看,就这4个字段,地面站就能判断无人机当前的状态。我调试时,第一件事就是看心跳包有没有——如果心跳断了,后面所有数据都不用看了。

4.2.2 GPS_RAW_INT(原始GPS数据)

这个MSG ID是24。它把GPS信息打包成整数发送,节省带宽。payload里包含:

  • lat / lon:纬度、经度,单位是度×10^7(整数)
  • alt:海拔高度,单位是毫米
  • eph / epv:水平/垂直定位精度,单位是厘米
  • fix_type:定位类型,0=无定位,1=无GPS,2=2D,3=3D
  • satellites_visible:可见卫星数

避坑指南:我曾经在仿真里发现GPS数据一直显示0,查了半天,原来是SITL启动时没设置GPS模拟参数。默认情况下,SITL的GPS是关闭的。记得加 --gps 参数,或者用 param set 把GPS使能。

4.2.3 ATTITUDE(姿态数据)

MSG ID是30。这个包告诉你飞机当前“怎么躺的”。payload包含:

  • roll / pitch / yaw:横滚角、俯仰角、偏航角,单位是弧度
  • rollspeed / pitchspeed / yawspeed:角速度,单位是弧度/秒
  • time_boot_ms:从启动到现在的毫秒数

你想想看,地面站画的那个小飞机模型,就是靠这个数据转来转去的。我调试姿态控制时,经常盯着这个包看——如果roll突然跳变,说明传感器或者滤波器出问题了。

4.3 uORB与MAVLink的关系:内部总线 vs 外部协议

这个问题,很多初学者搞混。我直接说结论:uORB是PX4飞控内部的消息总线,MAVLink是飞控和外部通信的协议。

它们的关系,可以用一张图说清楚:

uORB 与 MAVLink 的关系 PX4 飞控内部 uORB 消息总线 内部发布/订阅机制 传感器模块 发布 sensor_gps 姿态估计 发布 vehicle_attitude mavlink 模块 订阅 uORB,打包成 MAVLink 外部世界 地面站(QGC / Mission Planner) 解析 MAVLink,显示数据 其他 MAVLink 设备 如机载计算机、相机 核心逻辑 传感器 → uORB 发布 mavlink 模块订阅 → 打包 串口/UDP 发送 → 外部解析

你看这张图就明白了:

  • uORB:飞控内部各个模块之间“喊话”用的。比如GPS驱动发布了 sensor_gps 主题,姿态估计模块订阅它,然后发布 vehicle_attitude 主题。
  • MAVLink:飞控和地面站“打电话”用的。mavlink模块订阅uORB上的数据,然后打包成MAVLink消息,通过串口或UDP发出去。

注意:uORB和MAVLink的消息ID不是一回事。uORB的主题名是字符串(比如 sensor_gps),MAVLink的消息ID是数字(比如24对应GPS_RAW_INT)。mavlink模块负责做这个“翻译”工作。

我刚开始学PX4时,总以为改MAVLink消息要改uORB。其实不是——你只需要在mavlink模块里加一个订阅和打包函数就行。uORB那边完全不用动。

4.4 实战:在SITL里抓一个MAVLink包看看

光说不练假把式。我们启动SITL,然后用 mavlink 命令行工具抓个包看看。

先启动SITL(假设你已经配好了环境):

make px4_sitl gazebo

等飞控启动后,另开一个终端,用 mavlink 工具监听:

mavlink receive udp:127.0.0.1:14550

你会看到类似这样的输出:

MAVLink: received 1 messages
  #0: HEARTBEAT (type=2, autopilot=12, base_mode=81, system_status=3)
MAVLink: received 1 messages
  #1: GPS_RAW_INT (lat=473825000, lon=85000000, alt=488000, fix_type=3, satellites_visible=10)
MAVLink: received 1 messages
  #2: ATTITUDE (roll=0.01, pitch=-0.02, yaw=1.57, rollspeed=0.00, pitchspeed=0.00, yawspeed=0.00)

嗯,这就是飞控在“说话”。你看心跳包的 base_mode=81,表示飞控已经解锁并处于自动模式。fix_type=3 表示3D定位成功。yaw=1.57 大约是90度,说明飞机朝东。

调试技巧:如果你不想装mavlink工具,也可以用 netcat 直接看原始字节流。不过那玩意是人眼不可读的——全是十六进制。我建议还是用 mavlink 或者 mavproxy,它们会自动解析消息。

4.5 小结:记住这三句话

这一节内容不少,但核心就三句话:

  1. MAVLink消息结构:起始标志 + 长度 + 序列号 + 系统/组件ID + 消息ID + 负载 + 校验码。就这么简单。
  2. 常见消息类型:HEARTBEAT(心跳,MSG ID=0)、GPS_RAW_INT(原始GPS,MSG ID=24)、ATTITUDE(姿态,MSG ID=30)。这三个包覆盖了无人机90%的调试需求。
  3. uORB与MAVLink的关系:uORB是内部总线,MAVLink是外部协议。mavlink模块是“翻译官”,把uORB主题翻译成MAVLink消息发出去。