通過PID對電機(jī)轉(zhuǎn)速進(jìn)行閉環(huán)控制婿脸。
1.PID控制的原理
在工程實際中莫矗,PID控制是應(yīng)用最為廣泛控制方式飒硅。PID為比例、積分作谚、微分的縮寫三娩。當(dāng)被控制的系統(tǒng)的結(jié)構(gòu)和參數(shù)不能完全掌握,或得不到精確的數(shù)學(xué)模型時妹懒,控制理論的其它技術(shù)難以采用時雀监,系統(tǒng)控制器的結(jié)構(gòu)和參數(shù)必須依靠經(jīng)驗和現(xiàn)場調(diào)試來確定,這時應(yīng)用PID控制技術(shù)最為方便眨唬。即當(dāng)我們不完全了解一個系統(tǒng)和被控對象﹐或不能通過有效的測量手段來獲得系統(tǒng)參數(shù)時会前,最適合用PID控制技術(shù)好乐。PID控制,實際中也有PI和PD控制回官。PID控制器就是根據(jù)系統(tǒng)的誤差,利用比例搂橙、積分歉提、微分計算出控制量來對系統(tǒng)進(jìn)行控制。
比例(P)控制
比例控制是一種最簡單的控制方式区转。其控制器的輸出與輸入誤差信號成比例關(guān)系苔巨。當(dāng)僅有比例控制時系統(tǒng)輸出存在穩(wěn)態(tài)誤差(Steady-state error)。
積分(I)控制
在積分控制中废离,控制器的輸出與輸入誤差信號的積分成正比關(guān)系侄泽。對一個自動控制系統(tǒng),如果在進(jìn)入穩(wěn)態(tài)后存在穩(wěn)態(tài)誤差蜻韭,則稱這個控制系統(tǒng)是有穩(wěn)態(tài)誤差的或簡稱有差系統(tǒng)(System with Steady-state Error)悼尾。為了消除穩(wěn)態(tài)誤差,在控制器中必須引入“積分項”肖方。積分項對誤差取決于時間的積分闺魏,隨著時間的增加,積分項會增大俯画。這樣析桥,即便誤差很小,積分項也會隨著時間的增加而加大艰垂,它推動控制器的輸出增大使穩(wěn)態(tài)誤差進(jìn)一步減小泡仗,直到等于零。因此猜憎,比例+積分(PI)控制器娩怎,可以使系統(tǒng)在進(jìn)入穩(wěn)態(tài)后無穩(wěn)態(tài)誤差。
微分(D)控制
在微分控制中胰柑,控制器的輸出與輸入誤差信號的微分(即誤差的變化率)成正比關(guān)系峦树。 自動控制系統(tǒng)在克服誤差的調(diào)節(jié)過程中可能會出現(xiàn)振蕩甚至失穩(wěn)。其原因是由于存在有較大慣性組件(環(huán)節(jié))或有滯后(delay)組件旦事,具有抑制誤差的作用魁巩,其變化總是落后于誤差的變化。解決的辦法是使抑制誤差的作用的變化“超前”姐浮,即在誤差接近零時谷遂,抑制誤差的作用就應(yīng)該是零。這就是說卖鲤,在控制器中僅引入“比例”項往往是不夠的肾扰,比例項的作用僅是放大誤差的幅值畴嘶,而目前需要增加的是“微分項”,它能預(yù)測誤差變化的趨勢集晚,這樣窗悯,具有比例+微分的控制器,就能夠提前使抑制誤差的控制作用等于零偷拔,甚至為負(fù)值蒋院,從而避免了被控量的嚴(yán)重超調(diào)。所以對有較大慣性或滯后的被控對象莲绰,比例+微分(PD)控制器能改善系統(tǒng)在調(diào)節(jié)過程中的動態(tài)特性欺旧。
2.實際模型
對于3WD全向小車,在對整體運(yùn)動進(jìn)行解算后得到各個輪子的期望轉(zhuǎn)速Vd蛤签,以這個轉(zhuǎn)速作為PID控制的輸入辞友,輸出為控制電機(jī)的PWM值,反饋則為通過編碼器反饋值計算出的實際速度V震肮。閉環(huán)系統(tǒng)如下:
在實際操作中称龙,由于是通過程序進(jìn)行PID的計算,無法達(dá)到連續(xù)的積分和微分計算戳晌,所以用離散處理茵瀑。給定PID控制頻率,周期性地進(jìn)行PID控制計算躬厌。
主要參數(shù):
pid_interval 控制周期 ms
kp 比例系數(shù)
ki 積分系數(shù)
kd 微分系數(shù)
ko 統(tǒng)一放大縮小比例
3 具體實現(xiàn)
30ms控制周期马昨,C代碼如下:
pid.h
#ifndef PIBOT_PID_H_
#define PIBOT_PID_H_
class PID{
public:
PID(float* input, float* feedback, float kp, float ki, float kd, unsigned short max_output);
short compute(float interval);
void clear();
private:
float kp, ki, kd;
unsigned short max_output;
float* input;
float* feedback;
float error;
float integra;
float derivative;
float previous_error;
};
#endif
pid.cpp
#include "pid.h"
#include "board.h"
PID::PID(float* _input, float* _feedback, float _kp, float _ki, float _kd, unsigned short _max_output)
:input(_input), feedback(_feedback), kp(_kp), ki(_ki), kd(_kd), max_output(_max_output){
clear();
}
void PID::clear(){
error = integra = derivative = previous_error =0;
}
short PID::compute(float interval){
error = *input - *feedback;
integra = integra + error*interval;
derivative = (error - previous_error) / interval;
previous_error = error;
if (ki != 0)
if (integra < -max_output/ki)
{
//printf("integra clear\r\n");
integra = -max_output/ki;
}
if (integra > max_output/ki)
{
//printf("integra clear\r\n");
integra = max_output/ki;
}
float val = error*kp + integra*ki + derivative*kd;
if (val < -max_output)
val = -max_output+1;
else if (val > max_output)
val = max_output-1;
return val;
}