Program Listing for File pid.hpp
↰ Return to documentation for file (include/control_toolbox/pid.hpp)
// Copyright (c) 2008, Willow Garage, Inc.
// All rights reserved.
//
// Software License Agreement (BSD License 2.0)
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of the Willow Garage nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef CONTROL_TOOLBOX__PID_HPP_
#define CONTROL_TOOLBOX__PID_HPP_
#include <chrono>
#include <limits>
#include <string>
#include "rclcpp/duration.hpp"
#include "realtime_tools/realtime_buffer.hpp"
namespace control_toolbox
{
class AntiwindupStrategy
{
public:
enum Value : int8_t
{
NONE = 0,
BACK_CALCULATION,
CONDITIONAL_INTEGRATION
};
constexpr AntiwindupStrategy() : value_(NONE) {}
constexpr AntiwindupStrategy(Value v) : value_(v) {} // NOLINT(runtime/explicit)
explicit AntiwindupStrategy(const std::string & s)
{
if (s == "back_calculation")
{
value_ = BACK_CALCULATION;
}
else if (s == "conditional_integration")
{
value_ = CONDITIONAL_INTEGRATION;
}
else
{
value_ = NONE;
}
}
operator std::string() const { return to_string(); }
constexpr bool operator==(AntiwindupStrategy other) const { return value_ == other.value_; }
constexpr bool operator!=(AntiwindupStrategy other) const { return value_ != other.value_; }
constexpr bool operator==(Value other) const { return value_ == other; }
constexpr bool operator!=(Value other) const { return value_ != other; }
std::string to_string() const
{
switch (value_)
{
case BACK_CALCULATION:
return "back_calculation";
case CONDITIONAL_INTEGRATION:
return "conditional_integration";
case NONE:
default:
return "none";
}
}
private:
Value value_;
};
template <typename T>
inline bool is_zero(T value, T tolerance = std::numeric_limits<T>::epsilon())
{
return std::abs(value) <= tolerance;
}
/***************************************************/
/***************************************************/
class Pid
{
public:
struct Gains
{
[[deprecated("Use constructor with AntiwindupStrategy instead.")]]
Gains(double p, double i, double d, double i_max, double i_min)
: p_gain_(p),
i_gain_(i),
d_gain_(d),
i_max_(i_max),
i_min_(i_min),
u_max_(0.0),
u_min_(0.0),
trk_tc_(0.0),
saturation_(false),
antiwindup_(true),
antiwindup_strat_(AntiwindupStrategy::NONE)
{
}
[[deprecated("Use constructor with AntiwindupStrategy instead.")]]
Gains(double p, double i, double d, double i_max, double i_min, bool antiwindup)
: p_gain_(p),
i_gain_(i),
d_gain_(d),
i_max_(i_max),
i_min_(i_min),
u_max_(0.0),
u_min_(0.0),
trk_tc_(0.0),
saturation_(false),
antiwindup_(antiwindup),
antiwindup_strat_(AntiwindupStrategy::NONE)
{
}
[[deprecated("Use constructor with AntiwindupStrategy only.")]]
Gains(
double p, double i, double d, double i_max, double i_min, double u_max, double u_min,
double trk_tc, bool saturation, bool antiwindup, AntiwindupStrategy antiwindup_strat)
: p_gain_(p),
i_gain_(i),
d_gain_(d),
i_max_(i_max),
i_min_(i_min),
u_max_(u_max),
u_min_(u_min),
trk_tc_(trk_tc),
saturation_(saturation),
antiwindup_(antiwindup),
antiwindup_strat_(antiwindup_strat)
{
}
Gains(
double p, double i, double d, double u_max, double u_min, double trk_tc, bool saturation,
AntiwindupStrategy antiwindup_strat)
: p_gain_(p),
i_gain_(i),
d_gain_(d),
i_max_(0.0),
i_min_(0.0),
u_max_(u_max),
u_min_(u_min),
trk_tc_(trk_tc),
saturation_(saturation),
antiwindup_(false),
antiwindup_strat_(antiwindup_strat)
{
}
// Default constructor
Gains()
: p_gain_(0.0),
i_gain_(0.0),
d_gain_(0.0),
i_max_(0.0),
i_min_(0.0),
u_max_(0.0),
u_min_(0.0),
trk_tc_(0.0),
saturation_(false),
antiwindup_(false),
antiwindup_strat_(AntiwindupStrategy::NONE)
{
}
double p_gain_;
double i_gain_;
double d_gain_;
double i_max_;
double i_min_;
double u_max_;
double u_min_;
double trk_tc_;
bool saturation_;
bool antiwindup_;
AntiwindupStrategy antiwindup_strat_;
};
[[deprecated("Use constructor with AntiwindupStrategy only.")]]
Pid(
double p = 0.0, double i = 0.0, double d = 0.0, double i_max = 0.0, double i_min = -0.0,
bool antiwindup = false);
[[deprecated("Use constructor with AntiwindupStrategy only.")]]
Pid(
double p, double i, double d, double i_max, double i_min, double u_max, double u_min,
double trk_tc, bool saturation, bool antiwindup, AntiwindupStrategy antiwindup_strat);
Pid(
double p, double i, double d, double u_max, double u_min, double trk_tc, bool saturation,
AntiwindupStrategy antiwindup_strat);
Pid(const Pid & source);
~Pid();
[[deprecated("Use initialize with AntiwindupStrategy instead.")]]
void initialize(
double p, double i, double d, double i_max, double i_min, bool antiwindup = false);
[[deprecated("Use initialize() instead")]] void initPid(
double p, double i, double d, double i_max, double i_min, bool antiwindup = false);
[[deprecated("Use initialize with AntiwindupStrategy only.")]]
void initialize(
double p, double i, double d, double i_max, double i_min, double u_max, double u_min,
double trk_tc, bool saturation, bool antiwindup, AntiwindupStrategy antiwindup_strat);
void initialize(
double p, double i, double d, double u_max, double u_min, double trk_tc, bool saturation,
AntiwindupStrategy antiwindup_strat);
void reset();
void reset(bool save_i_term);
void clear_saved_iterm();
void get_gains(double & p, double & i, double & d, double & i_max, double & i_min);
[[deprecated("Use get_gains() instead")]] void getGains(
double & p, double & i, double & d, double & i_max, double & i_min);
[[deprecated("Use get_gains overload without bool antiwindup.")]]
void get_gains(
double & p, double & i, double & d, double & i_max, double & i_min, bool & antiwindup);
[[deprecated("Use get_gains() instead")]] void getGains(
double & p, double & i, double & d, double & i_max, double & i_min, bool & antiwindup);
[[deprecated("Use get_gains overload with AntiwindupStrategy only.")]]
void get_gains(
double & p, double & i, double & d, double & i_max, double & i_min, double & u_max,
double & u_min, double & trk_tc, bool & saturation, bool & antiwindup,
AntiwindupStrategy & antiwindup_strat);
void get_gains(
double & p, double & i, double & d, double & u_max, double & u_min, double & trk_tc,
bool & saturation, AntiwindupStrategy & antiwindup_strat);
Gains get_gains();
[[deprecated("Use get_gains() instead")]] Gains getGains();
[[deprecated("Use set_gains with AntiwindupStrategy instead.")]]
void set_gains(double p, double i, double d, double i_max, double i_min, bool antiwindup = false);
[[deprecated("Use set_gains() instead")]] void setGains(
double p, double i, double d, double i_max, double i_min, bool antiwindup = false);
[[deprecated("Use set_gains with AntiwindupStrategy only.")]]
void set_gains(
double p, double i, double d, double i_max, double i_min, double u_max, double u_min,
double trk_tc = 0.0, bool saturation = false, bool antiwindup = false,
AntiwindupStrategy antiwindup_strat = AntiwindupStrategy::NONE);
void set_gains(
double p, double i, double d, double u_max, double u_min, double trk_tc, bool saturation,
AntiwindupStrategy antiwindup_strat);
void set_gains(const Gains & gains);
[[deprecated("Use set_gains() instead")]] void setGains(const Gains & gains);
[[nodiscard]] double compute_command(double error, const double & dt_s);
[[deprecated("Use compute_command() instead")]] [[nodiscard]] double computeCommand(
double error, uint64_t dt);
[[nodiscard]] double compute_command(double error, const rcl_duration_value_t & dt_ns);
[[nodiscard]] double compute_command(double error, const rclcpp::Duration & dt);
[[nodiscard]] double compute_command(double error, const std::chrono::nanoseconds & dt_ns);
[[nodiscard]] double compute_command(double error, double error_dot, const double & dt_s);
[[deprecated("Use compute_command() instead")]] [[nodiscard]] double computeCommand(
double error, double error_dot, uint64_t dt);
[[nodiscard]] double compute_command(
double error, double error_dot, const rcl_duration_value_t & dt_ns);
[[nodiscard]] double compute_command(double error, double error_dot, const rclcpp::Duration & dt);
[[nodiscard]] double compute_command(
double error, double error_dot, const std::chrono::nanoseconds & dt_ns);
void set_current_cmd(double cmd);
[[deprecated("Use set_current_cmd() instead")]] void setCurrentCmd(double cmd);
double get_current_cmd();
[[deprecated("Use get_current_cmd() instead")]] double getCurrentCmd();
[[deprecated("Use get_current_pid_errors() instead")]] double getDerivativeError();
void get_current_pid_errors(double & pe, double & ie, double & de);
[[deprecated("Use get_current_pid_errors() instead")]] void getCurrentPIDErrors(
double & pe, double & ie, double & de);
Pid & operator=(const Pid & source)
{
if (this == &source)
{
return *this;
}
// Copy the realtime buffer to then new PID class
gains_buffer_ = source.gains_buffer_;
// Reset the state of this PID controller
reset();
return *this;
}
protected:
// Store the PID gains in a realtime buffer to allow dynamic reconfigure to update it without
// blocking the realtime update loop
realtime_tools::RealtimeBuffer<Gains> gains_buffer_;
double p_error_last_ = 0;
double p_error_ = 0;
double d_error_ = 0;
double i_term_ = 0;
double cmd_ = 0;
double cmd_unsat_ = 0;
};
} // namespace control_toolbox
#endif // CONTROL_TOOLBOX__PID_HPP_