4、MAVLink模式切换命令:COMMAND_INT与COMMAND_LONG详解、MAV_CMD_DO_SET_MODE参数解析、模式切换的响应机制

好,咱们进入正题。模式切换,说白了就是告诉飞控:「我现在想换个玩法」。但怎么告诉它?通过什么指令?参数怎么填?飞控收到后又怎么回你?

这章我把这三个问题拆开揉碎了讲。我个人习惯是先把命令本身搞清楚,再看参数怎么配,最后盯一下响应流程——这样一套下来,你写模式切换代码基本不会翻车。

4.1 两条核心命令:COMMAND_INT 与 COMMAND_LONG

MAVLink 里用来发「指令」的消息主要有两条:COMMAND_INT(编号 75)和 COMMAND_LONG(编号 76)。

名字上就差一个「INT」,但实际用起来区别不小。我刚开始接触时也搞混过,后来踩了一次坑才彻底分清楚。

对比项 COMMAND_INT (75) COMMAND_LONG (76)
坐标精度 使用 int32 纬度/经度,精度更高 使用 float 纬度/经度
参数数量 最多 7 个参数(param1-param7) 最多 7 个参数(param1-param7)
适用场景 需要高精度坐标的任务(如航点、区域) 一般指令(模式切换、参数设置等)
帧类型 包含 frame 字段(坐标系) 无 frame 字段
推荐度 新协议更推荐使用 兼容性好,老设备常用

核心结论:模式切换不需要高精度坐标,所以两条命令都能用。但我个人建议——优先用 COMMAND_INT。为什么?因为它是 MAVLink 2 的推荐方式,未来兼容性更好。

4.2 MAV_CMD_DO_SET_MODE 参数解析

不管用哪条命令发,真正干活的都是命令 ID:MAV_CMD_DO_SET_MODE(数值 176)。

这个命令有 7 个参数位,但模式切换只用前两个。嗯,这里要注意——很多人把参数填错了,结果飞控没反应。

参数 名称 说明 常用值
param1 模式基值 指定模式大类(MAV_MODE 枚举) 1 = MANUAL, 2 = STABILIZE, 3 = AUTO…
param2 自定义模式 飞控厂商自定义的子模式 见下方表格
param3-7 保留/未使用 填 0 或 NaN 0

避坑指南:我曾经在 param1 里直接填了「4」(AUTO),结果飞控没切过去。后来才发现——param1 必须填 MAV_MODE 枚举值,不是自定义模式编号。自定义模式要放在 param2 里。

4.2.1 自定义模式(param2)详解

param2 才是真正决定「飞控飞成什么样」的关键。不同厂商定义不同,我列几个最常见的:

飞控类型 模式名称 param2 值 说明
ArduPilot STABILIZE 0 自稳模式
ArduPilot ALT_HOLD 2 定高模式
ArduPilot AUTO 3 自动任务模式
ArduPilot GUIDED 4 引导模式
ArduPilot LOITER 5 悬停模式
ArduPilot RTL 6 返航模式
PX4 MANUAL 0 手动模式
PX4 ALTCTL 1 高度控制
PX4 POSCTL 2 位置控制
PX4 AUTO_MISSION 3 自动任务
PX4 AUTO_RTL 4 自动返航

小技巧:如果你不确定 param2 的值,可以先用 QGroundControl 手动切一次模式,同时抓包看 MAVLink 日志。我经常这么干——省得翻文档翻到眼花。

4.3 模式切换的响应机制

命令发出去了,飞控怎么回你?这涉及到 MAVLink 的「命令确认」机制。

4.3.1 响应流程

  1. 地面站发送:COMMAND_INT 或 COMMAND_LONG,命令 ID = 176
  2. 飞控接收:解析命令,检查参数合法性
  3. 飞控执行:切换模式(或拒绝切换)
  4. 飞控回复:发送 COMMAND_ACK(编号 77)

你想想看,如果没有这个 ACK,你根本不知道飞控到底切没切成功。我早期做地面站时,就遇到过发了命令但飞控没反应——后来才发现是 param2 填错了,飞控直接拒绝了。

4.3.2 COMMAND_ACK 结构

字段 说明 常见值
command 原始命令 ID 176 (MAV_CMD_DO_SET_MODE)
result 执行结果枚举 0 = 成功, 1 = 被拒绝, 2 = 错误…
progress 进度(0-100) 通常为 0 或 255
result_param2 附加信息 失败原因代码
target_system 目标系统 ID 与请求一致
target_component 目标组件 ID 与请求一致

