WPILibC++ 2024.1.1-beta-4
ProfiledPIDController.h
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 <cmath>
9#include <functional>
10#include <limits>
11
12#include <wpi/SymbolExports.h>
16
17#include "frc/MathUtil.h"
20#include "units/time.h"
21
22namespace frc {
23namespace detail {
26} // namespace detail
27
28/**
29 * Implements a PID control loop whose setpoint is constrained by a trapezoid
30 * profile.
31 */
32template <class Distance>
34 : public wpi::Sendable,
35 public wpi::SendableHelper<ProfiledPIDController<Distance>> {
36 public:
38 using Velocity =
46
47 /**
48 * Allocates a ProfiledPIDController with the given constants for Kp, Ki, and
49 * Kd. Users should call reset() when they first start running the controller
50 * to avoid unwanted behavior.
51 *
52 * @param Kp The proportional coefficient.
53 * @param Ki The integral coefficient.
54 * @param Kd The derivative coefficient.
55 * @param constraints Velocity and acceleration constraints for goal.
56 * @param period The period between controller updates in seconds. The
57 * default is 20 milliseconds.
58 */
59 ProfiledPIDController(double Kp, double Ki, double Kd,
60 Constraints constraints, units::second_t period = 20_ms)
61 : m_controller{Kp, Ki, Kd, period},
62 m_constraints{constraints},
63 m_profile{m_constraints} {
67 wpi::SendableRegistry::Add(this, "ProfiledPIDController", instances);
68 }
69
70 ~ProfiledPIDController() override = default;
71
76
77 /**
78 * Sets the PID Controller gain parameters.
79 *
80 * Sets the proportional, integral, and differential coefficients.
81 *
82 * @param Kp Proportional coefficient
83 * @param Ki Integral coefficient
84 * @param Kd Differential coefficient
85 */
86 void SetPID(double Kp, double Ki, double Kd) {
87 m_controller.SetPID(Kp, Ki, Kd);
88 }
89
90 /**
91 * Sets the proportional coefficient of the PID controller gain.
92 *
93 * @param Kp proportional coefficient
94 */
95 void SetP(double Kp) { m_controller.SetP(Kp); }
96
97 /**
98 * Sets the integral coefficient of the PID controller gain.
99 *
100 * @param Ki integral coefficient
101 */
102 void SetI(double Ki) { m_controller.SetI(Ki); }
103
104 /**
105 * Sets the differential coefficient of the PID controller gain.
106 *
107 * @param Kd differential coefficient
108 */
109 void SetD(double Kd) { m_controller.SetD(Kd); }
110
111 /**
112 * Sets the IZone range. When the absolute value of the position error is
113 * greater than IZone, the total accumulated error will reset to zero,
114 * disabling integral gain until the absolute value of the position error is
115 * less than IZone. This is used to prevent integral windup. Must be
116 * non-negative. Passing a value of zero will effectively disable integral
117 * gain. Passing a value of infinity disables IZone functionality.
118 *
119 * @param iZone Maximum magnitude of error to allow integral control.
120 */
121 void SetIZone(double iZone) { m_controller.SetIZone(iZone); }
122
123 /**
124 * Gets the proportional coefficient.
125 *
126 * @return proportional coefficient
127 */
128 double GetP() const { return m_controller.GetP(); }
129
130 /**
131 * Gets the integral coefficient.
132 *
133 * @return integral coefficient
134 */
135 double GetI() const { return m_controller.GetI(); }
136
137 /**
138 * Gets the differential coefficient.
139 *
140 * @return differential coefficient
141 */
142 double GetD() const { return m_controller.GetD(); }
143
144 /**
145 * Get the IZone range.
146 *
147 * @return Maximum magnitude of error to allow integral control.
148 */
149 double GetIZone() const { return m_controller.GetIZone(); }
150
151 /**
152 * Gets the period of this controller.
153 *
154 * @return The period of the controller.
155 */
156 units::second_t GetPeriod() const { return m_controller.GetPeriod(); }
157
158 /**
159 * Gets the position tolerance of this controller.
160 *
161 * @return The position tolerance of the controller.
162 */
163 double GetPositionTolerance() const {
164 return m_controller.GetPositionTolerance();
165 }
166
167 /**
168 * Gets the velocity tolerance of this controller.
169 *
170 * @return The velocity tolerance of the controller.
171 */
172 double GetVelocityTolerance() const {
173 return m_controller.GetVelocityTolerance();
174 }
175
176 /**
177 * Sets the goal for the ProfiledPIDController.
178 *
179 * @param goal The desired unprofiled setpoint.
180 */
181 void SetGoal(State goal) { m_goal = goal; }
182
183 /**
184 * Sets the goal for the ProfiledPIDController.
185 *
186 * @param goal The desired unprofiled setpoint.
187 */
188 void SetGoal(Distance_t goal) { m_goal = {goal, Velocity_t{0}}; }
189
190 /**
191 * Gets the goal for the ProfiledPIDController.
192 */
193 State GetGoal() const { return m_goal; }
194
195 /**
196 * Returns true if the error is within the tolerance of the error.
197 *
198 * This will return false until at least one input value has been computed.
199 */
200 bool AtGoal() const { return AtSetpoint() && m_goal == m_setpoint; }
201
202 /**
203 * Set velocity and acceleration constraints for goal.
204 *
205 * @param constraints Velocity and acceleration constraints for goal.
206 */
207 void SetConstraints(Constraints constraints) {
208 m_constraints = constraints;
209 m_profile = TrapezoidProfile<Distance>{m_constraints};
210 }
211
212 /**
213 * Get the velocity and acceleration constraints for this controller.
214 * @return Velocity and acceleration constraints.
215 */
216 Constraints GetConstraints() { return m_constraints; }
217
218 /**
219 * Returns the current setpoint of the ProfiledPIDController.
220 *
221 * @return The current setpoint.
222 */
223 State GetSetpoint() const { return m_setpoint; }
224
225 /**
226 * Returns true if the error is within the tolerance of the error.
227 *
228 * Currently this just reports on target as the actual value passes through
229 * the setpoint. Ideally it should be based on being within the tolerance for
230 * some period of time.
231 *
232 * This will return false until at least one input value has been computed.
233 */
234 bool AtSetpoint() const { return m_controller.AtSetpoint(); }
235
236 /**
237 * Enables continuous input.
238 *
239 * Rather then using the max and min input range as constraints, it considers
240 * them to be the same point and automatically calculates the shortest route
241 * to the setpoint.
242 *
243 * @param minimumInput The minimum value expected from the input.
244 * @param maximumInput The maximum value expected from the input.
245 */
246 void EnableContinuousInput(Distance_t minimumInput, Distance_t maximumInput) {
247 m_controller.EnableContinuousInput(minimumInput.value(),
248 maximumInput.value());
249 m_minimumInput = minimumInput;
250 m_maximumInput = maximumInput;
251 }
252
253 /**
254 * Disables continuous input.
255 */
257
258 /**
259 * Sets the minimum and maximum values for the integrator.
260 *
261 * When the cap is reached, the integrator value is added to the controller
262 * output rather than the integrator value times the integral gain.
263 *
264 * @param minimumIntegral The minimum value of the integrator.
265 * @param maximumIntegral The maximum value of the integrator.
266 */
267 void SetIntegratorRange(double minimumIntegral, double maximumIntegral) {
268 m_controller.SetIntegratorRange(minimumIntegral, maximumIntegral);
269 }
270
271 /**
272 * Sets the error which is considered tolerable for use with
273 * AtSetpoint().
274 *
275 * @param positionTolerance Position error which is tolerable.
276 * @param velocityTolerance Velocity error which is tolerable.
277 */
278 void SetTolerance(Distance_t positionTolerance,
279 Velocity_t velocityTolerance = Velocity_t{
280 std::numeric_limits<double>::infinity()}) {
281 m_controller.SetTolerance(positionTolerance.value(),
282 velocityTolerance.value());
283 }
284
285 /**
286 * Returns the difference between the setpoint and the measurement.
287 *
288 * @return The error.
289 */
291 return Distance_t{m_controller.GetPositionError()};
292 }
293
294 /**
295 * Returns the change in error per second.
296 */
298 return Velocity_t{m_controller.GetVelocityError()};
299 }
300
301 /**
302 * Returns the next output of the PID controller.
303 *
304 * @param measurement The current measurement of the process variable.
305 */
306 double Calculate(Distance_t measurement) {
307 if (m_controller.IsContinuousInputEnabled()) {
308 // Get error which is smallest distance between goal and measurement
309 auto errorBound = (m_maximumInput - m_minimumInput) / 2.0;
310 auto goalMinDistance = frc::InputModulus<Distance_t>(
311 m_goal.position - measurement, -errorBound, errorBound);
312 auto setpointMinDistance = frc::InputModulus<Distance_t>(
313 m_setpoint.position - measurement, -errorBound, errorBound);
314
315 // Recompute the profile goal with the smallest error, thus giving the
316 // shortest path. The goal may be outside the input range after this
317 // operation, but that's OK because the controller will still go there and
318 // report an error of zero. In other words, the setpoint only needs to be
319 // offset from the measurement by the input range modulus; they don't need
320 // to be equal.
321 m_goal.position = goalMinDistance + measurement;
322 m_setpoint.position = setpointMinDistance + measurement;
323 }
324
325 m_setpoint = m_profile.Calculate(GetPeriod(), m_setpoint, m_goal);
326 return m_controller.Calculate(measurement.value(),
327 m_setpoint.position.value());
328 }
329
330 /**
331 * Returns the next output of the PID controller.
332 *
333 * @param measurement The current measurement of the process variable.
334 * @param goal The new goal of the controller.
335 */
336 double Calculate(Distance_t measurement, State goal) {
337 SetGoal(goal);
338 return Calculate(measurement);
339 }
340 /**
341 * Returns the next output of the PID controller.
342 *
343 * @param measurement The current measurement of the process variable.
344 * @param goal The new goal of the controller.
345 */
346 double Calculate(Distance_t measurement, Distance_t goal) {
347 SetGoal(goal);
348 return Calculate(measurement);
349 }
350
351 /**
352 * Returns the next output of the PID controller.
353 *
354 * @param measurement The current measurement of the process variable.
355 * @param goal The new goal of the controller.
356 * @param constraints Velocity and acceleration constraints for goal.
357 */
358 double Calculate(
359 Distance_t measurement, Distance_t goal,
361 SetConstraints(constraints);
362 return Calculate(measurement, goal);
363 }
364
365 /**
366 * Reset the previous error and the integral term.
367 *
368 * @param measurement The current measured State of the system.
369 */
370 void Reset(const State& measurement) {
371 m_controller.Reset();
372 m_setpoint = measurement;
373 }
374
375 /**
376 * Reset the previous error and the integral term.
377 *
378 * @param measuredPosition The current measured position of the system.
379 * @param measuredVelocity The current measured velocity of the system.
380 */
381 void Reset(Distance_t measuredPosition, Velocity_t measuredVelocity) {
382 Reset(State{measuredPosition, measuredVelocity});
383 }
384
385 /**
386 * Reset the previous error and the integral term.
387 *
388 * @param measuredPosition The current measured position of the system. The
389 * velocity is assumed to be zero.
390 */
391 void Reset(Distance_t measuredPosition) {
392 Reset(measuredPosition, Velocity_t{0});
393 }
394
395 void InitSendable(wpi::SendableBuilder& builder) override {
396 builder.SetSmartDashboardType("ProfiledPIDController");
397 builder.AddDoubleProperty(
398 "p", [this] { return GetP(); }, [this](double value) { SetP(value); });
399 builder.AddDoubleProperty(
400 "i", [this] { return GetI(); }, [this](double value) { SetI(value); });
401 builder.AddDoubleProperty(
402 "d", [this] { return GetD(); }, [this](double value) { SetD(value); });
403 builder.AddDoubleProperty(
404 "izone", [this] { return GetIZone(); },
405 [this](double value) { SetIZone(value); });
406 builder.AddDoubleProperty(
407 "goal", [this] { return GetGoal().position.value(); },
408 [this](double value) { SetGoal(Distance_t{value}); });
409 }
410
411 private:
412 PIDController m_controller;
413 Distance_t m_minimumInput{0};
414 Distance_t m_maximumInput{0};
415
417 TrapezoidProfile<Distance> m_profile;
419 typename frc::TrapezoidProfile<Distance>::State m_setpoint;
420};
421
422} // namespace frc
#define WPILIB_DLLEXPORT
Definition: SymbolExports.h:36
Implements a PID control loop.
Definition: PIDController.h:23
double GetPositionError() const
Returns the difference between the setpoint and the measurement.
double GetVelocityTolerance() const
Gets the velocity tolerance of this controller.
void SetPID(double Kp, double Ki, double Kd)
Sets the PID Controller gain parameters.
bool IsContinuousInputEnabled() const
Returns true if continuous input is enabled.
units::second_t GetPeriod() const
Gets the period of this controller.
double GetIZone() const
Get the IZone range.
double GetP() const
Gets the proportional coefficient.
void DisableContinuousInput()
Disables continuous input.
double GetD() const
Gets the differential coefficient.
void SetI(double Ki)
Sets the integral coefficient of the PID controller gain.
void SetIZone(double iZone)
Sets the IZone range.
void SetP(double Kp)
Sets the proportional coefficient of the PID controller gain.
double Calculate(double measurement)
Returns the next output of the PID controller.
void Reset()
Reset the previous error, the integral term, and disable the controller.
double GetPositionTolerance() const
Gets the position tolerance of this controller.
double GetI() const
Gets the integral coefficient.
void SetTolerance(double positionTolerance, double velocityTolerance=std::numeric_limits< double >::infinity())
Sets the error which is considered tolerable for use with AtSetpoint().
bool AtSetpoint() const
Returns true if the error is within the tolerance of the setpoint.
void SetD(double Kd)
Sets the differential coefficient of the PID controller gain.
void SetIntegratorRange(double minimumIntegral, double maximumIntegral)
Sets the minimum and maximum values for the integrator.
void EnableContinuousInput(double minimumInput, double maximumInput)
Enables continuous input.
double GetVelocityError() const
Returns the velocity error.
Implements a PID control loop whose setpoint is constrained by a trapezoid profile.
Definition: ProfiledPIDController.h:35
ProfiledPIDController(double Kp, double Ki, double Kd, Constraints constraints, units::second_t period=20_ms)
Allocates a ProfiledPIDController with the given constants for Kp, Ki, and Kd.
Definition: ProfiledPIDController.h:59
double GetP() const
Gets the proportional coefficient.
Definition: ProfiledPIDController.h:128
State GetSetpoint() const
Returns the current setpoint of the ProfiledPIDController.
Definition: ProfiledPIDController.h:223
double Calculate(Distance_t measurement, Distance_t goal)
Returns the next output of the PID controller.
Definition: ProfiledPIDController.h:346
ProfiledPIDController & operator=(ProfiledPIDController &&)=default
void Reset(Distance_t measuredPosition)
Reset the previous error and the integral term.
Definition: ProfiledPIDController.h:391
State GetGoal() const
Gets the goal for the ProfiledPIDController.
Definition: ProfiledPIDController.h:193
bool AtSetpoint() const
Returns true if the error is within the tolerance of the error.
Definition: ProfiledPIDController.h:234
double Calculate(Distance_t measurement, State goal)
Returns the next output of the PID controller.
Definition: ProfiledPIDController.h:336
units::unit_t< Distance > Distance_t
Definition: ProfiledPIDController.h:37
typename TrapezoidProfile< Distance >::Constraints Constraints
Definition: ProfiledPIDController.h:45
Distance_t GetPositionError() const
Returns the difference between the setpoint and the measurement.
Definition: ProfiledPIDController.h:290
void SetTolerance(Distance_t positionTolerance, Velocity_t velocityTolerance=Velocity_t{ std::numeric_limits< double >::infinity()})
Sets the error which is considered tolerable for use with AtSetpoint().
Definition: ProfiledPIDController.h:278
void SetIntegratorRange(double minimumIntegral, double maximumIntegral)
Sets the minimum and maximum values for the integrator.
Definition: ProfiledPIDController.h:267
void SetI(double Ki)
Sets the integral coefficient of the PID controller gain.
Definition: ProfiledPIDController.h:102
ProfiledPIDController(const ProfiledPIDController &)=default
void SetGoal(Distance_t goal)
Sets the goal for the ProfiledPIDController.
Definition: ProfiledPIDController.h:188
void DisableContinuousInput()
Disables continuous input.
Definition: ProfiledPIDController.h:256
void SetD(double Kd)
Sets the differential coefficient of the PID controller gain.
Definition: ProfiledPIDController.h:109
units::second_t GetPeriod() const
Gets the period of this controller.
Definition: ProfiledPIDController.h:156
Velocity_t GetVelocityError() const
Returns the change in error per second.
Definition: ProfiledPIDController.h:297
double GetD() const
Gets the differential coefficient.
Definition: ProfiledPIDController.h:142
void SetP(double Kp)
Sets the proportional coefficient of the PID controller gain.
Definition: ProfiledPIDController.h:95
double GetPositionTolerance() const
Gets the position tolerance of this controller.
Definition: ProfiledPIDController.h:163
double GetIZone() const
Get the IZone range.
Definition: ProfiledPIDController.h:149
double Calculate(Distance_t measurement, Distance_t goal, typename frc::TrapezoidProfile< Distance >::Constraints constraints)
Returns the next output of the PID controller.
Definition: ProfiledPIDController.h:358
void EnableContinuousInput(Distance_t minimumInput, Distance_t maximumInput)
Enables continuous input.
Definition: ProfiledPIDController.h:246
ProfiledPIDController(ProfiledPIDController &&)=default
double GetVelocityTolerance() const
Gets the velocity tolerance of this controller.
Definition: ProfiledPIDController.h:172
void InitSendable(wpi::SendableBuilder &builder) override
Initializes this Sendable object.
Definition: ProfiledPIDController.h:395
ProfiledPIDController & operator=(const ProfiledPIDController &)=default
units::compound_unit< Velocity, units::inverse< units::seconds > > Acceleration
Definition: ProfiledPIDController.h:42
typename TrapezoidProfile< Distance >::State State
Definition: ProfiledPIDController.h:44
void SetPID(double Kp, double Ki, double Kd)
Sets the PID Controller gain parameters.
Definition: ProfiledPIDController.h:86
void Reset(const State &measurement)
Reset the previous error and the integral term.
Definition: ProfiledPIDController.h:370
units::compound_unit< Distance, units::inverse< units::seconds > > Velocity
Definition: ProfiledPIDController.h:39
double Calculate(Distance_t measurement)
Returns the next output of the PID controller.
Definition: ProfiledPIDController.h:306
void Reset(Distance_t measuredPosition, Velocity_t measuredVelocity)
Reset the previous error and the integral term.
Definition: ProfiledPIDController.h:381
void SetGoal(State goal)
Sets the goal for the ProfiledPIDController.
Definition: ProfiledPIDController.h:181
double GetI() const
Gets the integral coefficient.
Definition: ProfiledPIDController.h:135
Constraints GetConstraints()
Get the velocity and acceleration constraints for this controller.
Definition: ProfiledPIDController.h:216
~ProfiledPIDController() override=default
void SetConstraints(Constraints constraints)
Set velocity and acceleration constraints for goal.
Definition: ProfiledPIDController.h:207
bool AtGoal() const
Returns true if the error is within the tolerance of the error.
Definition: ProfiledPIDController.h:200
void SetIZone(double iZone)
Sets the IZone range.
Definition: ProfiledPIDController.h:121
Definition: TrapezoidProfile.h:55
Definition: TrapezoidProfile.h:70
A trapezoid-shaped velocity profile.
Definition: TrapezoidProfile.h:45
constexpr underlying_type value() const noexcept
unit value
Definition: base.h:2119
Definition: SendableBuilder.h:18
virtual void AddDoubleProperty(std::string_view key, std::function< double()> getter, std::function< void(double)> setter)=0
Add a double property.
virtual void SetSmartDashboardType(std::string_view type)=0
Set the string representation of the named data type that will be used by the smart dashboard for thi...
A helper class for use with objects that add themselves to SendableRegistry.
Definition: SendableHelper.h:19
Interface for Sendable objects.
Definition: Sendable.h:16
static void Add(Sendable *sendable, std::string_view name)
Adds an object to the registry.
static void ReportUsage(MathUsageId id, int count)
Definition: MathShared.h:73
typename units::detail::compound_impl< U, Us... >::type compound_unit
Represents a unit type made up from other units.
Definition: base.h:1446
detail namespace with internal helper functions
Definition: ranges.h:23
WPILIB_DLLEXPORT int IncrementAndGetProfiledPIDControllerInstances()
Definition: AprilTagPoseEstimator.h:15