Soy teóricamente consciente de cómo funciona un controlador PID, nunca he implementado uno. Estoy implementando un método de control para conducir una válvula sobre PWM.
Detalles del caso de uso: El sistema tiene dos canales ADC, uno para entrada y otro para retroalimentación. La lectura de los canales ADC es de ejecución libre, y se toman suficientes muestras.
Implementación existente: Hay un bucle infinito, que hace solo dos trabajos: Leer valores ADC y Generar PWM. Hay una interrupción del temporizador configurada para invocar a 20 ms. Entonces, '¿ha pasado el tiempo?' en el siguiente diagrama de flujo se evaluará 'Sí' después de cada 20 ms. A continuación se muestra el diagrama de flujo de lo que estoy haciendo a partir de ahora.
Elsiguienteeselprogramaqueestoyinvestigando:
/*Someinformationonvariablesthatarebeingused:CURR_OUT_CHisFeedbackchannelCMD_INP_CHisthechannelwhereexternalinputisapplied.So,ADC_Val.fADC_Final_mAVal[CURR_OUT_CH]iswhereIamreceivingthevalueoffeedbackAnd,ADC_Val.fADC_Final_mAVal[CMD_INP_CH]iswhereIamreceivingthevalueofexternalinputthatIamtryingtoachieveMAX_ALLOWABLE_DUTY_CYCLEisamacrosetto((uint16_t)480)whichMapsto60%-Thisisarequirement.(Op-AmpoutputisinmV,IconvertitintomAbasedonresistorvalues)(Config[chUser_Config_Mode].uiMaxCMD_I)is350.(maxcurrentallowedthrough,inmA)*/#defineRESTRICT(x,low,high)(x=(x)<(low)?(low):((x)>(high)?(x=high):(x)))typedefstruct{floatfFeedback;floatfOutput;floatKp;floatKi;floatfIntegralError;floatfSetpoint;}PIControl_t;PIControl_tPI;uint16_tLoad_Dutycount;voidPICompute(PIControl_t*pPI){//IknowthatifPIisalreadyaglobal,thentakingthepointerdoesn'tmakesensehere,//but,ImayhavetoaddanotherPIforadifferentsensorhere,thatiswhyIhaveused//itthisway!//InstantaneouserrorisalwayslocalfloatfError=0.0;//TheclassicPIDerrortermfError=pPI->fSetpoint-pPI->fFeedback;//ComputetheintegraltermpPI->fIntegralError+=(pPI->Ki*fError);//RunallthetermstogethertogettheoveralloutputpPI->fOutput=(pPI->Kp*fError)+(pPI->fIntegralError);}voidUpdate_PWM_Module(void){//MightwanttogetridofthisfCount,letssee.floatfCount=0.0;//Timerhasn'tgeneratedaninterruptyet(Integrationtimehasn'telapsed)//ISRsetsthebComputevariable-FlagsareNotthebestway,butdoeswhatitshould.//And,Timerdoesn'tstartcountingifbComputeissetif(!bCompute){//Nocontrolactionneeded,return!return;}//AssignthefeedbackvaluereadforPIoutputcomputationPI.fFeedback=ADC_Val.fADC_Final_mAVal[CURR_OUT_CH];//ComputethePIControlleroutputPICompute(&PI);//FormulatethevaluetobeusedtogeneratePWMADC_Val.fADC_Final_mAVal[CURR_OUT_CH]=ADC_Val.fADC_Final_mAVal[CURR_OUT_CH]+PI.fOutput;//MapOutputtono.ofcountsfCount=(float)((ADC_Val.fADC_Final_mAVal[CURR_OUT_CH]*MAX_ALLOWABLE_DUTY_CYCLE)/(float)(Config[chUser_Config_Mode].uiMaxCMD_I));//ConvertintocompatibleDutyCounttype-uint16_tLoad_Dutycount=(uint16_t)fCount;//BoundtheoutputcountbetweenworstcaselowerandhigherpointsRESTRICT(Load_Dutycount,MIN_DUTY_CYCLE_COUNT,MAX_ALLOWABLE_DUTY_CYCLE);//GeneratePWMGenerate_PWM(Load_Dutycount);//AssignthelatestexternalinputvaluereadfromADCastheSetpointforPIcomputationPI.fSetpoint=ADC_Val.fADC_Final_mAVal[CMD_INP_CH];//Notsureaboutthis---BecauseIthinkwithanewSetpoint,theintegratederror(whichwasdevelopedbasedonpreviousSetpoints)willhavenosignificance.PI.fIntegralError=0.0;//Startintegrationalloveragain(Timerdoesn'tstartcountingifbComputeisset)bCompute=false;}intmain(void){//SomecodeforPower-ONinitializationlike,//ADC//Timer//PWM//PIvariables//Everythingelsewhichneedsone-timeinitializationbeforegoingintotheinfiniteloopwhile(1){Read_ADC();Update_PWM_Module();}}
UnavezquesegeneraelPWM,suejecucióneslibre.Elciclodetrabajosemantendráconstanteamenosquelocambie,porloquesolosemodificaperiódicamenteenfuncióndelacomputaciónPI.
Enarasdelaaclaración,cuandodigo"anular el valor del error integrado", me refiero a pPI->integralError = 0.0;
en el programa C.
Declaración de problema: El tiempo total tomado para la ejecución del bucle cuando el temporizador no ha transcurrido es de aproximadamente 2 ms. Por supuesto, el tiempo de ejecución aumenta cuando se realiza el cálculo de PI y se invoca la función de generación de PWM.
Estoy sondeando las dos señales:
- Salida de la retroalimentación en la salida del amplificador operacional que se utiliza.
- Entrada al sistema.
Mi pregunta es, ¿es correcto el flujo operacional? ¿Estoy en lo correcto al generar PWM solo después de que se realice el cálculo de PI y restablecer el valor del error integrado a 0.0 cada vez que se asigna un nuevo punto de ajuste? Cuando se prueba con una entrada escalonada de 0-4V, 0,5 Hz, en el osciloscopio veo que el sistema tarda unos 120 ms en aumentar su salida a entrada. Puedo correlacionar que los valores de P e I tendrán que ajustarse para mejorar el tiempo. Esta publicación no tiene mucho que ver con ajustar los valores de los factores P e I.
Lectura relacionada: Preguntas sobre electronics.stackexchange He leído y están estrechamente relacionadas: