
1. 項目概述與核心思路做一臺能自己站起來的平衡小車大概是每個玩單片機的朋友都繞不開的一個“執念”。我第一次看到別人做的平衡小車視頻時那種顛覆物理直覺的穩定感讓我立刻決定自己也要搞一臺。但真動手了才發現從“知道原理”到“能讓它穩穩立住”中間隔著無數個需要親手調試的坑。這個項目我們聚焦最核心、也最磨人的部分——平衡控制。它不涉及復雜的循跡或遙控目標純粹而直接讓一個兩輪結構在沒有任何外部支撐的情況下自主保持直立。這本質上是一個典型的倒立擺控制問題。你可以把它想象成用手掌豎直托起一根長桿桿子往前倒你的手就得往前追桿子往后倒你的手就得往后撤。我們的STM32單片機就是那個“大腦”它通過讀取車體傾角是往前倒還是往后倒和傾角變化的速度倒得快還是慢然后快速計算出兩個電機應該轉多快、往哪個方向轉來模擬手掌的追桿動作從而維持車體的動態平衡。整個系統的核心閉環是這樣的傳感器感知姿態 - 單片機處理數據并計算控制量 - 電機驅動執行動作 - 車體姿態改變 - 傳感器再次感知。這個循環必須在極短的時間內通常是幾毫秒完成任何一環的延遲或誤差累積都會導致小車劇烈振蕩甚至直接“趴窩”。所以這個項目不僅是對STM32性能的考驗更是對控制算法理解、傳感器數據處理和電機驅動調參的一次綜合實戰。無論你是想深入理解PID控制還是想挑戰嵌入式實時系統自制平衡小車都是絕佳的練手項目。2. 硬件系統設計與核心器件選型硬件是算法的基石一個穩定可靠的硬件平臺能讓后續的調試事半功倍。平衡小車的硬件架構相對清晰主要圍繞感知、決策、執行三大模塊展開。2.1 主控與姿態感知模塊主控芯片STM32F103C8T6核心板這是平衡小車領域經久不衰的“神U”選擇它主要基于幾點考量首先是性能足夠72MHz的主頻和充足的定時器、中斷資源能夠輕松應對毫秒級的控制周期計算。其次是生態完善無論是標準庫還是HAL庫資料和例程都極其豐富社區里你遇到的絕大多數問題都能找到答案。最后是成本核心板價格低廉即便調試過程中操作失誤導致損壞也不會太心疼。對于初次嘗試完全夠用如果想追求更高性能或更多功能如接入更復雜的濾波算法、無線調試可以考慮STM32F4系列但F103是性價比最高的起點。姿態傳感器MPU6050六軸陀螺儀加速度計這是整個系統的“眼睛”。它集成了三軸陀螺儀測量角速度和三軸加速度計測量加速度通過融合這兩類數據我們可以解算出車體相對于重力方向的傾角。為什么不用簡單的角度傳感器因為我們需要的是動態、實時的姿態MPU6050以數字信號輸出通過I2C接口與單片機通信速度快集成度高。注意MPU6050模塊一定要選擇帶電平轉換芯片和穩壓電路的版本。因為MPU6050芯片本身是3.3V供電而很多調試器或供電是5V直接連接可能損壞傳感器。好的模塊會集成一顆如AMS1117的LDO和TXS0108E之類的電平轉換器省去很多麻煩。2.2 執行與驅動模塊電機TT減速直流電機帶編碼器電機的選擇直接決定了小車的“力氣”和“反應速度”。我們通常選擇N20或類似尺寸的減速直流電機。減速比很重要常見的有1:30, 1:100, 1:200等。減速比越大輸出扭矩越大力氣大帶得動車體但最高轉速越低反應可能慢。對于自重約300-500克的小車1:100左右的減速比是一個不錯的平衡點。務必選擇帶正交編碼器的型號。編碼器是閉環控制的“另一只眼”它反饋電機輪子的實際轉速讓我們能實現精準的速度控制這是實現平衡和后續速度環、轉向環的基礎。電機驅動TB6612FNG 或 DRV8833絕不推薦使用L298N。雖然L298N經典但其壓降大、發熱嚴重、控制精度一般。TB6612FNG和DRV8833是更現代的MOSFET橋驅動芯片效率高、發熱小、支持PWM頻率更高。TB6612FNG驅動能力更強單路1.2A邏輯電壓與單片機3.3V兼容性好DRV8833體積更小價格略有優勢。兩者都支持雙路電機控制且帶有待機引腳方便安全控制。2.3 電源與結構模塊電源18650鋰電池兩節串聯7.4V電機和單片機系統最好分開供電。方案一兩節18650串聯得到7.4V直接給電機驅動供電同時使用一塊降壓模塊如MP1584EN將7.4V降為穩定的5V或3.3V給單片機和傳感器供電。方案二使用一塊帶充放電保護板的2S鋰電池搭配一個雙路輸出的DC-DC降壓模塊分別輸出電機驅動所需的電壓和單片機所需的電壓。絕對不要試圖用USB供電來驅動電機電流遠遠不夠會導致小車一啟動就復位。車體結構亞克力或碳纖維板結構強度至關重要。車體不能太軟否則會在啟動或平衡時產生難以建模的形變和振動。自己用亞克力激光切割是最常見的選擇設計時要注意電機安裝孔的精度確保兩個輪子平行且軸線水平。電池的安裝位置應盡可能靠近輪軸這能降低整車的轉動慣量讓小車反應更靈敏。你可以把電池放在車體下層緊貼底盤。3. 軟件框架與核心算法解析軟件是平衡小車的靈魂。一個好的程序架構能讓復雜的控制邏輯變得清晰而核心算法的理解則是調參成功的鑰匙。3.1 程序主循環與中斷設計平衡控制對實時性要求極高絕不能使用while(1)循環中簡單延時的方式來讀取傳感器和控制電機。標準的做法是建立一個定時器中斷作為系統的心跳。// 示例使用STM32的定時器配置1ms中斷 void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 1. 讀取MPU6050原始數據 // 2. 執行姿態解算如互補濾波 // 3. 讀取編碼器值計算電機速度 // 4. 執行平衡PID和速度PID計算 // 5. 更新電機PWM輸出 Control_Task(); // 將上述步驟封裝成一個控制任務函數 } }在這個1ms的中斷里我們完成一次從感知到執行的全流程。主函數main()的循環則負責一些非實時性的任務比如按鍵掃描、狀態LED指示、通過串口向上位機發送調試數據等。這種中斷驅動的方式確保了控制周期的絕對精確。3.2 姿態解算從數據到角度MPU6050輸出的是原始的陀螺儀角速度單位度/秒和加速度計數據單位g。我們需要把它們融合成一個穩定、準確的傾角。加速度計算角度當小車近似靜止時通過測量重力加速度在X、Z軸上的分量可以用三角函數atan2(AccX, AccZ)算出傾角。這個方法在靜態時很準但一旦小車運動起來電機振動、小車加速度都會引入巨大噪聲。陀螺儀積分算角度對角速度進行積分可以得到角度變化。這個方法動態響應好沒有運動加速度干擾但存在積分漂移溫漂、零漂會隨時間累積導致角度越來越不準。互補濾波一種簡單而有效的融合算法。其思想是用加速度計的角度去校正陀螺儀積分的漂移。// 簡化的互補濾波公式 float Complementary_Filter(float acc_angle, float gyro_rate, float dt) { static float angle 0; float K 0.02; // 互補濾波系數通常很小0.02-0.1 // 角度 0.98 * (上一角度 陀螺儀角速度*時間差) 0.02 * 加速度計角度 angle (1 - K) * (angle gyro_rate * dt) K * acc_angle; return angle; }這里的K是一個權衡參數。K越大信任加速度計越多靜態越穩但動態響應差K越小信任陀螺儀越多動態好但漂移大。通常需要根據實際效果微調。實操心得在調試初期務必通過串口將acc_angle加速度計角度、gyro_integral陀螺儀積分角度和filtered_angle融合后角度實時打印出來用上位機軟件如SerialChart、匿名上位機觀察波形。你會直觀地看到加速度計數據的抖動和陀螺儀的漂移以及互補濾波如何將它們平滑地結合在一起。這是理解濾波最有效的方式。3.3 控制核心串級PID算法單靠一個PID環很難讓小車既穩定又聽話。這里我們采用最經典的串級PID控制外環是速度環內環是平衡環角度環。內環平衡環這是維持直立的核心。輸入是期望角度通常設為0度即完全直立與當前融合后角度的偏差以及角速度可由陀螺儀直接獲得作為微分項D。輸出是一個控制量直接決定電機的“力度”和方向。比如車體前傾角度為正平衡環就輸出一個正值驅動電機向前轉把車體“追回來”。平衡環輸出 Kp_balance * 角度偏差 Kd_balance * 角速度這里Kp比例決定了反應的強度Kd微分決定了“剎車”的力度能抑制振蕩。通常不需要積分項(I)因為直立控制是一個快速、無靜差要求的動態過程加入積分容易導致超調和不穩定。外環速度環如果只有平衡環小車雖然能站住但會不受控制地朝一個方向慢慢移動因為任何微小的不對稱都會累積。速度環的輸入是期望速度通常由遙控器給定自平衡模式下可設為0與編碼器反饋的實際速度的偏差。輸出是一個角度偏移量疊加到平衡環的期望角度上。速度環輸出 Kp_speed * 速度偏差 Ki_speed * 速度偏差積分 期望角度 0 速度環輸出當小車因為地面輕微傾斜而開始下滑時編碼器會檢測到向下的速度速度環輸出一個負的角度偏移比如-0.5度這意味著平衡環的目標不再是0度而是-0.5度略微后仰。于是平衡環會驅動電機向后轉產生一個向上的加速度來抵消下滑最終使平均速度穩定在0。關鍵點速度環的積分項Ki_speed至關重要。正是這個積分作用能夠持續累加微小的速度偏差產生一個穩定的角度偏移來抵消重力分力或機械不對稱帶來的持續漂移從而實現真正的“原地”平衡。4. 詳細實現步驟與調試實錄理論懂了接下來就是動手實現和痛苦的調試過程。遵循一個清晰的步驟能讓你少走彎路。4.1 硬件組裝與基礎驅動測試焊接與組裝按照電路圖將電機驅動、單片機核心板、MPU6050模塊、電池接口等焊接在洞洞板或PCB上。注意電源走線要粗電機驅動部分最好并聯大電容如470uF以吸收電機啟停產生的電流沖擊。機械組裝時確保車體重心在輪軸下方、電池居中兩個輪子轉動靈活且無卡滯。基礎通信測試單片機程序先寫一個最簡單的程序讓LED閃爍確認開發環境、下載器沒問題。MPU6050測試使用I2C讀取MPU6050的WHO_AM_I寄存器默認值0x68確認通信成功。然后循環讀取加速度計和陀螺儀的原始值通過串口打印出來。靜止時Z軸加速度應接近±1g取決于模塊方向轉動模塊時陀螺儀數據應有明顯變化。編碼器測試編寫編碼器讀數程序。STM32的定時器編碼器接口模式是最高效的方式。配置一個定時器為編碼器模式它會自動根據AB相的脈沖和方向更新計數值。讓輪子空轉打印計數值正轉應遞增反轉應遞減。電機驅動測試寫一個函數輸入PWM值和方向能控制電機正反轉。先低速測試確保電機響應正確沒有接反線否則后續調試會完全混亂。4.2 姿態解算與平衡環初步調試實現互補濾波將MPU6050的讀取和互補濾波函數整合到1ms定時器中斷中。計算并輸出filtered_angle。通過串口波形觀察確保角度響應平滑沒有劇烈跳變。用手緩慢改變車體傾角觀察角度值是否線性變化。平衡環PID參數整定空載手扶著將小車用手扶住保持近似直立。先調Kd后調Kp這是一個非常重要的技巧。首先將Kp_balance設為0Kd_balance設為一個較小的正值比如-1。給Kd一個負號是因為角速度方向與我們需要抑制的運動方向相反。用手給小車一個快速的、小幅度的推力然后松開模擬一個擾動。觀察輪子的反應。如果輪子迅速向擾動相反方向轉動一下然后停止說明Kd在起作用阻尼。如果小車來回振蕩說明Kd不夠大緩慢增加Kd值直到擾動后能快速穩定下來沒有振蕩。固定Kd開始調Kp。將Kp_balance設為一個很小的正值比如1。同樣用手施加擾動。Kp決定了小車“追”的力度。Kp太小小車反應慢扶正無力Kp太大會產生過沖和振蕩。緩慢增加Kp直到小車能較快地抵抗擾動回到直立位置且不產生持續振蕩。核心觀察點電機的聲音和反應。調試時你應該能聽到電機隨著你的推力發出相應的高頻響應聲。參數合適時小車在你手里會感覺“有韌性”既不會軟綿綿也不會跟你“較勁”亂抖。4.3 速度環整合與參數整定實現速度環計算在1ms中斷中通過編碼器差值計算電機轉速單位脈沖/毫秒或轉/分鐘。速度環的計算頻率可以比平衡環低例如每10ms計算一次。速度環PID輸出一個angle_offset將其加到平衡環的期望角度上。速度環參數整定小車已能短暫自立先讓平衡環工作嘗試松手讓小車自己平衡。此時它大概率會朝一個方向勻速跑掉。將速度環的Kp_speed和Ki_speed都設為0。然后先調Kp_speed。給Kp_speed一個很小的負值比如-0.1。這個負號很關鍵如果小車向前跑速度為正我們希望它產生一個后仰的角度偏移角度為負來剎車。觀察效果。增加Kp_speed的絕對值小車的漂移速度會變慢甚至開始來回緩慢擺動。Kp_speed太大會引起低頻振蕩。當Kp_speed使小車基本能在一個小范圍內來回移動而不是跑遠時引入Ki_speed。Ki_speed也是一個負值且數值非常小比如-0.001。它的作用是消除靜差。緩慢增加Ki_speed的絕對值你會發現小車逐漸能夠“定”在一點不再緩慢漂移。危險區Ki_speed是導致系統不穩定的常見元兇。如果Ki_speed過大積分會累積過快導致角度偏移巨大小車會突然加速沖向一邊并倒下。調試時必須非常小心每次只做微小的調整。4.4 進階調試與性能優化當小車能穩定站立幾十秒后可以開始優化機械振動濾波電機轉動和車體抖動會嚴重影響MPU6050的加速度計讀數。除了在軟件上優化互補濾波系數K可以在MPU6050模塊和車體之間增加海綿雙面膠或軟性硅膠墊進行物理隔震效果立竿見影。控制量輸出限幅與死區// 對平衡環和速度環的最終輸出進行限幅 #define MAX_OUTPUT 5000 // 對應PWM計數值上限 if (output MAX_OUTPUT) output MAX_OUTPUT; if (output -MAX_OUTPUT) output -MAX_OUTPUT; // 加入死區避免電機在零點附近的嗡嗡聲 if (abs(output) DEAD_ZONE) output 0;電池電壓監測與補償電池電壓下降會導致電機出力不足。可以測量電池電壓計算一個補償系數動態調整PWM輸出或PID參數讓小車在電量不足時也能工作。5. 常見問題排查與實戰心得調試平衡小車的過程就是與各種詭異現象斗爭的過程。下面是一些典型問題及排查思路現象可能原因排查與解決思路上電后電機狂轉不受控制1. 電機驅動輸入邏輯錯誤。2. PWM初始化或GPIO配置錯誤。3. 單片機與驅動共地問題。1. 檢查驅動芯片的AIN1/AIN2, BIN1/BIN2與STM32引腳的連接和初始化代碼確保正反轉邏輯正確。2. 用萬用表測量驅動模塊的電源和地是否穩定。3. 確保單片機、驅動、電池的“地”是連接在一起的。小車一邊倒扶正后向反方向加速倒下平衡環的Kp或Kd極性錯誤。檢查角度和角速度的符號定義。通常前傾車頭向下角度為正此時電機應向前轉輸出為正以追回。如果反了嘗試將Kp_balance或Kd_balance乘以-1。小車能站住但劇烈高頻抖動1.Kd_balance過大。2. 機械結構松動或電機軸套間隙大。3. PWM頻率過低建議在10kHz以上。1. 減小Kd_balance。2. 緊固所有螺絲檢查輪子與電機軸是否固定牢靠。3. 將定時器PWM輸出頻率提高到15kHz左右超出人耳聽覺范圍也能減少電機嘯叫。小車緩慢地朝一個方向勻速移動速度環未起作用或參數不正確。機械不對稱。1. 確認速度環計算已開啟且angle_offset被正確加到期望角度上。2. 檢查速度環Kp_speed和Ki_speed的極性應為負值。3. 嘗試微調小車機械結構或軟件上給兩個電機一個微小的靜態偏移補償。用手推一下小車來回振蕩幾次才穩定阻尼不足。Kd_balance太小。在保證不振的前提下逐步增大Kd_balance。Kd是抑制振蕩的關鍵可以理解為“電子阻尼”。松手后小車往一個方向加速沖出去速度環積分項Ki_speed過大。立即調小Ki_speed的絕對值。這是最危險的參數之一。先將其設為0重新調整Kp_speed使小車緩慢擺動再以極小的步進增加Ki_speed。角度數據跳動厲害1. MPU6050受到振動干擾。2. 互補濾波系數K不合適。3. I2C通信受干擾。1. 物理隔震加海綿。2. 適當減小K更信任陀螺儀。3. 在I2C數據線和時鐘線上加上拉電阻4.7kΩ并盡量縮短走線。最后的個人體會調平衡小車耐心比技術更重要。參數沒有絕對的最優值每個車體都不一樣。一定要一次只調一個參數并且記錄下每次改動和對應的現象。善用串口繪圖工具將關鍵數據角度、角速度、控制輸出可視化這比盯著數字瞎猜要高效一百倍。當你的小車第一次顫顫巍巍地自己站起來并且能堅持超過5秒鐘時那種成就感是無與倫比的。之后你可以在此基礎上增加藍牙遙控、超聲波避障、循跡等功能把它變成一個真正的移動平臺。這個從零到一的過程會讓你對嵌入式實時控制有一個脫胎換骨的理解。