3. RTOS选型与配置:主流RTOS对比与内核裁剪
做飞控这些年,我换过好几款RTOS。说实话,没有哪款是完美的。关键看你的项目需要什么。今天我就把FreeRTOS、RT-Thread、Zephyr这三款主流系统掰开揉碎了讲,顺便聊聊内核裁剪和调度策略。
3.1 主流RTOS横向对比
先看一张对比表,心里有个底:
| 特性 | FreeRTOS | RT-Thread | Zephyr |
|---|---|---|---|
| 内核大小 | 极小(4-9KB) | 中等(10-20KB) | 较大(20-50KB) |
| 任务数量 | 无硬限制 | 无硬限制 | 无硬限制 |
| 调度策略 | 抢占式+时间片 | 抢占式+时间片 | 抢占式+时间片+协作式 |
| IPC机制 | 队列、信号量、互斥量 | 邮箱、消息队列、信号量 | FIFO、栈、信号量、邮箱 |
| POSIX支持 | 有限 | 部分 | 较好 |
| 社区活跃度 | 极高 | 高(国内) | 中(Linux基金会) |
| 典型场景 | 资源受限MCU | IoT、智能硬件 | 多协议、多架构 |
我个人习惯,小四轴、穿越机这类资源紧张的项目,首选FreeRTOS。它轻量、稳定,文档也全。RT-Thread我用的不多,但它的组件丰富,适合做带网络功能的飞控。Zephyr嘛,我最近在玩,它的驱动框架确实强,但学习曲线陡。
3.2 内核裁剪与配置
RTOS不是越大越好。你想想看,飞控芯片就那点Flash和RAM,能省则省。内核裁剪说白了就是「去掉你用不到的功能」。
裁剪的核心原则:
- 只保留你需要的IPC机制。比如只用信号量,就把队列和邮箱关掉。
- 关掉调试输出。很多RTOS默认开了printf,这在正式产品里是浪费。
- 调整任务栈大小。默认栈往往偏大,我习惯先设小一点,跑起来再调。
FreeRTOS裁剪示例(FreeRTOSConfig.h):
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 20 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 8 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
我曾经在一个项目里,默认配置下FreeRTOS占了12KB Flash。裁剪后降到6KB,省出来的空间刚好放一个传感器驱动库。嗯,这里要注意:裁剪后一定要做压力测试,别省出bug来。
3.3 任务调度策略
调度策略是RTOS的灵魂。飞控里最常用的就两种:抢占式和时间片轮转。
3.3.1 抢占式调度
说白了就是「高优先级任务来了,低优先级的立马让路」。这在飞控里是刚需。比如姿态解算任务优先级最高,一旦有传感器数据更新,它必须立刻抢到CPU。
我遇到过一个问题:两个任务优先级相同,但一个任务里有个死循环,结果另一个任务永远跑不了。后来我强制给每个任务设了不同的优先级,才解决。
避坑指南:我曾经把姿态解算任务优先级设得过高,导致低优先级的通信任务饿死。后来我加了个看门狗,低优先级任务如果长时间没运行,就临时提升它的优先级。这招挺管用。
3.3.2 时间片轮转
当多个任务优先级相同时,时间片轮转就派上用场了。每个任务轮流跑一个固定时间片,比如1ms。这样谁都不会饿死。
但要注意:时间片太短,上下文切换开销大;时间片太长,实时性变差。我一般设5ms,飞控里够用。
警告:时间片轮转不能保证确定性。如果你的任务有严格的截止时间,还是用抢占式+优先级吧。
3.4 调度策略选择建议
我总结了一个简单规则:
- 关键任务(姿态解算、控制输出)→ 抢占式,高优先级
- 中等任务(传感器读取、数据融合)→ 抢占式,中优先级
- 非关键任务(日志、通信)→ 时间片轮转,低优先级
你想想看,飞控里最怕什么?怕姿态解算被中断。所以它的优先级必须最高。其他任务,能忍就忍忍。
3.5 知识体系结构图
下面这张图,是我梳理的RTOS选型与配置的核心逻辑:
这张图把整个流程串起来了:先选型,再裁剪,最后定调度策略。每一步都影响飞控的实时性。我个人建议,新手先从FreeRTOS入手,等摸透了再尝试RT-Thread或Zephyr。
小技巧:我习惯在项目初期就定好调度策略,而不是等代码写完了再改。因为任务优先级一旦定死,后面改起来牵一发动全身,特别麻烦。
好了,这一章就聊到这儿。RTOS选型没有标准答案,关键看你的飞控需要什么。下一章我们聊聊任务间通信,那又是另一个坑了。