
扫地机器人这个品类这几年从随机碰撞进化到激光导航AI避障功能越来越花哨但真正决定一台机器能不能长期稳定服役的往往不是它扫得多干净而是它会不会在某个深夜突然失控、撞坏家具、甚至把自己烧了。我拆过不下十台不同品牌的扫地机也参与过两代产品的电控架构设计越做越觉得一件事把安全相关的逻辑交给跑Linux的主控是嵌入式产品里最危险的设计习惯之一。这篇就围绕双脑架构这个思路聊聊为什么扫地机器人必须把安全职责从Linux手里拿走交给一颗独立的MCU以及这套架构具体怎么落地。1. 双脑架构到底在解决什么问题1.1 单脑方案的甜蜜陷阱很多早期扫地机包括现在一些低价走量款用的是一颗主控打天下的方案。这颗主控通常是一颗跑Linux的应用处理器比如全志、瑞芯微或者晶晨的芯片上面跑着导航算法、SLAM建图、WiFi通信、语音交互顺便还管着电机驱动、碰撞检测、悬崖检测。听起来很省成本一颗芯片全包了BOM表也好看。问题在于Linux是一个非确定性的系统。什么叫非确定性就是你让它执行一段代码它什么时候执行完、中间会不会被别的进程抢占、会不会因为内存回收卡顿几百毫秒这些都是不确定的。你在PC上感觉不到因为PC卡一下你顶多骂一句。但扫地机在高速旋转边刷、驱动轮全速前进的时候主控卡顿200毫秒机器可能已经冲下楼梯了。我实测过一台单脑方案的样机在跑大型SLAM回环检测的时候CPU占用率飙到95%以上这时候如果恰好触发悬崖传感器中断Linux内核要经过中断上半部、下半部、调度器唤醒用户态进程这一整套流程实测响应延迟能到80到150毫秒。而机器人在全速前进时轮速大约0.3米每秒150毫秒就是4.5厘米。听起来不多但悬崖边缘的容错空间往往只有2到3厘米。1.2 双脑架构的分工逻辑双脑架构的核心思想很简单让Linux专心做它擅长的事——建图、导航、路径规划、联网、人机交互让MCU专心做它擅长的事——实时响应、电机控制、传感器采集、安全保护。两者通过串口或者SPI通信各司其职。这里的关键词是实时。MCU比如STM32系列跑的是裸机程序或者RTOS中断响应延迟可以做到微秒级。悬崖传感器触发到切断电机PWM输出整个链路可以控制在1毫秒以内。这个数量级的差距就是安全和不安全的区别。我习惯把这种架构叫做决策脑和反射脑。Linux是决策脑负责我要去哪里、怎么走最优MCU是反射脑负责前面是悬崖立刻停。反射脑不需要知道全局地图它只需要对本地传感器做出即时反应。这跟人的神经系统很像——你手碰到烫的东西是脊髓反射先让你缩手大脑皮层过一会儿才反应过来哦好烫。1.3 为什么不能靠Linux加实时补丁解决有人会说Linux不是有PREEMPT_RT实时补丁吗打了补丁不就能保证实时性了这个问题我专门验证过。PREEMPT_RT确实能把最坏情况下的调度延迟从毫秒级降到几十微秒级但它有几个致命问题。第一实时补丁会显著增加内核复杂度出bug的概率上升而且很多厂商的BSP包对RT补丁支持并不完善你打上去可能WiFi驱动就挂了。第二即使调度延迟达标Linux的启动时间、内存管理、文件系统IO这些环节仍然存在不确定性一个日志写入操作就可能阻塞关键线程。第三也是最现实的——成本。为了跑LinuxRT你需要的芯片算力、内存、闪存都要往上走而一颗STM32F0或者STM32G0系列几块钱人民币就能搞定安全逻辑何必去赌Linux的实时性。注意安全逻辑的独立性原则是即使Linux完全死机、重启、跑飞安全功能也必须照常工作。这意味着MCU不能依赖Linux的任何输出才能做出安全判断。2. Linux在扫地机里到底管什么边界在哪里2.1 Linux负责的高层业务在双脑架构里Linux主控的职责边界需要划得非常清楚。它管的是慢思考和重计算的活。具体来说激光雷达的点云数据处理、SLAM建图、路径规划、房间分割、禁区设置、APP通信、OTA升级、语音识别这些都属于Linux的范畴。这些任务的共同特点是计算量大、对延迟不敏感几百毫秒的延迟用户感知不到、需要复杂的软件栈支持。比如SLAM算法动辄需要几十兆内存和大量浮点运算MCU根本扛不住。再比如WiFi协议栈和MQTT通信Linux有成熟的网络栈MCU做起来就吃力得多。我一般建议把Linux主控的任务按优先级分成三层。最高层是用户交互和联网这部分挂了顶多APP连不上不影响机器运行。中间层是导航和建图这部分挂了机器会迷路但不会造成物理伤害。最底层是运动指令下发这部分Linux只负责告诉MCU往哪走而不负责保证走的过程安全。2.2 MCU负责的底层安全MCU这边职责就非常明确了而且必须是硬实时。我列一下我经手的项目里MCU必须独立承担的功能清单悬崖检测与紧急制动红外或者ToF悬崖传感器信号直接进MCU的ADC或者GPIO检测到悬空立即切断轮子电机PWM。碰撞检测与缓冲碰撞传感器的微动开关或者霍尔元件信号进MCU触发后立即停止前进并后退。电机堵转保护通过采样电机电流或者编码器反馈判断轮子是否堵转堵转超过阈值时间立即停机。电池保护过压、欠压、过流、过温这些保护逻辑必须在MCU里独立实现不能等Linux来决策。看门狗与心跳MCU监控Linux的心跳信号如果Linux超过一定时间没有发心跳MCU判定主控异常执行安全停机。充电对接安全回充时的电流控制、温度监控、异常断开都由MCU处理。这些功能的共同点是一旦失效可能造成人身伤害或者财产损失。所以它们不能依赖Linux甚至不能依赖两者之间的通信链路。2.3 通信链路的可靠性设计Linux和MCU之间的通信通常用UART或者SPI。UART简单、可靠、成本低我大多数项目都用UART波特率115200或者921600。SPI速度快但需要更多引脚而且主从关系下MCU作为从机时Linux死机可能导致SPI总线挂死。通信协议的设计有几个要点。第一必须有帧头、帧尾、长度、校验我一般用CRC16。第二必须有序列号防止重复帧或者丢帧导致的状态错乱。第三必须有超时机制MCU如果超过500毫秒没收到Linux的有效指令就进入安全状态——停止运动等待恢复。这里有个坑我踩过早期协议设计时我把停止指令也放在正常通信帧里结果Linux死机时发不出停止指令MCU就一直保持上一次的速度跑。后来改成心跳超时自动停止才解决这个问题。安全设计的原则是安全状态应该是默认状态而不是需要指令才能进入的状态。3. MCU侧安全逻辑的具体实现3.1 悬崖检测的响应链路悬崖检测是扫地机最核心的安全功能之一。典型的实现是底部装4到6个红外对管或者ToF传感器朝下发射接收反射光。地面反射强悬崖处没有反射通过ADC读取反射强度来判断。在MCU里我通常用定时器触发ADC多通道扫描DMA搬运数据然后在ADC中断或者DMA完成中断里做判断。整个链路的时间预算是这样的ADC采样转换大约几微秒DMA搬运几微秒中断响应加上判断逻辑几十微秒然后直接操作GPIO关闭电机驱动使能或者修改定时器的PWM输出。总延迟可以控制在100微秒以内。对比一下Linux方案传感器数据要先经过I2C或者SPI进Linux驱动层处理上报到用户态用户态算法判断再通过通信链路发给MCUMCU再执行。这条链路里任何一环卡顿延迟就上去了。而且Linux的用户态调度延迟本身就不确定。我实测过两种方案的悬崖响应时间。Linux方案平均45毫秒最坏情况210毫秒。MCU方案平均0.08毫秒最坏情况0.15毫秒。差了三个数量级。这就是为什么安全逻辑必须在MCU。3.2 电机控制的实时性要求扫地机的轮子电机通常是直流有刷电机或者无刷电机用PWM驱动。MCU需要做的是根据Linux下发的目标速度通过PID闭环控制实际速度同时监控电流和编码器反馈。PID控制的周期很关键。我一般用1kHz的控制频率也就是每1毫秒执行一次PID计算和PWM更新。这个频率下MCU的CPU占用率很低STM32F1系列跑起来绰绰有余。如果用Linux来做PID1kHz的周期在非实时内核下根本保证不了实际抖动可能到几毫秒甚至几十毫秒速度控制会明显不平滑。更重要的是堵转保护。当轮子被卡住时电机电流会迅速上升。MCU在每个PID周期里采样电流如果连续N个周期电流超过阈值就判定堵转立即关闭PWM输出。这个N我一般设成50也就是50毫秒。如果等Linux来判断可能电机已经过热冒烟了。3.3 看门狗与心跳机制MCU监控Linux的方式通常是Linux用户态程序定期通过串口发送心跳帧MCU收到后重置一个软件定时器。如果定时器超时MCU判定Linux异常执行安全动作。这里有几个细节要注意。第一心跳周期不能太短否则Linux正常卡顿就会误触发也不能太长否则Linux真死了响应太慢。我一般设500毫秒心跳周期1.5秒超时。第二心跳帧里最好带上Linux的关键状态信息比如当前是否在运动、电池电量等这样MCU可以做出更合理的判断。第三MCU自身也要有硬件看门狗防止MCU程序跑飞。还有一种情况是Linux在重启。重启过程中Linux会有一段时间发不出心跳。MCU检测到心跳丢失后应该进入安全状态并等待而不是直接断电。等Linux重启完成重新建立通信后MCU再恢复正常工作。这个恢复流程要设计好否则会出现Linux重启后MCU不认它的尴尬。4. 双脑之间的通信协议怎么设计才不坑4.1 帧结构与校验通信协议是双脑架构的血管设计不好就会出现各种诡异问题。我用的帧结构一般是这样的字段长度说明帧头2字节固定0xAA 0x55序列号1字节0-255循环用于检测丢帧命令字1字节区分指令类型数据长度1字节后续数据字节数数据N字节具体载荷CRC162字节从序列号到数据的校验帧头用两个字节是为了降低误同步概率。序列号用于检测丢帧和重复帧。CRC16用标准的多项式0x1021实测能检出绝大多数传输错误。解析的时候状态机要能处理各种异常帧头只收到一半、数据长度超出预期、CRC校验失败、超时。每种异常都要有明确的处理策略比如丢弃当前帧、重新同步、请求重传等。4.2 指令优先级与安全指令的独立通道不是所有指令都同等重要。停止指令的优先级必须高于前进指令。我通常把指令分成两类安全相关指令和普通指令。安全相关指令走独立的命令字MCU收到后立即执行不排队。更进一步的做法是安全指令不仅走通信帧还可以用一根独立的GPIO线作为硬件急停信号。Linux拉低这根线MCU的中断立即响应不管串口在干什么。这根线成本极低但可靠性极高。我经手的项目里这根线救过好几次场——有一次Linux的串口驱动出bug正常帧全乱了但急停线还是好的。4.3 状态同步与故障恢复双脑之间需要同步的状态包括当前运动状态、电池信息、传感器状态、故障码等。同步策略我一般用MCU主动上报Linux按需查询的混合模式。MCU每100毫秒上报一次核心状态Linux需要详细信息时再发查询指令。故障恢复的流程要设计清楚。比如MCU检测到悬崖触发紧急停止后会进入安全锁定状态此时不接受任何运动指令直到Linux明确发送解除锁定指令并且MCU确认悬崖传感器已经恢复正常。这个锁定机制防止了传感器抖动导致反复启停的问题。5. 那些年我在双脑架构上踩过的坑5.1 通信丢帧导致的状态不一致早期项目里我遇到过一个问题Linux认为机器在前进MCU因为丢帧没收到指令实际停着。结果Linux的SLAM算法基于机器在前进的假设更新地图地图就飘了。解决办法是引入指令确认机制。MCU收到运动指令后在下一个状态上报帧里带上当前实际运动状态。Linux对比自己下发的指令和MCU上报的实际状态如果不一致就重新下发或者进入故障处理。这个机制增加了一点通信开销但换来了状态一致性。5.2 MCU复位后的状态恢复MCU因为看门狗复位或者电源波动重启后它的状态是未知的。如果MCU重启后直接进入正常工作可能会执行上一次残留的指令造成危险。我的做法是MCU启动后先进入安全初始化状态所有电机输出关闭然后等待Linux发送初始化完成指令并且完成一轮状态同步后才进入正常工作状态。这个过程大概需要几百毫秒但保证了安全。5.3 Linux OTA升级时的安全处理OTA升级是另一个容易出问题的场景。Linux在升级过程中会重启重启期间MCU收不到心跳。如果MCU直接进入安全停机那升级完成后机器就趴窝了需要人工干预。正确的做法是Linux在开始OTA之前先给MCU发一个我要升级了的指令。MCU收到后进入升级模式保持安全状态但不清除故障标志。升级完成后Linux重新连接发送升级完成指令MCU恢复正常。如果升级失败Linux回滚后重新连接MCU也能识别。5.4 电磁干扰导致的通信误码扫地机里有电机、有DC-DC、有无线模块电磁环境很恶劣。我遇到过UART通信在电机启动瞬间误码率飙升的问题。排查下来是电机换向产生的尖峰干扰通过地线耦合到了UART线上。解决办法有几个一是UART线加磁珠和TVS管二是通信协议加强校验CRC16不够就上CRC32三是关键指令重传机制四是PCB布局上把UART走线远离电机驱动区域。这些措施叠加后误码率降到了可接受范围。6. 选型与成本为什么STM32是常见选择6.1 MCU选型的几个硬指标选安全MCU我一般看这几个指标中断响应时间、GPIO翻转速度、ADC采样率、定时器数量和精度、通信外设数量、工作温度范围、供货稳定性。STM32系列在这些指标上表现均衡。STM32F0/F1系列适合成本敏感的项目STM32G0/G4系列适合需要更多外设和更高性能的项目。STM32的生态也很成熟HAL库、LL库、CubeMX工具链开发效率高。而且STM32的供货相对稳定不像某些小众MCU缺货时能让你停产。6.2 双脑架构的成本账有人觉得加一颗MCU是增加成本。算一笔账一颗STM32G030大概几块钱人民币加上外围晶振、电容、PCB面积总成本增加可能不到十块钱。但换来的是安全性的质变以及Linux主控可以选用更低算力的芯片——因为安全逻辑不用它管了它只需要跑导航和通信。反过来如果不用双脑Linux主控要承担安全逻辑你就得选更高算力、更贵、功耗更大的芯片还要承担实时性不达标的风险。这笔账算下来双脑架构在成本上未必吃亏在安全性上则是碾压。6.3 国产MCU的替代可能性这两年国产MCU进步很快GD32、华大、中微、航顺等都有可以对标STM32的产品。我在一些非安全关键的项目上用过GD32PIN to PIN兼容STM32代码移植成本低。但安全相关的项目我目前还是倾向用STM32或者经过认证的车规/工业级MCU因为安全认证、长期供货、文档完整性这些方面国产MCU还在追赶。如果要用国产MCU做安全逻辑建议至少做完整的EMC测试和长期老化测试确认在恶劣电磁环境下的可靠性。安全无小事省几块钱不值得赌。7. 测试与验证怎么证明这套架构真的安全7.1 故障注入测试双脑架构的安全性不能靠我觉得没问题来证明必须做故障注入测试。我常用的测试项包括强制杀死Linux上的关键进程看MCU是否在超时后进入安全状态。拔掉Linux和MCU之间的通信线看MCU是否停止运动。在MCU运行过程中触发硬件看门狗看复位后是否进入安全初始化。模拟悬崖传感器故障遮挡或者短路看MCU是否正确处理。在电机运行过程中突然堵转看保护是否在预期时间内触发。这些测试要反复做每次代码变更后都要回归。我一般会写一个自动化测试脚本通过调试接口控制MCU和Linux自动执行测试用例并记录结果。7.2 长时间老化测试安全逻辑的可靠性还要靠长时间老化来验证。我一般会做72小时连续运行测试让机器在测试场地里反复跑同时监控MCU的复位次数、通信误码率、传感器异常次数等指标。老化测试中我遇到过一个有意思的问题机器连续运行48小时后MCU的某个ADC通道读数开始漂移。排查下来是ADC参考电压受温度影响而机内温度在长时间运行后升高了。解决办法是改用外部基准电压源或者在软件里做温度补偿。这种问题短时间测试根本发现不了。7.3 安全逻辑的代码审查要点安全相关的代码我建议做独立的代码审查审查要点包括所有安全判断是否都有明确的阈值和超时安全状态是否默认进入而不是需要指令触发是否存在死循环或者可能阻塞的代码路径中断服务程序是否足够短是否有可能被更高优先级中断长时间阻塞所有外设初始化是否完整是否存在未初始化就使用的风险看门狗是否在正确的地方喂是否存在喂狗过于频繁导致失效这些问题看起来基础但实际项目中出问题的往往就是这些基础点。8. 从双脑到多脑架构的演进方向8.1 安全岛与功能安全随着扫地机功能越来越复杂双脑架构也在演进。一些高端产品开始引入安全岛概念也就是在MCU内部或者旁边再放一颗专门的安全芯片负责最核心的安全逻辑比如IEC 61508或者ISO 13849认证的功能安全。这种架构下主MCU负责运动控制和传感器处理安全芯片负责监控主MCU是否正常工作。安全芯片会定期检查主MCU的关键输出如果发现异常直接切断执行器电源。这比单纯的双脑架构又高了一个安全等级。8.2 异构多核的整合趋势另一个方向是异构多核SoC把Linux核和实时核集成在一颗芯片里。比如一些芯片厂商推出的LinuxRTOS双核架构一颗芯片里既有Cortex-A核跑Linux又有Cortex-M核跑RTOS两者通过片内总线通信。这种方案的好处是成本低、体积小、通信快。但缺点是隔离性不如独立双芯片——如果芯片本身出问题两个核一起挂。所以这种方案适合对成本敏感、安全等级要求不是最高的产品。真正的高安全等级产品还是倾向于独立芯片方案。8.3 我的实际选择建议根据我这些年做产品的经验给几个实际建议入门级产品可以用单脑方案但安全逻辑必须用MCU独立实现Linux只做导航和通信。中端产品标准双脑架构Linux主控安全MCU通信用UART独立急停线。高端产品双脑安全岛或者异构多核独立安全芯片满足功能安全认证要求。不管哪个等级核心原则不变安全逻辑必须独立于Linux必须有独立的硬件通道必须默认进入安全状态。这条原则我做了这么多年产品从来没见它错过。最后分享一个我在实际项目中总结的小技巧在MCU的固件里给每个安全功能都加一个自检例程上电时自动运行一遍确认传感器、执行器、通信链路都正常。如果自检失败MCU直接进入安全锁定并且通过LED或者蜂鸣器给出明确的故障指示。这个自检机制帮我提前发现过好几次硬件焊接不良的问题比等到用户手里出问题再召回成本低太多了。