4. 常用核心消息类型与语义

MAVLink 的消息体系非常庞大,但真正贯穿飞控运行全过程的“核心消息”其实只有一小撮。它们分别承担心跳、系统状态、原始 GPS、姿态、全局位置、命令下发与命令确认这七类职责。理解这些消息的字段语义、更新频率以及它们与飞控内部状态机的映射关系,是后续做数据链监控、地面站开发和自动化任务的前提。本节围绕 HEARTBEAT、SYS_STATUS、GPS_RAW_INT、ATTITUDE、GLOBAL_POSITION_INT、COMMAND_LONG 和 COMMAND_ACK 展开,并给出订阅打印关键字段的实现思路。

七类核心消息的职责划分

可以把这七类消息按“谁在说、说什么、多久说一次”三个维度来理解。HEARTBEAT 是系统存在性广播,任何 MAVLink 节点(飞控、地面站、云台、伴飞计算机)都必须周期性发送,接收方据此判断对方是否在线、属于哪类设备、当前是否解锁。SYS_STATUS 描述飞控自身的健康度,包括传感器健康位图、电池电压电流、剩余电量、通信丢包率等。GPS_RAW_INT 提供未经融合的原始 GPS 定位与定位质量指标。ATTITUDE 给出机体坐标系下的滚转、俯仰、偏航角速度与角度。GLOBAL_POSITION_INT 是融合后的全局位置,含经纬度、相对/绝对高度、速度矢量与航向。COMMAND_LONG 用于地面站向飞控下发带参数的长命令,COMMAND_ACK 则是飞控对该命令的执行结果回执。

核心消息频率分层与系统状态映射 飞控 (System 1) Component 1 · 自动驾驶仪 HEARTBEAT 1 Hz · 存在性广播 SYS_STATUS 1 Hz · 健康与电池 GPS_RAW_INT 5 Hz · 原始定位 ATTITUDE 10 Hz · 姿态角/角速度 GLOBAL_POSITION_INT 5 Hz · 融合位置 COMMAND_ACK 事件触发 · 命令回执 地面站 (System 255) Component 190 · 任务计算机 HEARTBEAT 1 Hz · 地面站心跳 COMMAND_LONG 事件触发 · 命令下发 订阅打印 解析关键字段 遥测流 命令流 状态映射:HEARTBEAT.base_mode → 解锁/手动/自动;SYS_STATUS.battery_remaining → 电量告警;GPS_RAW_INT.fix_type → 定位质量 COMMAND_LONG.command → 动作意图;COMMAND_ACK.result → 执行结果(0=ACCEPTED, 1=TEMPORARILY_REJECTED, 4=FAILED)

HEARTBEAT:系统存在性与状态的第一入口

HEARTBEAT 的字段不多,但信息密度很高。type 字段标识节点类型,常见值有 MAV_TYPE_QUADROTOR(2)、MAV_TYPE_GCS(6)、MAV_TYPE_ONBOARD_CONTROLLER(18)。autopilot 字段区分飞控固件家族,如 MAV_AUTOPILOT_PX4(12)、MAV_AUTOPILOT_ARDUPILOTMEGA(3)。base_mode 是位掩码,其中 MAV_MODE_FLAG_SAFETY_ARMED(128)这一位直接反映电机是否解锁,是判断“飞机能不能动”的最快依据。custom_mode 是飞控自定义模式号,PX4 与 ArduPilot 的解释不同,需要结合 autopilot 字段一起看。system_status 给出 MAV_STATE 枚举,如 STANDBY(3)、ACTIVE(4)、CRITICAL(5)。

实际订阅时,HEARTBEAT 通常以 1 Hz 发送。如果超过 3 秒没有收到某个 system_id 的心跳,就应判定该节点离线。这个超时判断是链路健康监控的基础逻辑。

SYS_STATUS:飞控健康与电池的集中体现

SYS_STATUS 的 onboard_control_sensors_health 是一个 32 位位图,每一位对应一类传感器或估计器,例如 0x01 表示 3D 陀螺仪健康、0x02 表示 3D 加速度计健康、0x20 表示 GPS 健康、0x100 表示姿态估计器健康。判断时用按位与运算即可:若 (health & 0x20) == 0,说明 GPS 子系统当前不可用。battery_remaining 是剩余电量百分比,-1 表示未知。voltage_battery 单位为毫伏,current_battery 单位为十毫安。drop_rate_comm 是通信丢包率,单位为 0.01%,即数值 100 表示 1% 丢包。

这些字段组合起来,可以支撑一个简单的健康判断:电量低于 20% 且丢包率高于 5%,就应触发返航或降落提示。

GPS_RAW_INT 与 GLOBAL_POSITION_INT:原始定位与融合定位的分工

GPS_RAW_INT 的 fix_type 是定位质量的核心指标:0=无 GPS、1=无定位、2=2D 定位、3=3D 定位、4=DGPS、5=RTK 浮点、6=RTK 固定。只有 fix_type ≥ 3 时,经纬度才具备可用性。lat 和 lon 的单位是 1e-7 度,alt 单位是毫米,eph 是水平精度因子(单位厘米),satellites_visible 是可见卫星数。GLOBAL_POSITION_INT 则是融合后的结果,lat/lon 同样为 1e-7 度,alt 为海拔毫米,relative_alt 为相对起飞点高度毫米,vx/vy/vz 为 NED 坐标系下的速度(厘米/秒),hdg 为航向(0.01 度)。

