做車間視覺識別:六個(gè)坑與實(shí)戰(zhàn)經(jīng)驗(yàn))
車間里一臺舊工控機(jī)壞了維修報(bào)價(jià)嚇人新工控機(jī)動(dòng)輒四五千元。我手里剛好有一臺樹莓派5心想不就是跑個(gè)視覺識別嗎這玩意幾百塊錢CPU理論上也不算弱是不是能頂上去結(jié)果理想很豐滿現(xiàn)實(shí)連扇耳光——從裝系統(tǒng)開始到把自訓(xùn)練的YOLOv5模型跑起來再到車間里又臟又亂的電源和高溫環(huán)境我被六件事硬生生卡了一個(gè)多月。這篇文章就按踩坑順序把這六件事寫出來給想把樹莓派5搬進(jìn)車間當(dāng)“便宜視覺終端”的兄弟們一個(gè)參考。我當(dāng)時(shí)的任務(wù)其實(shí)很簡單一條老產(chǎn)線上需要給料框計(jì)數(shù)和讀儀表盤數(shù)字原來那臺工控機(jī)壞了PLC側(cè)的數(shù)據(jù)要撈出來圖像要走一個(gè)輕量識別模型。算上攝像頭、傳感器、繼電器預(yù)算就一千塊。Jetson Orin Nano單板要兩千上下二手工控機(jī)怕翻新件最后我選了樹莓派5。后面的事實(shí)證明選型只是最簡單的一步真正的難題全在車間現(xiàn)場。1. 為什么車間會需要一臺樹莓派51.1 維修成本倒逼的選型實(shí)驗(yàn)我先說清楚樹莓派5并不是什么“工業(yè)級”設(shè)備它連寬溫、防塵、防振這些指標(biāo)都談不上。但車間里有一種很現(xiàn)實(shí)的需求叫“低成本試錯(cuò)”先花很少的錢驗(yàn)證一套邏輯再決定要不要上正經(jīng)工控設(shè)備。我那臺壞掉的工控機(jī)是某品牌老款i5維修報(bào)價(jià)接近兩千換新要四五千。而產(chǎn)線上要的只是一路相機(jī)、一個(gè)TCP通信、一個(gè)簡單的識別模型負(fù)載并不高。把樹莓派5當(dāng)作“邊緣盒子”臨時(shí)頂上去哪怕最后發(fā)現(xiàn)不行損失也不大。這是它進(jìn)車間的最初動(dòng)機(jī)。1.2 樹莓派5能不能干視覺活先看紙面數(shù)據(jù)樹莓派5用的是BCM2712四核Cortex-A76最高主頻2.4GHz相比樹莓派4B的Cortex-A72單核性能提升明顯整體算力大概有4B的兩到三倍。8GB內(nèi)存版跑YOLOv5這類輕量模型理論上不是異想天開。我和Jetson入門板做了個(gè)簡單對比項(xiàng)目樹莓派5 (8GB)Jetson Orin Nano (4GB)二手X86工控機(jī)價(jià)格區(qū)間400-600元2000-2500元1500-3000元功耗5-15W7-25W40-100W視覺推理CPU推理低FPS支持GPU/CUDA加速看CPU和顯卡社區(qū)資料多多但門檻高少工業(yè)可靠性低需自行加固中中一臺機(jī)器加攝像頭加電源整套不到一千塊比Jetson方案便宜一半還多。而且樹莓派的GPIO直接能接繼電器、接傳感器改造靈活。抱著“反正便宜”的心態(tài)我開始往里裝系統(tǒng)然后第一個(gè)坑就來了。2. 第一個(gè)卡點(diǎn)Ubuntu 裝上了啟動(dòng)卻翻了車2.1 為什么我用 Ubuntu 而不是 Raspberry Pi OS樹莓派官方系統(tǒng)Raspberry Pi OS確實(shí)最省心開箱即用但車間里我還有其他需求倉庫有一批腳本和容器鏡像跑在Ubuntu上YOLOv5相關(guān)的部署資料也大多是Ubuntu環(huán)境統(tǒng)一系統(tǒng)能少背一套命令。另外Ubuntu Server沒有桌面內(nèi)存占用小剩下的全部給推理進(jìn)程。所以我直接從官網(wǎng)下載了Ubuntu Server arm64鏡像。這里要提醒一句樹莓派5對Ubuntu的版本有要求太老的版本根本不認(rèn)識這個(gè)板子。Ubuntu 23.10是第一個(gè)官方支持樹莓派5的版本24.04 LTS則是長期支持版本。我當(dāng)時(shí)圖穩(wěn)直接選了24.04 Server。2.2 彩虹屏、舊固件與EEPROM 升級第一次燒錄完插上TF卡上電屏幕卡在彩虹色塊指示燈亂閃SSH也連不上。這是典型的“引導(dǎo)固件沒讀到內(nèi)核”的現(xiàn)象。查了一圈原因是樹莓派5的EEPROM引導(dǎo)固件版本太舊對Ubuntu 24.04的內(nèi)核支持不完整。樹莓派5和4B不一樣它的啟動(dòng)過程依賴板載EEPROM中的引導(dǎo)代碼不是光換TF卡就完事。解決辦法是先把配套的EEPROM固件更新到最新版本。操作分兩步用樹莓派Imager重新燒錄Raspberry Pi OS到一張卡插入樹莓派5啟動(dòng)。進(jìn)入系統(tǒng)后執(zhí)行sudo rpi-eeprom-update -a sudo reboot順帶一提如果你想直接用外部存儲啟動(dòng)比如NVMe SSD需要先確認(rèn)EEPROM版本里帶NVMe boot支持具體看rpi-eeprom-update的返回信息。更新完EEPROM后再燒Ubuntu Server就正常了。2.3 穩(wěn)定后我才補(bǔ)上的 NVMe 啟動(dòng)TF卡在車間環(huán)境里容易出問題一是長時(shí)間讀寫導(dǎo)致性能衰減二是突然斷電可能丟文件。Ubuntu跑起來后我又加了塊NVMe SSD通過PCIe轉(zhuǎn)接板把系統(tǒng)遷過去。遷移很簡單在TF卡系統(tǒng)里把整個(gè)根文件系統(tǒng)rsync到SSD再修改/boot/firmware/cmdline.txt里的root路徑或者干脆用官方推薦的鏡像備份工具。換到NVMe后系統(tǒng)啟動(dòng)時(shí)間從原來的40多秒降到15秒左右推理模型從SSD加載也快了。對車間這種“可能隨時(shí)斷電”的環(huán)境SSD的穩(wěn)定性比TF卡強(qiáng)不少。3. 第二個(gè)卡點(diǎn)車間電源環(huán)境讓樹莓派5頻繁重啟3.1 樹莓派5的功耗與供電要求樹莓派5官方推薦使用27W USB-C電源5V/5A實(shí)際跑滿負(fù)載無外設(shè)時(shí)功耗大概8-12W接USB攝像頭和傳感器后能到15W左右??雌饋聿桓叩囬g里的供電環(huán)境遠(yuǎn)比辦公室惡劣。我最初用的是手邊一個(gè)舊手機(jī)快充頭標(biāo)稱5V/3A心想應(yīng)該夠。結(jié)果一跑推理就隨機(jī)重啟有時(shí)候過兩三個(gè)小時(shí)才出問題有時(shí)候剛開機(jī)十幾分鐘就再也連不上去現(xiàn)場一看機(jī)器已經(jīng)重啟卡死了。后來才明白5V/3A只是它“穩(wěn)態(tài)輸出”的參數(shù)樹莓派5在CPU瞬間滿載時(shí)會突然拉高電流舊充電頭根本扛不住這種瞬態(tài)響應(yīng)電壓一掉過閾值芯片就復(fù)位重啟。3.2 欠壓癥狀與電壓核查欠壓不是一下子就會爆出來的它的典型癥狀很隱蔽推理程序偶爾報(bào)錯(cuò)攝像頭取流中斷SSH斷連重連后發(fā)現(xiàn)系統(tǒng)時(shí)間變了狀態(tài)燈異常閃爍更嚴(yán)重時(shí)直接開機(jī)卡死排查欠壓最直接的辦法是看系統(tǒng)自己記的日志。在樹莓派上執(zhí)行vcgencmd get_throttled返回0x0表示一切正常如果出現(xiàn)0x1表示當(dāng)前正在欠壓0x10則表示歷史上發(fā)生過欠壓。我那次返回的是一串非零值基本實(shí)錘了。再用萬用表測GPIO的5V引腳上電空載時(shí)5.1V一跑推理就掉到4.6V左右這就是典型的電源帶不動(dòng)。車間的動(dòng)力電還有波動(dòng)幾個(gè)大功率設(shè)備同時(shí)啟動(dòng)時(shí)整條線的電壓都會突然矮一截。3.3 供電整改從插座到電源適配器整改方案說穿了并不復(fù)雜換官方27W USB-C電源或者選質(zhì)量靠譜的工業(yè)級5V/5A適配器。電源線盡量短且粗避免線路上額外的壓降。如果從控制柜取電建議加一個(gè)DC-DC穩(wěn)壓模塊把輸入波動(dòng)穩(wěn)住。有條件就上PoE HAT用交換機(jī)的PoE口供電網(wǎng)絡(luò)和電源一根線解決還能順便做隔離。我自己最后用的是官方電源然后用一個(gè)帶浪涌保護(hù)的插座單獨(dú)給它供電不再和車床、焊機(jī)共用一路電。整改之后看vcgencmd get_throttled永遠(yuǎn)是0再也沒有隨機(jī)重啟過。車間用電真的不能按實(shí)驗(yàn)室插座的標(biāo)準(zhǔn)來。4. 第三個(gè)卡點(diǎn)散熱問題車間夏天直接降頻4.1 為什么樹莓派5比4B更燙樹莓派5性能提升的代價(jià)是發(fā)熱明顯增加。BCM2712在滿負(fù)荷推理時(shí)裸板不加散熱片溫度幾分鐘就飆到85°C以上然后觸發(fā)降頻保護(hù)。樹莓派4B勉強(qiáng)用個(gè)鋁殼還能壓住到5代就不行了。車間環(huán)境溫度比辦公室高得多我放樹莓派5的那個(gè)電控柜里夏天體感溫度45°C以上。同樣的負(fù)載在車間里熱得更快降頻更猛。4.2 散熱方案實(shí)測對比我手頭有三套散熱方案直接上機(jī)器測過散熱方案滿負(fù)荷穩(wěn)定溫度CPU頻率狀態(tài)無散熱片88-90°C降頻到1.5GHz左右鋁殼被動(dòng)散熱78-82°C降頻到1.8-2.0GHz官方主動(dòng)散熱器鋁片風(fēng)扇60-65°C幾乎穩(wěn)定2.4GHz看溫度和頻率用這幾條命令vcgencmd measure_temp vcgencmd measure_clock arm官方主動(dòng)散熱器本身不貴裝好后能在車間45°C高溫下把溫度壓在65°C左右缺點(diǎn)是有風(fēng)扇噪音。因?yàn)榭刂乒癖緛砭统尺@點(diǎn)聲音可忽略。如果放在安靜辦公環(huán)境就得權(quán)衡一下。4.3 軟件層面的溫度兜底硬件散熱做完了我還在軟件層面加了兜底。在/boot/firmware/config.txt里設(shè)了溫度限制避免極端情況下燒芯片。同時(shí)寫了個(gè)簡單的守護(hù)腳本檢測到溫度超過78°C時(shí)自動(dòng)把推理任務(wù)暫停10秒溫度降下來再恢復(fù)。原理類似“間歇性工作”對計(jì)數(shù)、讀表這類非連續(xù)識別場景完全夠用。散熱這事沒有捷徑先把風(fēng)道做好別把設(shè)備悶在密閉塑料盒里。車間控制柜如果散熱差最好在柜門上開孔加過濾風(fēng)扇不然什么樹莓派都撐不住。5. 第四個(gè)卡點(diǎn)自訓(xùn)練的 YOLOv5 模型跑起來像幻燈片5.1 部署路線為什么最終選了 ONNX Runtime我這邊模型是用YOLOv5在自己電腦上訓(xùn)練好的專門識別產(chǎn)線上的幾種工件。最初的思路最粗放直接在樹莓派5上裝PyTorch跑.pt權(quán)重。結(jié)果裝了半天一跑發(fā)現(xiàn)一幀推理要兩三秒根本無法用。后來換成ONNX Runtime這條路才算走通。對比了幾種常見的部署方式方案轉(zhuǎn)換難度樹莓派5上的推理性能內(nèi)存占用PyTorch直接跑無需轉(zhuǎn)換約1-3 FPS高ONNX Runtime中等約6-10 FPS中NCNN較高約8-12 FPS中TensorFlow Lite較高約5-8 FPS中Hailo-8 NPU很高30 FPS以上低ONNX Runtime在ARM CPU上的優(yōu)化做得不錯(cuò)依賴安裝也簡單。NCNN性能更好但需要額外編譯轉(zhuǎn)換步驟多對只想快速上線的我不劃算。最終選型ONNX Runtime。5.2 從 .pt 到 .onnx 的轉(zhuǎn)換實(shí)操轉(zhuǎn)換過程要用原訓(xùn)練機(jī)完成。YOLOv5倉庫里自帶導(dǎo)出腳本python export.py --weights best.pt --include onnx --opset 12 --img 640這里有幾個(gè)容易踩的坑如果你改過模型結(jié)構(gòu)比如自定義了檢測頭導(dǎo)出時(shí)可能報(bào)錯(cuò)如果訓(xùn)練時(shí)用了不同輸入尺寸導(dǎo)出時(shí)也要保持一致。我的模型是標(biāo)準(zhǔn)YOLOv5s結(jié)構(gòu)只是改了類別數(shù)導(dǎo)出還順利。導(dǎo)出后我用onnx-simplifier簡化了一遍去掉冗余節(jié)點(diǎn)文件大小和推理速度都有改善。最后在PC上用ONNX Runtime加載測試輸出結(jié)果和PyTorch基本一致才敢傳到樹莓派5上。5.3 從 4FPS 到 10FPS 的調(diào)優(yōu)記錄第一次在樹莓派5上跑ONNX模型640x640輸入4線程大概4-5 FPS看著就是幻燈片。經(jīng)過幾輪調(diào)整最后穩(wěn)定在9-10 FPS左右。調(diào)整順序如下輸入尺寸從640降到416速度幾乎翻倍精度損失對計(jì)數(shù)場景可接受。把預(yù)處理從Python循環(huán)改成NumPy向量化和圖片縮放單獨(dú)線程處理省掉每幀的額外開銷。推理進(jìn)程固定4線程不再和攝像頭采集線程搶CPU。后處理NMS用簡單版本實(shí)現(xiàn)避免YOLOv5完整后處理在ARM上消耗過多時(shí)間。實(shí)際代碼里核心就是import onnxruntime as ort sess ort.InferenceSession(best_fp32.onnx, providers[CPUExecutionProvider]) # 輸入已經(jīng)是 1x3x416x416 的float32數(shù)組 outputs sess.run(None, {input_name: img_blob})調(diào)優(yōu)的結(jié)論是在車間這種場景里10 FPS的識別速度完全夠用。料框計(jì)數(shù)根本不需要連續(xù)視頻流一秒取一幀就行。如果你硬要追求20 FPS以上那就要考慮NPU加速了。5.4 預(yù)算允許的話外掛NPU是另一條路樹莓派5支持通過PCIe接AI加速模塊比如Hailo-8或者Google Coral。樹莓派官方出過一個(gè)AI Kit套件搭配Hailo-8跑YOLOv5s實(shí)測能到幾十FPS。這個(gè)方案的好處是CPU占用很低壞處是軟件棧更復(fù)雜尤其是把你自己的模型量化成Hailo需要的格式要多花不少時(shí)間。我的建議是如果項(xiàng)目周期緊、識別頻率低就先用CPU推理湊合如果后續(xù)有多個(gè)識別點(diǎn)要部署直接批量上NPU套件更劃算。我自己是因?yàn)榭蛻舸叩眉毕扔肅PU版本上線了采購計(jì)劃里已經(jīng)在排NPU了。6. 第五個(gè)卡點(diǎn)車間網(wǎng)絡(luò)太野設(shè)備一會兒就失聯(lián)6.1 車間 Wi-Fi 靠不住的真實(shí)原因一開始圖省事樹莓派5用WiFi聯(lián)網(wǎng)。結(jié)果慘痛車間里全是金屬貨架和設(shè)備WiFi信號穿兩層鐵皮就只剩一格。更麻煩的是車間有自己的無線環(huán)境AP漫游切換會斷流PLC和電機(jī)產(chǎn)生的電磁干擾也讓無線穩(wěn)定性雪上加霜?,F(xiàn)象就是SSH連不上程序還在跑但圖像數(shù)據(jù)回傳卡死偶爾出現(xiàn)推理進(jìn)程假死。排查網(wǎng)絡(luò)真的比排查代碼還難。6.2 有線靜態(tài)IP隔離的最終配置后來我把樹莓派5直接插網(wǎng)線到產(chǎn)線交換機(jī)再也不用WiFi。靜態(tài)IP也直接寫死在netplan配置里network: version: 2 ethernets: eth0: addresses: - 192.168.20.66/24 routes: - to: default via: 192.168.20.1 nameservers: addresses: [192.168.20.1] wifis: wlan0: dhcp4: no optional: true同時(shí)把樹莓派劃到了獨(dú)立的VLAN和辦公網(wǎng)、PLC控制網(wǎng)做隔離避免車間里亂七八糟的廣播風(fēng)暴把設(shè)備搞崩。樹莓派5自帶的網(wǎng)口是千兆實(shí)測跑圖像數(shù)據(jù)傳輸很穩(wěn)比WiFi快得多。6.3 斷網(wǎng)容錯(cuò)與數(shù)據(jù)緩存即使有線也保不齊交換機(jī)重啟、光纖收發(fā)器斷電。我把應(yīng)用層改成“斷網(wǎng)不丟數(shù)據(jù)”的模式識別結(jié)果先寫本地SQLite定時(shí)批量上報(bào)。MQTT斷線自動(dòng)重連上線后補(bǔ)發(fā)離線消息。找個(gè)獨(dú)立腳本每30秒ping網(wǎng)關(guān)連續(xù)失敗就重啟網(wǎng)絡(luò)服務(wù)。這套容錯(cuò)設(shè)計(jì)上線后再也沒出現(xiàn)過“設(shè)備恢復(fù)網(wǎng)絡(luò)但程序已經(jīng)死掉”的情況。車間的網(wǎng)絡(luò)再野也翻不出大浪了。7. 第六個(gè)卡點(diǎn)裝好之后沒人愿意天天重啟樹莓派7.1 systemd 服務(wù)開機(jī)自啟和崩潰拉起系統(tǒng)裝好、模型跑通只完成了一半。真正麻煩的是后期運(yùn)維——車間工人不會去敲命令設(shè)備斷電重啟后必須自己跑起來程序崩了也必須自己拉起來。我用systemd寫了一個(gè)服務(wù)文件[Unit] DescriptionRPI Vision Detection Service Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple WorkingDirectory/opt/vision ExecStart/usr/bin/python3 /opt/vision/app.py Restartalways RestartSec5 EnvironmentPYTHONUNBUFFERED1 [Install] WantedBymulti-user.targetRestartalways是關(guān)鍵參數(shù)只要進(jìn)程異常退出systemd會在5秒后拉起來。再執(zhí)行systemctl enable vision開機(jī)就會自動(dòng)啟動(dòng)。這一步解決了“程序崩潰沒人管”的問題。7.2 硬件看門狗專注治死機(jī)不重啟程序崩了systemd能拉起來但如果整個(gè)系統(tǒng)卡死systemd也沒辦法。這時(shí)候需要硬件看門狗。樹莓派的SoC內(nèi)置了看門狗開啟方法是在/boot/firmware/config.txt里加一行dtparamwatchdogon重啟后會出現(xiàn)/dev/watchdog0。在應(yīng)用層定期“喂狗”如果系統(tǒng)卡死導(dǎo)致喂狗中斷看門狗會在幾十秒內(nèi)強(qiáng)制重啟整機(jī)。我用的一個(gè)簡單Python喂狗腳本import os, time WATCHDOG_PATH /dev/watchdog0 fd os.open(WATCHDOG_PATH, os.O_WRONLY) while True: os.write(fd, bV) time.sleep(5)注意喂狗腳本一定要和主進(jìn)程獨(dú)立運(yùn)行最好使用單獨(dú)服務(wù)這樣即使主進(jìn)程卡死喂狗腳本還在喂那就白搭了。我把主進(jìn)程掛了“健康檢查”鉤子主進(jìn)程每10秒寫一個(gè)心跳文件喂狗腳本發(fā)現(xiàn)心跳文件超過30秒沒更新就主動(dòng)停止喂狗觸發(fā)看門狗重啟。這套組合拳用了一個(gè)季度車間斷電恢復(fù)再也沒人工干預(yù)過。7.3 交付給車間前的最后三步正式交付前我還做了三件事把樹莓派5裝進(jìn)帶透明窗的金屬端子盒固定在電控柜內(nèi)貼好散熱片導(dǎo)風(fēng)罩。在盒子上裝一個(gè)三色指示燈綠燈運(yùn)行、黃燈告警、紅燈死機(jī)配合看門狗邏輯。車間工人看到紅燈知道打電話給我不用自己碰設(shè)備。用dd做了一份系統(tǒng)全量鏡像備份刻到備用的NVMe里。萬一這臺設(shè)備徹底掛了換卡就能頂一個(gè)小時(shí)左右恢復(fù)到可用狀態(tài)。這三步看起來很土但非常管用。把樹莓派5當(dāng)“家電”交付給車間比給工人發(fā)一堆英文文檔靠譜得多。8. 寫在最后的經(jīng)驗(yàn)?zāi)男┸囬g適合樹莓派5哪些不適合8.1 這幾類活樹莓派5干得很穩(wěn)經(jīng)過這輪折騰我對樹莓派5進(jìn)車間有了清晰的判斷。它最適合的場景是料框計(jì)數(shù)、零件分類、讀儀表數(shù)字這類低頻視覺識別設(shè)備狀態(tài)數(shù)據(jù)采集和上報(bào)的邊緣網(wǎng)關(guān)需要GPIO控制簡單執(zhí)行器繼電器、聲光報(bào)警的小改造預(yù)算敏感、允許低幀率的視覺驗(yàn)證項(xiàng)目這類負(fù)載的特點(diǎn)是單次推理時(shí)間幾百毫秒沒關(guān)系采集間隔可以設(shè)成每1-2秒一拍樹莓派5完全扛得住。8.2 這幾個(gè)場景別省錢上樹莓派5不適合的場景我也列出了高速產(chǎn)線視覺檢測要求30 FPS以上連續(xù)檢測的需要長時(shí)間無人值守且系統(tǒng)可靠性要求極高的核心工位環(huán)境溫度超過50°C、沒有做任何散熱改造的密閉柜體需要工業(yè)級認(rèn)證高溫、振動(dòng)、防塵等的交付項(xiàng)目這些場景老老實(shí)實(shí)上正經(jīng)工控機(jī)或者Jetson不要為了幾百塊錢埋雷。樹莓派5適合做“輔助工位”和“邊緣小腦”不適合當(dāng)產(chǎn)線心臟。8.3 重新選一次我會先解決哪兩件事如果重新來一次我會把供電和散熱問題放在系統(tǒng)安裝之前解決。當(dāng)時(shí)太樂觀以為軟件是最難的事實(shí)恰恰相反系統(tǒng)裝好、模型調(diào)通只占了三分之一的工作量剩下的時(shí)間全耗在“讓設(shè)備在車間環(huán)境里穩(wěn)定活著”。六件事捋順之后核心也就四句話供電給足、散熱做好、模型用對、網(wǎng)絡(luò)穩(wěn)定再補(bǔ)上開機(jī)自啟和看門狗樹莓派5在車間里完全能當(dāng)個(gè)合格的小工具。它不會像幾十萬的設(shè)備那樣金光閃閃但勝在便宜、靈活、壞了不心疼。對我來說這就夠了。