Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 Add PID controller 🎉 #434

Merged
merged 37 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f3d8b66
Create PID Controller package.
destogl Sep 10, 2022
e9a1fc9
Updated PID controller with functionality.
destogl Sep 15, 2022
f21ec62
Move parameter read and check into separate method for easier inherit…
destogl Sep 15, 2022
64cd572
Small fixes of pid_controller for compilation.
destogl Sep 29, 2022
6b92bc2
Correct dependencies of PID controller.
destogl Nov 30, 2022
ea7941b
Debug PID controller to actually work.
destogl Nov 30, 2022
19c5859
Remove validation file since it is not needed.
destogl Dec 1, 2022
229946a
Delete LICENSE
destogl Feb 7, 2023
446d909
Simplify things in the PID controller and add some error management.
destogl Dec 16, 2022
3fab744
Update CMake export in pid-controller
tylerjw Mar 18, 2023
bcc9f3f
Cleaning CMakeLists and deprecation from PID controller and starting …
destogl Mar 20, 2023
e80197e
pid_controller compiles, tests need adjustments
muritane Mar 21, 2023
8acea6f
all tests in test_pid_controller are green
muritane Mar 24, 2023
b47d961
test_pid_controller_preceeding: all green
muritane Mar 27, 2023
e511393
Update pid_controller/include/pid_controller/pid_controller.hpp
destogl Mar 28, 2023
6fae4c9
Apply suggestions from code review
destogl Mar 28, 2023
cd12034
Apply suggestions from code review
destogl Apr 3, 2023
e462191
Rename test_pid_controller_preceeding.cpp to test_pid_controller_prec…
destogl Apr 3, 2023
223e1b1
Rename pid_controller_preceeding_params.yaml to pid_controller_preced…
destogl Apr 3, 2023
5baa484
Update pid_controller/CMakeLists.txt
destogl Apr 3, 2023
9f2eb74
Update pid_controller/test/test_pid_controller.cpp
destogl Apr 4, 2023
7e73ef7
More fixups for PID after renaming stuff in the message.
destogl Apr 4, 2023
f8d8667
Apply suggestions from code review
destogl Apr 4, 2023
c60a855
Add user doc
destogl Apr 4, 2023
cd1c875
Update controllers_index.rst
destogl Apr 4, 2023
ef6a206
Apply suggestions from code review
destogl Apr 5, 2023
0a34441
Fixup formatting.
destogl Apr 5, 2023
d29ef49
Fix unused variable compiler warning in pid_controller tests
bijoua29 Apr 7, 2023
0a414ee
Update pid_controller/src/pid_controller.yaml
destogl Apr 12, 2023
9ec3c02
Update pid_controller/doc/userdoc.rst
destogl Apr 19, 2023
ce5ac8c
Remove misleading docs.
destogl May 4, 2023
cc8d2c0
Don't reset commands in `on_deactivate`.
destogl Jun 19, 2023
2f7bf48
Update PIDController to enable parameter updates.
destogl Sep 11, 2023
fe7f0a1
Remove option for enabling/disabling runtime param updates - they can…
destogl Dec 3, 2023
166a9f5
Correct compilation and tests.
destogl Dec 3, 2023
d0cb6e2
Update doc.
destogl Dec 4, 2023
40b9360
update maintainers
bmagyar Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/controllers_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ The controllers are using `common hardware interface definitions`_, and may use
Forward Command Controller <../forward_command_controller/doc/userdoc.rst>
Gripper Controller <../gripper_controllers/doc/userdoc.rst>
Joint Trajectory Controller <../joint_trajectory_controller/doc/userdoc.rst>
PID Controller <../pid_controller/doc/userdoc.rst>
Position Controllers <../position_controllers/doc/userdoc.rst>
Velocity Controllers <../velocity_controllers/doc/userdoc.rst>

Expand Down
108 changes: 108 additions & 0 deletions pid_controller/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
cmake_minimum_required(VERSION 3.16)
project(pid_controller LANGUAGES CXX)

if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
add_compile_options(-Wall -Wextra)
endif()

set(THIS_PACKAGE_INCLUDE_DEPENDS
angles
control_msgs
control_toolbox
controller_interface
generate_parameter_library
hardware_interface
parameter_traits
pluginlib
rclcpp
rclcpp_lifecycle
realtime_tools
std_srvs
)

find_package(ament_cmake REQUIRED)
find_package(backward_ros REQUIRED)
foreach(Dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS})
find_package(${Dependency} REQUIRED)
endforeach()

generate_parameter_library(pid_controller_parameters
src/pid_controller.yaml
)

add_library(pid_controller SHARED
src/pid_controller.cpp
)
target_compile_features(pid_controller PUBLIC cxx_std_17)
target_include_directories(pid_controller PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/pid_controller>
)
target_link_libraries(pid_controller PUBLIC
pid_controller_parameters
)
ament_target_dependencies(pid_controller PUBLIC ${THIS_PACKAGE_INCLUDE_DEPENDS})

# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(pid_controller PRIVATE "PID_CONTROLLER_BUILDING_DLL")

pluginlib_export_plugin_description_file(controller_interface pid_controller.xml)

