diff --git a/PID_v1.cpp b/PID_v1.cpp index cb6637c..1379ba7 100644 --- a/PID_v1.cpp +++ b/PID_v1.cpp @@ -18,7 +18,7 @@ * 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 POn, int ControllerDirection) + double Kp, double Ki, double Kd, pid_p_on POn, pid_direction ControllerDirection) { myOutput = Output; myInput = Input; @@ -42,8 +42,8 @@ PID::PID(double* Input, double* Output, double* Setpoint, ***************************************************************************/ 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) + double Kp, double Ki, double Kd, pid_direction ControllerDirection) + :PID::PID(Input, Output, Setpoint, Kp, Ki, Kd, ERROR, ControllerDirection) { } @@ -65,6 +65,18 @@ bool PID::Compute() /*Compute all the working error variables*/ double input = *myInput; double error = *mySetpoint - input; + + if (hystControl && error > hystOn) { + *myOutput = outMax; + outputSum = outMax; //Good idea? + return true; + } + else if (hystControl && error < hystOff) { + *myOutput = outMin; + outputSum = outMin; //Good idea? + return true; + } + double dInput = (input - lastInput); outputSum+= (ki * error); @@ -82,7 +94,7 @@ bool PID::Compute() /*Compute Rest of PID Output*/ output += outputSum - kd * dInput; - if(output > outMax) output = outMax; + if(output > outMax) output = outMax; else if(output < outMin) output = outMin; *myOutput = output; @@ -94,17 +106,36 @@ bool PID::Compute() else return false; } +/* +Hysteresis/Bang-Bang/On-Off control when PV/Input is far form setpoint. +Useful for very slow moving porcesses. + +IF PV-SP > Output = OutMax, +IF PV-SP < Output = OutMin. +ELSE Use normal pid control +*/ +void PID::SetHysteresisControl(bool enable, double on, double off) { + hystControl = enable; + if (controllerDirection == REVERSE) { + hystOn = -on; + hystOff = -off; + return; + } + hystOn = on; + hystOff = off; +} + /* SetTunings(...)************************************************************* * 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, int POn) +void PID::SetTunings(double Kp, double Ki, double Kd, pid_p_on POn) { if (Kp<0 || Ki<0 || Kd<0) return; pOn = POn; - pOnE = POn == P_ON_E; + pOnE = POn == ERROR; dispKp = Kp; dispKi = Ki; dispKd = Kd; @@ -113,7 +144,7 @@ void PID::SetTunings(double Kp, double Ki, double Kd, int POn) ki = Ki * SampleTimeInSec; kd = Kd / SampleTimeInSec; - if(controllerDirection ==REVERSE) + if(controllerDirection == REVERSE) { kp = (0 - kp); ki = (0 - ki); @@ -172,9 +203,9 @@ void PID::SetOutputLimits(double Min, double Max) * when the transition from manual to auto occurs, the controller is * automatically initialized ******************************************************************************/ -void PID::SetMode(int Mode) +void PID::SetMode(pid_mode mode) { - bool newAuto = (Mode == AUTOMATIC); + bool newAuto = (mode == AUTOMATIC); if(newAuto && !inAuto) { /*we just went from manual to auto*/ PID::Initialize(); @@ -200,15 +231,15 @@ void PID::Initialize() * know which one, because otherwise we may increase the output when we should * be decreasing. This is called from the constructor. ******************************************************************************/ -void PID::SetControllerDirection(int Direction) +void PID::SetControllerDirection(pid_direction direction) { - if(inAuto && Direction !=controllerDirection) + if(inAuto && direction != controllerDirection) { - kp = (0 - kp); + kp = (0 - kp); ki = (0 - ki); kd = (0 - kd); } - controllerDirection = Direction; + controllerDirection = direction; } /* Status Funcions************************************************************* @@ -221,4 +252,3 @@ double PID::GetKi(){ return dispKi;} double PID::GetKd(){ return dispKd;} int PID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;} int PID::GetDirection(){ return controllerDirection;} - diff --git a/PID_v1.h b/PID_v1.h index 9cba046..0623be6 100644 --- a/PID_v1.h +++ b/PID_v1.h @@ -2,29 +2,29 @@ #define PID_v1_h #define LIBRARY_VERSION 1.2.1 + class PID { public: - //Constants used in some of the functions below - #define AUTOMATIC 1 - #define MANUAL 0 - #define DIRECT 0 - #define REVERSE 1 - #define P_ON_M 0 - #define P_ON_E 1 + //Enums + enum pid_mode { AUTOMATIC = 1, MANUAL = 0 }; + enum pid_direction { DIRECT = 0, REVERSE = 1 }; + enum pid_p_on { ERROR = 0, MESUREMENT = 1 }; + - //commonly used functions ************************************************************************** + //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) + double, double, double, // Setpoint. Initial tuning parameters are also set here. + pid_p_on, pid_direction); // (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 + double, double, double, // Setpoint. Initial tuning parameters are also set here + pid_direction); - void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0) + void SetMode(pid_mode); // * sets PID to either Manual (0) or Auto (non-0) bool Compute(); // * performs the PID calculation. it should be // called every time loop() cycles. ON/OFF and @@ -42,15 +42,16 @@ class PID 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); + double, pid_p_on); - void SetControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT + void SetControllerDirection(pid_direction); // * 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 // once it is set in the constructor. void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which - // the PID calculation is performed. default is 100 - + // the PID calculation is performed. default is 10 + + void SetHysteresisControl(bool, double, double); //Display functions **************************************************************** @@ -72,7 +73,7 @@ class PID double kd; // * (D)erivative Tuning Parameter int controllerDirection; - int pOn; + pid_p_on pOn; double *myInput; // * Pointers to the Input, Output, and Setpoint variables double *myOutput; // This creates a hard link between the variables and the @@ -81,10 +82,10 @@ class PID unsigned long lastTime; double outputSum, lastInput; + double hystOn, hystOff; //Hysteresis control if PV-SP is > hystOn or < hystOff unsigned long SampleTime; double outMin, outMax; - bool inAuto, pOnE; + bool inAuto, pOnE, hystControl; }; #endif -