當(dāng)前位置:首頁 > 公眾號精選 > 小麥大叔
[導(dǎo)讀]0 前面的話 好久沒有更新了,內(nèi)心有種罪惡感,,至于原因,可能是因為菜吧,不知道該寫什么,還有就是因為懶吧,雖然一部分在B乎上發(fā)了,被噴了一地,便沒整理到公眾號。后面打算整理一個PID算法系列,系統(tǒng)地總結(jié)和整理一下; 這里給大家推薦一首灌籃高手的片

0 前面的話

好久沒有更新了,內(nèi)心有種罪惡感,,至于原因,可能是因為菜吧,不知道該寫什么,還有就是因為懶吧,雖然一部分在B乎上發(fā)了,被噴了一地,便沒整理到公眾號。后面打算整理一個PID算法系列,系統(tǒng)地總結(jié)和整理一下;


這里給大家推薦一首灌籃高手的片尾曲,三井壽是灌籃高手中我最喜歡的人物之一,在湘北對抗翔陽的比賽中,三井在對位長谷川一志時體力近乎崩潰。但他想起國中的那場決賽,想到安西教練那番話:“你現(xiàn)在放棄就等于比賽提前結(jié)束?!毕氲剿彩菆猿值阶詈蟛湃〉昧藙倮?。此時,他又重燃斗志,于是便響起了這首歌《直到世界終結(jié)》。希望在生活中,大家遇到挫折和困難,多一點堅持,最終一定都能克服難關(guān)。(感覺有點陳年雞湯了


目錄

  • 1 什么是增量式PID?

  • 2 舉個例子

    • 2.1 位置式PID

    • 2.2 增量式PID

  • 3 偽算法

  • 4 C語言實現(xiàn)

  • 5 總結(jié)


在之前一篇博客中( 簡易PID算法的快速掃盲 )簡單介紹了PID算法的基本原理位置式算法的實現(xiàn)過程,由于部分推導(dǎo)過程已經(jīng)在上一篇文章做過介紹,所以推導(dǎo)過程本文不再贅述,重點將對離散增量式PID的算法進(jìn)行實現(xiàn)。

1 什么是增量式PID?

先看一下增量式PID的離散公式如下:

:比例系數(shù)
:積分系數(shù)
:微分系數(shù)
:偏差

對于所謂的位置式,增量式的算法,這兩者只是在算法的實現(xiàn)上的存在差異,本質(zhì)的控制上對于系統(tǒng)控制的影響還是相同,單純從輸入和輸出的角度來比較,具體如下表所示;

這里簡單的說明一下;

  • 位置式:位置式算法較為簡單,直接輸入當(dāng)前的偏差 ,即可得到輸出 ;
  • 增量式:增量式算法需要保存歷史偏差, ,即在第 次控制周期時,需要使用第 和第 次控制所輸入的偏差,最終計算得到 ,此時, 這還不是我們所需要的PID輸出量;所以需要進(jìn)行累加;

不難發(fā)現(xiàn)第一次控制周期時,即 時;

由以上公式我們可以推導(dǎo)出下式;

所以可以看出,最終PID的輸出量 ,滿足以下公式;

可見增量式算法,就是所計算出的PID增量的歷史累加和;

2 舉個例子

2.1 位置式PID

下面從一個簡單的例子中去理解一下增量式PID,這里依然舉一個不是很恰當(dāng)?shù)睦?;如果?strong>位置式PID算法的話:

  • 隆哥對一個直流電機進(jìn)行調(diào)速,設(shè)定了轉(zhuǎn)速為 1000;
  • 這時由于反饋回來的速度和設(shè)定的速度偏差為 ;
  • 經(jīng)過 位置式PID計算得到 ;
  • 作為 Process的輸入值(可以是 PWM的占空比),最終 Process輸出相應(yīng)的 PWM驅(qū)動直流電機;
  • 反饋裝置檢測到電機轉(zhuǎn)速,然后重復(fù)以上步驟;

