最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

電機控制進(jìn)階3——PID串級控制(附全套代碼下載)

2021-06-14 22:12 作者:碼農(nóng)愛學(xué)習(xí)-B站  | 我要投稿

前兩篇文章,分別介紹了PID速度控制PID位置控制,分別用來控制電機以期望的速度持續(xù)轉(zhuǎn)動以及以期望的位置(圈數(shù))轉(zhuǎn)動,這里的期望值都只有一個,但是,如果想要以期望的速度轉(zhuǎn)動到期望的位置(啟動與停止的加減速過程不考慮),該怎么控制呢?那就要將兩者結(jié)合起來了,即PID的串級控制來控制電機。

串級PID結(jié)構(gòu)圖

PID串級控制的典型結(jié)構(gòu)為位置環(huán)+速度環(huán)+電流環(huán),如下圖。

PID串級控制中,最外環(huán)是輸入是整個控制系統(tǒng)的期望值,外環(huán)PID的輸出值是內(nèi)環(huán)PID的期望值。

能夠使用三環(huán)控制的前提是要硬件支持,比如位置環(huán)和速度環(huán)需要實時的電機轉(zhuǎn)動位置和轉(zhuǎn)動速度作為反饋,這就需要電機需要配有編碼器用于測速與測量轉(zhuǎn)動的位置;電流環(huán)需要有電流采樣電路來實時獲取電機的電流作為反饋。

如果沒有電流采樣電路,可以將電流環(huán)去掉,只使用位置環(huán)+速度環(huán),系統(tǒng)的期望仍是轉(zhuǎn)動的位置,內(nèi)環(huán)可以調(diào)節(jié)轉(zhuǎn)動的速度。

另外,如果只是想控制電機轉(zhuǎn)速實現(xiàn)電機調(diào)速,可以使用速度環(huán)+電流環(huán),系統(tǒng)的期望仍是轉(zhuǎn)動的位置,內(nèi)環(huán)可以調(diào)節(jié)電機的電流,增強系統(tǒng)轉(zhuǎn)動調(diào)節(jié)的抗干擾能力。

位置環(huán)+速度環(huán)實踐

由于我的電機沒有電流測量電路,所以,本文以位置環(huán)+速度環(huán)來學(xué)習(xí)PID串級控制。就是按照下面這個圖:

PID參數(shù)定義

由于是串級PID控制,每一級的PID都要有自己的參數(shù),本次實驗使用位置PID+速度PID,參數(shù)定義如下:

/*定義位置PID與速度PID結(jié)構(gòu)體型的全局變量*/
PID pid_location;
PID pid_speed;

