架構(gòu)到PID調(diào)參實戰(zhàn))
簡介這是一份基于51單片機的兩輪自平衡小車完整工程包適合正在學習嵌入式控制、電機驅(qū)動或PID算法的初學者和電子愛好者。資料圍繞項目實現(xiàn)展開從硬件組成到軟件邏輯均有覆蓋。壓縮包共140個文件約477KB以C語言與匯編源代碼、Keil工程配置、A51啟動文件、hex燒錄文件以及obj/lst等編譯中間文件為主便于在Keil中直接打開查看與二次開發(fā)。已有1360人學習下載。通過閱讀源碼可理解傾角數(shù)據(jù)采集、PID偏差計算、電機PWM輸出和藍牙串口指令解析的完整流程壓縮包內(nèi)文件組織清晰按目錄閱讀十分方便。項目也涉及傳感器選型與電源管理等硬件設(shè)計要點對于想把自平衡原理落地到真實硬件上的讀者是一份示例完整、可直接參考的實戰(zhàn)資料。無論是課程設(shè)計還是個人興趣項目都能從中獲得從算法到硬件的完整經(jīng)驗。 自平衡小車這個項目在51單片機學習路徑里算是一個分水嶺。前面玩流水燈、數(shù)碼管、按鍵中斷本質(zhì)上還是在跟單片機的“外圍設(shè)備”打交道而自平衡小車第一次把一個帶有負反饋的控制閉環(huán)塞進了八位機里讓單片機的角色從“邏輯控制器”變成了“實時控制器”。最有意思的是網(wǎng)上流傳的“51單片機自平衡小車.zip”這類壓縮包往往不只是一個源碼文件夾里面通常包含了原理圖、PCB、PID參數(shù)、調(diào)車思路甚至還有當年調(diào)車時踩坑的聊天記錄這些東西比光看教程有用得多。收到一個不明來歷的zip第一件事不是解壓跑代碼而是先把整個包的結(jié)構(gòu)摸透。我就按自己解壓這類項目包的習慣從系統(tǒng)框架到硬件選型再到姿態(tài)解算和PID調(diào)參把整個項目的關(guān)鍵環(huán)節(jié)拆開聊一聊其中穿插一些當初調(diào)車時摔出來的經(jīng)驗。1. 項目整體設(shè)計與系統(tǒng)架構(gòu)拆解1.1 解壓之后一個靠譜壓縮包應(yīng)該長什么樣一個真正值得參考的“51單片機自平衡小車.zip”通常不會只有一份main.c。常見的完整包應(yīng)該包含這幾類內(nèi)容源碼目錄包含main.c、mpu6050.c、pid.c、motor.c、uart.c等模塊劃分清晰的工程文件而不是所有邏輯全塞在一個文件里。硬件資料原理圖PDF、PCB源文件可能是DXP或立創(chuàng)EDA格式、元器件BOM清單。調(diào)試工具串口上位機程序用于看波形、調(diào)參數(shù)、PID調(diào)節(jié)說明文檔。調(diào)車記錄如果作者有心會把調(diào)車過程中遇到的現(xiàn)象、參數(shù)變化、解決辦法放在README或博客鏈接里。如果壓縮包里只有單一代碼文件也沒有原理圖和接線說明那這個包的質(zhì)量就要打一個問號。好的工程習慣是模塊化分離——傳感器采集、數(shù)據(jù)處理、控制邏輯、電機驅(qū)動各管各的這樣以后你想換傳感器或者改控制算法只需要改對應(yīng)模塊。當年我拿到第一個自平衡車項目時代碼是一坨一千多行的main.c調(diào)的時候注釋掉了半篇代碼痛苦得不行。1.2 平衡車的閉環(huán)框架傳感器-控制-執(zhí)行整個自平衡小車的控制邏輯用一句話說就是通過MPU6050傳感器感知車身傾角單片機計算后輸出PWM波控制電機讓車身始終保持在直立平衡點附近。系統(tǒng)的信號流是這樣的MPU6050采集角速度/加速度 → I2C總線 → 51單片機STC12系列 → PID控制器計算輸出 → PWM輸出 → TB6612電機驅(qū)動 → 直流減速電機 → 車身姿態(tài)修正 ↓ 車身的姿態(tài)變化又反過來被MPU6050感知形成閉環(huán)負反饋核心是“負反饋”不是“大力出奇跡”。人騎自行車保持平衡也不是靠肌肉硬撐而是通過不斷微調(diào)方向來維持重心投影在支撐面內(nèi)。自平衡小車做的是一維版本的這件事情——讓重心始終保持在車輪軸上方的那個窄窄的平衡區(qū)間里。1.3 為什么用51單片機做自平衡車很多人一上來就問51單片機做自平衡車算力夠嗎主頻才12MHz還要處理浮點運算MPU6050的數(shù)據(jù)讀取通過I2C速度也一般是不是應(yīng)該換STM32這里我的回答是51做自平衡尤其是STC12系列比如STC12C5A60S2不但做得成而且作為學習項目反而是最好的選擇。STM32的算力強大調(diào)試工具豐富但它也會掩蓋很多底層問題。用51你得精打細算——中斷怎么安排PWM頻率選多少I2C時序要不要用硬件方式實現(xiàn)浮點運算要怎樣用int替代每一步都在逼你理解單片機資源的本質(zhì)。自平衡車控制周期可以做到10ms左右PID運算本身計算量不大51的1T模式下完全跑得動。難的不是算不過來而是你怎么把有限的算力花在刀刃上。8位機做浮點運算是很奢侈的事情所以有經(jīng)驗的作者會在源碼里把PID計算和姿態(tài)融合寫成整數(shù)運算或者用移位替代乘除法。這一點跟你拿到手的zip里代碼質(zhì)量直接相關(guān)——如果代碼里大量使用float并且沒做任何優(yōu)化那調(diào)出來的效果會一言難盡。2. 硬件選型與電路設(shè)計核心2.1 主控最小系統(tǒng)STC12系列的關(guān)鍵優(yōu)勢自平衡小車項目里常用的51單片機不是89C52而是STC12C5A60S2等1T增強型51。這里區(qū)別很大89C52是12T指令周期是系統(tǒng)時鐘的12分頻而STC12是1T單周期指令執(zhí)行效率高了差不多12倍。還有一點很關(guān)鍵STC12C5A60S2自帶兩個PWM模塊和ADC省去了外部擴展PWM芯片的工作同時也支持6~8路硬件PWM輸出這對同時驅(qū)動兩個電機、后續(xù)還要擴展舵機等模塊非常方便。除此之外STC12系列還內(nèi)置了1K字節(jié)的SRAM比89C52的256字節(jié)大了不少存幾十個數(shù)組的傳感器數(shù)據(jù)不會捉襟見肘。最小系統(tǒng)的設(shè)計里最容易出問題的不是單片機本體而是電源。51單片機正常工作電流在20~50mAMPU6050約3.9mATB6612待機電流大約2mA整個系統(tǒng)總電流并不大但在電機啟動和堵轉(zhuǎn)瞬間瞬時電流可以達到幾百毫安甚至超過1A。這時候如果供電設(shè)計不合理電壓跌落會導(dǎo)致單片機復(fù)位小車正在平衡突然就趴窩了。最穩(wěn)的方法是把模擬電源和功率電源分開走線在單片機電源引腳處放置10μF電解電容和0.1μF陶瓷電容做去耦并且電機電源、邏輯電源用共地但獨立走線的方式連接。很多自平衡車調(diào)不好問題不在算法在電源紋波太大導(dǎo)致MPU6050數(shù)據(jù)跳變。2.2 傳感器單元MPU6050的使用要點MPU6050在自平衡小車項目里幾乎是標配6軸數(shù)據(jù)3軸加速度3軸角速度集成在一個QFN封裝的小芯片里通過I2C接口跟單片機通信。它內(nèi)部自帶DMP處理器可以直接輸出四元數(shù)但在51平臺上用DMP的例子不太多因為DMP初始化需要一些庫文件對單片機資源要求也高。自平衡小車只需要傾角數(shù)據(jù)我們用DMP反而有點殺雞用牛刀——直接在單片機里做姿態(tài)解算就夠了。接線時要注意I2C地址的問題。MPU6050的AD0引腳接GND時地址是0x68接VCC時地址是0x69。很多初學者第一次燒錄代碼后讀不到數(shù)據(jù)就是AD0默認懸空或接錯導(dǎo)致地址對不上。MPU6050供電要求是3.3V而51單片機是5V電平I2C通信是開漏結(jié)構(gòu)所以SDA和SCL線上要接上拉電阻到3.3V電壓域不能直接跟5V的51引腳硬連接。有些板子把MPU6050模塊集成了電平轉(zhuǎn)換電路直接5V供電也行但如果用的是裸芯片或沒有電平轉(zhuǎn)換的模塊這個問題就會讓你調(diào)試到懷疑人生。放置位置也有講究MPU6050盡量安裝在車身的中軸線上傳感器方向要與車身方向一致。如果模塊裝歪了或者偏了姿態(tài)解算出來的角度會有固定的偏置誤差后面調(diào)PID時會表現(xiàn)為小車往一邊倒而且你怎么調(diào)P、D都不管用。2.3 電機驅(qū)動方案TB6612與L298N的選擇自平衡小車項目里電機驅(qū)動模塊主要有兩種方案TB6612FNG和L298N。TB6612FNG是東芝推出的MOSFET型H橋驅(qū)動芯片最大驅(qū)動電流約1.2A內(nèi)部MOSFET導(dǎo)通電阻很低壓降小發(fā)熱量低PWM頻率可以支持到100kHz。而L298N是雙極性三極管方案壓降約2~3V驅(qū)動電流2A但自身功耗大發(fā)熱嚴重而且體積大裝在小車底盤上不太方便。在自平衡小車這種需要頻繁正反轉(zhuǎn)、快速響應(yīng)PWM控制的場景下我強烈推薦TB6612。它的PWM控制頻率響應(yīng)更快死區(qū)時間短適合PWM周期在1kHz~10kHz的控制場景。L298N更適合大功率直流電機且對控制實時性要求不高的場合。TB6612的接線也要注意VM接電機電源典型值6~12VVCC接邏輯電源2.7~5.5V通常直接接單片機的5V輸出AIN1/AIN2控制A電機的正反轉(zhuǎn)PWMA控制速度STBY接高電平使能輸出。有些人做自平衡車圖省事直接用L298N模塊上自帶的5V輸出去給單片機和MPU6050供電。但這里有個坑——L298N的5V輸出是從VM降壓來的線性穩(wěn)壓器在電機堵轉(zhuǎn)時會因為輸入電壓跌落導(dǎo)致輸出也跟著波動。一旦5V電壓跌破單片機正常工作范圍系統(tǒng)就會復(fù)位重啟。所以最好的供電方案是電機電源和邏輯電源獨立或者至少用單獨的穩(wěn)壓芯片給邏輯部分供電。2.4 電源系統(tǒng)的算賬式設(shè)計電源是一個自平衡車項目的生死線。以常見的7.4V 2S鋰電池為例整個供電結(jié)構(gòu)可以這樣設(shè)計鋰電池輸出7.4V直接給TB6612的VM供電經(jīng)過LM2596或AMS1117穩(wěn)壓后給單片機和傳感器供電。但要注意AMS1117-3.3的壓差在1.1V以上如果電池電壓在電機大電流拉低下跌到4.5V以下3.3V輸出就會掉出工作范圍。所以更多人用低壓差LDO或者DC-DC降壓模塊。整車電流的計算大概是這樣的兩個直流減速電機正常運行電流各約150mA堵轉(zhuǎn)電流可能到1A以上邏輯部分約100mA。如果用小容量鋰電池比如500mAh滿電時電壓接近8.4V但電機一堵轉(zhuǎn)電壓掉得很快這時候不是算法問題是硬件撐不住。我的建議是至少用1000mAh以上的2S電池并留出充足的電壓余量給電源穩(wěn)壓器。后來我學到一個實用技巧給MPU6050的供電加一個RC濾波10Ω電阻串聯(lián)100μF電容這樣電源上的高頻紋波和電機換向產(chǎn)生的毛刺會被濾掉不少傳感器數(shù)據(jù)會干凈很多。別小看這幾個元器件它們對調(diào)車成功率的影響比換一個更復(fù)雜的濾波算法更直接。3. 軟件核心姿態(tài)解算與PID控制3.1 姿態(tài)解算互補濾波為何比卡爾曼更通用自平衡小車需要知道車身的“角度”但MPU6050直接輸出的原始數(shù)據(jù)并不是干凈的角度。加速度計通過測量重力在三軸的分量可以計算出傾角但加速度計對振動非常敏感電機轉(zhuǎn)動時產(chǎn)生的振動會混入大量高頻噪聲。陀螺儀輸出的是角速度對角速度積分可以得到角度但積分會累積漂移誤差時間越長誤差越大。經(jīng)典的解決方案是用互補濾波低頻段信任加速度計姿態(tài)不漂移高頻段信任陀螺儀響應(yīng)快、抗振動用一個系數(shù)α把兩者融合在一起?;パa濾波的公式主要包含以下幾步dt 采樣周期通常0.005s或0.01s angle α × (angle gyro_rate × dt) (1 - α) × accel_angle 其中α通常在0.95~0.98α越大對陀螺儀信任度越高角度曲線更平滑但響應(yīng)更慢α越小對加速度計跟蹤更快但振動噪聲更容易被引入。實際項目中α取0.98、dt取0.005s是比較常用的起始組合。我貼一段經(jīng)典的互補濾波實現(xiàn)// 互補濾波融合得到最終角度 float ComplementaryFilter(float accel_angle, float gyro_rate, float dt) { float angle 0.0f; angle 0.98f * (angle gyro_rate * dt) 0.02f * accel_angle; return angle; }用卡爾曼濾波在理論精度上優(yōu)于互補濾波但它涉及協(xié)方差矩陣的迭代計算在51平臺上每一步矩陣運算的浮點開銷不可忽視。實測下來自平衡小車這種線性度較好的場景互補濾波完全夠用而且調(diào)試直觀、參數(shù)簡單。如果你拿到的代碼里用的是卡爾曼濾波多半作者是個算法愛好者也可以學習但別被復(fù)雜的公式勸退。3.2 PID控制器的層級與優(yōu)先級自平衡小車控制的核心是PID但大多數(shù)項目里的PID并不是一個而是兩個環(huán)串聯(lián)直立環(huán)角度環(huán)速度環(huán)轉(zhuǎn)速環(huán)。直立環(huán)是內(nèi)環(huán)也是平衡的基礎(chǔ)直立環(huán)輸出 Kp_angle × 角度 Kd_angle × 角速度其中Kd作用于角速度陀螺儀的原始輸出起到“阻尼”作用。如果只有Kp沒有Kd小車會像一個沒有阻尼的鐘擺來回震蕩不止。Kd的存在就是為了消耗這種振蕩的能量。速度環(huán)是外環(huán)解決的是小車向一個方向加速跑走的問題速度環(huán)輸出 Kp_speed × 速度偏差 Ki_speed × 速度積分最終電機PWM輸出為兩者疊加PWM 直立環(huán)輸出 速度環(huán)輸出速度環(huán)的反饋一般來自電機自帶的霍爾編碼器通過對編碼器脈沖計數(shù)計算車輪轉(zhuǎn)速。編碼器一般有PPR每轉(zhuǎn)脈沖數(shù)參數(shù)比如常見的微型減速電機帶11線霍爾編碼器配合減速比1:30那么電機軸每轉(zhuǎn)一圈輸出的脈沖數(shù)為11×30330個。用定時器捕獲編碼器脈沖每10ms統(tǒng)計一次除以時間就得到轉(zhuǎn)速。3.3 平衡車調(diào)參的順序先直立后速度環(huán)調(diào)參的順序有講究順序搞反了大概率調(diào)不出一個能立住的車。第一步單獨調(diào)整直立環(huán)。先把速度環(huán)系數(shù)全部設(shè)為0只讓直立環(huán)工作。逐步增大Kp_angle你會看到小車開始有“對抗重力”的傾向繼續(xù)增加到臨界值附近時小車會開始高頻抖動這時候加入Kd_angle抖動會被抑制住。注意直立環(huán)的P和D是一起調(diào)的不要只調(diào)P不調(diào)D。第二步加入速度環(huán)。直立環(huán)能把小車穩(wěn)定在一個位置附近但它會像一個“不倒翁”一樣慢慢往一個方向跑。速度環(huán)的加入讓車子檢測到“我在往一個方向跑”時主動傾斜車身回到中心位置就像人騎車時通過前傾來減速一樣。調(diào)參過程中最容易踩的坑是一上來就把P調(diào)得特別大以為響應(yīng)快就能立得住。實際上P太大會讓系統(tǒng)進入自激振蕩馬達嘶嘶響然后小車直接甩出去。參數(shù)的調(diào)節(jié)要從“小車站不穩(wěn)”過渡到“小車站得僵硬”再到“小車站得自然”是一個漸進的過程。4. 常見問題與調(diào)試實錄4.1 從拿到zip到跑起來的典型問題速查問題現(xiàn)象可能原因排查方法MPU6050讀不到數(shù)據(jù)I2C地址錯AD0懸空確認AD0接GND地址0x68MPU6050數(shù)據(jù)跳變電源紋波大濾波不干凈單獨給傳感器加RC濾波小車完全不動PWM信號沒輸出或TB6612未使能檢查STBY是否接高電平檢查PWM頻率小車高頻抖動直立環(huán)P過大或D不足降低Kp增加Kd小車往一邊加速跑速度環(huán)未生效或傳感器偏置先調(diào)直立環(huán)再調(diào)速度環(huán)上電后單片機反復(fù)重啟電源跌壓導(dǎo)致復(fù)位檢查電池容量使用獨立穩(wěn)壓供電車身傾斜但電機不反向轉(zhuǎn)動PWM死區(qū)設(shè)置過大減小死區(qū)值檢查電機接線4.2 調(diào)車現(xiàn)場手記一次典型的上位機調(diào)試過程我的習慣是把上位機波形打開串口發(fā)送角度值、角速度值、PID輸出值在電腦上實時看曲線。串口波特率115200時發(fā)送周期10ms是可行的注意浮點數(shù)太多時串口會成為瓶頸所以盡量只發(fā)送幾個關(guān)鍵變量。調(diào)試中我遇到過一個很經(jīng)典的問題小車能立住但每隔幾秒鐘就會突然往一個方向猛沖一下然后恢復(fù)直立反復(fù)循環(huán)。后來看波形發(fā)現(xiàn)速度環(huán)的積分項一直累積到比較大的值觸發(fā)了輸出飽和導(dǎo)致PWM輸出突變。解決辦法是給速度環(huán)積分項加一個限幅或者設(shè)置抗積分飽和的機制。很多項目源碼里沒有加上限這是調(diào)車時最容易被忽略的細節(jié)。另一個問題是電機死區(qū)補償。普通減速電機在PWM占空比很低的時候因為靜摩擦力的存在電機并不會轉(zhuǎn)動。如果PID輸出量很小電機不轉(zhuǎn)小車就會慢慢傾斜PID誤差增大輸出增大電機突然轉(zhuǎn)起來然后又過沖——這個現(xiàn)象在調(diào)直立環(huán)時特別常見。解決辦法是在PID輸出上疊加一個固定的死區(qū)補償值或者調(diào)整PWM占空比的映射方式讓低占空比區(qū)域的有效輸出不為零。4.3 從復(fù)制到融會貫通如何正確“使用”這份zip我的態(tài)度是奔著復(fù)現(xiàn)去沒問題但如果只在別人的代碼上小改參數(shù)項目做完之后你和它之間仍然是陌生人。建議把源碼里的幾個關(guān)鍵文件mpu6050.c、pid.c、motor.c打開逐行理解數(shù)據(jù)流是怎么走的然后把眼睛閉上試著在A4紙上把復(fù)用濾波和PID的代碼結(jié)構(gòu)默寫出來。只有做到這一步你才真正內(nèi)化了這個項目。你會發(fā)現(xiàn)其實一共沒幾行核心代碼真正的技術(shù)壁壘在硬件布局、供電設(shè)計和調(diào)參手感上。5. 寫給后來者的調(diào)車心得最后再分享一點個人的感受。自平衡小車這個項目本質(zhì)上不是讓代碼跑通而是讓一輛車在沒有外力干預(yù)的情況下自己站穩(wěn)。這個過程里你學到的不只是I2C通信、PWM輸出、中斷定時器更重要的是理解“系統(tǒng)”這個詞——一個由傳感器、執(zhí)行器、控制器互相耦合的系統(tǒng)任何一個環(huán)節(jié)出問題整個系統(tǒng)都會表現(xiàn)出異常而你要做的事情是從現(xiàn)象反推原因。如果這時候你手里正好有一份“51單片機自平衡小車.zip”打開它把原理圖看懂把芯片手冊翻出來把代碼一行一行讀清楚然后照著硬件圖焊接或接線把代碼燒錄進去開始你的調(diào)參之旅。等你真的看到小車自己站起來的那一剎那前面所有的排查和調(diào)試都會變得值得。本文還有配套的精品資源點擊獲取