From 9f59efabfc6f37389354e1c9e3622125fec769b0 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Fri, 19 Jul 2013 16:23:42 +0200 Subject: [PATCH 1/6] Allow to set the resolution to either microseconds or microseconds --- PID_v1/PID_v1.cpp | 37 ++++++++++++++++++++++++++++++------- PID_v1/PID_v1.h | 8 ++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/PID_v1/PID_v1.cpp b/PID_v1/PID_v1.cpp index 6c95895..bef8356 100644 --- a/PID_v1/PID_v1.cpp +++ b/PID_v1/PID_v1.cpp @@ -34,7 +34,7 @@ PID::PID(double* Input, double* Output, double* Setpoint, PID::SetControllerDirection(ControllerDirection); PID::SetTunings(Kp, Ki, Kd); - lastTime = millis()-SampleTime; + PID::setResolution(MILLIS); // Use a resolution of milliseconds by default } @@ -47,7 +47,7 @@ PID::PID(double* Input, double* Output, double* Setpoint, bool PID::Compute() { if(!inAuto) return false; - unsigned long now = millis(); + unsigned long now = PID::getTime(); unsigned long timeChange = (now - lastTime); if(timeChange>=SampleTime) { @@ -85,11 +85,11 @@ void PID::SetTunings(double Kp, double Ki, double Kd) if (Kp<0 || Ki<0 || Kd<0) return; dispKp = Kp; dispKi = Ki; dispKd = Kd; - - double SampleTimeInSec = ((double)SampleTime)/1000; - kp = Kp; - ki = Ki * SampleTimeInSec; - kd = Kd / SampleTimeInSec; + + double SampleTimeInSec = ((double)SampleTime)/secondsDivider; + kp = Kp; + ki = Ki * SampleTimeInSec; + kd = Kd / SampleTimeInSec; if(controllerDirection ==REVERSE) { @@ -182,6 +182,29 @@ void PID::SetControllerDirection(int 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************************************************************* * 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 diff --git a/PID_v1/PID_v1.h b/PID_v1/PID_v1.h index 6f86697..ac28c44 100644 --- a/PID_v1/PID_v1.h +++ b/PID_v1/PID_v1.h @@ -13,6 +13,8 @@ class PID #define MANUAL 0 #define DIRECT 0 #define REVERSE 1 + #define MILLIS 0 + #define MICROS 1 //commonly used functions ************************************************************************** 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. void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which // 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: 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 dispKi; // format for display purposes @@ -73,6 +80,7 @@ class PID double ITerm, lastInput; unsigned long SampleTime; + double secondsDivider; double outMin, outMax; bool inAuto; }; From 6231da4cf99dee3ec33ae41beb8eb243c62f3dde Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Fri, 19 Jul 2013 16:30:18 +0200 Subject: [PATCH 2/6] By setting SetSampleTime to 0. Compute will calculate the output every time it's called --- PID_v1/PID_v1.cpp | 37 +++++++++++++++++++++++++++++-------- PID_v1/PID_v1.h | 1 + 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/PID_v1/PID_v1.cpp b/PID_v1/PID_v1.cpp index bef8356..e5d1ba2 100644 --- a/PID_v1/PID_v1.cpp +++ b/PID_v1/PID_v1.cpp @@ -48,16 +48,24 @@ bool PID::Compute() { if(!inAuto) return false; unsigned long now = PID::getTime(); - unsigned long timeChange = (now - lastTime); - if(timeChange>=SampleTime) + timeChange = (now - lastTime); + if(SampleTime == 0 || timeChange>=SampleTime) { /*Compute all the working error variables*/ double input = *myInput; 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; else if(ITerm < outMin) ITerm= outMin; - double dInput = (input - lastInput); /*Compute PID Output*/ double output = kp * error + ITerm- kd * dInput; @@ -86,10 +94,16 @@ void PID::SetTunings(double Kp, double Ki, double Kd) dispKp = Kp; dispKi = Ki; dispKd = Kd; + if (SampleTime > 0) { double SampleTimeInSec = ((double)SampleTime)/secondsDivider; kp = Kp; ki = Ki * SampleTimeInSec; kd = Kd / SampleTimeInSec; + } else { + kp = Kp; + ki = Ki; + kd = Kd; + } if(controllerDirection ==REVERSE) { @@ -100,18 +114,25 @@ void PID::SetTunings(double Kp, double Ki, double Kd) } /* 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) { if (NewSampleTime > 0) { - double ratio = (double)NewSampleTime - / (double)SampleTime; + double ratio; + 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; kd /= ratio; SampleTime = (unsigned long)NewSampleTime; - } + } else + SampleTime = 0; // We will compute every time the function is called } /* SetOutputLimits(...)**************************************************** diff --git a/PID_v1/PID_v1.h b/PID_v1/PID_v1.h index ac28c44..b19e636 100644 --- a/PID_v1/PID_v1.h +++ b/PID_v1/PID_v1.h @@ -78,6 +78,7 @@ class PID unsigned long lastTime; double ITerm, lastInput; + unsigned long timeChange; unsigned long SampleTime; double secondsDivider; From e48e87eededdb1eadf9b8f4a17a02839e21c3a80 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Fri, 19 Jul 2013 17:00:53 +0200 Subject: [PATCH 3/6] Function should start with a capital letter to match the style of the existing functions --- PID_v1/PID_v1.cpp | 16 ++++++++-------- PID_v1/PID_v1.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/PID_v1/PID_v1.cpp b/PID_v1/PID_v1.cpp index e5d1ba2..bfbad00 100644 --- a/PID_v1/PID_v1.cpp +++ b/PID_v1/PID_v1.cpp @@ -34,7 +34,7 @@ PID::PID(double* Input, double* Output, double* Setpoint, PID::SetControllerDirection(ControllerDirection); PID::SetTunings(Kp, Ki, Kd); - PID::setResolution(MILLIS); // Use a resolution of milliseconds by default + PID::SetResolution(MILLIS); // Use a resolution of milliseconds by default } @@ -47,7 +47,7 @@ PID::PID(double* Input, double* Output, double* Setpoint, bool PID::Compute() { if(!inAuto) return false; - unsigned long now = PID::getTime(); + unsigned long now = PID::GetTime(); timeChange = (now - lastTime); if(SampleTime == 0 || timeChange>=SampleTime) { @@ -203,27 +203,27 @@ void PID::SetControllerDirection(int Direction) controllerDirection = Direction; } -/* getTime()******************************************************************* +/* GetTime()******************************************************************* * Will get the current time either by using millis() or micros() ******************************************************************************/ -unsigned long PID::getTime() +unsigned long PID::GetTime() { if (secondsDivider == 1000.0) return millis(); return micros(); } -/* setResolution(...)********************************************************** - * Will set the resolution of getTime(). +/* 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) +void PID::SetResolution(int resolution) { if (resolution == MILLIS) secondsDivider = 1000.0; else secondsDivider = 1000000.0; - lastTime = PID::getTime()-SampleTime; // Update last time variable + lastTime = PID::GetTime()-SampleTime; // Update last time variable } /* Status Funcions************************************************************* diff --git a/PID_v1/PID_v1.h b/PID_v1/PID_v1.h index b19e636..a9a8005 100644 --- a/PID_v1/PID_v1.h +++ b/PID_v1/PID_v1.h @@ -43,7 +43,7 @@ class PID // 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 - void setResolution(int); // * Set the resolution of the getTime() function. + void SetResolution(int); // * Set the resolution of the GetTime() function. // MILLIS sets the resolution to milliseconds. // MICROS sets the resolution to microseconds. @@ -58,7 +58,7 @@ class PID private: void Initialize(); - unsigned long getTime(); // * This will call either millis() or micros() + 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 From ba89cfe99d8d4ce0a55f26bf05109947322c2034 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Fri, 19 Jul 2013 17:01:06 +0200 Subject: [PATCH 4/6] Updated keywords --- PID_v1/keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/PID_v1/keywords.txt b/PID_v1/keywords.txt index 55969c1..6b78e51 100644 --- a/PID_v1/keywords.txt +++ b/PID_v1/keywords.txt @@ -18,6 +18,7 @@ SetOutputLimits KEYWORD2 SetTunings KEYWORD2 SetControllerDirection KEYWORD2 SetSampleTime KEYWORD2 +SetResolution KEYWORD2 GetKp KEYWORD2 GetKi KEYWORD2 GetKd KEYWORD2 From dc8d6f40047cb945225089a880ea1303165e6ac7 Mon Sep 17 00:00:00 2001 From: Kristian Sloth Lauszus Date: Sat, 20 Jul 2013 12:46:04 +0200 Subject: [PATCH 5/6] Forgot to add MILLIS and MICROS to keywords --- PID_v1/keywords.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PID_v1/keywords.txt b/PID_v1/keywords.txt index 6b78e51..3cb776b 100644 --- a/PID_v1/keywords.txt +++ b/PID_v1/keywords.txt @@ -32,4 +32,6 @@ GetDirection KEYWORD2 AUTOMATIC LITERAL1 MANUAL LITERAL1 DIRECT LITERAL1 -REVERSE LITERAL1 \ No newline at end of file +REVERSE LITERAL1 +MILLIS LITERAL1 +MICROS LITERAL1 \ No newline at end of file From 7753b8050063c61fce65b8de52e2e21f0a0a87c4 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 25 Apr 2014 15:45:09 +0200 Subject: [PATCH 6/6] Call SetTunings after SetResolution is called --- PID_v1/PID_v1.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PID_v1/PID_v1.cpp b/PID_v1/PID_v1.cpp index bfbad00..6c63016 100644 --- a/PID_v1/PID_v1.cpp +++ b/PID_v1/PID_v1.cpp @@ -32,9 +32,8 @@ PID::PID(double* Input, double* Output, double* Setpoint, SampleTime = 100; //default Controller Sample Time is 0.1 seconds PID::SetControllerDirection(ControllerDirection); - PID::SetTunings(Kp, Ki, Kd); - PID::SetResolution(MILLIS); // Use a resolution of milliseconds by default + PID::SetTunings(Kp, Ki, Kd); }