if(BUILD_TESTING)
find_package(ament_cmake_gmock REQUIRED)
find_package(controller_manager REQUIRED)
find_package(ros2_control_test_assets REQUIRED)

add_rostest_with_parameters_gmock(
test_pid_controller
test/test_pid_controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/pid_controller_params.yaml
)
target_include_directories(test_pid_controller PRIVATE include)
target_link_libraries(test_pid_controller pid_controller)
ament_target_dependencies(
test_pid_controller
controller_interface
hardware_interface
)

add_rostest_with_parameters_gmock(
test_pid_controller_preceding
test/test_pid_controller_preceding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/pid_controller_preceding_params.yaml
)
target_include_directories(test_pid_controller_preceding PRIVATE include)
target_link_libraries(test_pid_controller_preceding pid_controller)
ament_target_dependencies(
test_pid_controller_preceding
controller_interface
hardware_interface
)

ament_add_gmock(test_load_pid_controller test/test_load_pid_controller.cpp)
target_include_directories(test_load_pid_controller PRIVATE include)
ament_target_dependencies(
test_load_pid_controller
controller_manager
ros2_control_test_assets
)
endif()

install(
DIRECTORY include/
DESTINATION include/pid_controller
)

install(TARGETS
pid_controller
pid_controller_parameters
EXPORT export_pid_controller
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
)

ament_export_targets(export_pid_controller HAS_LIBRARY_TARGET)
ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS})
ament_package()
7 changes: 7 additions & 0 deletions pid_controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pid_controller
==========================================

Controller based on PID implementation from control_toolbox package.

Pluginlib-Library: pid_controller
Plugin: pid_controller/PidController (controller_interface::ControllerInterface)
86 changes: 86 additions & 0 deletions pid_controller/doc/userdoc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
:github_url: https://github.com/ros-controls/ros2_controllers/blob/{REPOS_FILE_BRANCH}/pid_controller/doc/userdoc.rst

.. _pid_controller_userdoc:

PID Controller
--------------------------------

PID Controller implementation that uses PidROS implementation from `control_toolbox <https://github.com/ros-controls/control_toolbox/>`_ package.
The controller can be used directly by sending references through a topic or in a chain having preceding or following controllers.
It also enables to use the first derivative of the reference and its feedback to have second-order PID control.

Depending on the reference/state and command interface of the hardware a different parameter setup of PidROS should be used as for example:

- reference/state POSITION; command VELOCITY --> PI CONTROLLER
- reference/state VELOCITY; command ACCELERATION --> PI CONTROLLER

- reference/state VELOCITY; command POSITION --> PD CONTROLLER
- reference/state ACCELERATION; command VELOCITY --> PD CONTROLLER

- reference/state POSITION; command POSITION --> PID CONTROLLER
- reference/state VELOCITY; command VELOCITY --> PID CONTROLLER
- reference/state ACCELERATION; command ACCELERATION --> PID CONTROLLER
- reference/state EFFORT; command EFFORT --> PID CONTROLLER

.. note::

Theoretically one can misuse :ref:`Joint Trajectory Controller (JTC)<joint_trajectory_controller_userdoc>` for the same purpose by sending only one reference point into it.
Nevertheless, this is not recommended. JTC should be used if you need to interpolate between trajectory points using linear, cubic or quintic interpolation. PID Controller doesn't do that.
PID term of JTC has different purpose - it enables commanding only ``velocity`` or ``effort`` interfaces to hardware.

Execution logic of the controller
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The controller can be also used in "feed-forward" mode where feed-forward gain is used to increase controllers dynamics.
If one type of the reference and state interfaces is used, only immediate error is used. If there are two, then the second interface type is considered to be the first derivative of the first type.
For example a valid combination would be ``position`` and ``velocity`` interface types.

destogl marked this conversation as resolved.
Show resolved Hide resolved
Using the controller
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Pluginlib-Library: pid_controller
Plugin name: pid_controller/PidController

Description of controller's interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

References (from a preceding controller)
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
- <reference_and_state_dof_names[i]>/<reference_and_state_interfaces[j]> [double]
**NOTE**: ``reference_and_state_dof_names[i]`` can be from ``reference_and_state_dof_names`` parameter, or if it is empty then ``dof_names``.

Commands
,,,,,,,,,
- <dof_names[i]>/<command_interface> [double]

States
,,,,,,,
- <reference_and_state_dof_names[i]>/<reference_and_state_interfaces[j]> [double]
**NOTE**: ``reference_and_state_dof_names[i]`` can be from ``reference_and_state_dof_names`` parameter, or if it is empty then ``dof_names``.


Subscribers
,,,,,,,,,,,,
If controller is not in chained mode (``in_chained_mode == false``):

- <controller_name>/reference [control_msgs/msg/MultiDOFCommand]

If controller parameter ``use_external_measured_states`` is true:

- <controller_name>/measured_state [control_msgs/msg/MultiDOFCommand]

Services
,,,,,,,,,,,

- <controller_name>/set_feedforward_control [std_srvs/srv/SetBool]

Publishers
,,,,,,,,,,,
- <controller_name>/controller_state [control_msgs/msg/MultiDOFStateStamped]

