Skip to content

Commit

Permalink
Version 1.2
Browse files Browse the repository at this point in the history
-Added capability for Proportional On Measurement
-Changed license from GPLv3 to MIT
  • Loading branch information
br3ttb committed Jun 19, 2017
1 parent 5adeed5 commit 5cefbae
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 58 deletions.
125 changes: 77 additions & 48 deletions PID_v1.cpp
Expand Up @@ -14,36 +14,47 @@
#include <PID_v1.h>

/*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;
Expand All @@ -52,55 +63,73 @@ 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);
ki = (0 - ki);
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)
{
Expand All @@ -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
Expand All @@ -127,22 +156,22 @@ 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;
}
}

/* SetMode(...)****************************************************************
* 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);
Expand All @@ -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.
Expand All @@ -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; }
Expand Down
22 changes: 16 additions & 6 deletions PID_v1.h
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -63,18 +72,19 @@ 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
double *mySetpoint; // PID, freeing the user from having to constantly tell us
// 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

4 changes: 2 additions & 2 deletions README.txt
@@ -1,8 +1,8 @@
***************************************************************
* Arduino PID Library - Version 1.1.1
* Arduino PID Library - Version 1.2.0
* by Brett Beauregard <br3ttb@gmail.com> 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:
Expand Down
36 changes: 36 additions & 0 deletions 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 <PID_v1.h>

//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);
}



4 changes: 3 additions & 1 deletion keywords.txt
Expand Up @@ -31,4 +31,6 @@ GetDirection KEYWORD2
AUTOMATIC LITERAL1
MANUAL LITERAL1
DIRECT LITERAL1
REVERSE LITERAL1
REVERSE LITERAL1
P_ON_E LITERAL1
P_ON_M LITERAL1
2 changes: 1 addition & 1 deletion 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
Expand Down

0 comments on commit 5cefbae

Please sign in to comment.