最新电影在线观看,jrs低调看直播,avav天堂,囯产精品宾馆在线精品酒店,亚洲精品成人区在线观看

從零理解PID控制:小球仿真到代碼實現,手把手教你掌握工業級控制算法

前言

很多人應該都聽說過PID,它的運算過程簡單,并能在大多情況下實現較好的控制效果,因此它是工程實踐中使用最廣泛的控制方法之一。

拋開公式,我將帶你從案例出發,詳細了解PID的工作原理和使用方法。

注:閱讀本文不需要有過多的基礎知識,只需中學物理和數學知識就能看懂(當然如果有高等數學知識和單片機知識的話理解起來會更容易)

仿真調參環境

我專門為本文搭了一個在線仿真環境,下面使用的案例都來自這個環境,讀者可以搭配使用

案例引入——小球位置控制

任務介紹

我們假設有一個一維的坐標軸(向右為正方向),在上面上有一個小球(可以看作質點),小球不受任何阻力,可以自由左右滑動;另外,我們還為小球規定了一個目標位置(圖中的綠色標線):

現在我們有下述任務:

  • 目標:在小球上施加一個水平方向的力(稱為控制力),使小球在偏離目標位置時回到目標位置
  • 已知條件:小球的實時坐標、目標位置坐標

看到這里的你可以停下來想一想,應該用什么樣的策略來計算這個力呢?

這里大多數人應該都能想出這樣的方法:

“當小球在目標左邊的時候向右施力,當小球在目標右邊的時候向左施力,就可以保證小球一直在目標位置上了”

思路是非常正確的,但這個策略仍不夠完善。由于小球存在慣性,我們施加的力將小球拉回目標位置后小球還會具有一定的速度繼續運動,并不會直接停在目標位置。

用PID完成任務

接下來我們來看看如果使用PID,我們應該如何計算出這個控制力呢?

誤差計算

計算PID的第一步就是計算誤差(Error):誤差=目標值-反饋值。在這個例子中,目標值是目標位置坐標,反饋值是小球實時位置坐標,那么誤差就是小球當前位置與目標間的距離。

接下來的運算我們都會圍繞誤差進行,分為三個步驟使用誤差分別算出一個分力,并將三個分力一起施加在小球上。

比例環節

第一個環節是比例環節P(Proportion),這個環節產生的分力是

即:分力大小與誤差成正比,且當小球在目標左邊的時候分力向右,當小球在目標右邊的時候分力向左,其中kp是比例系數。

比例環節的計算方法其實與上面大家通過直覺得出的方法差不多,如果只有這個分力作用的話,會產生什么效果呢?

大家可能會發現,這就與中學物理里的彈簧滑塊模型是一樣的,力與距離成正比,顯然小球會以目標位置為中心進行左右擺動(簡諧振動)(注:圖中藍色短線表示控制力):

只有比例環節時的小球運動

微分環節

那么如何讓小球能夠靜止在目標點呢?這就要請出PID的另一個環節:微分環節D(Differential)

微分環節也會計算出一個分力,計算方法是:

也就是說,這個分力與誤差的變化速度有關。假設目標位置不變,小球向右運動時誤差減小,即誤差變化速度為負,分力向左;反之當小球向左運動時分力向右;綜合看來,微分環節產生的分力始終阻礙小球的運動。

因此如果在剛剛的基礎上加入微分產生的分力,就會產生一個阻尼效果,小球會仿佛始終受到一個阻力,因此左右擺動的幅度會逐漸減小,最終收斂到目標位置上:

有比例和微分環節時的小球運動

由公式還可以看出,微分系數Kd可以影響這個“阻力”的大小,因此如果我們把系數調大一些,就可以讓小球的運動收斂得更快一些:

調大kd后的小球運動

到這里,其實我們已經完成我們的目標任務了,小球可以在驅動力的作用下運動到目標位置。

積分環節

但現在,我們更希望在小球有一些外部干擾時也能實現上面的效果,比如我們在小球上加上一個水平向右的恒力,此時會發生什么呢?

恒力干擾下小球靜止狀態

小球在運動過程中仍然會像之前一樣接近目標點,但在最終停下來時我們會發現,小球無法精確停在目標點上,而是像上圖一樣停在離目標點有一定距離的地方。此時控制力與干擾恒力平衡,小球靜止。

稍加分析我們就能發現,此時小球靜止,微分環節產生的分力為零,控制力完全由比例環節產生,且若距離更小則比例環節的輸出更小,更無法平衡干擾力,因此小球無法繼續向目標點接近。

