Simple PID Controller with Integral Windup Supports creating a diagnostics message to send to a GUI
Diff: pidContoller.cpp
- Revision:
- 1:15c12a119814
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidContoller.cpp Mon Sep 04 15:50:32 2017 +0000 @@ -0,0 +1,77 @@ +#include "mbed.h" +#include "pidContoller.h" + +pidContoller::pidContoller(){ + elapsedTime =0; + mode = MANUAL; + } + +int pidContoller::Calculate(float SP, float PV) + { + float CV; //(mm/s) Control Variable + float IntegralAction; // Integral Contribution to Output + float DerivativeAction; // Derivative Contribution to Output + + if (mode == MANUAL) + { + CV = SP; + accumError = 0; + lastError = 0; + } + else + { + //Calc error + error = SP -PV; + IntegralAction = K_i*(accumError + error); + DerivativeAction = K_d*(error - lastError); + + //-- PID Calculation + CV = bias + K_p*error, + IntegralAction - DerivativeAction; + + //-- Clamp Integral if Output is Saturated + if ((CV > maxLimit) || (CV < minLimit)) + { + accumError = accumError; + } + else + { + accumError += error; + } + + //-- Set Error for Next Scan + lastError = error; + } + + + //Check to See Output is Within Limits + if (CV > maxLimit){CV= maxLimit;} + if (CV < minLimit){CV= minLimit;} + + + if (collectDiagnostics){BuildDiagMessage(SP,PV, CV*scalar, K_p*error, IntegralAction, DerivativeAction);} + + //Convert from mm/s to 0-100% + return (int)(CV*scalar)*10; + } + +void pidContoller::UpdateSettings(float Bias, float PropGain, float IntGain, float DiffGain, float OutputMin, float OutputMax, float OutputScale){ + bias = Bias; + K_p = PropGain; + K_i = IntGain; + K_d = DiffGain; + minLimit = OutputMin; + maxLimit = OutputMax; + scalar = OutputScale; + } + +void pidContoller::StartDiag(void){ + elapsedTime =0; + } + +void pidContoller::BuildDiagMessage(float SP, float PV, float PWM, float PropAction, float IntAction, float DifAction){ + sprintf(diagMsg, "P %d %0.4f, %0.4f %0.1f %0.4f %0.4f %0.4f\n", + elapsedTime, SP, PV, PWM, PropAction, IntAction, DifAction); + elapsedTime += RATE; + if (elapsedTime > 32000){EndDiag();} + } +