4. 实时操作系统与任务调度
闭环控制对时间的要求不是“平均够快”,而是“每一次都不能太晚”。以典型的电流环为例,若采样周期为 100 μs,控制器必须在下一个周期到来前完成 ADC 读取、坐标变换、PI 运算与 PWM 更新;一旦某次抖动超过周期,输出就会用到过期状态,轻则相位裕度下降,重则振荡。因此本章关注的不是操作系统“能不能跑”,而是它能否为控制任务提供可界定的最坏情况响应时间(WCET 与调度延迟)。
RTOS 与通用 Linux 的调度差异
RTOS(如 FreeRTOS、Zephyr、RT-Thread)的核心特征是抢占式优先级调度 + 确定性中断延迟。任务按优先级就绪,高优先级任务一旦满足条件立即抢占低优先级任务,调度器本身开销固定且可分析。通用 Linux 追求吞吐与公平,其 CFS 调度器按权重分配 CPU 时间,内核中大量不可抢占区(自旋锁、中断关闭段)会引入毫秒级抖动,直接用于 1 kHz 以上闭环控制并不可靠。
Linux PREEMPT_RT 通过把自旋锁替换为可睡眠的 rtmutex、将中断处理线程化(threaded IRQ)、使大部分内核代码可抢占,把最坏调度延迟从毫秒级压到几十微秒量级。它仍不是硬实时,但配合 CPU 隔离、优先级设置与实时任务编程约束,足以支撑 1~10 kHz 的软实时闭环。
中断管理:把不确定性关进笼子
中断是实时性最大的敌人,也是最大的帮手。ADC 转换完成、编码器捕获、通信收包都依赖中断触发。问题在于:中断处理程序(ISR)运行在中断上下文,会抢占包括控制任务在内的一切,且不可睡眠。若 ISR 里做浮点运算、打印日志或等待信号量,控制周期立刻被破坏。
正确做法是顶半部/底半部分离:ISR 只做最紧急的事——读取硬件寄存器、清除中断标志、把数据放入无锁环形缓冲区,然后唤醒一个高优先级线程做后续处理。在 PREEMPT_RT 下,request_threaded_irq() 的 handler 在硬中断上下文执行,thread_fn 在内核线程中执行,天然实现这种分离。示例参数:ADC 采样率 20 kHz,ISR 执行时间控制在 2 μs 以内,thread_fn 优先级设为 85,控制任务优先级 80,确保数据就绪后控制任务能及时被唤醒。
任务优先级分配与周期保障
优先级分配遵循速率单调(Rate Monotonic)原则:周期越短、截止时间越紧的任务,优先级越高。一个典型的边缘 AI 闭环控制系统可划分为:
- 电流环任务:周期 100 μs,优先级 90,负责 ADC 采样、Clarke/Park 变换、PI 调节、SVPWM 更新;
- 速度/位置环任务:周期 1 ms,优先级 70,读取编码器、计算速度、输出电流指令;
- AI 推理任务:周期 10 ms,优先级 50,运行轻量神经网络做状态预测或异常检测;
- 通信与日志任务:非周期,优先级 20,处理 EtherCAT/CAN 上报与本地记录。
优先级数值越大越高(Linux SCHED_FIFO 语义)。控制任务必须使用绝对时间唤醒,避免相对睡眠导致的周期漂移。下面是一段可参考的周期任务骨架:
struct timespec next;
clock_gettime(CLOCK_MONOTONIC, &next);
while (running) {
/* 绝对时间推进一个周期 */
next.tv_nsec += 100000; /* 100 μs */
if (next.tv_nsec >= 1000000000) {
next.tv_nsec -= 1000000000;
next.tv_sec++;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
/* 控制计算:读 ADC → 变换 → PI → 写 PWM */
control_step();
}
判断周期是否守住,不能只看平均值。应在控制任务入口和出口各打一个 GPIO 翻转或读取 TSC,用示波器或逻辑分析仪统计最大执行时间与唤醒抖动。若最大抖动持续超过周期的 20%,说明存在优先级反转、缺页或中断风暴,需要进一步排查。
闭环周期保障的检查清单
| 检查项 | 目标值(示例) | 验证方法 |
|---|---|---|
| 控制任务调度策略 | SCHED_FIFO,优先级 80~99 | chrt -p <pid> 查看 |
| 唤醒抖动 | < 10 μs | GPIO 翻转 + 示波器 |
| 单周期执行时间 | < 周期的 60% | TSC 差值统计最大值 |
| 中断线程优先级 | 高于控制任务 5~10 | ps -eLo pri,comm 查看 |
| 内存锁定 | mlockall 成功 | 返回值检查 + /proc/<pid>/status |
| CPU 隔离 | 控制核无其他任务 | taskset / isolcpus 确认 |
最后要强调:实时性不是靠“调大优先级”堆出来的,而是靠可分析的时间预算。每个周期内,中断、调度器、控制计算、AI 推理共享同一颗 CPU,必须为最坏情况留出余量。当 AI 推理任务偶尔超时,应让它降级或跳过,而不是拖垮电流环。这种“关键任务优先、非关键任务可丢弃”的设计,才是边缘 AI 闭环控制系统稳定运行的基础。