Subversion Repositories HomeAutomation

Rev

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