【嵌入式】故障与降级:看门狗、保护机制和工程可靠性的底线

上一节我们讨论了中断、任务与抖动:控制量即使数值正确,也必须在正确的时刻送达执行器。

但真实设备还会遇到另一类更棘手的问题------它不只是"晚了一拍",而是传感器突然失真、通信突然中断、任务悄悄卡住,或者功率级已经接近物理边界。

此时继续按原样运行,并不叫坚持控制,而是在把未知风险送进执行器。

文章摘要

本文以单关节机械臂为例,讨论嵌入式控制系统在传感器异常、任务卡死、通信丢失、过流和过温等场景下,如何把"发现问题"变成可验证的安全动作。文章先区分故障、失效、保护与降级,再建立"检测---确认---隔离---安全状态---记录恢复"的处置链;随后说明硬件保护、软件限幅和看门狗各自能解决什么、不能解决什么,强调看门狗应监督关键控制链是否真实推进,而非被任意任务随手喂狗。最后给出分级降级、故障锁存、恢复条件和故障注入测试的工程原则。可靠性不是设备从不出错,而是出错时仍能在明确时间边界内把风险收住。并留存故障上下文。

写在前面

还是回到单关节机械臂。

它正在以较低速度搬运工件:编码器持续返回位置,电流环每 200 μs200\ \mu\text{s}200 μs 更新一次,驱动器根据 PWM 输出扭矩,控制器也按计划接收上位机给出的目标位置。表面上一切正常。

可如果某一刻编码器线缆松动,位置读数跳到一个不可能的值;或者控制任务因为一次异常资源等待而不再推进;又或者通信链路断开,上位机最后一条"继续运动"的命令仍停留在缓冲区里------系统不能只回答"这是不是一个错误码",而要回答更现实的问题:现在还能不能继续施加这个扭矩?如果不能,应在多久内把机械臂带到什么状态?

故障处理的终点不是"报出错误",而是让受控对象进入与当前风险相匹配的状态:可能是限速继续完成动作,也可能是切断驱动并保持在安全位置。

这也是嵌入式控制与普通应用程序很不一样的地方。应用程序崩溃,最多是一次服务不可用;控制系统在物理世界里继续输出,可能意味着电机持续加力、机构撞向限位,或者本应停下的设备仍在移动。

因此,这一节只追问一个问题:当传感器失真、任务失联或执行器接近危险边界时,控制系统如何识别故障、限制风险,并有序地降到一个可信的安全状态。


一、先分清四件事:故障、失效、保护与降级

工程讨论里,常把"故障"统称为所有异常;这样虽然方便,却容易把应对方式混在一起。对控制系统来说,至少要把下面四件事区分开。

概念 它描述的是什么 机械臂中的例子 系统首先该做什么
故障 某个部件、信号或环境偏离了正常假设 编码器跳变、温度传感器断线 发现异常证据
失效 某项预期功能已经不能可信地完成 位置不再可测,控制器无法确认姿态 停止依赖这项功能
保护 为限制风险而立即采取的动作 关断驱动使能、限制电流、急停 先把危险能量收住
降级 放弃部分性能,保留仍可信的能力 速度降低、只允许回零、改为保持模式 在边界内继续服务

例如,编码器偶尔出现一个毛刺,不必立刻把整机断电;它首先是一个故障迹象 。如果连续多帧位置不可信,或者双编码器长期不一致,位置闭环的基础就被破坏,这才构成了需要处置的功能失效。接下来是限扭矩、停止轨迹、切换到安全保持还是切断功率,取决于机构、负载、制动器和人机距离,而不是由一条通用规则决定。

这带来第一条底线:不要把"检测到异常"误当成"已经完成保护"。

一条错误日志、一个串口告警,甚至一次 MCU 复位,都不必然让电机停止。真正的保护必须落到能够改变物理能量流的执行路径上:例如撤销驱动使能、触发硬件刹车、切断功率级,或将控制命令限制到经过验证的安全范围。


