首页 / 资讯中心 / 文章详情

飞控计算机为什么非硬实时不可?主流RTOS对比与选型实战

飞控计算机为什么非硬实时不可?主流RTOS对比与选型实战 ★ FEATURED ARTICLE
飞控圈里待久了你会发现一个有意思的现象只要聊到飞控计算机话题总是绕不开“硬实时操作系统”这几个字。不管是做有人机飞控的还是搞无人机的手里握着一颗 DSP 或者 ARM 处理器第一件事往往就是选一个能拍胸脯保证“绝不迟到”的系统。这篇文章我就想把这层窗户纸捅开——飞控计算机为什么非硬实时不可市面上常用的硬实时系统到底差在哪以及我在实际项目里摸索出来的那些选型和排障经验都一并摊开聊聊。内容适合正在做飞控软件、从裸机开发往 RTOS 迁移的工程师也适合想弄明白“硬实时”到底硬在哪的嵌入式开发朋友。1. 为什么飞控计算机必须先讲“硬实时”1.1 飞控计算机的任务到底有多苛刻飞行控制计算机不干别的核心工作就一句话周期性地读传感器、解算姿态、输出舵面指令。听起来简单但拆开看就麻烦了。飞行器在空中每秒钟飞几十米甚至上百米传感器数据晚到一毫秒飞控解算出来的控制量就滞后一拍舵面执行机构再晚一拍整个控制回路就是欠阻尼甚至发散。你可以把它理解成开车时打方向盘方向盘必须和车轮实时联动晚半秒就是跑偏晚一秒就是失控。飞机上飞控计算机要处理的任务也不是单一的一个循环。通常姿态估计要跑到 250 Hz 到 1 kHz导航解算可能要 50 Hz 到 100 Hz控制律输出在 50 Hz 到 400 Hz 之间再加上外部通讯、健康管理、数据记录、看门狗翻转一大堆任务挤在同一个 CPU 上跑。这时候系统调度器就必须做到一件事高优先级任务到了该运行的时间就必须在严格的时限内被推进 CPU不能被低优先级任务耽误也不能被某个异常中断堵住。这种“时限刚性”就是硬实时和软实时最大的分界线。硬实时系统还有个常被忽略的属性时间确定性。界面好看的通用操作系统也能做到“大多时候挺准时”但硬实时讲究的是最坏情况下的延迟可预测。控制领域看的是最坏情况不管概率多低只要有一天中招飞机姿态发散一次后面什么后果都撑不住。1.2 硬实时与软实时的边界软实时系统比如很多通用 Linux 方案也支持高优先级调度大多数场景下延迟不高。但它的弱点在于不可控中断处理、内存申请、驱动代码里的临界区都可能把某个任务卡在调度器外面几十毫秒。对视频播放、网络传输这种应用偶尔卡一下无非是多等一帧可对飞控来说这个“偶尔”就是事故。硬实时系统的定义其实很朴素任务的完成时限如果被突破后果是不可接受的是轮子掉下来的等级。所以工程上一般要求任务调度延迟和中断响应时间有上界这个上界可以通过分析、测试来验证而不是靠“跑分平均表现”来保证。典型的硬实时窗在微秒级中断响应三五微秒以内任务切换也是微秒量级而且要能通过各种负载压力测试把最坏延迟给测出来。1.3 通用操作系统为什么顶不上通用 OS 干不了这个活卡点主要在三处。第一是调度粒度不够硬Linux 虽然在 2.6 之后引入了实时抢占补丁但整体内核里的锁、内存子系统、块设备驱动随时可能让一个高优先级线程长时间等待。第二是内存管理不确定缺页中断、swap 换页这种机制在关键任务路径上会导致毫秒级延迟抖动这在飞控里就是时间炸弹。第三是生态和习惯问题通用系统喜欢通过复杂的驱动模型、电源管理、图形栈来覆盖更多场景功能越丰富确定性越难保证。不过我也要补一句现在主流的无人机开源飞控里有相当一部分产品把硬实时功能下放到单独的核心来跑另一颗核心才跑通用 Linux 做视觉、通信这类弱实时任务。这种做法本质上就是承认通用系统和硬实时系统各管一摊谁也别越界。2. 主流硬实时操作系统横向对比2.1 VxWorks航空电子领域的老牌主力VxWorks 是风河公司Wind River的产品在航空电子领域的历史地位基本是教科书级的。它从 80 年代就开始积累内核采用优先级抢占式调度中断延迟和任务切换时间能控制在微秒级还支持多核、内存保护、容错文件系统等。更重要的是它在适航认证上走得最早DO-178C 达到 DAL A 等级的认证案例非常多很多有人机飞控系统直接用 VxWorks 653 这种支持 ARINC 653 分区的版本。ARINC 653 是个好东西它把 CPU 时间和内存空间分成多个独立分区每个分区内再跑自己的任务集合一个分区出问题不会拖垮别的分区。不过 VxWorks 的代价也直接。商业许可证费用不低培训资料、BSP 适配、工具链都得花钱而且它的调试手段比较封闭很多细节不在公开社区里讨论。项目预算充裕、安全认证要求极高的有人机项目选它很少出大错但在小团队、快迭代的产品里它的成本和黑盒程度会让很多人犹豫。2.2 RTEMS开源航天老兵RTEMSReal-Time Executive for Multiprocessor Systems是一个开源的硬实时系统在航天领域名气很大NASA、ESA 的不少卫星和深空探测任务都用过它。RTEMS 原生支持 POSIX API 和经典的 RTEMS API任务调度、信号量、消息队列、事件、定时器一整套都齐而且许可证是 GPL 基础上的特殊许可商业闭源使用时可以避免 GPL 传染这对做商业飞控的公司是个实际考量。RTEMS 的代码结构非常透明你能把调度器源码翻到底层去验证每个细节这对讲究可信性的航空航天项目很重要。它的硬实时指标和 VxWorks 在一个量级任务切换、中断延迟都在微秒级。但它的社区规模比 FreeRTOS 小开发文档偏学术化新手入门的挫败感强而且硬件驱动库的维护靠社群试新芯片可能要自己写 BSP。我的经验是如果你要做偏航天级的载荷设备又有耐心啃源码RTEMS 是很值得压注的开源方案。2.3 FreeRTOS、NuttX 与 ChibiOS中小型无人机的务实选择小型无人机市场基本被开源实时内核统治这里不能不提 FreeRTOS。FreeRTOS 体量小内核精简调度器是典型的优先级抢占式再加上信号量、队列、软件定时器官方学习和移植资料丰富很多飞控产品外围子系统都拿它做基础内核。它的商业友好之处在于 MIT 许可闭源商用也没负担。不过 FreeRTOS 官方内核其实定位偏轻量对于大型飞控系统里需要 POSIX 兼容、多进程隔离这类高级需求的场景它并不是最顺手的选择。PX4 背后的 NuttX 则是另一路代表。NuttX 是 POSIX 风格比较完整的实时操作系统支持文件系统、网络协议栈、动态加载还支持内存管理单元能提供一定的进程隔离能力。PX4 之所以选它就是因为飞控系统不只是跑控制律还要跑各种驱动、通信、日志、参数系统太精简的内核反而碍手。ArduPilot 在不少硬件平台上跑在 ChibiOS 上ChibiOS 以高效、低资源占用和良好的线程同步原语见长特别适合主频不高、内存有限的飞控主控。你说这些系统谁更“硬实时”其实都满足飞控要求差别更多在于生态和功能裁剪的边界。工程选型时别只盯着内核指标还得看整个开发链路的成熟度。我给小型无人机团队的建议是如果只是把飞控跑起来用团队最熟的内核最稳妥如果目标是长期迭代、频繁加功能选一个有文件系统、驱动、可扩展性的系统更划算。2.4 需要关注的还有谁除了上面几位航空电子和汽车自动驾驶领域还有几个系统值得扫一眼。PikeOS 和 LynxSecure 走的是 hypervisor 加分区实时路线在同一个硬件上跑多个隔离分区一个分区跑硬实时控制另一个分区跑 Linux 做应用兼顾确定性和生态。Green Hills 的 INTEGRITY-178B 也是高安全分区系统的代表在欧美的航空和军工项目里站得很稳但生态封闭国内团队获取和上手成本高。QNX 是汽车和部分航空领域的老牌微内核实时系统它的微内核架构把驱动都隔离在用户态容错性好只是它对飞控这种传感器直接读取、执行机构直接驱动的场景来说架构有点重。这些系统的共性是都在解决同一个问题如何在高可靠场景下既保证实时性又允许足够复杂的功能迭代。说白了硬实时系统也在向“隔离”和“混合”演进安全分区慢慢成为大系统标配尤其是未来无人机进入有人机空域适航标准必然把分区隔离能力摆在台面上。3. 硬实时系统开发中必须抓牢的五个技术点3.1 任务划分与优先级分配把飞控软件做成硬实时系统第一步就是任务骨架设计。控制领域的常见做法是把任务按频率分层最高优先级给最紧迫、周期最短的姿态控制内环然后是外环导航、传感器采集、健康管理、通讯和日志。优先级分配有一条原则紧急且周期短的任务优先级要高但不能高到让其他必要任务一直饿死。飞控中常见的设计是把传感器采集放在中断里或者用一个高优先级任务做采集把姿态解算放在稍低优先级通过信号量或消息队列把数据喂过去。这里我想强调一个容易错的地方不是周期越短就该放越高。有的工程师为了“更精细”把日志任务跑到 1 kHz结果它抢在控制任务前面执行反而影响姿态解算。日志这种任务没有硬截止期完全可以丢片放到低优先级乃至空闲任务里慢慢写。任务划分的产出应该是一张表每个任务写清楚周期、最坏执行时间、截止时间、优先级、共享资源清单。这张表是后面所有优化和问题排查的地图千万不要图省事跳过。3.2 共享资源与优先级反转硬实时系统里最常见的翻车现场就是优先级反转。1997 年火星探路者上出现过一次著名事故一个低优先级任务长期霸占共享总线导致高优先级任务迟迟拿不到资源系统最终看门狗复位。后来 NASA 的工程师发现是 VxWorks 的互斥信号量默认没有优先级继承低优先级任务可以先拿信号量再被中等优先级任务抢占高优先级任务就只能干等。这个案子后来成了 RTOS 教材里的标准案例。解决优先级反转的手段主要有三种优先级继承、优先级天花板、以及使用非阻塞的无锁设计。优先级继承是指低优先级任务持有信号量时临时把它的优先级抬高到和等待者相同一旦释放再降回来这样中等优先级任务就没机会插队。优先级天花板则是直接把持有信号量的任务优先级提到所有可能等待它的任务的最高值逻辑更简单但保守。实际开发时你要逐个检查每个共享资源的使用场景飞控里传感器数据、日志缓冲、参数系统都是高发区该加继承的加继承该拆缓冲的拆缓冲。绝对不要为了省事把整个临界区用关中断包起来一旦关中断时间超过几十微秒实时性防线就破了。3.3 中断处理与时间确定性中断在硬实时系统里是把双刃剑。传感器数据来了走中断可以第一时间把数据搬进内存避免查询浪费 CPU。但中断服务函数ISR里绝不能做复杂业务处理常见错误是在 ISR 里做浮点运算、申请动态内存、调用阻塞 API这些操作会让中断占用时间失控。标准做法是 ISR 只做“拿数据、存队列、发信号量、快速清现场”复杂处理由高优先级任务来干。这既是实时性要求也是系统稳定性的共识。另外要特别关注中断优先级和任务优先级的关系。很多内核把中断优先级放在所有任务之上这意味着即便最高优先级任务正在运行一次高优先级中断也能立刻打断它。如果外部设备的中断频繁且处理时间长任务延迟就会飙升。飞控系统里IMU 数据通常用 SPI 或 I2C 每次小批量读取中断处理要控制在微秒级别。排查抖动问题时我一般先用逻辑分析仪拉出任务实际执行时刻再把系统中每个中断的触发频率和执行时长列出来挨个对。多数“任务偶发超时”的案子最后都是某个外设中断在捣乱。3.4 内存管理与确定性分配硬实时系统在内存管理上的态度和通用系统截然不同。通用系统喜欢动态分配随时申请随时释放硬实时任务则要求最坏执行时间可分析动态堆分配恰恰是分析的大敌因为堆管理器在最坏情况下可能遍历整个空闲链表造成微秒甚至毫秒级的抖动。飞控里常见的做法是启动阶段一次性分配好所有任务栈、消息队列、缓冲区运行期间不再动态申请。团队里应立个规矩进入飞行任务状态后禁止调用 malloc、new 这类动态分配接口。任务栈大小也是重灾区。栈太小会溢出踩内存栈太大又浪费 RAM。我们在飞控上一般先在裸环境里给每个任务设一个保守偏大的栈跑完整个任务流程后在特定位置填充标记字等任务退出后检查标记字被破坏的程度反复迭代收敛出安全栈大小。市面上的 RTOS 基本都带栈溢出检测钩子开发阶段全开哪怕性能损失一点也值得稳定后如果实测余量够再考虑关闭部分检测。3.5 时钟管理与看门狗策略硬实时系统的时间基准来自系统 tick 定时器常用的是 1 ms 到 10 ms 一个 tick。任务延迟、超时判断、软件定时器都依赖 tick但需要注意飞控中真正驱动控制律的还是高精度硬件定时器而不是系统 tick。比如控制周期 400 Hz你不可能用 1 ms tick 去凑应该在定时器中断里直接启动一个周期任务或解锁信号量让控制律和外部时钟严格对齐。看门狗是另一件必须认真对待的事。飞控计算机的看门狗一般分两级芯片看门狗和外部独立看门狗。很多人的误区是只在一个任务里喂狗这个任务不卡死就以为系统没事。正确做法是设计一个“死亡侦测”机制用喂狗任务检查关键任务是否在各自周期窗口内正确表态比如每个控制周期更新一个心跳计数喂狗任务发现心跳停滞就拒绝喂狗并触发复位或安全模式的切换。如果整机有独立的飞行终止监控这条链路还要和底层硬件联动否则看门狗只保护了软件保护不了执行机构的机械故障。4. 选型与排障的实战经验4.1 选型阶段容易踩进的坑我做过的几个飞控项目里选型阶段最常见的坑是把“跑分”当标准。有人拿两个系统跑了一个任务切换基准测试然后就说 A 比 B 快最后整体开发时才发现 A 的可用外设驱动少得可怜BSP 是你从零开始啃。实际上硬实时系统的差距更多体现在工具链、BSP 覆盖、调试手段和认证合规度上。一个成熟系统哪怕单个指标慢两微秒但驱动齐全、调试手段先进、网上问题案例多综合收益远比那两微秒高。还有个常见问题是被“免费”蛊惑。开源系统确实省了许可费但你要评估定制维护的人力成本。用开源 RTOS 做飞控意味着你随时要自己补驱动、修内核 bug还要应对社区升级带来的兼容性问题。反过来商业系统高昂的许可费里其实包含了技术支持、更新维护和认证文档对于很多安全敏感项目来说这笔钱花得值。我的建议是把 5 年总成本做一张表把许可、培训、移植人力、风险应对全部量化再决定走开源还是商业路线。4.2 调度配置错误引发的“灵异”问题有一次我们排查一个飞控偶发抖动的案子现象很怪地面测试几个小时不出事一上天转几圈就出现一次执行机构跳跃。最初怀疑是控制律 bug后来把任务执行时序拉出来才发现是低优先级的无线数传任务在特定时刻发送大包占用了共享 SPI 总线而 IMU 采集任务用的 DMA 刚好也被总线仲裁拖延姿态数据进来晚了整整两个周期。底层原因就是 SPI 总线上没有做访问优先级管理低优先级任务也能发起长时间的冲突访问。解决办法是把所有外设访问统一收口到一个高优先级驱动任务低优先级任务只能通过队列请求数据同时给 DMA 传输设置超时保护。这类“灵异”现象绝大多数不是 CPU 算不过来而是共享总线和资源调度上出了问题。另一类高发问题出在队列水位上。飞控里常用消息队列在任务间传递数据如果某个任务消费速度略慢于生产速度队列会周期性堆积。到了满队列后生产者被阻塞开始拖延自己的 deadline而你可能根本察觉不到因为消费任务看起来还在正常工作。我们后来在关键队列上都加了水位监控超过阈值就报警并触发降级逻辑把故障暴露在处理链路上而不是让它在角落里慢慢变成定时炸弹。4.3 调试验证的三个土办法正规的硬实时系统开发基本靠硬件在环仿真HIL、时间分析工具加逻辑分析仪做验证但实际项目里我还特别依赖三个“土办法”。第一个是 GPIO 脉冲标记法在任务入口和出口翻转一个 GPIO用逻辑分析仪或者示波器把每个任务的实际执行窗口拉出来最坏执行时间一目了然。第二个是心跳计数器在每个任务里维护一个监测变量看门狗任务定期检查这些变量的更新频率和间隔抖动可以快速发现哪个任务被饿着了。第三个是故障注入测试人为提高某个任务的负载或者在中断里插入延时看调度器能不能保持其他任务的时限这在硬件投入有限时特别管用。直接说一个我强烈建议的习惯飞控软件里永远保留一个“Debug 模式”可以按需开关日志、执行统计、时序标记这些功能在低速模式下跑正常飞行时全部关闭。不要以为上量产后就不需要了我曾经为了一个问题来回烧一个星期的板子最后发现是忘了打开执行统计。把这些调试能力编译进系统配合动态配置能省下大量排障时间。5. 我对飞控硬实时系统的一点体会写了这么多最想表达的一件事是硬实时操作系统不是买回来装上就能保平安的“保险”它是一个需要你从任务设计、优先级调度、资源管理到异常处理全链条投入思考的地基。我见过不少团队花了大价钱选了 VxWorks却因为 ISR 写得乱七八糟最后实时性还不如别人用 FreeRTOS 认真调出来的效果。反之我也见过一个小团队用开源内核把每个任务的最坏执行时间测到明明白白最终顺利通过苛刻的转阶段评审。关键差别从来不在系统品牌而在团队对“确定性”的执念。飞控计算机的硬实时问题说到底是一个工程问题你要在规定时间里拿到数据、算出结果、发出指令并且要能证明这个链条在最恶劣的条件下依然成立。希望这篇文章能帮你把选型思路捋得更清楚也能在真正面对任务超时、优先级反转、总线冲突这些问题时少走一点弯路。
阅读完成 · 觉得有帮助?
咨询建站