/**
?* @brief ?PID參數(shù)初始化
?* @note ?無
?* @retval 無
?*/
void PID_param_init()
{
/* 位置相關(guān)初始化參數(shù) */
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;

/* 速度相關(guān)初始化參數(shù) */
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的實現(xiàn)

這里有兩點需要注意:

閉環(huán)死區(qū)的設(shè)定

閉環(huán)死區(qū)是指執(zhí)行機構(gòu)的最小控制量,無法再通過調(diào)節(jié)來滿足控制精度,如果仍然持續(xù)調(diào)節(jié),系統(tǒng)則會在目標(biāo)值前后頻繁動作,不能穩(wěn)定下來。

比如某個系統(tǒng)的控制精度是1,但目標(biāo)值需要是1.5,則無論怎么調(diào)節(jié),最終的結(jié)果只能控制在 1或 2,始終無法達(dá)到預(yù)設(shè)值。這 1.5L小數(shù)點后的范圍,就是閉環(huán)死區(qū),系統(tǒng)是無法控制的,誤差會一直存在,容易發(fā)生震蕩現(xiàn)象。

對應(yīng)精度要求不高的系統(tǒng),可以設(shè)定閉環(huán)死區(qū),比如將允許的誤差范圍設(shè)為0.5,則最終結(jié)果在 1或 2都認(rèn)為是沒有誤差,這時將目標(biāo)值 與實際值之差強制設(shè)為 0,認(rèn)為沒有誤差,即限定了閉環(huán)死區(qū)。

積分分離的設(shè)定

通過積分分離的方式來實現(xiàn)抗積分飽和,積分飽和是指執(zhí)行機構(gòu)達(dá)到極限輸出能力了,仍無法到達(dá)目標(biāo)值,在很長一段時間內(nèi)無法消除靜差造成的。

例如,PWM輸出到了100%,仍達(dá)不到期望位置,此時若一直進(jìn)行誤差累加,在一段時間后, PID 的積分項累計了很大的數(shù)值,如果這時候到達(dá)了目標(biāo)值或者重新設(shè)定了目標(biāo)值,由于積分由于累計的誤差很大,系統(tǒng)并不能立即調(diào)整到目標(biāo)值,可能造成超調(diào)或失調(diào)的現(xiàn)象。

解決積分飽和的一種方法是使用積分分離,該方法是在累計誤差小于某個閾值才使用積分項,累計誤差過大則不再繼續(xù)累計誤差,相當(dāng)于只使用了PD控制器。

控制流程圖

帶有閉環(huán)死區(qū)積分分離的PID控制流程如下圖:


完整的位置PID代碼如下:

/**
?* @brief ?位置PID算法實現(xiàn)
?* @param ?actual_val:實際值
?* @note ?無
?* @retval 通過PID計算后的輸出
?*/
#define LOC_DEAD_ZONE 60 /*位置環(huán)死區(qū)*/
#define LOC_INTEGRAL_START_ERR 200 /*積分分離時對應(yīng)的誤差范圍*/
#define LOC_INTEGRAL_MAX_VAL 800 ? /*積分范圍限定,防止積分飽和*/
float location_pid_realize(PID *pid, float actual_val)
{
/*計算目標(biāo)值與實際值的誤差*/
pid->err = pid->target_val - actual_val;

/* 設(shè)定閉環(huán)死區(qū) */
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算法實現(xiàn)*/
pid->output_val = pid->Kp * pid->err +
?? ? ? ? ? ? ? ? ?pid->Ki * pid->integral +
?? ? ? ? ? ? ? ? ?pid->Kd * (pid->err - pid->err_last);

/*誤差傳遞*/
pid->err_last = pid->err;

/*返回當(dāng)前實際值*/
return pid->output_val;
}

速度PID實現(xiàn)

速度PID的實現(xiàn)代碼與位置PID的類似:

/**
?* @brief ?速度PID算法實現(xiàn)
?* @param ?actual_val:實際值
?* @note ?無
?* @retval 通過PID計算后的輸出
?*/
#define SPE_DEAD_ZONE 5.0f /*速度環(huán)死區(qū)*/
#define SPE_INTEGRAL_START_ERR 100 /*積分分離時對應(yīng)的誤差范圍*/
#define SPE_INTEGRAL_MAX_VAL 260 ? /*積分范圍限定,防止積分飽和*/
float speed_pid_realize(PID *pid, float actual_val)
{
/*計算目標(biāo)值與實際值的誤差*/
pid->err = pid->target_val - actual_val;

/* 設(shè)定閉環(huán)死區(qū) */
if( (pid->err>-SPE_DEAD_ZONE) && (pid->err<SPE_DEAD_ZONE ) )
{
?pid->err = 0;
?pid->integral = 0;
?pid->err_last = 0;
}
? ?
/*積分項,積分分離,偏差較大時去掉積分作用*/
if(pid->err > -SPE_INTEGRAL_START_ERR && pid->err < SPE_INTEGRAL_START_ERR)
{
?pid->integral += pid->err; ?
? ? ? ?/*積分范圍限定,防止積分飽和*/
?if(pid->integral > SPE_INTEGRAL_MAX_VAL)
?{
? pid->integral = SPE_INTEGRAL_MAX_VAL;
?}
?else if(pid->integral < -SPE_INTEGRAL_MAX_VAL)
?{
? pid->integral = -SPE_INTEGRAL_MAX_VAL;
?}
}

/*PID算法實現(xiàn)*/
pid->output_val = pid->Kp * pid->err +
?? ? ? ? ? ? ? ? ?pid->Ki * pid->integral +
?? ? ? ? ? ? ? ? ?pid->Kd *(pid->err - pid->err_last);

/*誤差傳遞*/
pid->err_last = pid->err;

/*返回當(dāng)前實際值*/
return pid->output_val;
}

串級控制代碼

//周期定時器的回調(diào)函數(shù)
void AutoReloadCallback()
{
static uint32_t location_timer = 0; ? ?// 位置環(huán)周期

static __IO int encoderNow = 0; ? ?/*當(dāng)前時刻總計數(shù)值*/
? ?static __IO int encoderLast = 0; ? /*上一時刻總計數(shù)值*/
int encoderDelta = 0; /*當(dāng)前時刻與上一時刻編碼器的變化量*/
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;/*獲取當(dāng)前的累計值*/
encoderDelta = encoderNow - encoderLast; /*得到變化值*/
encoderLast = encoderNow;/*更新上次的累計值*/

/*【2】位置PID運算,得到PWM控制值*/
if ((location_timer++ % 2) == 0)
{
?float control_val = 0; ? /*當(dāng)前控制值*/
?
?/*位置PID計算*/
?control_val = location_pid_realize(&pid_location, encoderNow); ?
?
? ? ? ?/*目標(biāo)速度值限制*/
?speed_val_protect(&control_val);

?/*設(shè)定速度PID的目標(biāo)值*/
?set_pid_target(&pid_speed, control_val); ? ?
}
??
/* 轉(zhuǎn)速(1秒鐘轉(zhuǎn)多少圈)=單位時間內(nèi)的計數(shù)值/總分辨率*時間系數(shù), 再乘60變?yōu)?分鐘轉(zhuǎn)多少圈 */
? ?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】數(shù)據(jù)上傳到上位機顯示*/
set_computer_value(SEND_FACT_CMD, CURVES_CH1, &encoderNow, 1); ? /*給通道1發(fā)送實際的電機【位置】值*/
}

PID的計算是通過定時器調(diào)用,每10ms一次,從代碼中可以看到,內(nèi)環(huán)(速度PID)控制的周期要比外環(huán)(位置PID)的周期短,位置PID是每兩次循環(huán)計算一次,因為內(nèi)環(huán)控制著最終的輸出,這個輸出對應(yīng)的就是實際場景中的控制量 (本實驗最終控制的是位置),位置是無法突變,是需要時間積累的,所以內(nèi)環(huán)輸出盡可能快些。

視頻演示

視頻中,測試以不同的目標(biāo)速度到達(dá)目標(biāo)位置,視頻后半段測試引入干擾情況下的控制效果:



開源代碼

本篇以及前面幾篇電機與PID的完整程序代碼已開源分享:



文章對你有幫助,歡迎轉(zhuǎn)發(fā)、點贊、再看支持哦~



電機控制進(jìn)階3——PID串級控制(附全套代碼下載)的評論 (共 條)

分享到微博請遵守國家法律
禹州市| 鄢陵县| 沂南县| 社旗县| 大宁县| 来安县| 马公市| 郁南县| 依兰县| 巴林右旗| 民乐县| 公安县| 松阳县| 高要市| 华阴市| 湖口县| 南宫市| 政和县| 长春市| 延庆县| 阜宁县| 漳浦县| 巨鹿县| 邯郸市| 全椒县| 武乡县| 五峰| 鹤山市| 三河市| 天津市| 淅川县| 舒城县| 芜湖县| 孝感市| 花莲市| 西平县| 鄢陵县| 安丘市| 化州市| 泰兴市| 韶关市|