        for (uint i = 0; i < info_.joints.size(); ++i) {
          if (!dynamixel_workbench_.torqueOff(joint_ids_[i], &log)) {
            RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
            return return_type::ERROR;
          }
        }
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "Torque disabled");
      }

      torque_enabled_ = enabled;
      return return_type::OK;
    }

    return_type DynamixelHardware::set_control_mode(const ControlMode & mode, const bool force_set)
    {
      const char * log = nullptr;

      if (mode == ControlMode::Velocity && (force_set || control_mode_ != ControlMode::Velocity)) {
        bool torque_enabled = torque_enabled_;
        if (torque_enabled) {
          enable_torque(false);
        }

        for (uint i = 0; i < joint_ids_.size(); ++i) {
          if (!dynamixel_workbench_.setVelocityControlMode(joint_ids_[i], &log)) {
            RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
            return return_type::ERROR;
          }
        }
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "Velocity control");
        control_mode_ = ControlMode::Velocity;

        if (torque_enabled) {
          enable_torque(true);
        }
      } else if (
        mode == ControlMode::Position && (force_set || control_mode_ != ControlMode::Position)) {
        bool torque_enabled = torque_enabled_;
        if (torque_enabled) {
          enable_torque(false);


  auto call_prepare_mode_switch =
    [&start_interfaces, &stop_interfaces, &interfaces_to_string](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.prepare_command_mode_switch(start_interfaces, stop_interfaces))
        {
          RCUTILS_LOG_ERROR_NAMED(
            "resource_manager",
            "Component '%s' did not accept command interfaces combination: \n%s",
            component.get_name().c_str(), interfaces_to_string().c_str());
          ret = false;
        }
      }
    }
    return ret;
  };


    #include <algorithm>
    #include <array>
    #include <string>
    #include <limits>
    #include <vector>

    #include "dynamixel_hardware_interface/dynamixel_hardware_interface.hpp"
    #include "hardware_interface/types/hardware_interface_return_values.hpp"
    #include "hardware_interface/types/hardware_interface_type_values.hpp"
    #include "rclcpp/rclcpp.hpp"

    namespace dynamixel_hardware
    {
    constexpr const char * kDynamixelHardware = "DynamixelHardware";
    constexpr uint8_t kGoalPositionIndex = 0;
    constexpr uint8_t kGoalVelocityIndex = 1;
    constexpr uint8_t kPresentPositionVelocityCurrentIndex = 0;
    constexpr const char * kGoalPositionItem = "Goal_Position";
    constexpr const char * kGoalVelocityItem = "Goal_Velocity";
    constexpr const char * kMovingSpeedItem = "Moving_Speed";
    constexpr const char * kPresentPositionItem = "Present_Position";
    constexpr const char * kPresentVelocityItem = "Present_Velocity";
    constexpr const char * kPresentSpeedItem = "Present_Speed";
    constexpr const char * kPresentCurrentItem = "Present_Current";
    constexpr const char * kPresentLoadItem = "Present_Load";

    CallbackReturn DynamixelHardware::on_init(const hardware_interface::HardwareInfo & info)
    {
      RCLCPP_DEBUG(rclcpp::get_logger(kDynamixelHardware), "configure");
      if (hardware_interface::SystemInterface::on_init(info) != CallbackReturn::SUCCESS)
      {
        return CallbackReturn::ERROR;
      }

      joints_.resize(info_.joints.size(), Joint());
      joint_ids_.resize(info_.joints.size(), 0);

      for (uint i = 0; i < info_.joints.size(); i++) {


Karsten Knese, Victor Lopez,
Jordan Palacios, Olivier
Stasse, Mathias Arbo, Jaron
Lundwall, Colin MacKenzie,
Matthew Reynolds, Andy
Zelenak, Lovro Ivanov, Jafar
Abdi, Tyler Weaver, Anas Abou
Allaban, Yutaka Kondo, Mateus
Amarante, Auguste Bourgois
and many more!
Thank you!


  * [ Actions  ](/ros-controls/ros2_control/actions)
  * [ Projects  0  ](/ros-controls/ros2_control/projects)
  * [ Security  ](/ros-controls/ros2_control/security)
  * [ Insights  ](/ros-controls/ros2_control/pulse)
Additional navigation options
  * [ Code  ](/ros-controls/ros2_control)
  * [ Issues  ](/ros-controls/ros2_control/issues)
  * [ Pull requests  ](/ros-controls/ros2_control/pulls)
  * [ Actions  ](/ros-controls/ros2_control/actions)
  * [ Projects  ](/ros-controls/ros2_control/projects)
  * [ Security  ](/ros-controls/ros2_control/security)
  * [ Insights  ](/ros-controls/ros2_control/pulse)
New issue
**Have a question about this project?** Sign up for a free GitHub account to
open an issue and contact its maintainers and the community.
Pick a username

Email Address

Password

Sign up for GitHub
By clicking “Sign up for GitHub”, you agree to our [ terms of service
](https://docs.github.com/terms) and [ privacy statement
](https://docs.github.com/privacy) . We’ll occasionally send you account
related emails.
Already on GitHub? [ Sign in ](/login?return_to=%2Fros-
controls%2Fros2_control%2Fissues%2Fnew%2Fchoose) to your account
Jump to bottom
#  [HW Interface] Change creation, exportation and storing of
Command-/StateInterface + Support for variant  #1240
Open
[ mamueluth ](/mamueluth) wants to merge  22  commits into  [ ros-controls  :
master  ](/ros-controls/ros2_control/tree/master "ros-
controls/ros2_control:master")
_base:_ master
Choose a base branch
Branches  Tags
Could not load branches
Branch not found: **{{ refName }}**


auto found_it = resource_storage_->hardware_info_map_.find(component_name);


  // Update rate of the controller manager, and the clock interface of its node
  // Used by async components.
  unsigned int cm_update_rate_;
  rclcpp::node_interfaces::NodeClockInterface::SharedPtr clock_interface_;
};


void ResourceManager::validate_storage(
  const std::vector<hardware_interface::HardwareInfo> & hardware_info) const
{
  std::vector<std::string> missing_state_keys = {};
  std::vector<std::string> missing_command_keys = {};


#include "hardware_interface/resource_manager.hpp"


Currently, the error is solved by define the CallbackReturn in the .hpp file.


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


  /// Vectors with interfaces available to controllers (depending on hardware component state)
  std::vector<std::string> available_state_interfaces_;
  std::vector<std::string> available_command_interfaces_;


        if (!dynamixel_workbench_.syncWrite(
              kGoalVelocityIndex, ids.data(), ids.size(), commands.data(), 1, &log)) {
          RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
        }
        return return_type::OK;
      } else if (std::any_of(
                   joints_.cbegin(), joints_.cend(), [](auto j) { return j.command.effort != 0.0; })) {
        // Effort control
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "Effort control is not implemented");
        return return_type::ERROR;
      }

      // Position control
      set_control_mode(ControlMode::Position);
      for (uint i = 0; i < ids.size(); i++) {
        commands[i] = dynamixel_workbench_.convertRadian2Value(
          ids[i], static_cast<float>(joints_[i].command.position));
      }
      if (!dynamixel_workbench_.syncWrite(
            kGoalPositionIndex, ids.data(), ids.size(), commands.data(), 1, &log)) {
        RCLCPP_ERROR(rclcpp::get_logger(kDynamixelHardware), "%s", log);
      }

      return return_type::OK;
    }

    return_type DynamixelHardware::enable_torque(const bool enabled)
    {
      const char * log = nullptr;

      if (enabled && !torque_enabled_) {
        for (uint i = 0; i < info_.joints.size(); ++i) {
          if (!dynamixel_workbench_.torqueOn(joint_ids_[i], &log)) {
            RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
            return return_type::ERROR;
          }
        }
        reset_command();
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "Torque enabled");
      } else if (!enabled && torque_enabled_) {


#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>


  * [ Home ](/)
  * [ Categories ](/categories)
  * [ FAQ/Guidelines ](/guidelines)
  * [ Terms of Service ](http://www.theconstructsim.com/terms_and_conditions/)
  * [ Privacy Policy ](http://www.theconstructsim.com/privacy_policy/)


[ Course Support  ](/c/course-support/ros2-control/69) [ ROS2 Control
Framework  ](/c/course-support/ros2-control/69)


  void load_and_initialize_sensor(const HardwareInfo & hardware_info)
  {
    auto load_and_init_sensors = [&](auto & container)
    {
      check_for_duplicates(hardware_info);
      load_hardware<Sensor, SensorInterface>(hardware_info, sensor_loader_, container);
      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());
      }
    };


 uint32 size
 uint32 stride
 uint32 data_offset
float64[] data
std_msgs/Header header
string[] joint_names
float64[] displacements
float64[] velocities
float64 duration
example_msgs/Float64MultiArray control_msgs/JointJog
Messages and modifying a controller
class RRBotController : public controller_interface::ControllerInterface
{
public:
 ...
protected:
 ...


|  |  HARDWARE_INTERFACE_PUBLIC
|  |  std::vector<StateInterface> export_state_interfaces();
|  |  std::vector< std::shared_ptr< StateInterface  > >
export_state_interfaces();

Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 13, 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
I recommend defining the ` typedef ` or ` using ` like StateInterfacePtr and
use it instead of having std::shared_ptr. Not important but nice to have
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
|  |  *
---|---|---
|  |  * \return vector of descriptions to the unlisted StateInterfaces
|  |  */
|  |  virtual std::vector<hardware_interface::InterfaceDescription>
export_state_interfaces_2()

Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 13, 2024
There was a problem hiding this comment.
###  Choose a reason for hiding this comment


  bool found = find_set_component_state(
    std::bind(&ResourceStorage::set_component_state<Actuator>, resource_storage_.get(), _1, _2),
    resource_storage_->actuators_);
  if (!found)
  {
    found = find_set_component_state(
      std::bind(&ResourceStorage::set_component_state<Sensor>, resource_storage_.get(), _1, _2),
      resource_storage_->sensors_);
  }
  if (!found)
  {
    found = find_set_component_state(
      std::bind(&ResourceStorage::set_component_state<System>, resource_storage_.get(), _1, _2),
      resource_storage_->systems_);
  }
  if (!found)
  {
    found = find_set_component_state(
      std::bind(&ResourceStorage::set_component_state<Actuator>, resource_storage_.get(), _1, _2),
      resource_storage_->async_actuators_);
  }
  if (!found)
  {
    found = find_set_component_state(
      std::bind(&ResourceStorage::set_component_state<System>, resource_storage_.get(), _1, _2),
      resource_storage_->async_systems_);
  }
  if (!found)
  {
    found = find_set_component_state(
      std::bind(&ResourceStorage::set_component_state<Sensor>, resource_storage_.get(), _1, _2),
      resource_storage_->async_sensors_);
  }


  auto find_set_component_state = [&](auto action, auto & components)
  {
    auto found_component_it = std::find_if(
      components.begin(), components.end(),
      [&](const auto & component) { return component.get_name() == component_name; });


        if (!command_interface_exists(gpio.name + "/" + command_interface.name))
        {
          missing_command_keys.emplace_back(gpio.name + "/" + command_interface.name);
        }
      }
    }
  }


bool result = new_state.id() == target_state;


This topic was automatically closed 7 days after the last reply. New replies
are no longer allowed.


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


  std::vector<Actuator> actuators_;
  std::vector<Sensor> sensors_;
  std::vector<System> systems_;


// CM API: Called in "callback/slow"-thread
std::vector<std::string> ResourceManager::get_controller_reference_interface_names(
  const std::string & controller_name)
{
  return resource_storage_->controllers_reference_interfaces_map_.at(controller_name);
}


class ResourceStorage
{
  static constexpr const char * pkg_name = "hardware_interface";


      // add command interfaces to available list
      for (const auto & interface : hardware_info_map_[hardware.get_name()].command_interfaces)
      {
        // TODO(destogl): check if interface should be available on configure
        auto found_it = std::find(
          available_command_interfaces_.begin(), available_command_interfaces_.end(), interface);


Hello [ @pbnpama ](/u/pbnpama) ,


  std::lock_guard<std::recursive_mutex> guard(resources_lock_);
  read_write_status.failed_hardware_names.reserve(
    resource_storage_->actuators_.size() + resource_storage_->sensors_.size() +
    resource_storage_->systems_.size());
}


ros2_control - a robot-agnostic
control framework for ROS2
WR Meetup #13 – 7 Oct. 2021
Outline
● Why do we need a control framework in ROS/ROS2?
● History & basic concepts
● How to use ros(1)_control?
● What is a bit tricky in ros(1)_control?
● Architecture of ros2_control
● “Everything is an interface ”
● URDF extension with <ros2_control>-tag
● Examples from users
Buckle up, this will be an adventure :)
$whoarewe
Bence Magyar
● PhD in Robotics
● Lead Software Engineer at FiveAI
● ros_control and ros2_control maintainer
Denis Štogl
● Control Engineer and Roboticist (PhD soon official)
● Robotics Consultant at Stogl Robotics Consulting
● ros2_control maintainer
Why do we need a control framework in ROS?
1. “Control” is tricky — everybody needs it (to run a physical robot)
2. “Stop reinventing the wheel when controlling hardware”
● Provide standardized interfaces for “high-level”/task control “nodes”
○ MoveIt, Navigation, <your_sexy_cool_application>, …
● Establish standard set of controllers:
○ “Implement control-method once and use it on various hardware”
● To implement access management each time is annoying
● Optimize controllers and management-functions for real-time performance
● Standardization of hardware-abstraction layer
What & where
pr2_controller_manager
(pr2_mechanism)
2009
ros_control
2012/2013
ros2_control
2017/2021


      if (found_it != available_state_interfaces_.end())
      {
        available_state_interfaces_.erase(found_it);
        RCUTILS_LOG_DEBUG_NAMED(
          "resource_manager", "(hardware '%s'): '%s' state interface removed from available list",
          hardware_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 not in available list. "
          "This should not happen (hint: multiple cleanup calls).",
          hardware_name.c_str(), interface.c_str());
      }
    }
  }


    return result;
  }