此時就需要我們的第三個環節出場了:積分環節I(Integral),它的計算方法是:

也就是說積分環節產生的分力正比于誤差的積分,當誤差持續存在時,這個分力會逐漸變大,試圖消除誤差。

加入積分作用,我們的PID就能完美實現在有恒力干擾的情況下對小球的控制了:

PID作用下小球控制效果

拋開案例——更專業地理解PID

常用術語

  • 被控對象:需要控制的對象,案例中指小球
  • 目標值:期望被控對象達到的狀態量,案例中指目標位置的坐標
  • 反饋值:被控對象當前時刻的狀態量,案例中指小球的實時位置坐標
  • 輸出量:PID的計算結果,案例中指控制力
  • 誤差:目標值-反饋值
  • 穩態誤差:系統穩定狀態下仍存在的誤差,如案例中加入干擾恒力后小球靜止時仍存在的誤差

不同參數下系統的階躍響應(源:百度百科)

  • 階躍輸入:在穩定狀態下目標值發生突然變化(上圖目標值在0時刻由0躍升到虛線位置)
  • 階躍響應:階躍輸入后被控對象的跟隨狀態,能夠代表系統的控制性能(上圖彩色線條)
  • 響應速度:階躍輸入后被控對象再次到達目標值的速度
  • 超調量:階躍輸入后,被控對象到達目標值后超出目標值的距離(上圖各彩色線條第一個峰值與目標值的距離)

PID計算過程

PID信號框圖

上圖就是PID的信號框圖,表示了PID的運行過程:

  1. 為系統指定一個目標值;

  2. PID將目標值與被控對象當前的反饋量作差得到誤差;

  3. PID將誤差值分別經過三個環節計算得到輸出分量,三個分量加起來得到PID的輸出;

  4. 將PID的輸出施加到被控對象上,使反饋量向目標值靠攏。

PID三個環節的作用

由控制小球案例我們可以總結出PID三個環節各自的主要作用和效應:

  • 比例環節:起主要控制作用,使反饋量向目標值靠攏,但可能導致振蕩
  • 積分環節:消除穩態誤差,但會增加超調量
  • 微分環節:產生阻尼效果,抑制振蕩和超調,但會降低響應速度

PID中物理量的設計

我們在設計PID時主要關注三個量:目標值反饋值輸出值,PID會根據目標值和反饋值計算輸出值。

需要強調的是,PID并不知道被控對象是什么,它僅負責進行數值計算,而我們——作為控制系統的設計者,就需要為PID指定這三個量所對應的實際物理量,這在不同的控制系統中是不一樣的。

那么如何確定實際物理量呢,我為大家總結了一個常用準則。

  • 目標值和反饋值通常為同種物理量,就是你需要控制的物理量
  • 輸出值通常是直接驅動被控對象的控制量
  • 輸出量作用在被控對象上需要經過時間積累才會產生反饋量的變化,換言之輸出值通常為反饋值對于時間的低階物理量。比如:目標值和反饋值為位置,則輸出值可以為速度或加速度
  • 對于線性關系的兩個物理量(只差一個系數),可以直接替換。比如:目標和反饋值為小球位置,根據上一條準則,輸出值可以為加速度。但我們無法直接控制加速度,只能控制驅動力大小,由于驅動力與加速度只差一個系數(F=ma),因此可以將輸出值直接定為驅動力

接下來給出幾個例子:

任務一:對小球進行速度控制

可用條件:已知小球的實時速度,并且可施加一個力來改變小球的速度

PID目標值:需要小球達到的速度

PID反饋值:小球的實時速度

PID輸出值:施加在小球上的力

分析:小球加速度是小球速度的低階物理量,而施加的力正比于小球加速度

任務二:對電機轉速進行控制

可用條件:已知電機的實時轉速,并且可控制電機中流過的電流大小

PID目標值:需要電機達到的轉速

PID反饋值:電機的實時轉速

PID輸出值:電機中流過的電流大小

分析:電機中流過的電流大小近似正比于電機的扭矩,也就近似正比于電機角加速度的大小,是轉速的低階物理量,因此可以用電流大小作為輸出值

任務三:液位高度控制

描述:容器有進水口和出水口,需要通過進水口的閥門控制容器內液位的高度

可用條件:容器內液位實時高度,可控制進水口閥門液體流速

PID目標值:需要達到的液位高度

PID反饋值:液位實時高度

PID輸出值:閥門液體流速

分析:閥門液體流速正比于液位高度的變化速度,是液位高度的低階物理量

