Have fun!
Use-cases from wilderness - ros2_control + MoveIt2
Use-cases from wilderness
● UR driver: https://github.com/UniversalRobots/Universal_Robots_ROS2_Driver
○ The first open-source driver with ros2_control integration
○ Needs special features:
■ Digital and analog inputs and outputs
■ General robot operation: unlock protective stop, restart safety, break release (TBD)
■ Loading, starting, and stopping programs (TBD)
● Dynamixel: https://github.com/youtalk/dynamixel_control
○ Uses multiple servos
○ Reference implementation for ROBOTIS OpenManipulator-X
Use-cases from wilderness
● ros2_control_demos: https://github.com/ros-controls/ros2_control_demos
○ Tool changing — hardware-lifecycle example (PR #133)
○ “Stacking HW together” — RRBot + FTS Sensor (example 4)
● “My robot has measurement offset”
○ Separate commanded and measured states in visualization (example coming soon)
● Hardware “architectures” and capabilities:
○ https://github.com/ros-controls/roadmap/blob/master/design_drafts/components_architecture_and_urdf_examples.md
References
● ros_control paper in the Journal of Open Source Software
● ros2_control resources
○ https://control.ros.org
○ https://github.com/ros-controls/ros2_control
○ https://github.com/ros-controls/ros2_controllers
○ https://github.com/ros-controls/ros2_control_demos
○ https://github.com/ros-controls/roadmap/blob/master/documentation_resources.md
● Videos/presentations:
○ https://youtu.be/G__yFTWp_M0
○ https://www.youtube.com/watch?v=5OfOPcu8Erw&t=245s
○
References
● ros_control paper in the Journal of Open Source Software
● ros2_control resources
○ https://control.ros.org
○ https://github.com/ros-controls/ros2_control
○ https://github.com/ros-controls/ros2_controllers
○ https://github.com/ros-controls/ros2_control_demos
○ https://github.com/ros-controls/roadmap/blob/master/documentation_resources.md


  // hardware plugins
  pluginlib::ClassLoader<ActuatorInterface> actuator_loader_;
  pluginlib::ClassLoader<SensorInterface> sensor_loader_;
  pluginlib::ClassLoader<SystemInterface> system_loader_;


![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 17, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
Suggested change
|  virtual  std::vector<hardware_interface::InterfaceDescription>
export_command_interfaces_2  ()
---|---
|  virtual  std::vector<hardware_interface::InterfaceDescription>
export_command_interfaces_description  ()

Sorry, something went wrong.
All reactions
[ hardware_interface/src/resource_manager.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-31aaa609a55e1333d6e694aea6963bdaceed8615945c65fb57daa91a7c9fd58d)
Comment on lines  +472  to  +487
|  |  // BEGIN (Handle export change): for backward compatibility, can be
removed if
---|---|---
|  |  // export_command_interfaces() method is removed
|  |  void insert_command_interface(CommandInterface && command_interface)
|  |  {
|  |  std::string key = command_interface.get_name();
|  |  const auto [it, success] = command_interface_map_.emplace(
|  |  std::make_pair(key,
std::make_shared<CommandInterface>(std::move(command_interface))));
|  |  if (!success)
|  |  {
|  |  std::string msg(
|  |  "ResourceStorage: Tried to insert CommandInterface with already existing
key. Insert[" +
|  |  key + "]");
|  |  throw std::runtime_error(msg);
|  |  }
|  |  }


  /// Mapping between hardware and controllers that are using it (accessing data from it)
  std::unordered_map<std::string, std::vector<std::string>> hardware_used_by_controllers_;


[ pbnpama  ](https://get-help.theconstruct.ai/u/pbnpama) August 9, 2023,
8:12am  3


    return result;
  }


        joint_ids_[i] = std::stoi(info_.joints[i].parameters.at("id"));
        joints_[i].state.position = std::numeric_limits<double>::quiet_NaN();
        joints_[i].state.velocity = std::numeric_limits<double>::quiet_NaN();
        joints_[i].state.effort = std::numeric_limits<double>::quiet_NaN();
        joints_[i].command.position = std::numeric_limits<double>::quiet_NaN();
        joints_[i].command.velocity = std::numeric_limits<double>::quiet_NaN();
        joints_[i].command.effort = std::numeric_limits<double>::quiet_NaN();
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "joint_id %d: %d", i, joint_ids_[i]);
      }

      if (
        info_.hardware_parameters.find("use_dummy") != info_.hardware_parameters.end() &&
        info_.hardware_parameters.at("use_dummy") == "true") {
        use_dummy_ = true;
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "dummy mode");
        return CallbackReturn::SUCCESS;
      }

      auto usb_port = info_.hardware_parameters.at("usb_port");
      auto baud_rate = std::stoi(info_.hardware_parameters.at("baud_rate"));
      const char * log = nullptr;

      RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "usb_port: %s", usb_port.c_str());
      RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "baud_rate: %d", baud_rate);

      if (!dynamixel_workbench_.init(usb_port.c_str(), baud_rate, &log)) {
        RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
        return CallbackReturn::ERROR;
      }

      for (uint i = 0; i < info_.joints.size(); ++i) {
        uint16_t model_number = 0;
        if (!dynamixel_workbench_.ping(joint_ids_[i], &model_number, &log)) {
          RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
          return CallbackReturn::ERROR;
        }
      }

      enable_torque(false);
      set_control_mode(ControlMode::Position, true);


  template <class HardwareT>
  bool initialize_hardware(const HardwareInfo & hardware_info, HardwareT & hardware)
  {
    RCUTILS_LOG_INFO_NAMED(
      "resource_manager", "Initialize hardware '%s' ", hardware_info.name.c_str());


    In file included from /opt/ros/foxy/include/class_loader/class_loader_core.hpp:57,
                     from /opt/ros/foxy/include/class_loader/class_loader.hpp:55,
                     from /opt/ros/foxy/include/pluginlib/class_list_macros.hpp:40,
                     from /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:395:
    /opt/ros/foxy/include/class_loader/meta_object.hpp: In instantiation of ‘B* class_loader::impl::MetaObject<C, B>::create() const [with C = dynamixel_hardware::DynamixelHardware; B = hardware_interface::SystemInterface]’:
    /opt/ros/foxy/include/class_loader/meta_object.hpp:216:7:   required from here
    /opt/ros/foxy/include/class_loader/meta_object.hpp:218:12: error: invalid new-expression of abstract class type ‘dynamixel_hardware::DynamixelHardware’
      218 |     return new C;
          |            ^~~~~
    In file included from /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:7:
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp:45:7: note:   because the following virtual functions are pure within ‘dynamixel_hardware::DynamixelHardware’:
       45 | class DynamixelHardware : public hardware_interface::SystemInterface {
          |       ^~~~~~~~~~~~~~~~~
    In file included from /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp:9,
                     from /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:7:
    /opt/ros/foxy/include/hardware_interface/system_interface.hpp:48:23: note: 	‘virtual hardware_interface::return_type hardware_interface::SystemInterface::configure(const hardware_interface::HardwareInfo&)’
       48 |   virtual return_type configure(const HardwareInfo & system_info) = 0;
          |                       ^~~~~~~~~
    /opt/ros/foxy/include/hardware_interface/system_interface.hpp:116:23: note: 	‘virtual hardware_interface::return_type hardware_interface::SystemInterface::start()’
      116 |   virtual return_type start() = 0;
          |                       ^~~~~
    /opt/ros/foxy/include/hardware_interface/system_interface.hpp:122:23: note: 	‘virtual hardware_interface::return_type hardware_interface::SystemInterface::stop()’
      122 |   virtual return_type stop() = 0;
          |                       ^~~~
    /opt/ros/foxy/include/hardware_interface/system_interface.hpp:128:23: note: 	‘virtual std::string hardware_interface::SystemInterface::get_name() const’
      128 |   virtual std::string get_name() const = 0;
          |                       ^~~~~~~~
    /opt/ros/foxy/include/hardware_interface/system_interface.hpp:134:18: note: 	‘virtual hardware_interface::status hardware_interface::SystemInterface::get_status() const’
      134 |   virtual status get_status() const = 0;
          |                  ^~~~~~~~~~
    make[2]: *** [CMakeFiles/dynamixel_hardware_interface.dir/build.make:63: CMakeFiles/dynamixel_hardware_interface.dir/src/dynamixel_hardware_interface.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/dynamixel_hardware_interface.dir/all] Error 2
    make: *** [Makefile:141: all] Error 2
    ---
    Failed   <<< dynamixel_hardware_interface [1.90s, exited with code 2]

    Summary: 12 packages finished [2.63s]
      1 package failed: dynamixel_hardware_interface
      1 package had stderr output: dynamixel_hardware_interface


bool result = new_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED;


The course has been developed and tested on a specific environment (for
instance, this course is in ROS2 Galactic). So, trying it outside the course
environment might not work directly. Unfortunately, it’s impossible for us to
provide support for each specific local environment (every student has a
different local environment). If you are working in ROS2 Foxy, make sure that
all the packages/code you are trying to build is compatible with this
distribution. If you copy/pasted code from the course, it might not be
directly compatible.


[ system  ](https://get-help.theconstruct.ai/u/system) Closed  August 16,
2023, 8:21am  5


Here is the .cpp code


  template <class HardwareT>
  void import_command_interfaces(HardwareT & hardware)
  {
    auto interfaces = hardware.export_command_interfaces();
    hardware_info_map_[hardware.get_name()].command_interfaces = add_command_interfaces(interfaces);
  }


// CM API: Called in "update"-thread
bool ResourceManager::perform_command_mode_switch(
  const std::vector<std::string> & start_interfaces,
  const std::vector<std::string> & stop_interfaces)
{
  // When only broadcaster is activated then this lists are empty
  if (start_interfaces.empty() && stop_interfaces.empty())
  {
    return true;
  }


  read_components(resource_storage_->actuators_);
  read_components(resource_storage_->sensors_);
  read_components(resource_storage_->systems_);


![Inheritance
graph](classhardware__interface_1_1StateInterface__inherit__graph.png)


  auto write_components = [&](auto & components)
  {
    for (auto & component : components)
    {
      auto ret_val = component.write(time, period);
      if (ret_val == return_type::ERROR)
      {
        read_write_status.ok = false;
        read_write_status.failed_hardware_names.push_back(component.get_name());
        resource_storage_->remove_all_hardware_interfaces_from_available_list(component.get_name());
      }
      else if (ret_val == return_type::DEACTIVATE)
      {
        resource_storage_->deactivate_hardware(component);
      }
    }
  };


namespace hardware_interface
{
auto trigger_and_print_hardware_state_transition =
  [](
    auto transition, const std::string transition_name, const std::string & hardware_name,
    const lifecycle_msgs::msg::State::_id_type & target_state)
{
  RCUTILS_LOG_INFO_NAMED(
    "resource_manager", "'%s' hardware '%s' ", transition_name.c_str(), hardware_name.c_str());


Thank you for your answer, I also think that the distro is the main problem.
I’ve tried to edit some part but still error.


  /// List of async components by type
  std::unordered_map<std::string, AsyncComponentThread> async_component_threads_;


  void remove_all_hardware_interfaces_from_available_list(const std::string & hardware_name)
  {
    // remove all command interfaces from available list
    for (const auto & interface : hardware_info_map_[hardware_name].command_interfaces)
    {
      auto found_it = std::find(
        available_command_interfaces_.begin(), available_command_interfaces_.end(), interface);


const rclcpp_lifecycle::State new_state = transition();


Collaboration diagram for hardware_interface::StateInterface:


    * [ Collections ](/collections)
  * [ Pricing ](/pricing)
Search or jump to...
#  Search code, repositories, users, issues, pull requests...
Search
Clear
[ Search syntax tips ](https://docs.github.com/search-github/github-code-
search/understanding-github-code-search-syntax)
#  Provide feedback
We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel  Submit feedback
#  Saved searches
##  Use saved searches to filter your results more quickly
Name
Query
To see all available qualifiers, see our [ documentation
](https://docs.github.com/search-github/github-code-search/understanding-
github-code-search-syntax) .
Cancel  Create saved search
[ Sign in ](/login?return_to=https%3A%2F%2Fgithub.com%2Fros-
controls%2Fros2_control%2Fpull%2F1240)
[ Sign up
](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-
name%3E%2F%3Crepo-
name%3E%2Fvoltron%2Fpull_requests_fragments%2Fpull_request_layout&source=header-
repo&source_repo=ros-controls%2Fros2_control)
You signed in with another tab or window. [ Reload ]() to refresh your
session.  You signed out in another tab or window. [ Reload ]() to refresh
your session.  You switched accounts on another tab or window. [ Reload ]() to
refresh your session.  Dismiss alert
{{ message }}
[ ros-controls ](/ros-controls) /  **[ ros2_control ](/ros-
controls/ros2_control) ** Public
  * [ Notifications ](/login?return_to=%2Fros-controls%2Fros2_control)
  * [ Fork  253  ](/login?return_to=%2Fros-controls%2Fros2_control)
  * [ Star  390  ](/login?return_to=%2Fros-controls%2Fros2_control)
  * [ Code  ](/ros-controls/ros2_control)
  * [ Issues  131  ](/ros-controls/ros2_control/issues)
  * [ Pull requests  25  ](/ros-controls/ros2_control/pulls)


    return interface_names;
  }


  std::vector<Actuator> async_actuators_;
  std::vector<Sensor> async_sensors_;
  std::vector<System> async_systems_;


controls/ros2_control/pull/1240/files#diff-76f1eebe99a92140f6b3e99d1a250e6a9cca669ecddbcb270c396b603bf16efe)
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dca572d4721d979c8fb92a36453f69a34a5dd4ae5bf45fb11267269bcfed1212) Outdated
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dca572d4721d979c8fb92a36453f69a34a5dd4ae5bf45fb11267269bcfed1212) Outdated
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dca572d4721d979c8fb92a36453f69a34a5dd4ae5bf45fb11267269bcfed1212) Outdated
Show resolved  Hide resolved
19 hidden conversations  Load more…
[ hardware_interface/include/hardware_interface/system_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dbaf9de12582df8a9762c4f68267da70d479584cbaddc35f9726acf3fad8302a) Outdated
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/system_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dbaf9de12582df8a9762c4f68267da70d479584cbaddc35f9726acf3fad8302a) Outdated
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/system_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dbaf9de12582df8a9762c4f68267da70d479584cbaddc35f9726acf3fad8302a) Outdated
Show resolved  Hide resolved
[ hardware_interface/src/actuator.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
ef3775b758b1e2366de15b39245eff2f7b3c664f24f9f5a75d3795534466ecc3) Outdated
|  |  @@ -192,12 +192,22 @@ std::vector<StateInterface>
Actuator::export_state_interfaces()
---|---|---
|  |  return impl_->export_state_interfaces();
|  |  }
|  |

|  |  std::vector<std::shared_ptr<StateInterface>>
Actuator::on_export_state_interfaces()


](/saikishor) [ saikishor  ](/saikishor) [ ](/ros-
controls/ros2_control/pull/1240/files/7c07d0c6bf0b677fe0feedd48d5343c5b8e9079a)
saikishor requested changes
[ ![@destogl](https://avatars.githubusercontent.com/u/1918204?s=40&v=4)
](/destogl) [ destogl  ](/destogl) [ ](/ros-
controls/ros2_control/pull/1240/files/e70f436b6a20181ccdddc657572e4fec60195979)
destogl requested changes
[
![@christophfroehlich](https://avatars.githubusercontent.com/u/3367244?s=40&v=4)
](/christophfroehlich) [ christophfroehlich  ](/christophfroehlich) [ ](/ros-
controls/ros2_control/pull/1240/files/7c07d0c6bf0b677fe0feedd48d5343c5b8e9079a)
christophfroehlich requested changes
[ ![@aprotyas](https://avatars.githubusercontent.com/u/34530011?s=40&v=4)
](/aprotyas) [ aprotyas  ](/aprotyas) Awaiting requested review from aprotyas
[ ![@bmagyar](https://avatars.githubusercontent.com/u/3524577?s=40&v=4)
](/bmagyar) [ bmagyar  ](/bmagyar) Awaiting requested review from bmagyar
[ ![@livanov93](https://avatars.githubusercontent.com/u/26708124?s=40&v=4)
](/livanov93) [ livanov93  ](/livanov93) Awaiting requested review from
livanov93
[ ![@moriarty](https://avatars.githubusercontent.com/u/55676?s=40&v=4)
](/moriarty) [ moriarty  ](/moriarty) Awaiting requested review from moriarty
[
![@peterdavidfagan](https://avatars.githubusercontent.com/u/42982057?s=40&v=4)
](/peterdavidfagan) [ peterdavidfagan  ](/peterdavidfagan) Awaiting requested
review from peterdavidfagan
[ ![@VanshGehlot](https://avatars.githubusercontent.com/u/63863949?s=40&v=4)
](/VanshGehlot) [ VanshGehlot  ](/VanshGehlot) Awaiting requested review from
VanshGehlot
Requested changes must be addressed to merge this pull request.
Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
None yet


Copy link
Member
###
**[ saikishor ](/saikishor) ** commented  Jan 26, 2024
> [ @saikishor ](https://github.com/saikishor) Manuel is changing this, he was
> using this a lot in the tests. He will finish their adjustment on friday.
Sure. If it's being used a few times std::map should be fine. 🙌🏽🙌🏽🙌🏽

---

All reactions
Sorry, something went wrong.
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=80&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth)
Copy link
Contributor  Author
###
**[ mamueluth ](/mamueluth) ** commented  Jan 29, 2024
Now unorderd_map is used everywhere and tests are adjusted accordingly.
Further new export_command/state_interface_2() function has been introduced
which the user can override to export custom unlisted interfaces. This
function is going to be renamed as soon as the deprecated version is removed.

---

All reactions
Sorry, something went wrong.
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth) [ mamueluth ](/mamueluth) [ force-pushed ](/ros-
controls/ros2_control/compare/a3ad478d0230ae870dec9f43c9bc1ed76d07ced9..b5f9b4d3a87a246a637c091e8356472384b1366a)
the  change_interface_export_variant  branch from [ ` a3ad478 ` ](/ros-
controls/ros2_control/commit/a3ad478d0230ae870dec9f43c9bc1ed76d07ced9) to [ `
b5f9b4d ` ](/ros-
controls/ros2_control/commit/b5f9b4d3a87a246a637c091e8356472384b1366a) [
Compare  ](/ros-
controls/ros2_control/compare/a3ad478d0230ae870dec9f43c9bc1ed76d07ced9..b5f9b4d3a87a246a637c091e8356472384b1366a)
January 29, 2024 09:59
[


  /// Mapping between controllers and list of reference interfaces they are using
  std::unordered_map<std::string, std::vector<std::string>> controllers_reference_interfaces_map_;


[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ fix failing tests ](/ros-
controls/ros2_control/pull/1240/commits/c7e2c1af5a850cb583ea60bc57a2e039a43d7746
"fix failing tests") `
` [ c7e2c1a ](/ros-
controls/ros2_control/pull/1240/commits/c7e2c1af5a850cb583ea60bc57a2e039a43d7746)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ change rest of component_interface test and mark what should be removed
](/ros-
controls/ros2_control/pull/1240/commits/57ecbc78004c0a0c6aba09052cc6cc6a1055dff1
"change rest of component_interface test and mark what should be removed") `
` [ 57ecbc7 ](/ros-
controls/ros2_control/pull/1240/commits/57ecbc78004c0a0c6aba09052cc6cc6a1055dff1)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ code review suggestions and: ](/ros-
controls/ros2_control/pull/1240/commits/56e8be3285a50c46b664413f4c9b944cb637cec3
"code review suggestions and:
* components check for export of interfaces
* change intefaces to allow custom export and test") ` …
` [ 56e8be3 ](/ros-
controls/ros2_control/pull/1240/commits/56e8be3285a50c46b664413f4c9b944cb637cec3)
`

    * components check for export of interfaces
    * change intefaces to allow custom export and test
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ undo prefix_ -> prefix (HWInfo) and Command-/StateIntefaceSharedPtr
](/ros-
controls/ros2_control/pull/1240/commits/4ae546aa5f6339332389413cf7f1e5dc7ad90b1c
"undo prefix_ -> prefix \(HWInfo\) and Command-/StateIntefaceSharedPtr") `
` [ 4ae546a ](/ros-
controls/ros2_control/pull/1240/commits/4ae546aa5f6339332389413cf7f1e5dc7ad90b1c)
`


Basic concepts
Basic Concepts
How to use ros(1)_control?
1. Implement RobotHW (hardware abstraction layer)
a. init(), read(), write()
b. JointStateInterface and [Position|Velocity|Effort]JointInterface
2. Implement a control node
a. Load URDF (“/robot_description” parameter) - usually needed
b. Initialize RobotHW
c. Initialize ControllerManager
d. Start main loop `while(ros::ok())`
i. read()
ii. update() — controllers
iii. write()
Standard controllers
● joint_state_broadcaster
● diff_drive_controller
● joint_trajectory_controller
● gripper_controllers
● Forwarding controllers for groups of joints
○ position_controllers
○ velocity_controllers
○ effort_controllers
Image from ros_control paper
What is a bit tricky in ros(1)_control?
● Joint interfaces limited to: “position”, “velocity”, and “effort
● Complex code-base — lots of templating and inheritance
● “Control node” has to be implemented for each hardware
● Unclear semantic — everything is a RobotHW
● Hardware composition possible, but not straightforward
Improvements in ros2_control
● Joint interfaces limited to: “position”, “velocity”, and “effort
○ Interface types are “strings” — fully flexible
● Complex code-base — lots of templating and inheritance
○ Cleaner code-base, modern C++
● “Control node” has to be implemented for each hardware
○ Default “ros2_control_node”, no need for boilerplates
● Unclear semantic — everything is a RobotHW
○ Actuator, Sensor, and System hardware types
● Hardware composition possible, but not straightforward


std::unordered_map<std::string, HardwareComponentInfo> hardware_info_map_;


        if (found_it == available_state_interfaces_.end())
        {
          available_state_interfaces_.emplace_back(interface);
          RCUTILS_LOG_DEBUG_NAMED(
            "resource_manager", "(hardware '%s'): '%s' state interface added into available list",
            hardware.get_name().c_str(), interface.c_str());
        }
        else
        {
          // TODO(destogl): do here error management if interfaces are only partially added into
          // "available" list - this should never be the case!
          RCUTILS_LOG_WARN_NAMED(
            "resource_manager",
            "(hardware '%s'): '%s' state interface already in available list."
            " This can happen due to multiple calls to 'configure'",
            hardware.get_name().c_str(), interface.c_str());
        }
      }


  auto call_perform_mode_switch = [&start_interfaces, &stop_interfaces](auto & components)
  {
    bool ret = true;
    for (auto & component : components)
    {
      if (
        component.get_state().id() == lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE ||
        component.get_state().id() == lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE)
      {
        if (
          return_type::OK !=
          component.perform_command_mode_switch(start_interfaces, stop_interfaces))
        {
          RCUTILS_LOG_ERROR_NAMED(
            "resource_manager", "Component '%s' could not perform switch",
            component.get_name().c_str());
          ret = false;
        }
      }
    }
    return ret;
  };


size_t ResourceManager::system_components_size() const
{
  return resource_storage_->systems_.size();
}


  return actuators_result && systems_result;
}


// CM API: Called in "update"-thread
LoanedStateInterface ResourceManager::claim_state_interface(const std::string & key)
{
  if (!state_interface_is_available(key))
  {
    throw std::runtime_error(std::string("State interface with key '") + key + "' does not exist");
  }


  return read_write_status;
}


// CM API: Called in "update"-thread
LoanedCommandInterface ResourceManager::claim_command_interface(const std::string & key)
{
  if (!command_interface_is_available(key))
  {
    throw std::runtime_error(std::string("Command interface with '") + key + "' does not exist");
  }


// BEGIN: private methods


  // Check if interfaces are available
  std::stringstream ss_not_available;
  ss_not_available << "Not available: " << std::endl << "[" << std::endl;
  auto check_available = [&](const std::vector<std::string> & list_to_check)
  {
    bool all_available = true;
    for (const auto & interface : list_to_check)
    {
      if (!command_interface_is_available(interface))
      {
        all_available = false;
        ss_not_available << " " << interface << std::endl;
      }
    }
    return all_available;
  };
  if (!(check_available(start_interfaces) && check_available(stop_interfaces)))
  {
    ss_not_available << "]" << std::endl;
    RCUTILS_LOG_ERROR_NAMED(
      "resource_manager", "Not acceptable command interfaces combination: \n%s%s",
      interfaces_to_string().c_str(), ss_not_available.str().c_str());
    return false;
  }


  if (target_state.id() == 0)
  {
    if (target_state.label() == lifecycle_state_names::UNCONFIGURED)
    {
      target_state = rclcpp_lifecycle::State(
        State::PRIMARY_STATE_UNCONFIGURED, lifecycle_state_names::UNCONFIGURED);
    }
    if (target_state.label() == lifecycle_state_names::INACTIVE)
    {
      target_state =
        rclcpp_lifecycle::State(State::PRIMARY_STATE_INACTIVE, lifecycle_state_names::INACTIVE);
    }
    if (target_state.label() == lifecycle_state_names::ACTIVE)
    {
      target_state =
        rclcpp_lifecycle::State(State::PRIMARY_STATE_ACTIVE, lifecycle_state_names::ACTIVE);
    }
    if (target_state.label() == lifecycle_state_names::FINALIZED)
    {
      target_state =
        rclcpp_lifecycle::State(State::PRIMARY_STATE_FINALIZED, lifecycle_state_names::FINALIZED);
    }
  }


  for (const auto & hardware : hardware_info)
  {
    for (const auto & joint : hardware.joints)
    {
      for (const auto & state_interface : joint.state_interfaces)
      {
        if (!state_interface_exists(joint.name + "/" + state_interface.name))
        {
          missing_state_keys.emplace_back(joint.name + "/" + state_interface.name);
        }
      }
      for (const auto & command_interface : joint.command_interfaces)
      {
        if (!command_interface_exists(joint.name + "/" + command_interface.name))
        {
          missing_command_keys.emplace_back(joint.name + "/" + command_interface.name);
        }
      }
    }
    for (const auto & sensor : hardware.sensors)
    {
      for (const auto & state_interface : sensor.state_interfaces)
      {
        if (!state_interface_exists(sensor.name + "/" + state_interface.name))
        {
          missing_state_keys.emplace_back(sensor.name + "/" + state_interface.name);
        }
      }
    }
    for (const auto & gpio : hardware.gpios)
    {
      for (const auto & state_interface : gpio.state_interfaces)
      {
        if (!state_interface_exists(gpio.name + "/" + state_interface.name))
        {
          missing_state_keys.emplace_back(gpio.name + "/" + state_interface.name);
        }
      }
      for (const auto & command_interface : gpio.command_interfaces)
      {


// CM API: Called in "callback/slow"-thread
void ResourceManager::remove_controller_reference_interfaces(const std::string & controller_name)
{
  auto interface_names =
    resource_storage_->controllers_reference_interfaces_map_.at(controller_name);
  resource_storage_->controllers_reference_interfaces_map_.erase(controller_name);


  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  for (const auto & interface : interface_names)
  {
    auto found_it = std::find(
      resource_storage_->available_command_interfaces_.begin(),
      resource_storage_->available_command_interfaces_.end(), interface);
    if (found_it != resource_storage_->available_command_interfaces_.end())
    {
      resource_storage_->available_command_interfaces_.erase(found_it);
      RCUTILS_LOG_DEBUG_NAMED(
        "resource_manager", "'%s' command interface removed from available list",
        interface.c_str());
    }
  }
}


Generated by [ ![doxygen](doxygen.svg) ](https://www.doxygen.org/index.html)
1.9.1


hardware_interface::StateInterface Class Reference


  auto interfaces_to_string = [&]()
  {
    std::stringstream ss;
    ss << "Start interfaces: " << std::endl << "[" << std::endl;
    for (const auto & start_if : start_interfaces)
    {
      ss << "  " << start_if << std::endl;
    }
    ss << "]" << std::endl;
    ss << "Stop interfaces: " << std::endl << "[" << std::endl;
    for (const auto & stop_if : stop_interfaces)
    {
      ss << "  " << stop_if << std::endl;
    }
    ss << "]" << std::endl;
    return ss.str();
  };


          info_.joints[i].name, hardware_interface::HW_IF_POSITION, &joints_[i].state.position));
        state_interfaces.emplace_back(hardware_interface::StateInterface(
          info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &joints_[i].state.velocity));
        state_interfaces.emplace_back(hardware_interface::StateInterface(
          info_.joints[i].name, hardware_interface::HW_IF_EFFORT, &joints_[i].state.effort));
      }

      return state_interfaces;
    }

    std::vector<hardware_interface::CommandInterface> DynamixelHardware::export_command_interfaces()
    {
      RCLCPP_DEBUG(rclcpp::get_logger(kDynamixelHardware), "export_command_interfaces");
      std::vector<hardware_interface::CommandInterface> command_interfaces;
      for (uint i = 0; i < info_.joints.size(); i++) {
        command_interfaces.emplace_back(hardware_interface::CommandInterface(
          info_.joints[i].name, hardware_interface::HW_IF_POSITION, &joints_[i].command.position));
        command_interfaces.emplace_back(hardware_interface::CommandInterface(
          info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &joints_[i].command.velocity));
      }

      return command_interfaces;
    }

    CallbackReturn DynamixelHardware::on_activate(const rclcpp_lifecycle::State & previous_state)
    {
      RCLCPP_DEBUG(rclcpp::get_logger(kDynamixelHardware), "start");
      for (uint i = 0; i < joints_.size(); i++) {
        if (use_dummy_ && std::isnan(joints_[i].state.position)) {
          joints_[i].state.position = 0.0;
          joints_[i].state.velocity = 0.0;
          joints_[i].state.effort = 0.0;
        }
      }
      read();
      reset_command();
      write();

      return CallbackReturn::SUCCESS;
    }


](/saikishor)
Copy link
Member
###
**[ saikishor ](/saikishor) ** commented  Jan 26, 2024  •
edited
> and in my understanding it would be beneficial to have the same ordering of
> the Interfaces in this map as they are defined in the URDF.
Hello [ @mamueluth ](https://github.com/mamueluth) !
is there a specific reason to have the same ordering of the interfaces as in
the URDF?. Moreover, ` std::map ` doesn't ensure this order at all. Well
anyway, if you are accessing only a few times but not continuously a std::map
is fine

---

All reactions
Sorry, something went wrong.
[ ![@destogl](https://avatars.githubusercontent.com/u/1918204?s=80&v=4)
](/destogl)
Copy link
Member
###
**[ destogl ](/destogl) ** commented  Jan 26, 2024
> is there a specific reason to have the same ordering of the interfaces as in
> the URDF?. Moreover, ` std::map ` doesn't ensure this order at all. Well
> anyway, if you are accessing only a few times but not continuously a
> std::map is fine
[ @saikishor ](https://github.com/saikishor) Manuel is changing this, he was
using this a lot in the tests. He will finish their adjustment on friday.

---

👍  1  saikishor reacted with thumbs up emoji
All reactions
  * 👍  1 reaction
Sorry, something went wrong.
[
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=80&u=a8449baf27fec21608c3919a53021b418098ddfe&v=4)
](/saikishor)


[ error ](https://get-help.theconstruct.ai/tag/error) , [ ros2 ](https://get-
help.theconstruct.ai/tag/ros2) , [ simulation ](https://get-
help.theconstruct.ai/tag/simulation)


[ hardware_interface/src/component_parser.cpp ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Fsrc%2Fcomponent_parser.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-aGFyZHdhcmVfaW50ZXJmYWNlL3NyYy9jb21wb25lbnRfcGFyc2VyLmNwcA==) |
` 44.48% <55.55%> (-48.76%) ` |  ⬇
[ ...ce/include/hardware_interface/sensor_interface.hpp
](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Fsensor_interface.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL3NlbnNvcl9pbnRlcmZhY2UuaHBw)
|  ` 67.44% <62.50%> (-32.56%) ` |  ⬇
... and [ 3 more ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree-
more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls) |  |

... and [ 23 files with indirect coverage changes
](https://app.codecov.io/gh/ros-controls/ros2_control/pull/1240/indirect-
changes?src=pr&el=tree-
more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls)

All reactions
Sorry, something went wrong.
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth) [ mamueluth ](/mamueluth) mentioned this pull request  Jan 22,
2024
[ Add Interfaces for reporting of error and warning messages from HW  #1319
](/ros-controls/ros2_control/pull/1319)
Open
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth) [ mamueluth ](/mamueluth) [ force-pushed ](/ros-
controls/ros2_control/compare/923866c5cf80dd91d606634a0e0fdfae5f82695f..e70f436b6a20181ccdddc657572e4fec60195979)
the  change_interface_export_variant  branch from [ ` 923866c ` ](/ros-
controls/ros2_control/commit/923866c5cf80dd91d606634a0e0fdfae5f82695f) to [ `
e70f436 ` ](/ros-
controls/ros2_control/commit/e70f436b6a20181ccdddc657572e4fec60195979) [
Compare  ](/ros-
controls/ros2_control/compare/923866c5cf80dd91d606634a0e0fdfae5f82695f..e70f436b6a20181ccdddc657572e4fec60195979)


The documentation for this class was generated from the following file:


// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// 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.


  void initialize_sensor(
    std::unique_ptr<SensorInterface> sensor, const HardwareInfo & hardware_info)
  {
    auto init_sensors = [&](auto & container)
    {
      container.emplace_back(Sensor(std::move(sensor)));
      if (initialize_hardware(hardware_info, container.back()))
      {
        import_state_interfaces(container.back());
      }
      else
      {
        RCUTILS_LOG_WARN_NAMED(
          "resource_manager",
          "Sensor hardware component '%s' from plugin '%s' failed to initialize.",
          hardware_info.name.c_str(), hardware_info.hardware_plugin_name.c_str());
      }
    };


    switch (target_state.id())
    {
      case State::PRIMARY_STATE_UNCONFIGURED:
        switch (hardware.get_state().id())
        {
          case State::PRIMARY_STATE_UNCONFIGURED:
            result = true;
            break;
          case State::PRIMARY_STATE_INACTIVE:
            result = cleanup_hardware(hardware);
            break;
          case State::PRIMARY_STATE_ACTIVE:
            result = deactivate_hardware(hardware);
            if (result)
            {
              result = cleanup_hardware(hardware);
            }
            break;
          case State::PRIMARY_STATE_FINALIZED:
            result = false;
            RCUTILS_LOG_WARN_NAMED(
              "resource_manager", "hardware '%s' is in finalized state and can be only destroyed.",
              hardware.get_name().c_str());
            break;
        }
        break;
      case State::PRIMARY_STATE_INACTIVE:
        switch (hardware.get_state().id())
        {
          case State::PRIMARY_STATE_UNCONFIGURED:
            result = configure_hardware(hardware);
            break;
          case State::PRIMARY_STATE_INACTIVE:
            result = true;
            break;
          case State::PRIMARY_STATE_ACTIVE:
            result = deactivate_hardware(hardware);
            break;
          case State::PRIMARY_STATE_FINALIZED:
            result = false;


  std::scoped_lock guard(resource_interfaces_lock_, claimed_command_interfaces_lock_);
  resource_storage_->remove_command_interfaces(interface_names);
}


#  [ Cannot build the dynamixel hardware interface in ros2_control course
](/t/cannot-build-the-dynamixel-hardware-interface-in-ros2-control-
course/25749)


![@mateusmenezes95](https://avatars.githubusercontent.com/u/22382953?s=40&v=4)
](/mateusmenezes95) [ mateusmenezes95 ](/mateusmenezes95) mentioned this pull
request  Feb 1, 2024
[ How to pass additional information to the hardware interface  #1016  ](/ros-
controls/ros2_control/issues/1016)
Open
[ ![@destogl](https://avatars.githubusercontent.com/u/1918204?s=40&v=4)
](/destogl) [ destogl ](/destogl) mentioned this pull request  Mar 11, 2024
[ [HW Interface] Command-/SystemInterface export via description. Handles
store value instead of pointers  #952  ](/ros-controls/ros2_control/pull/952)
Closed
1 task
[ ![saikishor](https://avatars.githubusercontent.com/u/10082428?s=60&v=4)
](/saikishor)
**[ saikishor ](/saikishor) ** suggested changes  Mar 17, 2024
[ View reviewed changes  ](/ros-controls/ros2_control/pull/1240/files)
Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** left a comment
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
I've added some minor comments and some questions at different parts to
discuss
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/actuator.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dca572d4721d979c8fb92a36453f69a34a5dd4ae5bf45fb11267269bcfed1212)
|  |  @@ -65,10 +65,10 @@ class Actuator final
---|---|---
|  |  const rclcpp_lifecycle::State & error();
|  |


// CM API: Called in "callback/slow"-thread
bool ResourceManager::prepare_command_mode_switch(
  const std::vector<std::string> & start_interfaces,
  const std::vector<std::string> & stop_interfaces)
{
  // When only broadcaster is activated then this lists are empty
  if (start_interfaces.empty() && stop_interfaces.empty())
  {
    return true;
  }


  /// List of all claimed command interfaces
  std::unordered_map<std::string, bool> claimed_command_interface_map_;


[ albertoezquerro  ](https://get-help.theconstruct.ai/u/albertoezquerro)
August 9, 2023, 7:55am  2


> differs from pull request most recent head [ ` 1612802 `
> ](https://github.com/ros-
> controls/ros2_control/commit/16128028a351ba0d4b667381419c2fe6e0f55b7e) .
> Consider uploading reports for the commit [ ` 1612802 `
> ](https://github.com/ros-
> controls/ros2_control/commit/16128028a351ba0d4b667381419c2fe6e0f55b7e) to
> get more accurate results
Additional details and impacted files

    @@             Coverage Diff             @@
    ##           master    #1240       +/-   ##
    ===========================================
    - Coverage   75.51%   48.20%   -27.31%
    ===========================================
      Files          41       42        +1
      Lines        3328     3850      +522
      Branches     1921     2090      +169
    ===========================================
    - Hits         2513     1856      -657
    - Misses        421      481       +60
    - Partials      394     1513     +1119
|  [ Flag ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls) |  Coverage Δ  |
---|---|---
[ unittests ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls) |  ` 48.20% <55.21%> (-27.31%) ` |  ⬇

Flags with carried forward coverage won't be shown. [ Click here
](https://docs.codecov.io/docs/carryforward-
flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#carryforward-flags-in-the-pull-request-comment) to find out more.
[ Files ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls) |  Coverage Δ  |
---|---|---
[ ..._interface/include/hardware_interface/actuator.hpp
](https://app.codecov.io/gh/ros-


 using ControllerCommandMsg = control_msgs::msg::JointJog;
 …
};
Messages and modifying a controller
controller_interface::return_type RRBotController::update()
{
 auto current_command = input_command_.readFromRT();
 for (size_t i = 0; i < command_interfaces_.size(); ++i) {
 if (!std::isnan((*current_command)->displacements[i])) {
 command_interfaces_[i].set_value((*current_command)->displacements[i]);
 }
 }
...
 return controller_interface::return_type::OK;
}
Messages and modifying a controller
ros2 launch rrbot_bringup rrbot_with_rrbot_controller.launch.py
ros2 control list_controllers
ros2 control list_hardware_interfaces
ros2 topic echo /rrbot_controller/state
ros2 topic echo /joint_states ros2 topic pub /rrbot_controller/commands
control_msgs/msg/JointJog "joint_names:
- joint1
- joint2
displacements:
- 0.5
- 0.5"


Powered by [ Discourse ](https://www.discourse.org) , best viewed with
JavaScript enabled


"move parsing of interface description to component parser") `
` [ 5635631 ](/ros-
controls/ros2_control/pull/1240/commits/5635631fc6cbd00785eca8e4bc60e971f31caf21)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ adjusted actuator- and sensor_interface as well ](/ros-
controls/ros2_control/pull/1240/commits/5d61eaf108d6b514a87f298abe021d64301d66da
"adjusted actuator- and sensor_interface as well") `
` [ 5d61eaf ](/ros-
controls/ros2_control/pull/1240/commits/5d61eaf108d6b514a87f298abe021d64301d66da)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ add first tests ](/ros-
controls/ros2_control/pull/1240/commits/79d0068067e1acc0d94198790404f4360c754c80
"add first tests") `
` [ 79d0068 ](/ros-
controls/ros2_control/pull/1240/commits/79d0068067e1acc0d94198790404f4360c754c80)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ adjust sensor_interface getting/setting and add tests ](/ros-
controls/ros2_control/pull/1240/commits/f40fdcf10afd33c989d3fc163e1bc6b4581e5d58
"adjust sensor_interface getting/setting and add tests") `
` [ f40fdcf ](/ros-
controls/ros2_control/pull/1240/commits/f40fdcf10afd33c989d3fc163e1bc6b4581e5d58)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ add more tests ](/ros-
controls/ros2_control/pull/1240/commits/4533df9fbab7e4afb7dafdde2f8adb14b63431cb
"add more tests") `
` [ 4533df9 ](/ros-
controls/ros2_control/pull/1240/commits/4533df9fbab7e4afb7dafdde2f8adb14b63431cb)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ first steps towards variants and storing of value in handle, missing:
](/ros-


  template <class HardwareT>
  bool deactivate_hardware(HardwareT & hardware)
  {
    bool result = trigger_and_print_hardware_state_transition(
      std::bind(&HardwareT::deactivate, &hardware), "deactivate", hardware.get_name(),
      lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE);


        if (found_it == available_command_interfaces_.end())
        {
          available_command_interfaces_.emplace_back(interface);
          RCUTILS_LOG_DEBUG_NAMED(
            "resource_manager", "(hardware '%s'): '%s' command interface added into available list",
            hardware.get_name().c_str(), interface.c_str());
        }
        else
        {
          // TODO(destogl): do here error management if interfaces are only partially added into
          // "available" list - this should never be the case!
          RCUTILS_LOG_WARN_NAMED(
            "resource_manager",
            "(hardware '%s'): '%s' command interface already in available list."
            " This can happen due to multiple calls to 'configure'",
            hardware.get_name().c_str(), interface.c_str());
        }
      }


over it like so:

    for (const auto & [name, descr] : sensor_state_interfaces_) {
    set_state(name, <state>)
    ....

and in my understanding it would be beneficial to have the same ordering of
the Interfaces in this map as they are defined in the URDF.

---

All reactions
Sorry, something went wrong.
[ ![@VX792](https://avatars.githubusercontent.com/u/25421074?s=80&v=4)
](/VX792)
Copy link
Contributor
###
**[ VX792 ](/VX792) ** commented  Jan 25, 2024  •
edited
Thanks for the great work!
These changes make it a lot easier to finish the asynchronous stuff, as
currently any syhncronization can be bypassed due to the user having direct
access to the double ptr.
I only have one question, which is why shared ptrs are used here instead of
unique ptrs. It's possible I missed something, but to me it looks like there's
clear ownership (the hardware interface owns the states and commands).
For the sensor_state interfaces example it's also possible to use a presorted
vector of pairs instead of a map if it's accessed often and every nanosecond
counts (if not, then it shouldn't matter), since the vector has better cache
locality and usually performs better for a small number of elements, unless
you're also inserting into and deleting elements from the middle.

---

All reactions
Sorry, something went wrong.
[
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=80&u=a8449baf27fec21608c3919a53021b418098ddfe&v=4)


○ Hardware interfaces are always plugins with lifecycle
○ A robot-cell can now be created via plug-and-play
Architecture of ros2_control
“Everything is an interface ”
● ∞ number of interface types → control_msgs/DynamicJointState
○ Type-names are freely choosable
○ Standard names: “position”, “velocity”, “acceleration”, and “effort”
● This enables:
○ Semantic clarity of interface-types (use as clear type-name as possible)
○ Out-of-the-box support for digital and analog inputs and outputs
○ Use of multiple sensors for the same “value”
○ “Interface-type” == string → no need for templating and complex inheritance
URDF extension with <ros2_control>-tag
● Defines hardware type and name
● <hardware>
○ plugin and its parameters
● <joint>
○ Describes 1 DoF
○ Name, interfaces, and parameters
● <sensor>
○ Sensing component that is not related to a joint
○ name, state interfaces, and parameters
● <gpio>
○ Everything else
○ Size, data type, name, interfaces, and parameters
All interfaces has internally type double!
URDF extension with
<ros2_control>-tag
Lifecycle for controllers and hardware
● Managed nodes - interface
https://design.ros2.org/articles/node_lifecycle.html
How to use ros2_control
● Write <ros2_control> tag for your robot
○ Tip: write as xacro macro
● Implement hardware interface
○ Actuator - for 1 DoF actuators, e.g., motors
○ Sensor - for sensors
○ System - for multi DoF actuators, e.g., robots
● Configure controllers / controller manager
○ Do not forget to configure used interfaces


controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Factuator.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL2FjdHVhdG9yLmhwcA==)
|  ` 100.00% <ø> (ø) ` |
[ ...re_interface/include/hardware_interface/sensor.hpp
](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Fsensor.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL3NlbnNvci5ocHA=)
|  ` 100.00% <ø> (ø) ` |
[ ...re_interface/include/hardware_interface/system.hpp
](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Fsystem.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL3N5c3RlbS5ocHA=)
|  ` 100.00% <ø> (ø) ` |
[ ...rface/include/hardware_interface/hardware_info.hpp
](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Fhardware_info.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL2hhcmR3YXJlX2luZm8uaHBw)
|  ` 60.00% <60.00%> (ø) ` |
[ ...re_interface/include/hardware_interface/handle.hpp
](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Finclude%2Fhardware_interface%2Fhandle.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-
aGFyZHdhcmVfaW50ZXJmYWNlL2luY2x1ZGUvaGFyZHdhcmVfaW50ZXJmYWNlL2hhbmRsZS5ocHA=)
|  ` 80.64% <83.33%> (-19.36%) ` |  ⬇
[ hardware_interface/src/sensor.cpp ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Fsrc%2Fsensor.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-aGFyZHdhcmVfaW50ZXJmYWNlL3NyYy9zZW5zb3IuY3Bw) |  ` 50.46%
<55.55%> (-18.22%) ` |  ⬇
[ hardware_interface/src/system.cpp ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Fsrc%2Fsystem.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-aGFyZHdhcmVfaW50ZXJmYWNlL3NyYy9zeXN0ZW0uY3Bw) |  ` 56.71%
<61.11%> (-16.17%) ` |  ⬇
[ hardware_interface/src/actuator.cpp ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?src=pr&el=tree&filepath=hardware_interface%2Fsrc%2Factuator.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls#diff-aGFyZHdhcmVfaW50ZXJmYWNlL3NyYy9hY3R1YXRvci5jcHA=) |  ` 55.97%
<55.55%> (-16.92%) ` |  ⬇


// CM API: Called in "update"-thread
void ResourceManager::make_controller_reference_interfaces_unavailable(
  const std::string & controller_name)
{
  auto interface_names =
    resource_storage_->controllers_reference_interfaces_map_.at(controller_name);


  /// Removes command interfaces from internal storage.
  /**
   * Command interface are removed from the maps with theirs storage and their claimed status.
   *
   * \param[interface_names] list of command interface names to remove from storage.
   */
  void remove_command_interfaces(const std::vector<std::string> & interface_names)
  {
    for (const auto & interface : interface_names)
    {
      command_interface_map_.erase(interface);
      claimed_command_interface_map_.erase(interface);
    }
  }


I’m not sure that should I change info_ to info or not.


  const bool actuators_result = call_perform_mode_switch(resource_storage_->actuators_);
  const bool systems_result = call_perform_mode_switch(resource_storage_->systems_);


// CM API: Called in "callback/slow"-thread
std::vector<std::string> ResourceManager::state_interface_keys() const
{
  std::vector<std::string> keys;
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  for (const auto & item : resource_storage_->state_interface_map_)
  {
    keys.push_back(std::get<0>(item));
  }
  return keys;
}


{{ refName }}  default
Could not load tags
Nothing to show
{{ refName }}  default
###  Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline, and
old review comments may become outdated.
Change base
from  [ StoglRobotics-forks  :  change_interface_export_variant
](/StoglRobotics-forks/ros2_control/tree/change_interface_export_variant
"StoglRobotics-forks/ros2_control:change_interface_export_variant")
Open
#  [HW Interface] Change creation, exportation and storing of
Command-/StateInterface + Support for variant  #1240
[ mamueluth ](/mamueluth) wants to merge  22  commits into  [ ros-controls  :
master  ](/ros-controls/ros2_control/tree/master "ros-
controls/ros2_control:master") from  [ StoglRobotics-forks  :
change_interface_export_variant  ](/StoglRobotics-
forks/ros2_control/tree/change_interface_export_variant "StoglRobotics-
forks/ros2_control:change_interface_export_variant")
+2,735  −216
[ Conversation  127  ](/ros-controls/ros2_control/pull/1240) [ Commits  22
](/ros-controls/ros2_control/pull/1240/commits) [ Checks  11  ](/ros-
controls/ros2_control/pull/1240/checks) [ Files changed  25  ](/ros-
controls/ros2_control/pull/1240/files)
##  Conversation
This file contains bidirectional Unicode text that may be interpreted or
compiled differently than what appears below. To review, open the file in an
editor that reveals hidden Unicode characters. [ Learn more about
bidirectional Unicode characters ](https://github.co/hiddenchars)
[ Show hidden characters ]({{ revealButtonHref }})
[ ![mamueluth](https://avatars.githubusercontent.com/u/19118679?s=60&v=4)
](/mamueluth)
Copy link
Contributor
###
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=48&v=4) **[
mamueluth ](/mamueluth) ** commented  Dec 20, 2023  •
edited
The concept fully backward compatible, has been tested and works. In the [


// END: private methods


      310 |     for (uint i = 0; i < info_.joints.size(); ++i) {
          |                          ^~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:319:26: error: ‘info_’ was not declared in this scope
      319 |     for (uint i = 0; i < info_.joints.size(); ++i) {
          |                          ^~~~~
    make[2]: *** [CMakeFiles/dynamixel_hardware_interface.dir/build.make:63: CMakeFiles/dynamixel_hardware_interface.dir/src/dynamixel_hardware_interface.cpp.o] Error 1
    make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/dynamixel_hardware_interface.dir/all] Error 2
    make: *** [Makefile:141: all] Error 2
    ---
    Failed   <<< dynamixel_hardware_interface [1.83s, exited with code 2]

    Summary: 12 packages finished [2.98s]
      1 package failed: dynamixel_hardware_interface
      1 package had stderr output: dynamixel_hardware_interface


Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
I doubt that we need methods here. The code is not so long, and the import is
used only once. So if we use here import directly, it might be that we even
increase readability.
Sorry, something went wrong.
All reactions
Copy link
Contributor  Author
###
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=48&v=4) **[
mamueluth ](/mamueluth) ** Jan 23, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
in my opinion the code is more readable like this because you have the
functions with a name that explains what is done and then the comments for the
functions which explains it in more detail.
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Outdated  Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Outdated  Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Outdated  Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/hardware_info.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e7dc4bf1991f727ec29c459437748c1ec733d22be43f00d5f2f3c07add314f5d)
Show resolved  Hide resolved
6 hidden conversations  Load more…
[ hardware_interface/src/resource_manager.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-31aaa609a55e1333d6e694aea6963bdaceed8615945c65fb57daa91a7c9fd58d)
Outdated  Show resolved  Hide resolved


// CM API: Called in "callback/slow"-thread
std::unordered_map<std::string, HardwareComponentInfo> ResourceManager::get_components_status()
{
  auto loop_and_get_state = [&](auto & container)
  {
    for (auto & component : container)
    {
      resource_storage_->hardware_info_map_[component.get_name()].state = component.get_state();
    }
  };


  return actuators_result && systems_result;
}


bool ResourceManager::command_interface_exists(const std::string & key) const
{
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return resource_storage_->command_interface_map_.find(key) !=
         resource_storage_->command_interface_map_.end();
}


    #ifndef DYNAMIXEL_HARDWARE__DYNAMIXEL_HARDWARE_HPP_
    #define DYNAMIXEL_HARDWARE__DYNAMIXEL_HARDWARE_HPP_

    #include <vector>
    #include <map>

    #include <hardware_interface/handle.hpp>
    #include <hardware_interface/hardware_info.hpp>
    #include <hardware_interface/system_interface.hpp>
    #include <rclcpp_lifecycle/state.hpp>
    #include "rclcpp/macros.hpp"

    #include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
    #include "rclcpp_lifecycle/lifecycle_publisher.hpp"

    #include <dynamixel_workbench_toolbox/dynamixel_workbench.h>

    using hardware_interface::return_type;

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

    namespace dynamixel_hardware {
    struct JointValue {
      double position{0.0};
      double velocity{0.0};
      double effort{0.0};
    };

    struct Joint {
      JointValue state{};
      JointValue command{};
    };

    enum class ControlMode {
      Position,
      Velocity,
      Torque,
      Currrent,


---|---
|  std::vector<std::shared_ptr<StateInterface>> interfaces = hardware.
on_export_state_interfaces  ();

Shouldn't this be using the method ` on_export_state_interfaces ` ?
Sorry, something went wrong.
All reactions
Copy link
Contributor  Author
###
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=48&v=4) **[
mamueluth ](/mamueluth) ** Apr 11, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
no because of how the deprecation is handled.
Sorry, something went wrong.
All reactions
Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Apr 11, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
Got it
Sorry, something went wrong.
All reactions
[ hardware_interface/src/resource_manager.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-31aaa609a55e1333d6e694aea6963bdaceed8615945c65fb57daa91a7c9fd58d)
|  |  template <class HardwareT>


[ pbnpama  ](https://get-help.theconstruct.ai/u/pbnpama) August 9, 2023,
8:21am  4


[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ merge parser functions ](/ros-
controls/ros2_control/pull/1240/commits/cc1f9752de26ee34173c200270059bf88f2c07fb
"merge parser functions") `
` [ cc1f975 ](/ros-
controls/ros2_control/pull/1240/commits/cc1f9752de26ee34173c200270059bf88f2c07fb)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ export_interfaces_2() virtual for custom interface export ](/ros-
controls/ros2_control/pull/1240/commits/ab00a0651b3734d3658b1da203af00127756d24f
"export_interfaces_2\(\) virtual for custom interface export") `
` [ ab00a06 ](/ros-
controls/ros2_control/pull/1240/commits/ab00a0651b3734d3658b1da203af00127756d24f)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ use unordered map and adjust tests ](/ros-
controls/ros2_control/pull/1240/commits/219544ab393e0d12000c0204b067343755383c1b
"use unordered map and adjust tests") `
` [ 219544a ](/ros-
controls/ros2_control/pull/1240/commits/219544ab393e0d12000c0204b067343755383c1b)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ make states and commands of component interfaces private ](/ros-
controls/ros2_control/pull/1240/commits/8d431f014cca6ddf03bd29cb7d188a655e460a6a
"make states and commands of component interfaces private") `
` [ 8d431f0 ](/ros-
controls/ros2_control/pull/1240/commits/8d431f014cca6ddf03bd29cb7d188a655e460a6a)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ add migration guide for ](/ros-
controls/ros2_control/pull/1240/commits/4b2328a0b4d753752ab783c251cd6af2518ac616
"add migration guide for") `
` [ 4b2328a ](/ros-
controls/ros2_control/pull/1240/commits/4b2328a0b4d753752ab783c251cd6af2518ac616)
`


  const auto hardware_info = hardware_interface::parse_control_resources_from_urdf(urdf);
  if (load_and_initialize_components)
  {
    for (const auto & individual_hardware_info : hardware_info)
    {
      if (individual_hardware_info.type == actuator_type)
      {
        std::scoped_lock guard(resource_interfaces_lock_, claimed_command_interfaces_lock_);
        resource_storage_->load_and_initialize_actuator(individual_hardware_info);
      }
      if (individual_hardware_info.type == sensor_type)
      {
        std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
        resource_storage_->load_and_initialize_sensor(individual_hardware_info);
      }
      if (individual_hardware_info.type == system_type)
      {
        std::scoped_lock guard(resource_interfaces_lock_, claimed_command_interfaces_lock_);
        resource_storage_->load_and_initialize_system(individual_hardware_info);
      }
    }
  }


// CM API: Called in "update"-thread
std::vector<std::string> ResourceManager::available_command_interfaces() const
{
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return resource_storage_->available_command_interfaces_;
}


// CM API: Called in "update"-thread
bool ResourceManager::command_interface_is_claimed(const std::string & key) const
{
  if (!command_interface_is_available(key))
  {
    return false;
  }


 </joint>
 <joint name="joint2">
 <command_interface name="position">
 <param name="min">-1</param>
 <param name="max">1</param>
 </command_interface>
 <state_interface name="position"/>
 </joint>
</ros2_control>
ros2 launch rrbot_bringup rrbot.launch.py
Implementing a forwarding controller
class RRBotControllerArray : public controller_interface::ControllerInterface
{
public:
 controller_interface::return_type init(const std::string & controller_name) override;
 controller_interface::InterfaceConfiguration command_interface_configuration() const override;
 controller_interface::InterfaceConfiguration state_interface_configuration() const override;
 CallbackReturn on_configure(const rclcpp_lifecycle::State & previous_state) override;
 CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
 CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
 controller_interface::return_type update() override;
...
};
Implementing a forwarding controller
class RRBotControllerArray : public controller_interface::ControllerInterface
{
...
protected:
 std::vector<std::string> joint_names_;
 std::string interface_name_;
 using ControllerCommandMsg = example_interfaces::msg::Float64MultiArray;
 rclcpp::Subscription<ControllerCommandMsg>::SharedPtr command_subscriber_ = nullptr;
 realtime_tools::RealtimeBuffer<std::shared_ptr<ControllerCommandMsg>> input_command_;
 using ControllerStateMsg = control_msgs::msg::JointControllerState;
 using ControllerStatePublisher = realtime_tools::RealtimePublisher<ControllerStateMsg>;
 rclcpp::Publisher<ControllerStateMsg>::SharedPtr s_publisher_;
 std::unique_ptr<ControllerStatePublisher> state_publisher_;
};
Implementing a forwarding controller
controller_interface::return_type RRBotControllerArray::update()


 if (configure_default(info) != hardware_interface::return_type::OK) {
 return hardware_interface::return_type::ERROR;
 }
 hw_states_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());
 hw_commands_.resize(info_.joints.size(), std::numeric_limits<double>::quiet_NaN());
 status_ = hardware_interface::status::CONFIGURED;
 return hardware_interface::return_type::OK;
}
Implementing a system component
hardware_interface::return_type RRBotHardwareInterface::read()
{
 // read robot states from hardware, in this example print only
 RCLCPP_INFO(rclcpp::get_logger("RRBotHardwareInterface"), "Reading...");
 // write command to hardware, in this example do mirror command to states
 for (size_t i = 0; i < hw_states_.size(); ++i){
 RCLCPP_INFO(
 rclcpp::get_logger("RRBotHardwareInterface"),
 "Got state %.2f for joint %d!", hw_states_[i], i);
 }
 return hardware_interface::return_type::OK;
}
hardware_interface::return_type RRBotHardwareInterface::write()
{
 // write command to hardware, in this example do mirror command to states
 for (size_t i = 0; i < hw_commands_.size(); ++i){
 hw_states_[i] = hw_states_[i] + (hw_commands_[i] - hw_states_[i]) / 100.0;
 }
 return hardware_interface::return_type::OK;
}
Implementing a system component
<ros2_control name="${name}" type="system">
 <hardware>
 <plugin>rrbot_hardware_interface/RRBotHardwareInterface</plugin>
 </hardware>
 <joint name="joint1">
 <command_interface name="position">
 <param name="min">-1</param>
 <param name="max">1</param>
 </command_interface>
 <state_interface name="position"/>


      if (found)
      {
        // check if controller exist already in the list and if not add it
        auto controllers = resource_storage_->hardware_used_by_controllers_[hw_name];
        auto ctrl_it = std::find(controllers.begin(), controllers.end(), controller_name);
        if (ctrl_it == controllers.end())
        {
          // add because it does not exist
          controllers.reserve(controllers.size() + 1);
          controllers.push_back(controller_name);
        }
        resource_storage_->hardware_used_by_controllers_[hw_name] = controllers;
        break;
      }
    }
  }
}


demos repository the _example_1_ ](https://github.com/ros-
controls/ros2_control_demos/pull/396) has been adapted to showcase the changes
and test the approach.
##  Idea
The idea is that the creation of the ` Command-/StateInterface ` is no longer
handled by the HW (user) but instead by the Framework. The user doesn't need
to know about creation of ` Command-/StateInterface ` and creation and
management of local memory. Instead, the ` Command-/StateInterface ` are
defined in the urdf as before and then everything is handled automatically by
the Framework. The HW only needs to set/get states or set/get commands via
functions provided by the component interface.
Additionally, the Handles are now prepared to support more than double as
datatype (std::variant is used) and could in future provide functionality to
check if the Handles has been updated since now the value is stored directly
in the handle instead a pointer.
The export_command/state_interfaces_2() function is going to be renamed to
export_command/state_interfaces() as soon as the deprecated version is
removed. This step is necessary as no return type polymorphism is possible and
we later want abase function the user can override to export custom unlisted
interfaces.
##  Description
With this PR the exportation and creation of the ` Command-/StateInterface `
is now handled by the Framework with ` on_export_state_interface() ` and `
on_export_command_interface() ` instead of the HW-component exporting them via
the ` export_state_interface() ` or ` export_command_interface() ` .
The ` Command-/StateInterface ` are created based on an ` InterfaceDescription
` which encapsulates all the information about an interface and is directly
parsed from the urdf. This includes data_type, default_values, min and max. `
Command-/StateInterface ` are stored in the component interface (Actuator-,
Sensor- or SystemInterface). The resource manager gets shared_ptr to the `
Command-/StateInterface ` .
The ` Command-/StateInterface ` are now store the value directly. There is no
raw pointer to memory in the HW passed to the ` Command-/StateInterface ` . A
component can then set/get values from the ` Command-/StateInterface ` via `
set_state ` / ` get_state ` and ` set_commad ` / ` get_command ` functions
provided by the component interface. In addition, the value is now of typ `
std::variant `
##  Overview
  * replace ` export_state_interface() ` or ` export_command_interface() ` with ` on_export_state_interface() ` and ` on_export_command_interface() ` in component interface -> Framework handles creation of ` Command-/StateInterface `
  * Memory was moved from HW into the Handle -> HW doesn't need to create/manage memory. Support for std::variant (different datatypes than double in Handles). Support to for example check in Handle if the value of Handle has been changed. Support for distributed control.


    if (result)
    {
      // TODO(destogl): make all command interfaces unavailable that should be present only
      // when active (currently are all available) also at inactive
    }
    return result;
  }


  template <class HardwareT>
  bool set_component_state(HardwareT & hardware, const rclcpp_lifecycle::State & target_state)
  {
    using lifecycle_msgs::msg::State;


    if (hardware_info.is_async)
    {
      init_sensors(async_sensors_);
    }
    else
    {
      init_sensors(sensors_);
    }
  }


