2 /// Copyright (c) Titan Robotics Club. All rights reserved.
4 /// <module name="TrcPIDCtrl.h" />
7 /// This module contains the definition and implementation of the
12 /// Environment: Wind River C++ for National Instrument cRIO based Robot.
22 #define MOD_ID MOD_PIDCTRL
26 #define MOD_NAME "TrcPIDCtrl"
31 #define PIDCTRLO_INVERSE 0x00000001
32 #define PIDCTRLO_ABS_SETPT 0x00000002
33 #define PIDCTRLO_SPEED_CTRL 0x00000004
34 #define PIDCTRLO_NO_OSCILLATE 0x00000008
39 * This abstract class defines the PIDInput object. The object is
40 * a callback interface. It is not meant to be created as an object.
41 * Instead, it should be inherited by a subclass who needs to provide
42 * input data to a PID controller.
48 * This function is provided by the subclass to provide input to the PID
51 * @param pidCtrl Points to the PIDCtrl object that requires input.
61 * This class defines and implements the TrcPIDCtrl object. This object
62 * replaces the PIDController object from the WPI library. The PIDController
63 * object in the WPI library is not flexible enough because it dealt with
64 * PID input and PID output directly. In contrast, the TrcPIDCtrl object is
65 * a simple primitive that calculates the PID output according to the given
66 * PID input. So it is agnostic to the kind of input, output or even how the
67 * calculated output is used. This is especially important because the
68 * TrcPIDDrive object is going to combine three PID controllers to
69 * calculate the drive output. One PID controller is for driving straight
70 * distance in the X direction, one PID controller is for driving straight
71 * distance in the Y direction, and one for rotation. In addition, the WPI
72 * PIDController is creating a periodic loop per controller. In the TRC
73 * library, we will do periodic loop at a higher level in the TrcPIDDrive
84 UINT32 m_settlingTime;
85 UINT32 m_pidCtrlOptions;
92 UINT32 m_startSettling;
98 * Constructor: Create an instance of the TrcPIDCtrl object.
100 * @param idString Identifying the PID controller, mainly for logging
102 * @param Kp Specifies the proportional coefficient.
103 * @param Ki Specifies the integral coefficient.
104 * @param Kd Specifies the derivative coefficient.
105 * @param tolerance Specifies the on-target tolerance.
106 * @param settlingTime Specifes the on-target settling time in msec.
107 * @param pidCtrlOptions Specifies the option flags.
108 * @param initialOutput Specifies the initial prevOutput value,
109 * applicable only in speed control mode.
116 float tolerance = 0.0,
117 UINT32 settlingTime = 0,
118 UINT32 pidCtrlOptions = 0,
119 float initialOutput = 0.0
123 , m_tolerance(tolerance)
124 , m_settlingTime(settlingTime)
125 , m_pidCtrlOptions(pidCtrlOptions)
134 , m_prevOutput(initialOutput)
137 TEnterMsg(("ID=%s,Kp=%f,Ki=%f,Kd=%f,tolerance=%f,settlingTime=%d,"
138 "options=%x,initialOuptut=%f",
139 idString, Kp, Ki, Kd, tolerance, settlingTime,
140 pidCtrlOptions, initialOutput));
142 #ifdef _LOGDATA_PIDCTRL
143 DataLogger *dataLogger = DataLogger::GetInstance();
144 dataLogger->AddDataPoint(MOD_NAME, idString, "setPt", "%f",
145 DataFloat, &m_setPoint);
146 dataLogger->AddDataPoint(MOD_NAME, idString, "output", "%f",
147 DataFloat, &m_prevOutput);
148 dataLogger->AddDataPoint(MOD_NAME, idString, "error", "%f",
149 DataFloat, &m_prevError);
150 dataLogger->AddDataPoint(MOD_NAME, idString, "totalError", "%f",
151 DataFloat, &m_totalError);
158 * Destructor: Destroy an instance of the TrcPIDCtrl object.
170 * This function resets the PID controller.
188 * This function gets the proportional constant.
190 * @return Proportional coefficient constant.
199 TExitMsg(("=%f", m_Kp));
204 * This function gets the integral constant.
206 * @return Integral coefficient constant.
215 TExitMsg(("=%f", m_Ki));
220 * This function gets the differential constant.
222 * @return Differential coefficient constant.
231 TExitMsg(("=%f", m_Kd));
236 * This function gets the PID controller constants.
238 * @param pKp Points to the variable to hold the proportional constant.
239 * @param pKi Points to the variable to hold the integral constant.
240 * @param pKd Points to the variable to hold the differential constant.
250 TEnterMsg(("pKp=%p,pKi=%p,pKd=%p", pKp, pKi, pKd));
267 TExitMsg(("Kp=%f,Ki=%f,Kd=%f", m_Kp, m_Ki, m_Kd));
272 * This function sets the PID controller constants.
274 * @param Kp Specifies the proportional constant.
275 * @param Ki Specifies the integral constant.
276 * @param Kd Specifies the differential constant.
286 TEnterMsg(("Kp=%f,Ki=%f,Kd=%f", Kp, Ki, Kd));
297 * This function gets the last error.
299 * @return the last error.
308 TExitMsg(("=%f", m_prevError));
313 * This function gets the PID controller setpoint.
315 * @return the current setpoint.
324 TExitMsg(("=%f", m_setPoint));
329 * This function sets the PID controller setpoint.
331 * @param setPoint Specifies the target setpoint.
332 * @param currInput Specifies the current input value.
341 TEnterMsg(("setpt=%f,currInput=%f", setPoint, currInput));
343 if (!(m_pidCtrlOptions & PIDCTRLO_ABS_SETPT))
345 setPoint += currInput;
348 if (m_maxInput > m_minInput)
350 if (setPoint > m_maxInput)
352 m_setPoint = m_maxInput;
354 else if (setPoint < m_minInput)
356 m_setPoint = m_minInput;
360 m_setPoint = setPoint;
365 m_setPoint = setPoint;
367 m_prevError = m_setPoint - currInput;
369 m_startSettling = GetMsecTime();
376 * This function determines if we are on target by checking if the
377 * previous error is within target tolerance and remain within tolerance
378 * for at least the settling period.
380 * @return True if we are on target, false otherwise.
387 bool fOnTarget = false;
392 if (m_pidCtrlOptions & PIDCTRLO_NO_OSCILLATE)
394 if (fabs(m_prevError) < m_tolerance)
399 else if (fabs(m_prevError) > m_tolerance)
401 m_startSettling = GetMsecTime();
403 else if (GetMsecTime() - m_startSettling >= m_settlingTime)
408 TExitMsg(("=%x", fOnTarget));
413 * This function sets the minimum and maximum values expected from the
416 * @param minInput Specifies the minimum value.
417 * @param maxInput Specifies the maximum value.
426 TEnterMsg(("min=%f,max=%f", minInput, maxInput));
428 m_minInput = minInput;
429 m_maxInput = maxInput;
436 * This function limits the minimum and maximum values of the output.
438 * @param minOutput Specifies the minimum value.
439 * @param maxOutput Specifies the maximum value.
448 TEnterMsg(("min=%f,max=%f", minOutput, maxOutput));
450 m_minOutput = minOutput;
451 m_maxOutput = maxOutput;
458 * This function returns the calculated PID output according to the input
459 * value from the input source.
461 * @param currInput Specifies the current input value.
463 * @return Returns the PID control source input value.
475 TEnterMsg(("currInput=%f", currInput));
477 error = m_setPoint - currInput;
478 if (m_pidCtrlOptions & PIDCTRLO_INVERSE)
483 adjTotalError = m_Ki*(m_totalError + error);
484 if ((adjTotalError > m_minOutput) && (adjTotalError < m_maxOutput))
486 m_totalError += error;
489 output = m_Kp*error + m_Ki*m_totalError + m_Kd*(error - m_prevError);
491 if (m_pidCtrlOptions & PIDCTRLO_SPEED_CTRL)
493 output += m_prevOutput;
496 output = BOUND(output, m_minOutput, m_maxOutput);
499 m_prevOutput = output;
501 TExitMsg(("=%f", output));
505 }; //class TrcPIDCtrl
507 #endif //ifndef _TRCPIDCTRL_H