关键点:result 字段为 0 才表示模式切换成功。其他值都要查原因。我见过有人只看 ACK 收到了就以为成功了——结果飞控根本没切。

4.3.3 常见失败原因

  • result = 1 (MAV_RESULT_DENIED):飞控拒绝了切换。常见原因:当前飞行状态不允许切换(比如正在执行关键任务)、参数值非法。
  • result = 2 (MAV_RESULT_FAILED):执行失败。可能是飞控内部错误。
  • result = 3 (MAV_RESULT_IN_PROGRESS):正在切换中,稍后重试。
  • result = 4 (MAV_RESULT_UNSUPPORTED):飞控不支持该模式。

避坑指南:我曾经在无人机正在执行 AUTO 任务时,试图切到 STABILIZE——结果飞控返回 DENIED。后来查文档才知道,某些飞控在任务执行中会锁定模式切换。解决办法:先发 MAV_CMD_MISSION_START 暂停任务,再切模式。

4.4 完整代码示例

下面给一个实际可用的 Python 示例(使用 pymavlink 库)。我习惯用 COMMAND_INT,但也会注释 COMMAND_LONG 的写法,方便你对比。

from pymavlink import mavutil

# 连接飞控
master = mavutil.mavlink_connection('udp:127.0.0.1:14550')

# 等待心跳
master.wait_heartbeat()
print("已连接飞控")

# 准备参数
target_system = 1
target_component = 1
# 模式:ArduPilot 的 GUIDED 模式
param1 = 1  # MAV_MODE_FLAG_CUSTOM_MODE_ENABLED
param2 = 4  # GUIDED

# 方式一:使用 COMMAND_INT(推荐)
master.mav.command_int_send(
    target_system,
    target_component,
    0,          # frame: MAV_FRAME_GLOBAL
    176,        # command: MAV_CMD_DO_SET_MODE
    0,          # current: 0
    0,          # autocontinue: 0
    param1,     # param1
    param2,     # param2
    0, 0, 0, 0, 0  # param3-7
)

# 方式二:使用 COMMAND_LONG(兼容)
# master.mav.command_long_send(
#     target_system,
#     target_component,
#     176,        # command
#     0,          # confirmation
#     param1,     # param1
#     param2,     # param2
#     0, 0, 0, 0, 0  # param3-7
# )

# 等待 ACK
ack = master.recv_match(type='COMMAND_ACK', blocking=True, timeout=5)
if ack:
    if ack.result == 0:
        print("模式切换成功!")
    else:
        print(f"模式切换失败,错误码:{ack.result}")
else:
    print("未收到 ACK,请检查连接")

小提示:实际项目中,我建议加一个重试机制——如果 2 秒内没收到 ACK,重新发一次。网络丢包时这招很管用。

4.5 知识体系总览

下面这张图把本章的核心逻辑串起来了。你一看就明白:命令怎么发、参数怎么填、响应怎么收。

MAVLink模式切换流程 MAVLink 模式切换核心流程 地面站 / GCS 选择命令 COMMAND_INT (75) 或 COMMAND_LONG (76) 填充参数 command=176 (MAV_CMD_DO_SET_MODE) param1=模式基值, param2=自定义模式 飞控接收并执行 回复 COMMAND_ACK (77) result=0 成功 / 其他值失败 ⚠️ 常见错误 • param1 填了自定义模式编号 • 忘记检查 ACK 的 result • 在任务执行中强行切换 💡 最佳实践 • 优先用 COMMAND_INT • 加 2 秒超时重试 • 抓包确认 param2 值

嗯,这张图基本把整个流程讲透了。你写代码时,就按这个顺序来:选命令 → 填参数 → 发出去 → 等 ACK → 检查 result。少一步都可能出问题。

本章核心要点:

  • 模式切换用 MAV_CMD_DO_SET_MODE(176),通过 COMMAND_INT 或 COMMAND_LONG 发送
  • param1 填模式基值(MAV_MODE 枚举),param2 填自定义模式(厂商定义)
  • 飞控回复 COMMAND_ACK,必须检查 result 字段确认是否成功
  • 常见失败原因:参数错误、任务锁定、不支持的模式