This commit is contained in:
Kristian Sloth Lauszus 2015-04-20 05:55:20 +00:00
commit ace42521d0
3 changed files with 72 additions and 17 deletions

View File

@ -32,9 +32,8 @@ PID::PID(double* Input, double* Output, double* Setpoint,
SampleTime = 100; //default Controller Sample Time is 0.1 seconds SampleTime = 100; //default Controller Sample Time is 0.1 seconds
PID::SetControllerDirection(ControllerDirection); PID::SetControllerDirection(ControllerDirection);
PID::SetResolution(MILLIS); // Use a resolution of milliseconds by default
PID::SetTunings(Kp, Ki, Kd); PID::SetTunings(Kp, Ki, Kd);
lastTime = millis()-SampleTime;
} }
@ -47,17 +46,25 @@ PID::PID(double* Input, double* Output, double* Setpoint,
bool PID::Compute() bool PID::Compute()
{ {
if(!inAuto) return false; if(!inAuto) return false;
unsigned long now = millis(); unsigned long now = PID::GetTime();
unsigned long timeChange = (now - lastTime); timeChange = (now - lastTime);
if(timeChange>=SampleTime) if(SampleTime == 0 || timeChange>=SampleTime)
{ {
/*Compute all the working error variables*/ /*Compute all the working error variables*/
double input = *myInput; double input = *myInput;
double error = *mySetpoint - input; double error = *mySetpoint - input;
ITerm+= (ki * error);
double dInput;
if (SampleTime > 0) {
ITerm += (ki * error);
dInput = (input - lastInput);
} else {
ITerm += (ki * error)*(((double)timeChange)/secondsDivider);
dInput = (input - lastInput)/(((double)timeChange)/secondsDivider);
}
if(ITerm > outMax) ITerm= outMax; if(ITerm > outMax) ITerm= outMax;
else if(ITerm < outMin) ITerm= outMin; else if(ITerm < outMin) ITerm= outMin;
double dInput = (input - lastInput);
/*Compute PID Output*/ /*Compute PID Output*/
double output = kp * error + ITerm- kd * dInput; double output = kp * error + ITerm- kd * dInput;
@ -85,11 +92,17 @@ void PID::SetTunings(double Kp, double Ki, double Kd)
if (Kp<0 || Ki<0 || Kd<0) return; if (Kp<0 || Ki<0 || Kd<0) return;
dispKp = Kp; dispKi = Ki; dispKd = Kd; dispKp = Kp; dispKi = Ki; dispKd = Kd;
double SampleTimeInSec = ((double)SampleTime)/1000; if (SampleTime > 0) {
kp = Kp; double SampleTimeInSec = ((double)SampleTime)/secondsDivider;
ki = Ki * SampleTimeInSec; kp = Kp;
kd = Kd / SampleTimeInSec; ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
} else {
kp = Kp;
ki = Ki;
kd = Kd;
}
if(controllerDirection ==REVERSE) if(controllerDirection ==REVERSE)
{ {
@ -100,18 +113,25 @@ void PID::SetTunings(double Kp, double Ki, double Kd)
} }
/* SetSampleTime(...) ********************************************************* /* SetSampleTime(...) *********************************************************
* sets the period, in Milliseconds, at which the calculation is performed * sets the period, in Milliseconds, at which the calculation is performed
* If it's set to 0 or a negative value it will computer every time the
* function is called
******************************************************************************/ ******************************************************************************/
void PID::SetSampleTime(int NewSampleTime) void PID::SetSampleTime(int NewSampleTime)
{ {
if (NewSampleTime > 0) if (NewSampleTime > 0)
{ {
double ratio = (double)NewSampleTime double ratio;
/ (double)SampleTime; if (SampleTime > 0)
ratio = (double)NewSampleTime/(double)SampleTime;
else
ratio = (double)NewSampleTime/(double)timeChange; // We will assume the user is calling Compute at a regular interval
ki *= ratio; ki *= ratio;
kd /= ratio; kd /= ratio;
SampleTime = (unsigned long)NewSampleTime; SampleTime = (unsigned long)NewSampleTime;
} } else
SampleTime = 0; // We will compute every time the function is called
} }
/* SetOutputLimits(...)**************************************************** /* SetOutputLimits(...)****************************************************
@ -182,6 +202,29 @@ void PID::SetControllerDirection(int Direction)
controllerDirection = Direction; controllerDirection = Direction;
} }
/* GetTime()*******************************************************************
* Will get the current time either by using millis() or micros()
******************************************************************************/
unsigned long PID::GetTime()
{
if (secondsDivider == 1000.0) return millis();
return micros();
}
/* SetResolution(...)**********************************************************
* Will set the resolution of GetTime().
* MILLIS will set the resolution to milliseconds while
* MICROS will set the resolution to microseconds.
******************************************************************************/
void PID::SetResolution(int resolution)
{
if (resolution == MILLIS)
secondsDivider = 1000.0;
else
secondsDivider = 1000000.0;
lastTime = PID::GetTime()-SampleTime; // Update last time variable
}
/* Status Funcions************************************************************* /* Status Funcions*************************************************************
* Just because you set the Kp=-1 doesn't mean it actually happened. these * 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

View File

@ -13,6 +13,8 @@ class PID
#define MANUAL 0 #define MANUAL 0
#define DIRECT 0 #define DIRECT 0
#define REVERSE 1 #define REVERSE 1
#define MILLIS 0
#define MICROS 1
//commonly used functions ************************************************************************** //commonly used functions **************************************************************************
PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and
@ -41,6 +43,9 @@ class PID
// once it is set in the constructor. // once it is set in the constructor.
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which 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 100
void SetResolution(int); // * Set the resolution of the GetTime() function.
// MILLIS sets the resolution to milliseconds.
// MICROS sets the resolution to microseconds.
@ -53,6 +58,8 @@ class PID
private: private:
void Initialize(); void Initialize();
unsigned long GetTime(); // * This will call either millis() or micros()
// depending on the used resolution.
double dispKp; // * we'll hold on to the tuning parameters in user-entered double dispKp; // * we'll hold on to the tuning parameters in user-entered
double dispKi; // format for display purposes double dispKi; // format for display purposes
@ -71,8 +78,10 @@ class PID
unsigned long lastTime; unsigned long lastTime;
double ITerm, lastInput; double ITerm, lastInput;
unsigned long timeChange;
unsigned long SampleTime; unsigned long SampleTime;
double secondsDivider;
double outMin, outMax; double outMin, outMax;
bool inAuto; bool inAuto;
}; };

View File

@ -18,6 +18,7 @@ SetOutputLimits KEYWORD2
SetTunings KEYWORD2 SetTunings KEYWORD2
SetControllerDirection KEYWORD2 SetControllerDirection KEYWORD2
SetSampleTime KEYWORD2 SetSampleTime KEYWORD2
SetResolution KEYWORD2
GetKp KEYWORD2 GetKp KEYWORD2
GetKi KEYWORD2 GetKi KEYWORD2
GetKd KEYWORD2 GetKd KEYWORD2
@ -31,4 +32,6 @@ GetDirection KEYWORD2
AUTOMATIC LITERAL1 AUTOMATIC LITERAL1
MANUAL LITERAL1 MANUAL LITERAL1
DIRECT LITERAL1 DIRECT LITERAL1
REVERSE LITERAL1 REVERSE LITERAL1
MILLIS LITERAL1
MICROS LITERAL1