:Linux+MCU安全設(shè)計實戰(zhàn))
1. 掃地機器人雙腦架構(gòu)到底在解決什么問題掃地機器人這個品類從最早的隨機碰撞式走到今天的激光導(dǎo)航、視覺SLAM硬件方案已經(jīng)迭代了十幾輪。但如果你拆過幾臺主流機型會發(fā)現(xiàn)一個很有意思的現(xiàn)象幾乎所有的中高端掃地機內(nèi)部都不是一顆芯片在干活而是至少兩顆——一顆跑Linux的應(yīng)用處理器一顆跑RTOS的MCU。這個結(jié)構(gòu)在圈內(nèi)被叫做“雙腦架構(gòu)”也有人叫“主控協(xié)處理”或者“APMCU”方案。為什么非要搞兩顆芯片一顆性能強一點的SoC全包了不行嗎這個問題我在早期做原型機的時候也想過當(dāng)時覺得多加一顆MCU純粹是增加BOM成本和PCB面積。但真正把機器跑起來、跑夠幾百小時之后我才理解這個設(shè)計的必要性——它本質(zhì)上不是性能問題而是安全問題。具體來說掃地機器人是一個“移動的、帶旋轉(zhuǎn)部件的、有大電流驅(qū)動的、可能撞到人或?qū)櫸锏牡孛嬖O(shè)備”。它同時具備幾個危險屬性第一它有輪子會自己跑第二它有滾刷和邊刷會卷東西第三它有風(fēng)機和電池涉及大功率第四它工作在有人活動的家庭環(huán)境里可能碰到小孩、寵物、電線、液體。這些屬性疊加起來意味著它的任何一次控制失效都可能造成物理傷害或財產(chǎn)損失。而Linux恰恰是一個在實時性和確定性上“不太靠譜”的系統(tǒng)。這不是說Linux不好而是它的設(shè)計目標從來就不是硬實時。Linux要處理內(nèi)存管理、進程調(diào)度、文件系統(tǒng)、網(wǎng)絡(luò)協(xié)議棧、各種驅(qū)動任何一個環(huán)節(jié)出現(xiàn)延遲抖動對于“必須在10毫秒內(nèi)切斷電機”這種需求來說都是災(zāi)難。你可能會說Linux有RT補丁啊PREEMPT_RT不是能把延遲壓到幾十微秒嗎理論上可以但實際產(chǎn)品里你還要跑SLAM、跑路徑規(guī)劃、跑WiFi通信、跑語音識別這些任務(wù)會互相搶占最壞情況下的延遲是不可預(yù)測的。所以雙腦架構(gòu)的核心邏輯就一句話讓Linux負責(zé)“聰明”的部分讓MCU負責(zé)“安全”的部分兩者之間用明確的邊界隔開。Linux可以死機、可以重啟、可以卡頓但MCU必須始終在跑始終在監(jiān)控始終能在異常發(fā)生時把機器停下來。這就是標題里說的“安全永遠不能交給Linux”的真正含義——不是Linux不能用而是安全相關(guān)的最后一道防線必須由一顆獨立的、確定性的MCU來守。這套架構(gòu)適合誰來參考如果你是做機器人、智能家居、工業(yè)控制、汽車電子這類涉及“移動執(zhí)行器人身安全”的產(chǎn)品這套思路可以直接借鑒。如果你只是做純信息處理類的設(shè)備那單顆SoC就夠了不需要雙腦。下面我會把這套架構(gòu)從設(shè)計思路、硬件選型、通信協(xié)議、安全機制到實際調(diào)試踩坑完整拆一遍。2. 雙腦架構(gòu)的整體設(shè)計與職責(zé)劃分2.1 為什么是“LinuxMCU”而不是“LinuxLinux”或者“MCUMCU”先說說為什么不是兩顆Linux。有人會想既然一顆Linux不夠安全那我搞兩顆Linux互相監(jiān)控行不行答案是不行或者說性價比極低。兩顆Linux意味著兩套完整的內(nèi)存、存儲、電源、時鐘系統(tǒng)成本直接翻倍而且兩顆Linux之間的通信延遲和不確定性依然存在。更關(guān)鍵的是Linux的失效模式往往是“整機卡死”或“內(nèi)核panic”這時候另一顆Linux未必能及時感知并接管。你等于用兩個不確定的系統(tǒng)去互相保證確定性邏輯上就不成立。那為什么不是兩顆MCU因為掃地機需要跑SLAM、需要處理激光雷達點云、需要跑WiFi協(xié)議棧、需要做語音交互這些任務(wù)對算力和內(nèi)存的需求遠超MCU的能力范圍。MCU通常只有幾百KB的RAM和幾十到幾百MHz的主頻跑個簡單的控制邏輯沒問題但跑視覺算法和網(wǎng)絡(luò)通信就力不從心了。所以“LinuxMCU”的組合是算力與確定性的最優(yōu)分工Linux這邊有GB級的內(nèi)存、GHz級的主頻、完整的網(wǎng)絡(luò)和文件系統(tǒng)適合做“重計算、可容忍延遲”的任務(wù)MCU這邊有納秒級的中斷響應(yīng)、硬件級的定時器、看門狗適合做“輕計算、必須準時”的任務(wù)。兩者通過一條明確的通信通道連接各司其職。2.2 職責(zé)邊界怎么劃哪些歸Linux哪些歸MCU這個邊界劃分是整個架構(gòu)設(shè)計的核心劃錯了后面全是坑。我自己的經(jīng)驗是遵循一個原則凡是“失效后可能導(dǎo)致物理傷害或不可逆損失”的功能全部歸MCU凡是“失效后只是體驗變差或功能暫時不可用”的功能歸Linux。具體到掃地機器人我一般這樣分功能模塊歸屬理由電機驅(qū)動與調(diào)速MCU電機失控會撞人、卷線、燒毀碰撞檢測與急停MCU必須毫秒級響應(yīng)不能等Linux調(diào)度懸崖檢測MCU掉下樓梯是重大事故電池過充過放保護MCU涉及起火風(fēng)險看門狗與復(fù)位管理MCU系統(tǒng)最后一道防線傳感器原始數(shù)據(jù)采集MCU需要精確時序如超聲波、紅外SLAM與路徑規(guī)劃Linux計算密集延遲容忍度高WiFi/藍牙通信Linux協(xié)議棧復(fù)雜MCU跑不動語音識別與交互Linux需要算力和大內(nèi)存OTA升級管理Linux需要文件系統(tǒng)和網(wǎng)絡(luò)地圖存儲與用戶界面Linux需要存儲和顯示這張表不是絕對的不同產(chǎn)品會有調(diào)整。比如有些低端機型把WiFi放在MCU上跑用ESP32之類的方案但那是成本妥協(xié)不是最優(yōu)設(shè)計。中高端機型基本都遵循“安全歸MCU、智能歸Linux”的原則。2.3 通信通道的選擇UART、SPI還是CAN兩顆芯片之間怎么通信這個選擇直接影響系統(tǒng)的可靠性和實時性。常見的選項有UART、SPI、I2C、CAN我逐個說一下實際使用感受。UART是最常用的成本低、引腳少、協(xié)議簡單幾乎每顆MCU都有。缺點是速率有限通常115200到921600bps而且沒有硬件仲裁和錯誤重傳機制需要自己在協(xié)議層做校驗和重傳。對于掃地機這種數(shù)據(jù)量不大的場景UART其實夠用——Linux發(fā)給MCU的主要是速度指令、模式切換、查詢狀態(tài)MCU發(fā)給Linux的主要是傳感器數(shù)據(jù)、異常事件、心跳包。我實測下來115200bps跑一個50Hz的控制循環(huán)加事件上報完全沒問題。SPI速率高可以到幾MHz甚至幾十MHz適合大數(shù)據(jù)量傳輸比如MCU采集的原始點云數(shù)據(jù)傳給Linux。但SPI是主從結(jié)構(gòu)通常Linux做主機MCU做從機這意味著MCU不能主動發(fā)起通信只能等Linux來讀。對于“MCU檢測到碰撞要立刻通知Linux”這種場景SPI就不太合適除非額外加一根中斷線。I2C速率更低而且總線仲裁機制復(fù)雜不適合做主要通信通道一般只用來掛低速傳感器。CAN總線在汽車和工業(yè)上很成熟有硬件仲裁、錯誤檢測、自動重傳可靠性最高。但CAN需要額外的收發(fā)器芯片成本略高而且Linux這邊需要CAN控制器或USB-CAN轉(zhuǎn)換器。如果產(chǎn)品定位高端、對可靠性要求極高CAN是值得的。我做過一個工業(yè)AGV項目用的就是CAN確實穩(wěn)但掃地機這種消費級產(chǎn)品UART加協(xié)議層保護已經(jīng)足夠。我最終的選擇通常是主通信走UART關(guān)鍵事件用獨立GPIO中斷線。這樣既控制了成本又保證了緊急事件的響應(yīng)速度。比如MCU檢測到碰撞除了通過UART發(fā)消息還會拉低一根“緊急”GPIOLinux那邊用中斷處理響應(yīng)時間可以壓到微秒級。3. MCU側(cè)的核心安全機制與實操要點3.1 看門狗怎么喂才安全獨立看門狗與窗口看門狗看門狗是MCU安全機制的基石但很多人用錯了。最常見的錯誤是“在定時器中斷里喂狗”這樣即使主循環(huán)卡死中斷還在跑狗照樣被喂系統(tǒng)實際上已經(jīng)失控了但看門狗沒起作用。正確的做法是在主循環(huán)的最后喂狗并且喂狗條件要包含“關(guān)鍵任務(wù)都已完成”的判斷。STM32通常有獨立看門狗IWDG和窗口看門狗WWDG。IWDG用獨立的低速時鐘即使主時鐘掛了它還在跑適合做最后防線。WWDG有“窗口”概念喂狗太早或太晚都會復(fù)位適合檢測任務(wù)執(zhí)行時間是否異常。我的做法是兩級都用IWDG設(shè)一個較長的超時比如500msWWDG設(shè)一個較短的窗口比如10ms到20ms之間必須喂這樣既能檢測任務(wù)超時又能防止主循環(huán)完全卡死。具體配置IWDG的時候預(yù)分頻和重裝載值的計算要注意。假設(shè)內(nèi)部低速時鐘是32kHz預(yù)分頻設(shè)為64那么計數(shù)頻率是500Hz周期2ms。如果重裝載值設(shè)為250超時就是500ms。這個500ms要大于你最慢任務(wù)的執(zhí)行時間但又要小于“人反應(yīng)過來去拔電源”的時間。我一般取200到500ms之間。注意調(diào)試的時候一定要先關(guān)掉看門狗否則單步調(diào)試時狗會一直復(fù)位根本沒法調(diào)??梢栽诔跏蓟a里加一個“調(diào)試模式”判斷檢測到調(diào)試器連接就禁用看門狗。3.2 急停回路硬件切斷比軟件切斷更可靠軟件急停的流程是檢測到異常 - MCU執(zhí)行中斷 - 關(guān)閉PWM - 電機停轉(zhuǎn)。這個流程即使再快也有幾個毫秒的延遲而且如果MCU本身跑飛了軟件急停就失效了。所以真正可靠的設(shè)計是硬件急?;芈酚靡活w獨立的模擬開關(guān)或繼電器直接切斷電機驅(qū)動器的使能引腳這個切斷信號由“碰撞傳感器MCU的GPIO”共同控制甚至可以是純硬件的——碰撞開關(guān)直接串在使能回路里。我做過一個方案碰撞傳感器是一個常閉開關(guān)串在電機驅(qū)動器的EN引腳上。正常時開關(guān)閉合EN拉高電機可以轉(zhuǎn)碰撞時開關(guān)斷開EN被下拉電阻拉低電機立刻斷電。這個響應(yīng)時間是微秒級的完全不依賴MCU。MCU這邊只是“知道”發(fā)生了碰撞然后去處理后續(xù)邏輯比如后退、轉(zhuǎn)向。這樣即使MCU死機碰撞時電機也會停。當(dāng)然純硬件急停會增加線束復(fù)雜度而且碰撞開關(guān)的可靠性本身也要考慮。所以我的折中方案是硬件急停做第一道防線MCU軟件急停做第二道防線Linux的監(jiān)控做第三道防線。三道防線層層遞進任何一道生效都能避免事故。3.3 電池管理過充過放保護的獨立監(jiān)控掃地機的電池通常是鋰電池組過充會起火過放會損壞電池。很多方案是用專門的充電管理IC但IC也可能失效所以MCU要獨立監(jiān)控電池電壓和溫度。我的做法是MCU用ADC持續(xù)采樣電池電壓用NTC采樣電池溫度一旦電壓超過4.25V每節(jié)或溫度超過60度立刻切斷充電MOS并通過UART通知Linux上報異常。這里有個細節(jié)ADC采樣要加RC濾波否則電機啟動時的電壓波動會誤觸發(fā)保護。我一般用10k電阻加100nF電容截止頻率約160Hz能濾掉大部分開關(guān)噪聲。另外保護閾值要加遲滯比如過壓保護在4.25V觸發(fā)但要等到電壓降到4.15V以下才恢復(fù)避免在閾值附近反復(fù)跳變。3.4 傳感器數(shù)據(jù)采集的時序保證MCU采集傳感器數(shù)據(jù)最怕的是“時序抖動”。比如超聲波測距需要先發(fā)一個10微秒的脈沖然后計時等待回波。如果這個10微秒的脈沖因為中斷延遲變成了15微秒測距結(jié)果就會偏差。所以MCU這邊要用硬件定時器來產(chǎn)生脈沖和捕獲回波而不是用軟件延時。STM32的定時器輸入捕獲功能很適合做這個。配置一個定時器通道輸出PWM固定10微秒脈沖另一個通道做輸入捕獲記錄回波上升沿和下降沿的時間戳差值就是回波時間。整個過程硬件完成CPU只需要讀寄存器。這樣即使有中斷打斷測量精度也不受影響。紅外懸崖傳感器也是類似需要精確的調(diào)制頻率通常38kHz用硬件PWM產(chǎn)生軟件只負責(zé)讀接收頭的輸出。如果軟件模擬38kHzCPU占用率高不說頻率還不準。4. Linux側(cè)的任務(wù)調(diào)度與異常處理4.1 Linux側(cè)的進程優(yōu)先級與CPU親和性設(shè)置Linux這邊雖然不負責(zé)安全但它的任務(wù)調(diào)度會間接影響MCU的通信。比如SLAM進程如果占滿CPUUART通信線程可能得不到調(diào)度導(dǎo)致MCU發(fā)來的異常事件延遲處理。所以Linux側(cè)也要做優(yōu)先級管理。我的做法是把與MCU通信的線程設(shè)為實時優(yōu)先級SCHED_FIFO優(yōu)先級設(shè)成80左右比普通進程高但比內(nèi)核關(guān)鍵線程低。然后用taskset把這個線程綁定到一個獨立的CPU核心上如果SoC是多核的避免被其他計算任務(wù)搶占。SLAM和路徑規(guī)劃這些計算任務(wù)設(shè)為普通優(yōu)先級SCHED_OTHER讓它們用剩下的核心。具體命令示例# 把通信線程綁定到CPU核心2并設(shè)為實時優(yōu)先級 taskset -cp 2 pid chrt -f -p 80 pid在代碼里可以用pthread_setschedparam和pthread_setaffinity_np來實現(xiàn)。注意實時優(yōu)先級線程里不能有阻塞操作否則會卡住整個核心。UART讀寫要用非阻塞模式或者帶超時的poll。4.2 通信協(xié)議設(shè)計幀結(jié)構(gòu)、校驗與重傳Linux和MCU之間的UART通信不能裸發(fā)數(shù)據(jù)必須有幀結(jié)構(gòu)。我一般用這樣的格式幀頭(2字節(jié)) | 長度(1字節(jié)) | 命令(1字節(jié)) | 數(shù)據(jù)(N字節(jié)) | CRC16(2字節(jié)) | 幀尾(1字節(jié))幀頭用0xAA 0x55這種不容易出現(xiàn)在數(shù)據(jù)里的組合。長度字段表示數(shù)據(jù)段的長度。CRC16用CCITT多項式能檢測大部分傳輸錯誤。幀尾用0x0D或0x0A。接收方要做狀態(tài)機解析先找?guī)^再讀長度再收數(shù)據(jù)最后校驗CRC。如果CRC錯誤丟棄并請求重傳。重傳機制用序列號加ACK發(fā)送方發(fā)一幀后等待ACK超時沒收到就重發(fā)重發(fā)3次還失敗就上報通信故障。這里有個坑如果MCU在發(fā)數(shù)據(jù)時被高優(yōu)先級中斷打斷可能導(dǎo)致幀內(nèi)字節(jié)間隔過大Linux側(cè)的串口驅(qū)動可能認為幀結(jié)束了。解決辦法是MCU發(fā)送時關(guān)中斷或者用DMA發(fā)送。STM32的UART DMA發(fā)送可以保證字節(jié)連續(xù)不被打斷。4.3 Linux死機時MCU如何接管這是雙腦架構(gòu)最關(guān)鍵的安全場景Linux因為內(nèi)存溢出、驅(qū)動bug、看門狗超時等原因死機了MCU必須能檢測到并讓機器安全停下。檢測機制是心跳包Linux每隔100ms通過UART發(fā)一個心跳幀給MCUMCU收到后重置一個心跳計數(shù)器。如果MCU連續(xù)500ms沒收到心跳就判定Linux失聯(lián)執(zhí)行安全動作停止電機、關(guān)閉風(fēng)機、點亮故障燈、蜂鳴器報警。然后MCU可以嘗試復(fù)位Linux通過控制Linux的復(fù)位引腳如果復(fù)位后還是沒心跳就保持停機狀態(tài)。這里要注意心跳包不能只是“收到了就行”還要檢查內(nèi)容。比如心跳包里可以帶Linux的當(dāng)前狀態(tài)正常、低電量、故障MCU根據(jù)狀態(tài)決定是否繼續(xù)允許運動。如果Linux報告“傳感器故障”MCU應(yīng)該限制速度或停止。另外MCU復(fù)位Linux的引腳要設(shè)計成“開漏”或“可控”避免MCU自己復(fù)位時誤觸發(fā)Linux復(fù)位。我一般用一個MOS管做電平隔離MCU的GPIO控制MOS管柵極MOS管漏極接Linux的復(fù)位引腳。4.4 OTA升級時的雙腦協(xié)同OTA升級是另一個容易出問題的場景。Linux負責(zé)下載固件包但MCU的固件也要升級。流程通常是Linux下載包含MCU固件的包 - Linux通過UART把MCU固件傳給MCU - MCU寫入自己的Flash - MCU重啟生效。這里的安全點是MCU固件升級過程中機器必須處于安全狀態(tài)停在充電座上電機斷電。而且MCU要有“回滾”機制如果新固件啟動失敗比如看門狗超時要能回退到舊固件。STM32可以用雙Bank Flash或者外部EEPROM存儲舊固件。我一般用雙Bank方案升級時寫入備用Bank啟動時如果備用Bank校驗失敗就切回主Bank。Linux這邊升級失敗相對好處理因為Linux有文件系統(tǒng)可以保留舊版本。但要注意Linux升級時MCU不能斷電否則MCU可能處于未知狀態(tài)。所以升級流程要設(shè)計成“MCU先進入安全模式Linux再升級升級完成后MCU退出安全模式”。5. 常見問題與排查技巧實錄5.1 通信丟包與誤碼的排查思路UART通信出問題最常見的原因是波特率不匹配、地線沒接好、或者干擾。我遇到過一次MCU和Linux的波特率都設(shè)的115200但實際通信誤碼率很高。用示波器看波形發(fā)現(xiàn)MCU的TX信號上升沿很緩原來是上拉電阻太大10k加上線纜電容導(dǎo)致邊沿變圓。換成4.7k上拉后就好了。另一個常見問題是地環(huán)路。如果MCU和Linux的電源地不是同一點兩地之間有壓差UART信號就會偏移。解決辦法是用單點接地或者加隔離芯片。我一般會在UART線上串22歐姆電阻并在接收端加對地電容100pF能濾掉高頻干擾。排查步驟我總結(jié)成一張表現(xiàn)象可能原因排查方法完全無數(shù)據(jù)接線錯誤、波特率不對示波器看TX是否有波形偶發(fā)誤碼干擾、地線問題檢查地線、加濾波電容幀頭對但CRC錯字節(jié)丟失、時鐘偏差降低波特率測試通信一段時間后死掉緩沖區(qū)溢出、中斷未清檢查驅(qū)動緩沖區(qū)大小MCU收不到但Linux能收MCU RX配置錯誤檢查MCU串口初始化代碼5.2 MCU跑飛后的恢復(fù)策略MCU跑飛通常表現(xiàn)為看門狗復(fù)位、HardFault、或者程序卡在某個循環(huán)里。STM32的HardFault可以通過讀取SCB-CFSR寄存器定位原因比如是總線錯誤、內(nèi)存訪問錯誤還是未定義指令。我一般會在HardFault_Handler里把關(guān)鍵寄存器存到備份RAM然后復(fù)位復(fù)位后讀取備份RAM分析原因。預(yù)防跑飛的措施第一所有指針使用前判空第二數(shù)組訪問加邊界檢查第三中斷服務(wù)函數(shù)盡量短復(fù)雜邏輯放到主循環(huán)第四棧大小要留夠我一般給每個任務(wù)至少512字節(jié)??臻g主棧1KB以上。如果MCU頻繁復(fù)位先看是不是電源問題。電機啟動時電流突變可能導(dǎo)致MCU供電跌落觸發(fā)BOR復(fù)位。解決辦法是在MCU電源引腳加100uF電解電容加100nF陶瓷電容并且電機電源和MCU電源用磁珠隔離。5.3 Linux側(cè)串口被占用或阻塞的處理Linux的串口設(shè)備/dev/ttyS0或/dev/ttyAMA0如果被其他進程打開通信線程會打開失敗。我遇到過調(diào)試時用minicom占了串口導(dǎo)致主程序打不開。解決辦法是在程序啟動時檢查串口是否可用如果被占用就報錯退出而不是靜默失敗。另一個問題是串口讀阻塞。如果用阻塞模式讀沒有數(shù)據(jù)時線程會掛起心跳包就發(fā)不出去。所以要用非阻塞模式O_NONBLOCK或者用select/poll加超時。我一般用poll超時設(shè)10ms這樣既能及時讀數(shù)據(jù)又不會阻塞太久。還有Linux的串口默認可能有流控RTS/CTS如果MCU沒接流控線要關(guān)掉流控否則可能發(fā)不出數(shù)據(jù)。用stty命令可以配置stty -F /dev/ttyS0 115200 cs8 -cstopb -parenb -crtscts5.4 電機干擾導(dǎo)致MCU復(fù)位的解決這是掃地機最經(jīng)典的坑電機一啟動MCU就復(fù)位。原因是電機換向時產(chǎn)生高頻噪聲通過電源線或空間輻射耦合到MCU。解決辦法分幾層第一電機兩端加續(xù)流二極管和RC吸收電路第二電機電源線用雙絞線并加磁環(huán)第三MCU電源加LC濾波第四PCB布局時電機驅(qū)動部分和MCU部分分區(qū)地平面分割單點連接。我實測下來最有效的是在電機端子處加一個100nF加100歐姆的RC吸收再加一個TVS管鉗位。這樣能把換向尖峰壓到安全范圍。另外MCU的復(fù)位引腳要加100nF電容到地防止干擾誤觸發(fā)復(fù)位。5.5 常見問題速查表問題現(xiàn)象解決MCU頻繁復(fù)位電機啟動時復(fù)位加電源濾波、RC吸收通信誤碼數(shù)據(jù)偶爾錯誤檢查地線、加串阻和電容看門狗誤復(fù)位正常運行時復(fù)位檢查喂狗位置和超時時間Linux收不到心跳MCU判定失聯(lián)檢查串口配置和線程優(yōu)先級急停不生效碰撞后電機不停檢查硬件急?;芈泛虴N引腳OTA后MCU不啟動升級后死機檢查雙Bank切換和校驗電池保護誤觸發(fā)電量正常但停機調(diào)整閾值和遲滯超聲波測距偏差數(shù)據(jù)跳動大用硬件定時器捕獲6. 雙腦架構(gòu)的擴展與個人經(jīng)驗這套雙腦架構(gòu)不只適用于掃地機器人。我后來做割草機器人、AGV、甚至智能門鎖都用了類似的思路一顆Linux做智能交互和計算一顆MCU做安全控制和實時響應(yīng)。區(qū)別只是通信協(xié)議和安全等級的要求不同。比如割草機器人對刀片電機的安全要求更高MCU這邊要加雙重冗余的急停回路AGV對通信可靠性要求高就換成CAN總線。我個人在實際操作中的體會是雙腦架構(gòu)的難點不在硬件而在“邊界定義”和“異常處理”。硬件選型、通信協(xié)議這些都有成熟方案但“什么情況下MCU該接管”“接管后做什么”“怎么恢復(fù)到正常狀態(tài)”這些邏輯需要反復(fù)推敲和測試。我一般會做故障注入測試故意讓Linux死機、故意拔掉傳感器、故意讓電機堵轉(zhuǎn)看MCU的反應(yīng)是否符合預(yù)期。這個過程能發(fā)現(xiàn)很多設(shè)計時想不到的邊界情況。最后分享一個小技巧在MCU的Flash里留一塊“黑匣子”區(qū)域記錄最近幾次異常事件的時間戳和狀態(tài)碼。機器出問題時讀這塊區(qū)域就能快速定位原因比看日志高效得多。這個習(xí)慣幫我省了很多調(diào)試時間。