/** * @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 "memory.h" /* ----------------------------ä¸é¢æ¯pidä¼åç¯èçå®ç°---------------------------- */ // 梯形积å static void f_Trapezoid_Intergral(PIDInstance *pid) { // è®¡ç®æ¢¯å½¢çé¢ç§¯,(ä¸åº+ä¸åº)*é«/2 pid->ITerm = pid->Ki * ((pid->Err + pid->Last_Err) / 2) * pid->dt; } // åé积å(è¯¯å·®å°æ¶ç§¯åä½ç¨æ´å¼º) static void f_Changing_Integration_Rate(PIDInstance *pid) { if (pid->Err * pid->Iout > 0) { // 积åå累积è¶å¿ 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(PIDInstance *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) // 积åå´è¿å¨ç´¯ç§¯ { 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(PIDInstance *pid) { pid->Dout = pid->Kd * (pid->Last_Measure - pid->Measure) / pid->dt; } // 微忻¤æ³¢(éé微忶,滤é¤é«é¢åªå£°) static void f_Derivative_Filter(PIDInstance *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(PIDInstance *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(PIDInstance *pid) { if (pid->Output > pid->MaxOut) { pid->Output = pid->MaxOut; } if (pid->Output < -(pid->MaxOut)) { pid->Output = -(pid->MaxOut); } } // çµæºå µè½¬æ£æµ static void f_PID_ErrorHandle(PIDInstance *pid) { /*Motor Blocked Handle*/ if (fabsf(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 = PID_MOTOR_BLOCKED_ERROR; } } /* ---------------------------ä¸é¢æ¯PIDçå¤é¨ç®æ³æ¥å£--------------------------- */ /** * @brief åå§åPID,è®¾ç½®åæ°åå¯ç¨çä¼åç¯è,å°å ¶ä»æ°æ®ç½®é¶ * * @param pid PIDå®ä¾ * @param config PIDåå§å设置 */ void PIDInit(PIDInstance *pid, PID_Init_Config_s *config) { // configçæ°æ®åpidçé¨åæ°æ®æ¯è¿ç»ä¸ç¸åçç,æä»¥å¯ä»¥ç´æ¥ç¨memcpy // @todo: ä¸å»ºè®®è¿æ ·å,坿©å±æ§å·®,ä¸ç¥éçå¼åè å¯è½ä¼è¯¯ä»¥ä¸ºpidåconfigæ¯åä¸ä¸ªç»æä½ // åç»ä¿®æ¹ä¸ºé个èµå¼ memset(pid, 0, sizeof(PIDInstance)); // utilize the quality of struct that its memeory is continuous memcpy(pid, config, sizeof(PID_Init_Config_s)); // set rest of memory to 0 DWT_GetDeltaT(&pid->DWT_CNT); } /** * @brief PIDè®¡ç® * @param[in] PIDç»æä½ * @param[in] æµéå¼ * @param[in] ææå¼ * @retval è¿å空 */ float PIDCalculate(PIDInstance *pid, float measure, float ref) { // å µè½¬æ£æµ if (pid->Improve & PID_ErrorHandle) f_PID_ErrorHandle(pid); pid->dt = DWT_GetDeltaT(&pid->DWT_CNT); // è·å两次pid计ç®çæ¶é´é´é,ç¨äºç§¯ååå¾®å // ä¿å䏿¬¡çæµéå¼å误差,计ç®å½åerror pid->Measure = measure; pid->Ref = ref; pid->Err = pid->Ref - pid->Measure; // 妿卿»åºå¤,å计ç®PID if (abs(pid->Err) > pid->DeadBand) { // åºæ¬çpid计ç®,使ç¨ä½ç½®å¼ 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 & PID_Trapezoid_Intergral) f_Trapezoid_Intergral(pid); // åé积å if (pid->Improve & PID_ChangingIntegrationRate) f_Changing_Integration_Rate(pid); // å¾®åå è¡ if (pid->Improve & PID_Derivative_On_Measurement) f_Derivative_On_Measurement(pid); // 微忻¤æ³¢å¨ if (pid->Improve & PID_DerivativeFilter) f_Derivative_Filter(pid); // 积åéå¹ if (pid->Improve & PID_Integral_Limit) f_Integral_Limit(pid); pid->Iout += pid->ITerm; // ç´¯å 积å pid->Output = pid->Pout + pid->Iout + pid->Dout; // 计ç®è¾åº // è¾åºæ»¤æ³¢ if (pid->Improve & PID_OutputFilter) f_Output_Filter(pid); // è¾åºéå¹ f_Output_Limit(pid); } else // è¿å ¥æ»åº, 忏 空积ååè¾åº { pid->Output = 0; pid->ITerm = 0; } // ä¿åå½åæ°æ®,ç¨äºä¸æ¬¡è®¡ç® 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; }