C++ API and example

1. Introduction

This page exist in order to extract the examples from the Doxygen documentation, Please have look at the end of this page there are all the examples.

2. C++ API and example

class DefaultConfiguration : public package_template::Gains_configuration

Default configuration for the kp, kd, ki paramters.

This class initialize the PID gains as follow:

  • kp = DEFAULT_KP,

  • kd = DEFAULT_KD

  • ki = DEFAULT_KI

Public Functions

inline ~DefaultConfiguration()

Here we use the default destructor.

virtual double get_kp() const

Always returns DEFAULT_KP.

Returns:

double DEFAULT_KP

virtual double get_kd() const

Always returns DEFAULT_KD.

Returns:

double DEFAULT_KD

virtual double get_ki() const

Always returns DEFAULT_KI.

Returns:

double DEFAULT_KI

virtual bool has_error() const

Always returns false.

Returns:

true Never

Returns:

false Always

virtual std::string get_error() const

Always returns “no error”.

Returns:

std::string “no error”

class File_configuration : public package_template::Gains_configuration

Reading configuration from yaml file.

Public Functions

File_configuration(std::string yaml_file)

Returns error encountered when reading configuration.

See also

has_error()

Parameters:

yaml_file – absolute path to configuration yaml file. The file is expected to have parameters “kp”, “kd” and “ki”

virtual double get_kp() const

Get the proportional gain.

Returns:

double

virtual double get_kd() const

Get the derivative gain.

Returns:

double

virtual double get_ki() const

Get the integral gain.

Returns:

double

virtual bool has_error() const

Enquire if an error was encountered while reading the configuration.

See also

get_error()

Returns:

true if an error has been encountered

Returns:

false otherwise

virtual std::string get_error() const

returns error encountered when reading configuration

See also

has_error()

Private Members

double kp_

Proportinal gain.

double kd_

Derivative gain.

double ki_

Integral gain.

std::string error_message_

Internal error message.

bool error_

True if an error occured.

class Gains_configuration

Abstract class defining for the PID configuration.

This virtual object describes the configuration a PID objects is waiting for. Daughter class will for example be initialize through files, ROS params, etc.

Subclassed by package_template::DefaultConfiguration, package_template::File_configuration, package_template::RosParameters_configuration

Public Functions

inline virtual ~Gains_configuration()

The default destructor do nothing.

virtual double get_kp() const = 0

Get the proportional gain.

Returns:

double

virtual double get_kd() const = 0

Get the derivative gain.

Returns:

double

virtual double get_ki() const = 0

Get the integral gain.

Returns:

double

virtual bool has_error() const = 0

Enquire if an error was encountered while reading the configuration.

See also

get_error()

Returns:

true if an error has been encountered

Returns:

false otherwise

virtual std::string get_error() const = 0

returns error encountered when reading configuration

See also

has_error()

class PID
#include <pid.hpp>

Simple 1D pid controller.

Public Functions

PID()

Construct a default PID object using the DefaultConfiguration.

PID(const Gains_configuration &configuration)

Construct a new PID object using a user provided configuration.

Parameters:

configuration

~PID()
double compute(const double position, const double velocity, const double position_target, const double delta_time)

compute the force related to the pid controller.

Warning

this function is not stateless, as it performs integration. Call reset_pid() to reset the integral part.

Parameters:
  • position – current position

  • velocity – current velocity

  • position_target – target position

  • delta_time – time passed since last measurement. Used for integral computation

Returns:

computed force

void reset_integral()

reset integral part of the PID

Private Members

const Gains_configuration *configuration_
bool private_configuration_
double integral_
class RosParameters_configuration : public package_template::Gains_configuration

Read gains configuration from the ros parameter server.

Public Functions

RosParameters_configuration()

Attempt to get the gains from the parameter server (“gains_kp”,”gains_kd”,”gains_ki” parameters) If roscore is running, calls to this constructor will be blocking until all the gains are read or roscore is turned off.

If roscore is turned off before gains are read, has_error() will return true

See also

has_error()

virtual double get_kp() const

Get the proportinal gain.

virtual double get_kd() const

Get the derivative gain.

virtual double get_ki() const

get the integral gain

virtual bool has_error() const

Check if there are internal errors

virtual std::string get_error() const

Get the error messages

Private Members

double kp_

Proportinal gain.

double kd_

Derivative gain.

double ki_

Integral gain.

std::string error_message_

Internal error message.

bool error_

True is an error occured.

namespace package_template

Functions

void print_configuration(const Gains_configuration &configuration)

print values encapsulated by the provided configuration console on the standard output

PID &get_default_pid()

convenience factory for getting default controller, i.e.

same as PID(std::shared_ptr<DefaultConfiguration> configuration)

file demo_pid.cpp
#include “package_template/pid.hpp

Example of a simple demo suitable for continuous integration.

Author

Vincent Berenz license License BSD-3-Clause

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft.

Date

2019-05-22

Functions

void run_demo()

Creates a PID controller and use the API in a small demo.

int main()