* hardware_interface/include/hardware_interface/ [ handle.hpp ](hardware__interface_2include_2hardware__interface_2handle_8hpp_source.html)


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


  /// Storage of all available state interfaces
  std::map<std::string, StateInterface> state_interface_map_;
  /// Storage of all available command interfaces
  std::map<std::string, CommandInterface> command_interface_map_;


  return result;
}


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


|  |  * \return vector of descriptions to the unlisted StateInterfaces
|  |  */
|  |  virtual std::vector<hardware_interface::InterfaceDescription>
export_state_interfaces_2()

Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 14, 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_state_interfaces_2  ()
---|---
|  virtual  std::vector<hardware_interface::InterfaceDescription>
export_state_interface_description  ()

Sorry, something went wrong.
All reactions
7 hidden conversations  Load more…
[ hardware_interface/include/hardware_interface/system_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
dbaf9de12582df8a9762c4f68267da70d479584cbaddc35f9726acf3fad8302a)
|  |  *
---|---|---
|  |  * \return vector of descriptions to the unlisted CommandInterfaces
|  |  */
|  |  virtual std::vector<hardware_interface::InterfaceDescription>
export_command_interfaces_2()

Copy link
Member
###


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


    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:30:44: error: ‘on_init’ is not a member of ‘hardware_interface::SystemInterface’
       30 |   if (hardware_interface::SystemInterface::on_init(info) != CallbackReturn::SUCCESS)
          |                                            ^~~~~~~
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:35:18: error: ‘info_’ was not declared in this scope; did you mean ‘info’?
       35 |   joints_.resize(info_.joints.size(), Joint());
          |                  ^~~~~
          |                  info
    /home/tharit/moonbot_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/moonbot_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/moonbot_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/moonbot_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/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘CallbackReturn dynamixel_hardware::DynamixelHardware::on_activate(const rclcpp_lifecycle::State&)’:
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:183:79: warning: unused parameter ‘previous_state’ [-Wunused-parameter]
      183 | CallbackReturn DynamixelHardware::on_activate(const rclcpp_lifecycle::State & previous_state)
          |                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘CallbackReturn dynamixel_hardware::DynamixelHardware::on_deactivate(const rclcpp_lifecycle::State&)’:
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:200:81: warning: unused parameter ‘previous_state’ [-Wunused-parameter]
      200 | CallbackReturn DynamixelHardware::on_deactivate(const rclcpp_lifecycle::State & previous_state)
          |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
    /home/tharit/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual hardware_interface::return_type dynamixel_hardware::DynamixelHardware::read()’:
    /home/tharit/moonbot_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/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp: In member function ‘virtual hardware_interface::return_type dynamixel_hardware::DynamixelHardware::write()’:
    /home/tharit/moonbot_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/moonbot_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/moonbot_ws/src/dynamixel_hardware_interface/src/dynamixel_hardware_interface.cpp:310:26: error: ‘info_’ was not declared in this scope
      310 |     for (uint i = 0; i < info_.joints.size(); ++i) {
          |                          ^~~~~
    /home/tharit/moonbot_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) {
          |                          ^~~~~


    if (found_component_it != components.end())
    {
      if (action(*found_component_it, target_state))
      {
        result = return_type::OK;
      }
      else
      {
        result = return_type::ERROR;
      }
      return true;
    }
    return false;
  };


      if (hardware_info_map_[hardware.get_name()].is_async)
      {
        async_component_threads_.emplace(
          std::piecewise_construct, std::forward_as_tuple(hardware.get_name()),
          std::forward_as_tuple(&hardware, cm_update_rate_, clock_interface_));
      }
    }
    return result;
  }


  std::lock_guard<std::recursive_mutex> guard_claimed(claimed_command_interfaces_lock_);
  return resource_storage_->claimed_command_interface_map_.at(key);
}


      ExtendedPosition,
      MultiTurn,
      CurrentBasedPosition,
      PWM,
    };

    class DynamixelHardware : public hardware_interface::SystemInterface {
    public:
      RCLCPP_SHARED_PTR_DEFINITIONS(DynamixelHardware)

      CallbackReturn on_init(const hardware_interface::HardwareInfo & info) override;

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

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

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

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

      return_type read() override;

      return_type write() override;

    private:
      return_type enable_torque(const bool enabled);
      return_type set_control_mode(const ControlMode & mode, const bool force_set = false);
      return_type reset_command();

      DynamixelWorkbench dynamixel_workbench_;
      std::map<const char * const, const ControlItem *> control_items_;
      std::vector<Joint> joints_;
      std::vector<uint8_t> joint_ids_;
      bool torque_enabled_{false};
      ControlMode control_mode_{ControlMode::Position};
      bool use_dummy_{false};
    };
    }  // namespace dynamixel_hardware

    #endif  // DYNAMIXEL_HARDWARE__DYNAMIXEL_HARDWARE_HPP_


