ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

[ROS2] Subscriber in component

asked 2022-06-28 12:17:05 -0600

Cryoschrome gravatar image

updated 2022-06-28 12:18:03 -0600

Configuration

  • ROS Distro: Humble
  • OS Version: Ubuntu 22.04

Description

Hi, I am trying to create a hardware_interface plugin for ros2_control. I want to create a publisher to write() and a subscriber to read(). I am running into issues setting up the subscriber. Then code is given below.

Code


#include <cstdlib>
#include <chrono>
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/float64.hpp"
#include "sensor_msgs/msg/joint_state.hpp"
#include "custom_interfaces/msg/motor_command.hpp"

#include "test_hardware_interface/test_hardware_interface.hpp"
#include "hardware_interface/actuator_interface.hpp"
#include "hardware_interface/types/hardware_interface_type_values.hpp"

using namespace hardware_interface;

static const auto LOGGER = rclcpp::get_logger("Grab-Hardware");

namespace test_hardware_interface
{
  //HardwareComms Methods
  HardwareComms::HardwareComms() : Node("joint_comms")
  {
    //Lamda callback for stateSub_
    auto stateCB =
      [this](const std_msgs::msg::Float64::SharedPtr state) -> void
      {
        RCLCPP_INFO(this->get_logger(), "Callback");
        state_ = state->data;
      };
    commandPub_ = this->create_publisher<custom_interfaces::msg::motorcommand>(
      "/test_pub",
      0
    );

    stateSub_ = this->create_subscription<std_msgs::msg::float64>(
      "/test_sub",
      0,
      stateCB
    );
  }

  void HardwareComms::sendCommand(double position, double velocity, double acceleration)
  {
    auto command = custom_interfaces::msg::MotorCommand();
    command.position = position;
    command.velocity = velocity;
    command.acceleration = acceleration;
    commandPub_->publish(command);
  }

  double HardwareComms::getState()
  {
    return state_;
  }

  //HardwareInterface Methods
  CallbackReturn HardwareInterface::on_init(const hardware_interface::HardwareInfo &info)
  {
    RCLCPP_INFO(LOGGER, "Initialising...");
    if(
      hardware_interface::ActuatorInterface::on_init(info) !=
        hardware_interface::CallbackReturn::SUCCESS)
    {
      return hardware_interface::CallbackReturn::ERROR;
    }

    comms = std::make_shared<hardwarecomms>();

    hw_joint_state_           = std::numeric_limits<double>::quiet_NaN();
    hw_position_command_      = std::numeric_limits<double>::quiet_NaN();
    hw_velocity_command_      = std::numeric_limits<double>::quiet_NaN();
    hw_acceleration_command_  = std::numeric_limits<double>::quiet_NaN();

    const ComponentInfo &joint = info_.joints[0];
    if(joint.command_interfaces.size() != 3) {
      RCLCPP_FATAL(
        LOGGER,
        "Joint '%s' has %zu command interfaces found. 3 expected.", joint.name.c_str(),
        joint.command_interfaces.size()
      );
      return hardware_interface::CallbackReturn::ERROR;
    }

    RCLCPP_INFO(LOGGER, "Checking Position IF");
    if (joint.command_interfaces[0].name != hardware_interface::HW_IF_POSITION) {
      RCLCPP_FATAL(
        LOGGER,
        "Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),
        joint.command_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION
      );
      return hardware_interface::CallbackReturn::ERROR;
    }
    RCLCPP_INFO(LOGGER, "Clear!");

    RCLCPP_INFO(LOGGER, "Checking Velocity IF");
    if (joint.command_interfaces[1].name != hardware_interface::HW_IF_VELOCITY) {
      RCLCPP_FATAL(
        LOGGER,
        "Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),
        joint.command_interfaces[1].name.c_str(), hardware_interface::HW_IF_VELOCITY
      );
      return hardware_interface::CallbackReturn::ERROR;
    }
    RCLCPP_INFO(LOGGER, "Clear!");

    RCLCPP_INFO(LOGGER, "Checking Acceleration IF");
    if (joint.command_interfaces[2].name != hardware_interface::HW_IF_ACCELERATION) {
      RCLCPP_FATAL(
        LOGGER,
        "Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),
        joint.command_interfaces[2].name.c_str(), hardware_interface::HW_IF_ACCELERATION
      );
      return hardware_interface::CallbackReturn::ERROR;
    }
    RCLCPP_INFO(LOGGER, "Clear!");

    if (joint.state_interfaces.size() != 1) {
      RCLCPP_FATAL(
        LOGGER, "Joint '%s' has %zu state interface. 1 expected.",
        joint.name.c_str(), joint.state_interfaces.size());
      return hardware_interface::CallbackReturn::ERROR;
    }

    if (joint.state_interfaces[0].name != hardware_interface::HW_IF_POSITION) {
      RCLCPP_FATAL(
        LOGGER, "Joint '%s' have %s state interface. '%s' expected.",
        joint.name.c_str(), joint.state_interfaces[0].name.c_str(),
        hardware_interface::HW_IF_POSITION);
      return hardware_interface::CallbackReturn::ERROR;
    }

    RCLCPP_INFO(LOGGER, "Done!");
    return hardware_interface::CallbackReturn::SUCCESS;
  }