整體框圖如下所示;

2.2 增量式PID

對于增量式PID來說;

  • 隆哥對一個直流電機進(jìn)行調(diào)速,設(shè)定了轉(zhuǎn)速為 1000;
  • 這時由于反饋回來的速度和設(shè)定的速度偏差為 ,系統(tǒng)中保存上一次的偏差 和上上次的偏差 ,這三個輸入量經(jīng)過 增量PID計算得到 ;
  • 系統(tǒng)中還保存了上一次的 PID輸出 ,所以 加上增量 ,就是本次控制周期的 PID輸出——
  • 作為 Process的輸入值(可以是 PWM的占空比),最終 Process輸出相應(yīng)的 PWM驅(qū)動直流電機;
  • 反饋裝置檢測到電機轉(zhuǎn)速,然后重復(fù)以上步驟;

整體框圖如下所示;

所以這里不難發(fā)現(xiàn),所謂增量式PID,它的特點有:

  • 需要輸入歷史的偏差值;
  • 計算得到的是PID輸出增量,因此每一次需要累加歷史增量最為當(dāng)前的PID輸出;

下面簡單介紹一下如何實現(xiàn)增量式PID算法;

3 偽算法

previous02_error := 0  //上上次偏差
previous01_error := 0  //上一次偏差
integral := 0   //積分和
pid_out := 0   //pid增量累加和
//循環(huán) 
//采樣周期為dt
loop:
 //setpoint 設(shè)定值
 //measured_value 反饋值
    error := setpoint ? measured_value //計算得到偏差
    proportion := error - previous01_error //計算得到比例輸出
    integral := error × dt //計算得到積分累加和
    derivative := (error ? 2*previous01_error + previous02_error) / dt //計算得到微分
    pid_delta := Kp × error + Ki × integral + Kd × derivative //計算得到PID增量
    pid_out := pid_out + pid_delta //計算得到PID輸出

    //保存當(dāng)前的偏差和上一次偏差作為下一次采樣所需要的歷史偏差
    previous02_error := previous01_error 
    previous01_error := error    //保存當(dāng)前偏差為下一次采樣時所需要的歷史偏差
    wait(dt) //等待下一次采用
    goto loop

4 C語言實現(xiàn)

這里直接使用了TI公司的PID算法,做了積分抗飽和;具體可以參考controlSUITE\libs\app_libs\motor_control\math_blocks\v4.2\pid_grando.h

具體代碼如下所示;

pid_grando.h

/* =================================================================================
File name:       PID_GRANDO.H 
===================================================================================*/



#ifndef __PID_H__
#define __PID_H__

typedef struct {  _iq  Ref;      // Input: reference set-point
      _iq  Fbk;      // Input: feedback
      _iq  Out;      // Output: controller output 
      _iq  c1;      // Internal: derivative filter coefficient 1
      _iq  c2;      // Internal: derivative filter coefficient 2
    } PID_TERMINALS;
    // note: c1 & c2 placed here to keep structure size under 8 words

typedef struct {  _iq  Kr;    // Parameter: reference set-point weighting 
      _iq  Kp;    // Parameter: proportional loop gain
      _iq  Ki;       // Parameter: integral gain
      _iq  Kd;           // Parameter: derivative gain
      _iq  Km;           // Parameter: derivative weighting
      _iq  Umax;   // Parameter: upper saturation limit
      _iq  Umin;   // Parameter: lower saturation limit
    } PID_PARAMETERS;

typedef struct {  _iq  up;    // Data: proportional term
      _iq  ui;    // Data: integral term
      _iq  ud;    // Data: derivative term
      _iq  v1;    // Data: pre-saturated controller output
      _iq  i1;    // Data: integrator storage: ui(k-1)
      _iq  d1;    // Data: differentiator storage: ud(k-1)
      _iq  d2;    // Data: differentiator storage: d2(k-1) 
      _iq  w1;    // Data: saturation record: [u(k-1) - v(k-1)]
    } PID_DATA;


