單片機之C語言實現簡單的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 = KpError_1 + Ki(Error_1+Error_2+Error_3+…+Error_n) + Kd*(Error_1-Error_2)

增量式:

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

PID(k) =Sp + Si + Sd = KpError_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 = KpError_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;}

運行結果:

在這裏插入圖片描述
未完待續。。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章