二、先定义安全状态,再谈怎样发现故障

很多项目会先列一长串"可能发生的错误",最后才发现:即使错误被发现了,也没有定义设备该做什么。更可靠的顺序恰好相反------先为每个风险场景定义安全状态,再反推需要哪些检测与保护。

对机械臂而言,"安全"并不总等于"立刻断电"。若关掉电机后重力会使关节下坠,那么无扭矩状态反而可能更危险;若机构有抱闸,先撤销驱动、再合上抱闸可能更合适;若只是上位机暂时断连,在没有新的运动命令时维持当前位置或以受限速度回到待机位,可能比突然急停更平稳。

可以把常见安全状态理解为一组由弱到强的约束:

安全状态 仍允许什么 适合的场景 关键前提
正常运行 完整闭环与全部运动能力 无异常 传感、控制和执行链均可信
受限运行 限速、限加速度、限扭矩 温度偏高、通信质量变差 关键反馈仍可信
受控停止 停止接受新轨迹,按受限制动停下 非关键传感器异常、命令超时 仍可安全估计当前状态
安全保持 保持姿态或合抱闸,不再执行任务 位置已知但任务条件失效 保持动作本身可验证
能量隔离 禁止驱动、切断危险能量 过流、急停、位置完全不可信 独立硬件路径可动作

这里最重要的不是状态名称,而是每一种状态都必须写清三件事:谁有权进入、进入时要执行哪些原子动作、什么条件下才允许离开。

例如"通信超时"进入受控停止,不能只写成 timeout = true。它至少应包含:冻结新目标、生成有限加速度的停机轨迹、限制最大扭矩、上报原因、等待确认;如果在这个过程中又发现位置反馈失真,则应立即升级到更保守的安全保持或能量隔离。


三、保护要分层:越靠近危险能量,越不能只依赖软件

控制软件可以做很多事:给命令限幅、检查速度、判断温度、停止状态机。但当 CPU 卡死、程序跑飞,或总线已经来不及响应时,软件本身也可能成为故障的一部分。因此,保护机制必须分层,且最靠近危险能量的一层应尽量独立。

1. 快速硬件保护:先守住来不及等待的软件路径

典型例子包括:驱动器硬件过流比较器、母线过压/欠压关断、功率级的 ENABLE 引脚、急停回路、机械限位开关和抱闸。它们的共同特点是:触发后不必等待控制任务完成一次调度,也不依赖串口、CAN 或上层状态机给出结论。

这类保护解决的是"已经接近不可接受的物理边界时,谁能最快收住能量"。例如电流超过绝对上限时,驱动器应能在硬件路径中停止门极驱动;若仍先把 ADC 数据交给控制器、等软件算完再决定,保护链路就把最宝贵的响应时间交给了最不确定的部分。

2. 软件保护:在危险到来之前把系统留在可控区域

软件层更适合处理需要上下文的风险:速度接近软限位、温度持续上升、通信命令变旧、传感器出现短时异常、目标变化过快。它可以使用斜坡、滞回、状态机和任务诊断,避免系统在阈值附近反复开关或因一帧噪声误停。

但软件保护必须有明确边界。比如电流软件限幅可以防止正常控制命令过大,却不能替代硬件短路保护;位置软限位可以提前减速,却不能替代物理限位和急停;软件日志可以帮助追溯,却不能成为故障发生时的唯一动作。

3. 两层之间要能互相印证

一个实用的设计是:硬件负责"最后一道不可越过的线",软件负责"尽量别走到那条线"。软件提前限扭、减速和告警;若异常继续恶化或软件自身失去可信性,硬件关断仍能生效。

这也是可靠性设计里很重要的思想:独立性比重复更有价值。 两份运行在同一个线程、依赖同一个传感器、最终还要经过同一条 PWM 通道的"保护代码",并不能提供真正独立的兜底。


四、看门狗看守的不是"程序活着",而是关键控制链在推进

看门狗(Watchdog Timer,WDT)的常见误用,是在主循环末尾放一句 feed_watchdog()。这样做只能说明主循环还有机会绕回来,却无法说明传感器是否更新、控制任务是否运行、PWM 是否被正确锁存,甚至无法说明系统是否正卡在一个看似循环、实则没有完成任何有效工作的错误状态里。

更好的问题是:在规定时间窗内,控制系统完成了哪些不可替代的进展?

对单关节机械臂,可以把一次健康控制周期拆为以下事实:采样帧更新了;控制任务消耗了这帧数据;新的命令通过了限幅与安全检查;驱动器状态仍正常。只有这些事实都在持续发生,监督者才有资格刷新看门狗。

看门狗的价值不在于"重启一下试试",而在于当关键软件不再可信时,仍能在限定时间内撤销执行器继续施加危险能量的权限。

下面的伪代码展示的是监督关系,而非某款 MCU 的驱动模板:

c 复制代码
typedef struct {
    uint32_t sensor_seq;
    uint32_t control_seq;
    uint32_t driver_seq;
    bool     hard_fault_latched;
} HealthFrame;

void control_task(void)
{
    SensorFrame sample = read_latest_complete_frame();
    health.sensor_seq++;

    MotorCommand cmd = run_controller(sample);
    if (!command_is_safe(cmd)) {
        latch_hard_fault(FAULT_COMMAND_RANGE);
        disable_motor_enable();
        return;
    }

    write_pwm_shadow_register(cmd);
    health.control_seq++;
}

void safety_supervisor_task(void)
{
    static HealthFrame last;
    HealthFrame now = snapshot_health();

    bool chain_advanced = now.sensor_seq  > last.sensor_seq &&
                          now.control_seq > last.control_seq &&
                          driver_is_healthy();

    if (chain_advanced && !now.hard_fault_latched) {
        refresh_independent_watchdog();
    } else {
        disable_motor_enable();
        /* 不刷新看门狗:超时后由独立硬件执行复位或安全关断 */
    }
    last = now;
}

这段关系包含三条关键约束:

  • 喂狗权不能分散:通信、日志或普通后台任务不应自行刷新看门狗,否则它们可能掩盖控制链已经停止推进的事实;
  • 看门狗应尽量独立:由 MCU 内部独立时钟或外部器件计时,避免主任务卡死时计时也一同停住;
  • 复位不等于安全:若功率级在复位期间仍可能保持使能,就应让看门狗或安全回路同时影响驱动使能、抱闸或能量隔离路径。

某些系统还会使用窗口看门狗:刷新得太晚会超时,刷新得过早也会被视为异常。它能发现"错误循环高速喂狗"这一类问题,但不能替代对控制链真实进展的监督。看门狗始终只是安全架构中的一环,而不是可靠性的万能按钮。


五、降级不是"性能变差一点",而是能力边界被重新定义

设备发生异常后,只有"正常"和"断电"两种选择,往往会让系统不是过于激进,就是过于脆弱。更工程化的做法,是根据仍然可信的信息和剩余的执行能力,逐级缩小允许做的事。

一个好的降级路径不会把设备推向"带病硬撑",也不会把所有轻微异常都升级成剧烈急停。它根据风险和可观测性,选择最保守但仍合理的下一步。

以机械臂为例,可建立这样一张故障处置表:

观察到的证据 首先限制什么 可保留的能力 必须升级的条件
驱动温度持续偏高 最大电流、速度与加速度 低负载、低速度完成当前短动作 温度继续上升或越过硬件阈值
上位机命令超时 禁止新目标,冻结轨迹入口 受控减速并停在当前位置 停止过程中位置反馈异常
编码器短时毛刺 拒绝异常样本,降低速度 使用最近可信状态短时保持 连续失真或双传感器长期不一致
次要诊断任务失联 禁止非关键功能扩展 核心位置/电流闭环继续运行 失联影响到关键控制链
电流快速越界、急停输入触发 立即撤销驱动权限 通常不保留运动能力 需人工检查和明确复位流程

