From 5cefbae8e5c6cfc8cb3fbdcd76d37c07d341938b Mon Sep 17 00:00:00 2001 From: Brett Date: Mon, 19 Jun 2017 16:29:36 -0700 Subject: [PATCH] Version 1.2 -Added capability for Proportional On Measurement -Changed license from GPLv3 to MIT --- PID_v1.cpp | 125 ++++++++++++++++++++------------- PID_v1.h | 22 ++++-- README.txt | 4 +- examples/PID_PonM/PID_PonM.ino | 36 ++++++++++ keywords.txt | 4 +- library.properties | 2 +- 6 files changed, 135 insertions(+), 58 deletions(-) create mode 100644 examples/PID_PonM/PID_PonM.ino diff --git a/PID_v1.cpp b/PID_v1.cpp index 86222c7..285de13 100644 --- a/PID_v1.cpp +++ b/PID_v1.cpp @@ -14,36 +14,47 @@ #include /*Constructor (...)********************************************************* - * The parameters specified here are those for for which we can't set up + * The parameters specified here are those for for which we can't set up * reliable defaults, so we need to have the user set them. ***************************************************************************/ PID::PID(double* Input, double* Output, double* Setpoint, - double Kp, double Ki, double Kd, int ControllerDirection) + double Kp, double Ki, double Kd, int POn, int ControllerDirection) { - myOutput = Output; myInput = Input; mySetpoint = Setpoint; - inAuto = false; - - PID::SetOutputLimits(0, 255); //default output limit corresponds to + inAuto = false; + + PID::SetOutputLimits(0, 255); //default output limit corresponds to //the arduino pwm limits SampleTime = 100; //default Controller Sample Time is 0.1 seconds PID::SetControllerDirection(ControllerDirection); - PID::SetTunings(Kp, Ki, Kd); + PID::SetTunings(Kp, Ki, Kd, POn); - lastTime = millis()-SampleTime; + lastTime = millis()-SampleTime; } - - + +/*Constructor (...)********************************************************* + * To allow backwards compatability for v1.1, or for people that just want + * to use Proportional on Error without explicitly saying so + ***************************************************************************/ + +PID::PID(double* Input, double* Output, double* Setpoint, + double Kp, double Ki, double Kd, int ControllerDirection) + :PID::PID(Input, Output, Setpoint, Kp, Ki, Kd, P_ON_E, ControllerDirection) +{ + +} + + /* Compute() ********************************************************************** * This, as they say, is where the magic happens. this function should be called * every time "void loop()" executes. the function will decide for itself whether a new * pid Output needs to be computed. returns true when the output is computed, * false when nothing has been done. - **********************************************************************************/ + **********************************************************************************/ bool PID::Compute() { if(!inAuto) return false; @@ -52,45 +63,56 @@ bool PID::Compute() if(timeChange>=SampleTime) { /*Compute all the working error variables*/ - double input = *myInput; + double input = *myInput; double error = *mySetpoint - input; - ITerm+= (ki * error); - if(ITerm > outMax) ITerm= outMax; - else if(ITerm < outMin) ITerm= outMin; double dInput = (input - lastInput); - - /*Compute PID Output*/ - double output = kp * error + ITerm- kd * dInput; - - if(output > outMax) output = outMax; + outputSum+= (ki * error); + + /*Add Proportional on Measurement, if P_ON_M is specified*/ + if(!pOnE) outputSum-= kp * dInput; + + if(outputSum > outMax) outputSum= outMax; + else if(outputSum < outMin) outputSum= outMin; + + /*Add Proportional on Error, if P_ON_E is specified*/ + double output; + if(pOnE) output = kp * error; + else output = 0; + + /*Compute Rest of PID Output*/ + output += outputSum - kd * dInput; + + if(output > outMax) output = outMax; else if(output < outMin) output = outMin; - *myOutput = output; - + *myOutput = output; + /*Remember some variables for next time*/ lastInput = input; lastTime = now; - return true; + return true; } else return false; } - /* SetTunings(...)************************************************************* - * This function allows the controller's dynamic performance to be adjusted. + * This function allows the controller's dynamic performance to be adjusted. * it's called automatically from the constructor, but tunings can also * be adjusted on the fly during normal operation - ******************************************************************************/ -void PID::SetTunings(double Kp, double Ki, double Kd) + ******************************************************************************/ +void PID::SetTunings(double Kp, double Ki, double Kd, int POn) { if (Kp<0 || Ki<0 || Kd<0) return; - + + pOn = POn; + pOnE = POn == P_ON_E; + dispKp = Kp; dispKi = Ki; dispKd = Kd; - - double SampleTimeInSec = ((double)SampleTime)/1000; + + double SampleTimeInSec = ((double)SampleTime)/1000; kp = Kp; ki = Ki * SampleTimeInSec; kd = Kd / SampleTimeInSec; - + if(controllerDirection ==REVERSE) { kp = (0 - kp); @@ -98,9 +120,16 @@ void PID::SetTunings(double Kp, double Ki, double Kd) kd = (0 - kd); } } - + +/* SetTunings(...)************************************************************* + * Set Tunings using the last-rembered POn setting + ******************************************************************************/ +void PID::SetTunings(double Kp, double Ki, double Kd){ + SetTunings(Kp, Ki, Kd, pOn); +} + /* SetSampleTime(...) ********************************************************* - * sets the period, in Milliseconds, at which the calculation is performed + * sets the period, in Milliseconds, at which the calculation is performed ******************************************************************************/ void PID::SetSampleTime(int NewSampleTime) { @@ -113,7 +142,7 @@ void PID::SetSampleTime(int NewSampleTime) SampleTime = (unsigned long)NewSampleTime; } } - + /* SetOutputLimits(...)**************************************************** * This function will be used far more often than SetInputLimits. while * the input to the controller will generally be in the 0-1023 range (which is @@ -127,14 +156,14 @@ void PID::SetOutputLimits(double Min, double Max) if(Min >= Max) return; outMin = Min; outMax = Max; - + if(inAuto) { if(*myOutput > outMax) *myOutput = outMax; else if(*myOutput < outMin) *myOutput = outMin; - - if(ITerm > outMax) ITerm= outMax; - else if(ITerm < outMin) ITerm= outMin; + + if(outputSum > outMax) outputSum= outMax; + else if(outputSum < outMin) outputSum= outMin; } } @@ -142,7 +171,7 @@ void PID::SetOutputLimits(double Min, double Max) * Allows the controller Mode to be set to manual (0) or Automatic (non-zero) * when the transition from manual to auto occurs, the controller is * automatically initialized - ******************************************************************************/ + ******************************************************************************/ void PID::SetMode(int Mode) { bool newAuto = (Mode == AUTOMATIC); @@ -152,21 +181,21 @@ void PID::SetMode(int Mode) } inAuto = newAuto; } - + /* Initialize()**************************************************************** * does all the things that need to happen to ensure a bumpless transfer * from manual to automatic mode. - ******************************************************************************/ + ******************************************************************************/ void PID::Initialize() { - ITerm = *myOutput; + outputSum = *myOutput; lastInput = *myInput; - if(ITerm > outMax) ITerm = outMax; - else if(ITerm < outMin) ITerm = outMin; + if(outputSum > outMax) outputSum = outMax; + else if(outputSum < outMin) outputSum = outMin; } /* SetControllerDirection(...)************************************************* - * The PID will either be connected to a DIRECT acting process (+Output leads + * The PID will either be connected to a DIRECT acting process (+Output leads * to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to * know which one, because otherwise we may increase the output when we should * be decreasing. This is called from the constructor. @@ -175,16 +204,16 @@ void PID::SetControllerDirection(int Direction) { if(inAuto && Direction !=controllerDirection) { - kp = (0 - kp); + kp = (0 - kp); ki = (0 - ki); kd = (0 - kd); - } + } controllerDirection = Direction; } /* Status Funcions************************************************************* * Just because you set the Kp=-1 doesn't mean it actually happened. these - * functions query the internal state of the PID. they're here for display + * functions query the internal state of the PID. they're here for display * purposes. this are the functions the PID Front-end uses for example ******************************************************************************/ double PID::GetKp(){ return dispKp; } diff --git a/PID_v1.h b/PID_v1.h index 77b3e4b..db710bf 100644 --- a/PID_v1.h +++ b/PID_v1.h @@ -13,8 +13,14 @@ class PID #define MANUAL 0 #define DIRECT 0 #define REVERSE 1 + #define P_ON_M 0 + #define P_ON_E 1 //commonly used functions ************************************************************************** + PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and + double, double, double, int, int);// Setpoint. Initial tuning parameters are also set here. + // (overload for specifying proportional mode) + PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and double, double, double, int); // Setpoint. Initial tuning parameters are also set here @@ -25,16 +31,19 @@ class PID // calculation frequency can be set using SetMode // SetSampleTime respectively - void SetOutputLimits(double, double); //clamps the output to a specific range. 0-255 by default, but - //it's likely the user will want to change this depending on - //the application + void SetOutputLimits(double, double); // * clamps the output to a specific range. 0-255 by default, but + // it's likely the user will want to change this depending on + // the application //available but not commonly used functions ******************************************************** void SetTunings(double, double, // * While most users will set the tunings once in the - double); // constructor, this function gives the user the option + double); // constructor, this function gives the user the option // of changing tunings during runtime for Adaptive control + void SetTunings(double, double, // * overload for specifying proportional mode + double, int); + void SetControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT // means the output will increase when error is positive. REVERSE // means the opposite. it's very unlikely that this will be needed @@ -63,6 +72,7 @@ class PID double kd; // * (D)erivative Tuning Parameter int controllerDirection; + int pOn; double *myInput; // * Pointers to the Input, Output, and Setpoint variables double *myOutput; // This creates a hard link between the variables and the @@ -70,11 +80,11 @@ class PID // what these values are. with pointers we'll just know. unsigned long lastTime; - double ITerm, lastInput; + double outputSum, lastInput; unsigned long SampleTime; double outMin, outMax; - bool inAuto; + bool inAuto, pOnE; }; #endif diff --git a/README.txt b/README.txt index 61f4be2..9b9cb83 100644 --- a/README.txt +++ b/README.txt @@ -1,8 +1,8 @@ *************************************************************** -* Arduino PID Library - Version 1.1.1 +* Arduino PID Library - Version 1.2.0 * by Brett Beauregard brettbeauregard.com * -* This Library is licensed under a GPLv3 License +* This Library is licensed under the MIT License *************************************************************** - For an ultra-detailed explanation of why the code is the way it is, please visit: diff --git a/examples/PID_PonM/PID_PonM.ino b/examples/PID_PonM/PID_PonM.ino new file mode 100644 index 0000000..121c161 --- /dev/null +++ b/examples/PID_PonM/PID_PonM.ino @@ -0,0 +1,36 @@ +/******************************************************** + * PID Proportional on measurement Example + * Setting the PID to use Proportional on measurement will + * make the output move more smoothly when the setpoint + * is changed. In addition, it can eliminate overshoot + * in certain processes like sous-vides. + ********************************************************/ + +#include + +//Define Variables we'll be connecting to +double Setpoint, Input, Output; + +//Specify the links and initial tuning parameters +PID myPID(&Input, &Output, &Setpoint,2,5,1,P_ON_M, DIRECT); //P_ON_M specifies that Proportional on Measurement be used + //P_ON_E (Proportional on Error) is the default behavior + +void setup() +{ + //initialize the variables we're linked to + Input = analogRead(0); + Setpoint = 100; + + //turn the PID on + myPID.SetMode(AUTOMATIC); +} + +void loop() +{ + Input = analogRead(0); + myPID.Compute(); + analogWrite(3,Output); +} + + + diff --git a/keywords.txt b/keywords.txt index 55969c1..330d7fc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -31,4 +31,6 @@ GetDirection KEYWORD2 AUTOMATIC LITERAL1 MANUAL LITERAL1 DIRECT LITERAL1 -REVERSE LITERAL1 \ No newline at end of file +REVERSE LITERAL1 +P_ON_E LITERAL1 +P_ON_M LITERAL1 diff --git a/library.properties b/library.properties index 9a316b0..baf51b6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PID -version=1.1.1 +version=1.2.0 author=Brett Beauregard maintainer=Brett Beauregard sentence=PID controller