两者对照使用很有价值:如果 GPS_RAW_INT.fix_type 掉到 2 以下,而 GLOBAL_POSITION_INT 仍在更新,说明飞控正在依靠惯性或视觉估计维持位置,此时定位精度会逐渐漂移。

ATTITUDE:姿态角与角速度

ATTITUDE 的 roll、pitch、yaw 单位为弧度,rollspeed、pitchspeed、yawspeed 单位为弧度/秒。注意 yaw 的范围是 -π 到 +π,跨越 ±π 时会出现跳变,做航向平滑显示时需要先解缠。姿态消息频率通常为 10 Hz,是遥控飞行和姿态监控的主要数据源。

COMMAND_LONG 与 COMMAND_ACK:命令下发与回执闭环

COMMAND_LONG 包含 target_system、target_component、command、confirmation、param1~param7 七个参数字段。以解锁为例,command 为 MAV_CMD_COMPONENT_ARM_DISARM(400),param1=1 表示解锁,param1=0 表示上锁。起飞命令 MAV_CMD_NAV_TAKEOFF(22)用 param7 表示目标高度(米)。COMMAND_ACK 则回传 command 和 result,result=0 为 MAV_RESULT_ACCEPTED,1 为 TEMPORARILY_REJECTED,2 为 DENIED,3 为 UNSUPPORTED,4 为 FAILED。只有收到 result=0 才能认为命令被接受,否则需要根据 result 决定重试还是放弃。

订阅与打印关键字段的实现

下面以 pymavlink 为例,展示如何订阅上述消息并打印关键字段。代码假设已通过 UDP 或串口建立连接,并已收到过心跳。

from pymavlink import mavutil

master = mavutil.mavlink_connection('udp:127.0.0.1:14550')
master.wait_heartbeat()
print("heartbeat from system %u component %u" % (master.target_system, master.target_component))

while True:
    msg = master.recv_match(
        type=['HEARTBEAT','SYS_STATUS','GPS_RAW_INT',
              'ATTITUDE','GLOBAL_POSITION_INT','COMMAND_ACK'],
        blocking=True)
    if msg is None:
        continue
    t = msg.get_type()

    if t == 'HEARTBEAT':
        armed = bool(msg.base_mode & mavutil.mavlink.MAV_MODE_FLAG_SAFETY_ARMED)
        print(f"[HB] type={msg.type} autopilot={msg.autopilot} "
              f"armed={armed} status={msg.system_status}")

    elif t == 'SYS_STATUS':
        gps_ok = bool(msg.onboard_control_sensors_health & 0x20)
        print(f"[SYS] gps_health={gps_ok} batt={msg.battery_remaining}% "
              f"volt={msg.voltage_battery}mV drop={msg.drop_rate_comm*0.01:.2f}%")

    elif t == 'GPS_RAW_INT':
        print(f"[GPS] fix={msg.fix_type} sats={msg.satellites_visible} "
              f"lat={msg.lat*1e-7:.7f} lon={msg.lon*1e-7:.7f} eph={msg.eph}")

    elif t == 'ATTITUDE':
        print(f"[ATT] roll={msg.roll:.3f} pitch={msg.pitch:.3f} "
              f"yaw={msg.yaw:.3f} rad")

    elif t == 'GLOBAL_POSITION_INT':
        print(f"[POS] lat={msg.lat*1e-7:.7f} lon={msg.lon*1e-7:.7f} "
              f"rel_alt={msg.relative_alt/1000:.1f}m hdg={msg.hdg*0.01:.1f}deg")

    elif t == 'COMMAND_ACK':
        print(f"[ACK] cmd={msg.command} result={msg.result}")

运行后,典型输出会呈现明显的频率差异:HEARTBEAT 和 SYS_STATUS 约每秒一行,GPS_RAW_INT 和 GLOBAL_POSITION_INT 约每秒五行,ATTITUDE 约每秒十行。COMMAND_ACK 只在发送命令后出现。通过观察这些行的间隔,可以直观感受到消息频率与系统状态更新节奏的对应关系。

判断链路是否健康,可以同时看三个指标:HEARTBEAT 是否在 3 秒内到达、SYS_STATUS.drop_rate_comm 是否持续上升、COMMAND_ACK 是否在 1 秒内返回。三者分别对应节点存活、链路质量和命令闭环。

消息频率与系统状态的映射关系

把频率和状态放在一起看,会发现一条清晰的逻辑链:HEARTBEAT 的 base_mode 决定“能不能动”,SYS_STATUS 的传感器健康位和电量决定“该不该动”,GPS_RAW_INT 的 fix_type 决定“定位准不准”,GLOBAL_POSITION_INT 决定“在哪里”,ATTITUDE 决定“姿态如何”,COMMAND_LONG/ACK 决定“让做什么、做没做成”。这七类消息共同构成了飞控状态监控的最小完备集。后续做数据链开发时,无论使用哪种语言或框架,只要围绕这七类消息建立订阅、解析和状态判断逻辑,就能覆盖绝大多数地面站和伴飞计算机的核心需求。