4、用户控制与指令触发:RC通道切换原理、MAVLink指令切换、GCS地面站切换逻辑

飞行模式切换,说白了就是告诉飞控「你现在该干嘛」。在SITL仿真里,切换方式主要有三种:遥控器通道、MAVLink指令、地面站界面操作。这三种方式底层逻辑不同,但最终都会汇聚到同一个模式管理模块。我最早做仿真时,以为它们只是入口不一样,结果踩了不少坑——嗯,今天咱们就把这三条路彻底捋清楚。

4.1 RC通道切换原理

这是最传统的方式。飞控通过接收机读取遥控器上某个通道的PWM值,然后映射到对应的飞行模式。

核心流程:

  1. 遥控器拨动开关 → 改变通道PWM值(通常1000~2000us)
  2. 接收机通过SBUS/PPM/DSM等协议传给飞控
  3. 飞控的RC输入模块解析PWM值
  4. 模式映射表根据PWM区间确定目标模式
  5. 调用模式切换函数执行切换

在SITL中,我们通过--rc-in-port参数模拟RC输入。我个人习惯在启动SITL时加上:

sim_vehicle.py -v ArduCopter --console --map --rc-in-port 14551

然后通过MAVProxy发送RC覆盖指令:

rc 5 1800   # 将通道5设为1800us,对应某个模式

关键点:通道5(RC5)是ArduPilot默认的模式切换通道。PWM区间与模式的对应关系在参数FLTMODE_CH和FLTMODE1~6中定义。

我在项目中遇到过一个问题:仿真时RC覆盖值明明发过去了,但模式没变。后来发现是SYSID_MYGCS参数没设对,地面站ID不匹配导致指令被忽略。这个坑我记了很久。

4.2 MAVLink指令切换

MAVLink方式更灵活,适合自动化测试和地面站控制。核心指令是MAV_CMD_DO_SET_MODE。

指令结构:

MAV_CMD_DO_SET_MODE
  Param1: 模式类型(MAV_MODE_FLAG)
  Param2: 自定义模式编号(如ArduPilot的4代表GUIDED)
  Param3: 自定义子模式(通常为0)

在MAVProxy中发送:

mode guided   # 简写方式
# 或者完整指令
long DO_SET_MODE 1 4 0 0 0 0 0

在Python脚本中:

from pymavlink import mavutil
master = mavutil.mavlink_connection('udp:127.0.0.1:14550')
master.mav.command_long_send(
    master.target_system, master.target_component,
    mavutil.mavlink.MAV_CMD_DO_SET_MODE,
    0,
    mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
    4,  # GUIDED模式编号
    0, 0, 0, 0, 0
)

避坑指南:我曾经在自动化测试脚本里连续发送模式切换指令,结果飞控直接卡死。原因是切换频率太快,模式管理模块来不及处理。建议每次切换后至少等待1秒,或者监听HEARTBEAT消息确认模式已变更。

4.3 GCS地面站切换逻辑

地面站(如Mission Planner、QGroundControl)切换模式,本质上是封装了MAVLink指令。你点一下按钮,地面站帮你构造并发送MAV_CMD_DO_SET_MODE。

地面站切换的典型流程:

  • 用户点击模式按钮
  • 地面站检查当前连接状态
  • 构造MAVLink消息并发送
  • 监听飞控返回的COMMAND_ACK确认
  • 更新界面显示当前模式

但这里有个细节:地面站通常还会发送SET_MODE消息(与COMMAND_LONG不同)。两种方式在ArduPilot中都能生效,但优先级不同。

切换方式 消息类型 优先级 适用场景
RC通道 PWM信号 最高(硬件中断) 手动遥控飞行
MAVLink指令 COMMAND_LONG 中 自动化脚本、GCS
地面站SET_MODE SET_MODE消息 低(可被覆盖) 快速调试

注意:在SITL仿真中,如果同时使用RC覆盖和MAVLink指令切换模式,飞控会以最后一次收到的指令为准。我见过有人调试时RC通道一直发着某个值,然后MAVLink指令发过去又被RC覆盖回来,来回跳模式。建议调试时只使用一种切换方式。

4.4 三种切换方式的底层统一

不管从哪条路进来,最终都会调用飞控的set_mode()函数。这个函数会做几件事:

  • 检查模式是否合法(参数配置里有没有启用)
  • 检查当前状态是否允许切换(比如降落过程中不能切到RTL)
  • 调用模式退出函数(离开当前模式)
  • 调用模式进入函数(初始化目标模式)
  • 更新control_mode变量
  • 发送HEARTBEAT通知地面站

下面这张图展示了完整的切换链路:

飞行模式切换逻辑总览 RC通道输入 MAVLink指令 GCS地面站 模式解析与映射(PWM→模式编号 / 指令解析) 合法性校验(模式启用?状态允许?) set_mode() 执行(退出旧模式→进入新模式) 更新 control_mode + 发送 HEARTBEAT 三种输入源最终汇聚到同一个 set_mode() 函数,区别仅在于前端的解析方式

4.5 实际仿真中的调试技巧

我在做SITL仿真时,经常需要验证模式切换逻辑。这里分享几个实用技巧:

  • 监听模式变化:在MAVProxy中执行watch HEARTBEAT,可以实时看到模式字段的变化
  • 强制切换:如果RC通道和MAVLink都失效了,可以直接修改参数FLTMODE1然后重启飞控——不过这是下下策
  • 日志分析:SITL生成的.bin日志里记录了每次模式切换的时间戳和触发源,用mavlogdump.py可以提取

个人经验:我习惯在自动化测试脚本里先通过MAVLink切换到STABILIZE模式,然后等待2秒确认,再切到LOITER。这样能避免模式切换过程中飞控状态不稳定导致的误判。你想想看,如果刚切到GUIDED模式就立刻发航点指令,飞控可能还没完成初始化——这个时序问题我吃过亏。

三种切换方式各有适用场景。RC通道适合手动飞行,MAVLink适合自动化,地面站适合调试。理解它们的底层统一逻辑,能帮你更快定位仿真中的模式切换问题。