  CallbackReturn HardwareInterface::on_configure(const rclcpp_lifecycle::State & /*previous_state*/)
  {
    RCLCPP_INFO(LOGGER, "Configuring...");
    return hardware_interface::CallbackReturn::SUCCESS;
  }

  std::vector<stateinterface> HardwareInterface::export_state_interfaces()
  {
    std::vector<hardware_interface::stateinterface> state_interfaces;

    state_interfaces.emplace_back(hardware_interface::StateInterface(
      info_.joints[0].name, hardware_interface::HW_IF_POSITION, &hw_joint_state_));

    return state_interfaces;
  }

  std::vector<commandinterface> HardwareInterface::export_command_interfaces()
  {
    std::vector<hardware_interface::commandinterface> command_interfaces;

    command_interfaces.emplace_back(hardware_interface::CommandInterface(
      info_.joints[0].name, hardware_interface::HW_IF_POSITION, &hw_position_command_));
    command_interfaces.emplace_back(hardware_interface::CommandInterface(
      info_.joints[0].name, hardware_interface::HW_IF_VELOCITY, &hw_velocity_command_));
    command_interfaces.emplace_back(hardware_interface::CommandInterface(
      info_.joints[0].name ...
(more)
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
3

answered 2023-02-02 15:33:44 -0600

Cryoschrome gravatar image

updated 2023-02-03 02:35:40 -0600

I specified a new node to handle communication to and from the hardware interface. Since the an executor is necessary to spin the node, I defined one in the hardware interface component and executed it in a detached thread.

joint_hardware_interface.hpp


#ifndef JOINT_HARDWARE_INTERFACE
#define JOINT_HARDWARE_INTERFACE

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

#include "hardware_interface/actuator_interface.hpp"

#include "rclcpp/rclcpp.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
#include "rclcpp_lifecycle/state.hpp"
#include "joint_limits/joint_limits.hpp"

#include "std_msgs/msg/float64.hpp"
#include "sensor_msgs/msg/joint_state.hpp"
#include "custom_interfaces/msg/motor_command.hpp"
#include <custom_interfaces msg="" motor_state.hpp="">

namespace join_hardware_interface
{
  class JointComms : public rclcpp::Node
  {
    public:
      /**
       * @brief Constructor a new Grab Joint Comms object
       */
      JointComms();

      /**
       * @brief Create the msg and publish to MCU
       */
      void sendCommand(double position, double velocity, double acceleration);

      /**
       * @brief Position and velocity getters
       */
      double getPosition();
      double getVelocity();
    private:
      double position_;
      double velocity_;
      rclcpp::Subscription<custom_interfaces::msg::motorstate>::SharedPtr stateSub_;
      rclcpp::Publisher<custom_interfaces::msg::motorcommand>::SharedPtr commandPub_;
  };

  class JointHardware : public hardware_interface::ActuatorInterface
  {
    public:
      JointHardware();    
      CallbackReturn on_configure(const rclcpp_lifecycle::State &previous_state);
      CallbackReturn on_activate(const rclcpp_lifecycle::State &previous_state);
      CallbackReturn on_deactivate(const rclcpp_lifecycle::State &previous_state);
      CallbackReturn on_init(const hardware_interface::HardwareInfo &info);

      std::vector<hardware_interface::stateinterface> export_state_interfaces() override;
      std::vector<hardware_interface::commandinterface> export_command_interfaces() override;
      hardware_interface::return_type read(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;
      hardware_interface::return_type write(
        const rclcpp::Time & time, const rclcpp::Duration & period) override;

      std::shared_ptr<JointComms> comms;

    private:
      rclcpp::executors::SingleThreadedExecutor executor_;  //Executor needed to subscriber
      double hw_position_command_;
      double hw_velocity_command_;
      double hw_acceleration_command_;
      double hw_position_state_;
      double hw_velocity_state_;
      int setSpeed_;
      int setAccelaration_;
      bool isActive_;

      joint_limits::JointLimits limits;
  };
}
 

and in the .cpp file, within the on_init() function, I created the thread.


    comms = std::make_shared<JointComms>();
    executor_.add_node(comms);
    std::thread([this]() { executor_.spin(); }).detach();
 
edit flag offensive delete link more

Question Tools

4 followers

Stats

Asked: 2022-06-28 12:17:05 -0600

Seen: 656 times

Last updated: Feb 03 '23