小車:從避障到自主導(dǎo)航的實(shí)戰(zhàn)解析)
簡(jiǎn)介《Arduino項(xiàng)目開(kāi)發(fā)激光雷達(dá)導(dǎo)航的小車》是一份面向Arduino/樹(shù)莓派愛(ài)好者和嵌入式初學(xué)者的項(xiàng)目式開(kāi)發(fā)文檔以激光雷達(dá)自主導(dǎo)航小車為切入點(diǎn)完整呈現(xiàn)從系統(tǒng)架構(gòu)、硬件選型到代碼調(diào)試的全流程。壓縮包內(nèi)共1個(gè)文件為2.44MB的Word版技術(shù)文檔內(nèi)容圍繞微控制器MCU與樹(shù)莓派的分工協(xié)作展開(kāi)MCU負(fù)責(zé)電機(jī)底層控制樹(shù)莓派負(fù)責(zé)處理雷達(dá)數(shù)據(jù)并實(shí)時(shí)生成行駛指令兩者通過(guò)模擬串口通信并定義了前進(jìn)、后退、左轉(zhuǎn)、右轉(zhuǎn)、調(diào)速等一系列指令代碼。文檔還詳細(xì)介紹了利用PWM占空比調(diào)節(jié)電機(jī)轉(zhuǎn)速、通過(guò)左右輪速度差實(shí)現(xiàn)不同轉(zhuǎn)彎半徑等關(guān)鍵技巧同時(shí)附有代碼片段和云臺(tái)擴(kuò)展接口說(shuō)明方便讀者將方案遷移到自己的項(xiàng)目中。目前已有1042人瀏覽學(xué)習(xí)適合課程設(shè)計(jì)、機(jī)器人競(jìng)賽備賽或畢業(yè)設(shè)計(jì)參考也是計(jì)算機(jī)科學(xué)在硬件控制與數(shù)據(jù)處理應(yīng)用中的優(yōu)質(zhì)案例。 過(guò)去兩年我前后做了好幾臺(tái)基于Arduino的小車從最簡(jiǎn)單的紅外避障一路做到帶激光雷達(dá)的導(dǎo)航版本踩過(guò)的坑比寫過(guò)的代碼還多。這次做的激光雷達(dá)導(dǎo)航小車核心思路很直接用Arduino作為主控搭配一顆低成本激光雷達(dá)做環(huán)境感知實(shí)現(xiàn)小范圍內(nèi)的自主導(dǎo)航與避障。它不需要跑復(fù)雜的ROS也沒(méi)有用樹(shù)莓派整個(gè)系統(tǒng)圍繞Arduino展開(kāi)從硬件選型、供電設(shè)計(jì)到算法實(shí)現(xiàn)全部自己動(dòng)手。這篇東西會(huì)盡量把我在這個(gè)項(xiàng)目里的關(guān)鍵決策、失敗嘗試和最終跑通的方案講透給想從零開(kāi)始做激光雷達(dá)小車的朋友一個(gè)可參照的路線。適合看這篇文章的人有兩類一類是已經(jīng)玩過(guò)Arduino基本傳感器超聲波、紅外、舵機(jī)想往更高階的激光雷達(dá)方向走但不知道怎么下手的另一類是手里已經(jīng)有現(xiàn)成小車底盤想給它加裝雷達(dá)但被供電、通信、數(shù)據(jù)解析這些細(xì)節(jié)卡住的項(xiàng)目黨。如果你完全沒(méi)接觸過(guò)Arduino建議先跑一遍L(zhǎng)ED亮滅和串口打印的例子再回來(lái)看否則有些細(xì)節(jié)會(huì)接不上。1. 為什么Arduino樹(shù)莓派都能做卻仍選擇Arduino市面上做激光雷達(dá)小車的教程十個(gè)里有九個(gè)是樹(shù)莓派或者Jetson Nano當(dāng)主控再配合ROS環(huán)境跑起來(lái)。沒(méi)錯(cuò)那個(gè)方案上限高能上SLAM建圖、能跑A*全局規(guī)劃但學(xué)習(xí)曲線陡光是把ROS環(huán)境配好就能勸退一批人。我在這個(gè)項(xiàng)目里堅(jiān)持用Arduino Mega 2560核心原因是你只需要讓小車看得見(jiàn)障礙物并且做出避讓反應(yīng)這個(gè)需求用Arduino完全能扛住而且整個(gè)調(diào)試過(guò)程透明得多。Arduino做激光雷達(dá)導(dǎo)航的真正優(yōu)勢(shì)在于實(shí)時(shí)性和確定性。主頻只有16MHz但激光雷達(dá)的數(shù)據(jù)通過(guò)串口以固定波特率進(jìn)來(lái)每次掃描一周的數(shù)據(jù)量是固定的處理邏輯也是固定的循環(huán)。你不會(huì)遇到Linux系統(tǒng)調(diào)度抖動(dòng)導(dǎo)致的幀延遲也不會(huì)有內(nèi)存不足突然殺掉進(jìn)程的問(wèn)題。對(duì)于教學(xué)和驗(yàn)證原型來(lái)說(shuō)這種每一條數(shù)據(jù)都看得見(jiàn)摸得著的感覺(jué)反而比ROS黑盒更友好。當(dāng)然Arduino的短板也很明顯沒(méi)有文件系統(tǒng)無(wú)法保存地圖內(nèi)存只有8KB裝不下復(fù)雜的地圖數(shù)據(jù)結(jié)構(gòu)算力不足以同時(shí)解算里程計(jì)和激光點(diǎn)云做匹配。所以我的定位很明確Arduino負(fù)責(zé)實(shí)時(shí)反應(yīng)層上位機(jī)電腦負(fù)責(zé)決策顯示層。雷達(dá)數(shù)據(jù)發(fā)送到Arduino做緊急避障同時(shí)通過(guò)USB串口轉(zhuǎn)發(fā)到電腦端做可視化監(jiān)控。這不是妥協(xié)而是最合理的分工。關(guān)于開(kāi)發(fā)板的具體選型我一開(kāi)始用的是Arduino Uno做完第一版之后果斷換成了Mega 2560。原因倒不是Uno性能不夠而是引腳數(shù)量。激光雷達(dá)的PWM調(diào)速、兩個(gè)直流電機(jī)的方向與使能、編碼器反饋、超聲波備用傳感器、蜂鳴器、LED指示燈這些加起來(lái)Uno的可用IO就捉襟見(jiàn)肘了尤其是硬件串口。Uno只有一個(gè)硬件串口給了雷達(dá)就沒(méi)法跟電腦調(diào)試通信只能靠SoftwareSerial軟串口穩(wěn)定性奇差。Mega有四個(gè)硬件串口雷達(dá)、藍(lán)牙、調(diào)試口可以各走各的這是后期調(diào)試效率大幅提升的關(guān)鍵。2. 激光雷達(dá)選型與串口通信鏈路搭建激光雷達(dá)是整個(gè)項(xiàng)目的感知核心選型直接決定后續(xù)算法能不能跑起來(lái)。我最后用的是Neato XV-11拆機(jī)雷達(dá)也就是早期掃地機(jī)器人Neato Botvac上用的那顆二手價(jià)格很低掃描頻率大約4Hz測(cè)距范圍0.2米到6米雖然精度和現(xiàn)在的國(guó)產(chǎn)RPLIDAR A1沒(méi)法比但用來(lái)做室內(nèi)低速導(dǎo)航的感知驗(yàn)證完全夠用。如果你預(yù)算充足直接上思嵐RPLIDAR A1或者A2數(shù)據(jù)格式和接口標(biāo)準(zhǔn)得多后面接上位機(jī)也會(huì)省事很多。這里想多說(shuō)一句測(cè)距原理。XV-11用的是三角測(cè)距法激光二極管發(fā)射光斑照射到障礙物后反射反射光通過(guò)透鏡成像在CMOS傳感器上。障礙物距離不同光斑在傳感器上的成像位置也不同通過(guò)標(biāo)定好的幾何關(guān)系就能算出距離。這個(gè)原理決定了它的特性近距離精度好遠(yuǎn)距離超過(guò)5米誤差快速增大而且對(duì)環(huán)境光比較敏感。所以小車最好在室內(nèi)光線穩(wěn)定的環(huán)境下跑大太陽(yáng)底下戶外基本沒(méi)法用。串口通信是接雷達(dá)的第一道坎。XV-11的串口參數(shù)是115200波特率8位數(shù)據(jù)位無(wú)校驗(yàn)1位停止位。雷達(dá)內(nèi)部以固定周期旋轉(zhuǎn)每轉(zhuǎn)一圈輸出多組數(shù)據(jù)包。每個(gè)數(shù)據(jù)包的結(jié)構(gòu)包括同步字節(jié)、轉(zhuǎn)速信息、角度索引和一組距離數(shù)據(jù)。我拿到雷達(dá)之后第一件事不是接Arduino而是先接USB轉(zhuǎn)TTL模塊在電腦上用串口助手看原始字節(jié)流確認(rèn)數(shù)據(jù)格式后再寫解析代碼。// Arduino Mega 串口2接激光雷達(dá) void setup() { Serial.begin(115200); // 調(diào)試口兼數(shù)據(jù)轉(zhuǎn)發(fā) Serial2.begin(115200); // 雷達(dá)串口 } void loop() { if (Serial2.available()) { uint8_t b Serial2.read(); // 這里需要做數(shù)據(jù)幀同步和解析 // 詳見(jiàn)下方數(shù)據(jù)幀解析段落 } }解析的關(guān)鍵在于幀同步。XV-11的數(shù)據(jù)包以特定的同步字節(jié)0xFA開(kāi)頭但0xFA也可能出現(xiàn)在數(shù)據(jù)字段里所以不能簡(jiǎn)單看到0xFA就當(dāng)包頭。正確做法是維護(hù)一個(gè)狀態(tài)機(jī)先找到第一個(gè)0xFA然后讀下一個(gè)字節(jié)判斷是否也是0xFA如果是則確認(rèn)同步否則重新搜索。同步之后再按固定長(zhǎng)度讀取一幀從幀內(nèi)索引字段解析當(dāng)前掃描角度從數(shù)據(jù)字段解析距離值。這一步寫不好后面全是亂碼。硬件接線同樣有講究。XV-11使用5V邏輯電平Arduino Mega的IO也是5V理論可以直接連但我不建議這么做。雷達(dá)電機(jī)的啟動(dòng)瞬間會(huì)有較大的電流沖擊和電磁干擾通過(guò)地線串到數(shù)字電路里輕則丟幀重則復(fù)位。我的做法是雷達(dá)供電獨(dú)立用一塊LM2596降壓模塊直接從電池取電調(diào)到5VArduino的供電走另一路降壓模塊兩路共地但不共電源。串口線之間串了1kΩ電阻做保護(hù)實(shí)測(cè)幀丟失率從之前的接近10%降到了幾乎為零。3. 底盤結(jié)構(gòu)與電機(jī)控制先解決走得好再解決看得遠(yuǎn)導(dǎo)航算法再漂亮底盤執(zhí)行不到位也白搭。我選了兩輪差速驅(qū)動(dòng)加一個(gè)萬(wàn)向輪的經(jīng)典三輪結(jié)構(gòu)兩個(gè)直流減速電機(jī)分別驅(qū)動(dòng)左右輪通過(guò)左右輪速差實(shí)現(xiàn)轉(zhuǎn)向。這個(gè)結(jié)構(gòu)的好處是模型簡(jiǎn)單速度和轉(zhuǎn)向控制都可以套教科書(shū)上的差速模型公式后期如果要接上位機(jī)做更復(fù)雜的路徑規(guī)劃運(yùn)動(dòng)學(xué)解算也不會(huì)太痛苦。電機(jī)驅(qū)動(dòng)模塊用的是L298N。必須承認(rèn)這芯片效率不高壓降大還發(fā)熱但在這種教學(xué)項(xiàng)目里勝在皮實(shí)壞了換一塊也就幾塊錢。接線方面有個(gè)容易忽略的細(xì)節(jié)L298N上面那個(gè)5V輸出腳如果你同時(shí)給邏輯電路供電會(huì)把電機(jī)電源的紋波直接引到Arduino的5V軌上。我第一版就是這么干的結(jié)果雷達(dá)數(shù)據(jù)時(shí)不時(shí)跳一個(gè)毛刺值。后來(lái)改成L298N的5V輸出只用來(lái)給使能引腳做高電平參考Arduino的供電完全走獨(dú)立的降壓模塊問(wèn)題立刻消失。電機(jī)控制代碼我封裝成了一個(gè)Motor類左右輪各占用三個(gè)引腳兩個(gè)方向引腳控制正反轉(zhuǎn)一個(gè)PWM引腳控制速度。Arduino Mega的PWM頻率默認(rèn)約490Hz直接驅(qū)動(dòng)電機(jī)能跑但會(huì)聽(tīng)到明顯的嘯叫而且低速時(shí)線性度很差。我在代碼里把PWM頻率提高到了大約20kHz超出人耳聽(tīng)覺(jué)范圍電機(jī)運(yùn)行變得很安靜低速可控性也好了很多。具體做法是把定時(shí)器寄存器直接配置不走analogWrite的默認(rèn)設(shè)置。void setupMotors() { // 調(diào)整定時(shí)器4的PWM頻率到20kHz左右針對(duì)Mega引腳6和7 TCCR4B (TCCR4B B11111000) | B00000001; }底盤做好之后的調(diào)試同樣重要。我給兩個(gè)輪子加了霍爾編碼器每轉(zhuǎn)一圈輸出約330個(gè)脈沖用Mega的外部中斷讀取。這個(gè)編碼器讀數(shù)有兩個(gè)用途一是實(shí)現(xiàn)閉環(huán)速度控制——PID調(diào)節(jié)PWM占空比讓輪速跟隨目標(biāo)值二是粗略估計(jì)行駛距離作為導(dǎo)航的輔助數(shù)據(jù)。測(cè)出來(lái)的實(shí)際數(shù)據(jù)是設(shè)定目標(biāo)速度0.3m/s閉環(huán)穩(wěn)定后誤差在±3%以內(nèi)這個(gè)精度對(duì)于室內(nèi)低速避障足夠用了。4. 嵌入式端核心邏輯不是建圖而是看得見(jiàn)地躲這是整個(gè)項(xiàng)目里我體會(huì)最深的部分。樹(shù)莓派加ROS的路線可以跑復(fù)雜的SLAM算法但Arduino端的導(dǎo)航邏輯必須樸素務(wù)實(shí)。我最終跑通的核心策略是三層遞進(jìn)緊急剎車、方向重規(guī)劃、直行恢復(fù)。雷達(dá)數(shù)據(jù)進(jìn)來(lái)后先以車體正前方為中心取一個(gè)扇區(qū)例如左右各30度計(jì)算這個(gè)扇區(qū)內(nèi)最近障礙物的距離。如果這個(gè)距離小于安全閾值我設(shè)為0.4米立即停車然后檢查左側(cè)和右側(cè)的最近障礙物距離哪邊空間大就往哪邊原地旋轉(zhuǎn)旋轉(zhuǎn)角度根據(jù)兩側(cè)距離差連續(xù)調(diào)整避免固定角度轉(zhuǎn)彎導(dǎo)致的反復(fù)橫跳。雷達(dá)一圈有大約360個(gè)角度數(shù)據(jù)直接全量存下來(lái)做判斷對(duì)Arduino的內(nèi)存壓力比較大。我的做法是只保留前方180度范圍內(nèi)的有效距離值并且降采樣到每5度存一個(gè)代表值一個(gè)36元素的float數(shù)組總共占144字節(jié)Mega的8KB內(nèi)存輕松搞定。降采樣的過(guò)程順便做了中值濾波每個(gè)扇區(qū)取5個(gè)原始數(shù)據(jù)的中值能有效濾掉那些環(huán)境光反射造成的毛刺點(diǎn)。扇區(qū)策略聽(tīng)起來(lái)簡(jiǎn)單但實(shí)現(xiàn)起來(lái)有一個(gè)細(xì)節(jié)特別坑雷達(dá)坐標(biāo)系和車體坐標(biāo)系之間有安裝偏移。雷達(dá)裝在車頭正中旋轉(zhuǎn)軸和車體中心線沒(méi)有完全對(duì)齊掃描0度方向正對(duì)車尾。如果不做角度偏置校正車子判斷的前方其實(shí)是偏的。我在機(jī)械安裝后做了校準(zhǔn)找一面墻放在車正前方0.8米處觀察雷達(dá)數(shù)據(jù)里哪個(gè)角度讀出的距離最近記錄這個(gè)角度偏移量并存入常量后續(xù)所有扇區(qū)計(jì)算都減去這個(gè)偏移量。這一步不做實(shí)車標(biāo)定只靠尺子量安裝角度是永遠(yuǎn)調(diào)不準(zhǔn)的。避障過(guò)程中還會(huì)遇到一個(gè)典型問(wèn)題小車一旦原地旋轉(zhuǎn)雷達(dá)也跟著旋轉(zhuǎn)上一次掃描計(jì)算的右側(cè)開(kāi)闊在車子轉(zhuǎn)完90度之后已經(jīng)完全變了。所以每次決策之后必須重新讀取最新一圈掃描數(shù)據(jù)而不是復(fù)用上一圈的判斷結(jié)果。我在代碼里加了一個(gè)數(shù)據(jù)刷新標(biāo)志位——只有等到雷達(dá)傳完完整一圈通過(guò)角度索引回繞判斷之后才允許執(zhí)行下一輪避障決策。這相當(dāng)于給整個(gè)控制循環(huán)上了鎖避免決策頻率快于傳感器刷新率導(dǎo)致的失效判斷。5. 上位機(jī)可視化與數(shù)據(jù)驗(yàn)證方法Arduino端接入串口調(diào)試助手看原始數(shù)據(jù)當(dāng)然可以但想要直觀地驗(yàn)證雷達(dá)轉(zhuǎn)一圈的效果最好是做一個(gè)簡(jiǎn)單的上位機(jī)可視化。這個(gè)項(xiàng)目我沒(méi)有上ROS而是用Processing寫了一個(gè)極簡(jiǎn)的二維點(diǎn)云顯示工具。Arduino通過(guò)USB串口把降采樣后的雷達(dá)數(shù)據(jù)按特定格式發(fā)出來(lái)每幀數(shù)據(jù)以幀頭AA起始后面跟36組角度和距離值最后以校驗(yàn)和結(jié)尾。Processing端讀取串口解析出每組數(shù)據(jù)換算成極坐標(biāo)下的點(diǎn)坐標(biāo)并畫(huà)在畫(huà)布上同時(shí)畫(huà)出車體輪廓和當(dāng)前避障決策狀態(tài)。這個(gè)可視化工具的價(jià)值遠(yuǎn)超看起來(lái)炫酷。我調(diào)試過(guò)程中的很多奇怪問(wèn)題都是靠它發(fā)現(xiàn)的。比如有一次小車總朝一個(gè)方向偏點(diǎn)云顯示出來(lái)發(fā)現(xiàn)雷達(dá)掃描圓的圓心和車體中心偏差了大約8厘米檢查之后發(fā)現(xiàn)是雷達(dá)固定支架的孔位打偏了。還有一次發(fā)現(xiàn)距離數(shù)據(jù)在某個(gè)角度區(qū)間周期性跳動(dòng)最后定位到是雷達(dá)供電電壓紋波太大導(dǎo)致的測(cè)距波動(dòng)。這些問(wèn)題如果只看串口數(shù)字很難快速定位但一旦把數(shù)據(jù)畫(huà)出來(lái)異常就非常直觀。數(shù)據(jù)驗(yàn)證方面我建議拿到雷達(dá)后先做一組靜態(tài)精度測(cè)試在0.3米、0.5米、1米、2米、3米五個(gè)距離點(diǎn)各放一個(gè)白色紙板用激光測(cè)距儀做基準(zhǔn)對(duì)比雷達(dá)讀數(shù)。我的XV-11實(shí)測(cè)結(jié)果是0.5米以內(nèi)誤差約±2厘米1至2米誤差約±5厘米3米以上誤差跑到了±15厘米。所以我把避障安全閾值設(shè)置在0.4米是有依據(jù)的——在這個(gè)范圍內(nèi)讀數(shù)誤差不足以讓算法產(chǎn)生危險(xiǎn)誤判。每一顆雷達(dá)的出廠標(biāo)定狀態(tài)不同拿到手先測(cè)一組真實(shí)數(shù)據(jù)后面所有算法閾值才能定得有底氣。6. 電源系統(tǒng)設(shè)計(jì)激光雷達(dá)項(xiàng)目的隱藏大坑這個(gè)章節(jié)值得單獨(dú)拎出來(lái)說(shuō)。激光雷達(dá)比超聲波、紅外這些傳感器嬌貴得多供電質(zhì)量直接影響測(cè)距數(shù)據(jù)質(zhì)量。我踩過(guò)最慘的一次坑是這樣的第一版用單節(jié)3S鋰電池通過(guò)7805線性穩(wěn)壓到5V給雷達(dá)供電地面測(cè)試一切正常一放到地上走起來(lái)雷達(dá)數(shù)據(jù)就開(kāi)始抽風(fēng)距離值頻繁跳變。示波器一量電池空載時(shí)電壓12.4V電機(jī)啟動(dòng)瞬間電壓跌到10.5V7805輸入輸出壓差不足5V輸出掉到了4.6V雷達(dá)直接進(jìn)入欠壓狀態(tài)。解決辦法是換成兩級(jí)供電方案。電池12V輸出分兩路一路接LM2596降壓模塊調(diào)到6V專門給雷達(dá)供電雷達(dá)板載穩(wěn)壓再把6V降到5V這樣即便電機(jī)拖動(dòng)電池電壓波動(dòng)雷達(dá)端的輸入仍有足夠的壓差余量另一路接另一個(gè)LM2596調(diào)到7.5V給Arduino的Vin供電和L298N邏輯供電。兩個(gè)降壓模塊共地但輸出互不干擾。實(shí)測(cè)在電機(jī)啟停、正反轉(zhuǎn)切換的瞬態(tài)過(guò)程中雷達(dá)供電端的電壓波動(dòng)控制在±0.15V以內(nèi)測(cè)距數(shù)據(jù)明顯穩(wěn)定了。還有一個(gè)很多人忽略的點(diǎn)雷達(dá)的電機(jī)和測(cè)距模塊共用一條電源線。測(cè)距模塊對(duì)電源噪聲很敏感而電機(jī)換向時(shí)的火花會(huì)產(chǎn)生高頻噪聲疊加在電源線上。我的處理是在雷達(dá)供電端并聯(lián)一個(gè)470μF電解電容和一個(gè)0.1μF陶瓷電容電解電容吸收低頻波動(dòng)陶瓷電容濾高頻噪聲。另外一個(gè)技巧是雷達(dá)盡量用獨(dú)立的降壓模塊不要和舵機(jī)、電機(jī)驅(qū)動(dòng)共用一個(gè)模塊哪怕那個(gè)模塊電流余量足夠大噪聲串?dāng)_的問(wèn)題依然存在。7. 不同場(chǎng)景下的實(shí)測(cè)表現(xiàn)與參數(shù)調(diào)優(yōu)方法整套系統(tǒng)聯(lián)調(diào)完成之后我做了三組場(chǎng)景測(cè)試這組數(shù)據(jù)對(duì)實(shí)際調(diào)參參考意義最大。第一組是空曠房間直行測(cè)試。房間大約4米乘5米中間無(wú)遮擋小車從一側(cè)直行到另一側(cè)。因?yàn)榍胺?80度內(nèi)沒(méi)有障礙物避障邏輯不觸發(fā)小車以0.3m/s均勻直行。這組測(cè)試主要驗(yàn)證底盤閉環(huán)和里程計(jì)精度實(shí)測(cè)行走3.5米編碼器累積距離3.42米誤差約2.3%來(lái)源主要是輪子打滑和編碼器安裝間隙。結(jié)論是里程計(jì)只能作短距離輔助定位不適合作長(zhǎng)時(shí)間導(dǎo)航的位置依據(jù)。第二組是單障礙物避讓測(cè)試。在小車前進(jìn)路徑上放一個(gè)紙箱寬約40厘米距離起點(diǎn)大約1.5米。小車以0.2m/s前進(jìn)當(dāng)雷達(dá)檢測(cè)到正前方0.4米內(nèi)有障礙時(shí)急停然后判斷左側(cè)無(wú)障礙、右側(cè)有墻于是向左原地旋轉(zhuǎn)約70度后直行繞開(kāi)紙箱后再通過(guò)邏輯判斷恢復(fù)原航向。這套流程跑下來(lái)大約用了6秒軌跡比較順滑沒(méi)有出現(xiàn)反復(fù)橫擺。調(diào)參的關(guān)鍵是兩個(gè)閾值安全距離0.4米和旋轉(zhuǎn)角度的比例系數(shù)。安全距離設(shè)得太大小車離障礙物老遠(yuǎn)就開(kāi)始躲路徑繞得遠(yuǎn)設(shè)得太小剎車距離不夠容易撞上。我實(shí)測(cè)下來(lái)0.4米對(duì)應(yīng)0.2m/s的車速比較合理速度每提高0.1m/s安全距離要相應(yīng)增加約0.15米。第三組是密集障礙物穿行測(cè)試。房間里擺了四五把椅子和幾個(gè)紙箱通道最窄處約60厘米。這種場(chǎng)景對(duì)XV-11這種低幀率雷達(dá)來(lái)說(shuō)已經(jīng)接近能力極限。小車能走出去但路徑比較猶豫經(jīng)常走走停停偶爾還會(huì)陷入原地旋轉(zhuǎn)的死循環(huán)。問(wèn)題根源在于雷達(dá)掃描頻率只有4Hz而車子的決策周期遠(yuǎn)快于這個(gè)頻率導(dǎo)致連續(xù)好幾輪看到的是同一幀舊數(shù)據(jù)。我的解決辦法是當(dāng)檢測(cè)到兩側(cè)距離同時(shí)小于0.3米時(shí)強(qiáng)制轉(zhuǎn)入脫困模式——反向直行退0.5米再重新掃描判斷。這相當(dāng)于給避障邏輯加了一個(gè)防止死鎖的看門狗機(jī)制實(shí)際效果立竿見(jiàn)影。如果你的雷達(dá)是RPLIDAR A1掃描頻率能到10Hz以上這個(gè)死鎖問(wèn)題會(huì)輕微很多但脫困模式仍然值得保留。8. 整個(gè)項(xiàng)目做完后我最后悔沒(méi)早點(diǎn)知道的事回頭看這個(gè)項(xiàng)目有兩點(diǎn)想特別分享。第一是務(wù)必在項(xiàng)目開(kāi)始前就把上位機(jī)調(diào)試工具準(zhǔn)備好。我第一次調(diào)試?yán)走_(dá)數(shù)據(jù)的時(shí)候就靠Serial.println往串口監(jiān)視器刷數(shù)字看到一串串距離值根本不知道雷達(dá)轉(zhuǎn)得對(duì)不對(duì)、某個(gè)角度是不是有盲區(qū)。后來(lái)寫了個(gè)最簡(jiǎn)單的SerialPlotter可視化用折線圖顯示一圈掃描數(shù)據(jù)才第一次直觀地看到雷達(dá)的整個(gè)視野。如果你不想自己寫Processing工具也可以用開(kāi)源串口繪圖工具把數(shù)據(jù)格式化成角度:距離逐行輸出畫(huà)出來(lái)之后整個(gè)系統(tǒng)狀態(tài)一目了然。第二是電機(jī)控制一定要先于雷達(dá)調(diào)試完成。很多人跟我一樣拿到激光雷達(dá)很興奮先花了一周調(diào)通了雷達(dá)通信和數(shù)據(jù)解析然后才去折騰底盤和電機(jī)驅(qū)動(dòng)。結(jié)果聯(lián)調(diào)那天發(fā)現(xiàn)電機(jī)PWM一開(kāi)雷達(dá)數(shù)據(jù)立刻變差前面調(diào)通的東西全部需要重來(lái)。正確的順序應(yīng)該是先把底盤做到輪速閉環(huán)穩(wěn)定、PWM輸出對(duì)測(cè)距無(wú)干擾再接入雷達(dá)做感知層調(diào)試最后才是導(dǎo)航算法的聯(lián)調(diào)。每往下走一層都要確保底下那層已經(jīng)穩(wěn)固不要跳級(jí)。關(guān)于后續(xù)擴(kuò)展我現(xiàn)在的方向是給這輛小車加藍(lán)牙模塊把上游的決策數(shù)據(jù)和雷達(dá)降采樣數(shù)據(jù)實(shí)時(shí)發(fā)到手機(jī)端App顯示同時(shí)通過(guò)手機(jī)上按鍵下發(fā)目標(biāo)點(diǎn)讓小車朝著指定方向自主行駛。雖然還是到不了完整SLAM的程度但作為Arduino平臺(tái)下理解感知-決策-執(zhí)行閉環(huán)的載體這套系統(tǒng)已經(jīng)能覆蓋很完整的知識(shí)面了。如果你也想動(dòng)手做一輛不必追求昂貴的雷達(dá)和復(fù)雜的算法先把一整套閉環(huán)跑通獲得的經(jīng)驗(yàn)比堆硬件更有價(jià)值。本文還有配套的精品資源點(diǎn)擊獲取