PID APIs

PID

The PID component provides a simple, thread-safe class representing a PID controller. It tracks how frequently its update() method is called and can have its gains change dynamically.

Code examples for the task API are provided in the pid example folder.

API Reference

Header File

Classes

class Pid : public espp::BaseComponent

Simple PID (proportional, integral, derivative) controller class with integrator clamping, output clamping, and prevention of integrator windup during output saturation. This class is thread-safe, so you can update(), clear(), and change_gains() from multiple threads if needed.

Basic PID Example

    espp::Pid pid({.kp = 1.0f,
                   .ki = 0.1f,
                   .kd = 0.0f,
                   .integrator_min = -1000.0f,
                   .integrator_max = 1000.0f,
                   .output_min = -100.0f,
                   .output_max = 100.0f});
    for (int i = 0; i < num_seconds_to_run; i++) {
      float error = (float)num_seconds_to_run / (float)(i + 1);
      float output = pid.update(error);
      fmt::print("PID: ({}) -> {:0.3f}\n", pid, output);
      // std::this_thread::sleep_for(5ms);
    }

Complex PID Example

    espp::Pid::Config pid_config{.kp = 1.0f,
                                 .ki = 0.1f,
                                 .kd = 0.0f,
                                 .integrator_min = -1000.0f,
                                 .integrator_max = 1000.0f,
                                 .output_min = -100.0f,
                                 .output_max = 100.0f,
                                 .log_level = espp::Logger::Verbosity::INFO};
    espp::Pid pid(pid_config);
    auto task_fn = [&pid](std::mutex &m, std::condition_variable &cv) {
      auto now = std::chrono::high_resolution_clock::now();
      float elapsed = std::chrono::duration<float>(now - start).count();
      float error = 2.0f / elapsed;
      float output = pid.update(error);
      fmt::print("PID: ({}) -> {:0.3f}\n", pid, output);
      // NOTE: sleeping in this way allows the sleep to exit early when the
      // task is being stopped / destroyed
      {
        std::unique_lock<std::mutex> lk(m);
        cv.wait_for(lk, 100ms);
      }
      // don't want to stop the task
      return false;
    };
    auto task = espp::Task({.callback = task_fn,
                            .task_config = {.name = "PID Update"},
                            .log_level = espp::Logger::Verbosity::INFO});
    task.start();
    for (int i = 0; i < num_seconds_to_run; i++) {
      // change PID gains here
      fmt::print("Increasing p-gain\n");
      pid_config.kp = (float)i / (float)num_seconds_to_run;
      pid.change_gains(pid_config);
      std::this_thread::sleep_for(1s);
    }

Public Functions

inline explicit Pid(const Config &config)

Create the PID controller.

inline void change_gains(const Config &config, bool reset_state = true)

Change the gains and other configuration for the PID controller.

Parameters
  • config – Configuration struct with new gains and sampling time.

  • reset_state – Reset / clear the PID controller state.

inline void set_config(const Config &config, bool reset_state = true)

Change the gains and other configuration for the PID controller.

Parameters
  • config – Configuration struct with new gains and sampling time.

  • reset_state – Reset / clear the PID controller state.

inline void clear()

Clear the PID controller state.

inline float update(float error)

Update the PID controller with the latest error measurement, getting the output control signal in return.

Note

Tracks invocation timing to better compute time-accurate integral/derivative signals.

Parameters

error – Latest error signal.

Returns

The output control signal based on the PID state and error.

inline float operator()(float error)

Update the PID controller with the latest error measurement, getting the output control signal in return.

Note

Tracks invocation timing to better compute time-accurate integral/derivative signals.

Parameters

error – Latest error signal.

Returns

The output control signal based on the PID state and error.

inline float get_error() const

Get the current error (as of the last time update() or operator() were called)

Returns

Most recent error.

inline float get_integrator() const

Get the current integrator (as of the last time update() or operator() were called)

Returns

Most recent integrator value.

inline Config get_config() const

Get the configuration for the PID (gains, etc.).

Returns

Config structure containing gains, etc.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

struct Config

Public Members

float kp

Proportional gain.

float ki

Integral gain.

Note

should not be pre-multiplied by the time constant.

float kd

Derivative gain.

Note

should not be pre-divided by the time-constant.

float integrator_min

Minimum value the integrator can wind down to.

Note

Operates at the same scale as output_min and output_max. Could be 0 or negative. Can have different magnitude from integrator_max for asymmetric response.

float integrator_max

Maximum value the integrator can wind up to.

Note

Operates at the same scale as output_min and output_max.

float output_min

Limit the minimum output value. Can be a different magnitude from output max for asymmetric output behavior.

float output_max

Limit the maximum output value.

espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}

Verbosity for the adc logger.