前兩篇文章:
http://www.zgszdi.cn/d/1796839.html
http://www.zgszdi.cn/d/1798370.html
分別介紹了PID速度控制和PID位置控制,分別用來控制電機以期望的速度持續轉動以及以期望的位置(圈數)轉動,這里的期望值都只有一個,但是,如果想要以期望的速度轉動到期望的位置(啟動與停止的加減速過程不考慮),該怎么控制呢?那就要將兩者結合起來了,即PID的串級控制來控制電機。
串級PID結構圖
PID串級控制的典型結構為位置環+速度環+電流環,如下圖。
PID串級控制中,最外環是輸入是整個控制系統的期望值,外環PID的輸出值是內環PID的期望值。
能夠使用三環控制的前提是要硬件支持,比如位置環和速度環需要實時的電機轉動位置和轉動速度作為反饋,這就需要電機需要配有編碼器用于測速與測量轉動的位置;電流環需要有電流采樣電路來實時獲取電機的電流作為反饋。
如果沒有電流采樣電路,可以將電流環去掉,只使用位置環+速度環,系統的期望仍是轉動的位置,內環可以調節轉動的速度。
另外,如果只是想控制電機轉速實現電機調速,可以使用速度環+電流環,系統的期望仍是轉動的位置,內環可以調節電機的電流,增強系統轉動調節的抗干擾能力。
位置環+速度環實踐
由于我的電機沒有電流測量電路,所以,本文以位置環+速度環來學習PID串級控制。就是按照下面這個圖:
PID參數定義
由于是串級PID控制,每一級的PID都要有自己的參數,本次實驗使用位置PID+速度PID,參數定義如下:
/*定義位置PID與速度PID結構體型的全局變量*/
PID pid_location;
PID pid_speed;
/**
* @brief PID參數初始化
* @note 無
* @retval 無
*/
void PID_param_init()
{
/* 位置相關初始化參數 */
pid_location.target_val = TOTAL_RESOLUTION*10;
pid_location.output_val = 0.0;
pid_location.err = 0.0;
pid_location.err_last = 0.0;
pid_location.integral = 0.0;
pid_location.Kp = 0.05;
pid_location.Ki = 0;
pid_location.Kd = 0;
/* 速度相關初始化參數 */
pid_speed.target_val=10.0;
pid_speed.output_val=0.0;
pid_speed.err=0.0;
pid_speed.err_last=0.0;
pid_speed.integral=0.0;
pid_speed.Kp = 80.0;
pid_speed.Ki = 2.0;
pid_speed.Kd = 100.0;
}
位置PID的實現
這里有兩點需要注意:
閉環死區的設定
閉環死區是指執行機構的最小控制量,無法再通過調節來滿足控制精度,如果仍然持續調節,系統則會在目標值前后頻繁動作,不能穩定下來。
比如某個系統的控制精度是1,但目標值需要是1.5,則無論怎么調節,最終的結果只能控制在 1或 2,始終無法達到預設值。這 1.5L小數點后的范圍,就是閉環死區,系統是無法控制的,誤差會一直存在,容易發生震蕩現象。
對應精度要求不高的系統,可以設定閉環死區,比如將允許的誤差范圍設為0.5,則最終結果在 1或 2都認為是沒有誤差,這時將目標值 與實際值之差強制設為 0,認為沒有誤差,即限定了閉環死區。
積分分離的設定
通過積分分離的方式來實現抗積分飽和,積分飽和是指執行機構達到極限輸出能力了,仍無法到達目標值,在很長一段時間內無法消除靜差造成的。
例如,PWM輸出到了100%,仍達不到期望位置,此時若一直進行誤差累加,在一段時間后, PID 的積分項累計了很大的數值,如果這時候到達了目標值或者重新設定了目標值,由于積分由于累計的誤差很大,系統并不能立即調整到目標值,可能造成超調或失調的現象。
解決積分飽和的一種方法是使用積分分離,該方法是在累計誤差小于某個閾值才使用積分項,累計誤差過大則不再繼續累計誤差,相當于只使用了PD控制器。
控制流程圖
帶有閉環死區與積分分離的PID控制流程如下圖:
完整的位置PID代碼如下:
/**
* @brief 位置PID算法實現
* @param actual_val:實際值
* @note 無
* @retval 通過PID計算后的輸出
*/
#define LOC_DEAD_ZONE 60 /*位置環死區*/
#define LOC_INTEGRAL_START_ERR 200 /*積分分離時對應的誤差范圍*/
#define LOC_INTEGRAL_MAX_VAL 800 /*積分范圍限定,防止積分飽和*/
float location_pid_realize(PID *pid, float actual_val)
{
/*計算目標值與實際值的誤差*/
pid->err = pid->target_val - actual_val;
/* 設定閉環死區 */
if((pid->err >= -LOC_DEAD_ZONE) && (pid->err <= LOC_DEAD_ZONE))
{
pid->err = 0;
pid->integral = 0;
pid->err_last = 0;
}
/*積分項,積分分離,偏差較大時去掉積分作用*/
if(pid->err > -LOC_INTEGRAL_START_ERR && pid->err < LOC_INTEGRAL_START_ERR)
{
pid->integral += pid->err;
/*積分范圍限定,防止積分飽和*/
if(pid->integral > LOC_INTEGRAL_MAX_VAL)
{
pid->integral = LOC_INTEGRAL_MAX_VAL;
}
else if(pid->integral < -LOC_INTEGRAL_MAX_VAL)
{
pid->integral = -LOC_INTEGRAL_MAX_VAL;
}
}
/*PID算法實現*/
pid->output_val = pid->Kp * pid->err +
pid->Ki * pid->integral +
pid->Kd * (pid->err - pid->err_last);
/*誤差傳遞*/
pid->err_last = pid->err;
/*返回當前實際值*/
return pid->output_val;
}
串級控制代碼
//周期定時器的回調函數
void AutoReloadCallback()
{
static uint32_t location_timer = 0; // 位置環周期
static __IO int encoderNow = 0; /*當前時刻總計數值*/
static __IO int encoderLast = 0; /*上一時刻總計數值*/
int encoderDelta = 0; /*當前時刻與上一時刻編碼器的變化量*/
float actual_speed = 0; /*實際測得速度*/
int actual_speed_int = 0;
int res_pwm = 0;/*PID計算得到的PWM值*/
static int i=0;
/*【1】讀取編碼器的值*/
encoderNow = read_encoder() + EncoderOverflowCnt*ENCODER_TIM_PERIOD;/*獲取當前的累計值*/
encoderDelta = encoderNow - encoderLast; /*得到變化值*/
encoderLast = encoderNow;/*更新上次的累計值*/
/*【2】位置PID運算,得到PWM控制值*/
if ((location_timer++ % 2) == 0)
{
float control_val = 0; /*當前控制值*/
/*位置PID計算*/
control_val = location_pid_realize(&pid_location, encoderNow);
/*目標速度值限制*/
speed_val_protect(&control_val);
/*設定速度PID的目標值*/
set_pid_target(&pid_speed, control_val);
}
/* 轉速(1秒鐘轉多少圈)=單位時間內的計數值/總分辨率*時間系數, 再乘60變為1分鐘轉多少圈 */
actual_speed = (float)encoderDelta / TOTAL_RESOLUTION * 10 * 60;
/*【3】速度PID運算,得到PWM控制值*/
actual_speed_int = actual_speed;
res_pwm = pwm_val_protect((int)speed_pid_realize(&pid_speed, actual_speed));
/*【4】PWM控制電機*/
set_motor_rotate(res_pwm);
/*【5】數據上傳到上位機顯示*/
set_computer_value(SEND_FACT_CMD, CURVES_CH1, &encoderNow, 1); /*給通道1發送實際的電機【位置】值*/
}
PID的計算是通過定時器調用,每10ms一次,從代碼中可以看到,內環(速度PID)控制的周期要比外環(位置PID)的周期短,位置PID是每兩次循環計算一次,因為內環控制著最終的輸出,這個輸出對應的就是實際場景中的控制量 (本實驗最終控制的是位置),位置是無法突變,是需要時間積累的,所以內環輸出盡可能快些。
視頻演示
視頻中,測試以不同的目標速度到達目標位置,視頻后半段測試引入干擾情況下的控制效果:
https://www.bilibili.com/video/BV1QK4y1g7yg?spm_id_from=333.999.0.0
開源代碼
-
單片機
+關注
關注
6043文章
44621瀏覽量
638626 -
電機控制
+關注
關注
3540文章
1897瀏覽量
269267 -
STM32
+關注
關注
2272文章
10924瀏覽量
357608 -
PID
+關注
關注
35文章
1473瀏覽量
85826
發布評論請先 登錄
相關推薦
評論