Choose a reason  Spam  Abuse  Off Topic  Outdated  Duplicate  Resolved  Hide
comment
I've a question here. Now everyone who has access to the `
StateInterfaceHandle ` will also be able to set the value right?. Shouldn't we
add this ` set_value ` method only to the ` CommandInterfaceHandle ` ?
Sorry, something went wrong.
All reactions
Copy link
Contributor  Author
###
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=48&v=4) **[
mamueluth ](/mamueluth) ** Apr 10, 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
The problem is that we have to be able to set a value for the ` StateInterface
` as well (from hardware side). If we only have the ` set_value ` in the `
CommandInterfaceHandle ` we can not set a value for the ` StateInterface `
from hardware.
This should not be a Problem however since we expose only loans to the
Controllers which do not expose the ` set_value ` function
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
Sure. Got it.


###
![@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
they mimic the hardware in the test_component_interfaces.cpp -> don't need to
adapt the test for the new functionality can just copy paste them and adapt to
new export version-> this ensures we use same test for old new version and do
not introduce any regerssion
Sorry, something went wrong.
All reactions
[ ![saikishor](https://avatars.githubusercontent.com/u/10082428?s=60&v=4)
](/saikishor)
**[ saikishor ](/saikishor) ** suggested changes  Jan 23, 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
Here are some changes I think are necessary. I will review the rest of the
code later
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/handle.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-76f1eebe99a92140f6b3e99d1a250e6a9cca669ecddbcb270c396b603bf16efe)
Show resolved  Hide resolved
[ hardware_interface/include/hardware_interface/handle.hpp ](/ros-


// CM API: Called in "callback/slow"-thread
void ResourceManager::load_urdf(
  const std::string & urdf, bool validate_interfaces, bool load_and_initialize_components)
{
  is_urdf_loaded__ = true;
  const std::string system_type = "system";
  const std::string sensor_type = "sensor";
  const std::string actuator_type = "actuator";


// CM API: Called in "callback/slow"-thread
void ResourceManager::import_controller_reference_interfaces(
  const std::string & controller_name, std::vector<CommandInterface> & interfaces)
{
  std::scoped_lock guard(resource_interfaces_lock_, claimed_command_interfaces_lock_);
  auto interface_names = resource_storage_->add_command_interfaces(interfaces);
  resource_storage_->controllers_reference_interfaces_map_[controller_name] = interface_names;
}


![Collaboration
graph](classhardware__interface_1_1StateInterface__coll__graph.png)


    if (result)
    {
      if (async_component_threads_.find(hardware.get_name()) != async_component_threads_.end())
      {
        async_component_threads_.at(hardware.get_name()).activate();
      }
      // TODO(destogl): make all command interfaces available (currently are all available)
    }


// CM API: Called in "update"-thread
HardwareReadWriteStatus ResourceManager::read(
  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();


  loop_and_get_state(resource_storage_->actuators_);
  loop_and_get_state(resource_storage_->async_actuators_);
  loop_and_get_state(resource_storage_->sensors_);
  loop_and_get_state(resource_storage_->async_sensors_);
  loop_and_get_state(resource_storage_->systems_);
  loop_and_get_state(resource_storage_->async_systems_);


  static constexpr const char * actuator_interface_name = "hardware_interface::ActuatorInterface";
  static constexpr const char * sensor_interface_name = "hardware_interface::SensorInterface";
  static constexpr const char * system_interface_name = "hardware_interface::SystemInterface";


      enable_torque(true);

      const ControlItem * goal_position =
        dynamixel_workbench_.getItemInfo(joint_ids_[0], kGoalPositionItem);
      if (goal_position == nullptr) {
        return CallbackReturn::ERROR;
      }

      const ControlItem * goal_velocity =
        dynamixel_workbench_.getItemInfo(joint_ids_[0], kGoalVelocityItem);
      if (goal_velocity == nullptr) {
        goal_velocity = dynamixel_workbench_.getItemInfo(joint_ids_[0], kMovingSpeedItem);
      }
      if (goal_velocity == nullptr) {
        return CallbackReturn::ERROR;
      }

      const ControlItem * present_position =
        dynamixel_workbench_.getItemInfo(joint_ids_[0], kPresentPositionItem);
      if (present_position == nullptr) {
        return CallbackReturn::ERROR;
      }

      const ControlItem * present_velocity =
        dynamixel_workbench_.getItemInfo(joint_ids_[0], kPresentVelocityItem);
      if (present_velocity == nullptr) {
        present_velocity = dynamixel_workbench_.getItemInfo(joint_ids_[0], kPresentSpeedItem);
      }
      if (present_velocity == nullptr) {
        return CallbackReturn::ERROR;
      }

      const ControlItem * present_current =
        dynamixel_workbench_.getItemInfo(joint_ids_[0], kPresentCurrentItem);
      if (present_current == nullptr) {
        present_current = dynamixel_workbench_.getItemInfo(joint_ids_[0], kPresentLoadItem);
      }
      if (present_current == nullptr) {
        return CallbackReturn::ERROR;
      }


  if (found_it == resource_storage_->hardware_info_map_.end())
  {
    RCUTILS_LOG_INFO_NAMED(
      "resource_manager", "Hardware Component with name '%s' does not exists",
      component_name.c_str());
    return return_type::ERROR;
  }


// END: "used only in tests and locally"


// CM API: Called in "update"-thread
std::vector<std::string> ResourceManager::get_cached_controllers_to_hardware(
  const std::string & hardware_name)
{
  return resource_storage_->hardware_used_by_controllers_[hardware_name];
}


5 participants
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=52&v=4)
](/mamueluth) [
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=52&v=4)
](/saikishor) [
![@VX792](https://avatars.githubusercontent.com/u/25421074?s=52&v=4) ](/VX792)
[ ![@destogl](https://avatars.githubusercontent.com/u/1918204?s=52&v=4)
](/destogl) [
![@christophfroehlich](https://avatars.githubusercontent.com/u/3367244?s=52&v=4)
](/christophfroehlich)
Add this suggestion to a batch that can be applied as a single commit.  This
suggestion is invalid because no changes were made to the code.  Suggestions
cannot be applied while the pull request is closed.  Suggestions cannot be
applied while viewing a subset of changes.  Only one suggestion per line can
be applied in a batch.  Add this suggestion to a batch that can be applied as
a single commit.  Applying suggestions on deleted lines is not supported.  You
must change the existing code in this line in order to create a valid
suggestion.  Outdated suggestions cannot be applied.  This suggestion has been
applied or marked resolved.  Suggestions cannot be applied from pending
reviews.  Suggestions cannot be applied on multi-line comments.  Suggestions
cannot be applied while the pull request is queued to merge.  Suggestion
cannot be applied right now. Please check back later.
##  Footer
[ ](https://github.com "GitHub") © 2024 GitHub, Inc.
###  Footer navigation
  * [ Terms ](https://docs.github.com/site-policy/github-terms/github-terms-of-service)
  * [ Privacy ](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement)
  * [ Security ](/security)
  * [ Status ](https://www.githubstatus.com/)
  * [ Docs ](https://docs.github.com/)
  * [ Contact ](https://support.github.com?tags=dotcom-footer)
  * Manage cookies
  * Do not share my personal information
You can’t perform that action at this time.


Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 13, 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
Same here. Any alternative naming would be better
Sorry, something went wrong.
All reactions
Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 14, 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/include/hardware_interface/sensor_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
fa0ef931aa48e3c33845df69293c85d7556798bd2b670723038be7e63a1ecbd0)
|  |  *
---|---|---


  auto read_components = [&](auto & components)
  {
    for (auto & component : components)
    {
      auto ret_val = component.read(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);
      }
      // If desired: automatic re-activation. We could add a flag for this...
      // else
      // {
      // using lifecycle_msgs::msg::State;
      // rclcpp_lifecycle::State state(State::PRIMARY_STATE_ACTIVE, lifecycle_state_names::ACTIVE);
      // set_component_state(component.get_name(), state);
      // }
    }
  };


    if (hardware_info.is_async)
    {
      load_and_init_actuators(async_actuators_);
    }
    else
    {
      load_and_init_actuators(actuators_);
    }
  }


[ @destogl ](https://github.com/destogl)
  1. Please check if the deprecation is now how you mentioned it.
  2. Please look at the custom export again int the test if this is how you imagined it. on_export_function is now virtual and the states and command now protected instead of private to allow overriding and adding of custom interfaces.
[ @saikishor ](https://github.com/saikishor) I didn't use unordered_map
everywhere as for the name to interface description we want to keep the order
in my understanding. O(log(n)) overhead should be ok in this case since its
most of the time used to iterate over it. If you don't agree i can change it
but then all test_component_interface tests need to be changed as well since
they rely on implicit ordering of the interfaces...

---

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/9c5396ca817c829f2750c40047b8371ee13c83c3..720e11f27c5f1023160e6c25b8952be8113ef3a4)
the  change_interface_export_variant  branch from [ ` 9c5396c ` ](/ros-
controls/ros2_control/commit/9c5396ca817c829f2750c40047b8371ee13c83c3) to [ `
720e11f ` ](/ros-
controls/ros2_control/commit/720e11f27c5f1023160e6c25b8952be8113ef3a4) [
Compare  ](/ros-
controls/ros2_control/compare/9c5396ca817c829f2750c40047b8371ee13c83c3..720e11f27c5f1023160e6c25b8952be8113ef3a4)
January 23, 2024 15:06
[
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=80&u=a8449baf27fec21608c3919a53021b418098ddfe&v=4)
](/saikishor)
Copy link
Member
###
**[ saikishor ](/saikishor) ** commented  Jan 23, 2024
> [ @saikishor ](https://github.com/saikishor) I didn't use unordered_map
> everywhere as for the name to interface description we want to keep the
> order in my understanding. O(log(n)) overhead should be ok in this case
> since its most of the time used to iterate over it. If you don't agree i can
> change it but then all test_component_interface tests need to be changed as
> well since they rely on implicit ordering of the interfaces...
Usually, the unoredered_map's are faster to access O(1), which is better to
use in such a layer. For that reason, I recommended using ` unordered_map `


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/include/hardware_interface/handle.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-76f1eebe99a92140f6b3e99d1a250e6a9cca669ecddbcb270c396b603bf16efe)
Comment on lines  +105  to  +111
|  |  void set_value(double value)
---|---|---
|  |  {
|  |  // BEGIN (Handle export change): for backward compatibility
|  |  // TODO(Manuel) set value_ directly if old functionality is removed
|  |  THROW_ON_NULLPTR(this->value_ptr_);
|  |  *this->value_ptr_ = value;
|  |  // END

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


  write_components(resource_storage_->actuators_);
  write_components(resource_storage_->systems_);


    if (result)
    {
      remove_all_hardware_interfaces_from_available_list(hardware.get_name());
    }
    return result;
  }


[ pbnpama  ](https://get-help.theconstruct.ai/u/pbnpama) August 8, 2023,
7:53pm  1


      if (found_it != available_command_interfaces_.end())
      {
        available_command_interfaces_.erase(found_it);
        RCUTILS_LOG_DEBUG_NAMED(
          "resource_manager", "(hardware '%s'): '%s' command interface removed from available list",
          hardware_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 not in available list. "
          "This should not happen (hint: multiple cleanup calls).",
          hardware_name.c_str(), interface.c_str());
      }
    }
    // remove all state interfaces from available list
    for (const auto & interface : hardware_info_map_[hardware_name].state_interfaces)
    {
      auto found_it = std::find(
        available_state_interfaces_.begin(), available_state_interfaces_.end(), interface);


[ hardware_interface/test/mock_components/test_generic_system.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-
ae74c2bfe940cd637f580a53348b04d33ef4514d4b225b73b82927702f0dca39) Show
resolved  Hide resolved
[ hardware_interface/test/test_component_interfaces.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-50ee5330ba5b8d38fe2d2ea4de9f105856714e090a2b633d5144e9ef8135af6d)
Show resolved  Hide resolved
[
ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp
](/ros-
controls/ros2_control/pull/1240/files#diff-4408b84b0859e51c93823cd9b3660cce480700a81220c33880471c86779544d1)
Outdated  Show resolved  Hide resolved
[
ros2_control_test_assets/include/ros2_control_test_assets/components_urdfs.hpp
](/ros-
controls/ros2_control/pull/1240/files#diff-4408b84b0859e51c93823cd9b3660cce480700a81220c33880471c86779544d1)
|  |  </ros2_control>
---|---|---
|  |  )";
|  |

|  |  const auto valid_urdf_ros2_control_dummy_actuator_only =

Copy link
Member
###
![@destogl](https://avatars.githubusercontent.com/u/1918204?s=48&v=4) **[
destogl ](/destogl) ** Jan 22, 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
Why do we need those additional URDFs?
Sorry, something went wrong.
All reactions
Copy link
Contributor  Author


  template <class HardwareT, class HardwareInterfaceT>
  void load_hardware(
    const HardwareInfo & hardware_info, pluginlib::ClassLoader<HardwareInterfaceT> & loader,
    std::vector<HardwareT> & container)
  {
    RCUTILS_LOG_INFO_NAMED(
      "resource_manager", "Loading hardware '%s' ", hardware_info.name.c_str());
    // hardware_plugin_name has to match class name in plugin xml description
    auto interface = std::unique_ptr<HardwareInterfaceT>(
      loader.createUnmanagedInstance(hardware_info.hardware_plugin_name));
    HardwareT hardware(std::move(interface));
    container.emplace_back(std::move(hardware));
    // initialize static data about hardware component to reduce later calls
    HardwareComponentInfo component_info;
    component_info.name = hardware_info.name;
    component_info.type = hardware_info.type;
    component_info.plugin_name = hardware_info.hardware_plugin_name;
    component_info.is_async = hardware_info.is_async;


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


// CM API: Called in "update"-thread (indirectly through `claim_state_interface`)
bool ResourceManager::state_interface_is_available(const std::string & name) const
{
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return std::find(
           resource_storage_->available_state_interfaces_.begin(),
           resource_storage_->available_state_interfaces_.end(),
           name) != resource_storage_->available_state_interfaces_.end();
}


// CM API: Called in "callback/slow"-thread
void ResourceManager::cache_controller_to_hardware(
  const std::string & controller_name, const std::vector<std::string> & interfaces)
{
  for (const auto & interface : interfaces)
  {
    bool found = false;
    for (const auto & [hw_name, hw_info] : resource_storage_->hardware_info_map_)
    {
      auto cmd_itf_it =
        std::find(hw_info.command_interfaces.begin(), hw_info.command_interfaces.end(), interface);
      if (cmd_itf_it != hw_info.command_interfaces.end())
      {
        found = true;
      }
      auto state_itf_it =
        std::find(hw_info.state_interfaces.begin(), hw_info.state_interfaces.end(), interface);
      if (state_itf_it != hw_info.state_interfaces.end())
      {
        found = true;
      }


  resource_storage_->claimed_command_interface_map_[key] = true;
  std::lock_guard<std::recursive_mutex> guard(resource_interfaces_lock_);
  return LoanedCommandInterface(
    resource_storage_->command_interface_map_.at(key),
    std::bind(&ResourceManager::release_command_interface, this, key));
}


bool result = false;


    if (hardware_info.is_async)
    {
      init_actuators(async_actuators_);
    }
    else
    {
      init_actuators(actuators_);
    }
  }


Skip to content
Toggle navigation
[ ](https://github.com/)
[ Sign in ](/login?return_to=https%3A%2F%2Fgithub.com%2Fros-
controls%2Fros2_control%2Fpull%2F1240)
  * Product
    * [ Actions  Automate any workflow  ](/features/actions)
    * [ Packages  Host and manage packages  ](/features/packages)
    * [ Security  Find and fix vulnerabilities  ](/features/security)
    * [ Codespaces  Instant dev environments  ](/features/codespaces)
    * [ Copilot  Write better code with AI  ](/features/copilot)
    * [ Code review  Manage code changes  ](/features/code-review)
    * [ Issues  Plan and track work  ](/features/issues)
    * [ Discussions  Collaborate outside of code  ](/features/discussions)
Explore
    * [ All features ](/features)
    * [ Documentation  ](https://docs.github.com)
    * [ GitHub Skills  ](https://skills.github.com/)
    * [ Blog  ](https://github.blog)
  * Solutions
For
    * [ Enterprise ](/enterprise)
    * [ Teams ](/team)
    * [ Startups ](/enterprise/startups)
    * [ Education  ](https://education.github.com)
By Solution
    * [ CI/CD & Automation ](/solutions/ci-cd/)
    * [ DevOps ](/solutions/devops/)
    * [ DevSecOps  ](https://resources.github.com/devops/fundamentals/devsecops/)
Resources
    * [ Learning Pathways  ](https://resources.github.com/learn/pathways/)
    * [ White papers, Ebooks, Webinars  ](https://resources.github.com/)
    * [ Customer Stories ](/customer-stories)
    * [ Partners  ](https://partner.github.com/)
  * Open Source
    * [ GitHub Sponsors  Fund open source developers  ](/sponsors)
    * [ The ReadME Project  GitHub community articles  ](/readme)
Repositories
    * [ Topics ](/topics)
    * [ Trending ](/trending)


    if (result)
    {
      remove_all_hardware_interfaces_from_available_list(hardware.get_name());
      async_component_threads_.erase(hardware.get_name());
      // TODO(destogl): change this - deimport all things if there is there are interfaces there
      // deimport_non_movement_command_interfaces(hardware);
      // deimport_state_interfaces(hardware);
      // use remove_command_interfaces(hardware);
    }
    return result;
  }


}  // namespace hardware_interface


    throw std::runtime_error(err_msg);
  }
}


Inheritance diagram for hardware_interface::StateInterface:


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
Can we find any alternative name?
Sorry, something went wrong.
All reactions
Copy link
Member
###
![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=48&v=4) **[
saikishor ](/saikishor) ** Mar 14, 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_state_interfaces_2  ()
---|---
|  virtual  std::vector<hardware_interface::InterfaceDescription>
export_state_interfaces_description  ()

How about this?
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
|  |  *
---|---|---
|  |  * \return vector of descriptions to the unlisted CommandInterfaces
|  |  */
|  |  virtual std::vector<hardware_interface::InterfaceDescription>
export_command_interfaces_2()

Copy link


#include "hardware_interface/actuator.hpp"
#include "hardware_interface/actuator_interface.hpp"
#include "hardware_interface/async_components.hpp"
#include "hardware_interface/component_parser.hpp"
#include "hardware_interface/hardware_component_info.hpp"
#include "hardware_interface/sensor.hpp"
#include "hardware_interface/sensor_interface.hpp"
#include "hardware_interface/system.hpp"
#include "hardware_interface/system_interface.hpp"
#include "hardware_interface/types/hardware_interface_type_values.hpp"
#include "lifecycle_msgs/msg/state.hpp"
#include "pluginlib/class_loader.hpp"
#include "rcutils/logging_macros.h"


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


Public Member Functions  | [ List of all members
](classhardware__interface_1_1StateInterface-members.html)


rather than ` map ` . They tend to use a bit more or memory, but performance-
wise they are much better.
if you have a different opinion on this, we can discuss

---

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 24, 2024
> > [ @saikishor ](https://github.com/saikishor) I didn't use unordered_map
> everywhere as for the name to interface description we want to keep the
> order in my understanding. O(log(n)) overhead should be ok in this case
> since its most of the time used to iterate over it. If you don't agree i can
> change it but then all test_component_interface tests need to be changed as
> well since they rely on implicit ordering of the interfaces...
>
> Usually, the unoredered_map's are faster to access O(1), which is better to
> use in such a layer. For that reason, I recommended using ` unordered_map `
> rather than ` map ` . They tend to use a bit more or memory, but
> performance-wise they are much better.
>
> if you have a different opinion on this, we can discuss
Yes you are completely right about the performance thats why i now use
unordered_map for the states and commands which is accessed a lot e.g. for
SensorInterface:

    std::map<std::string, InterfaceDescription> sensor_state_interfaces_;
    std::unordered_map<std::string, StateInterfaceSharedPtr> sensor_states_;

But for the ` sensor_state_interfaces_ ` i would still use map, because this
is only used to get the InterfaceDescription for a given name and for
initialization of the actual StateInterfaces in the Interface e.g. the `
sensor_states_ ` later. The user uses this map most of the time by iterating


// CM API: Called in "update"-thread
void ResourceManager::release_command_interface(const std::string & key)
{
  std::lock_guard<std::recursive_mutex> guard_claimed(claimed_command_interfaces_lock_);
  resource_storage_->claimed_command_interface_map_[key] = false;
}


        }

        for (uint i = 0; i < joint_ids_.size(); ++i) {
          if (!dynamixel_workbench_.setPositionControlMode(joint_ids_[i], &log)) {
            RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
            return return_type::ERROR;
          }
        }
        RCLCPP_INFO(rclcpp::get_logger(kDynamixelHardware), "Position control");
        control_mode_ = ControlMode::Position;

        if (torque_enabled) {
          enable_torque(true);
        }
      } else if (control_mode_ != ControlMode::Velocity && control_mode_ != ControlMode::Position) {
        RCLCPP_FATAL(
          rclcpp::get_logger(kDynamixelHardware), "Only position/velocity control are implemented");
        return return_type::ERROR;
      }

      return return_type::OK;
    }

    return_type DynamixelHardware::reset_command()
    {
      for (uint i = 0; i < joints_.size(); i++) {
        joints_[i].command.position = joints_[i].state.position;
        joints_[i].command.velocity = 0.0;
        joints_[i].command.effort = 0.0;
      }

      return return_type::OK;
    }

    }  // namespace dynamixel_hardware

    #include "pluginlib/class_list_macros.hpp"

    PLUGINLIB_EXPORT_CLASS(dynamixel_hardware::DynamixelHardware, hardware_interface::SystemInterface)


ResourceManager::~ResourceManager() = default;


  void check_for_duplicates(const HardwareInfo & hardware_info)
  {
    // Check for identical names
    if (hardware_info_map_.find(hardware_info.name) != hardware_info_map_.end())
    {
      throw std::runtime_error(
        "Hardware name " + hardware_info.name +
        " is duplicated. Please provide a unique 'name' in the URDF.");
    }
  }


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


  if (!missing_state_keys.empty() || !missing_command_keys.empty())
  {
    std::string err_msg = "Wrong state or command interface configuration.\n";
    err_msg += "missing state interfaces:\n";
    for (const auto & missing_key : missing_state_keys)
    {
      err_msg += "' " + missing_key + " '" + "\t";
    }
    err_msg += "\nmissing command interfaces:\n";
    for (const auto & missing_key : missing_command_keys)
    {
      err_msg += "' " + missing_key + " '" + "\t";
    }


ResourceManager::ResourceManager(
  unsigned int update_rate, rclcpp::node_interfaces::NodeClockInterface::SharedPtr clock_interface)
: resource_storage_(std::make_unique<ResourceStorage>(update_rate, clock_interface))
{
}


  if (activate_all)
  {
    for (auto const & hw_info : resource_storage_->hardware_info_map_)
    {
      using lifecycle_msgs::msg::State;
      rclcpp_lifecycle::State state(State::PRIMARY_STATE_ACTIVE, lifecycle_state_names::ACTIVE);
      set_component_state(hw_info.first, state);
    }
  }
}


    hardware_info_map_.insert(std::make_pair(component_info.name, component_info));
    hardware_used_by_controllers_.insert(
      std::make_pair(component_info.name, std::vector<std::string>()));
  }


January 22, 2024 11:21
[ ![destogl](https://avatars.githubusercontent.com/u/1918204?s=60&v=4)
](/destogl)
**[ destogl ](/destogl) ** requested changes  Jan 22, 2024
[ View reviewed changes  ](/ros-controls/ros2_control/pull/1240/files)
Copy link
Member
###
![@destogl](https://avatars.githubusercontent.com/u/1918204?s=48&v=4) **[
destogl ](/destogl) ** left a comment  •
edited
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 general, this looks good. I just see two bigger things to fix:
  * abstract deprecated approach from new approach on the component level and not in the ResourceManager, then we don't need additional ` on_export_* ` methods inside components, but just interfaces.
  * I didn't see a test with the custom implementation fo a component that exports custom, not in URDF defined, interface manually. This functionality we want to keep and, therefore, should be tested. There is already a test with the current approach for exactly that case.
Sorry, something went wrong.
All reactions
[ hardware_interface/include/hardware_interface/actuator_interface.hpp ](/ros-
controls/ros2_control/pull/1240/files#diff-e16d64b1db47f4c0e6a6c6698b69e63346f56e10644ed52229cf3417ea9009a5)
Comment on lines  +104  to  +105
|  |  import_state_interface_descriptions(info_);
---|---|---
|  |  import_command_interface_descriptions(info_);

Copy link
Member
###
![@destogl](https://avatars.githubusercontent.com/u/1918204?s=48&v=4) **[
destogl ](/destogl) ** Jan 22, 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) .


  /// Adds exported command interfaces into internal storage.
  /**
   * Add command interfaces to the internal storage. Command interfaces exported from hardware or
   * chainable controllers are moved to the map with name-interface pairs, the interface names are
   * added to the claimed map and available list's size is increased to reserve storage when
   * interface change theirs status in real-time control loop.
   *
   * \param[interfaces] list of command interface to add into storage.
   * \returns list of interface names that are added into internal storage. The output is used to
   * avoid additional iterations to cache interface names, e.g., for initializing info structures.
   */
  std::vector<std::string> add_command_interfaces(std::vector<CommandInterface> & interfaces)
  {
    std::vector<std::string> interface_names;
    interface_names.reserve(interfaces.size());
    for (auto & interface : interfaces)
    {
      auto key = interface.get_name();
      command_interface_map_.emplace(std::make_pair(key, std::move(interface)));
      claimed_command_interface_map_.emplace(std::make_pair(key, false));
      interface_names.push_back(key);
    }
    available_command_interfaces_.reserve(
      available_command_interfaces_.capacity() + interface_names.size());


  * Add ` set_state ` / ` get_state ` and ` set_commad ` / ` get_command ` functions to component interface -> since memory is moved to Handle, HW needs to be able to still set states/receive commands.
  * ` Command-/StateInterface ` are stored in (Actuator-, Sensor- or SystemInterface) in map. -> This was done because the memory is moved to the Handles. HW still needs to be able to set states/receive commands. Otherwise we would need to import "hw-loans" or ptr to the ` Command-/StateInterface ` . Map was used to make it explicit rather then implicit. e.g. HW can now set state with ` set_state("joint1/position", 1.0) `
  * Create Handles based on InterfaceDescription -> encapsulate all information about Interface.
Sorry, something went wrong.
All reactions
[ ![@github-actions](https://avatars.githubusercontent.com/in/15368?s=40&v=4)
](/apps/github-actions) [ github-actions ](/apps/github-actions) bot
requested review from [ aprotyas  ](/aprotyas) , [ bmagyar  ](/bmagyar) , [
destogl  ](/destogl) , [ livanov93  ](/livanov93) , [ moriarty  ](/moriarty) ,
[ peterdavidfagan  ](/peterdavidfagan) and [ VanshGehlot  ](/VanshGehlot)
December 20, 2023 14:37
[
![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&u=f81462164d8259aace7a7f80ef76fd0c3dfeff1d&v=4)
](/mamueluth) [ mamueluth ](/mamueluth) mentioned this pull request  Dec 20,
2023
[ Change interface export variant  ros-controls/ros2_control_demos#396
](/ros-controls/ros2_control_demos/pull/396)
Open
[ ![@codecov](https://avatars.githubusercontent.com/in/254?s=80&v=4)
](/apps/codecov) [
![Codecov](https://avatars.githubusercontent.com/in/254?s=40&u=c392dd7c2afc51fe2347d4296afa8494ac05772e&v=4)
](https://github.com/apps/codecov)
Copy link
###
**[ codecov ](/apps/codecov) bot  ** commented  Dec 20, 2023  •
edited
##  [ Codecov ](https://app.codecov.io/gh/ros-
controls/ros2_control/pull/1240?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
controls) Report
Attention: Patch coverage is ` 55.21472% ` with ` 146 lines ` in your changes
are missing coverage. Please review.
> Project coverage is 48.20%. Comparing base [ ( ` 35bb5f7 ` )
> ](https://app.codecov.io/gh/ros-
> controls/ros2_control/commit/35bb5f7c2eff9ec82175db1e8e5fcb8a60b094e2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
> controls) to head [ ( ` 7c07d0c ` ) ](https://app.codecov.io/gh/ros-
> controls/ros2_control/pull/1240?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ros-
> controls) .
>  Report is 19 commits behind head on master.
> ❗ Current head [ ` 7c07d0c ` ](https://github.com/ros-
> controls/ros2_control/commit/7c07d0c6bf0b677fe0feedd48d5343c5b8e9079a)


  if (result)
  {
    RCUTILS_LOG_INFO_NAMED(
      "resource_manager", "Successful '%s' of hardware '%s'", transition_name.c_str(),
      hardware_name.c_str());
  }
  else
  {
    RCUTILS_LOG_INFO_NAMED(
      "resource_manager", "Failed to '%s' hardware '%s'", transition_name.c_str(),
      hardware_name.c_str());
  }
  return result;
};


[ [ legend ](graph_legend.html) ]


Sorry, something went wrong.
[ ![@mamueluth](https://avatars.githubusercontent.com/u/19118679?s=40&v=4)
](/mamueluth)
` [ update writing a hardware component ](/ros-
controls/ros2_control/pull/1240/commits/16128028a351ba0d4b667381419c2fe6e0f55b7e
"update writing a hardware component") `
` [ 1612802 ](/ros-
controls/ros2_control/pull/1240/commits/16128028a351ba0d4b667381419c2fe6e0f55b7e)
`
[
![@christophfroehlich](https://avatars.githubusercontent.com/u/3367244?s=80&u=98db36351213b952b1c6ce663c1fde4108272539&v=4)
](/christophfroehlich)
Copy link
Contributor
###
**[ christophfroehlich ](/christophfroehlich) ** commented  Apr 12, 2024  •
edited
> [ @christophfroehlich ](https://github.com/christophfroehlich) can you
> please check the migration guide and the updated docs
Thanks for the docs, I have fixed the rst syntax and some minor typos: [
StoglRobotics-forks#18 ](https://github.com/StoglRobotics-
forks/ros2_control/pull/18)

---

All reactions
Sorry, something went wrong.
[
![@christophfroehlich](https://avatars.githubusercontent.com/u/3367244?s=40&u=98db36351213b952b1c6ce663c1fde4108272539&v=4)
](/christophfroehlich) [ christophfroehlich ](/christophfroehlich) mentioned
this pull request  Apr 13, 2024
[ Fix RST syntax and some typos  StoglRobotics-forks/ros2_control#18
](/StoglRobotics-forks/ros2_control/pull/18)
Open
[ Sign up for free ](/join?source=comment-repo) **to join this conversation on
GitHub** . Already have an account? [ Sign in to comment
](/login?return_to=https%3A%2F%2Fgithub.com%2Fros-
controls%2Fros2_control%2Fpull%2F1240)
Reviewers
[ ![@saikishor](https://avatars.githubusercontent.com/u/10082428?s=40&v=4)


|  |  // END: for backward compatibility

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
I believe this is not needed, as within the System and Actuator interface the
method already returns the CommandInterface shared pointer. Am I right?
Sorry, something went wrong.
All reactions
[ hardware_interface/src/resource_manager.cpp ](/ros-
controls/ros2_control/pull/1240/files#diff-31aaa609a55e1333d6e694aea6963bdaceed8615945c65fb57daa91a7c9fd58d)
|  |  std::vector<std::string> interface_names;
---|---|---
|  |  std::vector<std::shared_ptr<StateInterface>> interfaces =
hardware.export_state_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
|  std::vector<std::shared_ptr<StateInterface>> interfaces = hardware.
export_state_interfaces  ();


  template <class HardwareT>
  void import_state_interfaces(HardwareT & hardware)
  {
    auto interfaces = hardware.export_state_interfaces();
    std::vector<std::string> interface_names;
    interface_names.reserve(interfaces.size());
    for (auto & interface : interfaces)
    {
      auto key = interface.get_name();
      state_interface_map_.emplace(std::make_pair(key, std::move(interface)));
      interface_names.push_back(key);
    }
    hardware_info_map_[hardware.get_name()].state_interfaces = interface_names;
    available_state_interfaces_.reserve(
      available_state_interfaces_.capacity() + interface_names.size());
  }


public:
  // TODO(VX792): Change this when HW ifs get their own update rate,
  // because the ResourceStorage really shouldn't know about the cm's parameters
  ResourceStorage(
    unsigned int update_rate = 100,
    rclcpp::node_interfaces::NodeClockInterface::SharedPtr clock_interface = nullptr)
  : actuator_loader_(pkg_name, actuator_interface_name),
    sensor_loader_(pkg_name, sensor_interface_name),
    system_loader_(pkg_name, system_interface_name),
    cm_update_rate_(update_rate),
    clock_interface_(clock_interface)
  {
  }


      control_items_[kGoalPositionItem] = goal_position;
      control_items_[kGoalVelocityItem] = goal_velocity;
      control_items_[kPresentPositionItem] = present_position;
      control_items_[kPresentVelocityItem] = present_velocity;
      control_items_[kPresentCurrentItem] = present_current;

      if (!dynamixel_workbench_.addSyncWriteHandler(
            control_items_[kGoalPositionItem]->address, control_items_[kGoalPositionItem]->data_length,
            &log)) {
        RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
        return CallbackReturn::ERROR;
      }

      if (!dynamixel_workbench_.addSyncWriteHandler(
            control_items_[kGoalVelocityItem]->address, control_items_[kGoalVelocityItem]->data_length,
            &log)) {
        RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
        return CallbackReturn::ERROR;
      }

      uint16_t start_address = std::min(
        control_items_[kPresentPositionItem]->address, control_items_[kPresentCurrentItem]->address);
      uint16_t read_length = control_items_[kPresentPositionItem]->data_length +
                             control_items_[kPresentVelocityItem]->data_length +
                             control_items_[kPresentCurrentItem]->data_length + 2;
      if (!dynamixel_workbench_.addSyncReadHandler(start_address, read_length, &log)) {
        RCLCPP_FATAL(rclcpp::get_logger(kDynamixelHardware), "%s", log);
        return CallbackReturn::ERROR;
      }

      return CallbackReturn::SUCCESS;
    }

    std::vector<hardware_interface::StateInterface> DynamixelHardware::export_state_interfaces()
    {
      RCLCPP_DEBUG(rclcpp::get_logger(kDynamixelHardware), "export_state_interfaces");
      std::vector<hardware_interface::StateInterface> state_interfaces;
      for (uint i = 0; i < info_.joints.size(); i++) {
        state_interfaces.emplace_back(hardware_interface::StateInterface(


  void initialize_system(
    std::unique_ptr<SystemInterface> system, const HardwareInfo & hardware_info)
  {
    auto init_systems = [&](auto & container)
    {
      container.emplace_back(System(std::move(system)));
      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());
      }
    };


Dear Community,


[ Your browser does not support videos  ![RoboDK Software for simulation and
programming]() ](https://robodk.com/)


  Crystallographic texture  [  [ edit
](/w/index.php?title=Euler_angles&action=edit&section=24 "Edit section:
Crystallographic texture") ]

[ ![](//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/MAUD-MTEX-TiAl-
hasylab-2003-Liss.png/220px-MAUD-MTEX-TiAl-hasylab-2003-Liss.png)
](/wiki/File:MAUD-MTEX-TiAl-hasylab-2003-Liss.png) Pole figures displaying
crystallographic texture of gamma-TiAl in an alpha2-gamma alloy, as measured
by high energy X-rays.  [8]

In materials science, crystallographic [ texture
](/wiki/Texture_\(crystalline\) "Texture \(crystalline\)") (or preferred
orientation) can be described using Euler angles. In texture analysis, the
Euler angles provide a mathematical depiction of the orientation of individual
crystallites within a polycrystalline material, allowing for the quantitative
description of the macroscopic material.  [9]  The most common definition of
the angles is due to Bunge and corresponds to the _ZXZ_ convention. It is
important to note, however, that the application generally involves axis
transformations of tensor quantities, i.e. passive rotations. Thus the matrix
that corresponds to the Bunge Euler angles is the transpose of that shown in
the table above.  [10]


The overall transformation of end-effector w.r.t base frame is computed as:


For link 1, the x0 and x1 are in the same direction. So frame 0 doesn’t need
to rotate around the axis z0. Hence, the value is theta1. If in case, frame 0
has to rotate 90 deg clockwise around the axis z0 to match axis x0 and x1,
then the value would be -90+theta1. Similarly, By looking at the assigned
frame on the robotic arm and the parameters definition, we can fill the DH
parameter table easily.


Similarly, in the local coordinate Σb, we can represent the robot arm pointing from joint
b to the end point e as a vector
p
[Σb]
b→e = (0, 0, l3)
>, (3)
where l3 denotes the arm link length.
From the numbers of the vector representations of p
[Σw]
a , p
[Σw]
b
and p
[Σw]
e in the world
coordinate system, as well as p
[Σa]
b
and p
[Σb]
e in the local coordinate systems, it seems that
p
[Σw]
b = p
[Σw]
a + p
[Σa]
a→b
, (4)
p
[Σw]
e = p
[Σw]
b + p
[Σb]
b→e = p
[Σw]
a + p
[Σa]
a→b + p


     1
Trophies


Sign up


     6
[ Posts ](https://www.robot-forum.com/robotforum/user-post-list/2400-nation/
"Posts by Nation")


we can directly calculate its corresponding rotation matrix R with Equation 68. Meanwhile,
when given a rotation matrix R, can we also directly calculate its corresponding angular
velocity vector or not? This is what we plan to introduce in this part.
According to Equation 62, the rotation matrix R can be represented as expωb
(the time
variable t is discarded). By defining the logarithm operator on the rotation matrix, we can
calculate the angular velocity vector ω to be
ω = (ωb)
∨ = (ln R)
∨
. (69)
Depending on the shape and contents of the rotation matrix R =


r11 r12 r13
r21 r22 r23
r31 r32 r33

, the
actual calculation can be represented as
ω = (ln R)
∨ =



(0, 0, 0)> if R = I
π
2
(r11 + 1, r22 + 1, r33 + 1,) if R is diagonal
θ
a
|a|
otherwise.
(70)
In the above representation, the scalar θ and vector a are defined based on the elements in
matrix R as follows:
a = (r32 − r23, r13 − r31, r21 − r12)
>, θ = atan2(|a| , r11 + r22 + r33 − 1), (71)
23
JIAWEI ZHANG, IFM LAB DIRECTOR


Check out my example Fanuc Ethernet/IP Explicit Messaging program [ here!
](https://www.robot-forum.com/robotforum/thread/46201-ethernet-ip-explicit-
messaging-example-program/)



cos θ 0 sin θ
0 1 0
− sin θ 0 cos θ

 , (22)
Rz(ψ) =


cos ψ − sin θ 0
sin ψ cos θ 0
0 0 1

 . (23)
(24)
Let’s assume, given a vector p pointing from the current joint to the end point, if we
rotate the current joint with a φ-degree angle around the x axis, a θ-degree angle around
the y axis and a ψ-degree angle around the z axis, we can represent the vector after those
3-way rotations as
p
0 = Rz(ψ)Ry(θ)Rx(φ)p = Rrpy(φ, θ, ψ)p, (25)
where the roll-pitch-yaw rotation matrix Rrpy(φ, θ, ψ) can be represented as follows:
Rrpy(φ, θ, ψ) = (26)


cos ψ cos θ − sin ψ cos φ + cos ψ sin θ sin φ sin ψ sin φ + cos ψ sin θ cos φ
sin ψ cos θ cos ψ cos φ + sin ψ sin θ sin φ − cos ψ sin φ + sin ψ sin θ cos φ
− sin θ cos θ sin φ cos θ cos φ

 . (27)
The readers may have notice the rotation matrix Rx(φ) defined in Equation 21 is slightly
different from the rotation matrix defined in Equation 9. The main differences lie at the
rotation direction, which actually follows the right-hand rule. With the right hand index
finger, middle finger, ring finger and little finger following the rotation direction, if the
thumb orientation is the same as the axis positive direction, then the rotation angle will be
positive; otherwise, the rotation angle will be negative.
According to the right-hand rule, for the rotations in the counter-clockwise direction,
their rotation matrices can be simply represented as those in Equation 21. Meanwhile, when
it comes to the clockwise rotation (just like Figure 5), we can add a negative mark to the
angles before applying them in Equation 21 for defining the rotation matrices, which will



ωypz − ωzpy
ωzpx − ωxpz
ωxpy − ωypx

 =


0 −ωz ωy
ωz 0 −ωx
−ωy ωx 0




px
py
pz

 . (44)
In the following subsection, we will illustrate the physical meanings of the matrix multiplied
with the vector p, which can be build from the angular velocity vector directly.
4.3.3 Rotation Transformation on Velocity Vectors
If the origin in Figure 8 denotes a robot joint, which may rotate with time, the object’s
angular velocity vector together with the central axis will also change with the rotation.
Here, we can represent the rotation as matrix R. By multiplying both sides of Equation 40
with matrix R, we can get
Rω = Rq˙ez. (45)
If we introduce two new vectors ω
0 = Rω and e
0
z = Rez, then the above equation can
be rewritten as follows:
ω
0 = ˙qe
0
z
, (46)
where ω
0 denotes the new angular velocity vector and e


b) Rotz(w)*Rot(r)*Rot(t) - zy'x'' / xyx


](/jobs-at-medium/work-at-medium-959d1a85284e?source=post_page-----
4f40883fbaef--------------------------------)


According to the manual W,P,R are the rotation angles around the X,Y,Z of the
fixed frame (extrinsic)


    * [ ](https://www.robot-forum.com/trophy/70-5th-anniversary/)
    * [ ](https://www.robot-forum.com/trophy/72-3rd-anniversary/)
    * [ ](https://www.robot-forum.com/trophy/73-helping-hand/)


  Last remarks  [  [ edit
](/w/index.php?title=Euler_angles&action=edit&section=16 "Edit section: Last
remarks") ]

Note that the inverse sine and cosine functions yield two possible values for
the argument. In this geometrical description, only one of the solutions is
valid. When Euler angles are defined as a sequence of rotations, all the
solutions can be valid, but there will be only one inside the angle ranges.
This is because the sequence of rotations to reach the target frame is not
unique if the ranges are not previously defined.  [2]

For computational purposes, it may be useful to represent the angles using  [
atan2 ](/wiki/Atan2 "Atan2") ( _y_ , _x_ )  . For example, in the case of
proper Euler angles:

     α  =  atan2    (  Z  1  ,  −  Z  2  )  ,  {\displaystyle \alpha =\operatorname {atan2} (Z_{1},-Z_{2}),}  ![{\\displaystyle \\alpha =\\operatorname {atan2} \(Z_{1},-Z_{2}\),}](https://wikimedia.org/api/rest_v1/media/math/render/svg/34e5aed0f1546710c4c2445217c3f4ad108533fe)
     γ  =  atan2    (  X  3  ,  Y  3  )  .  {\displaystyle \gamma =\operatorname {atan2} (X_{3},Y_{3}).}  ![{\\displaystyle \\gamma =\\operatorname {atan2} \(X_{3},Y_{3}\).}](https://wikimedia.org/api/rest_v1/media/math/render/svg/0fa87dfedec1c2c4c7f8b01d7c00f259df55b630)


My questions are:


* [ ![](https://www.robot-forum.com/images/avatars/9f/2747-9f0f94e2d3d1e4d993452c92b437517371ca3150.jpg) ](https://www.robot-forum.com/user/2400-nation/)


](https://policy.medium.com/medium-privacy-
policy-f03bf92035c9?source=post_page-----
4f40883fbaef--------------------------------)


> [
> ![](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjEyOCIgaGVpZ2h0PSIxMjgiPjxwYXRoIGZpbGw9IiM2NzE0YzMiIGQ9Ik0wIDBoMTZ2MTZIMHoiLz48dGV4dCB4PSI4IiB5PSI4IiBmaWxsPSIjZmZmIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iLjNlbSIgZm9udC1mYW1pbHk9IkFyaWFsIiBmb250LXNpemU9IjciPlNUPC90ZXh0Pjwvc3ZnPg==)
> ](https://www.robot-forum.com/user/73044-stevel/)
>
> [ Quote from SteveL ](https://www.robot-
> forum.com/forum/index.php?thread/&postID=110582#post110582)
>
>
>  I was looking for this information quite a bit. May I ask where you found
> it / read about it?
>


The transformation matrices calculated through DH parameters, for each links
are given below:


Trophies


>Rrpy(φ, θ, ψ) (34)
= (Rz(ψ)Ry(θ)Rx(φ))>
(Rz(ψ)Ry(θ)Rx(φ)) (35)
= Rx(φ)
>Ry(θ)
>Rz(ψ)
>Rz(ψ)Ry(θ)Rx(φ) (36)
= Rx(φ)
>

Ry(θ)
>

Rz(ψ)
>Rz(ψ)

Ry(θ)

Rx(φ) (37)
= I. (38)
Meanwhile, readers can also just calculate the product of Rrpy(φ, θ, ψ)
>Rrpy(φ, θ, ψ)
based on the concrete representations shown in Equation 26 on a piece of paper, whose
result should also be a identity matrix with value 1 on the diagonal.
Here, if we assume the rotation matrix R is invertible, by multiplying both sides of
equation RR> = I with R−1
, we can obtain
R> = R−1
. (39)
4.3 Angular Velocity
Before we talk more about the rotation matrix, we would like to have a cut-in subsection
here to talk about the robot rotation angular velocity first. More information about velocity
and transformation will be provided in the following Section 5.
17
JIAWEI ZHANG, IFM LAB DIRECTOR
o
p
!
v = ! ⇥ p
object


[ HawkME  ](https://www.robot-forum.com/user/57811-hawkme/)


So putting in the values of each joint angles as well as link lengths, we will
get the position of the gripper/end-effector of our robotic arm.
**Cheers! We have made it.**


  Contents

move to sidebar  hide

  * (Top)
  * 1  Chained rotations equivalence
  * 2  Classic Euler angles  Toggle Classic Euler angles subsection
    * 2.1  Geometrical definition
    * 2.2  Conventions by intrinsic rotations
    * 2.3  Conventions by extrinsic rotations
    * 2.4  Signs, ranges and conventions
    * 2.5  Precession, nutation and intrinsic rotation
  * 3  Tait–Bryan angles  Toggle Tait–Bryan angles subsection
    * 3.1  Definitions
    * 3.2  Conventions
    * 3.3  Signs and ranges
    * 3.4  Alternative names
  * 4  Angles of a given frame  Toggle Angles of a given frame subsection
    * 4.1  Proper Euler angles
    * 4.2  Tait–Bryan angles
    * 4.3  Last remarks
  * 5  Conversion to other orientation representations  Toggle Conversion to other orientation representations subsection
    * 5.1  Rotation matrix
  * 6  Properties  Toggle Properties subsection
    * 6.1  Geometric algebra
    * 6.2  Higher dimensions
  * 7  Applications  Toggle Applications subsection
    * 7.1  Vehicles and moving frames
    * 7.2  Crystallographic texture
    * 7.3  Others
  * 8  See also
  * 9  References
  * 10  Bibliography
  * 11  External links

Toggle the table of contents


[Σw]
a + ω
[Σw]
a ×

p
[Σw]
b − p
[Σw]
a

. (77)
In the above equation, we use many results obtained from the previous sections: (1) according to Equation 59, R˙ = ωbR, (2) according to Equation 58, ωbp = ω ×p, and (3) according
to the above Equation 72, R[Σa→Σw]p
[Σa]
a→b = p
[Σw]
a→b = p
[Σw]
b − p
[Σw]
a .
Since there exist one single link that rotates, we can easily get that the angular velocity
of the end point will be equal to the velocity of the joint a, i.e.,
ω
Σw
b = ω
Σw
a
. (78)
5.2 Multi-Link Robot End Point Velocity
For the robot with multiple (more than one) moveable links, the end point’s velocity calculation will be more difficulty and challenging. We take the multi-link robot arm used before
in this part to illustrate the calculation process for readers.
25
JIAWEI ZHANG, IFM LAB DIRECTOR
5.2.1 Multi-Link Robot Homogeneous Transition Matrix
As introduced in Section 3.2, for the robot arm involving multiple link, the homogenous
transformation matrices between the local and world coordinate systems can be represented
as follows:
T


Conversion_formulae_between_formalisms
"Rotation formalisms in three dimensions")

Euler angles are one way to represent orientations. There are others, and it
is possible to change to and from other conventions. Three parameters are
always required to describe orientations in a [ 3-dimensional
](/wiki/Dimension "Dimension") [ Euclidean space ](/wiki/Euclidean_space
"Euclidean space") . They can be given in several ways, Euler angles being one
of them; see [ charts on SO(3) ](/wiki/Charts_on_SO\(3\) "Charts on SO\(3\)")
for others.

The most used orientation representation are the [ rotation matrices
](/wiki/Rotation_matrix "Rotation matrix") , the [ axis-angle ](/wiki/Axis-
angle "Axis-angle") and the [ quaternions ](/wiki/Quaternion "Quaternion") ,
also known as [ Euler–Rodrigues parameters
](/wiki/Euler%E2%80%93Rodrigues_parameters "Euler–Rodrigues parameters") ,
which provide [ another mechanism ](/wiki/Quaternions_and_spatial_rotation
"Quaternions and spatial rotation") for representing 3D rotations. This is
equivalent to the special unitary group description.

Expressing rotations in 3D as unit quaternions instead of matrices has some
advantages:

  * Concatenating rotations is computationally faster and numerically more stable.
  * Extracting the angle and axis of rotation is simpler.
  * Interpolation is more straightforward. See for example [ slerp ](/wiki/Slerp "Slerp") .
  * Quaternions do not suffer from [ gimbal lock ](/wiki/Gimbal_lock "Gimbal lock") as Euler angles do.

Regardless, the rotation matrix calculation is the first step for obtaining
the other two representations.


will be coefficient-free. Only precession can be expressed in general as a
matrix in the basis of the space without dependencies of the other angles.

These movements also behave as a gimbal set. If we  [ _[ who?
](/wiki/Wikipedia:Manual_of_Style/Words_to_watch


R[Σa→Σw]p
[Σa]
a→b + p
[Σw]
a

0 1
#
. (82)
According to the physical meanings of elements in the calculated homogeneous transformation matrix T[Σb→Σw]
, we know that the rotation matrix from local coordinate Σb at
the second arm link to the world coordinate Σw and the arm end point position vector in
the world coordinate Σw can be represented as
p
[Σw]
b = R[Σa→Σw]p
[Σa]
a→b + p
[Σw]
a
, (83)
R[Σb→Σw] = R[Σa→Σw]R[Σb→Σa]
, (84)
which will help calculate the linear velocity and angular velocity vectors of the end point in
the world coordinate Σw.
5.2.2 Multi-Link Robot Linear Velocity
From Equation 1, by projecting the second arm link vector p
[Σb]
b→e
and adding to the position
vector p
[Σw]
b
, we can calculate the end point linear velocity as
p
[Σw]
e = p
[Σw]
b + R[Σb→Σw]p
[Σb]


**Using this convention, W,P,R are not Yaw, Pitch and Roll**


[ Write
](/m/signin?operation=register&redirect=https%3A%2F%2Fmedium.com%2Fnew-
story&source=---two_column_layout_nav-----------------------
new_post_topnav-----------)


* [ Feb 27th 2018  ](https://www.robot-forum.com/robotforum/thread/25960-fanuc-robot-rotations-and-positioning/?postID=110605#post110605)


**Forward Kinematics
** Forward kinematics is a concept in robotics that deals with the calculation
of the position and orientation of an end-effector based on the known joint
angles and link parameters of a robot’s kinematic chain. The first three row’s
element of fourth column of the given matrix provides the **x, y, z** position
of the end-effector and is given by:


  Vehicles and moving frames  [  [ edit
](/w/index.php?title=Euler_angles&action=edit&section=23 "Edit section:
Vehicles and moving frames") ]

Main article: [ rigid body ](/wiki/Rigid_body "Rigid body")

See also: [ axes conventions ](/wiki/Axes_conventions "Axes conventions")

Their main advantage over other orientation descriptions is that they are
directly measurable from a gimbal mounted in a vehicle. As gyroscopes keep
their rotation axis constant, angles measured in a gyro frame are equivalent
to angles measured in the lab frame. Therefore, gyros are used to know the
actual orientation of moving spacecraft, and Euler angles are directly
measurable. Intrinsic rotation angle cannot be read from a single gimbal, so
there has to be more than one gimbal in a spacecraft. Normally there are at
least three for redundancy. There is also a relation to the well-known [
gimbal lock ](/wiki/Gimbal_lock "Gimbal lock") problem of [ mechanical
engineering ](/wiki/Mechanical_engineering "Mechanical engineering") .  [7]

When studying rigid bodies in general, one calls the _xyz_ system _space
coordinates_ , and the _XYZ_ system _body coordinates_ . The space coordinates
are treated as unmoving, while the body coordinates are considered embedded in
the moving body. Calculations involving [ acceleration ](/wiki/Acceleration
"Acceleration") , [ angular acceleration ](/wiki/Angular_acceleration "Angular
acceleration") , [ angular velocity ](/wiki/Angular_velocity "Angular
velocity") , [ angular momentum ](/wiki/Angular_momentum "Angular momentum") ,
and [ kinetic energy ](/wiki/Kinetic_energy "Kinetic energy") are often
easiest in body coordinates, because then the moment of inertia tensor does
not change in time. If one also diagonalizes the rigid body's moment of
inertia tensor (with nine components, six of which are independent), then one
has a set of coordinates (called the principal axes) in which the moment of
inertia tensor has only three components.

The angular velocity of a rigid body takes a [ simple form
](/wiki/Angular_velocity



| {z }
p
. (55)
Definition 10 (Projection Operators): To simplify the notations, we can also introduce
two operators ∧ : ω → RR˙ > and ∨ : RR˙ > → ω.
• Given an angular velocity vector ω, we can represent the corresponding matrix RR˙ >
projected from it as
RR˙ > = ω
∧
, or RR˙ > = ωb. (56)
• Given a skew symmetric matrix RR˙ >, we can also represent the corresponding angular
velocity vector ω constructed from it as
ω = (RR˙ >)
∨
. (57)
Based on the above analysis, we can also rewrite Equation 52 as follows:
ω × p = ωbp, (58)
which can calculate the vector cross-product with the regular matrix-vector multiplication.
21
JIAWEI ZHANG, IFM LAB DIRECTOR
4.4 Rotation Matrix Exponential and Logarithm
As robot arm rotates with angular velocity, it will change the arm’s position with the
rotation matrix. It seems both the angular velocity vector ω and the rotation matrix R are
describing the effects of the robot rotation motion. Then, given the angular velocity vector
ω, can we directly calculate the corresponding rotation matrix R? And given the rotation
matrix R, can we calculate the corresponding angular velocity vector ω?
To answer these two questions, at the end of this section, we will introduce two important
operators defined on the rotation matrix R, i.e., the rotation matrix exponential and rotation
matrix logarithm.
4.4.1 Rotation Matrix Exponential
For Equation 56, if we multiply both sides with the rotation matrix R, we can get
ωbR = R R˙
| {z
>R}
=I
= R˙
. (59)
From the calculus course we learn at college, for a function f(x), if f(x)
0 = af(x), then


The rotation of 1) :


[ TitusLepic  ](https://www.robot-forum.com/user/58264-tituslepic/)


[ Sign in
](/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2F%40bikashojha904%2Fkinematic-
modelling-of-robotic-arms-4f40883fbaef&source=post_page---
two_column_layout_nav-----------------------global_nav-----------)


###  [ How to see your Job Posting (search or recruit) here in Robot-Forum.com
](https://www.robot-forum.com/robotforum/thread/39917-how-to-see-your-job-
posting-search-or-recruit-here-in-robot-forum-com/)


     6
[ Posts ](https://www.robot-forum.com/robotforum/user-post-list/2400-nation/
"Posts by Nation")


  Rotation matrix  [  [ edit
](/w/index.php?title=Euler_angles&action=edit&section=18 "Edit section:
Rotation matrix") ]

Any orientation can be achieved by composing three elemental rotations,
starting from a known standard orientation. Equivalently, any [ rotation
matrix ](/wiki/Rotation_matrix "Rotation matrix") _R_ can be [ decomposed
](/wiki/Matrix_decomposition "Matrix decomposition") as a product of three
elemental rotation matrices. For instance:

     R  =  X  (  α  )  Y  (  β  )  Z  (  γ  )  {\displaystyle R=X(\alpha )Y(\beta )Z(\gamma )}  ![{\\displaystyle R=X\(\\alpha \)Y\(\\beta \)Z\(\\gamma \)}](https://wikimedia.org/api/rest_v1/media/math/render/svg/ab48abbc214df3633ab0262c3ef043bbd497a38d)

is a rotation matrix that may be used to represent a composition of  extrinsic
rotations  about axes _z_ , _y_ , _x_ , (in that order), or a composition of
intrinsic rotations  about axes _x_ \- _y_ ′- _z_ ″ (in that order). However,
both the definition of the elemental rotation matrices _X_ , _Y_ , _Z_ , and
their multiplication order depend on the choices taken by the user about the
definition of both rotation matrices and Euler angles (see, for instance, [
Ambiguities in the definition of rotation matrices
](/wiki/Rotation_matrix


    * [ ](https://www.robot-forum.com/trophy/65-very-popular-member/)
    * [ ](https://www.robot-forum.com/trophy/76-typewriter/)


I have a question regarding the way Fanuc robots perform positioning of a
tool. I am using an LRMate200iC with a R-30 Mate controller, but I guess this
will be the same for all Fanuc robots.


](/@bikashojha904?source=post_page-----
4f40883fbaef--------------------------------)


* [ Feb 26th 2018  ](https://www.robot-forum.com/robotforum/thread/25960-fanuc-robot-rotations-and-positioning/?postID=110539#post110539)


[ Reactions Received ](https://www.robot-forum.com/user/57811-hawkme/#likes
"Reactions Received by HawkME")


∧
(105)
=ωb
[Σw]
a + ωb
[Σw]
b
. (106)
27
JIAWEI ZHANG, IFM LAB DIRECTOR
By applying the ∨ operator to both sides of the above equation, we can represent the
angular velocity of the end point as
ω
[Σw]
e = ω
[Σw]
a + ω
[Σw]
b
. (107)
To derive the angular velocity and linear velocity of the end point, we use several equations to replace terms with their equivalent representations, like
R[Σa→Σw]

ω
[Σa]
b × p
[Σa]
b→e

=

R[Σa→Σw]ω
[Σa]
b

×

R[Σa→Σw]p
[Σa]
b→e


  * [ SPEED ](https://www.robot-forum.com/tagged/429-speed/?objectType=com.woltlab.wbb.thread)
  * [ staubli ](https://www.robot-forum.com/tagged/193-staubli/?objectType=com.woltlab.wbb.thread)
  * [ tcp ](https://www.robot-forum.com/tagged/931-tcp/?objectType=com.woltlab.wbb.thread)
  * [ TCP/IP ](https://www.robot-forum.com/tagged/629-tcp-ip/?objectType=com.woltlab.wbb.thread)
  * [ teach pendant ](https://www.robot-forum.com/tagged/1318-teach-pendant/?objectType=com.woltlab.wbb.thread)
  * [ vision ](https://www.robot-forum.com/tagged/16-vision/?objectType=com.woltlab.wbb.thread)
  * [ Welding ](https://www.robot-forum.com/tagged/229-welding/?objectType=com.woltlab.wbb.thread)
  * [ workvisual ](https://www.robot-forum.com/tagged/13-workvisual/?objectType=com.woltlab.wbb.thread)
  * [ yaskawa ](https://www.robot-forum.com/tagged/173-yaskawa/?objectType=com.woltlab.wbb.thread)
  * [ YRC1000 ](https://www.robot-forum.com/tagged/560-yrc1000/?objectType=com.woltlab.wbb.thread)


**PHEW! It was pretty intense to begin with. But the good news is its all
downhill from here.**


  * [ abb ](https://www.robot-forum.com/tagged/116-abb/?objectType=com.woltlab.wbb.thread)
  * [ Backup ](https://www.robot-forum.com/tagged/207-backup/?objectType=com.woltlab.wbb.thread)
  * [ calibration ](https://www.robot-forum.com/tagged/344-calibration/?objectType=com.woltlab.wbb.thread)
  * [ Communication ](https://www.robot-forum.com/tagged/590-communication/?objectType=com.woltlab.wbb.thread)
  * [ DCS ](https://www.robot-forum.com/tagged/78-dcs/?objectType=com.woltlab.wbb.thread)
  * [ dx100 ](https://www.robot-forum.com/tagged/174-dx100/?objectType=com.woltlab.wbb.thread)
  * [ dx200 ](https://www.robot-forum.com/tagged/80-dx200/?objectType=com.woltlab.wbb.thread)
  * [ error ](https://www.robot-forum.com/tagged/175-error/?objectType=com.woltlab.wbb.thread)
  * [ Ethernet ](https://www.robot-forum.com/tagged/369-ethernet/?objectType=com.woltlab.wbb.thread)
  * [ external axis ](https://www.robot-forum.com/tagged/339-external-axis/?objectType=com.woltlab.wbb.thread)
  * [ Fanuc ](https://www.robot-forum.com/tagged/6-fanuc/?objectType=com.woltlab.wbb.thread)
  * [ help ](https://www.robot-forum.com/tagged/75-help/?objectType=com.woltlab.wbb.thread)
  * [ hmi ](https://www.robot-forum.com/tagged/351-hmi/?objectType=com.woltlab.wbb.thread)
  * [ I/O ](https://www.robot-forum.com/tagged/30-i-o/?objectType=com.woltlab.wbb.thread)
  * [ iiwa ](https://www.robot-forum.com/tagged/498-iiwa/?objectType=com.woltlab.wbb.thread)
  * [ irc5 ](https://www.robot-forum.com/tagged/313-irc5/?objectType=com.woltlab.wbb.thread)
  * [ IRVIsion ](https://www.robot-forum.com/tagged/244-irvision/?objectType=com.woltlab.wbb.thread)
  * [ karel ](https://www.robot-forum.com/tagged/36-karel/?objectType=com.woltlab.wbb.thread)
  * [ kawasaki ](https://www.robot-forum.com/tagged/12-kawasaki/?objectType=com.woltlab.wbb.thread)
  * [ kawasaki controller ](https://www.robot-forum.com/tagged/999-kawasaki-controller/?objectType=com.woltlab.wbb.thread)
  * [ Kawasaki robot ](https://www.robot-forum.com/tagged/998-kawasaki-robot/?objectType=com.woltlab.wbb.thread)
  * [ KRC2 ](https://www.robot-forum.com/tagged/97-krc2/?objectType=com.woltlab.wbb.thread)
  * [ KRC4 ](https://www.robot-forum.com/tagged/34-krc4/?objectType=com.woltlab.wbb.thread)
  * [ KRC 4 ](https://www.robot-forum.com/tagged/4105-krc-4/?objectType=com.woltlab.wbb.thread)
  * [ KRL ](https://www.robot-forum.com/tagged/196-krl/?objectType=com.woltlab.wbb.thread)
  * [ KUKA ](https://www.robot-forum.com/tagged/32-kuka/?objectType=com.woltlab.wbb.thread)
  * [ motoman ](https://www.robot-forum.com/tagged/172-motoman/?objectType=com.woltlab.wbb.thread)
  * [ Offset ](https://www.robot-forum.com/tagged/502-offset/?objectType=com.woltlab.wbb.thread)
  * [ PLC ](https://www.robot-forum.com/tagged/320-plc/?objectType=com.woltlab.wbb.thread)
  * [ position ](https://www.robot-forum.com/tagged/195-position/?objectType=com.woltlab.wbb.thread)
  * [ PROFINET ](https://www.robot-forum.com/tagged/317-profinet/?objectType=com.woltlab.wbb.thread)
  * [ Program ](https://www.robot-forum.com/tagged/8-program/?objectType=com.woltlab.wbb.thread)
  * [ Programming ](https://www.robot-forum.com/tagged/107-programming/?objectType=com.woltlab.wbb.thread)
  * [ RAPID ](https://www.robot-forum.com/tagged/152-rapid/?objectType=com.woltlab.wbb.thread)
  * [ roboguide ](https://www.robot-forum.com/tagged/43-roboguide/?objectType=com.woltlab.wbb.thread)
  * [ robot ](https://www.robot-forum.com/tagged/4-robot/?objectType=com.woltlab.wbb.thread)
  * [ robotstudio ](https://www.robot-forum.com/tagged/180-robotstudio/?objectType=com.woltlab.wbb.thread)
  * [ RSI ](https://www.robot-forum.com/tagged/33-rsi/?objectType=com.woltlab.wbb.thread)
  * [ safety ](https://www.robot-forum.com/tagged/506-safety/?objectType=com.woltlab.wbb.thread)
  * [ Siemens ](https://www.robot-forum.com/tagged/582-siemens/?objectType=com.woltlab.wbb.thread)


](https://speechify.com/medium?source=post_page-----
4f40883fbaef--------------------------------)