找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9444|回復(fù): 9
打印 上一主題 下一主題
收起左側(cè)

如何在STM32上實現(xiàn)增量PID控制

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:363309 發(fā)表于 2018-7-2 16:36 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
雖然PID不是什么牛逼的東西,但是真心希望以后剛剛接觸這塊的人能盡快進入狀態(tài)。特地分享一些自己如何實現(xiàn)的過程。
首先說說增量式PID的公式,這個關(guān)系到MCU算法公式的書寫,實際上兩個公式的寫法是同一個公式變換來得,不同的是系數(shù)的差異。
資料上比較多的是:


還有一種的算法是:


這里主要介紹第二種,具體會分析比例、積分、微分三個環(huán)節(jié)的作用。

硬件部分:
控制系統(tǒng)的控制對象是4個空心杯直流電機,電機帶光電編碼器,可以反饋轉(zhuǎn)速大小的波形。電機驅(qū)動模塊是普通的L298N模塊。
芯片型號,STM32F103ZET6

軟件部分:
PWM輸出:TIM3,可以直接輸出4路不通占空比的PWM波
PWM捕獲:STM32除了TIM6 TIM7其余的都有捕獲功能,使用TIM1 TIM2 TIM4 TIM5四個定時器捕獲四個反饋信號
PID的采樣和處理:使用了基本定時器TIM6,溢出時間就是我的采樣周期,理論上T越小效果會越好,這里我取20ms,依據(jù)控制對象吧,如果控制水溫什么的采樣周期會是幾秒幾分鐘什么的。

上面的PWM輸出和捕獲關(guān)于定時器的設(shè)置都有例程,我這里是這樣的:
TIM3輸出四路PWM,在引腳 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9輸出
四路捕獲分別是TIM4  TIM1  TIM2  TIM5   ,對應(yīng)引腳是:  PB7 PE11 PB3 PA1
高級定時器tim1的初始化略不同,它的中斷”名稱“和通用定時器不同。具體的內(nèi)容,請大家看一下我分享的代碼就明白了。
程序.zip (2.51 KB, 下載次數(shù): 122)

主要講解PID部分
準備部分:先定義PID結(jié)構(gòu)體:
  1. typedef struct
  2. {
  3. int setpoint;//設(shè)定目標
  4. int sum_error;//誤差累計
  5. float proportion ;//比例常數(shù)
  6. float integral ;//積分常數(shù)
  7. float derivative;//微分常數(shù)
  8. int last_error;//e[-1]
  9. int prev_error;//e[-2]
  10. }PIDtypedef;
復(fù)制代碼
在文件中定義幾個關(guān)鍵變量:
  1. float  Kp =     0.32  ; //比例常數(shù)
  2. float  Ti =                0.09 ; //積分時間常數(shù)
  3. float Td =                0.0028 ;  //微分時間常數(shù)
  4. #define T                  0.02 //采樣周期
  5. #define Ki     Kp*(T/Ti)        // Kp Ki Kd 三個主要參數(shù)
  6. #define Kd                Kp*(Td/T)
復(fù)制代碼

PID.H里面主要的幾個函數(shù):
  1. void PIDperiodinit(u16 arr,u16 psc);        //PID 采樣定時器設(shè)定
  2. void incPIDinit(void);                //初始化,參數(shù)清零清零
  3. int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);           //PID計算
  4. void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);  //設(shè)定 PID預(yù)期值
  5. void PID_set(float pp,float ii,float dd);//設(shè)定PID  kp ki kd三個參數(shù)
  6. void set_speed(float W1,float W2,float W3,float W4);//設(shè)定四個電機的目標轉(zhuǎn)速
復(fù)制代碼

PID處理過程:
岔開一下:這里我控制的是電機的轉(zhuǎn)速w,實際上電機的反饋波形的頻率f、電機轉(zhuǎn)速w、控制信號PWM的占空比a三者是大致線性的正比的關(guān)系,這里強調(diào)這個的目的是
因為樓主在前期一直搞不懂我控制的轉(zhuǎn)速怎么和TIM4輸出的PWM的占空比聯(lián)系起來,后來想清楚里面的聯(lián)系之后通過公式把各個系數(shù)算出來了。

正題:控制流程是這樣的,首先我設(shè)定我需要的車速(對應(yīng)四個輪子的轉(zhuǎn)速),然后PID就是開始響應(yīng)了,它先采樣電機轉(zhuǎn)速,得到偏差值E,帶入PID計算公式,得到調(diào)整量也就是最終更改了PWM的占空比,不斷調(diào)節(jié),直到轉(zhuǎn)速在穩(wěn)態(tài)的一個小范圍上下浮動。
上面講到的“得到調(diào)整量”就是增量PID的公式:

  1. int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
  2. {
  3. int iError,iincpid;
  4. iError=PIDx->setpoint-nextpoint;  //當前誤差
  5. /*iincpid=                                               //增量計算
  6. PIDx->proportion*iError                //e[k]項
  7. -PIDx->integral*PIDx->last_error          //e[k-1]
  8. +PIDx->derivative*PIDx->prev_error;//e[k-2]
  9. */
  10. iincpid=                                                          //增量計算
  11. PIDx->proportion*(iError-PIDx->last_error)
  12. +PIDx->integral*iError
  13. +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);

  14. PIDx->prev_error=PIDx->last_error; //存儲誤差,便于下次計算
  15. PIDx->last_error=iError;
  16. return(iincpid) ;
  17. }
