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 自定义消息定义方法

有时候标准消息和扩展消息都不够用。比如我做过一个项目,需要在飞控和地面站之间传一个自定义的传感器数据。这时候就得自己定义消息了。

自定义消息其实不复杂,核心就三步:

  1. 写一个XML文件,定义消息结构和ID
  2. 用MAVLink代码生成器生成C语言代码
  3. 把生成的代码集成到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消息定义流程 common.xml(标准) uAvionix.xml(扩展) my_custom.xml(自定义) MAVLink代码生成器 mavgen.py mavlink_msg_*.h / mavlink.h PX4飞控(发送/接收) 地面站(解析/显示) 注意:自定义消息ID必须避开标准(0-255)和扩展(256-511)区间

从这张图你能看到,不管是标准、扩展还是自定义,最终都汇到代码生成器里。生成出来的头文件,再分别集成到飞控和地面站。说白了,MAVLink的消息定义就是一个「定义-生成-集成」的闭环。

一个小技巧:如果你只是想在PX4里加一条自定义消息,不用每次都重新生成整个mavlink库。PX4的构建系统支持增量编译,你只需要把新的头文件放到 src/modules/mavlink/ 目录下,然后重新编译就行。

好了,关于MAVLink消息定义,核心就是这三层结构。标准消息集是地基,扩展消息集是楼层,自定义消息集是你自己装修的隔间。搞清楚了这些,后面聊消息的发送和接收就轻松多了。