第314篇 实时系统基础——硬实时与软实时
前面十几篇聊了软件架构、模块化设计和中间件。这些话题偏"设计"层面。现在开始一个全新的主题:实时系统。这是机器人软件中非常重要但经常被忽视的一块。
很多机器人工程师对实时系统的理解停留在"要快"这个层面。但实时系统的核心不是"快",而是"确定性"——在确定的时间内完成任务。一个跑得很快但偶尔超时的系统,不是实时系统。一个跑得不太快但每次都能在规定时间完成的系统,才是实时系统。
什么是实时系统
实时系统(Real-Time System)是指系统的正确性不仅取决于计算结果的正确性,还取决于结果产生的时间。如果错过了截止时间(deadline),即使计算结果是正确的,系统也被认为是失败的。
硬实时(Hard Real-Time):错过截止时间就是系统故障,可能造成灾难性后果。比如汽车的ABS防抱死系统——如果刹车控制延迟了几毫秒,可能导致车祸。机器人的紧急停机功能也是硬实时——检测到危险后必须在几毫秒内切断电机电源。
软实时(Soft Real-Time):偶尔错过截止时间可以容忍,只是性能下降。比如视频流——偶尔丢一帧用户可能注意不到,但丢太多就会卡顿。机器人的路径规划也是软实时——规划慢了一点,用上一次的路径继续执行就行。
firm real介于两者之间:错过截止时间不会造成安全问题,但会导致显著的性能下降。比如机器人的避障——如果避障计算超时,机器人可能不得不暂停等待,影响任务效率。
截止时间、延迟和抖动
实时系统中有几个关键的时间概念。
截止时间(Deadline):任务必须完成的时间点。分为硬截止时间和软截止时间。
执行时间(Execution Time):任务从开始到结束所需的时间。最坏情况执行时间(WCET, Worst-Case Execution Time)是任务在所有可能情况下最长的执行时间。实时调度分析需要知道WCET。
延迟(Latency):从事件发生到系统响应的时间。包括中断延迟(硬件中断到ISR开始执行的时间)、调度延迟(ISR就绪到实际获得CPU的时间)、通信延迟(数据从发送到接收的时间)。在ARM Cortex-M平台上,中断延迟通常在几十到几百个时钟周期。在x86平台上运行Linux,中断延迟可能达到几十微秒甚至更多,取决于系统负载和内核配置。
抖动(Jitter):任务执行时间的变化量。如果一个任务理论上应该每10ms执行一次,但实际执行间隔在9ms到11ms之间波动,抖动就是正负1ms。抖动太大会影响控制质量——控制算法通常假设采样周期是固定的。
用一个具体的例子来理解这些概念。假设你有一个电机控制任务,周期1ms(频率1kHz)。WCET是0.5ms(最坏情况下执行需要0.5ms)。截止时间是1ms(每次执行必须在下一次开始前完成)。如果因为某种原因(比如中断处理占用了CPU),某次执行延迟了0.3ms才开始,那它的完成时间就是0.3+0.5=0.8ms,还在截止时间之前。但如果延迟了0.6ms才开始,完成时间就是1.1ms,超过了截止时间——这就是实时违规。
实时系统的设计目标就是:在所有可能的情况下(最坏的负载、最多的中断、最复杂的计算路径),每个任务都能在截止时间前完成。这需要仔细的分析和设计,不是靠"跑得快"就能解决的。
实时系统的组成
一个典型的实时系统包括以下几个部分。
实时操作系统(RTOS)或者实时Linux(PREEMPT_RT)。它提供确定性的任务调度——高优先级任务能在确定的时间内获得CPU。RTOS的中断延迟通常在微秒级别,而普通Linux可能达到毫秒级别。常见的RTOS包括FreeRTOS、Zephyr、VxWorks、QNX等。选择RTOS时要考虑:支持的硬件平台、许可证模式、社区活跃度、实时性能指标。
实时驱动程序。硬件驱动不能有关中断时间太长的临界区,否则会影响其他任务的调度。在Linux中,一个常见的性能杀手是驱动中的spin_lock——如果持锁时间太长,其他CPU核心上的实时线程就无法调度。解决办法是把驱动中非关键的操作推迟到线程上下文(tasklet或workqueue),减少关中断的时间。
实时通信中间件。DDS的某些实现(如RTI Connext)是实时认证的,能保证消息在确定的时间内送达。普通TCP/IP协议栈不适合实时通信——网络拥塞时延迟不可预测。实时中间件通常用UDP或者自定义的轻量级协议来避免这个问题。
实时应用程序。控制算法、状态估计等需要在硬实时约束下运行的模块。这些模块通常用C/C++编写,避免使用动态内存分配(malloc/free的不确定性太大)、避免使用系统调用(可能触发不可预测的阻塞)、避免使用浮点运算(在某些嵌入式平台上浮点异常处理会引入延迟)。
在机器人中,通常只有最底层的控制循环需要硬实时保证(比如电机控制1kHz)。上层的感知和规划可以运行在普通的Linux上,属于软实时。两者之间通过实时中间件通信。这种"混合架构"是目前最主流的做法——既满足了底层的实时性要求,又利用了上层丰富的软件生态。
面试要点
实时和非实时的区别。面试官问"你的系统需要实时保证吗",你要能分析哪些模块需要、哪些不需要。不是所有东西都需要硬实时——把不需要实时保证的模块也放在实时线程中,反而会影响真正需要实时的模块。
WCET的分析方法。怎么确定一个任务的最坏执行时间?方法包括:测量法(跑很多次取最大值,但不能保证覆盖所有情况)、静态分析(分析代码路径,考虑所有分支和循环)、混合方法(静态分析给出上界,测量法验证)。
抖动的影响。在控制系统中,采样抖动会降低控制性能。如果控制算法假设采样周期是10ms,但实际周期在8ms到12ms之间波动,控制效果会下降。解决办法包括:用时间戳做插值补偿、在控制算法中显式处理可变采样周期、或者用硬件定时器保证精确的采样间隔。
实时系统的调试。实时问题通常很难复现和调试——因为问题可能只在特定负载下出现。常用的调试工具包括:ftrace(Linux内核跟踪工具,可以分析调度延迟)、cyclictest(测量系统的最坏延迟)、LTTng(Linux Trace Toolkit,功能强大的跟踪框架)。在嵌入式平台上,可以用GPIO翻转来测量任务的执行时间——任务开始时拉高GPIO,结束时拉低,用示波器观察波形。
优先级反转问题。这是实时系统中的经典问题:高优先级任务等待低优先级任务持有的锁,同时中优先级任务抢占了低优先级任务,导致高优先级任务被间接阻塞。解决办法是优先级继承协议——当高优先级任务等待锁时,临时提升持锁的低优先级任务的优先级,让它尽快释放锁。Linux的futex支持优先级继承。
实时系统的认证。在安全关键的应用中(汽车、航空、医疗),实时系统需要通过功能安全认证(如ISO 26262、DO-178C)。认证要求系统的时间行为可以被分析和验证——你需要证明在所有可能的情况下,每个任务都能在截止时间前完成。这需要完整的WCET分析和调度分析。
给你的建议
理解实时系统的基础概念后,建议动手体验一下。在Linux上用PREEMPT_RT补丁编译一个实时内核,写一个简单的实时程序(比如周期性的GPIO翻转),用示波器观察输出的抖动。这个过程会让你对"确定性"有直观的感受。
如果手边没有硬件,也可以用软件工具来测量。cyclictest是Linux下最常用的实时性能测试工具——它创建几个实时线程,让它们周期性地记录时间戳,然后统计时间偏差。在一台普通的x86电脑上跑cyclictest,你会看到最大延迟可能达到几百微秒。换成PREEMPT_RT内核后,最大延迟通常能降到几十微秒以内。这个对比非常直观。
面试时聊实时系统,核心要展示的是你对"确定性"和"最坏情况"的理解。不只是知道要快,还要知道怎么分析和保证时间约束。如果你能举出一个你实际解决过的实时问题的例子(比如怎么定位了一个调度延迟的bug、怎么优化了控制循环的抖动),面试官会非常感兴趣。
推荐读物:Jane Liu的"Real-Time Systems"是实时系统领域的经典教材,把调度理论讲得非常清楚。如果不想读整本书,至少看一下Rate Monotonic Scheduling和Earliest Deadline First这两个经典调度算法的原理。
下一篇预告:第315篇 RTOS与FreeRTOS详解
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)