I followed the ros2 control course and tried to use the dynamixel hardware
interface in my own labtop and this error was come. I’m not familiar with C++
so If someone know what should I fix, please tell me. Basically, I just copy
and paste the code from the code to my pkg. I use ros2 foxy and DynamixelSDK
and also workbench were also cloned from foxy-devel branch. In the terminal
inside the Construct, nothing error.


    if (result)
    {
      RCUTILS_LOG_INFO_NAMED(
        "resource_manager", "Successful initialization of hardware '%s'",
        hardware_info.name.c_str());
    }
    else
    {
      RCUTILS_LOG_INFO_NAMED(
        "resource_manager", "Failed to initialize hardware '%s'", hardware_info.name.c_str());
    }
    return result;
  }


  return resource_storage_->hardware_info_map_;
}


// CM API: Called in "callback/slow"-thread
bool ResourceManager::command_interface_is_available(const std::string & name) const
{
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return std::find(
           resource_storage_->available_command_interfaces_.begin(),
           resource_storage_->available_command_interfaces_.end(),
           name) != resource_storage_->available_command_interfaces_.end();
}


[ The Construct ROS Community ](/)


double  |  **get_value** () const

##  Additional Inherited Members

---
![-](closed.png) Protected Attributes inherited from [
hardware_interface::ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html)
std::string  |  **name_**
std::string  |  **interface_name_**
double *  |  **value_ptr_**

