單片機之PID算法


說到PID算法,想必大部人並不陌生,PID算法在很多方面都有重要應用,比如電機的速度控制,恆溫槽的溫度控制,四軸飛行器的平衡控制等等,作為閉環控制系統中的一種重要算法,其優點和可實現性都成為人們的首選。下面簡單來講解一下PID算法:

首先PID算法是有比例,積分,微分三部分組成,先說下比例部分,所謂比例部分,就是呈線性關系,舉個例子,一個電熱絲加熱水,開始的時候溫度很低,離50℃很大,這時應該加大功率,離目標溫度越大,其功率應該越大,反之越小,這就是比例部分。

乍一看,既然比例部分已經可以控制溫度了為啥還需要積分和微分部分呢,難道是多此一舉么?其實不然,在實際中會出現這種情況,當加熱到50℃時,系統很難停止下來,而是會持續一段時間,這樣就會超過預設值,所以僅有比例控制並不完美,這是就需要積分部分和微分部分。積分部分就是把之前的誤差全部累加起來,這樣起始時由於誤差很大加熱功率就大,隨着接近預設值后功率開始減少,微分部分就是起始時溫度增加很快,表示此時需要很大的功率,隨着溫度接近預設值,其斜率開始減小最后為零,意味着功率也減少,當然很難為零,一般在一定的范圍內波動。

現在開始用C語言來實現PID算法:

位置式:

比例部分

    Kp:比例系數  SetValue:預設值  FactValue:當前實際值  Error_1:當前誤差

則比例部分為:

    Sp  =   Kp*(SetValue - FactValue)

或者

    Sp  =  Kp*Error_1

注解:Sp大小反應需要控制的量大小,比如Sp越大,功率越大。當Sp為負值時,表示要超過預設值,如果是電機,則需要反轉

積分部分

    Ki:積分系數  Error_1:當前誤差  Error_2:上一次誤差  Error_3:上上一次誤差  ........Error_n:開始時的誤差

則積分部分為:

    Si  =  Ki*(Error_1+Error_2+Error_3+......+Error_n)

注解:因為整個是一個過程,所以上一次誤差其實就是上一次的當前誤差

微分部分

    Kd:微分系數  Error_1:當前誤差  Error_2:上一次誤差 

則微分部分為:

    Sd  =  Kd*(Error_1-Error_2)

綜上部分的PID得:

    PID=Sp + Si + Sd = Kp*Error_1 + Ki*(Error_1+Error_2+Error_3+......+Error_n) + Kd*(Error_1-Error_2)

增量式

 將上述推導的PID記作時間為k時刻的PID控制量,則

    PID(k) =Sp + Si + Sd = Kp*Error_1(k) + Ki*(Error_1(k)+Error_2(k-1)+Error_3(k-2)+......+Error_n(0)) + Kd*(Error_1(k)-Error_2(k-1))        1

將上式k=k-1代入得:

    PID(k-1) =Sp + Si + Sd = Kp*Error_1(k-1) + Ki*(Error_1(k-1)+Error_2(k-2)+Error_3(k-3)+......+Error_n(0)) + Kd*(Error_1(k-1)-Error_2(k-2))               2

1-2得:

    PID(k) - PID(k-1) =  Kp*(Error_1(k)-Error_1(k-1)) + Ki*(Error_1(k)) + Kd*(Error_1(k)-2*Error_2(k-1)+Error_2(k-2))

PID(k) - PID(k-1)記作detPID

    detPID = Kp*(Error_1(k)-Error_1(k-1)) + Ki*(Error_1(k)) + Kd*(Error_1(k)-2*Error_2(k-1)+Error_2(k-2))

這樣就得到了增量式的PID算法,其計算的結果為增加的控制量

增量式的PID有個好處就是只與當前三個誤差量有關系,與其他無關,這樣就簡化的處理過程,而且提高了精度,下面是PID源碼:

/*文件名:PID.h*/

#ifndef  _PID_H_
#define  _PID_H_

extern float Kp,Ki,Kd;       //系數(全局變量)
extern float AclValue; //實際值
extern float SetValue;

int PID(void);
    

#endif

 

/*########################################################################
文件名:PID.c
時間: 2018.9.7
備注:無
#########################################################################*/


#include "PID.h"

float Kp=10,Ki=0.8,Kd=0.5;  //系數

float SetValue=2000;  //設定值

float AclValue=0; //實際

float Error1=0,Error2=0,Error3=0;     //誤差

/*  下面為增量式PID算法  */

/**********************************************************************************
函數名:PID
返回值:輸出增量
參數:無
備注:當輸出大於0表示小於預設值,當輸出小於0表示大於預設值
***********************************************************************************/
int PID(void)
{
    float OutValue =0;
    Error3 = SetValue - AclValue;

    OutValue = Kp*(Error3-Error2)+Ki*(Error3)+Kd*(Error3-2*Error2+Error1);
    
    Error1=Error2;         //這部分是迭代,因為上次的誤差就是上次的當前誤差
    Error2=Error3;
    
    if(OutValue>3000)        //這部分是規定最大輸出增量
        OutValue=3000;
    if(OutValue<-3000)
        OutValue=-3000;
    
    return OutValue;
}

下面給出計算機模擬代碼;

#include "stdio.h"

float Kp=10,Ki=2,Kd=0.5;  //系數

float SetValue=1256;  //設定值

float AclValue=0; //實際

float Error1=0,Error2=0,Error3=0;     //誤差

/*  下面為增量式PID算法  */

/**********************************************************************************
函數名:PID
返回值:輸出增量
參數:無
備注:當輸出大於0表示小於預設值,當輸出小於0表示大於預設值
***********************************************************************************/
int PID(void)
{
    float OutValue =0;
    Error3 = SetValue - AclValue;

    OutValue = Kp*(Error3-Error2)+Ki*(Error3)+Kd*(Error3-2*Error2+Error1);
    
    Error1=Error2;
    Error2=Error3;
    
    return OutValue;
}


int main(void)
{
    unsigned int i=1000;
    while(i)
    {
        
        PID();  //特別注意這里:必須要運行,因為需要執行這一步:Error1=Error2; Error2=Error3;

printf("當前實際值為:%f \n",AclValue); AclValue += PID(); i--);
 } 

return 0;
}

運行結果:

 

    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM