#include "controller.h" #include /******************************* PID CONTROL *********************************/ // PID优化环节函数声明 static void f_Trapezoid_Intergral(PID_t *pid); static void f_Integral_Limit(PID_t *pid); static void f_Derivative_On_Measurement(PID_t *pid); static void f_Changing_Integration_Rate(PID_t *pid); static void f_Output_Filter(PID_t *pid); static void f_Derivative_Filter(PID_t *pid); static void f_Output_Limit(PID_t *pid); static void f_Proportion_Limit(PID_t *pid); static void f_PID_ErrorHandle(PID_t *pid); /** * @brief * * @param pid * @param config */ void PID_Init(PID_t* pid,PID_Init_config_s *config) { memcpy(pid, config, sizeof(PID_Init_config_s)); memset(&pid->Measure,0,sizeof(PID_t)-sizeof(PID_Init_config_s)); // // DWT定时器计数变量清零 // // reset DWT Timer count counter // pid->DWT_CNT = 0; // // 设置PID异常处理 目前仅包含电机堵转保护 // pid->ERRORHandler.ERRORCount = 0; // pid->ERRORHandler.ERRORType = PID_ERROR_NONE; } /** * @brief PID计算 * @param[in] PID结构体 * @param[in] 测量值 * @param[in] 期望值 * @retval 返回空 */ float PID_Calculate(PID_t *pid, float measure, float ref) { if (pid->Improve & ErrorHandle) f_PID_ErrorHandle(pid); pid->dt = DWT_GetDeltaT((void *)&pid->DWT_CNT); pid->Measure = measure; pid->Ref = ref; pid->Err = pid->Ref - pid->Measure; if (abs(pid->Err) > pid->DeadBand) { pid->Pout = pid->Kp * pid->Err; pid->ITerm = pid->Ki * pid->Err * pid->dt; pid->Dout = pid->Kd * (pid->Err - pid->Last_Err) / pid->dt; // 梯形积分 if (pid->Improve & Trapezoid_Intergral) f_Trapezoid_Intergral(pid); // 变速积分 if (pid->Improve & ChangingIntegrationRate) f_Changing_Integration_Rate(pid); // 微分先行 if (pid->Improve & Derivative_On_Measurement) f_Derivative_On_Measurement(pid); // 微分滤波器 if (pid->Improve & DerivativeFilter) f_Derivative_Filter(pid); // 积分限幅 if (pid->Improve & Integral_Limit) f_Integral_Limit(pid); pid->Iout += pid->ITerm; pid->Output = pid->Pout + pid->Iout + pid->Dout; // 输出滤波 if (pid->Improve & OutputFilter) f_Output_Filter(pid); // 输出限幅 f_Output_Limit(pid); } pid->Last_Measure = pid->Measure; pid->Last_Output = pid->Output; pid->Last_Dout = pid->Dout; pid->Last_Err = pid->Err; pid->Last_ITerm = pid->ITerm; return pid->Output; } static void f_Trapezoid_Intergral(PID_t *pid) { pid->ITerm = pid->Ki * ((pid->Err + pid->Last_Err) / 2) * pid->dt; } static void f_Changing_Integration_Rate(PID_t *pid) { if (pid->Err * pid->Iout > 0) { // 积分呈累积趋势 // Integral still increasing if (abs(pid->Err) <= pid->CoefB) return; // Full integral if (abs(pid->Err) <= (pid->CoefA + pid->CoefB)) pid->ITerm *= (pid->CoefA - abs(pid->Err) + pid->CoefB) / pid->CoefA; else pid->ITerm = 0; } } static void f_Integral_Limit(PID_t *pid) { static float temp_Output, temp_Iout; temp_Iout = pid->Iout + pid->ITerm; temp_Output = pid->Pout + pid->Iout + pid->Dout; if (abs(temp_Output) > pid->MaxOut) { if (pid->Err * pid->Iout > 0) { // 积分呈累积趋势 // Integral still increasing pid->ITerm = 0; } } if (temp_Iout > pid->IntegralLimit) { pid->ITerm = 0; pid->Iout = pid->IntegralLimit; } if (temp_Iout < -pid->IntegralLimit) { pid->ITerm = 0; pid->Iout = -pid->IntegralLimit; } } static void f_Derivative_On_Measurement(PID_t *pid) { pid->Dout = pid->Kd * (pid->Last_Measure - pid->Measure) / pid->dt; } static void f_Derivative_Filter(PID_t *pid) { pid->Dout = pid->Dout * pid->dt / (pid->Derivative_LPF_RC + pid->dt) + pid->Last_Dout * pid->Derivative_LPF_RC / (pid->Derivative_LPF_RC + pid->dt); } static void f_Output_Filter(PID_t *pid) { pid->Output = pid->Output * pid->dt / (pid->Output_LPF_RC + pid->dt) + pid->Last_Output * pid->Output_LPF_RC / (pid->Output_LPF_RC + pid->dt); } static void f_Output_Limit(PID_t *pid) { if (pid->Output > pid->MaxOut) { pid->Output = pid->MaxOut; } if (pid->Output < -(pid->MaxOut)) { pid->Output = -(pid->MaxOut); } } // PID ERRORHandle Function static void f_PID_ErrorHandle(PID_t *pid) { /*Motor Blocked Handle*/ if (pid->Output < pid->MaxOut * 0.001f || fabsf(pid->Ref) < 0.0001f) return; if ((fabsf(pid->Ref - pid->Measure) / fabsf(pid->Ref)) > 0.95f) { // Motor blocked counting pid->ERRORHandler.ERRORCount++; } else { pid->ERRORHandler.ERRORCount = 0; } if (pid->ERRORHandler.ERRORCount > 500) { // Motor blocked over 1000times pid->ERRORHandler.ERRORType = Motor_Blocked; } }