用Excel教會(huì)你PID算法
1、引入PID
電機(jī)控制
這樣是沒(méi)有反饋的,也就是說(shuō)我們完全相信輸入的數(shù)字,且是理想化的模型,比如輸入占空比為50%的25Kz的PWM,車輪速度為1m/s,實(shí)際產(chǎn)品中會(huì)受到各種這樣的影響,比如地面阻力,風(fēng)阻等等,同樣輸入占空比為50%的25Kz的PWM,車輪的速度并不是1m/s。
這時(shí)候我們就引入測(cè)量單元,也就是反饋系統(tǒng)。
這個(gè)時(shí)候,最常見(jiàn)的反饋就是:直接使用反饋值。簡(jiǎn)單的例子,屬于數(shù)值X和輸出數(shù)值y的數(shù)學(xué)公式是:y=2x,這是這最見(jiàn)的關(guān)系。假設(shè)我們輸入7,測(cè)量結(jié)果是5,那么我們就直接將輸入修改為7+2*(7-5)=11。也就是我們一次直接調(diào)整到位。這樣調(diào)節(jié)過(guò)于簡(jiǎn)單粗暴,因?yàn)槲覀冎苯訉⑤斎胄薷臑?1,有可能輸出直接變成6,超過(guò)預(yù)期值了。這時(shí)候就自然而然的想到多次調(diào)節(jié),每次只增加一點(diǎn),然后測(cè)量速度,看一下是否達(dá)標(biāo)。
這就是比例調(diào)節(jié)Kp。
2、比例調(diào)節(jié)
舉例說(shuō)明,當(dāng)前小車速度為0.2,目標(biāo)速度是1。輸出y和輸入x的關(guān)系是y=1*x。比例系數(shù)Kp=0.5。隨著時(shí)間的增大,輸出和輸入關(guān)系如下。
直觀折線圖顯示如下:
我們發(fā)現(xiàn)這太完美了,那么比例環(huán)節(jié)就能夠完美的解決問(wèn)題了,可是等等,在下這個(gè)結(jié)論前,我們忽略一個(gè)特因素:噪聲誤差。
在很多系統(tǒng)中都是有噪聲的,這我們舉例小車中,噪聲誤差可能來(lái)自于電機(jī)的誤差,外部因素風(fēng)阻等誤差,且是波動(dòng)的。我們將問(wèn)題簡(jiǎn)化,假設(shè)外部因素恒定,外部因素是的小車實(shí)際輸出速度減去1。
還是上面的例子,當(dāng)前小車速度為0.2,目標(biāo)速度是1。輸出y和輸入x的關(guān)系是y=1*x。比例系數(shù)Kp=0.5,恒定的誤差為-0.1,隨著時(shí)間的增大,輸出和輸入關(guān)系如下。
直觀折線圖顯示如下:
最終輸出穩(wěn)定在0.8,因?yàn)槲覀兂跏贾禐?.2,到最后和目標(biāo)差值是0.2,補(bǔ)償是0.1,誤差正好是-0.1,也就是說(shuō)等于我們沒(méi)有補(bǔ)償。
如果我們需要速度達(dá)到1呢???辦法就是增大比例系數(shù)Kp。
誤差為0.8時(shí)
誤差為1.9時(shí)
誤差為2時(shí),已經(jīng)完全震蕩
結(jié)論:比例控制引入了穩(wěn)態(tài)誤差,且無(wú)法消除。比例常數(shù)增大可以減小穩(wěn)態(tài)誤差,但如果太大則引起系統(tǒng)震蕩,不穩(wěn)定。
3、積分調(diào)節(jié)
為了消除穩(wěn)態(tài)誤差,第二次加入積分,使用PI(比例積分控制),積分控制就是將歷史誤差全部加起來(lái)乘以積分常數(shù)。公式如下:
u(t) -------------輸出曲線,pid輸出值隨時(shí)間的變化曲線
Kp --------------比例系數(shù)
e(t)--------------偏差曲線,設(shè)定值與實(shí)際值的偏差隨時(shí)間的變化曲線
t-----------------時(shí)間
關(guān)于定積分,如果你上過(guò)高數(shù),且沒(méi)有睡覺(jué)的話。
需要將數(shù)學(xué)公式離散化,才能用到計(jì)算機(jī)系統(tǒng)來(lái)。
①表示在時(shí)間點(diǎn)t,輸出的值
②表示在時(shí)間點(diǎn)t,輸出的誤差
③表示從時(shí)間0到t,累計(jì)誤差。
添加Ki參數(shù)之后的折線圖如下
結(jié)論:
只要存在偏差,積分就不停的累計(jì),直到誤差為0,積分項(xiàng)不再累加,變成一個(gè)常數(shù),可以抵消穩(wěn)態(tài)誤差.
4、微分調(diào)節(jié)
引入積分可以消除穩(wěn)態(tài)誤差,但會(huì)增加超調(diào),且Ki增大,超調(diào)量也增大.
為了消除超調(diào),我們引入微分作用
積分就是e(t)曲線的斜率。
將公式離散化為
ek是當(dāng)前誤差,ek-1是上一次誤差,所以①就是誤差曲線的斜率。
關(guān)于PID公式還有其他寫法,本質(zhì)是一樣的
離散化后是
u(t) -------------輸出曲線,pid輸出值隨時(shí)間的變化曲線
Kp --------------比例系數(shù)
e(t)------------- 偏差曲線,設(shè)定值與實(shí)際值的偏差隨時(shí)間的變化曲線
Ti--------------- 積分時(shí)間
Td--------------微分時(shí)間
T----------------調(diào)節(jié)周期
那么PID的參數(shù)如下
將前面的示例,加入微分項(xiàng),Ki=0.3。
折線圖如下
結(jié)論:微分能夠減弱超調(diào)趨勢(shì)。
5、總結(jié)
PID調(diào)節(jié)示意圖如下:
可以發(fā)現(xiàn):
比例項(xiàng)是糾正偏差的主力,越遠(yuǎn)離偏差絕對(duì)值就越大,快速把偏差糾正回來(lái)。
積分項(xiàng)和以往的狀態(tài)有關(guān),面積的絕對(duì)值越大它的絕對(duì)值就越大,它的作用是消除累計(jì)偏差。
微分項(xiàng)跟斜率有關(guān),比較難解釋,總的來(lái)說(shuō)它的作用是:當(dāng)目標(biāo)靠近設(shè)定值時(shí)加速它靠近,當(dāng)目標(biāo)遠(yuǎn)離設(shè)定值時(shí)阻止它遠(yuǎn)離。因此微分可以增加系統(tǒng)穩(wěn)定性,因?yàn)榈竭_(dá)目的之后,離開(kāi)會(huì)受到阻礙。
6、增量PID
上面我們講解的是位置PID,還有一種增量PID,輸出的不是目標(biāo)值,而是與上次值的差值。直觀上將就是u(t)-u(t-1)。
那么u(t)-u(t-1)的公式是
位置型PID控制器的基本特點(diǎn):
- 位置型PID控制的輸出與整個(gè)過(guò)去的狀態(tài)有關(guān),用到了偏差的累加值,容易產(chǎn)生累積偏差。
- 位置型PID適用于執(zhí)行機(jī)構(gòu)不帶積分部件的對(duì)象。
- 位置型的輸出直接對(duì)應(yīng)對(duì)象的輸出,對(duì)系統(tǒng)的影響比較大。
增量型PID控制器的基本特點(diǎn):
- 增量型PID算法不需要做累加,控制量增量的確定僅與最近幾次偏差值有關(guān),計(jì)算偏差的影響較小。
- 增量型PID算法得出的是控制量的增量,對(duì)系統(tǒng)的影響相對(duì)較小。
- 采用增量型PID算法易于實(shí)現(xiàn)手動(dòng)到自動(dòng)的無(wú)擾動(dòng)切換。
7、代碼編程
位置PID
- /*******************************************************************
- 位置式pid
- ********************************************************************/
- double PID(double Actual,double SET)
- {
- static double E_sum,Error_last; //上一次誤差
- double kp=20.767,ki=1.867,kd=115.55;
- double pid_out;
- double Error_now; //當(dāng)前誤差
- Error_now = SET-Actual; //當(dāng)前誤差
- // if(Error_now>-0.9&&Error_now<0.9) //防靜態(tài)誤差
- // {
- // Error_now=0;
- // Error_last=0;
- // }
- E_sum += Error_now; //誤差累計(jì)
- // if(E_sum>484)E_sum=484; //積分限幅度,防止積分飽和
- // if(E_sum<-484)E_sum=-484;
- pid_out= kp * Error_now + ki * E_sum + kd * (Error_now-Error_last); //pid計(jì)算公式
- Error_last=Error_now;
- // if(pid>900) pid=900; //輸出限幅
- // if(pid<-900)pid=-900;
- return -pid_out;
- }
增量PID
- error = target_speed - current_speed;
- P_error = error;
- I_error = error - left_motor.L_error;
- D_error = error - 2*left_motor.L_error + left_motor.LL_error;
- add = (s16)(KP * P_error + KI * I_error + KD * D_error);
- left_motor.ESC_output_PWM += add;
- left_motor.LL_error = left_motor.L_error;
- left_motor.L_error = error;
本文轉(zhuǎn)載自微信公眾號(hào)「知曉編程」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系知曉編程公眾號(hào)。