/** * @file controller.c * @author wanghongxi * @author modified by neozng * @brief PID控制器定义 * @version beta * @date 2022-11-01 * * @copyrightCopyright (c) 2022 HNU YueLu EC all rights reserved */ #include "controller.h" #include // 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_PID_ErrorHandle(PID_t *pid); // 堵转保护 /** * @brief 初始化PID,设置参数和启用的优化环节,将其他数据置零 * * @param pid PID实例 * @param config PID初始化设置 */ void PID_Init(PID_t *pid, PID_Init_config_s *config) { // utilize the quality of struct that its memeory is continuous memcpy(pid, config, sizeof(PID_Init_config_s)); // set rest of memory to 0 memset(&pid->Measure, 0, sizeof(PID_t) - sizeof(PID_Init_config_s)); } /** * @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; } }