typedef struct {  PID_TERMINALS term;
      PID_PARAMETERS param;
      PID_DATA  data;
    } PID_CONTROLLER;

/*-----------------------------------------------------------------------------
Default initalisation values for the PID objects
-----------------------------------------------------------------------------*/
                     

#define PID_TERM_DEFAULTS {    \
                           0,  \
                           0,  \
                           0,  \
                           0,  \
                           0   \
                   }


#define PID_PARAM_DEFAULTS {    \
                           _IQ(1.0), \
                           _IQ(1.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(1.0), \
                           _IQ(1.0), \
                           _IQ(-1.0) \
                   }


#define PID_DATA_DEFAULTS {        \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(0.0), \
                           _IQ(1.0)  \
                   }



/*------------------------------------------------------------------------------
  PID Macro Definition
------------------------------------------------------------------------------*/


#define PID_MACRO(v)                                         \
                                                             \
/* proportional term */                                         \
v.data.up = _IQmpy(v.param.Kr, v.term.Ref) - v.term.Fbk;  \
                                                             \
/* integral term */                                          \
v.data.ui = _IQmpy(v.param.Ki, _IQmpy(v.data.w1,                  \
(v.term.Ref - v.term.Fbk))) + v.data.i1;                     \
v.data.i1 = v.data.ui;                                         \
                                                             \
/* derivative term */                                          \
v.data.d2 = _IQmpy(v.param.Kd, _IQmpy(v.term.c1,                  \
(_IQmpy(v.term.Ref, v.param.Km) - v.term.Fbk))) - v.data.d2; \
v.data.ud = v.data.d2 + v.data.d1;                       \
v.data.d1 = _IQmpy(v.data.ud, v.term.c2);                     \
                                                             \
/* control output */                                          \
v.data.v1 = _IQmpy(v.param.Kp,                                    \
(v.data.up + v.data.ui + v.data.ud));                             \
v.term.Out= _IQsat(v.data.v1, v.param.Umax, v.param.Umin);        \
v.data.w1 = (v.term.Out == v.data.v1) ? _IQ(1.0) : _IQ(0.0);      \
 

#endif // __PID_H__



example

/* Instance the PID module */ 
 
PID   pid1={ PID_TERM_DEFAULTS, PID_PARAM_DEFAULTS, PID_DATA_DEFAULTS }; 
 
main() { 
 
    pid1.param.Kp = _IQ(0.5);     
    pid1.param.Ki  = _IQ(0.005);    
    pid1.param.Kd = _IQ(0);      
    pid1.param.Kr  = _IQ(1.0);     
    pid1.param.Km =_IQ(1.0);     
    pid1.param.Umax= _IQ(1.0);      
    pid1.param.Umin= _IQ(-1.0); 
 

 
void interrupt periodic_interrupt_isr() {  

    pid1.Ref = input1_1;   // Pass _iq inputs to pid1 
    pid1.Fbk = input1_2;   // Pass _iq inputs to pid1   
    PID_MACRO(pid1);  // Call compute macro for pid1        
    output1 = pid1.Out;  // Access the output of pid1     
}
 

5 總結(jié)

本文簡單總結(jié)了位置式PID算法增量式PID算法的差異,參考了TI公司的增量式PID算法實現(xiàn),對于不同的控制對象可以根據(jù)系統(tǒng)要求選擇合適的PID算法

由于作者能力和水平有限,文中難免存在錯誤和紕漏,請不吝賜教。

 簡易PID算法的快速掃盲 

 一文教你搞懂C語言的Q格式

  現(xiàn)成輪子OSAL操作系統(tǒng)抽象層的移植

 一招教你單片機固件快速瘦身

基礎(chǔ)知識 | hex文件格式詳解


—— The End —


長按識別二維碼關(guān)注獲取更多內(nèi)容




免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉
關(guān)閉