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

Hardware components extension for lifecycle support #503

Merged
merged 21 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ Concepts
:titlesonly:

Controller Manager <../controller_manager/doc/userdoc.rst>
Hardware Components <../hardware_interface/doc/hardware_components_userdoc.rst>
Fake Components <../hardware_interface/doc/fake_components_userdoc.rst>
2 changes: 2 additions & 0 deletions hardware_interface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ endif()
find_package(ament_cmake REQUIRED)
find_package(control_msgs REQUIRED)
find_package(pluginlib REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
find_package(tinyxml2_vendor REQUIRED)
Expand All @@ -31,6 +32,7 @@ ament_target_dependencies(
hardware_interface
control_msgs
pluginlib
rclcpp_lifecycle
destogl marked this conversation as resolved.
Show resolved Hide resolved
rcutils
rcpputils
)
Expand Down
49 changes: 49 additions & 0 deletions hardware_interface/doc/hardware_components_userdoc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.. _hardware_components_userdoc:

Hardware Components
-------------------
Hardware components represent abstraction of physical hardware in ros2_control framework.
There are three types of hardware Actuator, Sensor and System.
For details on each type check `Hardware Components description <https://ros-controls.github.io/control.ros.org/getting_started.html#hardware-components>`_.


Migration from Foxy to Galactic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Between Foxy and Galactic we made substantial changes to the interface of hardware components to enable management of their lifecycle.
The following list shows a set of quick changes to port existing hardware components to Galactic:

1. Rename ``configure`` to ``on_init`` and change return type to ``CallbackReturn``

2. If using BaseInterface as base class then you should remove it. Specifically, change:

hardware_interface::BaseInterface<hardware_interface::[Actuator|Sensor|System]Interface> to hardware_interface::[Actuator|Sensor|System]Interface

3. Remove include of headers ``base_interface.hpp`` and ``hardware_interface_status_values.hpp``

4. Add include of header ``rclcpp_lifecycle/state.hpp`` although this may not be strictly necessary

5. replace first three lines in ``on_init`` to:

.. code-block:: c++

if (hardware_interface::[Actuator|Sensor|System]Interface::on_init(info) != CallbackReturn::SUCCESS)
{
return CallbackReturn::ERROR;
}

6. Change last return of ``on_init`` to ``return CallbackReturn::SUCCESS;``

7. Remove all lines with ``status_ = ...`` or ``status::...``

8. Rename ``start()`` to ``on_activate(const rclcpp_lifecycle::State & previous_state)`` and
``stop()`` to ``on_deactivate(const rclcpp_lifecycle::State & previous_state)``

9. Change return type of ``on_activate`` and ``on_deactivate`` to ``CallbackReturn``

10. Change last return of ``on_activate`` and ``on_deactivate`` to ``return CallbackReturn::SUCCESS;``

11. If you have any ``return_type::ERROR`` in ``on_init``, ``on_activate``, or ``in_deactivate`` change to ``CallbackReturn::ERROR``

12. If you get link errors with undefined refernences to symbols in ``rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface``, then add
``rclcpp_lifecyle`` package dependency to ``CMakeLists.txt`` and ``package.xml``
23 changes: 4 additions & 19 deletions hardware_interface/include/fake_components/generic_system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,49 +20,34 @@
#include <string>
#include <vector>

#include "hardware_interface/base_interface.hpp"
#include "hardware_interface/handle.hpp"
#include "hardware_interface/hardware_info.hpp"
#include "hardware_interface/system_interface.hpp"
#include "hardware_interface/types/hardware_interface_return_values.hpp"
#include "hardware_interface/types/hardware_interface_status_values.hpp"
#include "hardware_interface/types/hardware_interface_type_values.hpp"

using hardware_interface::return_type;

namespace fake_components
{
class HARDWARE_INTERFACE_PUBLIC GenericSystem
: public hardware_interface::BaseInterface<hardware_interface::SystemInterface>
class HARDWARE_INTERFACE_PUBLIC GenericSystem : public hardware_interface::SystemInterface
{
public:
return_type configure(const hardware_interface::HardwareInfo & info) override;
CallbackReturn on_init(const hardware_interface::HardwareInfo & info) override;

std::vector<hardware_interface::StateInterface> export_state_interfaces() override;

std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;

return_type start() override
{
status_ = hardware_interface::status::STARTED;
return return_type::OK;
}

return_type stop() override
{
status_ = hardware_interface::status::STOPPED;
return return_type::OK;
}

return_type read() override;

return_type write() override { return return_type::OK; }

protected:
/// Use standard interfaces for joints because they are relevant for dynamic behaviour
/// Use standard interfaces for joints because they are relevant for dynamic behavior
/**
* By splitting the standard interfaces from other type, the users are able to inherit this
* class and simply create small "simulation" with desired dynamic behaviour.
* class and simply create small "simulation" with desired dynamic behavior.
* The advantage over using Gazebo is that enables "quick & dirty" tests of robot's URDF and
* controllers.
*/
Expand Down
32 changes: 22 additions & 10 deletions hardware_interface/include/hardware_interface/actuator.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 ros2_control Development Team
// Copyright 2020 - 2021 ros2_control Development Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -22,8 +22,8 @@
#include "hardware_interface/handle.hpp"
#include "hardware_interface/hardware_info.hpp"
#include "hardware_interface/types/hardware_interface_return_values.hpp"
#include "hardware_interface/types/hardware_interface_status_values.hpp"
#include "hardware_interface/visibility_control.h"
#include "rclcpp_lifecycle/state.hpp"

namespace hardware_interface
{
Expand All @@ -42,7 +42,25 @@ class Actuator final
~Actuator() = default;

HARDWARE_INTERFACE_PUBLIC
return_type configure(const HardwareInfo & actuator_info);
const rclcpp_lifecycle::State & initialize(const HardwareInfo & actuator_info);

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & configure();

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & cleanup();

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & shutdown();

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & activate();

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & deactivate();

HARDWARE_INTERFACE_PUBLIC
const rclcpp_lifecycle::State & error();

HARDWARE_INTERFACE_PUBLIC
std::vector<StateInterface> export_state_interfaces();
Expand All @@ -60,17 +78,11 @@ class Actuator final
const std::vector<std::string> & start_interfaces,
const std::vector<std::string> & stop_interfaces);

HARDWARE_INTERFACE_PUBLIC
return_type start();

HARDWARE_INTERFACE_PUBLIC
return_type stop();

HARDWARE_INTERFACE_PUBLIC
std::string get_name() const;

HARDWARE_INTERFACE_PUBLIC
status get_status() const;
const rclcpp_lifecycle::State & get_state() const;

HARDWARE_INTERFACE_PUBLIC
return_type read();
Expand Down
126 changes: 87 additions & 39 deletions hardware_interface/include/hardware_interface/actuator_interface.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 ros2_control Development Team
// Copyright 2020 - 2021 ros2_control Development Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -22,44 +22,94 @@
#include "hardware_interface/handle.hpp"
#include "hardware_interface/hardware_info.hpp"
#include "hardware_interface/types/hardware_interface_return_values.hpp"
#include "hardware_interface/types/hardware_interface_status_values.hpp"
#include "hardware_interface/types/lifecycle_state_names.hpp"
#include "lifecycle_msgs/msg/state.hpp"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
destogl marked this conversation as resolved.
Show resolved Hide resolved
#include "rclcpp_lifecycle/state.hpp"

using CallbackReturn = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn;

namespace hardware_interface
{
/// Virtual Class to implement when integrating a 1 DoF actuator into ros2_control.
/**
* The typical examples are conveyors or motors.
*/
class ActuatorInterface
* The typical examples are conveyors or motors.
*
* Methods return values have type rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
* with the following meaning:
*
* \returns CallbackReturn::SUCCESS method execution was successful.
* \returns CallbackReturn::FAILURE method execution has failed and and can be called again.
* \returns CallbackReturn::ERROR critical error has happened that should be managed in
* "on_error" method.
*
* The hardware ends after each method in a state with the following meaning:
*
* UNCONFIGURED (on_init, on_cleanup):
* Hardware is initialized but communication is not started and therefore no interface is available.
*
* INACTIVE (on_configure, on_deactivate):
* Communication with the hardware is started and it is configured.
* States can be read and non-movement hardware interfaces commanded.
* Hardware interfaces for movement will NOT be available.
* Those interfaces are: HW_IF_POSITION, HW_IF_VELOCITY, HW_IF_ACCELERATION, and HW_IF_EFFORT.
*
* FINALIZED (on_shutdown):
* Hardware interface is ready for unloading/destruction.
* Allocated memory is cleaned up.
*
* ACTIVE (on_activate):
* Power circuits of hardware are active and hardware can be moved, e.g., brakes are disabled.
* Command interfaces for movement are available and have to be accepted.
* Those interfaces are: HW_IF_POSITION, HW_IF_VELOCITY, HW_IF_ACCELERATION, and HW_IF_EFFORT.
*/
class ActuatorInterface : public rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface
{
public:
ActuatorInterface() = default;
ActuatorInterface()
: lifecycle_state_(rclcpp_lifecycle::State(
lifecycle_msgs::msg::State::PRIMARY_STATE_UNKNOWN, lifecycle_state_names::UNKNOWN))
{
}

/// SensorInterface copy constructor is actively deleted.
/**
* Hardware interfaces are having a unique ownership and thus can't be copied in order to avoid
* failed or simultaneous access to hardware.
*/
ActuatorInterface(const ActuatorInterface & other) = delete;

ActuatorInterface(ActuatorInterface && other) = default;

virtual ~ActuatorInterface() = default;

/// Configuration of the actuator from data parsed from the robot's URDF.
/// Initialization of the hardware interface from data parsed from the robot's URDF.
/**
* \param[in] actuator_info structure with data from URDF.
* \return return_type::OK if required data are provided and can be parsed,
* return_type::ERROR otherwise.
* \param[in] hardware_info structure with data from URDF.
* \returns CallbackReturn::SUCCESS if required data are provided and can be parsed.
* \returns CallbackReturn::ERROR if any error happens or data are missing.
*/
virtual return_type configure(const HardwareInfo & actuator_info) = 0;
virtual CallbackReturn on_init(const HardwareInfo & hardware_info)
{
info_ = hardware_info;
return CallbackReturn::SUCCESS;
};

/// Exports all state interfaces for this actuator.
/// Exports all state interfaces for this hardware interface.
/**
* The state interfaces have to be created and transferred according
* to the actuator info passed in for the configuration.
* to the hardware info passed in for the configuration.
*
* Note the ownership over the state interfaces is transferred to the caller.
*
* \return vector of state interfaces
*/
virtual std::vector<StateInterface> export_state_interfaces() = 0;

/// Exports all command interfaces for this actuator.
/// Exports all command interfaces for this hardware interface.
/**
* The command interfaces have to be created and transferred according
* to the actuator info passed in for the configuration.
* to the hardware info passed in for the configuration.
*
* Note the ownership over the state interfaces is transferred to the caller.
*
Expand Down Expand Up @@ -106,30 +156,6 @@ class ActuatorInterface
return return_type::OK;
}

/// Start exchange data with the hardware.
/**
* \return return_type:OK if everything worked as expected, return_type::ERROR otherwise.
*/
virtual return_type start() = 0;

/// Stop exchange data with the hardware.
/**
* \return return_type:OK if everything worked as expected, return_type::ERROR otherwise.
*/
virtual return_type stop() = 0;

/// Get name of the actuator hardware.
/**
* \return name.
*/
virtual std::string get_name() const = 0;

/// Get current state of the actuator hardware.
/**
* \return current status.
*/
virtual status get_status() const = 0;

/// Read the current state values from the actuator.
/**
* The data readings from the physical hardware has to be updated
Expand All @@ -148,6 +174,28 @@ class ActuatorInterface
* \return return_type::OK if the read was successful, return_type::ERROR otherwise.
*/
virtual return_type write() = 0;

/// Get name of the actuator hardware.
/**
* \return name.
*/
virtual std::string get_name() const { return info_.name; }

/// Get life-cycle state of the actuator hardware.
/**
* \return state.
*/
const rclcpp_lifecycle::State & get_state() const { return lifecycle_state_; }

/// Set life-cycle state of the actuator hardware.
/**
* \return state.
*/
void set_state(const rclcpp_lifecycle::State & new_state) { lifecycle_state_ = new_state; }

protected:
HardwareInfo info_;
rclcpp_lifecycle::State lifecycle_state_;
};

} // namespace hardware_interface
Expand Down
Loading