動(dòng)的microduck小車(chē):硬件選型到避障實(shí)現(xiàn))
1. microduck 到底是什么項(xiàng)目全貌與設(shè)計(jì)思路最近兩周我一直在折騰 microduck 這個(gè)小車(chē)機(jī)器人項(xiàng)目從硬件選型到跑通第一行代碼前前后后花了兩個(gè)完整的周末。說(shuō)實(shí)話這個(gè) GitHub 上公開(kāi)的開(kāi)源項(xiàng)目名字挺討喜——microduck就是一只小鴨子造型的雙輪小車(chē)。它的核心玩法很樸素用一塊主控板控制兩個(gè)電機(jī)配上幾個(gè)傳感器讓它在桌面上自己避開(kāi)障礙、沿著黑線跑特殊情況還能用手機(jī)藍(lán)牙遙控。聽(tīng)起來(lái)不復(fù)雜但實(shí)際上手之后你會(huì)發(fā)現(xiàn)從芯片選型到電機(jī)死活不轉(zhuǎn)的排查每一步都藏著坑也每一步都有收獲。我本職是寫(xiě)軟件的硬件這邊不算老手所以這篇文章里的路線圖可能特別適合兩類(lèi)人一類(lèi)是會(huì)寫(xiě)代碼但沒(méi)怎么焊過(guò)板子的軟件工程師另一類(lèi)是剛接觸嵌入式的學(xué)生朋友。如果你想找一個(gè)低成本、高信息密度的練手項(xiàng)目microduck 是一個(gè)非常好的起點(diǎn)。1.1 一句話講清 microduck 的定位microduck 本質(zhì)上是一個(gè)輕量級(jí)的雙輪差速機(jī)器人平臺(tái)。所謂輕量級(jí)指的是它對(duì)材料、工具、金錢(qián)的投入都?jí)旱搅藰O低主控板用 ESP32 系列開(kāi)發(fā)板市價(jià)大概 30 到 50 塊錢(qián)電機(jī)是常見(jiàn)的 TT 減速電機(jī)或者 N20 微型減速電機(jī)一對(duì)一二十塊驅(qū)動(dòng)芯片用 TB6612FNG 或 DRV8833幾塊到十幾塊傳感器按需購(gòu)買(mǎi)尋跡、避障、測(cè)距每樣都是幾塊錢(qián)的模塊全部物料加起來(lái)不算工具、外殼和電池總成本能控制在 150 元以內(nèi)。這個(gè)成本比買(mǎi)成品套件還便宜——當(dāng)然重點(diǎn)是成品套件不會(huì)讓你理解每一個(gè)零件為什么存在。它解決的問(wèn)題也很明確讓一個(gè)只寫(xiě)過(guò)軟件的人用最短路徑把硬件選型—接線—燒錄—跑起來(lái)這一整條鏈路走通。它刻意保持簡(jiǎn)單簡(jiǎn)單到每個(gè)模塊都能看懂、能替換、能修。這種可修復(fù)性恰恰是商業(yè)成品給不了你的學(xué)習(xí)價(jià)值。1.2 從原理圖到成品整體系統(tǒng)怎么拆我一開(kāi)始就給自己定了個(gè)原則不追求一步到位而是把整個(gè)系統(tǒng)拆成五個(gè)可以獨(dú)立驗(yàn)證的模塊。供電模塊電池、電源開(kāi)關(guān)、穩(wěn)壓電路負(fù)責(zé)給主控和電機(jī)分別供能控制模塊ESP32 主控負(fù)責(zé)讀傳感器、做決策、輸出 PWM 信號(hào)運(yùn)動(dòng)模塊電機(jī)驅(qū)動(dòng)板加兩個(gè)減速電機(jī)加兩個(gè)輪子感知模塊ED330 紅外尋跡傳感器、HC-SR04 超聲波測(cè)距模塊交互模塊0.96 寸 OLED 顯示當(dāng)前狀態(tài)藍(lán)牙負(fù)責(zé)手機(jī)遙控拆完之后每個(gè)模塊都能單獨(dú)測(cè)試。比如先把電機(jī)驅(qū)動(dòng)這塊焊好單獨(dú)寫(xiě)一小段代碼讓電機(jī)轉(zhuǎn)起來(lái)再往下做別的。這個(gè)思路救了我很多次——如果一次性把所有東西接好再寫(xiě)代碼任何一環(huán)出了問(wèn)題你都不知道該從哪里查起。模塊化拆解不只是代碼架構(gòu)的概念硬件調(diào)試同樣適用。1.3 為什么選這條路方案對(duì)比與取舍做這種小車(chē)機(jī)器人市面上其實(shí)有幾條經(jīng)典路線。最省事的是直接買(mǎi)成品套件說(shuō)明書(shū)一翻半個(gè)小時(shí)裝完。但那樣你學(xué)不到東西因?yàn)槟銢](méi)有做過(guò)任何一個(gè)選型決策出了問(wèn)題也只能問(wèn)客服。第二條路是照著網(wǎng)上的 Arduino 入門(mén)教程用 UNO 板子加 L298N 驅(qū)動(dòng)模塊。這個(gè)方案的資料堆積如山但有兩個(gè)硬傷一是 Arduino UNO 用的是 AVR 單片機(jī)性能太弱跑不了復(fù)雜邏輯以后想加攝像頭基本沒(méi)戲二是 L298N 模塊內(nèi)部是雙極型晶體管導(dǎo)通壓降能到 2V 以上電池電壓 6V 時(shí)真正到電機(jī)上的不到 4V續(xù)航和扭力都受影響。第三條路也就是 microduck 采用的路線ESP32 加 TB6612 驅(qū)動(dòng)配合模塊化傳感器。ESP32 自帶 Wi-Fi 和藍(lán)牙性能最高能到 240MHz 雙核以后想加攝像頭做視覺(jué)、做聯(lián)網(wǎng)控制都留了余地。TB6612 是 MOS 管驅(qū)動(dòng)壓降低、效率高兩路電機(jī)只需要一路 PWM 加一路方向信號(hào)接線也簡(jiǎn)潔。這個(gè)方案在學(xué)習(xí)成本、性能、擴(kuò)展空間三者之間是最平衡的。2. 硬件選型全解析從主控到每一個(gè)螺絲這一節(jié)詳細(xì)說(shuō)說(shuō)選型過(guò)程包括當(dāng)時(shí)為什么這么選、有什么替代方案以及我實(shí)際踩過(guò)的坑。硬件選型是這個(gè)項(xiàng)目里最容易讓人糾結(jié)的地方因?yàn)槊總€(gè)零件都有幾十種選擇但不代表你需要把所有選擇都搞明白才能下手。2.1 主控芯片ESP32 系列為什么是首選主控是整臺(tái) microduck 的腦子。為什么不是 STM32因?yàn)?STM32 的開(kāi)發(fā)門(mén)檻對(duì)新手極不友好光環(huán)境搭建和調(diào)試器配置就夠勸退一大批人。為什么不是樹(shù)莓派因?yàn)樗蟆⑻F、太耗電對(duì)一臺(tái)桌面小車(chē)來(lái)說(shuō)屬于殺雞用牛刀。ESP32 則是折中得最好的選項(xiàng)性能足夠跑實(shí)時(shí)控制開(kāi)發(fā)環(huán)境可以用 Arduino 框架快速上手后期想深入還能切換到 ESP-IDF。具體選哪一顆 ESP32我給三個(gè)參考建議ESP32-WROOM-32經(jīng)典款雙核 240MHz520KB RAM開(kāi)發(fā)板價(jià)格 30 到 50 塊社區(qū)資料最全適合絕大多數(shù)人。ESP32-C3單核 RISC-V性能弱一些但價(jià)格能壓到十幾塊引腳也夠用適合低成本改裝。ESP32-S3性能和功能最強(qiáng)帶向量指令加速如果你已經(jīng)想好后續(xù)要接攝像頭做視覺(jué)識(shí)別直接上它。我自己用的是經(jīng)典款 ESP32 DevKitC原因很簡(jiǎn)單microduck 倉(cāng)庫(kù)里的示例代碼幾乎都按這塊板子的引腳布局來(lái)寫(xiě)抄作業(yè)的時(shí)候不用自己改引腳映射能省下不少排查時(shí)間。2.2 電機(jī)與驅(qū)動(dòng)TT 電機(jī) TB6612 的經(jīng)典組合電機(jī)這塊microduck 默認(rèn)配置是 TT 減速電機(jī)。網(wǎng)上搜TT 電機(jī) 3-6V 減速馬達(dá)能出來(lái)一大片通常配橡膠輪子一起賣(mài)。TT 電機(jī)的優(yōu)勢(shì)是便宜、結(jié)實(shí)扭矩對(duì)桌面小車(chē)來(lái)說(shuō)綽綽有余缺點(diǎn)是轉(zhuǎn)速一致性一般同一批次的兩個(gè)電機(jī)實(shí)際轉(zhuǎn)速可能差 5% 到 10%這個(gè)問(wèn)題后面我會(huì)講怎么在代碼里做軟件校準(zhǔn)。驅(qū)動(dòng)芯片我強(qiáng)烈建議用 TB6612FNG而不是新手教程里常見(jiàn)的 L298N。我把兩者的關(guān)鍵差異整理成一張表對(duì)比項(xiàng)TB6612FNGL298N輸出器件場(chǎng)效應(yīng)管MOSFET雙極型晶體管導(dǎo)通壓降約 0.5V2V 以上最大電流單路 1.2A單路 2A邏輯電壓2.7V-5.5V5V模塊體積很小很大帶散熱片價(jià)格十幾塊十幾塊壓降這個(gè)參數(shù)最要命。L298N 在 6V 供電下電機(jī)實(shí)際只能拿到不到 4V扭矩直接掉一截電池稍微沒(méi)電就趴窩。TB6612 的壓降幾乎可以忽略這也是 microduck 項(xiàng)目選擇它的核心原因。TB6612 的接線邏輯非常清晰每個(gè)電機(jī)需要三個(gè)信號(hào)一個(gè) PWM 腳負(fù)責(zé)調(diào)速兩個(gè)方向腳決定正反轉(zhuǎn)。我把引腳定義留到第三節(jié)的表格里一起講避免重復(fù)。2.3 傳感器與顯示ED330 模塊和它的兄弟們microduck 的尋跡功能靠的是灰度傳感器。我在淘寶買(mǎi)的是很常見(jiàn)的 ED330 紅外尋跡模塊——就是板子上印著 ED330 字樣、中間一個(gè)紅外發(fā)射管加一個(gè)接收管的小板子。它的原理是反射式紅外探測(cè)紅外光打到地面后反射回來(lái)接收管根據(jù)反射光的強(qiáng)弱輸出不同的電平信號(hào)。黑色膠帶吸光反射弱白色桌面反射強(qiáng)模塊就能分辨當(dāng)前壓沒(méi)壓到線。ED330 模塊通常只有三根線VCC、GND、OUT其中 OUT 是數(shù)字輸出。板上有一個(gè)可調(diào)電位器用來(lái)設(shè)置觸發(fā)閾值。校準(zhǔn)的時(shí)候有個(gè)小技巧把模塊放在白色桌面上看 OUT 輸出是什么電平再放到黑色膠帶上看輸出是否翻轉(zhuǎn)。電位器要調(diào)到黑白兩種狀態(tài)都能穩(wěn)定區(qū)分不能只調(diào)到一邊靈敏。如果你發(fā)現(xiàn)模塊在兩個(gè)場(chǎng)景下輸出始終不變先懷疑電位器沒(méi)調(diào)好再懷疑模塊壞了。除了 ED330我還加了兩個(gè)輔助模塊HC-SR04 超聲波測(cè)距模塊用來(lái)檢測(cè)前方障礙物0.96 寸 OLED 顯示屏用 I2C 接口接主控實(shí)時(shí)顯示當(dāng)前狀態(tài)和傳感器數(shù)值。OLED 表面看起來(lái)是裝飾品實(shí)際是調(diào)試?yán)鳌唤悠聊坏脑捘阒荒芸看诖蛴《≤?chē)跑起來(lái)之后根本沒(méi)法連著電腦看串口屏幕能讓你直觀看到程序內(nèi)部的狀態(tài)。2.4 機(jī)械結(jié)構(gòu)與供電方案兩個(gè)最容易翻車(chē)的部分很多教程只講電路不講結(jié)構(gòu)但機(jī)械部分恰恰是讓 microduck 像一只鴨子的關(guān)鍵。車(chē)身我用的是一塊 3mm 亞克力板兩層結(jié)構(gòu)上層放 ESP32 和屏幕下層放電池盒和驅(qū)動(dòng)板。如果你沒(méi)有切割條件直接用塑料盒、甚至硬紙板加扎帶也能湊合但要保證兩個(gè)電機(jī)軸平行否則小車(chē)會(huì)跑偏。供電是自制小車(chē)?yán)锓?chē)率最高的部分沒(méi)有之一。TT 電機(jī)瞬間啟動(dòng)電流能到 1A 以上如果主控和電機(jī)共用一個(gè)電源電機(jī)一啟動(dòng)電壓瞬間跌落ESP32 會(huì)直接掉電重啟。我前幾次調(diào)試反復(fù)遇到這個(gè)問(wèn)題一度以為是代碼死循環(huán)。我的解決方案是兩節(jié) 18650 鋰電池串聯(lián)成 7.4V 給電機(jī)驅(qū)動(dòng)板供電同時(shí)從電池端接一個(gè) 5V 降壓模塊我用的 MP1584輸出電流 1A 以上單獨(dú)給 ESP32 供電。這樣在物理上做到電機(jī)和主控電源分離電機(jī)的電流沖擊不會(huì)干擾主控。線材方面單獨(dú)提醒一句杜邦線便宜但接觸不可靠尤其是電機(jī)這種大電流線路。建議至少用 20AWG 的硅膠線直接焊接到驅(qū)動(dòng)板焊盤(pán)上。我踩過(guò)的坑就是電機(jī)線用杜邦線插在驅(qū)動(dòng)板上小車(chē)一跑就抖動(dòng)斷電排查半天最后發(fā)現(xiàn)是杜邦線虛接。3. 開(kāi)發(fā)環(huán)境與工程骨架從 GitHub 到第一行代碼硬件都齊了接下來(lái)就是很多人最頭疼的環(huán)境搭建環(huán)節(jié)。這一節(jié)把工具鏈安裝、引腳規(guī)劃和工程拉取的完整過(guò)程寫(xiě)清楚照做就行。3.1 工具鏈安裝Arduino IDE 還是 ESP-IDFmicroduck 的示例代碼基于 Arduino 框架所以最省事的路徑就是用 Arduino IDE 開(kāi)發(fā)。建議直接裝 2.x 版本界面比 1.x 舒服自帶串口監(jiān)視器增強(qiáng)還能自動(dòng)補(bǔ)全。裝完 IDE 之后需要在文件 → 首選項(xiàng) → 附加開(kāi)發(fā)板管理器網(wǎng)址里填上 ESP32 官方的 JSON 地址然后在工具 → 開(kāi)發(fā)板 → 開(kāi)發(fā)板管理器里搜索 ESP32 并安裝支持包。這一步要下載幾十 MB 的數(shù)據(jù)國(guó)內(nèi)網(wǎng)絡(luò)偶爾會(huì)卡多試幾次就行或者手動(dòng)下載安裝包解壓到 Arduino 的 hardware 目錄下。裝好支持包后在工具 → 開(kāi)發(fā)板里選擇 ESP32 Dev Module 或?qū)?yīng)板型。還有一個(gè)很多人忽略的點(diǎn)串口驅(qū)動(dòng)。經(jīng)典款 DevKitC 用的 USB 轉(zhuǎn)串口芯片是 CP2102Windows 系統(tǒng)第一次插入需要裝 CP210x 驅(qū)動(dòng)否則電腦設(shè)備管理器里根本看不到串口。如果你買(mǎi)的板子是 CH340 芯片對(duì)應(yīng)驅(qū)動(dòng)又不一樣買(mǎi)板子的時(shí)候最好問(wèn)清楚。3.2 引腳分配表一次規(guī)劃省掉三次飛線接線之前強(qiáng)烈建議先把引腳分配畫(huà)成一張表。microduck 的參考接線可以這樣規(guī)劃我直接把有效的引腳分配表放出來(lái)功能模塊信號(hào)ESP32 引腳電機(jī) A PWMPWMAGPIO 25電機(jī) A 方向AIN1 / AIN2GPIO 26 / 27電機(jī) B PWMPWMBGPIO 14電機(jī) B 方向BIN1 / BIN2GPIO 12 / 13ED330 尋跡模塊OUTGPIO 34HC-SR04 超聲波Trig / EchoGPIO 5 / 18OLED 顯示屏SDA / SCLGPIO 21 / 22我特意避開(kāi)了 GPIO 0、GPIO 2、GPIO 12、GPIO 15 這些有特殊功能的引腳。比如 GPIO 0 是 BOOT 引腳如果接了強(qiáng)下拉設(shè)備可能導(dǎo)致開(kāi)發(fā)板無(wú)法進(jìn)入下載模式GPIO 12 是 MTDI 引腳在某些板子上會(huì)影響啟動(dòng)電壓。新手最容易犯的錯(cuò)誤就是隨手選一個(gè)引腳結(jié)果燒錄之后板子沒(méi)法正常工作還不明所以。3.3 拉取工程模板與倉(cāng)庫(kù)結(jié)構(gòu)GitHub 上搜 microduck 能找到官方倉(cāng)庫(kù)通常會(huì)有 examples 目錄放著幾個(gè)不同難度層級(jí)的示例代碼。如果你從 GitHub 下載 ZIP 包比較慢可以去國(guó)內(nèi)的代碼托管平臺(tái)找找鏡像倉(cāng)庫(kù)搜 microduck 一般能搜到別人同步過(guò)來(lái)的副本下載速度快不少。但我要給一個(gè)操作上的建議不要直接把倉(cāng)庫(kù)里的代碼整個(gè)復(fù)制過(guò)來(lái)用而是建立一個(gè)自己的工程目錄。雖然 Arduino 的示例通常是一個(gè).ino文件但當(dāng)代碼超過(guò)一百行之后我強(qiáng)烈建議按模塊拆文件。我的目錄結(jié)構(gòu)供參考microduck/ ├── src/ │ ├── main.cpp │ ├── motor.cpp │ ├── motor.h │ ├── sensor.cpp │ ├── sensor.h │ └── config.h ├── lib/ ├── docs/ └── README.md這樣做的核心價(jià)值在于后面每加一個(gè)功能就新建一個(gè)模塊文件出了問(wèn)題定位收縮得極快。很多人一上來(lái)就在一個(gè) main 文件里堆幾百行代碼出 bug 的時(shí)候頭都要大運(yùn)行日志和功能邏輯攪在一起改一處崩三處。4. 核心代碼實(shí)現(xiàn)點(diǎn)燈、轉(zhuǎn)電機(jī)、站起來(lái)這一節(jié)是大家最關(guān)心的部分——怎么把硬件變成真正能動(dòng)起來(lái)的 microduck。我從最基礎(chǔ)的第一行代碼講起再說(shuō)電機(jī)控制、傳感器讀取最后給出一個(gè)完整的運(yùn)動(dòng)邏輯用例。4.1 第一行代碼前的燒錄測(cè)試很多人拿到板子第一件事就是寫(xiě)業(yè)務(wù)代碼我的建議是先做一個(gè)最小驗(yàn)證插上電腦打開(kāi) Arduino IDE先燒一個(gè) Blink 例程。這個(gè)例程讓板載 LED 一閃一閃通過(guò)它你能確認(rèn)三件事電腦能識(shí)別串口、IDE 的編譯鏈路正常、燒錄過(guò)程順暢。Blink 的代碼核心就三行pinMode(LED_BUILTIN, OUTPUT)設(shè)腳為輸出digitalWrite(LED_BUILTIN, HIGH)點(diǎn)亮digitalWrite(LED_BUILTIN, LOW)熄滅中間夾著delay(500)。這個(gè)例程如果跑通說(shuō)明開(kāi)發(fā)環(huán)境沒(méi)問(wèn)題接下來(lái)寫(xiě)任何代碼都有底。如果這個(gè)都跑不通不要急著往下走先檢查串口是不是選對(duì)了、驅(qū)動(dòng)裝了沒(méi)有。4.2 電機(jī)控制PWM 是什么怎么調(diào)電機(jī)驅(qū)動(dòng)最關(guān)鍵的概念是 PWM即脈沖寬度調(diào)制。說(shuō)人話就是用高電平在一個(gè)固定周期內(nèi)占的比例也就是占空比來(lái)模擬不同的輸出電壓。占空比 100% 就是全速轉(zhuǎn)50% 就是半速0% 就是停。電機(jī)本質(zhì)上是慣性器件它在每個(gè)脈沖周期內(nèi)來(lái)不及反應(yīng)到完全停止所以平均電壓決定了它的平均轉(zhuǎn)速。Arduino 框架下有一個(gè)大坑ESP32 的 PWM 和 Arduino UNO 不一樣UNO 上的analogWrite()在 ESP32 上不可用。ESP32 必須用ledcSetup()和ledcAttachPin()來(lái)配置。下面是一個(gè)簡(jiǎn)化版的電機(jī)控制代碼可以直接抄#define PWM_FREQ 1000 // 1kHz 頻率 #define PWM_RES 8 // 8 位分辨率占空比 0-255 void motorInit() { ledcSetup(0, PWM_FREQ, PWM_RES); // 配置通道 0 ledcAttachPin(25, 0); // GPIO25 綁定到通道 0 } void setMotorA(int speed) { // speed 范圍 -255~255 if (speed 0) { digitalWrite(26, HIGH); digitalWrite(27, LOW); ledcWrite(0, speed); } else { digitalWrite(26, LOW); digitalWrite(27, HIGH); ledcWrite(0, -speed); } }思路很簡(jiǎn)單速度值的正負(fù)決定方向絕對(duì)值決定大小。正數(shù)讓 AIN1 高、AIN2 低電機(jī)正轉(zhuǎn)負(fù)數(shù)就反過(guò)來(lái)。這樣上層邏輯只需要傳一個(gè)帶符號(hào)的數(shù)不用操心方向引腳的狀態(tài)。關(guān)于 PWM 頻率的選擇有個(gè)知識(shí)點(diǎn)。頻率太低電機(jī)會(huì)發(fā)出明顯的高頻嗡嗡聲而且轉(zhuǎn)動(dòng)不均勻頻率太高驅(qū)動(dòng)芯片的開(kāi)關(guān)損耗增大芯片發(fā)熱。對(duì) TT 電機(jī)這種慣性較大的負(fù)載1kHz 到 10kHz 都能工作我最終選了 1kHz噪音和發(fā)熱平衡得好。如果你換用 N20 微型電機(jī)可以把頻率提到 20kHz 以上避開(kāi)人耳敏感區(qū)——這也是為什么有些 N20 小車(chē)跑起來(lái)幾乎靜音。4.3 傳感器讀取讓 microduck 有知覺(jué)讀 ED330 尋跡模塊是數(shù)字 IO 的入門(mén)操作直接digitalRead()就能拿到結(jié)果。但實(shí)際用的時(shí)候要注意單次讀值偶爾會(huì)有抖動(dòng)尤其是在黑白邊緣附近電平會(huì)在高低之間快速跳動(dòng)。所以我在代碼里加了一個(gè)簡(jiǎn)單的軟件濾波——連續(xù)讀三次取出現(xiàn)次數(shù)最多的值作為最終結(jié)果。這個(gè)三取二的算法雖然簡(jiǎn)單但對(duì)付傳感器抖動(dòng)非常有效。超聲波測(cè)距模塊 HC-SR04 稍微復(fù)雜一點(diǎn)它的工作流程是主控給 Trig 腳發(fā)送一個(gè) 10 微秒的高電平脈沖模塊內(nèi)部發(fā)出聲波然后 Echo 腳輸出一個(gè)高電平高電平持續(xù)的時(shí)間就是聲波往返的時(shí)間。換算公式如下float readDistance() { digitalWrite(TRIG, LOW); delayMicroseconds(2); digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); long duration pulseIn(ECHO, HIGH); return duration * 0.034 / 2; // 聲速約 340m/s取一半是單程 }有人會(huì)問(wèn)為什么除以 2——因?yàn)槁暡òl(fā)出去再?gòu)恼系K物反射回來(lái)走的是兩倍距離所以要折半。返回值單位是厘米。這里有個(gè)使用限制HC-SR04 的最小測(cè)量距離約 2 厘米最大約 4 米對(duì)桌面小車(chē)來(lái)說(shuō)綽綽有余。4.4 主邏輯一個(gè)簡(jiǎn)單的運(yùn)動(dòng)狀態(tài)機(jī)各個(gè)模塊都測(cè)通之后終于可以寫(xiě)主邏輯了。microduck 最簡(jiǎn)單也最好玩的玩法是避障巡邏我給它的整體邏輯設(shè)計(jì)了一個(gè)三態(tài)狀態(tài)機(jī)前進(jìn)、左轉(zhuǎn)、右轉(zhuǎn)。enum State { FORWARD, TURN_LEFT, TURN_RIGHT }; State state FORWARD; void loop() { float dist readDistance(); bool onLine digitalRead(ED330_PIN); switch (state) { case FORWARD: if (dist 15.0) { state TURN_RIGHT; // 前方有障礙向右轉(zhuǎn) } else if (onLine LOW) { state TURN_LEFT; // 壓到黑線向左躲 } break; case TURN_LEFT: setMotorA(-150); setMotorB(150); delay(200); // 原地左轉(zhuǎn) 200ms state FORWARD; break; case TURN_RIGHT: setMotorA(150); setMotorB(-150); delay(200); // 原地右轉(zhuǎn) 200ms state FORWARD; break; } if (state FORWARD) { setMotorA(180); setMotorB(180); } delay(20); }這個(gè)邏輯非常樸素但它是理解傳感器輸入 → 決策 → 執(zhí)行器輸出閉環(huán)的最小樣例。你可以看到整個(gè)程序就是在不斷重復(fù)讀數(shù)據(jù)、判斷狀態(tài)、控制電機(jī)。后面無(wú)論是換成 PID 直線校準(zhǔn)、還是加上藍(lán)牙遙控指令解析核心框架都不會(huì)變。4.5 錦上添花OLED 狀態(tài)顯示與避障提示在調(diào)試過(guò)程中我發(fā)現(xiàn) OLED 屏幕還能幫助做可視化排錯(cuò)。我寫(xiě)了一個(gè)簡(jiǎn)單的顯示函數(shù)把當(dāng)前狀態(tài)、前方距離、尋跡傳感器電平三個(gè)值循環(huán)刷新在屏幕上void updateDisplay(float dist, int sensorVal, int state) { display.clearDisplay(); display.setTextSize(1); display.setCursor(0, 0); display.println(MicroDuck v1.0); display.print(Dist: ); display.println(dist); display.print(Line: ); display.println(sensorVal); display.print(State: ); display.println(state); display.display(); }這段代碼有個(gè)實(shí)際價(jià)值小車(chē)在跑的時(shí)候你不需要連電腦串口只要低頭看屏幕就能知道它的內(nèi)心活動(dòng)。比如電機(jī)不動(dòng)屏幕顯示 State 一直在切換那問(wèn)題多半在電機(jī)驅(qū)動(dòng)如果屏幕顯示距離一直是 0那先查超聲波模塊的接線。用顯示模塊輔助定位問(wèn)題效率翻倍。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄最后這部分我把做 microduck 過(guò)程中遇到的、以及星友群里其他朋友反饋過(guò)的高頻問(wèn)題整理出來(lái)每個(gè)都附上排查思路和解決方案。這些內(nèi)容大多不會(huì)寫(xiě)在官方 README 里屬于實(shí)戰(zhàn)經(jīng)驗(yàn)。5.1 上電反復(fù)重啟的元兇供電不足現(xiàn)象插上電池之后ESP32 板載 LED 亮一下滅一下OLED 顯示一下又黑屏串口監(jiān)視器里反復(fù)輸出 Brownout detector was triggered。原因分析ESP32 內(nèi)部有一個(gè)欠壓檢測(cè)器當(dāng)供電電壓低于閾值通常是 3.0V 左右時(shí)它會(huì)強(qiáng)制系統(tǒng)復(fù)位防止程序在電壓不穩(wěn)的狀態(tài)下跑飛。這不是代碼 bug而是電源問(wèn)題。解決辦法首先確認(rèn)電池電壓兩節(jié) 18650 串聯(lián)是 7.4V經(jīng)降壓模塊到 5V 沒(méi)問(wèn)題其次確認(rèn)降壓模塊輸出電流能力ESP32 加 OLED 加傳感器峰值電流可能到 300mA建議降壓模塊至少支持 1A最后在 ESP32 的 5V 和 GND 之間并聯(lián)一個(gè) 470uF 電解電容濾掉電機(jī)啟動(dòng)瞬間的電壓毛刺。這個(gè)電容幾乎成了我所有項(xiàng)目的標(biāo)配。5.2 電機(jī)不轉(zhuǎn)三種最常見(jiàn)的故障電機(jī)不轉(zhuǎn)是新手遇到概率最高的問(wèn)題我總結(jié)下來(lái)基本逃不出三個(gè)原因。第一種驅(qū)動(dòng)板電源接錯(cuò)。TB6612 的 VM 和 VCC 是兩個(gè)不同的電源腳VM 接電池正極VCC 接主控的 3.3V 或 5V 邏輯電源。兩者接反或者漏接芯片都不會(huì)正常工作。注意 VM 和 VCC 千萬(wàn)不能混在一起。第二種使能腳沒(méi)接。TB6612 上有一個(gè) STBY 待機(jī)控制腳這個(gè)腳必須拉高驅(qū)動(dòng)器才會(huì)實(shí)際輸出。很多接線圖為了簡(jiǎn)化沒(méi)有畫(huà)出這個(gè)腳導(dǎo)致電機(jī)死活不動(dòng)。處理方法是把 STBY 直接接到 3.3V 或者主控的一個(gè) GPIO 并拉高。第三種PWM 通道沖突。ESP32 有多個(gè)獨(dú)立的 PWM 通道如果你在代碼里把兩個(gè)電機(jī)配置到同一個(gè)通道就會(huì)出現(xiàn)一個(gè)轉(zhuǎn)一個(gè)不轉(zhuǎn)或兩個(gè)一起轉(zhuǎn)但調(diào)速失效的怪現(xiàn)象。所以電機(jī) A 用通道 0電機(jī) B 一定要換一個(gè)通道編號(hào)。5.3 排查方法論從現(xiàn)象定位到根因我用了這么多年嵌入式項(xiàng)目總結(jié)出一個(gè)固定排查順序先看電源再看接線最后看代碼。這個(gè)順序不要亂。很多時(shí)候大家第一反應(yīng)就是代碼寫(xiě)錯(cuò)了查了半天最后發(fā)現(xiàn)是杜邦線松了——這種經(jīng)歷一次就夠了。我的排查動(dòng)作拆開(kāi)來(lái)講看電源用萬(wàn)用表量各節(jié)點(diǎn)電壓VM 有沒(méi)有 7.4VVCC 有沒(méi)有 3.3V 或 5V共地點(diǎn)是否連通看接線對(duì)照引腳表逐根檢查特別是 GND 必須所有模塊共地看代碼用Serial.println()把傳感器原始值、狀態(tài)變量打印出來(lái)確認(rèn)程序運(yùn)行到了哪一步還有一個(gè)我反復(fù)強(qiáng)調(diào)的小技巧把每個(gè)部分拆開(kāi)單獨(dú)測(cè)。電機(jī)不轉(zhuǎn)就先注釋掉傳感器邏輯只跑電機(jī)的代碼看電機(jī)本身有沒(méi)有問(wèn)題傳感器讀不到數(shù)據(jù)就單獨(dú)打印傳感器值看有沒(méi)有跳動(dòng)。能拆就拆拆到最后剩下的問(wèn)題才是真正的問(wèn)題。我自己用得最多的調(diào)試工具是兩樣串口打印和萬(wàn)用表。這兩樣加起來(lái)能解決掉 90% 的問(wèn)題。示波器當(dāng)然更好但新手沒(méi)必要一開(kāi)始就投入那么多等真遇到難啃的定時(shí)問(wèn)題再上儀器也不遲。做 microduck 這個(gè)項(xiàng)目給我最大的感受是它讓你親手把想法變成實(shí)物這個(gè)過(guò)程中學(xué)到的每一個(gè)小坑都是單純寫(xiě)代碼永遠(yuǎn)碰不到的。最后再分享一個(gè)實(shí)際建議——從開(kāi)工第一天就用文檔記錄每個(gè)模塊的測(cè)試結(jié)果哪怕只是幾行字。等你做到第三版、第四版回頭看這些記錄它們會(huì)比任何教程都珍貴。