4. 关键消息类型(下):COMMAND_ACK、MISSION_CURRENT、GPS_RAW_INT,定位解锁指令响应

上一节我们聊了心跳、姿态和电池,算是把飞控的"生命体征"摸清了。这一节咱们继续深入,看看解锁指令发出去之后,飞控到底是怎么回应的。说白了,就是三个关键消息:COMMAND_ACK、MISSION_CURRENT 和 GPS_RAW_INT。

我个人习惯,拿到一份解锁失败的日志,第一件事就是搜这三个消息。它们就像飞控的"三连击",能告诉你指令有没有被接受、任务状态对不对、定位靠不靠谱。任何一个环节出问题,解锁都会卡住。

4.1 COMMAND_ACK:解锁指令的"回执"

你发了一条 MAV_CMD_COMPONENT_ARM_DISARM(也就是解锁指令),飞控收到后必须回复一条 COMMAND_ACK。这就像你寄了个快递,物流系统给你一个回执单,告诉你"已签收"还是"拒收"。

核心字段解读:

  • command:回执对应的指令ID。解锁指令是 400(MAV_CMD_COMPONENT_ARM_DISARM)。
  • result:执行结果。0 表示成功,非 0 表示失败。常见失败码有 1(DENIED)、3(UNSUPPORTED)、4(FAILED)。
  • progress:进度,一般用不到,但有些固件会用它传递额外信息。

我在项目中遇到过好几次,用户说"我发了解锁指令,飞控没反应"。结果一查日志,COMMAND_ACK 明明收到了,只是 result 是 1(DENIED)。飞控不是没反应,而是明确拒绝了。那为什么拒绝?

避坑指南:

我曾经被一个 case 坑过:日志里 COMMAND_ACK 的 result 是 0,但电机就是没转。后来发现,飞控回复了 ACK,但紧接着又因为某个预解锁检查失败,自动把电机锁回去了。所以,只看 ACK 不够,还得看后续消息。

4.2 MISSION_CURRENT:任务状态的"晴雨表"

解锁前,飞控通常会检查当前任务状态。如果任务列表为空,或者当前航点索引异常,解锁也会被拒绝。MISSION_CURRENT 消息就是告诉你当前飞控在任务中的位置。

字段 含义 解锁前正常值
seq 当前航点序号 0(表示从第一个航点开始)
total 任务总航点数 大于 0(至少有一个航点)
mission_state 任务状态 0(MISSION_STATE_UNKNOWN)或 1(MISSION_STATE_ACTIVE)

你想想看,如果 total 是 0,说明飞控里没装任务。有些固件在解锁前会强制要求至少有一个航点,否则直接拒绝。我记得有一次调试,日志里 MISSION_CURRENT 的 seq 一直跳变,从 0 跳到 5 又跳回 0,明显是任务列表被篡改了。后来发现是地面站反复上传任务导致的冲突。

注意: 有些飞控在解锁后才会开始执行任务,所以解锁前 mission_state 可能是 0。这不算异常。但如果 seq 是 65535(即 -1),说明任务列表为空或未加载,解锁大概率会失败。

4.3 GPS_RAW_INT:定位的"硬指标"

解锁前,飞控对 GPS 有硬性要求:至少 3D 定位,且精度够高。GPS_RAW_INT 消息就是用来评估这些指标的。

  • fix_type:定位类型。3 表示 3D 定位,2 表示 2D 定位,1 表示无定位。解锁通常要求 fix_type >= 3。
  • satellites_visible:可见卫星数。一般要求 >= 10 颗。
  • eph:水平位置精度(cm)。解锁前通常要求 eph < 100(即 1 米以内)。
  • epv:垂直位置精度(cm)。要求相对宽松,但最好也小于 200。

嗯,这里要注意:eph 的单位是厘米,不是米。我见过有人把 100 当成 100 米,结果发现飞控明明精度很好,却一直报"GPS 精度不足"。其实 100 厘米就是 1 米,完全够用。

实战经验:

有一次在室内测试,GPS 信号很差,fix_type 一直是 1,satellites_visible 只有 3 颗。飞控死活不解锁。后来我加了个 GPS 模拟器,把 fix_type 强制设为 3,才通过预解锁检查。但这是作弊,实际飞行千万别这么干。

4.4 三消息联动:解锁指令的完整响应链

这三个消息不是孤立的。它们共同构成了飞控对解锁指令的完整响应。我画了一张图,帮你理清它们的关系。

解锁指令响应链 解锁指令响应链 地面站发送解锁指令 飞控接收指令 预解锁检查 通过:发送 ACK(0) 电机解锁 失败:发送 ACK(1/4) 电机不解锁 关键消息联动说明 • COMMAND_ACK:指令是否被接受(result 字段) • MISSION_CURRENT:任务状态是否正常(seq/total 字段) • GPS_RAW_INT:定位是否满足要求(fix_type/eph 字段) • 三者任一异常,解锁都会被拒绝

从图上可以看得很清楚:地面站发送解锁指令后,飞控先做预解锁检查。检查通过,就回复 COMMAND_ACK 的 result 为 0,然后电机解锁。检查失败,就回复非 0 的 result,电机不解锁。

而预解锁检查的内容,就包括 MISSION_CURRENT 和 GPS_RAW_INT 的状态。所以,当你看到 COMMAND_ACK 的 result 非 0 时,别急着骂飞控,先看看 MISSION_CURRENT 的 total 是不是 0,或者 GPS_RAW_INT 的 fix_type 是不是小于 3。

我的调试习惯:

我会在日志里同时搜索这三个消息,然后按时间戳对齐。如果 COMMAND_ACK 的 result 是 1,我会立刻看 GPS_RAW_INT 的 eph 是不是超标了。如果 result 是 4,我会检查 MISSION_CURRENT 的 seq 是不是异常。这样定位问题,基本一抓一个准。

4.5 实战案例:一次典型的解锁失败分析

咱们来看一个真实案例。日志片段如下:

# 时间戳 消息类型 字段值
10:00:01.000 COMMAND_ACK command=400, result=1, progress=0
10:00:01.000 MISSION_CURRENT seq=0, total=0, mission_state=0
10:00:01.000 GPS_RAW_INT fix_type=3, satellites_visible=12, eph=85, epv=150

分析一下:

  • COMMAND_ACK 的 result 是 1(DENIED),说明飞控拒绝了解锁。
  • GPS_RAW_INT 的 fix_type 是 3,eph 是 85(0.85 米),定位没问题。
  • MISSION_CURRENT 的 total 是 0,说明任务列表为空。

问题就出在 MISSION_CURRENT 上。飞控要求解锁前至少有一个航点,但任务列表是空的,所以拒绝了。解决办法很简单:上传一个任务,或者修改飞控参数,允许无任务解锁。

注意: 不同固件的预解锁检查逻辑不一样。ArduPilot 和 PX4 的检查项有差异,甚至同一固件的不同版本也可能不同。所以,分析日志时一定要结合固件版本来看。