文章目錄
- 為什么要多環
- 程序
- 主函數
- 內環
- 外環
- 雙環PID調參
- 內環
- Kp調法
- Ki調法
- 外環
- Kp
- 以一定速度到達指定位置
- 封裝
為什么要多環
單環只能單一控制速度或者位置,如果想要同時控制多個量如速度,位置,角度,就需要多個PID
- 速度環一般PI控制,位置環一般PD
程序
主函數
/*定義內環變量*/
float InnerTarget, InnerActual, InnerOut;
float InnerKp = 值, InnerKi = 值, InnerKd = 值;
float InnerError0, InnerError1, InnerErrorInt;/*定義外環變量*/
float OuterTarget, OuterActual, OuterOut;
float OuterKp = 值, OuterKi = 值, OuterKd = 值;
float OuterError0, OuterError1, OuterErrorInt;int main(void)
{Timer_Init();while (1){/*用戶在此處根據需求寫入外環PID控制器的目標值*/OuterTarget = 用戶指定的一個值;}
}
內環
void TIM2_IRQHandler(void)
{static uint64_t Count1, Count2;if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){Count1 ++;if (Count1 >= 內環調控時間){Count1 = 0;/*內環每隔時間T1,程序執行到這里一次*//*執行內環PID控制*/InnerActual = 讀取內環實際值();InnerError1 = InnerError0;InnerError0 = InnerTarget - InnerActual;InnerErrorInt += InnerError0;InnerOut = InnerKp * InnerError0+ InnerKi * InnerErrorInt+ InnerKd * (InnerError0 - InnerError1);if (InnerOut > 上限) {InnerOut = 上限;}if (InnerOut < 下限) {InnerOut = 下限;}/*內環PID的輸出值作用于執行器*/輸出至被控對象(InnerOut);}}
}
外環
外環調控周期要大于等于內環,具體周期給多少,要不斷嘗試
Count2 ++;
if (Count2 >= 外環調控時間)
{Count2 = 0;/*外環每隔時間T2,程序執行到這里一次*//*執行外環PID控制*/OuterActual = 讀取外環實際值();OuterError1 = OuterError0;OuterError0 = OuterTarget - OuterActual;OuterErrorInt += OuterError0;OuterOut = OuterKp * OuterError0+ OuterKi * OuterErrorInt+ OuterKd * (OuterError0 - OuterError1);if (OuterOut > 上限) {OuterOut = 上限;}if (OuterOut < 下限) {OuterOut = 下限;}/*外環PID的輸出值作用于內環PID的目標值*/InnerTarget = OuterOut;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
雙環PID調參
- 參數越大,響應越快,但會出現抖動;參數越小,響應越慢,但更加平滑,需要自己取舍
- 同時調節內環和外環是不可行的
- 因為內環可以獨立工作,我們要先調內環(要把外環給注釋調),內環調好了,在內環的基礎上調節外環
內環
Kp調法
- 先讓出現抖動,再減小使抖動消失
Ki調法
- 與Kp類似
- 先讓出現抖動,再減小使抖動消失
外環
Kp
外環Kp不用怕超調,直接調到抖動再減小,用Kd減少超調
以一定速度到達指定位置
不能使innertarget=目標速度
正確做法是更改限幅,速度要小限幅就小
封裝
typedef struct {float Target;float Actual;float Out;float Kp;float Ki;float Kd;float Error0;float Error1;float ErrorInt;float OutMax;float OutMin;
} PID_t;
初始化賦值方法
PID_t Inner = {.Kp = 0.3,.Ki = 0.3,.Kd = 0,.OutMax = 100,.OutMin = -100};
```c
void PID_Update(PID_t *p)
{p->Error1 = p->Error0;p->Error0 = p->Target - p->Actual;if (p->Ki != 0){p->ErrorInt += p->Error0;}else{p->ErrorInt = 0;}p->Out = p->Kp * p->Error0+ p->Ki * p->ErrorInt+ p->Kd * (p->Error0 - p->Error1);if (p->Out > p->OutMax) {p->Out = p->OutMax;}if (p->Out < p->OutMin) {p->Out = p->OutMin;}
}