Execute the run_demo() trhough a try/catch expression.

Returns:

int

file demo_pid_load_from_file.cpp
#include <stdexcept>
#include “package_template/pid.hpp

Example of a demo that requires to read a config file.

Author

Vincent Berenz license License BSD-3-Clause

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft.

Date

2019-05-22

Functions

void run_demo()

Run some demo using a YAML file as configuration for the PID controller.

int main()

Run the demo in a safe environment.

file default_configuration.hpp

Author

Vincent Berenz

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft, License BSD-3-Clause

Date

2019-12-09

Defines

DEFAULT_KP
DEFAULT_KD
DEFAULT_KI
file file_configuration.hpp
#include “yaml-cpp/yaml.h”

Author

Vincent Berenz

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft, License BSD-3-Clause

Date

2019-12-09

file gains_configuration.hpp
#include <iostream>
#include <string>

Author

Vincent Berenz

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft, License BSD-3-Clause

Date

2019-12-09

file pid.hpp
#include <memory>
#include <vector>

Author

Vincent Berenz

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft, License BSD-3-Clause

Date

2019-12-09

file rosparameters_configuration.hpp
#include “package_template_cpp/gains_configuration.hpp”
#include “ros/master.h”
#include “ros/ros.h”

Author

Vincent Berenz

Copyright

Copyright (c) 2019, New York University and Max Planck Gesellschaft, License BSD-3-Clause

Date

2019-12-09

Defines

ROSPARAM_KP
ROSPARAM_KD
ROSPARAM_KI
file wrappers.cpp
#include <pybind11/pybind11.h>
#include “package_template/pid.hpp

Functions

PYBIND11_MODULE(package_template_cpp_bindings, m)
dir demos
dir include
dir include/package_template
dir srcpy
example demo_pid.cpp

Create the default PID controller and compute the control once.

Create the default PID controller and compute the control once. This illustrates in the simplest way the use of the PID class API.

#include "package_template/pid.hpp"

void run_demo()
{
    // PID controller with default gains values
    package_template::PID& controller = package_template::get_default_pid();

    // example of force computation
    double current_position = 1;
    double current_velocity = 1;
    double delta_time = 0.01;
    double target_position = 2;
    double force = controller.compute(
        current_position, current_velocity, target_position, delta_time);
    std::cout << "computed force: " << force << std::endl;

    // resetting integral of the controller
    // (useless here because we do not reuse it)
    controller.reset_integral();
}

int main()
{
    try
    {
        run_demo();
    }
    catch (const std::exception& e)
    {
        std::cout << "demo failed !\nerror message:\n" << e.what() << std::endl;
        return 1;  // informs continuous integration that this demo did not run
                   // successfully
    }

    return 0;  // informs continuous integration that this demo did run
               // successfully
}

example demo_pid_load_from_file.cpp

Load the PID gains from a yaml file and create a PID controller from them.

Load the PID gains from a yaml file and create a PID controller from them.This illustrates how to safely use the API when yaml file parsing is wanted.

#include <stdexcept>
#include "package_template/file_configuration.hpp"
#include "package_template/pid.hpp"

void run_demo()
{
    /* displaying what this demo is about */
    std::cout << "This demo shows how to create an executable run by the "
                 "continuous integration\n"
              << "which depends on a configuration file. In the solution "
                 "showed here, the absolute path\n"
              << "to the configuration file is set during pre-compilation. See "
                 "code in /demos/demo_pid_load_from_file.cpp\n"
              << "for details\n\n";

    /* reading gains (kp,kd,ki) from yaml config */

    // (look at the CMakeLists.txt to see why TEST_PID_GAINS_YAML_FILE_PATH is
    // replaced by correct abs path  during compilation)
    std::string config_file_path = TEST_PID_GAINS_YAML_FILE_PATH;

    // Gains_configuration is the base class for all configuration, including
    // the one read from yaml file, as done here.
    package_template::File_configuration gains =
        package_template::File_configuration(config_file_path);

    // printing to standard output the gains
    std::cout << "gains read from configuration file:" << std::endl;
    package_template::print_configuration(gains);

    // checking reading the config file when fine
    // if not, throwing corresponding error
    if (gains.has_error())
    {
        throw std::runtime_error(gains.get_error());
    }

    /* creating and running the controller */

    // PID controller creation
    package_template::PID controller(gains);

    // example of force computation
    double current_position = 1;
    double current_velocity = 1;
    double delta_time = 0.01;
    double target_position = 2;
    double force = controller.compute(
        current_position, current_velocity, target_position, delta_time);
    std::cout << "computed force: " << force << std::endl;

    // resetting integral of the controller
    controller.reset_integral();
}

int main()
{
    try
    {
        run_demo();
    }
    catch (const std::runtime_error& e)
    {
        std::cout << "demo failed !\nerror message:\n" << e.what() << std::endl;
        return 1;  // informs continuous integration that this demo did not run
                   // successfully
    }

    return 0;  // informs continuous integration that this demo did run
               // successfully
}