|
| 1 | +/********************************************************************************************** |
| 2 | + * Arduino PID Library - Version 1.0.1 |
| 3 | + * by Brett Beauregard <br3ttb@gmail.com> brettbeauregard.com |
| 4 | + * |
| 5 | + * This Library is licensed under a GPLv3 License |
| 6 | + **********************************************************************************************/ |
| 7 | + |
| 8 | +#if ARDUINO >= 100 |
| 9 | + #include "Arduino.h" |
| 10 | +#else |
| 11 | + #include "WProgram.h" |
| 12 | +#endif |
| 13 | + |
| 14 | +#include <PID_v1.h> |
| 15 | + |
| 16 | +/*Constructor (...)********************************************************* |
| 17 | + * The parameters specified here are those for for which we can't set up |
| 18 | + * reliable defaults, so we need to have the user set them. |
| 19 | + ***************************************************************************/ |
| 20 | +PID::PID(double* Input, double* Output, double* Setpoint, |
| 21 | + double Kp, double Ki, double Kd, int ControllerDirection) |
| 22 | +{ |
| 23 | + PID::SetOutputLimits(0, 255); //default output limit corresponds to |
| 24 | + //the arduino pwm limits |
| 25 | + |
| 26 | + SampleTime = 100; //default Controller Sample Time is 0.1 seconds |
| 27 | + |
| 28 | + PID::SetControllerDirection(ControllerDirection); |
| 29 | + PID::SetTunings(Kp, Ki, Kd); |
| 30 | + |
| 31 | + lastTime = millis()-SampleTime; |
| 32 | + inAuto = false; |
| 33 | + myOutput = Output; |
| 34 | + myInput = Input; |
| 35 | + mySetpoint = Setpoint; |
| 36 | + |
| 37 | +} |
| 38 | + |
| 39 | + |
| 40 | +/* Compute() ********************************************************************** |
| 41 | + * This, as they say, is where the magic happens. this function should be called |
| 42 | + * every time "void loop()" executes. the function will decide for itself whether a new |
| 43 | + * pid Output needs to be computed |
| 44 | + **********************************************************************************/ |
| 45 | +void PID::Compute() |
| 46 | +{ |
| 47 | + if(!inAuto) return; |
| 48 | + unsigned long now = millis(); |
| 49 | + int timeChange = (now - lastTime); |
| 50 | + if(timeChange>=SampleTime) |
| 51 | + { |
| 52 | + /*Compute all the working error variables*/ |
| 53 | + double input = *myInput; |
| 54 | + double error = *mySetpoint - input; |
| 55 | + ITerm+= (ki * error); |
| 56 | + if(ITerm > outMax) ITerm= outMax; |
| 57 | + else if(ITerm < outMin) ITerm= outMin; |
| 58 | + double dInput = (input - lastInput); |
| 59 | + |
| 60 | + /*Compute PID Output*/ |
| 61 | + double output = kp * error + ITerm- kd * dInput; |
| 62 | + |
| 63 | + if(output > outMax) output = outMax; |
| 64 | + else if(output < outMin) output = outMin; |
| 65 | + *myOutput = output; |
| 66 | + |
| 67 | + /*Remember some variables for next time*/ |
| 68 | + lastInput = input; |
| 69 | + lastTime = now; |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | + |
| 74 | +/* SetTunings(...)************************************************************* |
| 75 | + * This function allows the controller's dynamic performance to be adjusted. |
| 76 | + * it's called automatically from the constructor, but tunings can also |
| 77 | + * be adjusted on the fly during normal operation |
| 78 | + ******************************************************************************/ |
| 79 | +void PID::SetTunings(double Kp, double Ki, double Kd) |
| 80 | +{ |
| 81 | + if (Kp<0 || Ki<0 || Kd<0) return; |
| 82 | + |
| 83 | + dispKp = Kp; dispKi = Ki; dispKd = Kd; |
| 84 | + |
| 85 | + double SampleTimeInSec = ((double)SampleTime)/1000; |
| 86 | + kp = Kp; |
| 87 | + ki = Ki * SampleTimeInSec; |
| 88 | + kd = Kd / SampleTimeInSec; |
| 89 | + |
| 90 | + if(controllerDirection ==REVERSE) |
| 91 | + { |
| 92 | + kp = (0 - kp); |
| 93 | + ki = (0 - ki); |
| 94 | + kd = (0 - kd); |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +/* SetSampleTime(...) ********************************************************* |
| 99 | + * sets the period, in Milliseconds, at which the calculation is performed |
| 100 | + ******************************************************************************/ |
| 101 | +void PID::SetSampleTime(int NewSampleTime) |
| 102 | +{ |
| 103 | + if (NewSampleTime > 0) |
| 104 | + { |
| 105 | + double ratio = (double)NewSampleTime |
| 106 | + / (double)SampleTime; |
| 107 | + ki *= ratio; |
| 108 | + kd /= ratio; |
| 109 | + SampleTime = (unsigned long)NewSampleTime; |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +/* SetOutputLimits(...)**************************************************** |
| 114 | + * This function will be used far more often than SetInputLimits. while |
| 115 | + * the input to the controller will generally be in the 0-1023 range (which is |
| 116 | + * the default already,) the output will be a little different. maybe they'll |
| 117 | + * be doing a time window and will need 0-8000 or something. or maybe they'll |
| 118 | + * want to clamp it from 0-125. who knows. at any rate, that can all be done |
| 119 | + * here. |
| 120 | + **************************************************************************/ |
| 121 | +void PID::SetOutputLimits(double Min, double Max) |
| 122 | +{ |
| 123 | + if(Min >= Max) return; |
| 124 | + outMin = Min; |
| 125 | + outMax = Max; |
| 126 | + |
| 127 | + if(inAuto) |
| 128 | + { |
| 129 | + if(*myOutput > outMax) *myOutput = outMax; |
| 130 | + else if(*myOutput < outMin) *myOutput = outMin; |
| 131 | + |
| 132 | + if(ITerm > outMax) ITerm= outMax; |
| 133 | + else if(ITerm < outMin) ITerm= outMin; |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +/* SetMode(...)**************************************************************** |
| 138 | + * Allows the controller Mode to be set to manual (0) or Automatic (non-zero) |
| 139 | + * when the transition from manual to auto occurs, the controller is |
| 140 | + * automatically initialized |
| 141 | + ******************************************************************************/ |
| 142 | +void PID::SetMode(int Mode) |
| 143 | +{ |
| 144 | + bool newAuto = (Mode == AUTOMATIC); |
| 145 | + if(newAuto == !inAuto) |
| 146 | + { /*we just went from manual to auto*/ |
| 147 | + PID::Initialize(); |
| 148 | + } |
| 149 | + inAuto = newAuto; |
| 150 | +} |
| 151 | + |
| 152 | +/* Initialize()**************************************************************** |
| 153 | + * does all the things that need to happen to ensure a bumpless transfer |
| 154 | + * from manual to automatic mode. |
| 155 | + ******************************************************************************/ |
| 156 | +void PID::Initialize() |
| 157 | +{ |
| 158 | + ITerm = *myOutput; |
| 159 | + lastInput = *myInput; |
| 160 | + if(ITerm > outMax) ITerm = outMax; |
| 161 | + else if(ITerm < outMin) ITerm = outMin; |
| 162 | +} |
| 163 | + |
| 164 | +/* SetControllerDirection(...)************************************************* |
| 165 | + * The PID will either be connected to a DIRECT acting process (+Output leads |
| 166 | + * to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to |
| 167 | + * know which one, because otherwise we may increase the output when we should |
| 168 | + * be decreasing. This is called from the constructor. |
| 169 | + ******************************************************************************/ |
| 170 | +void PID::SetControllerDirection(int Direction) |
| 171 | +{ |
| 172 | + if(inAuto && Direction !=controllerDirection) |
| 173 | + { |
| 174 | + kp = (0 - kp); |
| 175 | + ki = (0 - ki); |
| 176 | + kd = (0 - kd); |
| 177 | + } |
| 178 | + controllerDirection = Direction; |
| 179 | +} |
| 180 | + |
| 181 | +/* Status Funcions************************************************************* |
| 182 | + * Just because you set the Kp=-1 doesn't mean it actually happened. these |
| 183 | + * functions query the internal state of the PID. they're here for display |
| 184 | + * purposes. this are the functions the PID Front-end uses for example |
| 185 | + ******************************************************************************/ |
| 186 | +double PID::GetKp(){ return dispKp; } |
| 187 | +double PID::GetKi(){ return dispKi;} |
| 188 | +double PID::GetKd(){ return dispKd;} |
| 189 | +int PID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;} |
| 190 | +int PID::GetDirection(){ return controllerDirection;} |
| 191 | + |
0 commit comments