由虛到實——代碼編寫

程序流程

根據上面的步驟,我們其實很容易就能得出程序的執行流程了,就是在計算誤差后逐個進行PID各環節的計算。要注意的是整個采樣-計算-輸出的流程需要定時執行,可以在每次流程運行完后延時一段固定的時間(一般而言計算頻率不高于傳感器反饋頻率,但也不能太低,否則會使控制精度下降)。

代碼流程圖

實現細節

有一個問題沒有解決,積分和微分應該怎么算呢?畢竟微積分都是連續的,而我們采樣得到的是離散的數據點。其實也很簡單,離散狀態下的積分計算其實就是把過去采樣得到的所有誤差加在一起,而微分計算就是把這一輪計算得到的誤差與上一輪的誤差相減。

最后,我們一般還會對PID的積分和輸出進行限幅(規定上下限),積分限幅可以減小積分引起的超調,輸出限幅可以保護執行機構或被控對象。

C語言代碼

//首先定義PID結構體用于存放一個PID的數據
typedef struct
{
   	float kp, ki, kd; //三個系數
    float error, lastError; //誤差、上次誤差
    float integral, maxIntegral; //積分、積分限幅
    float output, maxOutput; //輸出、輸出限幅
}PID;
 
//用于初始化pid參數的函數
void PID_Init(PID *pid, float p, float i, float d, float maxI, float maxOut)
{
    pid->kp = p;
    pid->ki = i;
    pid->kd = d;
    pid->maxIntegral = maxI;
    pid->maxOutput = maxOut;
}
 
//進行一次pid計算
//參數為(pid結構體,目標值,反饋值),計算結果放在pid結構體的output成員中
void PID_Calc(PID *pid, float reference, float feedback)
{
 	//更新數據
    pid->lastError = pid->error; //將舊error存起來
    pid->error = reference - feedback; //計算新error
    //計算微分
    float dout = (pid->error - pid->lastError) * pid->kd;
    //計算比例
    float pout = pid->error * pid->kp;
    //計算積分
    pid->integral += pid->error * pid->ki;
    //積分限幅
    if(pid->integral > pid->maxIntegral) pid->integral = pid->maxIntegral;
    else if(pid->integral < -pid->maxIntegral) pid->integral = -pid->maxIntegral;
    //計算輸出
    pid->output = pout+dout + pid->integral;
    //輸出限幅
    if(pid->output > pid->maxOutput) pid->output =   pid->maxOutput;
    else if(pid->output < -pid->maxOutput) pid->output = -pid->maxOutput;
}
 
PID mypid = {0}; //創建一個PID結構體變量
 
int main()
{
    //...這里有些其他初始化代碼
    PID_Init(&mypid, 10, 1, 5, 800, 1000); //初始化PID參數
    while(1)//進入循環運行
    {
        float feedbackValue = ...; //這里獲取到被控對象的反饋值
        float targetValue = ...; //這里獲取到目標值
        PID_Calc(&mypid, targetValue, feedbackValue); //進行PID計算,結果在output成員變量中
        設定執行器輸出大小(mypid.output);
        delay(10); //等待一定時間再開始下一次循環
    }
}

最后一步——PID參數調整

在完成控制器代碼編寫后,就要連接好系統進行調參了,我們需要確定最合適的KpKiKd使控制效果最優。

通常還是使用經驗法調參,通俗而言就是“試參數”,測試多個參數選取最好的控制效果,一般的步驟如下:

  1. 先將所有參數置零

  2. 將輸出限幅設為執行機構能接受的最大值

  3. 增大p參數,使響應速度達到比較好的水平

  4. 若存在穩態誤差,逐漸增加i參數和積分限幅,使穩態誤差消失

  5. 若希望減少超調或振蕩,逐漸增加d參數,在保證響應速度的前提下盡可能降低超調

此時大家可以使用上述的小球仿真環境體驗一下各參數對系統的影響。到這里,我們就已經能夠使用PID來控制各種對象了。

總結——使用PID的步驟

  1. 確定需要控制的對象,確定需要控制的物理量,確定反饋量的獲取方式,確定被控對象的控制方式;

  2. 檢查目標值、反饋值、輸出值對應物理量的關系是否符合上面說的準則;

  3. 編寫代碼,將上述三個值的數值變量傳入PID進行運算,并將PID運算結果輸出到執行機構;

  4. 進行參數調整。

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 6
收藏 7
關注 13
成為作者 賺取收益
全部留言
0/200
  • 電子渣男 08-12 11:38
    講的很棒
    回復 1條回復