實際調參
從實際的 PID 系統(tǒng)曲線來理解 PID 各個系數(shù)的調節(jié)效果。
① 先調整比例系數(shù),積分、微分系數(shù)設置為 0,此時的系統(tǒng)只有比例環(huán)節(jié)參與控制,此時系統(tǒng)的曲線出現(xiàn)大幅振蕩。
首先確定硬件上是否出現(xiàn)了故障,例如電壓不穩(wěn)定、電機堵轉等,排除了這些之后,那就說明比例系數(shù)調節(jié)的過大了,這個時候我們可以把比例系數(shù)慢慢地減小,并同時觀察曲線的變化。
② 當我們調小比例系數(shù)之后,曲線的大幅度振蕩現(xiàn)象消失,但是曲線依舊存在小幅度的超調現(xiàn)象,并且此時通過調節(jié)比例系數(shù)已經無法優(yōu)化曲線。
此時,我們可以慢慢地增大微分系數(shù),并同時觀察曲線的變化,從而找到最合適的參數(shù)。
增大微分系數(shù)之后,如果系統(tǒng)的曲線已經較為理想,則說明這個系統(tǒng)只需要比例和微分環(huán)節(jié)的控制。
③ 如果在純比例環(huán)節(jié)的控制下,系統(tǒng)的實際值始終達不到目標值,存在靜態(tài)誤差。
此時,可以逐漸增大積分系數(shù),并同時觀察曲線的變化,如果消除靜差的時間過長,則可以再適當增大積分系數(shù),但是需要注意兼顧系統(tǒng)的超調量。
經過調整之后,如果系統(tǒng)的曲線已經較為理想,則說明這個系統(tǒng)只需要比例和積分環(huán)節(jié)的控制。
④ 如果系統(tǒng)在比例和積分環(huán)節(jié)的控制下出現(xiàn)小幅度的超調現(xiàn)象,可以慢慢地增大微分系數(shù),并同時觀察曲線的變化,從而找到最合適的參數(shù)。
以上就是在實際調參中經常遇到的一些問題以及解決方法。在實際應用中,控制系統(tǒng)是多樣且復雜的,這一些方法只能作為參考,并不是通用的,因此在 PID 調參過程中,要注意經驗的積累。
參考Code
PID初始化代碼
定義一個新的PID參數(shù)時,就是建立一個新的結構體,運算和初始化時直接調用對應的成員變量就行,十分方便簡潔,具體定義的結構體如下:
typedef struct{
//PID運算模式
uint8_t mode;
//PID 三個基本參數(shù)
__IO float Kp;
__IO float Ki;
__IO float Kd;
__IO float max_out; //PID最大輸出
__IO float max_iout; //PID最大積分輸出
__IO float2 set; //PID目標值
__IO float2 fdb; //PID當前值
__IO float out; //三項疊加輸出
__IO float Pout; //比例項輸出
__IO float Iout; //積分項輸出
__IO float Dout; //微分項輸出
//微分項最近三個值 0最新 1上一次 2上上次
__IO float Dbuf[3];
//誤差項最近三個值 0最新 1上一次 2上上次
__IO float error[3];
} pid_type_def;
初始運行時調用一次,初始化各個參數(shù)
void Own_PID_init(pid_type_def *pid, uint8_t mode, const __IO float PID[3], __IO float max_out, __IO float max_iout){
if (pid == NULL || PID == NULL){
return;
}
pid- >mode = mode;
pid- >Kp = PID[0];
pid- >Ki = PID[1];
pid- >Kd = PID[2];
pid- >max_out = max_out;
pid- >max_iout = max_iout;
pid- >Dbuf[0] = pid- >Dbuf[1] = pid- >Dbuf[2] = 0.0f;
pid- >error[0] = pid- >error[1] = pid- >error[2] = pid- >Pout = pid- >Iout = pid- >Dout = pid- >out = 0.0f;
}
PID運算代碼
__IO float PID_calc(pid_type_def *pid, __IO float ref, __IO float set)
{
//判斷傳入的PID指針不為空
if (pid == NULL){
return 0.0f;
}
//存放過去兩次計算的誤差值
pid- >error[2] = pid- >error[1];
pid- >error[1] = pid- >error[0];
//設定目標值和當前值到結構體成員
pid- >set = set;
pid- >fdb = ref;
//計算最新的誤差值
pid- >error[0] = set - ref;
//判斷PID設置的模式
if (pid- >mode == PID_POSITION)
{
//位置式PID
//比例項計算輸出
pid- >Pout = pid- >Kp * pid- >error[0];
//積分項計算輸出
pid- >Iout += pid- >Ki * pid- >error[0];
//存放過去兩次計算的微分誤差值
pid- >Dbuf[2] = pid- >Dbuf[1];
pid- >Dbuf[1] = pid- >Dbuf[0];
//當前誤差的微分用本次誤差減去上一次誤差來計算
pid- >Dbuf[0] = (pid- >error[0] - pid- >error[1]);
//微分項輸出
pid- >Dout = pid- >Kd * pid- >Dbuf[0];
//對積分項進行限幅
LimitMax(pid- >Iout, pid- >max_iout);
//疊加三個輸出到總輸出
pid- >out = pid- >Pout + pid- >Iout + pid- >Dout;
//對總輸出進行限幅
LimitMax(pid- >out, pid- >max_out);
}
else if (pid- >mode == PID_DELTA)
{
//增量式PID
//以本次誤差與上次誤差的差值作為比例項的輸入帶入計算
pid- >Pout = pid- >Kp * (pid- >error[0] - pid- >error[1]);
//以本次誤差作為積分項帶入計算
pid- >Iout = pid- >Ki * pid- >error[0];
//迭代微分項的數(shù)組
pid- >Dbuf[2] = pid- >Dbuf[1];
pid- >Dbuf[1] = pid- >Dbuf[0];
//以本次誤差與上次誤差的差值減去上次誤差與上上次誤差的差值作為微分項的輸入帶入計算
pid- >Dbuf[0] = (pid- >error[0] - 2.0f * pid- >error[1] + pid- >error[2]);
pid- >Dout = pid- >Kd * pid- >Dbuf[0];
//疊加三個項的輸出作為總輸出
pid- >out += pid- >Pout + pid- >Iout + pid- >Dout;
//對總輸出做一個先限幅
LimitMax(pid- >out, pid- >max_out);
}
return pid- >out;
}
#define LimitMax(input, max)
{
if (input > max)
{
input = max;
}
else if (input < -max)
{
input = -max;
}
}
PID數(shù)據清空代碼
有時候需要清除中間變量,例如目標值和中間變量清零。
void PID_clear(pid_type_def *pid)
{
if (pid == NULL)
{
return;
}
//當前誤差清零
pid- >error[0] = pid- >error[1] = pid- >error[2] = 0.0f;
//微分項清零
pid- >Dbuf[0] = pid- >Dbuf[1] = pid- >Dbuf[2] = 0.0f;
//輸出清零
pid- >out = pid- >Pout = pid- >Iout = pid- >Dout = 0.0f;
//目標值和當前值清零
pid- >fdb = pid- >set = 0.0f;
}
-
控制系統(tǒng)
+關注
關注
41文章
6419瀏覽量
110098 -
硬件
+關注
關注
11文章
3113瀏覽量
65851 -
PID
+關注
關注
35文章
1466瀏覽量
84840
發(fā)布評論請先 登錄
相關推薦
評論