Skip to content

Commit b256384

Browse files
committed
Add derivative filter and discretization
1 parent 5c3bea4 commit b256384

File tree

5 files changed

+345
-32
lines changed

5 files changed

+345
-32
lines changed

control_toolbox/include/control_toolbox/pid.hpp

Lines changed: 160 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
#ifndef CONTROL_TOOLBOX__PID_HPP_
3434
#define CONTROL_TOOLBOX__PID_HPP_
3535

36+
#include <rcl/time.h>
3637
#include <chrono>
3738
#include <cmath>
39+
#include <cstdint>
3840
#include <iostream>
3941
#include <limits>
4042
#include <string>
@@ -118,14 +120,14 @@ struct AntiWindupStrategy
118120
(tracking_time_constant < 0.0 || !std::isfinite(tracking_time_constant)))
119121
{
120122
throw std::invalid_argument(
121-
"AntiWindupStrategy 'back_calculation' requires a valid positive tracking time constant "
123+
"AntiWindupStrategy 'back_calculation' requires a non-negative tracking time constant "
122124
"(tracking_time_constant)");
123125
}
124-
if (i_min >= i_max)
126+
if (i_min > i_max)
125127
{
126128
throw std::invalid_argument(
127129
fmt::format(
128-
"PID requires i_min < i_max if limits are finite (i_min: {}, i_max: {})", i_min, i_max));
130+
"PID requires i_min <= i_max if limits are finite (i_min: {}, i_max: {})", i_min, i_max));
129131
}
130132
if (
131133
type != NONE && type != UNDEFINED && type != BACK_CALCULATION &&
@@ -204,6 +206,7 @@ inline bool is_zero(T value, T tolerance = std::numeric_limits<T>::epsilon())
204206
\param p Proportional gain. Reacts to current error.
205207
\param i Integral gain. Accumulates past error to eliminate steady-state error.
206208
\param d Derivative gain. Predicts future error to reduce overshoot and settling time.
209+
\param tf Derivative filter time constant. Used to filter high-frequency noise in the derivative term.
207210
\param u\_min Minimum bound for the controller output.
208211
\param u\_max Maximum bound for the controller output.
209212
\param tracking\_time\_constant Tracking time constant for BACK_CALCULATION anti-windup.
@@ -216,6 +219,14 @@ inline bool is_zero(T value, T tolerance = std::numeric_limits<T>::epsilon())
216219
and unsaturated outputs using \c tracking\_time\_constant.
217220
- CONDITIONAL_INTEGRATION: only integrates when output is not saturated
218221
or error drives it away from saturation.
222+
\param integration\_method Method to compute the integral contribution. Options:
223+
- "forward_euler"
224+
- "backward_euler"
225+
- "trapezoidal"
226+
\param derivative\_method Method to compute the derivative contribution. Options:
227+
- "forward_euler"
228+
- "backward_euler"
229+
- "trapezoidal"
219230
220231
\section antiwindup Anti-Windup Strategies
221232
Without anti-windup, clamping causes integral windup, leading to overshoot and sluggish
@@ -275,14 +286,44 @@ class Pid
275286
Gains(
276287
double p, double i, double d, double u_max, double u_min,
277288
const AntiWindupStrategy & antiwindup_strat)
289+
: Gains(
290+
p, i, d,
291+
/*tf*/ 0.0, u_max, u_min, antiwindup_strat,
292+
/*i_method*/ "forward_euler",
293+
/*d_method*/ "forward_euler")
294+
{
295+
}
296+
297+
/*!
298+
* \brief Constructor for passing in values.
299+
*
300+
* \param p The proportional gain.
301+
* \param i The integral gain.
302+
* \param d The derivative gain.
303+
* \param tf The derivative filter time constant.
304+
* \param u_max Upper output clamp.
305+
* \param u_min Lower output clamp.
306+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
307+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
308+
tracking_time_constant parameter to tune the anti-windup behavior.
309+
* \param i_method Method to compute the integral contribution.
310+
* \param d_method Method to compute the derivative contribution.
311+
*
312+
*/
313+
Gains(
314+
double p, double i, double d, double tf, double u_max, double u_min,
315+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method)
278316
: p_gain_(p),
279317
i_gain_(i),
280318
d_gain_(d),
319+
tf_(tf),
281320
i_max_(antiwindup_strat.i_max),
282321
i_min_(antiwindup_strat.i_min),
283322
u_max_(u_max),
284323
u_min_(u_min),
285-
antiwindup_strat_(antiwindup_strat)
324+
antiwindup_strat_(antiwindup_strat),
325+
i_method_(i_method),
326+
d_method_(d_method)
286327
{
287328
if (std::isnan(u_min) || std::isnan(u_max))
288329
{
@@ -301,19 +342,26 @@ class Pid
301342
{
302343
if (i_min_ > i_max_)
303344
{
304-
error_msg = fmt::format("Gains: i_min ({}) must be less than i_max ({})", i_min_, i_max_);
345+
error_msg =
346+
fmt::format("Gains: i_min ({}) must be less than or equal to i_max ({})", i_min_, i_max_);
305347
return false;
306348
}
307-
else if (u_min_ >= u_max_)
349+
else if (u_min_ > u_max_)
308350
{
309-
error_msg = fmt::format("Gains: u_min ({}) must be less than u_max ({})", u_min_, u_max_);
351+
error_msg =
352+
fmt::format("Gains: u_min ({}) must be less than or equal to u_max ({})", u_min_, u_max_);
310353
return false;
311354
}
312355
else if (std::isnan(u_min_) || std::isnan(u_max_))
313356
{
314357
error_msg = "Gains: u_min and u_max must not be NaN";
315358
return false;
316359
}
360+
else if (tf_ < 0.0)
361+
{
362+
error_msg = "Gains: tf (derivative filter time constant) must be non-negative";
363+
return false;
364+
}
317365
try
318366
{
319367
antiwindup_strat_.validate();
@@ -329,21 +377,25 @@ class Pid
329377
void print() const
330378
{
331379
std::cout << "Gains: p: " << p_gain_ << ", i: " << i_gain_ << ", d: " << d_gain_
332-
<< ", i_max: " << i_max_ << ", i_min: " << i_min_ << ", u_max: " << u_max_
333-
<< ", u_min: " << u_min_ << ", antiwindup_strat: " << antiwindup_strat_.to_string()
334-
<< std::endl;
380+
<< ", tf: " << tf_ << ", i_max: " << i_max_ << ", i_min: " << i_min_
381+
<< ", u_max: " << u_max_ << ", u_min: " << u_min_
382+
<< ", antiwindup_strat: " << antiwindup_strat_.to_string()
383+
<< ", i_method: " << i_method_ << ", d_method: " << d_method_ << std::endl;
335384
}
336385

337386
double p_gain_ = 0.0; /**< Proportional gain. */
338387
double i_gain_ = 0.0; /**< Integral gain. */
339388
double d_gain_ = 0.0; /**< Derivative gain. */
389+
double tf_ = 0.0; /**< Derivative filter time constant. */
340390
double i_max_ =
341391
std::numeric_limits<double>::infinity(); /**< Maximum allowable integral term. */
342392
double i_min_ =
343393
-std::numeric_limits<double>::infinity(); /**< Minimum allowable integral term. */
344394
double u_max_ = std::numeric_limits<double>::infinity(); /**< Maximum allowable output. */
345395
double u_min_ = -std::numeric_limits<double>::infinity(); /**< Minimum allowable output. */
346396
AntiWindupStrategy antiwindup_strat_; /**< Anti-windup strategy. */
397+
std::string i_method_ = "forward_euler"; /**< Integration method. */
398+
std::string d_method_ = "forward_euler"; /**< Derivative method. */
347399
};
348400

349401
/*!
@@ -366,6 +418,27 @@ class Pid
366418
double u_min = -std::numeric_limits<double>::infinity(),
367419
const AntiWindupStrategy & antiwindup_strat = AntiWindupStrategy());
368420

421+
/*!
422+
* \brief Constructor, initialize Pid-gains and term limits.
423+
*
424+
* \param p The proportional gain.
425+
* \param i The integral gain.
426+
* \param d The derivative gain.
427+
* \param tf The derivative filter time constant.
428+
* \param u_max Upper output clamp.
429+
* \param u_min Lower output clamp.
430+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
431+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
432+
tracking_time_constant parameter to tune the anti-windup behavior.
433+
* \param i_method Method to compute the integral contribution.
434+
* \param d_method Method to compute the derivative contribution.
435+
*
436+
* \throws An std::invalid_argument exception is thrown if u_min > u_max.
437+
*/
438+
Pid(
439+
double p, double i, double d, double tf, double u_max, double u_min,
440+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method);
441+
369442
/*!
370443
* \brief Copy constructor required for preventing mutexes from being copied
371444
* \param source - Pid to copy
@@ -396,6 +469,28 @@ class Pid
396469
double p, double i, double d, double u_max, double u_min,
397470
const AntiWindupStrategy & antiwindup_strat);
398471

472+
/*!
473+
* \brief Initialize Pid-gains and term limits.
474+
*
475+
* \param p The proportional gain.
476+
* \param i The integral gain.
477+
* \param d The derivative gain.
478+
* \param tf The derivative filter time constant.
479+
* \param u_max Upper output clamp.
480+
* \param u_min Lower output clamp.
481+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
482+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
483+
tracking_time_constant parameter to tune the anti-windup behavior.
484+
* \param i_method Method to compute the integral contribution.
485+
* \param d_method Method to compute the derivative contribution.
486+
* \return True if all parameters are successfully set, False otherwise.
487+
*
488+
* \note New gains are not applied if antiwindup_strat.i_min > antiwindup_strat.i_max or u_min > u_max.
489+
*/
490+
bool initialize(
491+
double p, double i, double d, double tf, double u_max, double u_min,
492+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method);
493+
399494
/*!
400495
* \brief Reset the state of this PID controller
401496
* @note The integral term is not retained and it is reset to zero
@@ -431,6 +526,26 @@ class Pid
431526
double & p, double & i, double & d, double & u_max, double & u_min,
432527
AntiWindupStrategy & antiwindup_strat);
433528

529+
/*!
530+
* \brief Get PID gains for the controller (preferred).
531+
* \param p The proportional gain.
532+
* \param i The integral gain.
533+
* \param d The derivative gain.
534+
* \param tf The derivative filter time constant.
535+
* \param u_max Upper output clamp.
536+
* \param u_min Lower output clamp.
537+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
538+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
539+
tracking_time_constant parameter to tune the anti-windup behavior.
540+
* \param i_method Method to compute the integral contribution.
541+
* \param d_method Method to compute the derivative contribution.
542+
*
543+
* \note This method is not RT safe
544+
*/
545+
void get_gains(
546+
double & p, double & i, double & d, double & tf, double & u_max, double & u_min,
547+
AntiWindupStrategy & antiwindup_strat, std::string & i_method, std::string & d_method);
548+
434549
/*!
435550
* \brief Get PID gains for the controller.
436551
* \return gains A struct of the PID gain values
@@ -467,6 +582,29 @@ class Pid
467582
double p, double i, double d, double u_max, double u_min,
468583
const AntiWindupStrategy & antiwindup_strat);
469584

585+
/*!
586+
* \brief Set PID gains for the controller.
587+
*
588+
* \param p The proportional gain.
589+
* \param i The integral gain.
590+
* \param d The derivative gain.
591+
* \param tf The derivative filter time constant.
592+
* \param u_max Upper output clamp.
593+
* \param u_min Lower output clamp.
594+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
595+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
596+
tracking_time_constant parameter to tune the anti-windup behavior.
597+
* \param i_method Method to compute the integral contribution.
598+
* \param d_method Method to compute the derivative contribution.
599+
* \return True if all parameters are successfully set, False otherwise.
600+
*
601+
* \note New gains are not applied if antiwindup_strat.i_min > antiwindup_strat.i_max or u_min > u_max.
602+
* \note This method is not RT safe
603+
*/
604+
bool set_gains(
605+
double p, double i, double d, double tf, double u_max, double u_min,
606+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method);
607+
470608
/*!
471609
* \brief Set PID gains for the controller.
472610
* \param gains A struct of the PID gain values.
@@ -623,19 +761,27 @@ class Pid
623761
0.0,
624762
0.0,
625763
0.0,
764+
0.0,
626765
std::numeric_limits<double>::infinity(),
627766
-std::numeric_limits<double>::infinity(),
628-
AntiWindupStrategy()};
767+
AntiWindupStrategy(),
768+
"forward_euler",
769+
"forward_euler"};
629770
// Store the PID gains in a realtime box to allow dynamic reconfigure to update it without
630771
// blocking the realtime update loop
631772
realtime_tools::RealtimeThreadSafeBox<Gains> gains_box_{gains_};
632773

633774
double p_error_last_ = 0; /** Save state for derivative state calculation. */
634775
double p_error_ = 0; /** Error. */
776+
777+
double d_error_last_ = 0; /** Save state for derivative state calculation. */
778+
double d_term_last_ = 0; /** Save state for derivative filter. */
635779
double d_error_ = 0; /** Derivative of error. */
636-
double i_term_ = 0; /** Integrator state. */
637-
double cmd_ = 0; /** Command to send. */
638-
double cmd_unsat_ = 0; /** command without saturation. */
780+
781+
double i_term_ = 0; /** Integrator state. */
782+
783+
double cmd_ = 0; /** Command to send. */
784+
double cmd_unsat_ = 0; /** command without saturation. */
639785
};
640786

641787
} // namespace control_toolbox

control_toolbox/include/control_toolbox/pid_ros.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,30 @@ class PidROS
175175
double p, double i, double d, double u_max, double u_min,
176176
const AntiWindupStrategy & antiwindup_strat, bool save_i_term);
177177

178+
/*!
179+
* \brief Initialize the PID controller and set the parameters.
180+
*
181+
* \param p The proportional gain.
182+
* \param i The integral gain.
183+
* \param d The derivative gain.
184+
* \param tf The derivative filter time constant.
185+
* \param u_max Upper output clamp.
186+
* \param u_min Lower output clamp.
187+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
188+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
189+
tracking_time_constant parameter to tune the anti-windup behavior.
190+
* \param i_method Method to compute the integral contribution.
191+
* \param d_method Method to compute the derivative contribution.
192+
* \param save_i_term save integrator output between resets.
193+
* \return True if all parameters are successfully set, False otherwise.
194+
*
195+
* \note New gains are not applied if antiwindup_strat.i_min > antiwindup_strat.i_max or u_min > u_max.
196+
*/
197+
bool initialize_from_args(
198+
double p, double i, double d, double tf, double u_max, double u_min,
199+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method,
200+
bool save_i_term);
201+
178202
/*!
179203
* \brief Initialize the PID controller based on already set parameters
180204
* \return True if all parameters are set (p, i, d, i_max, i_min, u_max, u_min), False otherwise
@@ -249,6 +273,29 @@ class PidROS
249273
double p, double i, double d, double u_max, double u_min,
250274
const AntiWindupStrategy & antiwindup_strat);
251275

276+
/*!
277+
* \brief Set PID gains for the controller.
278+
*
279+
* \param p The proportional gain.
280+
* \param i The integral gain.
281+
* \param d The derivative gain.
282+
* \param tf The derivative filter time constant.
283+
* \param u_max Upper output clamp.
284+
* \param u_min Lower output clamp.
285+
* \param antiwindup_strat Specifies the anti-windup strategy. Options: 'back_calculation',
286+
'conditional_integration', or 'none'. Note that the 'back_calculation' strategy use the
287+
tracking_time_constant parameter to tune the anti-windup behavior.
288+
* \param i_method Method to compute the integral contribution.
289+
* \param d_method Method to compute the derivative contribution.
290+
* \return True if all parameters are successfully set, False otherwise.
291+
*
292+
* \note New gains are not applied if antiwindup_strat.i_min > antiwindup_strat.i_max or u_min > u_max.
293+
* \note This method is not RT safe
294+
*/
295+
bool set_gains(
296+
double p, double i, double d, double tf, double u_max, double u_min,
297+
const AntiWindupStrategy & antiwindup_strat, std::string i_method, std::string d_method);
298+
252299
/*!
253300
* \brief Set PID gains for the controller.
254301
* \param gains A struct of the PID gain values

0 commit comments

Comments
 (0)