3. 飞控软件架构:RTOS基础、任务调度与优先级

各位同学,咱们今天聊聊飞控的“大脑”——软件架构。说白了,飞控就是一块跑着实时操作系统的单片机。我刚开始接触飞控时,总觉得不就是个嵌入式程序嘛,后来被炸机教训了几次才明白:飞控软件的核心,是实时性

你想想看,飞机在天上飞,传感器数据晚来1毫秒,控制指令晚到1毫秒,结果可能就是炸机。所以,飞控必须用实时操作系统(RTOS),而不是Linux那种分时系统。

3.1 实时操作系统(RTOS)基础

RTOS和普通操作系统的最大区别,就是确定性。普通系统“尽量”在规定时间内完成任务,RTOS是“必须”在规定时间内完成。我习惯用FreeRTOS,PX4和ArduPilot底层都基于它。

核心概念:

  • 任务(Task):一个无限循环的函数,有自己的栈空间和优先级。
  • 调度器(Scheduler):决定哪个任务在什么时候运行。
  • 临界区(Critical Section):不允许被打断的代码段,通常用关中断实现。

举个例子,一个典型的飞控任务长这样:

void sensor_task(void *param) {
    while(1) {
        // 读取IMU数据
        imu_read(&accel, &gyro);
        // 等待下一个周期
        vTaskDelay(pdMS_TO_TICKS(1)); // 1ms周期
    }
}

嗯,这里要注意:vTaskDelay不是精确延时,它只是让任务挂起。真正的定时靠硬件定时器中断。

3.2 任务调度与优先级

RTOS的调度策略,说白了就是谁急谁先跑。飞控里最常见的调度方式是抢占式优先级调度:高优先级任务可以打断低优先级任务。

我曾经在项目里犯过一个低级错误:把姿态控制任务的优先级设得比传感器采集任务还高。结果呢?传感器数据还没读完,控制任务就抢跑了,用的全是上一帧的旧数据。飞控直接震荡,差点炸机。

避坑指南:

我曾经见过一个团队,把10个任务全设成同一个优先级。结果调度器按时间片轮转,关键任务经常被非关键任务打断。飞控在天上忽忽悠悠的,跟喝醉了似的。

我的建议是:优先级不要超过5级,每级只放1-2个任务。

典型的飞控任务优先级分配如下:

优先级 任务名称 周期 说明
最高 IMU采集 1ms 必须最快响应
姿态控制 4ms 依赖最新传感器数据
位置控制 10ms 可以容忍少量延迟
日志记录 100ms 优先级最低,有空才跑

3.3 飞控固件的模块划分

ArduPilot和PX4虽然代码风格不同,但模块划分思路大同小异。我两个都用过,个人更喜欢PX4的模块化设计,每个模块独立编译,调试起来方便。

咱们以PX4为例,核心模块包括:

  • 传感器驱动层:负责IMU、磁力计、气压计、GPS的原始数据读取。
  • 状态估计模块:EKF(扩展卡尔曼滤波)融合多传感器数据,输出姿态、位置、速度。
  • 控制模块:包括角度控制、角速度控制、位置控制,输出电机混控指令。
  • 导航模块:航线规划、避障、返航逻辑。
  • 通信模块:MAVLink协议,地面站和遥控器数据交互。

我的经验:

模块划分时,一定要遵循单一职责原则。一个模块只做一件事,比如传感器采集模块只管读数据,别在里面写控制逻辑。否则后期维护会想哭。

3.4 传感器数据采集与滤波任务

传感器采集是飞控的“眼睛”。我习惯把采集任务分成两级:

  1. 硬件中断级:IMU数据通过SPI或I2C中断读取,保证最低延迟。
  2. 任务级:在任务中做数据预处理和滤波,比如低通滤波、滑动平均。

为什么需要滤波?因为传感器噪声很大。我测过MPU6000,静止状态下加速度计噪声就有±0.05g。如果不滤波,控制量会抖得像筛糠。

一个简单的低通滤波实现:

// 一阶低通滤波
float low_pass_filter(float input, float prev_output, float alpha) {
    return alpha * input + (1.0f - alpha) * prev_output;
}

// 使用示例
float filtered_accel = low_pass_filter(raw_accel, prev_filtered, 0.2f);

这里alpha值越小,滤波越平滑,但延迟越大。我一般取0.1~0.3之间,具体看传感器采样率。

核心要点:

传感器采集任务必须保证时间确定性。我曾经用FreeRTOS的vTaskDelayUntil来实现固定周期采集,比vTaskDelay更精确。因为vTaskDelayUntil会补偿任务执行时间,保证唤醒间隔恒定。

最后,咱们用一张图总结本章的知识体系:

飞控软件架构核心知识体系 RTOS基础 任务调度与优先级 飞控固件模块划分 传感器数据采集与滤波 任务/调度器/临界区 驱动/估计/控制/导航 关键设计原则 • 实时性优先:所有任务必须在规定时间内完成 • 优先级合理:关键任务(IMU采集)优先级最高 • 模块解耦:每个模块只做一件事,便于调试和维护 • 滤波必要:传感器噪声必须通过低通滤波消除 • 时间确定性:使用 vTaskDelayUntil 保证固定周期

好了,这一章的内容就这些。记住一句话:飞控软件没有“差不多”,只有“精确”和“炸机”。下一章咱们深入传感器驱动,聊聊怎么把原始数据变成可用的姿态信息。


公众号:蓝海资料掘金营,微信deep3321