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 package_template::Default_pid_factory

Use a PID factory for the unittests.

Public Static Functions

PID &get()

PID controller factory.

Return

PID& Return a reference to a newly created PID controller.

Public Static Attributes

std::vector<std::shared_ptr<Gains_configuration>> configs_

The PID gains.

std::vector<std::shared_ptr<PID>> controllers_

List of PID controllers.

class package_template::DefaultConfiguration : public package_template::Gains_configuration
#include <default_configuration.hpp>

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

~DefaultConfiguration()

Here we use the default destructor.

double get_kp() const

Always returns DEFAULT_KP.

Return

double DEFAULT_KP

double get_kd() const

Always returns DEFAULT_KD.

Return

double DEFAULT_KD

double get_ki() const

Always returns DEFAULT_KI.

Return

double DEFAULT_KI

bool has_error() const

Always returns false.

Return

true Never

Return

false Always

std::string get_error() const

Always returns “no error”.

Return

std::string “no error”

class package_template::File_configuration : public package_template::Gains_configuration
#include <file_configuration.hpp>

Reading configuration from yaml file.

Public Functions

File_configuration(std::string yaml_file)

Returns error encountered when reading configuration.

See

has_error()

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

double get_kp() const

Get the proportional gain.

Return

double

double get_kd() const

Get the derivative gain.

Return

double

double get_ki() const

Get the integral gain.

Return

double

bool has_error() const

Enquire if an error was encountered while reading the configuration.

See

get_error()

Return

true if an error has been encountered

Return

false otherwise

std::string get_error() const

returns error encountered when reading configuration

See

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 package_template::Gains_configuration
#include <gains_configuration.hpp>

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

~Gains_configuration()

The default destructor do nothing.

double get_kp() const = 0

Get the proportional gain.

Return

double

double get_kd() const = 0

Get the derivative gain.

Return

double

double get_ki() const = 0

Get the integral gain.

Return

double

bool has_error() const = 0

Enquire if an error was encountered while reading the configuration.

See

get_error()

Return

true if an error has been encountered

Return

false otherwise

std::string get_error() const = 0

returns error encountered when reading configuration

See

has_error()

class package_template::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.

Return

computed force

Parameters
  • position: current position

  • velocity: current velocity

  • position_target: target position

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

void reset_integral()

reset integral part of the PID

Private Members

const Gains_configuration *configuration_
bool private_configuration_
double integral_
class package_template::RosParameters_configuration : public package_template::Gains_configuration
#include <rosparameters_configuration.hpp>

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

has_error()

double get_kp() const

Get the proportinal gain.

double get_kd() const

Get the derivative gain.

double get_ki() const

get the integral gain

bool has_error() const

Check if there are internal errors

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)

See

DefaultConfiguration

bool get_parameter(const ros::NodeHandle &nh, const std::string &parameter, double &get_value)
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

See

https://git-amd.tuebingen.mpg.de/amd-clmc/package_template/wikis/catkin:-how-to-implement-a-demo

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.

Return

int

file demo_pid_load_from_file.cpp
#include <stdexcept>#include “package_template/file_configuration.hpp”#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

See

https://git-amd.tuebingen.mpg.de/amd-clmc/package_template/wikis/catkin:-how-to-implement-a-demo

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
#include “package_template/gains_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 “package_template/gains_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>#include “package_template/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

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 basic_pid.cpp
#include “package_template/basic_pid.hpp”

Author

Vincent Berenz license License BSD-3-Clause

Copyright

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

Date

2019-05-22

file default_configuration.cpp
#include “package_template/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

file file_configuration.cpp
#include “package_template/file_configuration.hpp”

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.cpp
#include “package_template/gains_configuration.hpp”

Author

Vincent Berenz

Copyright

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

Date

2019-12-09

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

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.cpp
#include “package_template/rosparameters_configuration.hpp”

Author

Vincent Berenz

Copyright

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

Date

2019-12-09

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 src
dir srcpy
example demo_pid.cpp

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.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
}