4、MAVLink消息定义:标准消息集、PX4扩展与自定义方法
聊到MAVLink,绕不开的就是消息定义。说白了,MAVLink就是靠一堆预先约定好的消息格式在飞控和地面站之间传数据。这些消息从哪来?怎么定义的?能不能自己加?今天咱们就把这事彻底说清楚。
我刚开始接触PX4的时候,也被这堆XML文件搞得有点懵。后来才发现,其实就三大块:官方标准集、厂商扩展集、还有你自己写的自定义集。咱们一个一个拆开看。
4.1 标准消息集:common.xml
common.xml 是MAVLink的基石。它由MAVLink官方维护,定义了所有飞控都应该支持的基础消息。你想想看,如果每个厂家的心跳包格式都不一样,那地面站还怎么通用?
这个文件里包含了大概200多条消息,我挑几个最常用的说说:
| 消息ID | 消息名 | 用途 | 我常用的场景 |
|---|---|---|---|
| 0 | HEARTBEAT | 心跳包,表明设备在线 | 判断飞控是否还活着 |
| 24 | GPS_RAW_INT | GPS原始数据(经纬度、高度) | 记录飞行轨迹 |
| 30 | ATTITUDE | 姿态信息(滚转、俯仰、偏航) | 实时监控飞机姿态 |
| 74 | COMMAND_LONG | 通用命令(解锁、起飞、返航) | 发送控制指令 |
核心要点:common.xml里的消息是所有MAVLink设备都必须理解的。如果你要做一个新的地面站,至少要把这些消息解析对。
我记得有一次调试一个第三方飞控,心跳包一直收不到。查了半天,发现是飞控的system_id设成了0。嗯,这里要注意:HEARTBEAT的system_id不能为0,这是MAVLink协议的死规定。
4.2 PX4扩展消息集:uAvionix.xml
光有标准消息够用吗?说实话,不够。PX4有很多自己的特色功能,比如避障、光流、ADSB,这些在common.xml里没有对应的消息。怎么办?加扩展。
uAvionix.xml 就是PX4团队专门为uAvionix(一家做ADSB的公司)定义的扩展消息集。但你别被名字骗了,里面其实包含了很多PX4特有的消息,不只是ADSB。
举个例子,PX4的避障系统会用到 OBSTACLE_DISTANCE 消息,这个在common.xml里就没有。还有 FOLLOW_TARGET,用于视觉跟随功能。这些都属于扩展消息。
我的习惯:在写地面站软件时,我会先加载common.xml,再加载uAvionix.xml。这样既能解析标准消息,也能处理PX4特有的数据。顺序不能反,因为扩展消息可能会引用标准消息里的枚举值。
扩展消息的ID范围是 256-511,跟标准消息(0-255)不冲突。这是MAVLink协议预留的厂商扩展区间。你想想看,如果大家都用同一个ID,那不乱套了?
4.3 自定义消息定义方法
有时候标准消息和扩展消息都不够用。比如我做过一个项目,需要在飞控和地面站之间传一个自定义的传感器数据。这时候就得自己定义消息了。
自定义消息其实不复杂,核心就三步:
- 写一个XML文件,定义消息结构和ID
- 用MAVLink代码生成器生成C语言代码
- 把生成的代码集成到PX4和地面站里
来看一个实际的例子。假设我要定义一个叫 CUSTOM_SENSOR 的消息,包含温度、湿度和气压:
<?xml version="1.0"?>
<mavlink>
<include>common.xml</include>
<messages>
<message id="300" name="CUSTOM_SENSOR">
<description>自定义传感器数据</description>
<field type="float" name="temperature" units="degC">温度</field>
<field type="float" name="humidity" units="%">湿度</field>
<field type="float" name="pressure" units="hPa">气压</field>
</message>
</messages>
</mavlink>
避坑指南:我曾经把自定义消息的ID设成了150,结果跟标准消息冲突了,地面站解析出来的数据全是乱的。记住:自定义消息的ID一定要用 256-511 或者 512-65535(用户自定义区间)。
定义好XML之后,用MAVLink的代码生成器跑一下:
python -m pymavlink.tools.mavgen --lang=C --wire-protocol=2.0 my_custom.xml
生成出来的 mavlink_msg_custom_sensor.h 里就有打包和解包的函数了。在PX4里发消息时,调用 mavlink_msg_custom_sensor_pack();在地面站里收消息时,调用 mavlink_msg_custom_sensor_decode()。
4.4 三种消息集的对比
| 类型 | ID范围 | 维护方 | 适用场景 |
|---|---|---|---|
| 标准消息集 | 0-255 | MAVLink官方 | 通用功能(心跳、GPS、姿态) |
| 厂商扩展集 | 256-511 | 厂商(如PX4团队) | 特定硬件功能(ADSB、避障) |
| 自定义消息集 | 512-65535 | 你自己 | 项目私有数据 |
我个人建议:能用标准消息就别自己造轮子。实在不行,先看看uAvionix.xml里有没有现成的。最后才考虑自定义。为什么?因为自定义消息意味着你的地面站和飞控都得改代码,维护成本高。
4.5 消息定义的整体流程
为了让你更直观地理解,我画了一张图,把整个消息定义的流程串起来:
从这张图你能看到,不管是标准、扩展还是自定义,最终都汇到代码生成器里。生成出来的头文件,再分别集成到飞控和地面站。说白了,MAVLink的消息定义就是一个「定义-生成-集成」的闭环。
一个小技巧:如果你只是想在PX4里加一条自定义消息,不用每次都重新生成整个mavlink库。PX4的构建系统支持增量编译,你只需要把新的头文件放到 src/modules/mavlink/ 目录下,然后重新编译就行。
好了,关于MAVLink消息定义,核心就是这三层结构。标准消息集是地基,扩展消息集是楼层,自定义消息集是你自己装修的隔间。搞清楚了这些,后面聊消息的发送和接收就轻松多了。