4. 覆盖优先级设计:手动模式覆盖,自动模式覆盖,紧急情况下的覆盖逻辑

优先级设计,说白了就是给飞控系统定个规矩——当多个控制源同时抢着发指令时,到底听谁的?

我刚开始做飞控那会儿,觉得这事儿挺简单:谁最后发指令就听谁的呗。结果有一次试飞,手动模式和自动模式打架,飞机在空中左右摇摆,差点炸机。嗯,从那以后我才真正重视起优先级设计来。

4.1 为什么需要覆盖优先级?

你想想看,飞控系统里同时存在好几个控制源:

  • 遥控器的手动摇杆输入
  • 自动驾驶的航线跟踪指令
  • 地面站的紧急指令
  • 机载传感器的保护触发

这些控制源如果同时生效,飞控就懵了。所以必须有一套清晰的优先级规则,告诉系统:谁的话最管用,谁的话可以忽略。

核心原则:安全第一,手动优先于自动,紧急情况优先于一切。

4.2 三层优先级模型

我个人习惯把覆盖优先级分成三层,从高到低排列:

优先级 层级名称 典型场景 覆盖源
最高 紧急覆盖层 失控保护、地理围栏、电池低压 传感器、安全逻辑
中等 手动覆盖层 遥控器切回增稳、手动干预 RC接收机、地面站
最低 自动覆盖层 航线飞行、悬停、返航 自动驾驶算法

说白了,自动模式是最听话的,它随时可以被手动模式打断。而手动模式呢,又得给紧急情况让路。这个模型我在PX4和ArduPilot里都验证过,基本通用。

4.3 手动模式覆盖逻辑

手动覆盖,就是飞行员通过遥控器强行接管飞机。这里有个关键点:不是所有手动输入都能覆盖自动模式。

我建议这样设计:

  • 摇杆位移超过死区阈值(比如20%),触发手动覆盖
  • 模式切换开关从Auto拨到Stabilize,立即生效
  • 油门杆拉到最低(0油门),触发紧急降落

避坑指南:我曾经遇到过一个问题——遥控器信号偶尔会跳变,导致误触发手动覆盖。后来加了个去抖逻辑:连续3个控制周期都检测到覆盖信号,才真正切换。这个经验分享给你。

4.4 自动模式覆盖逻辑

自动模式覆盖,指的是自动驾驶系统在某些条件下主动接管控制权。比如:

  • 电池电压低于3.5V/cell,自动触发返航
  • GPS信号丢失超过5秒,自动切换为悬停
  • 高度超过地理围栏上限,自动下降

这里要注意:自动覆盖不能和手动覆盖冲突。我见过一个设计缺陷——手动模式正在降落,结果自动返航逻辑检测到电池低压,强行拉起飞机。这多危险啊!

正确的做法是:自动覆盖只在手动模式未激活时生效。如果飞行员正在手动操作,自动覆盖只发出警告,不强制执行。

4.5 紧急情况下的覆盖逻辑

紧急情况是最高优先级,它甚至可以打断手动操作。常见的紧急覆盖场景:

  1. 失控保护(Failsafe):RC信号丢失超过1秒,自动触发降落或返航
  2. 地理围栏越界:飞机飞出设定范围,强制掉头
  3. 传感器故障:IMU数据异常,立即切换为备用传感器
  4. 碰撞检测:超声波或视觉传感器检测到障碍物,紧急刹车

警告:紧急覆盖一旦触发,必须记录日志。我遇到过一起事故——紧急覆盖触发了,但日志里没记录,事后根本查不出原因。所以,所有覆盖事件都要写入黑匣子,包括触发时间、触发源、执行动作。

4.6 优先级仲裁器实现

实际代码里,我习惯用一个仲裁器模块来处理优先级。核心逻辑很简单:

// 伪代码:优先级仲裁器
typedef enum {
    PRIORITY_EMERGENCY = 0,  // 最高
    PRIORITY_MANUAL   = 1,
    PRIORITY_AUTO     = 2    // 最低
} PriorityLevel;

typedef struct {
    PriorityLevel level;
    float roll_cmd;
    float pitch_cmd;
    float yaw_cmd;
    float throttle_cmd;
} ControlSource;

ControlSource arbitrate(ControlSource sources[], int count) {
    ControlSource winner = sources[0];
    for (int i = 1; i < count; i++) {
        if (sources[i].level < winner.level) {
            winner = sources[i];
        }
    }
    return winner;
}

你看,代码其实不复杂。但实际工程里,难点在于:如何判断一个控制源是否「有效」?比如手动模式,如果摇杆没动,算不算有效覆盖?我个人习惯加个超时机制——如果某个控制源超过100ms没更新数据,就认为它失效了,自动降级到下一优先级。

4.7 覆盖优先级流程图

下面这张图是我自己画的,把整个覆盖逻辑串起来了:

覆盖优先级仲裁流程图 多个控制源输入 优先级仲裁器 比较各控制源的优先级等级 是否有紧急 覆盖信号? 执行紧急覆盖 忽略其他所有输入 手动模式 是否激活? 执行手动控制 自动模式被覆盖 执行自动模式指令

4.8 实际工程中的坑

最后聊几个我踩过的坑:

  • 优先级反转:低优先级任务占用了高优先级需要的资源。比如自动模式占用了串口,紧急覆盖想发指令发不出去。解决办法是给紧急覆盖预留独立通道。
  • 覆盖死锁:两个覆盖源互相等待对方释放。我遇到过手动模式和自动模式同时要求控制舵机,结果舵机卡在中间位置。后来加了超时释放机制才解决。
  • 优先级穿透:高优先级覆盖结束后,低优先级指令突然生效,导致飞机抖动。建议加个平滑过渡,比如用100ms的时间把控制量从覆盖值渐变到正常值。

我的习惯:每次设计优先级逻辑,我都会画一张状态机图,把所有可能的覆盖路径走一遍。然后写单元测试,模拟各种覆盖组合。虽然麻烦,但能省掉后面试飞时的很多麻烦。

优先级设计,说白了就是给飞控系统立规矩。规矩立好了,飞机就听话。规矩立不好,它就跟你对着干。嗯,希望这些经验对你有帮助。