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
0 commit comments