本文轉(zhuǎn)載liuyy博客文章,如有侵權(quán),立刻刪帖!
一、PID算法簡介在智能車競賽中,要想讓智能車根據(jù)賽道的不斷變化靈活的行進(jìn),PID算法的采用很有意義。
? ? 首先必須明確PID算法是基于反饋的。一般情況下,這個反饋就是速度傳感器返回給單片機(jī)當(dāng)前電機(jī)的轉(zhuǎn)速。簡單的說,就是用這個反饋跟預(yù)設(shè)值進(jìn)行比較,如果轉(zhuǎn)速偏大,就減小電機(jī)兩端的電壓;相反,則增加電機(jī)兩端的電壓。?
控制器公式?為:??
式中??
? ???顧名思義,P指是比例(Proportion),I指是積分(Integral),D指微分(Differential)。在電機(jī)調(diào)速系統(tǒng)中,輸入信號為正,要求電機(jī)正轉(zhuǎn)時,反饋信號也為正(PID算法時,誤差=輸入-反饋),同時電機(jī)轉(zhuǎn)速越高,反饋信號越大。要想搞懂PID算法的原理,首先必須先明白P,I,D各自的含義及控制規(guī)律:
比例P:比例項(xiàng)部分其實(shí)就是對預(yù)設(shè)值和反饋值差值的發(fā)大倍數(shù)。舉個例子,假如原來電機(jī)兩端的電壓為U0,比例P為0.2,輸入值是800,而反饋值是1000,那么輸出到電機(jī)兩端的電壓應(yīng)變?yōu)閁0+0.2*(800-1000)。從而達(dá)到了調(diào)節(jié)速度的目的。顯然比例P越大時,電機(jī)轉(zhuǎn)速回歸到輸入值的速度將更快,及調(diào)節(jié)靈敏度就越高。從而,加大P值,可以減少從非穩(wěn)態(tài)到穩(wěn)態(tài)的時間。但是同時也可能造成電機(jī)轉(zhuǎn)速在預(yù)設(shè)值附近振蕩的情形,所以又引入積分I解決此問題。
積分I:顧名思義,積分項(xiàng)部分其實(shí)就是對預(yù)設(shè)值和反饋值之間的差值在時間上進(jìn)行累加。當(dāng)差值不是很大時,為了不引起振蕩。可以先讓電機(jī)按原轉(zhuǎn)速繼續(xù)運(yùn)行。當(dāng)時要將這個差值用積分項(xiàng)累加。當(dāng)這個和累加到一定值時,再一次性進(jìn)行處理。從而避免了振蕩現(xiàn)象的發(fā)生。可見,積分項(xiàng)的調(diào)節(jié)存在明顯的滯后。而且I值越大,滯后效果越明顯。
微分D:微分項(xiàng)部分其實(shí)就是求電機(jī)轉(zhuǎn)速的變化率。也就是前后兩次差值的差而已。也就是說,微分項(xiàng)是根據(jù)差值變化的速率,提前給出一個相應(yīng)的調(diào)節(jié)動作。可見微分項(xiàng)的調(diào)節(jié)是超前的。并且D值越大,超前作用越明顯。可以在一定程度上緩沖振蕩。比例項(xiàng)的作用僅是放大誤差的幅值,而目前需要增加的是“微分項(xiàng)”,它能預(yù)測誤差變化的趨勢,這樣,具有比例+微分的控制器,就能夠提前使抑制誤差的控制作用等于零,甚至為負(fù)值,從而避免了被控量的嚴(yán)重超調(diào)。
二、參數(shù)調(diào)整一般規(guī)則
由各個參數(shù)的控制規(guī)律可知,比例P使反應(yīng)變快,微分D使反應(yīng)提前,積分I使反應(yīng)滯后。在一定范圍內(nèi),P,D值越大,調(diào)節(jié)的效果越好。各個參數(shù)的調(diào)節(jié)原則如下:
PID調(diào)試一般原則?
a.? ?? ? 在輸出不振蕩時,增大比例增益P。
b.? ?? ? 在輸出不振蕩時,減小積分時間常數(shù)Ti。
c.? ?? ? 輸出不振蕩時,增大微分時間常數(shù)Td。
三、參數(shù)調(diào)整一般步驟
a.確定比例增益P
確定比例增益P 時,首先去掉PID的積分項(xiàng)和微分項(xiàng),一般是令Ti=0、Td=0,PID為純比例調(diào)節(jié)。輸入設(shè)定為系統(tǒng)允許的最大值的60%~70%,由0逐漸加大比例增益P,直至系統(tǒng)出現(xiàn)振蕩;再反過來,從此時的比例增益P逐漸減小,直至系統(tǒng)振蕩消失,記錄此時的比例增益P,設(shè)定PID的比例增益P為當(dāng)前值的60%~70%。比例增益P調(diào)試完成。
b.確定積分時間常數(shù)Ti
比例增益P確定后,設(shè)定一個較大的積分時間常數(shù)Ti的初值,然后逐漸減小Ti,直至系統(tǒng)出現(xiàn)振蕩,之后在反過來,逐漸加大Ti,直至系統(tǒng)振蕩消失。記錄此時的Ti,設(shè)定PID的積分時間常數(shù)Ti為當(dāng)前值的150%~180%。積分時間常數(shù)Ti調(diào)試完成。
c.確定積分時間常數(shù)Td
積分時間常數(shù)Td一般不用設(shè)定,為0即可。若要設(shè)定,與確定 P和Ti的方法相同,取不振蕩時的30%。
d.系統(tǒng)空載、帶載聯(lián)調(diào),再對PID參數(shù)進(jìn)行微調(diào),直至滿足要求
四、參數(shù)調(diào)整
PID控制器參數(shù)選擇的方法很多,例如試湊法、臨界比例度法、擴(kuò)充臨界比例度法等。但是,對于PID控制而言,參數(shù)的選擇始終是一件非常煩雜的工作,需要經(jīng)過不斷的調(diào)整才能得到較為滿意的控制效果。依據(jù)經(jīng)驗(yàn),一般PID參數(shù)確定的步驟如下:
(1)確定比例系數(shù)Kp
確定比例系數(shù)Kp時,首先去掉PID的積分項(xiàng)和微分項(xiàng),可以令Ti=0、Td=0,使之成為純比例調(diào)節(jié)。輸入設(shè)定為系統(tǒng)允許輸出最大值的60%~70%,比例系數(shù)Kp由0開始逐漸增大,直至系統(tǒng)出現(xiàn)振蕩;再反過來,從此時的比例系數(shù)Kp逐漸減小,直至系統(tǒng)振蕩消失。記錄此時的比例系數(shù)Kp,設(shè)定PID的比例系數(shù)Kp為當(dāng)前值的60%~70%。
(2)確定積分時間常數(shù)Ti
比例系數(shù)Kp確定之后,設(shè)定一個較大的積分時間常數(shù)Ti,然后逐漸減小Ti,直至系統(tǒng)出現(xiàn)振蕩,然后再反過來,逐漸增大Ti,直至系統(tǒng)振蕩消失。記錄此時的Ti,設(shè)定PID的積分時間常數(shù)Ti為當(dāng)前值的150%~180%。
(3) 確定微分時間常數(shù)Td
微分時間常數(shù)Td一般不用設(shè)定,為0即可,此時PID調(diào)節(jié)轉(zhuǎn)換為PI調(diào)節(jié)。如果需要設(shè)定,則與確定Kp的方法相同,取不振蕩時其值的30%。
(4) 系統(tǒng)空載、帶載聯(lián)調(diào)
對PID參數(shù)進(jìn)行微調(diào),直到滿足性能要求。
PID代碼如下:
#include
typedef struct PID {?
double SetPoint; // 設(shè)定目標(biāo)Desired value?
double Proportion; // 比例常數(shù)Proportional Const?
double Integral; // 積分常數(shù)Integral Const?
double Derivative; // 微分常數(shù)Derivative Const?
double LastError; // Error[-1]?
double PrevError; // Error[-2]?
double SumError; // Sums of Errors?
} PID;?
/*====================================================================================================?
PID計算函數(shù)
=====================================================================================================*/?
double PIDCalc( PID *pp, double NextPoint )?
{?
? ? double dError,?Error;?
? ? Error = pp->SetPoint - NextPoint; // 偏差?
? ? pp->SumError += Error; // 積分?
? ? dError = pp->LastError - pp->PrevError; // 當(dāng)前微分?
? ? pp->PrevError = pp->LastError;?
? ? pp->LastError = Error;?
? ? return (pp->Proportion * Error // 比例項(xiàng)?
? ? + pp->Integral * pp->SumError // 積分項(xiàng)?
? ? + pp->Derivative * dError // 微分項(xiàng)?);?
}?
/*====================================================================================================?
PID結(jié)構(gòu)體變量初始化函數(shù)
=====================================================================================================*/?
void PIDInit (PID *pp)?
{?
memset ( pp,0,sizeof(PID));?
}?
/*====================================================================================================?
讀取輸入變量函數(shù)(在此設(shè)定為固定值100)
======================================================================================================*/?
double sensor (void)??
{?
return 100.0;?
}?
/*====================================================================================================
輸出變量控制函數(shù)?
======================================================================================================*/?
void actuator(double rDelta)??
{
}?
//主函數(shù)?
void main(void)?
{?
? ? PID sPID; // PID Control Structure?
? ? double rOut; // PID Response (Output)?
? ? double rIn; // PID Feedback (Input)?
? ? PIDInit ( &sPID ); // Initialize Structure?
? ? sPID.Proportion = 0.5; // Set PID Coefficients?
? ? sPID.Integral = 0.5;?
? ? sPID.Derivative = 0.0;?
? ? sPID.SetPoint = 100.0; // Set PID Setpoint?
? ? for (;;)?
? ? { // Mock Up of PID Processing?
? ?? ???rIn = sensor (); // Read Input?
? ?? ???rOut = PIDCalc ( &sPID,rIn ); // Perform PID Interation?
? ?? ???actuator ( rOut ); // Effect Needed Changes?
? ? }?
}
評論