需要特别警惕一种错误思路:位置反馈已经不可信,却仍然尝试按原轨迹"温柔地停下来"。受控停止依赖于对当前位置、速度和执行器响应的足够信任;一旦这些前提消失,就应选择更保守的安全保持或能量隔离。降级不是为了让设备尽可能久地工作,而是为了让它只做仍能证明安全的事。


六、故障检测不能只看一个值:要看范围、关系和时间

传感器读数为零,可能是设备确实停在零位,也可能是线缆断开;电流偏高,可能是负载突然增加,也可能是采样偏置漂移。因此,单一阈值通常只能当作线索,真正可靠的检测需要从三个角度建立证据。

1. 范围是否合理

最基础的是物理范围检查:位置是否超出机构可达区间,电压是否落在 ADC 合理量程内,温度是否以不可能的速度跳变。范围检查很快,适合放在关键路径上;但它无法发现"数值看起来合理、语义却错误"的情况。

2. 多个信号之间是否自洽

位置在快速变化,速度却持续为零;PWM 已经很大,电流始终为零;编码器报告正向运动,限位开关却显示已到反向边界------这些矛盾往往比单个数值越界更早暴露问题。

这也是为什么关键设备常用双通道位置反馈、驱动器故障引脚、独立限位开关或电流与速度的交叉校验。它们并不要求每个传感器都"更精确",而是让一种错误不容易伪装成正常状态。

3. 异常持续了多久、以什么速度恶化

一帧毛刺不应触发不可逆停机;但连续十帧异常,也不能再被当作噪声。工程上常用去抖、持续时间、变化率和滞回:进入故障的阈值与恢复的阈值不同,避免系统在正常与降级之间反复跳变。

例如,可以规定温度连续高于预警线 500 ms500\text{ ms}500 ms 才进入限扭矩状态;只有降到更低的恢复线并保持一段时间,才允许解除限制。对于过流、急停等快速危险,则不等待确认窗口,直接走硬件保护路径。


七、故障状态必须可追溯、可锁存,也要有克制的恢复条件

"检测到故障后复位一下,再自动恢复运行"看似省事,实际上可能把间歇性问题藏得更深。若编码器连接不良,设备每次重启后都短暂正常,再次运动时又失真;若系统自动重新使能,操作者可能根本不知道刚才发生过一次危险的失控边缘。

因此,关键故障通常需要锁存:进入后保存原因、发生时刻、关键传感器快照和当时的控制状态;即使短暂恢复,也不自动回到完整运行。恢复应当是一个受约束的过程,而非故障标志被清零后自然发生。

一个朴素的安全状态机可以这样理解:

text 复制代码
正常运行
  ├─ 轻微且可恢复的异常 ──> 受限运行
  ├─ 通信超时或非关键功能失效 ──> 受控停止 / 安全保持
  └─ 过流、急停、关键反馈失真 ──> 能量隔离(故障锁存)

能量隔离
  └─ 原因排除 + 诊断通过 + 明确复位动作 ──> 受控初始化 ──> 正常运行

恢复前至少应确认:危险能量已被隔离;故障源不再存在;传感器值重新稳定且相互自洽;控制器完成初始化;执行器的当前状态已被重新建立。对会与人直接接触的设备,还应把"允许重新使能"的最终动作留给明确的人机交互或安全流程,而不是交给后台定时器。


八、可靠性要靠故障注入验证,而不是靠"理论上会保护"

保护路径最容易在真正需要它时暴露问题:某个中断优先级恰好压住了诊断任务,某条错误处理分支里还在等待互斥锁,或者看门狗复位了 MCU,却没有撤销驱动使能。因此,可靠性验证必须有意识地让系统"出错",并观察它是否按照设计进入安全状态。

