雖然PID不是什么牛逼的東西,但是真心希望以后剛剛接觸這塊的人能盡快進入狀態。特地分享一些自己如何實現的過程。
首先說說增量式PID的公式,這個關系到MCU算法公式的書寫,實際上兩個公式的寫法是同一個公式變換來得,不同的是系數的差異。
資料上比較多的是:
102650f6rimzizf76eegwc.jpg.thumb.jpg (26.31 KB, 下載次數: 56)
下載附件
2018-7-3 02:31 上傳
還有一種的算法是:
102740vub2bzbbuor7d1os.jpg.thumb.jpg (26.94 KB, 下載次數: 58)
下載附件
2018-7-3 02:31 上傳
這里主要介紹第二種,具體會分析比例、積分、微分三個環節的作用。
硬件部分:
控制系統的控制對象是4個空心杯直流電機,電機帶光電編碼器,可以反饋轉速大小的波形。電機驅動模塊是普通的L298N模塊。
芯片型號,STM32F103ZET6
軟件部分:
PWM輸出:TIM3,可以直接輸出4路不通占空比的PWM波
PWM捕獲:STM32除了TIM6 TIM7其余的都有捕獲功能,使用TIM1 TIM2 TIM4 TIM5四個定時器捕獲四個反饋信號
PID的采樣和處理:使用了基本定時器TIM6,溢出時間就是我的采樣周期,理論上T越小效果會越好,這里我取20ms,依據控制對象吧,如果控制水溫什么的采樣周期會是幾秒幾分鐘什么的。
上面的PWM輸出和捕獲關于定時器的設置都有例程,我這里是這樣的:
TIM3輸出四路PWM,在引腳 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9輸出
四路捕獲分別是TIM4 TIM1 TIM2 TIM5 ,對應引腳是: PB7 PE11 PB3 PA1
高級定時器tim1的初始化略不同,它的中斷”名稱“和通用定時器不同。具體的內容,請大家看一下我分享的代碼就明白了。
程序.zip
(2.51 KB, 下載次數: 122)
2018-7-3 02:24 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
主要講解PID部分
準備部分:先定義PID結構體:
- typedef struct
- {
- int setpoint;//設定目標
- int sum_error;//誤差累計
- float proportion ;//比例常數
- float integral ;//積分常數
- float derivative;//微分常數
- int last_error;//e[-1]
- int prev_error;//e[-2]
- }PIDtypedef;
復制代碼 在文件中定義幾個關鍵變量:
- float Kp = 0.32 ; //比例常數
- float Ti = 0.09 ; //積分時間常數
- float Td = 0.0028 ; //微分時間常數
- #define T 0.02 //采樣周期
- #define Ki Kp*(T/Ti) // Kp Ki Kd 三個主要參數
- #define Kd Kp*(Td/T)
復制代碼
PID.H里面主要的幾個函數:
- void PIDperiodinit(u16 arr,u16 psc); //PID 采樣定時器設定
- void incPIDinit(void); //初始化,參數清零清零
- int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint); //PID計算
- void PID_setpoint(PIDtypedef*PIDx,u16 setvalue); //設定 PID預期值
- void PID_set(float pp,float ii,float dd);//設定PID kp ki kd三個參數
- void set_speed(float W1,float W2,float W3,float W4);//設定四個電機的目標轉速
復制代碼
PID處理過程:
岔開一下:這里我控制的是電機的轉速w,實際上電機的反饋波形的頻率f、電機轉速w、控制信號PWM的占空比a三者是大致線性的正比的關系,這里強調這個的目的是
因為樓主在前期一直搞不懂我控制的轉速怎么和TIM4輸出的PWM的占空比聯系起來,后來想清楚里面的聯系之后通過公式把各個系數算出來了。
正題:控制流程是這樣的,首先我設定我需要的車速(對應四個輪子的轉速),然后PID就是開始響應了,它先采樣電機轉速,得到偏差值E,帶入PID計算公式,得到調整量也就是最終更改了PWM的占空比,不斷調節,直到轉速在穩態的一個小范圍上下浮動。
上面講到的“得到調整量”就是增量PID的公式:
- int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
- {
- int iError,iincpid;
- iError=PIDx->setpoint-nextpoint; //當前誤差
- /*iincpid= //增量計算
- PIDx->proportion*iError //e[k]項
- -PIDx->integral*PIDx->last_error //e[k-1]
- +PIDx->derivative*PIDx->prev_error;//e[k-2]
- */
- iincpid= //增量計算
- PIDx->proportion*(iError-PIDx->last_error)
- +PIDx->integral*iError
- +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
- PIDx->prev_error=PIDx->last_error; //存儲誤差,便于下次計算
- PIDx->last_error=iError;
- return(iincpid) ;
- }
復制代碼 注釋掉的是第一種寫法,沒注釋的是第二種以Kp KI kd為系數的寫法,實際結果是一樣的。
處理過程放在了TIM6,溢出周期時間就是是PID里面采樣周期(區分于反饋信號的采樣,反饋信號采樣是1M的頻率)
相關代碼:
- void TIM6_IRQHandler(void) // 采樣時間到,中斷處理函數
- {
-
- if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中斷
- {
- frequency1=1000000/period_TIM4 ; //通過捕獲的波形的周期算出頻率
- frequency2=1000000/period_TIM1 ;
- frequency3=1000000/period_TIM2 ;
- frequency4=1000000/period_TIM5 ;
- /********PID1處理**********/
- PID1.sum_error+=(incPIDcalc(&PID1,frequency1)); //計算增量并累加
- pwm1=PID1.sum_error*4.6875 ; //pwm1 代表將要輸出PWM的占空比
- frequency1=0; //清零
- period_TIM4=0;
- /********PID2處理**********/
- PID2.sum_error+=(incPIDcalc(&PID2,frequency2)); //計算增量并累加 Y=Y+Y'
- pwm2=PID2.sum_error*4.6875 ; //將要輸出PWM的占空比
- frequency2=0;
- period_TIM1=0;
- /********PID3處理**********/
- PID3.sum_error+=(incPIDcalc(&PID3,frequency3)); //常規PID控制
- pwm3=PID3.sum_error*4.6875 ; //將要輸出PWM的占空比
- frequency3=0;
- period_TIM2=0;
- /********PID4處理**********/
- PID4.sum_error+=(incPIDcalc(&PID4,frequency4)); //計算增量并累加
- pwm4=PID4.sum_error*4.6875 ; //將要輸出PWM的占空比
- frequency4=0;
- period_TIM5=0;
- }
- TIM_SetCompare(pwm1,pwm2,pwm3,pwm4); //重新設定PWM值
- TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中斷標志位
- }
復制代碼 上面幾個代碼是PID實現的關鍵部分
還有整定過程:
辦法有不少,這里用的是先KP,再TI,再TD,在微調。其他的辦法特別是有個尼古拉斯法我發現不適合我這個控制對象。
先Kp,就是消除積分和微分部分的影響,這里我糾結過到底是讓Ti 等于一個很大的值讓Ki=Kp*(T/Ti)里面的KI接近零,還是直接定義KI=0,TI=0.
然后發現前者沒法找到KP使系統震蕩的臨界值,第二個辦法可以得到預期的效果:即KP大了會產生震蕩,小了會讓系統穩定下來,當然這個時候是有穩態誤差的。
隨后把積分部分加進去,KI=Kp*(T/Ti)這個公式用起來,并且不斷調節TI 。TI太大系統穩定時間比較長。
然后加上Kd =Kp*(Td/T),對于系統響應比較滯后的情況效果好像好一些,我這里的電機反映挺快的,所以Td值很小。
最后就是幾個參數調節一下,讓波形好看一點。這里的波形實際反映的是采集回來的轉速值,用STM32的DAC功能輸出和轉速對應的電壓,用示波器采集的。
最后的波形是這樣的:
55.jpg (16.84 KB, 下載次數: 56)
下載附件
2018-7-3 02:31 上傳
當然最后還是要分享一下最終的PID文件
pid.zip
(2.88 KB, 下載次數: 136)
2018-7-3 02:29 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
本文的word版本下載:
http://m.raoushi.com/bbs/dpj-51261-1.html
|