復(fù)制代碼
注釋掉的是第一種寫法,沒注釋的是第二種以Kp KI kd為系數(shù)的寫法,實際結(jié)果是一樣的。
處理過程放在了TIM6,溢出周期時間就是是PID里面采樣周期(區(qū)分于反饋信號的采樣,反饋信號采樣是1M的頻率)
相關(guān)代碼:
  1. void TIM6_IRQHandler(void)        //        采樣時間到,中斷處理函數(shù)
  2. {         
  3.         
  4. if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中斷
  5.         {
  6.         frequency1=1000000/period_TIM4        ; //通過捕獲的波形的周期算出頻率
  7.         frequency2=1000000/period_TIM1        ;
  8.         frequency3=1000000/period_TIM2        ;
  9.         frequency4=1000000/period_TIM5        ;
  10. /********PID1處理**********/
  11.         PID1.sum_error+=(incPIDcalc(&PID1,frequency1));         //計算增量并累加
  12.        pwm1=PID1.sum_error*4.6875  ;   //pwm1 代表將要輸出PWM的占空比
  13.           frequency1=0; //清零
  14.      period_TIM4=0;
  15. /********PID2處理**********/
  16.          PID2.sum_error+=(incPIDcalc(&PID2,frequency2));         //計算增量并累加  Y=Y+Y'               
  17.          pwm2=PID2.sum_error*4.6875 ;   //將要輸出PWM的占空比
  18.         frequency2=0;
  19.         period_TIM1=0;
  20. /********PID3處理**********/
  21.          PID3.sum_error+=(incPIDcalc(&PID3,frequency3));          //常規(guī)PID控制
  22.         pwm3=PID3.sum_error*4.6875 ;   //將要輸出PWM的占空比
  23.         frequency3=0;
  24.         period_TIM2=0;
  25. /********PID4處理**********/
  26.             PID4.sum_error+=(incPIDcalc(&PID4,frequency4));         //計算增量并累加
  27.          pwm4=PID4.sum_error*4.6875 ;   //將要輸出PWM的占空比
  28.         frequency4=0;
  29.         period_TIM5=0;
  30.           }
  31. TIM_SetCompare(pwm1,pwm2,pwm3,pwm4);             //重新設(shè)定PWM值
  32. TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中斷標志位               
  33. }
復(fù)制代碼
上面幾個代碼是PID實現(xiàn)的關(guān)鍵部分

還有整定過程:
辦法有不少,這里用的是先KP,再TI,再TD,在微調(diào)。其他的辦法特別是有個尼古拉斯法我發(fā)現(xiàn)不適合我這個控制對象。
先Kp,就是消除積分和微分部分的影響,這里我糾結(jié)過到底是讓Ti 等于一個很大的值讓Ki=Kp*(T/Ti)里面的KI接近零,還是直接定義KI=0,TI=0.
然后發(fā)現(xiàn)前者沒法找到KP使系統(tǒng)震蕩的臨界值,第二個辦法可以得到預(yù)期的效果:即KP大了會產(chǎn)生震蕩,小了會讓系統(tǒng)穩(wěn)定下來,當然這個時候是有穩(wěn)態(tài)誤差的。
隨后把積分部分加進去,KI=Kp*(T/Ti)這個公式用起來,并且不斷調(diào)節(jié)TI 。TI太大系統(tǒng)穩(wěn)定時間比較長。
然后加上Kd        =Kp*(Td/T),對于系統(tǒng)響應(yīng)比較滯后的情況效果好像好一些,我這里的電機反映挺快的,所以Td值很小。
最后就是幾個參數(shù)調(diào)節(jié)一下,讓波形好看一點。這里的波形實際反映的是采集回來的轉(zhuǎn)速值,用STM32的DAC功能輸出和轉(zhuǎn)速對應(yīng)的電壓,用示波器采集的。
最后的波形是這樣的:


當然最后還是要分享一下最終的PID文件
pid.zip (2.88 KB, 下載次數(shù): 136)
本文的word版本下載:
http://www.torrancerestoration.com/bbs/dpj-51261-1.html


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏14 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:364988 發(fā)表于 2018-7-4 16:57 | 只看該作者
贊,記得有人把西門子PLC的PIDC語言搞出來了,應(yīng)該差不多吧
回復(fù)

使用道具 舉報

板凳
ID:104779 發(fā)表于 2018-12-22 01:45 | 只看該作者
cdust 發(fā)表于 2018-7-4 16:57
贊,記得有人把西門子PLC的PIDC語言搞出來了,應(yīng)該差不多吧

請問你在哪里看到有西門子PLC的PIDC語言呢?我想學(xué)習(xí)一下。
回復(fù)

使用道具 舉報

地板
ID:478002 發(fā)表于 2019-3-17 10:07 | 只看該作者
學(xué)習(xí)了
回復(fù)

使用道具 舉報

5#
ID:550312 發(fā)表于 2019-5-29 16:23 | 只看該作者
非常感謝啦超級有用
回復(fù)

使用道具 舉報

6#
ID:227663 發(fā)表于 2019-7-8 23:45 | 只看該作者
非常有用,學(xué)習(xí)了
回復(fù)

使用道具 舉報

7#
ID:453741 發(fā)表于 2019-7-13 18:59 | 只看該作者
除了pid還有其他平衡算法嗎
回復(fù)

使用道具 舉報

8#
ID:20672 發(fā)表于 2019-8-30 16:27 | 只看該作者
謝謝分享~~
回復(fù)

使用道具 舉報

9#
ID:113433 發(fā)表于 2019-8-31 08:24 | 只看該作者
非常讚的分享   感謝
回復(fù)

使用道具 舉報

10#
ID:583110 發(fā)表于 2019-8-31 14:54 | 只看該作者
學(xué)習(xí)了。。。。。
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表