目錄
我們提供的服務(wù)有:成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、淮陽(yáng)ssl等。為上千余家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的淮陽(yáng)網(wǎng)站制作公司前言
仿真調(diào)參環(huán)境
案例引入——小球位置控制
拋開(kāi)案例——更專業(yè)地理解PID
由虛到實(shí)——代碼編寫(xiě)
最后一步——PID參數(shù)調(diào)整
總結(jié)——使用PID的步驟
更進(jìn)一步——串級(jí)PID
很多人應(yīng)該都聽(tīng)說(shuō)過(guò)PID,它的運(yùn)算過(guò)程簡(jiǎn)單,并能在大多情況下實(shí)現(xiàn)較好的控制效果,因此它是工程實(shí)踐中使用最廣泛的控制方法之一。
拋開(kāi)公式,我將帶你從案例出發(fā),詳細(xì)了解PID的工作原理和使用方法。
注:閱讀本文不需要有過(guò)多的基礎(chǔ)知識(shí),只需中學(xué)物理和數(shù)學(xué)知識(shí)就能看懂(當(dāng)然如果有高等數(shù)學(xué)知識(shí)和單片機(jī)知識(shí)的話理解起來(lái)會(huì)更容易)
我專門為本文搭了一個(gè)在線仿真環(huán)境,下面使用的案例都來(lái)自這個(gè)環(huán)境,讀者可以搭配使用https://skythinker.gitee.io/pid-simulator-web/https://skythinker.gitee.io/pid-simulator-web/
我們假設(shè)有一個(gè)一維的坐標(biāo)軸(向右為正方向),在上面上有一個(gè)小球(可以看作質(zhì)點(diǎn)),小球不受任何阻力,可以自由左右滑動(dòng);另外,我們還為小球規(guī)定了一個(gè)目標(biāo)位置(圖中的綠色標(biāo)線):
現(xiàn)在我們有下述任務(wù):
看到這里的你可以停下來(lái)想一想,應(yīng)該用什么樣的策略來(lái)計(jì)算這個(gè)力呢?
到這里大多數(shù)人應(yīng)該都能想出來(lái)這樣的方法:
“當(dāng)小球在目標(biāo)左邊的時(shí)候向右施力,當(dāng)小球在目標(biāo)右邊的時(shí)候向左施力,就可以保證小球一直在目標(biāo)位置上了”
思路是非常正確的,但這個(gè)策略仍不夠完善,因?yàn)樾∏虼嬖趹T性,我們施加的力將小球拉回目標(biāo)位置后小球還會(huì)具有一定的速度繼續(xù)運(yùn)動(dòng),并不會(huì)直接停在目標(biāo)位置。
用PID完成任務(wù)接下來(lái)我們來(lái)看看如果使用PID,我們應(yīng)該如何計(jì)算出這個(gè)控制力呢?
誤差計(jì)算計(jì)算PID的第一步就是計(jì)算誤差(Error):誤差=目標(biāo)值-反饋值,在這個(gè)例子中,誤差就是小球當(dāng)前位置與目標(biāo)值間的距離。
接下來(lái)的運(yùn)算我們都會(huì)圍繞誤差進(jìn)行,分為三個(gè)步驟使用誤差分別算出一個(gè)分力,并將三個(gè)分力一起施加在小球上。
比例環(huán)節(jié)第一個(gè)環(huán)節(jié)是比例環(huán)節(jié)P(Proportion),這個(gè)環(huán)節(jié)產(chǎn)生的分力是:
也就是說(shuō)分力大小與誤差成正比,當(dāng)小球在目標(biāo)左邊的時(shí)候分力向右,當(dāng)小球在目標(biāo)右邊的時(shí)候分力向左,其中是比例系數(shù)。
比例環(huán)節(jié)的計(jì)算方法其實(shí)就與上面大家通過(guò)直覺(jué)得出的方法差不多,如果只有這個(gè)分力作用的話,會(huì)產(chǎn)生什么效果呢?
大家可能會(huì)發(fā)現(xiàn)這不就跟中學(xué)物理里的彈簧滑塊模型是一樣的嘛,力與距離成正比,很明顯小球會(huì)以目標(biāo)位置為中心進(jìn)行左右擺動(dòng)(簡(jiǎn)諧振動(dòng))(注:圖中藍(lán)色短線表示控制力):
微分環(huán)節(jié)那么如何讓小球能夠靜止在目標(biāo)點(diǎn)呢?這就要請(qǐng)出PID的另一個(gè)環(huán)節(jié):微分環(huán)節(jié)D(Differential)。
微分環(huán)節(jié)也會(huì)計(jì)算出一個(gè)分力,計(jì)算方法是:
也就是說(shuō),這個(gè)分力與誤差的變化速度有關(guān),在目標(biāo)位置不變的情況下,小球向右運(yùn)動(dòng)時(shí)誤差變化速度為負(fù),分力向左;反之當(dāng)小球向左運(yùn)動(dòng)時(shí)分力向右;綜合看來(lái),微分環(huán)節(jié)產(chǎn)生的分力始終阻礙小球的運(yùn)動(dòng)。
因此如果在剛剛的基礎(chǔ)上加入微分產(chǎn)生的分力,就會(huì)產(chǎn)生一個(gè)阻尼效果,小球會(huì)仿佛始終受到一個(gè)阻力,因此左右擺動(dòng)的幅度會(huì)逐漸減小,最終收斂到目標(biāo)位置上:
由公式還可以看出,微分系數(shù)可以影響這個(gè)“阻力”的大小,因此如果我們把系數(shù)調(diào)大一些,就可以讓小球的運(yùn)動(dòng)收斂得更快一些:
到這里,其實(shí)我們已經(jīng)完成我們的目標(biāo)任務(wù)了,小球可以在驅(qū)動(dòng)力的作用下運(yùn)動(dòng)到目標(biāo)位置。
積分環(huán)節(jié)但現(xiàn)在,我們更希望在小球有一些外部干擾時(shí)也能實(shí)現(xiàn)上面的效果,比如我們?cè)谛∏蛏霞由弦粋€(gè)水平向右的恒力,此時(shí)會(huì)發(fā)生什么呢?
小球在運(yùn)動(dòng)過(guò)程中仍然會(huì)像之前一樣接近目標(biāo)點(diǎn),但在最終停下來(lái)時(shí)我們會(huì)發(fā)現(xiàn),小球無(wú)法精確停在目標(biāo)點(diǎn)上,而是像上圖一樣停在離目標(biāo)點(diǎn)有一定距離的地方,此時(shí)控制力與干擾恒力平衡,小球靜止。
稍加分析我們就能發(fā)現(xiàn),此時(shí)小球靜止,微分環(huán)節(jié)產(chǎn)生的分力為零,控制力完全由比例環(huán)節(jié)產(chǎn)生,且若距離更小則比例環(huán)節(jié)的輸出更小,更無(wú)法平衡干擾力,因此小球無(wú)法繼續(xù)向目標(biāo)點(diǎn)接近。
此時(shí)就需要我們的第三個(gè)環(huán)節(jié)出場(chǎng)了:積分環(huán)節(jié)I(Integral),它的計(jì)算方法是:
也就是說(shuō)積分環(huán)節(jié)產(chǎn)生的分力輸出正比于誤差的積分,當(dāng)誤差持續(xù)存在時(shí),這個(gè)分力會(huì)逐漸變大,試圖消除誤差。
加入積分作用,我們的PID就能完美實(shí)現(xiàn)在有恒力干擾的情況下對(duì)小球的控制了:
上圖就是PID的信號(hào)框圖,表示了PID的運(yùn)行過(guò)程:
由控制小球案例我們可以總結(jié)出PID三個(gè)環(huán)節(jié)各自的主要作用和效應(yīng):
我們?cè)谠O(shè)計(jì)PID時(shí)主要關(guān)注三個(gè)量:目標(biāo)值、反饋值、輸出值,PID會(huì)根據(jù)目標(biāo)值和反饋值計(jì)算輸出值。
需要強(qiáng)調(diào)的是,PID的整個(gè)計(jì)算過(guò)程其實(shí)與被控對(duì)象是什么完全沒(méi)有關(guān)系,它只是負(fù)責(zé)進(jìn)行數(shù)值計(jì)算,而我們——作為控制系統(tǒng)的設(shè)計(jì)者,就需要為PID指定這三個(gè)量所對(duì)應(yīng)的實(shí)際物理量,這在不同的控制系統(tǒng)中是不一樣的。
那么如何確定實(shí)際物理量呢,我為大家總結(jié)了一個(gè)常用準(zhǔn)則:
接下來(lái)給出幾個(gè)例子:
任務(wù)一:對(duì)小球進(jìn)行速度控制
可用條件:已知小球的實(shí)時(shí)速度,并且可施加一個(gè)力來(lái)改變小球的速度
PID目標(biāo)值:需要小球達(dá)到的速度
PID反饋值:小球的實(shí)時(shí)速度
PID輸出值:施加在小球上的力
分析:小球加速度是小球速度的低階物理量,而施加的力正比于小球加速度
任務(wù)二:對(duì)電機(jī)轉(zhuǎn)速進(jìn)行控制
可用條件:已知電機(jī)的實(shí)時(shí)轉(zhuǎn)速,并且可控制電機(jī)中流過(guò)的電流大小
PID目標(biāo)值:需要電機(jī)達(dá)到的轉(zhuǎn)速
PID反饋值:電機(jī)的實(shí)時(shí)轉(zhuǎn)速
PID輸出值:電機(jī)中流過(guò)的電流大小
分析:電機(jī)中流過(guò)的電流大小近似正比于電機(jī)的扭矩,也就近似正比于電機(jī)角加速度的大小,是轉(zhuǎn)速的低階物理量,因此可以用電流大小作為輸出值
任務(wù)三:液位高度控制
描述:容器有進(jìn)水口和出水口,需要通過(guò)進(jìn)水口的閥門控制容器內(nèi)液位的高度
可用條件:容器內(nèi)液位實(shí)時(shí)高度,可控制進(jìn)水口閥門液體流速
PID目標(biāo)值:需要達(dá)到的液位高度
PID反饋值:液位實(shí)時(shí)高度
PID輸出值:閥門液體流速
分析:閥門液體流速正比于液位高度的變化速度,是液位高度的低階物理量
根據(jù)上面的步驟,我們其實(shí)很容易就能得出程序的執(zhí)行流程了,就是在計(jì)算誤差后逐個(gè)進(jìn)行PID各環(huán)節(jié)的計(jì)算就行了,要注意的是整個(gè)采樣-計(jì)算-輸出的流程需要定時(shí)執(zhí)行,可以在每次流程運(yùn)行完后延時(shí)一段固定的時(shí)間(一般而言計(jì)算頻率不高于傳感器反饋頻率,而若頻率過(guò)低可能使控制精度下降)。
實(shí)現(xiàn)細(xì)節(jié)有一個(gè)問(wèn)題沒(méi)有解決,積分和微分應(yīng)該怎么算呢?畢竟微積分都是連續(xù)的,而我們采樣得到的是離散的數(shù)據(jù)點(diǎn)。其實(shí)也很簡(jiǎn)單,離散狀態(tài)下的積分計(jì)算其實(shí)就是把過(guò)去采樣得到的所有誤差加在一起,而微分計(jì)算其實(shí)就是把這一輪計(jì)算得到的誤差與上一輪的誤差相減。
最后,我們一般還會(huì)對(duì)PID的積分和輸出進(jìn)行限幅(規(guī)定上下限),積分限幅可以減小積分引起的超調(diào),輸出限幅可以保護(hù)執(zhí)行機(jī)構(gòu)或被控對(duì)象。
C語(yǔ)言代碼//首先定義PID結(jié)構(gòu)體用于存放一個(gè)PID的數(shù)據(jù)
typedef struct
{
float kp,ki,kd;//三個(gè)系數(shù)
float error,lastError;//誤差、上次誤差
float integral,maxIntegral;//積分、積分限幅
float output,maxOutput;//輸出、輸出限幅
}PID;
//用于初始化pid參數(shù)的函數(shù)
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;
}
//進(jìn)行一次pid計(jì)算
//參數(shù)為(pid結(jié)構(gòu)體,目標(biāo)值,反饋值),計(jì)算結(jié)果放在pid結(jié)構(gòu)體的output成員中
void PID_Calc(PID *pid,float reference,float feedback)
{
//更新數(shù)據(jù)
pid->lastError=pid->error;//將舊error存起來(lái)
pid->error=reference-feedback;//計(jì)算新error
//計(jì)算微分
float dout=(pid->error-pid->lastError)*pid->kd;
//計(jì)算比例
float pout=pid->error*pid->kp;
//計(jì)算積分
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;
//計(jì)算輸出
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;//創(chuàng)建一個(gè)PID結(jié)構(gòu)體變量
int main()
{
//...這里有些其他初始化代碼
PID_Init(&mypid,10,1,5,800,1000);//初始化PID參數(shù)
while(1)//進(jìn)入循環(huán)運(yùn)行
{
float feedbackValue=...;//這里獲取到被控對(duì)象的反饋值
float targetValue=...;//這里獲取到目標(biāo)值
PID_Calc(&mypid,targetValue,feedbackValue);//進(jìn)行PID計(jì)算,結(jié)果在output成員變量中
設(shè)定執(zhí)行器輸出大小(mypid.output);
delay(10);//等待一定時(shí)間再開(kāi)始下一次循環(huán)
}
}
在完成控制器代碼編寫(xiě)后,就要連接好系統(tǒng)進(jìn)行調(diào)參了,我們需要確定最合適的使控制效果最優(yōu)。
通常還是使用經(jīng)驗(yàn)法調(diào)參,通俗而言就是“試參數(shù)”,測(cè)試多個(gè)參數(shù)選取最好的控制效果,一般的步驟如下:
此時(shí)大家可以使用上述的小球仿真環(huán)境體驗(yàn)一下各參數(shù)對(duì)系統(tǒng)的影響。到這里,我們就已經(jīng)能夠使用PID來(lái)控制各種對(duì)象了。
當(dāng)我們?cè)谶M(jìn)行小球的位置控制時(shí),我們可能經(jīng)常會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,就是如果小球與目標(biāo)之間的距離較遠(yuǎn)的話,小球在運(yùn)動(dòng)過(guò)程中的速度會(huì)很快,同時(shí)也總是會(huì)導(dǎo)致較大的超調(diào),而且不論怎么修改參數(shù)都很難讓系統(tǒng)的表現(xiàn)更好一些。
這時(shí)你可能會(huì)想,如果運(yùn)動(dòng)過(guò)程中的速度沒(méi)這么快就好了,這樣就不會(huì)沖過(guò)頭了。沒(méi)錯(cuò),這就要用到串級(jí)PID了。
我們上面所說(shuō)的算法其實(shí)就是單級(jí)PID,目標(biāo)值和反饋值經(jīng)過(guò)一次PID計(jì)算就得到輸出值并直接作為控制量,如果目標(biāo)物理量和輸出物理量直接不止差了一階的話,中間階次的物理量我們是無(wú)法控制的。比如:目標(biāo)物理量是位置,輸出物理量是加速度,則小球的速度是無(wú)法控制的。
而串級(jí)PID就可以改善這一點(diǎn)。串級(jí)PID其實(shí)就是兩個(gè)單級(jí)PID“串”在一起組成的,它的信號(hào)框圖如下:
圖中的外環(huán)和內(nèi)環(huán)就分別是一個(gè)單級(jí)PID,每個(gè)單級(jí)PID就如我們之前所說(shuō),需要獲取一個(gè)目標(biāo)值和一個(gè)反饋值,然后可以產(chǎn)生一個(gè)輸出值。串級(jí)PID中兩個(gè)環(huán)相“串”的方式就是將外環(huán)的輸出作為內(nèi)環(huán)的目標(biāo)值。
串級(jí)PID的物理量如果將串級(jí)PID看作一個(gè)整體,可以看到他有三個(gè)輸入和一個(gè)輸出,而此時(shí)被控對(duì)象也需要提供兩個(gè)反饋量,那么它們都應(yīng)該對(duì)應(yīng)些什么物理量呢?
首先我們回到最開(kāi)始的小球案例中,如果用串級(jí)PID完成同樣的任務(wù),應(yīng)該這樣設(shè)計(jì):
可用條件:小球?qū)崟r(shí)位置、小球?qū)崟r(shí)速度、施加在小球上的控制力
目標(biāo)值:小球目標(biāo)位置
外環(huán)反饋:小球?qū)崟r(shí)位置
內(nèi)環(huán)反饋:小球?qū)崟r(shí)速度
輸出值:施加在小球上的控制力
此時(shí)的信號(hào)框圖會(huì)變成這樣:
可以發(fā)現(xiàn),內(nèi)環(huán)與小球構(gòu)成了一個(gè)恒速系統(tǒng),PID內(nèi)環(huán)負(fù)責(zé)小球的速度控制;而如果把內(nèi)環(huán)和小球看作一個(gè)整體被控對(duì)象,外環(huán)又與這個(gè)對(duì)象一起構(gòu)成了一個(gè)位置控制系統(tǒng),外環(huán)負(fù)責(zé)位置控制;總體來(lái)說(shuō),外環(huán)負(fù)責(zé)根據(jù)小球位置誤差計(jì)算出小球需要達(dá)到的速度,而內(nèi)環(huán)負(fù)責(zé)計(jì)算出控制力使小球達(dá)到這個(gè)目標(biāo)速度,兩個(gè)環(huán)協(xié)同工作,就可以完成任務(wù)了。
如果不局限于這個(gè)案例來(lái)說(shuō),串級(jí)PID的內(nèi)環(huán)一般負(fù)責(zé)低階物理量的調(diào)節(jié),而外環(huán)負(fù)責(zé)高階物理量的調(diào)節(jié)并計(jì)算出低階物理量的目標(biāo)值,比如下面這個(gè)例子:
串級(jí)PID的效果任務(wù):對(duì)電機(jī)進(jìn)行串級(jí)角度控制
可用條件:電機(jī)實(shí)時(shí)角度、電機(jī)實(shí)時(shí)轉(zhuǎn)速、可以控制電機(jī)電流大小
外環(huán)目標(biāo)值:需要電機(jī)達(dá)到的角度
外環(huán)反饋值:電機(jī)的實(shí)時(shí)角度
內(nèi)環(huán)反饋值:電機(jī)的實(shí)時(shí)速度
輸出值:電機(jī)電流大小
分析:外環(huán)負(fù)責(zé)電機(jī)角度控制,根據(jù)電機(jī)目標(biāo)角度和反饋角度計(jì)算出目標(biāo)轉(zhuǎn)速;內(nèi)環(huán)負(fù)責(zé)轉(zhuǎn)速控制,根據(jù)速度反饋和目標(biāo)轉(zhuǎn)速計(jì)算出電流
回到我們的小球控制案例,之前說(shuō)使用串級(jí)之后我們就可以對(duì)速度進(jìn)行控制了,如何進(jìn)行控制呢?其實(shí)就是對(duì)外環(huán)PID的輸出進(jìn)行限幅,因?yàn)橥猸h(huán)PID輸出的是目標(biāo)速度,限制外環(huán)輸出就相當(dāng)于限制了小球目標(biāo)速度的大值,內(nèi)環(huán)也就會(huì)維持小球的速度不超過(guò)這個(gè)大值了。
可以看到,使用串級(jí)PID后小球不再像之前那樣“著急”地奔著目標(biāo)而去,由于位置誤差很大,外環(huán)輸出在大部分時(shí)間內(nèi)都處于給定的大值,因此小球在運(yùn)動(dòng)中接近勻速,這個(gè)速度就是所設(shè)定的外環(huán)輸出大值。而且由于運(yùn)動(dòng)速度變慢了,超調(diào)也幾乎消失了。這就是我們想要的“控制位置的同時(shí)還能控制速度”的效果。
串級(jí)PID的C語(yǔ)言代碼//此處需要插入上面的單級(jí)PID相關(guān)代碼
//串級(jí)PID的結(jié)構(gòu)體,包含兩個(gè)單級(jí)PID
typedef struct
{
PID inner;//內(nèi)環(huán)
PID outer;//外環(huán)
float output;//串級(jí)輸出,等于inner.output
}CascadePID;
//串級(jí)PID的計(jì)算函數(shù)
//參數(shù)(PID結(jié)構(gòu)體,外環(huán)目標(biāo)值,外環(huán)反饋值,內(nèi)環(huán)反饋值)
void PID_CascadeCalc(CascadePID *pid,float outerRef,float outerFdb,float innerFdb)
{
PID_Calc(&pid->outer,outerRef,outerFdb);//計(jì)算外環(huán)
PID_Calc(&pid->inner,pid->outer.output,innerFdb);//計(jì)算內(nèi)環(huán)
pid->output=pid->inner.output;//內(nèi)環(huán)輸出就是串級(jí)PID的輸出
}
CascadePID mypid;//創(chuàng)建串級(jí)PID結(jié)構(gòu)體變量
int main()
{
//...其他初始化代碼
PID_Init(&mypid.inner,10,0,0,0,1000);//初始化內(nèi)環(huán)參數(shù)
PID_Init(&mypid.outer,5,0,5,0,100);//初始化外環(huán)參數(shù)
while(1)//進(jìn)入循環(huán)運(yùn)行
{
float outerTarget=...;//獲取外環(huán)目標(biāo)值
float outerFeedback=...;//獲取外環(huán)反饋值
float innerFeedback=...;//獲取內(nèi)環(huán)反饋值
PID_CascadeCalc(&mypid,outerTarget,outerFeedback,innerFeedback);//進(jìn)行PID計(jì)算
設(shè)定執(zhí)行機(jī)構(gòu)輸出大小(mypid.output);
delay(10);//延時(shí)一段時(shí)間
}
}
串級(jí)PID的調(diào)參一般而言,需要先斷開(kāi)兩環(huán)的連接,手動(dòng)指定內(nèi)環(huán)目標(biāo)值,進(jìn)行內(nèi)環(huán)調(diào)參,當(dāng)內(nèi)環(huán)控制效果較好后再接上外環(huán)進(jìn)行外環(huán)調(diào)參,具體的調(diào)參方法與單級(jí)PID相同。
此時(shí)大家也可以使用小球仿真環(huán)境體驗(yàn)一下串級(jí)控制的效果。
原創(chuàng)文章,未經(jīng)授權(quán)請(qǐng)勿轉(zhuǎn)載
by skythinker
2022.2.21
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