/************************************************************* 函數: int16_t Idle_PID_Ctrl(uint16_t setpoint,uint16_t point) 功能: 增量式PID算法,得到增量值 參數: setpoint: 設定值 point: 當前值 返回: uk: PID算法的控制增量 描述: 返回增量值,即在上一次的控制量的基礎上需要增加(負值意味減少)控制量 **************************************************************/ int16_t Idle_PID_Calc(uint16_t setpoint,uint16_t point) { float Kp = 0.0; //Proportion float Ki = 0.0; //Integral float Kd = 0.0; //Differential static int32_t ek_2 = 0; //上上次誤差 static int32_t ek_1 = 0; //上一次誤差 static int32_t ek = 0; //當前誤差 int16_t uk; //控制量增量 Kp = inpram.RPMOXLimit/100.0; Ki = inpram.TPSOXLimit/1000.0; //這里上位機將edit里的數據*10,所以Ki的實際結果為edit/100 Kd = inpram.MAPOXLimit/1000.0; //這里上位機將edit里的數據*10,所以Kd的實際結果為edit/100 ek = setpoint - point; //得到當前誤差 uk = (int16_t)(Kp*(ek - ek_1)+ Ki*ek + Kd*(ek - 2*ek_1 + ek_2));
ek_2 = ek_1; ek_1 = ek;
return (uk); }
上面是增量式PID算法的當前增量值代碼段,完整並且實用的程序,還要與歷史增量值相加,並要對總歷史總量值進行限幅,為何要限幅呢?因為控制的總量要送到執行機構,而執行機構往往是有機械限位的,
比如此例子中,實際是控制節氣門的開關角度,而節氣門是由舵機控制的,舵機不能變化的太大,否則轉速不穩定,造成發動機熄火,還會損壞舵機,減少其壽命。
看下一段代碼:
if(cnt_xS++ >= INTERVAL_50MS) //PID控制周期,在1ms定時中斷內 { cnt_xS = 0; rpm_setpoint = (inpram.RevLimRpm2 - inpram.Idle_rpm)*outpc.tps; //飛控油門對應的轉速增值 rpm_setpoint = rpm_setpoint/1000 + inpram.Idle_rpm; //當前油門對應的目標轉速 Idle.PID_increment = Idle_PID_Calc(rpm_setpoint,outpc.rpm); //得到PID控制增量 Idle.PID_value = Idle.PID_value + Idle.PID_increment; //得到PID控制總量,實際賦值給outpc.tps //PID控制總量(即總歷史值)加入限幅算法,控制在10%,防止單個控制周期內節氣門波動過大,造成轉速不穩 if(Idle.PID_value > 100) { Idle.PID_value = 100; }
else if(Idle.PID_value < -100) { Idle.PID_value = -100; } tps_temp = outpc.tps + Idle.PID_value;
//對舵機進行機械限幅 if(tps_temp > 1000) { Syspara.tps = 1000; } else if(tps_temp < 0) { Syspara.tps = 0; } else { Syspara.tps = tps_temp; }
}
根據自己的需要加入合適的限幅算法,也可以只保留機械限幅,這里在每次總增量控制處加入10%的限幅,是防止PID增量波動過大造成舵機不穩,進而影響轉速。