可以从以下场景开始建立测试清单:

  1. 断开或伪造传感器数据:检查范围校验、交叉校验和故障锁存是否按预期生效;
  2. 故意冻结关键任务:验证看门狗超时后,驱动使能是否真的被撤销,而不只是软件重启;
  3. 制造通信洪峰与命令超时:观察系统是否停止接受陈旧命令,并平稳进入受控停止;
  4. 提高负载或模拟温度上升:确认限扭、限速、硬件阈值和恢复滞回的顺序正确;
  5. 记录反应时间:从异常出现到发现、从发现到撤销驱动、从撤销驱动到机构稳定,各自的最长时间都应可测量。

测试时不要只写"已触发故障"。更有价值的记录是:故障发生在什么时刻,哪一层首先发现,哪条保护路径动作,最终进入哪个状态,是否有任何一次超出设计时间边界。只有这些证据存在,可靠性才不只是文档中的承诺。


九、把这一节放回整个专栏里看

控制理论告诉我们,稳定性依赖于对系统状态和执行器的可信把握;控制算法告诉我们,最优控制、观测器和预测都建立在模型与数据仍有效的前提上;嵌入式系统则必须面对一个更直接的问题:当这些前提不再成立时,谁来阻止控制器继续把"错误的自信"变成物理动作?

  • 有限精度设计保证数值不因量化和溢出而失真;
  • 实时调度保证关键控制链不因时间抖动而失约;
  • 故障处理与降级保证当数值、时间或感知本身不再可信时,系统仍有一条可验证的退路;
  • 后续的数据与机器学习同样需要这些故障记录。没有故障标签、可信时间戳和明确的安全状态,数据只会把异常与正常混在一起。

如果说控制器回答"这一拍该输出什么",那么安全架构回答的是:在什么条件下,系统已经不应再相信这个输出。


In the end:下一步该看什么?

看门狗、硬件关断和降级状态机,并不是给系统套上一层悲观的束缚。它们恰恰让控制器可以在明确边界内更放心地运行:正常时全力发挥,异常时先收住风险,再根据仍可信的信息恢复有限能力。

到这里,嵌入式控制的三条工程底线已经连起来了:数值不能失真,时间不能失约,异常也不能失控。与此同时,系统在每一次正常运行、受限运行和故障退出时,都在产生带时间关系的真实数据。

下一节,我们将从这些数据出发,进入机器学习这一层:当精确机理模型越来越难写,嵌入式系统留下的时序数据,怎样才能成为可学习、可验证的训练样本?

相关推荐
自小吃多1 小时前
PCB布线叠层与阻抗设计笔记
笔记·嵌入式硬件
运筹说1 小时前
运筹说 第160期 | 大模型如何“思考”? Transformer架构图解
人工智能·深度学习·transformer
pjj198541 小时前
深度学习-训练,评估与数据增强
人工智能·深度学习·机器学习
DO_Community1 小时前
RAG 的 Embedding 模型需要微调吗?什么时候值得自己训练?
人工智能·llm·aigc·agent·ai编程
三小河1 小时前
在 Codex 桌面端接入 DeepSeek 模型(CC Switch 代理中转)
前端·javascript·人工智能
shmily麻瓜小菜鸡1 小时前
JS/TS 易踩坑知识点 — 自动分号插入(ASI)
开发语言·javascript·ecmascript
深圳雨林凯AI1 小时前
印花提取的批量工程:底色分离、品牌字剔除与线条锐利度的技术拆解
图像处理·人工智能
满怀冰雪1 小时前
25-迁移学习入门:加载预训练模型并微调
人工智能·python·机器学习·迁移学习·paddle
CoderYanger1 小时前
前端基础——JavaScript(WebAPI)代码案例
java·开发语言·前端·javascript·css·前端框架·html5