* * *


  std::lock_guard<std::recursive_mutex> guard_claimed(claimed_command_interfaces_lock_);
  if (command_interface_is_claimed(key))
  {
    throw std::runtime_error(
      std::string("Command interface with '") + key + "' is already claimed");
  }


// CM API: Called in "callback/slow"-thread
std::vector<std::string> ResourceManager::command_interface_keys() const
{
  std::vector<std::string> keys;
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  for (const auto & item : resource_storage_->command_interface_map_)
  {
    keys.push_back(std::get<0>(item));
  }
  return keys;
}


    if (hardware_info.is_async)
    {
      load_and_init_systems(async_systems_);
    }
    else
    {
      load_and_init_systems(systems_);
    }
  }


---|---|---
|  |  void import_command_interfaces(HardwareT & hardware)
|  |  {
|  |  auto interfaces = hardware.export_command_interfaces();
|  |  std::vector<std::shared_ptr<CommandInterface>> interfaces =
|  |  hardware.export_command_interfaces();

Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 17, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
Suggested change
|  hardware.  export_command_interfaces  ();
---|---
|  hardware.  on_export_command_interfaces  ();

Shouldn't this be using ` on_export_command_interfaces ` as well?
If this is the case, I belive some methods can be removed from this file
Sorry, something went wrong.
All reactions
Copy link
Contributor  Author
###
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=48&v=4) **[
mamueluth ](/mamueluth) ** Apr 11, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment


URDF and ros2_control
<ros2_control name="${name}" type="system">
 <hardware>
 <plugin>fake_components/GenericSystem</plugin>
 </hardware>
 <joint name="joint1">
 <command_interface name="position">
 <param name="min">-1</param>
 <param name="max">1</param>
 </command_interface>
 <state_interface name="position"/>
 </joint>
 <joint name="joint2">
 <command_interface name="position">
 <param name="min">-1</param>
 <param name="max">1</param>
 </command_interface>
 <state_interface name="position"/>
 </joint>
</ros2_control>
Implementing a system component
class RRBotHardwareInterface
 : public hardware_interface::BaseInterface<hardware_interface::SystemInterface>
{
public:
 hardware_interface::return_type configure(const hardware_interface::HardwareInfo & info) override;
 std::vector<hardware_interface::StateInterface> export_state_interfaces() override;
 std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;
 hardware_interface::return_type start() override;
 hardware_interface::return_type stop() override;
 hardware_interface::return_type read() override;
 hardware_interface::return_type write() override;
private:
 std::vector<double> hw_commands_;
 std::vector<double> hw_states_;
};
Implementing a system component
hardware_interface::return_type RRBotHardwareInterface::configure(
 const hardware_interface::HardwareInfo & info)
{


  template <class HardwareT>
  bool configure_hardware(HardwareT & hardware)
  {
    bool result = trigger_and_print_hardware_state_transition(
      std::bind(&HardwareT::configure, &hardware), "configure", hardware.get_name(),
      lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE);


    In file included from /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:7:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp:44:3: error: ‘CallbackReturn’ does not name a type
       44 |   CallbackReturn on_init(const hardware_interface::HardwareInfo & info) override;
          |   ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp:50:3: error: ‘CallbackReturn’ does not name a type
       50 |   CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
          |   ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp:52:3: error: ‘CallbackReturn’ does not name a type
       52 |   CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
          |   ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:27:1: error: ‘CallbackReturn’ does not name a type
       27 | CallbackReturn DynamixelHardware::on_init(const hardware_interface::HardwareInfo & info)
          | ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual std::vector<hardware_interface::StateInterface> dynamixel_hardware::DynamixelHardware::export_state_interfaces()’:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:157:24: error: ‘info_’ was not declared in this scope
      157 |   for (uint i = 0; i < info_.joints.size(); i++) {
          |                        ^~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual std::vector<hardware_interface::CommandInterface> dynamixel_hardware::DynamixelHardware::export_command_interfaces()’:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:173:24: error: ‘info_’ was not declared in this scope
      173 |   for (uint i = 0; i < info_.joints.size(); i++) {
          |                        ^~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: At global scope:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:183:1: error: ‘CallbackReturn’ does not name a type
      183 | CallbackReturn DynamixelHardware::on_activate(const rclcpp_lifecycle::State & previous_state)
          | ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:200:1: error: ‘CallbackReturn’ does not name a type
      200 | CallbackReturn DynamixelHardware::on_deactivate(const rclcpp_lifecycle::State & previous_state)
          | ^~~~~~~~~~~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual hardware_interface::return_type dynamixel_hardware::DynamixelHardware::read()’:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:212:28: error: ‘info_’ was not declared in this scope
      212 |   std::vector<uint8_t> ids(info_.joints.size(), 0);
          |                            ^~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual hardware_interface::return_type dynamixel_hardware::DynamixelHardware::write()’:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:265:28: error: ‘info_’ was not declared in this scope
      265 |   std::vector<uint8_t> ids(info_.joints.size(), 0);
          |                            ^~~~~
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘hardware_interface::return_type dynamixel_hardware::DynamixelHardware::enable_torque(bool)’:
    /home/tharit/ros2_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:310:26: error: ‘info_’ was not declared in this scope


// BEGIN: "used only in tests and locally"
size_t ResourceManager::actuator_components_size() const
{
  return resource_storage_->actuators_.size();
}


// CM API: Called in "update"-thread
HardwareReadWriteStatus ResourceManager::write(
  const rclcpp::Time & time, const rclcpp::Duration & period)
{
  std::lock_guard<std::recursive_mutex> guard(resources_lock_);
  read_write_status.ok = true;
  read_write_status.failed_hardware_names.clear();


By this the error about override came. So I just delete overrride specifier
now the error is here


##  Public Member Functions

---
|  **StateInterface** (const [ StateInterface
](classhardware__interface_1_1StateInterface.html) &other)=default
|  **StateInterface** ( [ StateInterface
](classhardware__interface_1_1StateInterface.html) &&other)=default
|  **ReadOnlyHandle** (const std::string &name, const std::string
&interface_name, double *value_ptr=nullptr)
|  **ReadOnlyHandle** (const std::string &interface_name)
|  **ReadOnlyHandle** (const char *interface_name)
|  **ReadOnlyHandle** (const [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &other)=default
|  **ReadOnlyHandle** ( [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &&other)=default
![-](closed.png) Public Member Functions inherited from [
hardware_interface::ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html)
|  **ReadOnlyHandle** (const std::string &name, const std::string
&interface_name, double *value_ptr=nullptr)
|  **ReadOnlyHandle** (const std::string &interface_name)
|  **ReadOnlyHandle** (const char *interface_name)
|  **ReadOnlyHandle** (const [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &other)=default
|  **ReadOnlyHandle** ( [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &&other)=default
[ ReadOnlyHandle ](classhardware__interface_1_1ReadOnlyHandle.html) & |
**operator=** (const [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &other)=default
[ ReadOnlyHandle ](classhardware__interface_1_1ReadOnlyHandle.html) & |
**operator=** ( [ ReadOnlyHandle
](classhardware__interface_1_1ReadOnlyHandle.html) &&other)=default
|  [ operator bool
](classhardware__interface_1_1ReadOnlyHandle.html#a964b07a6a0f5b2414e070e5a8a1f746e)
() const
|  Returns true if handle references a value.

const std::string & |  **get_name** () const
const std::string & |  **get_interface_name** () const
const std::string  |  **get_full_name** () const


return_type result = return_type::OK;


const rclcpp_lifecycle::State new_state = hardware.initialize(hardware_info);


void ResourceManager::import_component(
  std::unique_ptr<ActuatorInterface> actuator, const HardwareInfo & hardware_info)
{
  std::lock_guard<std::recursive_mutex> guard(resources_lock_);
  resource_storage_->initialize_actuator(std::move(actuator), hardware_info);
  read_write_status.failed_hardware_names.reserve(
    resource_storage_->actuators_.size() + resource_storage_->sensors_.size() +
    resource_storage_->systems_.size());
}


[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth) [ mamueluth ](/mamueluth) [ force-pushed ](/ros-
controls/ros2_control/compare/abac29ec8313293138d8e295a38bd1fcc1d38efe..4b2328a0b4d753752ab783c251cd6af2518ac616)
the  change_interface_export_variant  branch from [ ` abac29e ` ](/ros-
controls/ros2_control/commit/abac29ec8313293138d8e295a38bd1fcc1d38efe) to [ `
4b2328a ` ](/ros-
controls/ros2_control/commit/4b2328a0b4d753752ab783c251cd6af2518ac616) [
Compare  ](/ros-
controls/ros2_control/compare/abac29ec8313293138d8e295a38bd1fcc1d38efe..4b2328a0b4d753752ab783c251cd6af2518ac616)
April 11, 2024 08:12
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=80&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth)
Copy link
Contributor  Author
###
**[ mamueluth ](/mamueluth) ** commented  Apr 11, 2024  •
edited
> I like the approach, considering the cleaner code as demonstrated with
> example_1 and the (as by now, theoretical) support of other datatypes. I
> don't comment on the code as this has been done extensively by others
> already.
>
> What is missing for my approval is an update to the documentation:
>
>
>     * [ ]  A migration guide [here](https://github.com/ros-
> controls/ros2_control/blob/master/doc/migration/Iron.rst).
>
>     * [ ]  Update the [Writing a Hardware
> Component](https://control.ros.org/master/doc/ros2_control/hardware_interface/doc/writing_new_hardware_component.html#writing-
> a-hardware-component) section
>
[ @christophfroehlich ](https://github.com/christophfroehlich) can you please
check the migration guide and the updated docs

---

All reactions


            result = shutdown_hardware(hardware);
            break;
          case State::PRIMARY_STATE_FINALIZED:
            result = true;
            break;
        }
        break;
    }


ResourceManager::ResourceManager(
  const std::string & urdf, bool validate_interfaces, bool activate_all, unsigned int update_rate,
  rclcpp::node_interfaces::NodeClockInterface::SharedPtr clock_interface)
: resource_storage_(std::make_unique<ResourceStorage>(update_rate, clock_interface))
{
  load_urdf(urdf, validate_interfaces);


  template <class HardwareT>
  bool cleanup_hardware(HardwareT & hardware)
  {
    bool result = trigger_and_print_hardware_state_transition(
      std::bind(&HardwareT::cleanup, &hardware), "cleanup", hardware.get_name(),
      lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED);


    CallbackReturn DynamixelHardware::on_deactivate(const rclcpp_lifecycle::State & previous_state)
    {
      RCLCPP_DEBUG(rclcpp::get_logger(kDynamixelHardware), "stop");
      return CallbackReturn::SUCCESS;
    }

    return_type DynamixelHardware::read()
    {
      if (use_dummy_) {
        return return_type::OK;
      }

      std::vector<uint8_t> ids(info_.joints.size(), 0);
      std::vector<int32_t> positions(info_.joints.size(), 0);
      std::vector<int32_t> velocities(info_.joints.size(), 0);
      std::vector<int32_t> currents(info_.joints.size(), 0);

      std::copy(joint_ids_.begin(), joint_ids_.end(), ids.begin());
      const char * log = nullptr;

      if (!dynamixel_workbench_.syncRead(
            kPresentPositionVelocityCurrentIndex, ids.data(), ids.size(), &log)) {
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
      }

      if (!dynamixel_workbench_.getSyncReadData(
            kPresentPositionVelocityCurrentIndex, ids.data(), ids.size(),
            control_items_[kPresentCurrentItem]->address,
            control_items_[kPresentCurrentItem]->data_length, currents.data(), &log)) {
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
      }

      if (!dynamixel_workbench_.getSyncReadData(
            kPresentPositionVelocityCurrentIndex, ids.data(), ids.size(),
            control_items_[kPresentVelocityItem]->address,
            control_items_[kPresentVelocityItem]->data_length, velocities.data(), &log)) {
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
      }


  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return LoanedStateInterface(resource_storage_->state_interface_map_.at(key));
}


      if (!dynamixel_workbench_.getSyncReadData(
            kPresentPositionVelocityCurrentIndex, ids.data(), ids.size(),
            control_items_[kPresentPositionItem]->address,
            control_items_[kPresentPositionItem]->data_length, positions.data(), &log)) {
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
      }

      for (uint i = 0; i < ids.size(); i++) {
        joints_[i].state.position = dynamixel_workbench_.convertValue2Radian(ids[i], positions[i]);
        joints_[i].state.velocity = dynamixel_workbench_.convertValue2Velocity(ids[i], velocities[i]);
        joints_[i].state.effort = dynamixel_workbench_.convertValue2Current(currents[i]);
      }

      return return_type::OK;
    }

    return_type DynamixelHardware::write()
    {
      if (use_dummy_) {
        for (auto & joint : joints_) {
          joint.state.position = joint.command.position;
        }

        return return_type::OK;
      }

      std::vector<uint8_t> ids(info_.joints.size(), 0);
      std::vector<int32_t> commands(info_.joints.size(), 0);

      std::copy(joint_ids_.begin(), joint_ids_.end(), ids.begin());
      const char * log = nullptr;

      if (std::any_of(
            joints_.cbegin(), joints_.cend(), [](auto j) { return j.command.velocity != 0.0; })) {
        // Velocity control
        set_control_mode(ControlMode::Velocity);
        for (uint i = 0; i < ids.size(); i++) {
          commands[i] = dynamixel_workbench_.convertVelocity2Value(
            ids[i], static_cast<float>(joints_[i].command.velocity));
        }


Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Jan 23, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. [ Learn more
](https://docs.github.com/articles/managing-disruptive-comments/#hiding-a-
comment) .
Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
Suggested change
|  std::vector< std::shared_ptr<StateInterface> >
Actuator::on_export_state_interfaces  ()
---|---
|  std::vector< StateInterfaceSharedPtr  >
Actuator::on_export_state_interfaces  ()

Sorry, something went wrong.
All reactions
[ hardware_interface/src/actuator.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
ef3775b758b1e2366de15b39245eff2f7b3c664f24f9f5a75d3795534466ecc3) Outdated
Show resolved  Hide resolved
[ ![saikishor](https://avatars.githubusercontent.com/u/10082428?s=60&v=4)
](/saikishor)
**[ saikishor ](/saikishor) ** reviewed  Jan 23, 2024
[ View reviewed changes  ](/ros-controls/ros2_control/pull/1240/files)
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Show resolved  Hide resolved
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=80&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth)
Copy link
Contributor  Author
###
**[ mamueluth ](/mamueluth) ** commented  Jan 23, 2024
Think i changed everything.


ROS2 Control

---

  * [ hardware_interface ](namespacehardware__interface.html)
  * [ StateInterface ](classhardware__interface_1_1StateInterface.html)


            RCUTILS_LOG_WARN_NAMED(
              "resource_manager", "hardware '%s' is in finalized state and can be only destroyed.",
              hardware.get_name().c_str());
            break;
        }
        break;
      case State::PRIMARY_STATE_ACTIVE:
        switch (hardware.get_state().id())
        {
          case State::PRIMARY_STATE_UNCONFIGURED:
            result = configure_hardware(hardware);
            if (result)
            {
              result = activate_hardware(hardware);
            }
            break;
          case State::PRIMARY_STATE_INACTIVE:
            result = activate_hardware(hardware);
            break;
          case State::PRIMARY_STATE_ACTIVE:
            result = true;
            break;
          case State::PRIMARY_STATE_FINALIZED:
            result = false;
            RCUTILS_LOG_WARN_NAMED(
              "resource_manager", "hardware '%s' is in finalized state and can be only destroyed.",
              hardware.get_name().c_str());
            break;
        }
        break;
      case State::PRIMARY_STATE_FINALIZED:
        switch (hardware.get_state().id())
        {
          case State::PRIMARY_STATE_UNCONFIGURED:
            result = shutdown_hardware(hardware);
            break;
          case State::PRIMARY_STATE_INACTIVE:
            result = shutdown_hardware(hardware);
            break;
          case State::PRIMARY_STATE_ACTIVE:


the  change_interface_export_variant  branch from [ ` 7c07d0c ` ](/ros-
controls/ros2_control/commit/7c07d0c6bf0b677fe0feedd48d5343c5b8e9079a) to [ `
8dec983 ` ](/ros-
controls/ros2_control/commit/8dec983a6d3ca945ad6f4277b935f6d466e68120) [
Compare  ](/ros-
controls/ros2_control/compare/7c07d0c6bf0b677fe0feedd48d5343c5b8e9079a..8dec983a6d3ca945ad6f4277b935f6d466e68120)
April 10, 2024 13:18
[ mamueluth ](/mamueluth) added  21  commits  April 11, 2024 10:12
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ move creation of stateinterfaces to systeminterface ](/ros-
controls/ros2_control/pull/1240/commits/19395581d4e3183d4bc5ec772cf3d9ee7997be35
"move creation of stateinterfaces to systeminterface") `
` [ 1939558 ](/ros-
controls/ros2_control/pull/1240/commits/19395581d4e3183d4bc5ec772cf3d9ee7997be35)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ store description in state_interface and provide functions for ](/ros-
controls/ros2_control/pull/1240/commits/efcc37615ed1a85184e112ed9f3bbd858a77d05b
"store description in state_interface and provide functions for
setting/gettting") ` …
` [ efcc376 ](/ros-
controls/ros2_control/pull/1240/commits/efcc37615ed1a85184e112ed9f3bbd858a77d05b)
`

    setting/gettting
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ return correct name for InterfaceDescription ](/ros-
controls/ros2_control/pull/1240/commits/b76b8695ab7f7a2aa2128c3bab5662858363d398
"return correct name for InterfaceDescription") `
` [ b76b869 ](/ros-
controls/ros2_control/pull/1240/commits/b76b8695ab7f7a2aa2128c3bab5662858363d398)
`
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ move parsing of interface description to component parser ](/ros-
controls/ros2_control/pull/1240/commits/5635631fc6cbd00785eca8e4bc60e971f31caf21


  void load_and_initialize_system(const HardwareInfo & hardware_info)
  {
    auto load_and_init_systems = [&](auto & container)
    {
      check_for_duplicates(hardware_info);
      load_hardware<System, SystemInterface>(hardware_info, system_loader_, container);
      if (initialize_hardware(hardware_info, container.back()))
      {
        import_state_interfaces(container.back());
        import_command_interfaces(container.back());
      }
      else
      {
        RCUTILS_LOG_WARN_NAMED(
          "resource_manager",
          "System hardware component '%s' from plugin '%s' failed to initialize.",
          hardware_info.name.c_str(), hardware_info.hardware_plugin_name.c_str());
      }
    };


  // throw on missing state and command interfaces, not specified keys are being ignored
  if (validate_interfaces)
  {
    validate_storage(hardware_info);
  }


  const bool actuators_result = call_prepare_mode_switch(resource_storage_->actuators_);
  const bool systems_result = call_prepare_mode_switch(resource_storage_->systems_);


  void initialize_actuator(
    std::unique_ptr<ActuatorInterface> actuator, const HardwareInfo & hardware_info)
  {
    auto init_actuators = [&](auto & container)
    {
      container.emplace_back(Actuator(std::move(actuator)));
      if (initialize_hardware(hardware_info, container.back()))
      {
        import_state_interfaces(container.back());
        import_command_interfaces(container.back());
      }
      else
      {
        RCUTILS_LOG_WARN_NAMED(
          "resource_manager",
          "Actuator hardware component '%s' from plugin '%s' failed to initialize.",
          hardware_info.name.c_str(), hardware_info.hardware_plugin_name.c_str());
      }
    };