Simple PID Controller with Integral Windup Supports creating a diagnostics message to send to a GUI Prints to Binary

Dependents:   ApexPID

Fork of PidControllerV2 by James Batchelar

Files at this revision

API Documentation at this revision

Comitter:
batchee7
Date:
Mon May 07 05:15:19 2018 +0000
Parent:
5:1206105e20bd
Commit message:
InitialRelease

Changed in this revision

PidController.cpp Show annotated file Show diff for this revision Revisions of this file
PidController.h Show annotated file Show diff for this revision Revisions of this file
--- a/PidController.cpp	Tue Oct 31 03:46:43 2017 +0000
+++ b/PidController.cpp	Mon May 07 05:15:19 2018 +0000
@@ -1,37 +1,42 @@
 #include "mbed.h"
 #include "PidController.h"
 
-PidController::PidController(char c){
+PidController::PidController(){
     elapsedTime =0;
     mode = MANUAL;
-    diagChar = c;
     }
     
-float PidController::Calculate(float SP, float PV, float ManualMV) 
+float PidController::Calculate(float SP, float PV) 
     {
         float CV;                   //(mm/s) Control Variable
+        float ProportionalAction;
         float IntegralAction;       // Integral Contribution to Output
         float DerivativeAction;     // Derivative Contribution to Output
     
         if (mode == MANUAL)
         {   
-            CV = ManualMV;      //Write Manual Manipulated Variable
+            CV = SP;                    //Write Directly to Output
             accumError = 0;
             prevError = 0;
         }
         else 
         {   
             //Calc error
-            error = SP - PV;  
+            error = SP - PV; 
+            ProportionalAction =  K_p*error ;
             IntegralAction = K_i*(accumError + error);
-            //DerivativeAction = K_d*(PV - lastInput);
             DerivativeAction = K_d*(error - prevError);
             
             //-- PID Calculation
             if (SP)
             { 
-                CV =  bias + K_p*error + IntegralAction + DerivativeAction;
+                CV =  bias + ProportionalAction + IntegralAction + DerivativeAction;
                 if (CV>0) {CV = sqrt(CV);}
+                else if (CV<0)
+                {
+                    CV = sqrt(CV*-1.0);
+                    CV = CV*-1.0;
+                    }
             }
             else 
             {
@@ -40,23 +45,27 @@
             }
             
             //-- Only allow the Controller to integrate if the output isnt saturated
-            if ((CV < maxLimit) || (CV > minLimit))
-            {
-                accumError += error;
-                }
+            if ((CV < maxLimit) || (CV > minLimit)){accumError += error;}
 
             //-- Save Current Input for Next Loop
-            //lastInput = PV;  
             prevError = error;
-            
-            //Check to See Output is Within Limits
-            if (CV > maxLimit){CV= maxLimit;}
-            if (CV < minLimit){CV= minLimit;}
         }
+        
+        //Check to See Output is Within Limits
+        if (CV > maxLimit){CV= maxLimit;}
+        if (CV < minLimit){CV= minLimit;}
            
-        
         //-- Make message to send to GUI
-        if (collectDiagnostics){BuildDiagMessage(SP,PV, CV, K_p*error, IntegralAction, DerivativeAction);}
+        if (collectDiagnostics)//{BuildDiagMessage(SP,PV, CV, K_p*error, IntegralAction, DerivativeAction);}
+        {
+            int_to_byte(diagMsg, elapsedTime);
+            float_to_byte(diagMsg +2, &SP);
+            float_to_byte(diagMsg +6, &PV);
+            float_to_byte(diagMsg +10, &CV);
+            float_to_byte(diagMsg +14, &ProportionalAction);
+            float_to_byte(diagMsg +18, &IntegralAction);
+            float_to_byte(diagMsg +22, &DerivativeAction);
+            }
         
         return CV;
     }
@@ -89,10 +98,18 @@
     return;
     }
 
