4、模式切换逻辑设计:基于状态机的模式切换逻辑,优先级管理,以及模式切换的约束条件

模式切换,说白了就是飞控的大脑在决定“现在该干什么”。

我刚开始做飞控的时候,觉得切换模式不就是改个参数吗?后来炸了一次机才明白——切换时机不对,飞机就得摔。今天咱们就把这块掰开揉碎了讲。

4.1 状态机:模式切换的骨架

飞控里的模式切换,底层就是一个有限状态机(FSM)。每个模式是一个状态,触发条件满足就跳转。

我个人习惯把状态机分成三层:

  • 顶层:飞行模式(手动、定高、悬停、返航等)
  • 中间层:子状态(比如悬停里的“位置锁定”和“速度控制”)
  • 底层:执行器状态(电机怠速、解锁、急停)

举个例子,一个最简单的悬停模式切换逻辑:

// 伪代码:悬停模式状态机
enum FlightMode {
    MANUAL,
    ALT_HOLD,
    POS_HOLD,
    RTL
};

FlightMode current_mode = MANUAL;

void mode_switch_handler(FlightMode target_mode) {
    // 检查约束条件
    if (!check_constraints(target_mode)) {
        return; // 不满足条件,拒绝切换
    }
    
    // 执行退出当前模式的动作
    exit_current_mode(current_mode);
    
    // 切换到目标模式
    current_mode = target_mode;
    
    // 执行进入新模式的初始化
    enter_new_mode(current_mode);
}

你看,逻辑很直白。但实际工程里,坑全在check_constraints()和exit_current_mode()里。

核心原则:状态机必须保证确定性——同一个输入,永远得到同一个输出。别搞什么“有时候能切有时候切不了”,那是玄学,不是工程。

4.2 优先级管理:谁说了算?

模式之间是有优先级的。你不能在返航途中突然切到手动作动,那会出大事。

我一般把优先级分成三级:

优先级 模式举例 说明
高(不可抢占) 急停、降落、返航 一旦进入,必须完成才能切出
中(可抢占) 悬停、定高、跟随 可以被更高优先级打断
低(自由切换) 手动、特技、自稳 用户随时可以切,但受约束条件限制

举个例子:飞机正在执行返航(高优先级),这时候用户发了个“切手动”指令。怎么办?

我的做法是——忽略。返航逻辑里有个标志位 rtl_in_progress,只要它置位,任何低优先级切换请求都被丢弃,直到飞机落地或者用户通过特殊指令(比如长按急停)强制打断。

注意:高优先级模式之间的切换也要小心。比如从“返航”切到“急停”,你得确保急停逻辑能正确处理当前高度和速度,别直接断电摔机。

4.3 约束条件:不是你想切就能切

模式切换不是随心所欲的。每个模式都有它的前置条件。不满足条件就硬切,轻则飞控报错,重则炸机。

常见的约束条件有这几类:

  • GPS状态:悬停、返航、航点飞行必须要有有效的GPS定位(HDOP < 2.0,卫星数 > 8)
  • 电量:电量低于20%时,禁止切入手动模式以外的模式(防止低电量大机动导致电压骤降)
  • 高度:低于2米时,禁止切入返航模式(防止误触导致飞机突然爬升撞到障碍物)
  • 传感器状态:IMU未校准、磁罗盘异常时,禁止切入任何自动模式
  • 遥控器信号:RC信号丢失时,强制切入失控保护模式(Failsafe)

我曾经遇到过一个问题:用户在地面切返航,飞机直接原地爬升撞到了树。后来查日志发现,GPS定位误差有5米,飞机以为自己在10米外,结果一爬升就撞了。从那以后,我在约束条件里加了一条:离地高度低于3米时,返航模式必须先爬升到安全高度再水平移动。

小技巧:约束条件最好做成可配置的。不同机型、不同场景,约束阈值不一样。比如测绘无人机对GPS精度要求高(HDOP < 1.5),而娱乐机可以放宽到2.5。

4.4 模式切换流程图

下面这张图,是我做飞控时最常用的一张流程图。它把模式切换的完整逻辑串起来了。

模式切换逻辑流程图 模式切换逻辑流程图 收到切换请求 检查优先级 当前模式 可被抢占? 否 拒绝切换 是 检查约束条件 约束条件 满足? 否 拒绝切换 是 执行模式切换 切换完成 说明 高优先级模式不可抢占 约束不满足时拒绝切换

这张图的核心逻辑就一句话:先看优先级,再看约束条件,都通过了才执行切换。顺序不能乱。

4.5 实战中的避坑指南

最后,分享几个我踩过的坑:

  • 不要在地面切返航:除非你确认GPS精度足够,而且周围没有障碍物。我建议在代码里加一个“离地高度低于2米禁止切返航”的保护。
  • 电量低时禁止切手动:低电量下手动大机动,电压瞬间掉到3.3V以下,飞控直接重启。我一般会在电量低于15%时强制切降落模式。
  • 传感器异常时锁定当前模式:磁罗盘受到干扰时,不要切到需要航向的模式(比如航点飞行)。保持当前模式,或者切到纯手动。
  • RC信号丢失的处理:信号丢失后,不要立即切返航。先等3秒,确认不是短暂干扰,再执行失控保护。我曾经遇到过RC信号闪断导致飞机在悬停和返航之间反复横跳的情况。

我的习惯:每次模式切换,我都会在日志里记录一条MAVLink消息(MAV_CMD_DO_SET_MODE),包含切换时间、源模式、目标模式、切换结果。这样出了问题,查日志一目了然。