dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pid.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 #include "openpilot.h"
32 #include "physical_constants.h"
33 #include "misc_math.h"
34 #include "pid.h"
35 
37 static float deriv_tau = 7.9577e-3f;
38 
40 static float deriv_gamma = 1.0;
41 
48 float pid_apply(struct pid *pid, const float err)
49 {
50  float dT = pid->dT;
51 
52  if (pid->i == 0) {
53  // If Ki is zero, do not change the integrator. We do not reset to zero
54  // because sometimes the accumulator term is set externally
55  } else {
56  pid->iAccumulator += err * (pid->i * dT);
57  pid->iAccumulator = bound_sym(pid->iAccumulator, pid->iLim);
58  }
59 
60  // Calculate DT1 term
61  float diff = (err - pid->lastErr);
62  float dterm = 0;
63  pid->lastErr = err;
64  if(pid->d && dT)
65  {
66  dterm = pid->lastDer + dT / ( dT + deriv_tau) * ((diff * pid->d / dT) - pid->lastDer);
67  pid->lastDer = dterm; // ^ set constant to 1/(2*pi*f_cutoff)
68  } // 7.9577e-3 means 20 Hz f_cutoff
69 
70  return ((err * pid->p) + pid->iAccumulator + dterm);
71 }
72 
86 float pid_apply_antiwindup(struct pid *pid, const float err,
87  float min_bound, float max_bound, float aw_bound)
88 {
89  float dT = pid->dT;
90 
91  if (pid->i == 0) {
92  // If Ki is zero, do not change the integrator. We do not reset to zero
93  // because sometimes the accumulator term is set externally
94  } else {
95  if (aw_bound > 0) {
96  float p = bound_sym(err * pid->p, aw_bound) / aw_bound;
97  pid->iAccumulator += err * (pid->i * dT) * (1 - p*p);
98  } else {
99  pid->iAccumulator += err * (pid->i * dT);
100  }
101  }
102 
103  // Calculate DT1 term
104  float diff = (err - pid->lastErr);
105  float dterm = 0;
106  pid->lastErr = err;
107  if(pid->d && dT)
108  {
109  dterm = pid->lastDer + dT / ( dT + deriv_tau) * ((diff * pid->d / dT) - pid->lastDer);
110  pid->lastDer = dterm; // ^ set constant to 1/(2*pi*f_cutoff)
111  } // 7.9577e-3 means 20 Hz f_cutoff
112 
113  // Compute how much (if at all) the output is saturating
114  float ideal_output = ((err * pid->p) + pid->iAccumulator + dterm);
115  float saturation = 0;
116  if (ideal_output > max_bound) {
117  saturation = max_bound - ideal_output;
118  ideal_output = max_bound;
119  } else if (ideal_output < min_bound) {
120  saturation = min_bound - ideal_output;
121  ideal_output = min_bound;
122  }
123 
124  // Use Kt 10x Ki
125  pid->iAccumulator += saturation * (pid->i * 10.0f * dT);
126  pid->iAccumulator = bound_sym(pid->iAccumulator, pid->iLim);
127 
128  return ideal_output;
129 }
130 
141 float pid_apply_setpoint(struct pid *pid, struct pid_deadband *deadband, const float setpoint,
142  const float measured)
143 {
144  float dT = pid->dT;
145 
146  float err = setpoint - measured;
147  float err_d = (deriv_gamma * setpoint - measured);
148 
149  if(deadband && deadband->width > 0)
150  {
151  err = cubic_deadband(err, deadband->width, deadband->slope, deadband->cubic_weight,
152  deadband->integrated_response);
153  err_d = cubic_deadband(err_d, deadband->width, deadband->slope, deadband->cubic_weight,
154  deadband->integrated_response);
155  }
156 
157  if (pid->i == 0) {
158  // If Ki is zero, do not change the integrator. We do not reset to zero
159  // because sometimes the accumulator term is set externally
160  } else {
161  pid->iAccumulator += err * (pid->i * dT);
162  pid->iAccumulator = bound_sym(pid->iAccumulator, pid->iLim);
163  }
164 
165  // Calculate DT1 term,
166  float dterm = 0;
167  float diff = (err_d - pid->lastErr);
168  pid->lastErr = err_d;
169  if(pid->d && dT)
170  {
171  dterm = pid->lastDer + dT / ( dT + deriv_tau) * ((diff * pid->d / dT) - pid->lastDer);
172  pid->lastDer = dterm; // ^ set constant to 1/(2*pi*f_cutoff)
173  } // 7.9577e-3 means 20 Hz f_cutoff
174 
175  return ((err * pid->p) + pid->iAccumulator + dterm);
176 }
177 
188  struct pid_deadband *deadband, const float setpoint,
189  const float measured, float min_bound, float max_bound, float aw_bound)
190 {
191  float dT = pid->dT;
192 
193  float err = setpoint - measured;
194  float err_d = (deriv_gamma * setpoint - measured);
195 
196  if(deadband && deadband->width > 0)
197  {
198  err = cubic_deadband(err, deadband->width, deadband->slope, deadband->cubic_weight,
199  deadband->integrated_response);
200  err_d = cubic_deadband(err_d, deadband->width, deadband->slope, deadband->cubic_weight,
201  deadband->integrated_response);
202  }
203 
204  if (pid->i == 0) {
205  // If Ki is zero, do not change the integrator. We do not reset to zero
206  // because sometimes the accumulator term is set externally
207  } else {
208  if (aw_bound > 0) {
209  float p = bound_sym(err * pid->p, aw_bound) / aw_bound;
210  pid->iAccumulator += err * (pid->i * dT) * (1 - p*p);
211  } else {
212  pid->iAccumulator += err * (pid->i * dT);
213  }
214  pid->iAccumulator = bound_sym(pid->iAccumulator, pid->iLim);
215  }
216 
217  // Calculate DT1 term,
218  float dterm = 0;
219  float diff = (err_d - pid->lastErr);
220  pid->lastErr = err_d;
221  if(pid->d && dT)
222  {
223  dterm = pid->lastDer + dT / ( dT + deriv_tau) * ((diff * pid->d / dT) - pid->lastDer);
224  pid->lastDer = dterm; // ^ set constant to 1/(2*pi*f_cutoff)
225  } // 7.9577e-3 means 20 Hz f_cutoff
226 
227  // Compute how much (if at all) the output is saturating
228  float ideal_output = ((err * pid->p) + pid->iAccumulator + dterm);
229  float saturation = 0;
230  if (ideal_output > max_bound) {
231  saturation = max_bound - ideal_output;
232  ideal_output = max_bound;
233  } else if (ideal_output < min_bound) {
234  saturation = min_bound - ideal_output;
235  ideal_output = min_bound;
236  }
237 
238  if (pid->i == 0) {
239  // If Ki is zero, do not change the integrator.
240  } else {
241  pid->iAccumulator += saturation * (pid->i * dT);
242  pid->iAccumulator = bound_sym(pid->iAccumulator, pid->iLim);
243  }
244 
245  return ideal_output;
246 }
247 
252 void pid_zero(struct pid *pid)
253 {
254  if (!pid)
255  return;
256 
257  pid->iAccumulator = 0;
258  pid->lastErr = 0;
259  pid->lastDer = 0;
260 }
261 
267 void pid_configure_derivative(float cutoff, float g)
268 {
269  deriv_tau = 1.0f / (2 * PI * cutoff);
270  deriv_gamma = g;
271 }
272 
280 void pid_configure(struct pid *pid, float p, float i, float d, float iLim, float dT)
281 {
282  if (!pid)
283  return;
284 
285  pid->p = p;
286  pid->i = i;
287  pid->d = d;
288  pid->iLim = iLim;
289  pid->dT = dT;
290 }
291 
298 void pid_configure_deadband(struct pid_deadband *deadband, float width, float slope)
299 {
300  if(!deadband)
301  return;
302 
303  if(width < 0.1f)
304  {
305  // Below 0.1deg/s, we can assume that we don't want it.
306  // Also something something float zeroes...
307  deadband->width = deadband->slope = deadband->cubic_weight =
308  deadband->integrated_response = 0;
309  return;
310  }
311 
312  // Clamp slope to positive, otherwise it'll cause drama.
313  if(slope < 0.0f) slope = 0.0f;
314  else if(slope > 1.0f) slope = 1.0f;
315 
316  deadband->width = width;
317  deadband->slope = slope;
318 
319  cubic_deadband_setup(width, slope, &deadband->cubic_weight,
320  &deadband->integrated_response);
321 }
322 
float pid_apply_setpoint_antiwindup(struct pid *pid, struct pid_deadband *deadband, const float setpoint, const float measured, float min_bound, float max_bound, float aw_bound)
Definition: pid.c:187
float cubic_deadband(float in, float w, float b, float m, float r)
Definition: misc_math.c:246
float p
Definition: pid.h:43
float iAccumulator
Definition: pid.h:50
static float deriv_gamma
Store the setpoint weight to apply for the derivative term.
Definition: pid.c:40
float cubic_weight
Definition: pid.h:37
void pid_configure(struct pid *pid, float p, float i, float d, float iLim, float dT)
Definition: pid.c:280
void pid_configure_deadband(struct pid_deadband *deadband, float width, float slope)
Definition: pid.c:298
#define PI
Definition: mgrs.c:136
float i
Definition: pid.h:44
float width
Definition: pid.h:35
uint8_t i
Definition: msp_messages.h:97
float bound_sym(float val, float range)
Bound input value within range (plus or minus)
Definition: misc_math.c:50
float iLim
Definition: pid.h:46
uint8_t d
Definition: msp_messages.h:98
float d
Definition: pid.h:45
void pid_zero(struct pid *pid)
Definition: pid.c:252
float lastDer
Definition: pid.h:52
void cubic_deadband_setup(float w, float b, float *m, float *r)
Definition: misc_math.c:266
float pid_apply(struct pid *pid, const float err)
Methods to use the pid structures.
Definition: pid.c:48
tuple f
Definition: px_mkfw.py:81
Includes PiOS and core architecture components.
float integrated_response
Definition: pid.h:38
float pid_apply_setpoint(struct pid *pid, struct pid_deadband *deadband, const float setpoint, const float measured)
Definition: pid.c:141
float pid_apply_antiwindup(struct pid *pid, const float err, float min_bound, float max_bound, float aw_bound)
Definition: pid.c:86
void pid_configure_derivative(float cutoff, float g)
Configure the common terms that alter ther derivative.
Definition: pid.c:267
uint8_t p
Definition: msp_messages.h:96
Definition: pid.h:42
float dT
Definition: pid.h:48
static float deriv_tau
Store the shared time constant for the derivative cutoff.
Definition: pid.c:37
float lastErr
Definition: pid.h:51
float slope
Definition: pid.h:36
PID Control algorithms.