4. 覆盖优先级设计:手动模式覆盖,自动模式覆盖,紧急情况下的覆盖逻辑
优先级设计,说白了就是给飞控系统定个规矩——当多个控制源同时抢着发指令时,到底听谁的?
我刚开始做飞控那会儿,觉得这事儿挺简单:谁最后发指令就听谁的呗。结果有一次试飞,手动模式和自动模式打架,飞机在空中左右摇摆,差点炸机。嗯,从那以后我才真正重视起优先级设计来。
4.1 为什么需要覆盖优先级?
你想想看,飞控系统里同时存在好几个控制源:
- 遥控器的手动摇杆输入
- 自动驾驶的航线跟踪指令
- 地面站的紧急指令
- 机载传感器的保护触发
这些控制源如果同时生效,飞控就懵了。所以必须有一套清晰的优先级规则,告诉系统:谁的话最管用,谁的话可以忽略。
核心原则:安全第一,手动优先于自动,紧急情况优先于一切。
4.2 三层优先级模型
我个人习惯把覆盖优先级分成三层,从高到低排列:
| 优先级 | 层级名称 | 典型场景 | 覆盖源 |
|---|---|---|---|
| 最高 | 紧急覆盖层 | 失控保护、地理围栏、电池低压 | 传感器、安全逻辑 |
| 中等 | 手动覆盖层 | 遥控器切回增稳、手动干预 | RC接收机、地面站 |
| 最低 | 自动覆盖层 | 航线飞行、悬停、返航 | 自动驾驶算法 |
说白了,自动模式是最听话的,它随时可以被手动模式打断。而手动模式呢,又得给紧急情况让路。这个模型我在PX4和ArduPilot里都验证过,基本通用。
4.3 手动模式覆盖逻辑
手动覆盖,就是飞行员通过遥控器强行接管飞机。这里有个关键点:不是所有手动输入都能覆盖自动模式。
我建议这样设计:
- 摇杆位移超过死区阈值(比如20%),触发手动覆盖
- 模式切换开关从Auto拨到Stabilize,立即生效
- 油门杆拉到最低(0油门),触发紧急降落
避坑指南:我曾经遇到过一个问题——遥控器信号偶尔会跳变,导致误触发手动覆盖。后来加了个去抖逻辑:连续3个控制周期都检测到覆盖信号,才真正切换。这个经验分享给你。
4.4 自动模式覆盖逻辑
自动模式覆盖,指的是自动驾驶系统在某些条件下主动接管控制权。比如:
- 电池电压低于3.5V/cell,自动触发返航
- GPS信号丢失超过5秒,自动切换为悬停
- 高度超过地理围栏上限,自动下降
这里要注意:自动覆盖不能和手动覆盖冲突。我见过一个设计缺陷——手动模式正在降落,结果自动返航逻辑检测到电池低压,强行拉起飞机。这多危险啊!
正确的做法是:自动覆盖只在手动模式未激活时生效。如果飞行员正在手动操作,自动覆盖只发出警告,不强制执行。
4.5 紧急情况下的覆盖逻辑
紧急情况是最高优先级,它甚至可以打断手动操作。常见的紧急覆盖场景:
- 失控保护(Failsafe):RC信号丢失超过1秒,自动触发降落或返航
- 地理围栏越界:飞机飞出设定范围,强制掉头
- 传感器故障:IMU数据异常,立即切换为备用传感器
- 碰撞检测:超声波或视觉传感器检测到障碍物,紧急刹车
警告:紧急覆盖一旦触发,必须记录日志。我遇到过一起事故——紧急覆盖触发了,但日志里没记录,事后根本查不出原因。所以,所有覆盖事件都要写入黑匣子,包括触发时间、触发源、执行动作。
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的时间把控制量从覆盖值渐变到正常值。
我的习惯:每次设计优先级逻辑,我都会画一张状态机图,把所有可能的覆盖路径走一遍。然后写单元测试,模拟各种覆盖组合。虽然麻烦,但能省掉后面试飞时的很多麻烦。
优先级设计,说白了就是给飞控系统立规矩。规矩立好了,飞机就听话。规矩立不好,它就跟你对着干。嗯,希望这些经验对你有帮助。