基于STC单片机的两轮平衡车设计
給大家傳福利了。。后續繼續共享基于Arduino/安卓Android/樹莓派raspberry等平臺的兩輪車設計
這是我前年暑假做的一個小項目,今年拿出來整理了下當畢設了(當然畢設里添加了許多其他元素,比如Arduino/安卓Android/樹莓派raspberry等),現在共享出來給大家,有視頻上傳在優酷地址為http://v.youku.com/v_show/id_XNzI4MjA0NzQ4.html。
鑒于目前大一大二新生還都在用STC單片機搞基(我大一也是如此),因此特將兩輪平衡車的技術移植到STC單片機上,造福新生。。
ps:以后參加校園里面的智能車比賽,就不要做那種光電管檢測黑線四輪趴著跑的那種了,照學長的指示設計個基于STC單片機的兩輪平衡車跟他們四輪的小車比賽,不管結果怎樣,他們瞬間就弱爆了。。
本次設計的最終的目的設計一種基于STC單片機的兩輪直立自平衡小車。選用加速度計和陀螺儀為輸入和反饋,對輸入信號處理加工形成一個單閉環系統,由于PID控制具有結構簡單、適用面廣、魯棒性強、可靠性高等優點,控制策略自然采用PID控制。
本次設計研究的主要內容是如何在直立這個自然不穩定系統中設計單閉環調速系統的PID控制器,利用輸出不同的PWM控制電機正反轉來實現不斷調整小車狀態使之穩定直立。
2.1?任務分析
此次設計要求小車克服自然不穩定性保持直立狀態運行,相比較于兩腳著地而言,呵呵看起來還挺復雜的。但是為了將復雜的事情簡單化,首先我們將問題分解,一小塊一小塊地解決貌似會簡單點。
?????從任務分析來看,保持小車直立為結果,采用STC15F2K60S2為要求,通過著地的電機提供動力,因此,將小車看做被控對象,輸入量就是姿態解算和PWM輸出。小車的角度和速度緊密聯系,相互控制,我們既可以通過調整角度來調節速度,也可以通過調節速度來調節角度。而硬件方面STC15F2K60S2這款單片機既有AD模擬口輸入又有PWM口輸出,因此我們只需選用模擬量輸出的姿態傳感器,和大電流驅動電路即可完成設計。
點擊打開鏈接2.2?理論分析
?
圖2.1??保持木棒直立的反饋控制?
同樣的要使小車保持平衡,就需要使重心落在兩個輪子上,當然,絕對的落在輪子上是不可能的,因此我們需要不斷地調整,通過輪子的前后移動來調整重心,既然有調整那就必須要有負反饋,如圖2.2所示小車通過前后加減速調整小車狀態。
????另外在重力場中我們可以將這個模型改成單擺模型,這樣更容易理解和建模計算,如圖2.3所示。
?
圖2.3?系統簡化單擺模型?
對其受力分析如圖2.4所示。
圖2.4?單擺受力分析
當小球偏離重力的重心后,會受到一個拉回重心位置的力,成為回復力,大小為
?
?????但是如果這個角度非常小的話,我們可以忽略掉正玄和正切的差別,近似回復力與偏離角成正比。如上式的公式所示。
下面來講一下阻尼,我們都知道任何物體的受力分析里面不可或缺的就是摩擦力,在阻擾物體運動的情況下我們稱之為阻尼,如下圖2.5所示,單擺在空氣中受到阻尼力最終回復到重力位置,如圖過阻尼和欠阻尼的情況。如果阻尼過大就會導致達到平衡點的時間過長,如果阻尼太小就會來回運動導致時間一樣很長,因此,一個合適的阻尼系數很重要。
圖2.5?不同阻尼下的運動特性
?
2.3?可行性分析
上面闡述了車模直立的原理,可以看出要想保證車模直立,我們需要角度值,而單單使用陀螺儀來獲取角度值的話存在一個不可跨越的問題,就是陀螺儀的動態性能好但是靜態性能差(積分飽和等現象),為了彌補這個差距,我們另外選擇加速度計,因為加速度計正好具有靜態性能好而動態性能差的性能。形成互補。
(1)加速度傳感器
如下圖2.6所示為飛思卡爾生產的模擬加速度計MMA7260,他可以精確測量自身加速度,14位高精度。與重力加速度比較即可簡單獲得目前狀態下的角度。
圖2.6?MMA系列加速度計?
????方案一:選用?MMA8451三軸加速度計,利用IIC通信實時讀取MMA8451的數據。
方案二:選用MMA模擬系列三軸加速度計,利用MCU片內AD口采集數據并轉換。
方案對比:方案一采集到的直接就是數字量可以節省MCU的AD口并且精度高,節省MCU的轉換時間及功耗負擔。比賽而言建議選MMA8451,但是程序復雜度會較AD復雜一些。
(2)陀螺儀
單軸陀螺儀模擬量輸出(前文講過的村田研究所發明的)如圖2.7所示,精確測量自身翻轉角速度,以靈敏度著稱。其放大電路如圖2.8所示。
?
?
方案一:電路如圖2.9所示,此方案的設計是因為陀螺儀存在一個溫漂問題,這樣對我們零偏會有影響,因此如圖我們在輸出端先接一高通電容C3來抑制溫漂,然后進行放大輸入單片機的MCU的AD口。
方案二:電路在上圖的基礎上將C3短接,因為加上電容后雖然抑制了溫漂,但在車子加減速的時候會出現嚴重的過沖現象,這樣會導致車子激烈抖動無法平穩下來,為了避免此現象我們短接C3,降低放大倍數,達到相對較好的情況,實驗證明,此時車子已經相當平穩,對于溫漂問題,我們采取軟件解決方案,在每次啟動時首先執行自動獲取零點程序,直接矯零。
3??基于STC單片機的兩輪車設計
3.1?STC15F60S2簡介
STC15F2K60S2這款單片機是宏晶科技有限公司,也就是生產51的那個公司,該公司一直致力于做國產的芯片,將其做的極致,也是如此國內本科的大學教材統一選用宏晶科技的芯片作為教材案例。支持國產!呵呵。聽說該款芯片是1T的單片機,通俗地講就是更快了,快了幾十倍的說。另外這款新片更加注重了加密型,因為以前的該款單片機的二進制文件,居然可以從芯片里面弄出來,這樣便可以盜版等等,此款采用的是第八代加密技術,并且在首頁懸賞10萬元來破解。另外來說說他的可靠性和抗干擾性,在這一方面做的出色的一般都是一些如飛思卡爾等的大公司,穩定性和高的抗干擾能力是芯片性能的衡量標準,筆者在做這次畢業設計的過程中也是深有體會,對于直立車的電機輸出可謂是大大檢驗了芯片的抗干擾能力和穩定性,因為這里輸出的PWM變化特別快,而且還經常要改變方向,因此如果輸出沒有接光電隔離的話,對芯片的干擾勢必會非常之大。親測發現,飛思卡爾和STC15F2K的芯片可以抵抗這樣的干擾而穩定工作,而AVR也就是ATM公司生產的328p芯片就無法勝任,必掛的節奏。也就是后面文中將為大家介紹到的ARDUINO?小板,一定要加光電隔離。在指令代碼方面,宏晶科技非常人性化的告訴我可以兼容上一代8051的指令代碼,在keil中直接包含51頭文件就行了(即<reg51.h>)。這次變革,我感覺到的唯一亮點就是,以后韓單片機最小系統再也不用焊接晶振那塊的電路了,它內部集成了高精度振蕩電路,說是R/C電路,精度在0.003左右,溫漂0.01,晶振頻率在5MHz到35MHz之間設置,但是并非隨意值設定,有5.5296MHz?/?11.0592MHz?/?22.1184MHz?/?33.1776MHz選其中之一。然后值得一提的就是煩人的復位電路官方也幫我們省去了,雖然之前的51我都沒焊過復位電路,呵呵。
然后讓我們來看看這款芯片的片內資源有多豐富吧,首先就是他有3路獨立的CCP/PWM/PCA,這個好像淵源可以滿足我么做直立車的輸出要求吧。八路可達10位的A/D轉換,并且速度非常快,達到三十萬次每秒,串口通信也有福了,有兩個串口UART1和UART2。資源框架圖如圖3.1所示。
?
3.2?軟件設計及實現
軟件方面我們需要占用兩路ADC轉換來讀取外界陀螺儀加速度計模擬值,然后占用一路串口用于下載程序及輸出數據、波形調試參數;還有就是兩路PWM輸出,這里選用兩路PWM而不是四路的用意是,希望后來者做這個兩輪車的時候不要用兩個電機的兩輪車,而選用一個電機的兩輪車,這樣可以大大降低成本,減少一個電機的成本以及兩個驅動芯片的成本,驅動的價格真是貴啊。。。?總體軟件框架如圖3.2所示。
接下來是一部分小段落的程序,關于程序源碼的獲取,這里多說幾句,因為本文中涉及到的程序太多了,必去安卓那一塊,還有飛思卡爾那塊代碼太長了,不可能在文中附錄,因此我會于答辯后近日上傳至CSDN的個人博客資源里,供大家下載。也請大家廣泛傳播關注,不定期更新文中有些只有軟件的部分會在學長畢業后繼續倒騰各種奇葩的設計,諸如基于RASPBERRY(一種LINUX操作系統)的小型無人偵察機等。貼上個人主頁和個人信息(圖3.3、3.4所示)。關注成功便可以在我上傳的資源里面下載到所有你大學四年要用到的,以及最新的技術動態。附上網址:http://blog.csdn.net/baitianzi534011382
首先初始化AD轉換模塊,配置函數如下:
void ADC_config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Px????=?ADC_P10?|?ADC_P11?|?ADC_P12;
圖3.2?總體軟件框圖
ADC_InitStructure.ADC_Speed?????=?ADC_360T; ADC_90T,ADC_180T,ADC_360T,ADC_540T
ADC_InitStructure.ADC_Power?????=?ENABLE;
ENABLE,DISABLE
?
圖3.4?博客主頁
ADC_InitStructure.ADC_AdjResult?=?ADC_RES_H8L2; ADC_RES_H2L8,ADC_RES_H8L2
ADC_InitStructure.ADC_Polity????=?PolityLow;
PolityHigh,PolityLow
ADC_InitStructure.ADC_Interrupt?=?DISABLE;
ENABLE,DISABLE
ADC_Inilize(&ADC_InitStructure);
ADC_PowerControl(ENABLE);
}
然后初始化PWM輸出
void PCA_config(void)
{
PCA_InitTypeDef PCA_InitStructure; ????
?
PCA_InitStructure.PCA_Mode?????=?PCA_Mode_HighPulseOutput; //PCA_Mode_PWM,?PCA_Mode_Capture,?PCA_Mode_SoftTimer,?PCA_Mode_HighPulseOutput
PCA_InitStructure.PCA_PWM_Wide?=?0; //PCA_PWM_8bit,?PCA_PWM_7bit,?PCA_PWM_6bit
PCA_InitStructure.PCA_Interrupt_Mode?=?ENABLE; //PCA_Rise_Active,?PCA_Fall_Active,?ENABLE,?DISABLE
PCA_InitStructure.PCA_Value????=?65535;
PCA_Init(PCA0,&PCA_InitStructure);
PCA_InitStructure.PCA_Mode?????=?PCA_Mode_HighPulseOutput; //PCA_Mode_PWM,?PCA_Mode_Capture,?PCA_Mode_SoftTimer,? PCA_Mode_HighPulseOutput
PCA_InitStructure.PCA_PWM_Wide?=?0; //PCA_PWM_8bit,? PCA_PWM_7bit,?PCA_PWM_6bit
PCA_InitStructure.PCA_Interrupt_Mode?=?ENABLE;
?PCA_Fall_Active,?ENABLE,?DISABLE
PCA_InitStructure.PCA_Value????=?65535;
PCA_Init(PCA1,&PCA_InitStructure);
PCA_InitStructure.PCA_Mode?????=?PCA_Mode_HighPulseOutput; //PCA_Mode_PWM,?PCA_Mode_Capture,?PCA_Mode_SoftTimer,?PCA_Mode_HighPulseOutput
PCA_InitStructure.PCA_PWM_Wide?=?0; //PCA_PWM_8bit,?PCA_PWM_7bit,?PCA_PWM_6bit
PCA_InitStructure.PCA_Interrupt_Mode?=?ENABLE; //PCA_Rise_Active,?PCA_Fall_Active,?ENABLE,?DISABLE
PCA_InitStructure.PCA_Value????=?65535;
PCA_Init(PCA2,&PCA_InitStructure);
PCA_InitStructure.PCA_Clock????=?PCA_Clock_1T; //PCA_Clock_1T,?PCA_Clock_2T,?PCA_Clock_4T,?PCA_Clock_6T,?PCA_Clock_8T,?PCA_Clock_12T,?PCA_Clock_Timer0_OF,?PCA_Clock_ECI
PCA_InitStructure.PCA_IoUse????=?PCA_P24_P25_P26_P27; //PCA_P12_P11_P10_P37,?PCA_P34_P35_P36_P37,?PCA_P24_P25_P26_P27
PCA_InitStructure.PCA_Interrupt_Mode?=?DISABLE; //ENABLE,?DISABLE
PCA_InitStructure.PCA_Polity???=?PolityHigh; PolityHigh,PolityLow
PCA_Init(PCA_Counter,&PCA_InitStructure);
}
讀取陀螺儀和加速度計的AD值
gyro_ad?=?Get_ADC10bitResult(0);
MMA7361_Y?=?Get_ADC10bitResult(1);
MMA7361_Z?=?Get_ADC10bitResult(2);
轉化為歐拉角
MMA7361_Y-=0X0152;
MMA7361_Z-=0X0152;
roll=(float)(((atan2(MMA7361_Z,MMA7361_Y)*180)/3.14159265)+180);
積分并校正
gyro_angle=gyro_angle+gyro_speed*dt+jiao_du_cha/fGravityTimeConstant*dt;
PID控制器
jiao_PWM=(int)(0-gyro_angle*fAngleControlP-gyro_speed*fAngleControlD);
3.3?調試及實現
整個調試過程是非常重要的環節,因此此處給出調試函數,以下數據及波形均由此函數獲得:
void?debug(?int?ch0,??int?ch1,?int?ch2){
if(ch0>0)
{ TxSend(ch0%100/10?+?'0');
??? TxSend(ch0%10?+?'0');
}else
{??TxSend('-');
ch0?=0?-?ch0;
??? TxSend(ch0%100/10?+?'0');
??? TxSend(ch0%10?+?'0');
}
TxSend(',');
if(ch1>0)
{???TxSend(ch1%100/10?+?'0');
??? TxSend(ch1%10?+?'0');
}
else
{??TxSend('-');
ch1?=?0?-?ch1;
??? TxSend(ch1%100/10?+?'0');
??? TxSend(ch1%10?+?'0');
}
TxSend(',');
if(ch2>0)
{??TxSend(ch2%100/10?+?'0');
??? TxSend(ch2%10?+?'0');
}
else
{??TxSend('-');
ch2?=?0?-?ch2;
??? TxSend(ch2%100/10?+?'0');
??? TxSend(ch2%10?+?'0');
}
??? PrintString("\r\n");
}
?
圖3.5?陀螺儀加速計波形
1、初始化調整:對初始化位置的校正,首先手動保持車體處于重心垂直地面狀態下讀取陀螺儀加速度計的值使之輸出為0,即剛好處于臨界狀態。如圖3-5紅線和黑線為加速度計X軸和Z軸的糾正后輸出,藍線為陀螺儀輸出。
2、隨動性調整:調好第一步之后,由debug函數輸出融合后的角度值和直接由
加速度計輸出的角度值,調整積分時間看兩者的跟隨情況,使之剛好跟上而不過為最好。如圖3.6為調整好的波形輸出。
?
3、PID控制器參數調整:以上兩步確定調到最佳狀態,然后直接上機,上電看看提起來左右晃動看電機的反應是否正確,一般會有某個電機反轉的情況,修改電機接線(推薦)或者修改程序,修改PWM輸出引腳等等,然后根據PID調整原則,修改PD參數,使之能夠站穩,然后可以考慮注釋掉程序中的DEBUG段?這樣可以減少控制周期,是直立控制更加穩定,但是這時周期改變了,需要修改積分時間,改小來,這時因為沒有了DEBUG函數,只能盲調,但是這時PD的參數已經調好了,就只用調整積分時間這一個變量,因此只會越調越穩,不用擔心盲調會調不好或者不好調等問題。
PID參數調節問題,此處不多做討論。如圖3.7為實物照片,及調好的車體照片。
?
總結
以上是生活随笔為你收集整理的基于STC单片机的两轮平衡车设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java timsort_JDK(二)J
- 下一篇: LCD制作工艺及相关设备资料配方大全(转