3、调度策略分析:时间片轮转调度、优先级抢占调度、 Deadline调度(EDF)在姿态控制中的适用性

调度策略这东西,说白了就是操作系统怎么决定「下一个该谁跑」。我见过不少做飞控的同行,一上来就选个调度算法,结果飞着飞着就出问题。嗯,这里面的坑其实挺多的。

姿态控制对实时性要求极高。你想想看,传感器数据来了,控制律算完了,执行机构得立刻响应。任何一个环节被耽误,飞机可能就翻了个跟头。所以调度策略选不对,代码写得再好也白搭。

今天我就把三种常见的调度策略掰开揉碎了讲。时间片轮转、优先级抢占、还有Deadline调度(EDF),咱们一个一个看它们在姿态控制里到底合不合适。

3.1 时间片轮转调度(Round-Robin)

时间片轮转,说白了就是大家轮流来。每个任务分一个固定时间片,时间到了就换下一个。公平是公平,但用在姿态控制上……我个人不太推荐。

为什么? 姿态控制任务有严格的周期要求。比如IMU读取必须每5ms一次,控制律计算必须每10ms一次。时间片轮转没法保证这些任务在精确的时间点被执行。万一某个任务刚好在时间片末尾被切换出去,下次轮到它可能已经超时了。

核心问题: 时间片轮转无法保证任务的截止时间(Deadline)。它只保证每个任务都能得到CPU时间,但不保证什么时候得到。

我在一个早期项目中试过用FreeRTOS的时间片轮转模式跑姿态控制。结果呢?飞行器在悬停时偶尔会抖动一下。查了半天,发现是IMU读取任务被其他任务挤占了时间片,导致数据采集间隔不均匀。后来换了调度策略,问题才解决。

适用场景: 时间片轮转适合那些对实时性要求不高、任务之间没有严格时序关系的系统。比如地面站的数据记录、日志输出等非关键任务。

3.2 优先级抢占调度(Priority-Based Preemptive Scheduling)

这是目前嵌入式实时系统里用得最多的调度策略。每个任务分配一个优先级,高优先级的任务可以随时打断低优先级的任务。嗯,这个思路很符合直觉——重要的任务先跑。

在姿态控制里,我们通常这样分配优先级:

任务类型 优先级 说明
IMU中断处理 最高 传感器数据必须第一时间读取
控制律计算 计算延迟直接影响控制效果
PWM输出 执行机构响应要快
通信任务 遥控器数据、遥测数据
日志记录 可以容忍延迟

优先级抢占调度有个经典问题——优先级反转。我曾经在一个项目中遇到过:一个低优先级的日志任务拿着某个互斥锁,结果高优先级的控制任务等着这个锁,中间还有个中等优先级的通信任务一直跑着,导致高优先级任务迟迟拿不到锁。这就是典型的优先级反转。

避坑指南: 我曾经因为没处理好优先级反转,导致飞行器在关键时刻失控。后来我养成了一个习惯——所有共享资源都用优先级继承协议或者优先级天花板协议来保护。别嫌麻烦,这能救你的飞机。

优先级抢占调度在姿态控制里是可行的,但需要你仔细设计优先级。我的建议是:

  • 中断服务程序的优先级最高
  • 周期性实时任务(IMU读取、控制律计算)次之
  • 非周期性实时任务(遥控器指令处理)再次之
  • 非实时任务(日志、调试)优先级最低

3.3 Deadline调度(EDF - Earliest Deadline First)

EDF调度,顾名思义,谁的任务截止时间最近,谁就先跑。这个策略在理论上是最优的——它能最大化系统的可调度性。说白了,只要CPU利用率不超过100%,EDF总能保证所有任务在截止时间前完成。

但理论归理论,实际用起来有不少坑。

EDF的优点:

  • 理论上最优,CPU利用率可以接近100%
  • 自动适应任务负载变化
  • 不需要手动分配优先级

EDF的缺点:

  • 实现复杂,需要维护一个就绪队列并按截止时间排序
  • 过载时表现很差——所有任务都可能错过截止时间
  • 在大多数商用RTOS中不支持,需要自己实现

我记得有一次尝试在姿态控制系统中用EDF。当时觉得这个算法很完美,结果在测试时发现一个问题:当某个传感器偶尔出现延迟时,EDF会立刻把CPU资源分配给其他任务,导致传感器读取任务被推迟。嗯,这反而加剧了问题。

我的看法: EDF在学术研究中很热门,但在实际的姿态控制系统中,我建议谨慎使用。除非你的团队有足够的实时系统经验,否则优先级抢占调度更稳妥。

3.4 三种策略对比

特性 时间片轮转 优先级抢占 EDF
实时性保证 好(需合理设计) 理论最优
实现复杂度
过载行为 所有任务受影响 低优先级任务受影响 所有任务都可能失败
RTOS支持 几乎所有RTOS 几乎所有RTOS 少数RTOS
姿态控制适用性 不推荐 推荐 谨慎使用

3.5 我的最终建议

如果你问我个人习惯用什么,我会毫不犹豫地说——优先级抢占调度。原因很简单:

  • 它足够成熟,几乎所有RTOS都支持
  • 行为可预测,过载时至少能保证关键任务
  • 调试起来相对容易

但要注意,优先级抢占调度不是银弹。你需要做好这几件事:

  1. 优先级分配要合理——别把所有任务都设成同一个优先级
  2. 处理好优先级反转——用优先级继承或天花板协议
  3. 做可调度性分析——确保在最坏情况下所有任务都能按时完成

一个小技巧: 我习惯在系统设计阶段就画一张任务时序图,把每个任务的周期、执行时间、截止时间都标出来。然后用手算一下CPU利用率。如果超过70%,我就会开始担心了。留点余量总是好的。

好了,调度策略就讲到这里。下一章咱们聊聊实际代码里怎么实现这些调度策略,包括任务创建、优先级设置、还有那些容易踩的坑。