Rev 2281 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 2262 | linlun | 1 | /********************************************************************************************** |
| 2 | * C PID Library - Version 1.0.1 |
||
| 3 | * modified by Linus Lundin <linus.lundin@gmail.com (ported c to be used with AVR-GCC) |
||
| 4 | * originally by Brett Beauregard <br3ttb@gmail.com> brettbeauregard.com |
||
| 5 | * |
||
| 6 | * This Library is licensed under a GPLv3 License |
||
| 7 | **********************************************************************************************/ |
||
| 8 | |||
| 9 | #include "PID_v1.h" |
||
| 10 | #include <drivers/timer/timer.h> |
||
| 11 | void PID_Initialize(PidType* pid); |
||
| 12 | void PID_Limit(PidType* pid, FloatType *var); |
||
| 13 | |||
| 14 | /*Constructor (...)********************************************************* |
||
| 15 | * The parameters specified here are those for for which we can't set up |
||
| 16 | * reliable defaults, so we need to have the user set them. |
||
| 17 | ***************************************************************************/ |
||
| 18 | void PID_init(PidType* pid, FloatType* Input, FloatType* Output, FloatType* Setpoint, FloatType Kp, FloatType Ki, FloatType Kd, |
||
| 19 | PidDirectionType ControllerDirection) { |
||
| 20 | |||
| 21 | |||
| 22 | PID_SetOutputLimits(pid, 0, 0xffff); |
||
| 23 | |||
| 24 | //default Controller Sample Time is 0.1 seconds |
||
| 25 | pid->SampleTime = 100; |
||
| 26 | |||
| 27 | PID_SetControllerDirection(pid, ControllerDirection); |
||
| 28 | PID_SetTunings(pid, Kp, Ki, Kd); |
||
| 29 | |||
| 30 | pid->lastTime = Timer_GetTicks() - pid->SampleTime; |
||
| 31 | pid->mode = PID_Mode_Manual; |
||
| 32 | pid->myInput = Input; |
||
| 33 | pid->myOutput = Output; |
||
| 34 | pid->mySetpoint = Setpoint; |
||
| 35 | pid->MaxKd = 10.0; |
||
| 36 | } |
||
| 37 | |||
| 38 | /* Compute() ********************************************************************** |
||
| 39 | * This, as they say, is where the magic happens. this function should be called |
||
| 40 | * every time "void loop()" executes. the function will decide for itself whether a new |
||
| 41 | * pid Output needs to be computed. returns true when the output is computed, |
||
| 42 | * false when nothing has been done. |
||
| 43 | **********************************************************************************/ |
||
| 44 | bool PID_Compute(PidType* pid) |
||
| 45 | { |
||
| 46 | if (pid->mode == PID_Mode_Manual) |
||
| 47 | { |
||
| 48 | return false; |
||
| 49 | } |
||
| 50 | unsigned long now = Timer_GetTicks(); |
||
| 51 | unsigned long timeChange = (now - pid->lastTime); |
||
| 52 | if (timeChange >= pid->SampleTime) |
||
| 53 | { |
||
| 54 | // Compute all the working error variables |
||
| 55 | FloatType input = *pid->myInput; |
||
| 56 | |||
| 57 | // compute pid_t Output |
||
| 58 | FloatType error = *pid->mySetpoint - input; |
||
| 59 | FloatType dInput = (input - pid->lastInput); |
||
| 60 | |||
| 61 | pid->PTerm = pid->kp * error; |
||
| 62 | pid->ITerm += ( pid->ki * error ); |
||
| 63 | PID_Limit(pid, &pid->ITerm); |
||
| 64 | pid->DTerm = - pid->kd * dInput / ( pid->MaxKd < MAX_KD_MIN ? 1.0 : 1.0 + pid->kd / pid->MaxKd ); |
||
| 65 | |||
| 66 | // compute PID Output |
||
| 67 | FloatType output = pid->PTerm + pid->ITerm + pid->DTerm; |
||
| 68 | PID_Limit(pid, &output); |
||
| 69 | *pid->myOutput = output; |
||
| 70 | |||
| 71 | // remember some variables for next time |
||
| 72 | pid->lastInput = input; |
||
| 73 | pid->lastTime = now; |
||
| 74 | return true; |
||
| 75 | } |
||
| 76 | else |
||
| 77 | { |
||
| 78 | return false; |
||
| 79 | } |
||
| 80 | } |
||
| 81 | |||
| 82 | /* Limit(...)****************************************************************** |
||
| 83 | * bound supplied variable to (outMin, outMax) |
||
| 84 | ******************************************************************************/ |
||
| 85 | void PID_Limit(PidType* pid, FloatType *var) |
||
| 86 | { |
||
| 87 | if (*var < pid->outMin) |
||
| 88 | { |
||
| 89 | *var = pid->outMin; |
||
| 90 | } |
||
| 91 | else if (*var > pid->outMax) |
||
| 92 | { |
||
| 93 | *var = pid->outMax; |
||
| 94 | } |
||
| 95 | } |
||
| 96 | |||
| 97 | /* SetTunings(...)************************************************************* |
||
| 98 | * This function allows the controller's dynamic performance to be adjusted. |
||
| 99 | * it's called automatically from the constructor, but tunings can also |
||
| 100 | * be adjusted on the fly during normal operation |
||
| 101 | ******************************************************************************/ |
||
| 102 | void PID_SetTunings(PidType* pid, FloatType Kp, FloatType Ki, FloatType Kd) |
||
| 103 | { |
||
| 104 | if ((Kp < 0.0) || (Ki < 0.0) || (Kd < 0.0)) |
||
| 105 | { |
||
| 106 | return; |
||
| 107 | } |
||
| 108 | |||
| 109 | pid->dispKp = Kp; |
||
| 110 | pid->dispKi = Ki; |
||
| 111 | pid->dispKd = Kd; |
||
| 112 | |||
| 113 | FloatType SampleTimeInSec = ((FloatType) pid->SampleTime) / 1000.0; |
||
| 114 | pid->kp = Kp; |
||
| 115 | pid->ki = Ki * SampleTimeInSec; |
||
| 116 | pid->kd = Kd / SampleTimeInSec; |
||
| 117 | |||
| 118 | if (pid->controllerDirection == PID_Direction_Reverse) { |
||
| 119 | pid->kp = (0.0 - pid->kp); |
||
| 120 | pid->ki = (0.0 - pid->ki); |
||
| 121 | pid->kd = (0.0 - pid->kd); |
||
| 122 | } |
||
| 123 | } |
||
| 124 | |||
| 125 | /* SetSampleTime(...) ********************************************************* |
||
| 126 | * sets the period, in Milliseconds, at which the calculation is performed |
||
| 127 | ******************************************************************************/ |
||
| 128 | void PID_SetSampleTime(PidType* pid, uint32_t NewSampleTime) |
||
| 129 | { |
||
| 130 | if (NewSampleTime > 0) { |
||
| 131 | FloatType ratio = (FloatType) NewSampleTime / (FloatType) pid->SampleTime; |
||
| 132 | pid->ki *= ratio; |
||
| 133 | pid->kd /= ratio; |
||
| 134 | pid->SampleTime = (uint32_t) NewSampleTime; |
||
| 135 | } |
||
| 136 | } |
||
| 137 | |||
| 138 | /* SetOutputLimits(...)**************************************************** |
||
| 139 | * This function will be used far more often than SetInputLimits. while |
||
| 140 | * the input to the controller will generally be in the 0-1023 range (which is |
||
| 141 | * the default already,) the output will be a little different. maybe they'll |
||
| 142 | * be doing a time window and will need 0-8000 or something. or maybe they'll |
||
| 143 | * want to clamp it from 0-125. who knows. at any rate, that can all be done |
||
| 144 | * here. |
||
| 145 | **************************************************************************/ |
||
| 146 | void PID_SetOutputLimits(PidType* pid, FloatType newMin, FloatType newMax) { |
||
| 147 | if (newMin >= newMax) { |
||
| 2281 | linlun | 148 | return; |
| 2262 | linlun | 149 | } |
| 150 | pid->outMin = newMin; |
||
| 151 | pid->outMax = newMax; |
||
| 152 | |||
| 153 | if (pid->mode == PID_Mode_Automatic) |
||
| 154 | { |
||
| 155 | PID_Limit(pid, pid->myOutput); |
||
| 156 | PID_Limit(pid, &pid->ITerm); |
||
| 157 | } |
||
| 158 | } |
||
| 159 | |||
| 160 | /* SetMode(...)**************************************************************** |
||
| 161 | * Allows the controller Mode to be set to manual (0) or Automatic (non-zero) |
||
| 162 | * when the transition from manual to auto occurs, the controller is |
||
| 163 | * automatically initialized |
||
| 164 | ******************************************************************************/ |
||
| 165 | void PID_SetMode(PidType* pid, PidModeType newMode) |
||
| 166 | { |
||
| 167 | if (newMode != pid->mode) |
||
| 168 | { |
||
| 169 | // just changed mode |
||
| 170 | PID_Initialize(pid); |
||
| 171 | pid->mode = newMode; |
||
| 172 | } |
||
| 173 | } |
||
| 174 | |||
| 175 | /* Initialize()**************************************************************** |
||
| 176 | * does all the things that need to happen to ensure a bumpless transfer |
||
| 177 | * from manual to automatic mode. |
||
| 178 | ******************************************************************************/ |
||
| 179 | void PID_Initialize(PidType* pid) |
||
| 180 | { |
||
| 181 | pid->ITerm = *pid->myOutput; |
||
| 182 | pid->lastInput = *pid->myInput; |
||
| 183 | PID_Limit(pid, &pid->ITerm); |
||
| 184 | } |
||
| 185 | |||
| 186 | /* SetControllerDirection(...)************************************************* |
||
| 187 | * The PID will either be connected to a DIRECT acting process (+Output leads |
||
| 188 | * to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to |
||
| 189 | * know which one, because otherwise we may increase the output when we should |
||
| 190 | * be decreasing. This is called from the constructor. |
||
| 191 | ******************************************************************************/ |
||
| 192 | void PID_SetControllerDirection(PidType* pid, PidDirectionType newDirection) |
||
| 193 | { |
||
| 194 | if ((pid->mode == PID_Mode_Automatic) && (newDirection != pid->controllerDirection)) |
||
| 195 | { |
||
| 196 | pid->kp = (0.0 - pid->kp); |
||
| 197 | pid->ki = (0.0 - pid->ki); |
||
| 198 | pid->kd = (0.0 - pid->kd); |
||
| 199 | } |
||
| 200 | pid->controllerDirection = newDirection; |
||
| 201 | } |
||
| 202 | |||
| 203 | /* pid_set_max_Kd(...)********************************************************* |
||
| 204 | * set maximum derivative gain |
||
| 205 | * Default 0 means no maximum. |
||
| 206 | ******************************************************************************/ |
||
| 207 | void PID_SetMaxKd(PidType* pid, FloatType newMaxKd ) |
||
| 208 | { |
||
| 209 | if ( newMaxKd < MAX_KD_MIN ) |
||
| 210 | { |
||
| 211 | // no limit to Kd |
||
| 212 | newMaxKd = 0.0; |
||
| 213 | } |
||
| 214 | pid->MaxKd = newMaxKd; |
||
| 215 | } |
||
| 216 | |||
| 217 | /* Status Functions************************************************************ |
||
| 218 | * Just because you set the Kp=-1 doesn't mean it actually happened. these |
||
| 219 | * functions query the internal state of the PID. they're here for display |
||
| 220 | * purposes. this are the functions the PID Front-end uses for example |
||
| 221 | ******************************************************************************/ |
||
| 222 | FloatType PID_GetKp(PidType* pid) { |
||
| 223 | return pid->dispKp; |
||
| 224 | } |
||
| 225 | FloatType PID_GetKi(PidType* pid) { |
||
| 226 | return pid->dispKi; |
||
| 227 | } |
||
| 228 | FloatType PID_GetKd(PidType* pid) { |
||
| 229 | return pid->dispKd; |
||
| 230 | } |
||
| 2277 | linlun | 231 | FloatType PID_GetMin(PidType* pid) { |
| 232 | return pid->outMin; |
||
| 233 | } |
||
| 234 | FloatType PID_GetMax(PidType* pid) { |
||
| 235 | return pid->outMax; |
||
| 236 | } |
||
| 2262 | linlun | 237 | |
| 2283 | linlun | 238 | uint32_t PID_GetSampleTime(PidType* pid) { |
| 239 | return pid->SampleTime; |
||
| 240 | } |
||
| 241 | |||
| 2262 | linlun | 242 | PidModeType PID_GetMode(PidType* pid) { |
| 243 | return pid->mode; |
||
| 244 | } |
||
| 245 | |||
| 246 | PidDirectionType PID_GetDirection(PidType* pid) { |
||
| 247 | return pid->controllerDirection; |
||
| 248 | } |
||
| 249 | |||
| 250 | FloatType PID_GetPTerm(PidType* pid) |
||
| 251 | { |
||
| 252 | return pid->PTerm; |
||
| 253 | } |
||
| 254 | |||
| 255 | FloatType PID_GetITerm(PidType* pid) |
||
| 256 | { |
||
| 257 | return pid->ITerm; |
||
| 258 | } |
||
| 259 | |||
| 260 | FloatType PID_GetDTerm(PidType* pid) |
||
| 261 | { |
||
| 262 | return pid->DTerm; |
||
| 263 | } |
||
| 264 |