Parameters
,,,,,,,,,,,

The PID controller uses the `generate_parameter_library <https://github.com/PickNikRobotics/generate_parameter_library>`_ to handle its parameters.

.. generate_parameter_library_details:: ../src/pid_controller.yaml
141 changes: 141 additions & 0 deletions pid_controller/include/pid_controller/pid_controller.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright (c) 2023, Stogl Robotics Consulting UG (haftungsbeschränkt)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
destogl marked this conversation as resolved.
Show resolved Hide resolved
//
// Authors: Daniel Azanov, Dr. Denis
//

#ifndef PID_CONTROLLER__PID_CONTROLLER_HPP_
#define PID_CONTROLLER__PID_CONTROLLER_HPP_

#include <memory>
#include <string>
#include <vector>

#include "control_msgs/msg/multi_dof_command.hpp"
#include "control_msgs/msg/multi_dof_state_stamped.hpp"
#include "control_toolbox/pid_ros.hpp"
#include "controller_interface/chainable_controller_interface.hpp"
#include "pid_controller/visibility_control.h"
destogl marked this conversation as resolved.
Show resolved Hide resolved
#include "pid_controller_parameters.hpp"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
#include "rclcpp_lifecycle/state.hpp"
#include "realtime_tools/realtime_buffer.h"
#include "realtime_tools/realtime_publisher.h"
#include "std_srvs/srv/set_bool.hpp"

#include "control_msgs/msg/joint_controller_state.hpp"
#include "control_msgs/msg/joint_jog.hpp"

#include "control_msgs/msg/pid_state.hpp"
#include "trajectory_msgs/msg/joint_trajectory_point.hpp"

namespace pid_controller
{

enum class feedforward_mode_type : std::uint8_t
{
OFF = 0,
ON = 1,
};

class PidController : public controller_interface::ChainableControllerInterface
{
public:
PID_CONTROLLER__VISIBILITY_PUBLIC
PidController();

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::CallbackReturn on_init() override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::InterfaceConfiguration command_interface_configuration() const override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::InterfaceConfiguration state_interface_configuration() const override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::CallbackReturn on_cleanup(
const rclcpp_lifecycle::State & previous_state) override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::CallbackReturn on_configure(
const rclcpp_lifecycle::State & previous_state) override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::CallbackReturn on_activate(
const rclcpp_lifecycle::State & previous_state) override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::CallbackReturn on_deactivate(
const rclcpp_lifecycle::State & previous_state) override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::return_type update_reference_from_subscribers(
const rclcpp::Time & time, const rclcpp::Duration & period) override;

PID_CONTROLLER__VISIBILITY_PUBLIC
controller_interface::return_type update_and_write_commands(
const rclcpp::Time & time, const rclcpp::Duration & period) override;

using ControllerReferenceMsg = control_msgs::msg::MultiDOFCommand;
using ControllerMeasuredStateMsg = control_msgs::msg::MultiDOFCommand;
using ControllerModeSrvType = std_srvs::srv::SetBool;
using ControllerStateMsg = control_msgs::msg::MultiDOFStateStamped;

protected:
std::shared_ptr<pid_controller::ParamListener> param_listener_;
pid_controller::Params params_;

std::vector<std::string> reference_and_state_dof_names_;
size_t dof_;
std::vector<double> measured_state_values_;

using PidPtr = std::shared_ptr<control_toolbox::PidROS>;
std::vector<PidPtr> pids_;
// Feed-forward velocity weight factor when calculating closed loop pid adapter's command
std::vector<double> feedforward_gain_;

// Command subscribers and Controller State publisher
rclcpp::Subscription<ControllerReferenceMsg>::SharedPtr ref_subscriber_ = nullptr;
realtime_tools::RealtimeBuffer<std::shared_ptr<ControllerReferenceMsg>> input_ref_;

rclcpp::Subscription<ControllerMeasuredStateMsg>::SharedPtr measured_state_subscriber_ = nullptr;
realtime_tools::RealtimeBuffer<std::shared_ptr<ControllerMeasuredStateMsg>> measured_state_;

rclcpp::Service<ControllerModeSrvType>::SharedPtr set_feedforward_control_service_;
realtime_tools::RealtimeBuffer<feedforward_mode_type> control_mode_;

using ControllerStatePublisher = realtime_tools::RealtimePublisher<ControllerStateMsg>;

rclcpp::Publisher<ControllerStateMsg>::SharedPtr s_publisher_;
std::unique_ptr<ControllerStatePublisher> state_publisher_;

// override methods from ChainableControllerInterface
std::vector<hardware_interface::CommandInterface> on_export_reference_interfaces() override;

bool on_set_chained_mode(bool chained_mode) override;

// internal methods
void update_parameters();
controller_interface::CallbackReturn configure_parameters();

private:
// callback for topic interface
PID_CONTROLLER__VISIBILITY_LOCAL
void reference_callback(const std::shared_ptr<ControllerReferenceMsg> msg);
};

} // namespace pid_controller

#endif // PID_CONTROLLER__PID_CONTROLLER_HPP_
Loading