WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
PIDController.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <algorithm>
8#include <limits>
9#include <type_traits>
10
11#include <gcem.hpp>
12
15#include "wpi/units/time.hpp"
20
21namespace wpi::math {
22
23/**
24 * Implements a PID control loop.
25 */
27 : public wpi::util::Sendable,
28 public wpi::util::SendableHelper<PIDController> {
29 public:
30 /**
31 * Allocates a PIDController with the given constants for Kp, Ki, and Kd.
32 *
33 * @param Kp The proportional coefficient. Must be >= 0.
34 * @param Ki The integral coefficient. Must be >= 0.
35 * @param Kd The derivative coefficient. Must be >= 0.
36 * @param period The period between controller updates in seconds. The
37 * default is 20 milliseconds. Must be positive.
38 */
39 constexpr PIDController(double Kp, double Ki, double Kd,
40 wpi::units::second_t period = 20_ms)
41 : m_Kp(Kp), m_Ki(Ki), m_Kd(Kd), m_period(period) {
42 bool invalidGains = false;
43 if (Kp < 0.0) {
45 "Kp must be a non-negative number, got {}!", Kp);
46 invalidGains = true;
47 }
48 if (Ki < 0.0) {
50 "Ki must be a non-negative number, got {}!", Ki);
51 invalidGains = true;
52 }
53 if (Kd < 0.0) {
55 "Kd must be a non-negative number, got {}!", Kd);
56 invalidGains = true;
57 }
58 if (invalidGains) {
59 m_Kp = 0.0;
60 m_Ki = 0.0;
61 m_Kd = 0.0;
62 wpi::math::MathSharedStore::ReportWarning("PID gains defaulted to 0.");
63 }
64
65 if (period <= 0_s) {
67 "Controller period must be a positive number, got {}!",
68 period.value());
69 m_period = 20_ms;
71 "Controller period defaulted to 20ms.");
72 }
73 if (!std::is_constant_evaluated()) {
74 ++instances;
75
77 std::to_string(instances));
78 wpi::util::SendableRegistry::Add(this, "PIDController", instances);
79 }
80 }
81
82 constexpr ~PIDController() override = default;
83
84 constexpr PIDController(const PIDController&) = default;
85 constexpr PIDController& operator=(const PIDController&) = default;
86 constexpr PIDController(PIDController&&) = default;
87 constexpr PIDController& operator=(PIDController&&) = default;
88
89 /**
90 * Sets the PID Controller gain parameters.
91 *
92 * Sets the proportional, integral, and differential coefficients.
93 *
94 * @param Kp The proportional coefficient. Must be >= 0.
95 * @param Ki The integral coefficient. Must be >= 0.
96 * @param Kd The differential coefficient. Must be >= 0.
97 */
98 constexpr void SetPID(double Kp, double Ki, double Kd) {
99 m_Kp = Kp;
100 m_Ki = Ki;
101 m_Kd = Kd;
102 }
103
104 /**
105 * Sets the proportional coefficient of the PID controller gain.
106 *
107 * @param Kp The proportional coefficient. Must be >= 0.
108 */
109 constexpr void SetP(double Kp) { m_Kp = Kp; }
110
111 /**
112 * Sets the integral coefficient of the PID controller gain.
113 *
114 * @param Ki The integral coefficient. Must be >= 0.
115 */
116 constexpr void SetI(double Ki) { m_Ki = Ki; }
117
118 /**
119 * Sets the differential coefficient of the PID controller gain.
120 *
121 * @param Kd The differential coefficient. Must be >= 0.
122 */
123 constexpr void SetD(double Kd) { m_Kd = Kd; }
124
125 /**
126 * Sets the IZone range. When the absolute value of the position error is
127 * greater than IZone, the total accumulated error will reset to zero,
128 * disabling integral gain until the absolute value of the position error is
129 * less than IZone. This is used to prevent integral windup. Must be
130 * non-negative. Passing a value of zero will effectively disable integral
131 * gain. Passing a value of infinity disables IZone functionality.
132 *
133 * @param iZone Maximum magnitude of error to allow integral control. Must be
134 * >= 0.
135 */
136 constexpr void SetIZone(double iZone) {
137 if (std::is_constant_evaluated() && iZone < 0) {
139 "IZone must be a non-negative number, got {}!", iZone);
140 }
141 m_iZone = iZone;
142 }
143
144 /**
145 * Gets the proportional coefficient.
146 *
147 * @return proportional coefficient
148 */
149 constexpr double GetP() const { return m_Kp; }
150
151 /**
152 * Gets the integral coefficient.
153 *
154 * @return integral coefficient
155 */
156 constexpr double GetI() const { return m_Ki; }
157
158 /**
159 * Gets the differential coefficient.
160 *
161 * @return differential coefficient
162 */
163 constexpr double GetD() const { return m_Kd; }
164
165 /**
166 * Get the IZone range.
167 *
168 * @return Maximum magnitude of error to allow integral control.
169 */
170 constexpr double GetIZone() const { return m_iZone; }
171
172 /**
173 * Gets the period of this controller.
174 *
175 * @return The period of the controller.
176 */
177 constexpr wpi::units::second_t GetPeriod() const { return m_period; }
178
179 /**
180 * Gets the error tolerance of this controller. Defaults to 0.05.
181 *
182 * @return The error tolerance of the controller.
183 */
184 constexpr double GetErrorTolerance() const { return m_errorTolerance; }
185
186 /**
187 * Gets the error derivative tolerance of this controller. Defaults to ∞.
188 *
189 * @return The error derivative tolerance of the controller.
190 */
191 constexpr double GetErrorDerivativeTolerance() const {
192 return m_errorDerivativeTolerance;
193 }
194
195 /**
196 * Gets the position tolerance of this controller.
197 *
198 * @return The position tolerance of the controller.
199 * @deprecated Use GetErrorTolerance() instead.
200 */
201 [[deprecated("Use the GetErrorTolerance method instead.")]]
202 constexpr double GetPositionTolerance() const {
203 return m_errorTolerance;
204 }
205
206 /**
207 * Gets the velocity tolerance of this controller.
208 *
209 * @return The velocity tolerance of the controller.
210 * @deprecated Use GetErrorDerivativeTolerance() instead.
211 */
212 [[deprecated("Use the GetErrorDerivativeTolerance method instead.")]]
213 constexpr double GetVelocityTolerance() const {
214 return m_errorDerivativeTolerance;
215 }
216
217 /**
218 * Gets the accumulated error used in the integral calculation of this
219 * controller.
220 *
221 * @return The accumulated error of this controller.
222 */
223 constexpr double GetAccumulatedError() const { return m_totalError; }
224
225 /**
226 * Sets the setpoint for the PIDController.
227 *
228 * @param setpoint The desired setpoint.
229 */
230 constexpr void SetSetpoint(double setpoint) {
231 m_setpoint = setpoint;
232 m_haveSetpoint = true;
233
234 if (m_continuous) {
235 double errorBound = (m_maximumInput - m_minimumInput) / 2.0;
236 m_error =
237 InputModulus(m_setpoint - m_measurement, -errorBound, errorBound);
238 } else {
239 m_error = m_setpoint - m_measurement;
240 }
241
242 m_errorDerivative = (m_error - m_prevError) / m_period.value();
243 }
244
245 /**
246 * Returns the current setpoint of the PIDController.
247 *
248 * @return The current setpoint.
249 */
250 constexpr double GetSetpoint() const { return m_setpoint; }
251
252 /**
253 * Returns true if the error is within the tolerance of the setpoint.
254 * The error tolerance defauls to 0.05, and the error derivative tolerance
255 * defaults to ∞.
256 *
257 * This will return false until at least one input value has been computed.
258 */
259 constexpr bool AtSetpoint() const {
260 return m_haveMeasurement && m_haveSetpoint &&
261 gcem::abs(m_error) < m_errorTolerance &&
262 gcem::abs(m_errorDerivative) < m_errorDerivativeTolerance;
263 }
264
265 /**
266 * Enables continuous input.
267 *
268 * Rather then using the max and min input range as constraints, it considers
269 * them to be the same point and automatically calculates the shortest route
270 * to the setpoint.
271 *
272 * @param minimumInput The minimum value expected from the input.
273 * @param maximumInput The maximum value expected from the input.
274 */
275 constexpr void EnableContinuousInput(double minimumInput,
276 double maximumInput) {
277 m_continuous = true;
278 m_minimumInput = minimumInput;
279 m_maximumInput = maximumInput;
280 }
281
282 /**
283 * Disables continuous input.
284 */
285 constexpr void DisableContinuousInput() { m_continuous = false; }
286
287 /**
288 * Returns true if continuous input is enabled.
289 */
290 constexpr bool IsContinuousInputEnabled() const { return m_continuous; }
291
292 /**
293 * Sets the minimum and maximum contributions of the integral term.
294 *
295 * The internal integrator is clamped so that the integral term's contribution
296 * to the output stays between minimumIntegral and maximumIntegral. This
297 * prevents integral windup.
298 *
299 * @param minimumIntegral The minimum contribution of the integral term.
300 * @param maximumIntegral The maximum contribution of the integral term.
301 */
302 constexpr void SetIntegratorRange(double minimumIntegral,
303 double maximumIntegral) {
304 m_minimumIntegral = minimumIntegral;
305 m_maximumIntegral = maximumIntegral;
306 }
307
308 /**
309 * Sets the error which is considered tolerable for use with AtSetpoint().
310 *
311 * @param errorTolerance error which is tolerable.
312 * @param errorDerivativeTolerance error derivative which is tolerable.
313 */
314 constexpr void SetTolerance(double errorTolerance,
315 double errorDerivativeTolerance =
316 std::numeric_limits<double>::infinity()) {
317 m_errorTolerance = errorTolerance;
318 m_errorDerivativeTolerance = errorDerivativeTolerance;
319 }
320
321 /**
322 * Returns the difference between the setpoint and the measurement.
323 */
324 constexpr double GetError() const { return m_error; }
325
326 /**
327 * Returns the error derivative.
328 */
329 constexpr double GetErrorDerivative() const { return m_errorDerivative; }
330
331 /**
332 * Returns the difference between the setpoint and the measurement.
333 * @deprecated Use GetError() instead.
334 */
335 [[deprecated("Use GetError method instead.")]]
336 constexpr double GetPositionError() const {
337 return m_error;
338 }
339
340 /**
341 * Returns the velocity error.
342 * @deprecated Use GetErrorDerivative() instead.
343 */
344 [[deprecated("Use GetErrorDerivative method instead.")]]
345 constexpr double GetVelocityError() const {
346 return m_errorDerivative;
347 }
348
349 /**
350 * Returns the next output of the PID controller.
351 *
352 * @param measurement The current measurement of the process variable.
353 */
354 constexpr double Calculate(double measurement) {
355 m_measurement = measurement;
356 m_prevError = m_error;
357 m_haveMeasurement = true;
358
359 if (m_continuous) {
360 double errorBound = (m_maximumInput - m_minimumInput) / 2.0;
361 m_error =
362 InputModulus(m_setpoint - m_measurement, -errorBound, errorBound);
363 } else {
364 m_error = m_setpoint - m_measurement;
365 }
366
367 m_errorDerivative = (m_error - m_prevError) / m_period.value();
368
369 // If the absolute value of the position error is outside of IZone, reset
370 // the total error
371 if (gcem::abs(m_error) > m_iZone) {
372 m_totalError = 0;
373 } else if (m_Ki != 0) {
374 m_totalError =
375 std::clamp(m_totalError + m_error * m_period.value(),
376 m_minimumIntegral / m_Ki, m_maximumIntegral / m_Ki);
377 }
378
379 return m_Kp * m_error + m_Ki * m_totalError + m_Kd * m_errorDerivative;
380 }
381
382 /**
383 * Returns the next output of the PID controller.
384 *
385 * @param measurement The current measurement of the process variable.
386 * @param setpoint The new setpoint of the controller.
387 */
388 constexpr double Calculate(double measurement, double setpoint) {
389 m_setpoint = setpoint;
390 m_haveSetpoint = true;
391 return Calculate(measurement);
392 }
393
394 /**
395 * Reset the previous error, the integral term, and disable the controller.
396 */
397 constexpr void Reset() {
398 m_error = 0;
399 m_prevError = 0;
400 m_totalError = 0;
401 m_errorDerivative = 0;
402 m_haveMeasurement = false;
403 }
404
406
407 private:
408 // Factor for "proportional" control
409 double m_Kp;
410
411 // Factor for "integral" control
412 double m_Ki;
413
414 // Factor for "derivative" control
415 double m_Kd;
416
417 // The error range where "integral" control applies
418 double m_iZone = std::numeric_limits<double>::infinity();
419
420 // The period (in seconds) of the control loop running this controller
421 wpi::units::second_t m_period;
422
423 double m_maximumIntegral = 1.0;
424
425 double m_minimumIntegral = -1.0;
426
427 double m_maximumInput = 0;
428
429 double m_minimumInput = 0;
430
431 // Do the endpoints wrap around? eg. Absolute encoder
432 bool m_continuous = false;
433
434 // The error at the time of the most recent call to Calculate()
435 double m_error = 0;
436 double m_errorDerivative = 0;
437
438 // The error at the time of the second-most-recent call to Calculate() (used
439 // to compute velocity)
440 double m_prevError = 0;
441
442 // The sum of the errors for use in the integral calc
443 double m_totalError = 0;
444
445 // The error that is considered at setpoint.
446 double m_errorTolerance = 0.05;
447 double m_errorDerivativeTolerance = std::numeric_limits<double>::infinity();
448
449 double m_setpoint = 0;
450 double m_measurement = 0;
451
452 bool m_haveSetpoint = false;
453 bool m_haveMeasurement = false;
454
455 // Usage reporting instances
456 inline static int instances = 0;
457};
458
459} // namespace wpi::math
#define WPILIB_DLLEXPORT
Definition SymbolExports.hpp:36
static void ReportUsage(std::string_view resource, std::string_view data)
Definition MathShared.hpp:61
static void ReportError(const S &format, Args &&... args)
Definition MathShared.hpp:48
static void ReportWarning(const S &format, Args &&... args)
Definition MathShared.hpp:57
constexpr double GetIZone() const
Get the IZone range.
Definition PIDController.hpp:170
constexpr ~PIDController() override=default
constexpr double GetVelocityTolerance() const
Gets the velocity tolerance of this controller.
Definition PIDController.hpp:213
constexpr wpi::units::second_t GetPeriod() const
Gets the period of this controller.
Definition PIDController.hpp:177
constexpr void SetP(double Kp)
Sets the proportional coefficient of the PID controller gain.
Definition PIDController.hpp:109
constexpr double GetPositionError() const
Returns the difference between the setpoint and the measurement.
Definition PIDController.hpp:336
constexpr double GetErrorTolerance() const
Gets the error tolerance of this controller.
Definition PIDController.hpp:184
constexpr void SetIZone(double iZone)
Sets the IZone range.
Definition PIDController.hpp:136
constexpr double GetPositionTolerance() const
Gets the position tolerance of this controller.
Definition PIDController.hpp:202
constexpr double Calculate(double measurement)
Returns the next output of the PID controller.
Definition PIDController.hpp:354
constexpr double GetSetpoint() const
Returns the current setpoint of the PIDController.
Definition PIDController.hpp:250
constexpr PIDController(PIDController &&)=default
constexpr bool IsContinuousInputEnabled() const
Returns true if continuous input is enabled.
Definition PIDController.hpp:290
constexpr double GetD() const
Gets the differential coefficient.
Definition PIDController.hpp:163
constexpr PIDController & operator=(PIDController &&)=default
constexpr double Calculate(double measurement, double setpoint)
Returns the next output of the PID controller.
Definition PIDController.hpp:388
constexpr void Reset()
Reset the previous error, the integral term, and disable the controller.
Definition PIDController.hpp:397
constexpr void SetI(double Ki)
Sets the integral coefficient of the PID controller gain.
Definition PIDController.hpp:116
constexpr double GetError() const
Returns the difference between the setpoint and the measurement.
Definition PIDController.hpp:324
constexpr double GetAccumulatedError() const
Gets the accumulated error used in the integral calculation of this controller.
Definition PIDController.hpp:223
constexpr double GetVelocityError() const
Returns the velocity error.
Definition PIDController.hpp:345
constexpr void SetTolerance(double errorTolerance, double errorDerivativeTolerance=std::numeric_limits< double >::infinity())
Sets the error which is considered tolerable for use with AtSetpoint().
Definition PIDController.hpp:314
constexpr double GetErrorDerivativeTolerance() const
Gets the error derivative tolerance of this controller.
Definition PIDController.hpp:191
constexpr double GetP() const
Gets the proportional coefficient.
Definition PIDController.hpp:149
constexpr PIDController & operator=(const PIDController &)=default
constexpr void SetPID(double Kp, double Ki, double Kd)
Sets the PID Controller gain parameters.
Definition PIDController.hpp:98
constexpr double GetErrorDerivative() const
Returns the error derivative.
Definition PIDController.hpp:329
constexpr PIDController(double Kp, double Ki, double Kd, wpi::units::second_t period=20_ms)
Allocates a PIDController with the given constants for Kp, Ki, and Kd.
Definition PIDController.hpp:39
constexpr void EnableContinuousInput(double minimumInput, double maximumInput)
Enables continuous input.
Definition PIDController.hpp:275
constexpr double GetI() const
Gets the integral coefficient.
Definition PIDController.hpp:156
constexpr void SetD(double Kd)
Sets the differential coefficient of the PID controller gain.
Definition PIDController.hpp:123
constexpr void DisableContinuousInput()
Disables continuous input.
Definition PIDController.hpp:285
constexpr void SetSetpoint(double setpoint)
Sets the setpoint for the PIDController.
Definition PIDController.hpp:230
void InitSendable(wpi::util::SendableBuilder &builder) override
Initializes this Sendable object.
constexpr PIDController(const PIDController &)=default
constexpr void SetIntegratorRange(double minimumIntegral, double maximumIntegral)
Sets the minimum and maximum contributions of the integral term.
Definition PIDController.hpp:302
constexpr bool AtSetpoint() const
Returns true if the error is within the tolerance of the setpoint.
Definition PIDController.hpp:259
Helper class for building Sendable dashboard representations.
Definition SendableBuilder.hpp:21
A helper class for use with objects that add themselves to SendableRegistry.
Definition SendableHelper.hpp:21
Interface for Sendable objects.
Definition Sendable.hpp:16
static void Add(Sendable *sendable, std::string_view name)
Adds an object to the registry.
constexpr T abs(const T x) noexcept
Compile-time absolute value function.
Definition abs.hpp:40
Definition LinearSystem.hpp:20
constexpr T InputModulus(T input, T minimumInput, T maximumInput)
Returns modulus of input.
Definition MathUtil.hpp:205