-void PidController::BuildDiagMessage(float SetPoint, float ProcessVar, float PWM, float PropAction, float IntAction, float DifAction){
-    //sprintf(diagMsg, "%c %d %0.4f %0.4f %0.1f %0.4f %0.4f %0.4f\n", diagChar, elapsedTime, SetPoint, ProcessVar, PWM, PropAction, IntAction, DifAction);
-    sprintf(diagMsg, "%c %d %0.4f %0.4f %0.1f 0.0 0.0 0.0\n", diagChar, elapsedTime, SetPoint, ProcessVar, PWM); 
-    elapsedTime += RATE;
+void PidController::GetDiagnosticsMessage(char *data){
+    memcpy(data, &diagMsg, 27 );
     return;
     }
+//-- Helper Functions
+    
+//-- Convert floating point to byte array
+void PidController::float_to_byte(char *data, float *val) {
+      memcpy(data, val, sizeof(float)); 
+}
 
+//-- Convert integer to byte array
+void PidController::int_to_byte(char *data, uint16_t val) {
+      memcpy(data, &val, sizeof val); 
+}
--- a/PidController.h	Tue Oct 31 03:46:43 2017 +0000
+++ b/PidController.h	Mon May 07 05:15:19 2018 +0000
@@ -28,22 +28,14 @@
  * 
  * 
  *     
- 
- * @code
-#include "mbed.h"
-#include "PID.h"
-
- * @endcode
  */
 
-
-
 #ifndef PidController_H
 #define PidController_H
 #include "mbed.h"
 
 //-- Constants used in system
-const int RATE = 20;       //--(ms) Time that Calculate mehtod is being called       
+const int RATE = 100;        //--(ms) Time that Calculate mehtod is being called       
 const int AUTOMATIC = 0;    //-- In automatic then PID Controls Output
 const int MANUAL = 1;       //-- In Manual then User Controls Output directly
 
@@ -53,17 +45,15 @@
     public:
         // Public Methods
     
-        /** Constructor
-        *
-        */
-        PidController(char);
+        // Constructor
+        PidController();
         
         /** Performs the PID Calculation
         * @param SP - Setpoint (target value) units depends on what PID is controlling
         * @param PV - Process Variable (feedback/ measure value) units depends on what PID is controlling
-        * @return Returns If Controller is in Automatic then returns PID controlled signal. In manual returns the user SP multipled by scalar.
+        * @return Returns If Controller is in Automatic then returns PID controlled signal. In manual returns the user SP.
         */
-        float Calculate(float SP, float PV, float ManualMV);
+        float Calculate(float SP, float PV);
         
         /** Update Internal Settings
         * @param Bias - Added to the PID Calculation
@@ -103,37 +93,37 @@
         */
         void EndDiag(void);
         
-        /** Build a string to send back to HMI to Graph PID
-        */
-        void BuildDiagMessage(float SP, float PV, float PWM, float PropAction, float IntAction, float DifAction);
-        
         /** Check to see if the controller is collecting diagnostics data
         * @return true then a diagnostics message is been created.
         */
         bool DiagnosticsEnabled(void){return collectDiagnostics;}
         
-        int GetElapsedtime(void){return elapsedTime;}
-        
-        // Made Public as im lazy
-        char diagMsg[65];
+        /** Check to see if the controller is collecting diagnostics data
+        * @param Data - Starting address of target recieve buffer (must be at least 25char long)
+        */
+        void GetDiagnosticsMessage(char *data);
         
     private:
         bool mode;
-        
         //-- For Diagnostics to GUI
         bool collectDiagnostics;
-        int elapsedTime;
+        uint16_t elapsedTime;
+        char diagMsg[28];
+        
+        //-- Settings
+        float bias;
+        float minLimit, maxLimit;
+        float K_p,K_i,K_d;
         
         //-- For PID Calculations
-        char diagChar;
-        float bias;
         float error;
-        float lastInput;
         float accumError;
-        float minLimit, maxLimit;
-        float K_p,K_i,K_d;
         float prevError;
-    };
+        
+        //-- Private Helper functions
+        void float_to_byte(char *data, float *val);
+        void int_to_byte(char *data, uint16_t val);
+        };
     
 #endif