4. 常用MAVLink消息集:HEARTBEAT、SYS_STATUS、GPS_RAW_INT、ATTITUDE、LOCAL_POSITION_NED

各位同学,咱们今天聊点实在的。MAVLink协议里定义了上百种消息,但你实际调试无人机时,90%的时间都在跟五条消息打交道。我个人习惯把这五条消息称为「调试五件套」——它们就像医生的听诊器、血压计、心电图,缺了哪个你都看不透飞机的状态。

这五条消息分别是:HEARTBEAT(心跳)、SYS_STATUS(系统状态)、GPS_RAW_INT(原始GPS数据)、ATTITUDE(姿态四元数)、LOCAL_POSITION_NED(本地位置NED坐标系)。下面我一个一个拆开讲。

核心观点:这五条消息覆盖了无人机调试的「心跳-健康-定位-姿态-位置」五个维度。你只要把这五条消息的解析和可视化做扎实了,80%的空中异常都能快速定位。

MAVLink 调试五件套知识体系 调试五件套 HEARTBEAT SYS_STATUS GPS_RAW_INT ATTITUDE LOCAL_POSITION_NED 说明: HEARTBEAT 提供心跳和飞行模式;SYS_STATUS 提供电池和传感器健康度; GPS_RAW_INT 提供经纬高和卫星数;ATTITUDE 提供姿态角;LOCAL_POSITION_NED 提供位置和速度。

4.1 HEARTBEAT —— 飞机还活着吗?

HEARTBEAT 是所有MAVLink通信的基础。说白了,它就是飞机在喊「我还活着」。地面站如果连续几秒收不到HEARTBEAT,就会报「通信丢失」。我见过不少新手一上来就盯着高级消息看,结果飞机都掉线了还在那分析姿态数据——这不是本末倒置吗?

HEARTBEAT 消息里最重要的字段是 type 和 autopilot,它们告诉你飞机是什么类型、用的什么飞控。但调试时我最关注的是 system_status 和 base_mode。

字段 含义 调试关注点
type 飞行器类型(多旋翼/固定翼/地面站等) 确认机型枚举值正确
autopilot 飞控固件类型(PX4/ArduPilot等) 确认固件版本兼容
system_status 系统状态(未初始化/待机/激活/紧急降落等) 最常用:判断飞机是否就绪
base_mode 基础模式标志位(是否已解锁/是否已武装等) 判断解锁状态和模式切换

调试技巧:我建议你在地面站里把HEARTBEAT的接收间隔显示出来。正常情况是1Hz(每秒1条)。如果间隔突然跳到3秒以上,先别急着查GPS或姿态——大概率是数传链路有问题。我曾经在野外调试时,飞机飞出去200米就丢心跳了,最后发现是数传天线没拧紧。

4.2 SYS_STATUS —— 飞机身体怎么样?

SYS_STATUS 相当于飞机的体检报告。它告诉你电池还剩多少电、传感器有没有报错、当前负载高不高。我个人觉得,这条消息是「安全底线」——起飞前必须看一眼。

关键字段有三个:

  • voltage_battery:电池电压。3S锂电池满电12.6V,低于11.1V就该降落了。我见过有人把电压阈值设得太低,结果电池过放鼓包——嗯,那画面挺惨的。
  • current_battery:电池电流。配合电压可以算功率和剩余能量。
  • onboard_control_sensors_present:这是一个位掩码,每一位代表一个传感器(GPS、陀螺仪、加速度计、气压计等)。如果某一位为0,说明那个传感器没检测到。

避坑指南:我曾经遇到过一架飞机,SYS_STATUS 里显示电池电压正常,但飞了3分钟就掉高。后来发现是电流传感器坏了,飞控以为还有电,实际电池已经快空了。所以我的习惯是:同时监控电压和电流,只看电压不靠谱。

4.3 GPS_RAW_INT —— 飞机在哪?

GPS_RAW_INT 提供原始的GPS数据:经纬度、海拔、地面速度、航向角、卫星数。注意,这里的经纬度单位是 度×10⁷(int32),解析时要除以10⁷。很多新手在这里踩过坑——直接拿原始值当度数用,结果飞机定位到太平洋中间去了。

// 正确解析示例(C语言风格)
double lat = (double)gps_raw_int.lat / 1e7;
double lon = (double)gps_raw_int.lon / 1e7;
float alt = (float)gps_raw_int.alt / 1000.0;  // 海拔单位是毫米

调试时我最关注两个指标:卫星数(satellites_visible)和 定位类型(fix_type)。

fix_type 含义 能否起飞?
0-1 未定位/无GPS ❌ 不能
2 2D定位(只有经纬度) ⚠️ 不建议
3 3D定位(经纬高) ✅ 可以
4-5 DGPS/RTK浮点解 ✅ 精度更高
6 RTK固定解 ✅ 厘米级精度

个人经验:卫星数少于10颗时,我一般不会解锁起飞。尤其是城市峡谷或树荫下,GPS信号容易跳变。你想想看,飞机在天上突然从3D定位掉到2D定位,高度数据直接飞掉——那后果你懂的。

4.4 ATTITUDE —— 飞机姿势对不对?

ATTITUDE 消息里装的是四元数(q1、q2、q3、q4)和角速度(rollspeed、pitchspeed、yawspeed)。四元数可以直接用,也可以转成欧拉角(roll/pitch/yaw)来看。

调试时我一般把四元数转成欧拉角显示,因为人脑对角度更直观。但注意,欧拉角有万向锁问题——俯仰接近±90°时,横滚和偏航会耦合。所以飞控内部都用四元数,你在地面站看欧拉角就行。

// 四元数转欧拉角(Python示例)
import math

def quaternion_to_euler(q):
    # q = [w, x, y, z] 即 [q1, q2, q3, q4]
    sinr_cosp = 2.0 * (q[0]*q[1] + q[2]*q[3])
    cosr_cosp = 1.0 - 2.0 * (q[1]*q[1] + q[2]*q[2])
    roll = math.atan2(sinr_cosp, cosr_cosp)
    
    sinp = 2.0 * (q[0]*q[2] - q[3]*q[1])
    if abs(sinp) >= 1:
        pitch = math.copysign(math.pi/2, sinp)
    else:
        pitch = math.asin(sinp)
    
    siny_cosp = 2.0 * (q[0]*q[3] + q[1]*q[2])
    cosy_cosp = 1.0 - 2.0 * (q[2]*q[2] + q[3]*q[3])
    yaw = math.atan2(siny_cosp, cosy_cosp)
    
    return roll, pitch, yaw  # 弧度制

避坑指南:我曾经调试一架飞机,地面站显示姿态角一直在缓慢漂移,但飞机实际是水平的。查了半天,发现是飞控的加速度计没校准。ATTITUDE 消息本身没问题,但输入数据是错的。所以记住:ATTITUDE 准不准,取决于传感器校准到不到位。

4.5 LOCAL_POSITION_NED —— 飞机在空间里怎么动?

LOCAL_POSITION_NED 提供的是本地坐标系下的位置和速度。NED 坐标系:X轴指向北、Y轴指向东、Z轴指向地。这个坐标系对调试特别有用,因为它直接对应你在地面站地图上看到的「前后左右上下」。

关键字段:

  • x、y、z:位置(米)。z 是负值,因为向下为正——嗯,刚开始用的时候我也觉得反直觉。
  • vx、vy、vz:速度(米/秒)。同样,vz 向下为正。

调试时我经常用这个数据来验证飞控的位置控制效果。比如,你给飞机一个「向前飞1米」的指令,然后看 x 的变化曲线——如果超调大、震荡多,说明位置PID参数需要调。

实用技巧:把 LOCAL_POSITION_NED 的 z 和 GPS_RAW_INT 的 alt 放在同一张图上对比。如果两者偏差超过1米,说明气压计或者GPS高度有问题。我遇到过一架飞机,LOCAL_POSITION_NED 的 z 值一直在跳,最后发现是超声波高度计被桨叶气流干扰了。

4.6 五条消息的协同使用

单独看每条消息都有用,但真正的高手是把它们串起来看。我给你一个我常用的调试流程:

  1. 先看 HEARTBEAT:确认飞机在线、模式正确、已解锁。
  2. 再看 SYS_STATUS:确认电池电压正常、所有传感器就绪。
  3. 检查 GPS_RAW_INT:卫星数≥10、fix_type≥3。
  4. 观察 ATTITUDE:飞机静止时 roll/pitch 应接近0°,yaw 稳定。
  5. 最后看 LOCAL_POSITION_NED:位置和速度是否平滑,有没有异常跳变。

这个流程走下来,飞机能不能安全起飞,你心里就有数了。我每次外场调试都按这个顺序来,从来没出过事。

最后说一句:这五条消息的解析代码,我建议你提前写好并测试通过。别等到飞机在天上飘着,才发现代码里有个除零错误——那可就真「飘」了。