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

ROS 2 Composable Node Pass NodeHandler

asked 2019-08-16 16:05:33 -0600

zipp39 gravatar image

I have an object that does some internal publishing and subscribing within my Component Class. In ROS 1 we passed the node_handler to the constructor so that class had access to things of that nature. However, I believe the concept of node_handler is obsolete in ROS 2. Is there something similar that I can pass into the constructor to have access to node functions, etc..? Are there other solutions?

Thanks!

edit retag flag offensive close merge delete

3 Answers

Sort by ยป oldest newest most voted
2

answered 2021-03-09 22:23:58 -0600

AndyZe gravatar image

updated 2021-03-09 22:26:09 -0600

The way you pass a Node from one C++ class to another is with shared_from_this() and std::shared_ptr.

Example:

Class A inherits from rclcpp::Node. Get the node pointer like this:

auto node_ptr = shared_from_this();

Pass to another class (Class B) like this:

shared_pointer_to_class_b_object = std::make_shared<ClassB>(node_ptr);

The constructor of Class B should take a rclcpp::Node::SharedPtr node:

ClassB(rclcpp::Node::SharedPtr node) : node_(node)
{
}

And it should have a private member variable:

  // Pointer to the ROS node
  std::shared_ptr<rclcpp::Node> node_;

ROS2 documentation is still lacking and it helps to be a C++ guru :/

edit flag offensive delete link more

Comments

Shoot, this was working for me yesterday. Today it fails with a bad_weak_ptr error. Must be missing something...

AndyZe gravatar image AndyZe  ( 2021-03-10 16:55:15 -0600 )edit

The moment I call auto node_ptr = shared_from_this(); I get a bad_weak_ptr runtime error. I then realised it is because I call shared_from_this() in the constructor of Class A. (Silly mistake). I now moved the call out to the event handler of a subscriber. Sorted. Thank you for the clear explanation

Slaghuis gravatar image Slaghuis  ( 2021-07-01 08:39:37 -0600 )edit

I try to follow your logic but no result. @AndyZe@Slaghuis can you provide code example or point me to some work repos.

ghuan4 gravatar image ghuan4  ( 2021-08-31 09:59:08 -0600 )edit
0

answered 2019-08-29 09:55:34 -0600

mjcarroll gravatar image

In ROS1, the ros::NodeHandle was provided as a protected member of the ros::Nodelet class. In contrast, in ROS2, it is expected that user will create their own rclcpp::Node from the rclcpp::NodeOptions structure passed into the user's constructor.

In the composition paradigm, the thing that you want to compose will either directly inherit from rclcpp::Node or keep a rclcpp::Node as a member.

A demonstration of an object that inherits from rclcpp::Node is available in the ROS2 Demos package:

edit flag offensive delete link more

Comments

I think this doesn't quite answer the question, because I have the same question. Say you already have a class that inherits from rclcpp::Node. How do you pass that Node to the constructor of another class?

I don't think it would make sense for every single C++ class to inherit from rclcpp::Node.

AndyZe gravatar image AndyZe  ( 2021-03-09 21:56:48 -0600 )edit
0

answered 2022-02-20 11:31:54 -0600

rizkymille gravatar image

Adding comments above from AndyZe, yes you need to get the node pointer and pass it to another class. But if you do this in the class constructor, a bad_weak_ptr error will always show up. You can prevent this by initiating the class in callback.

I'm gonna use ClassA and ClassB example above, say you want to extend the node to ClassB to use ClassB functions from ClassA. Here's the header code of ClassB:

class ClassB {
  public:
    ClassB(rclcpp::Node::SharedPtr node); // constructor

    // your code here

  private:
    rclcpp::Node::SharedPtr node_;

    // your code here

and here's the definition code of ClassB:

// constructor
ClassB::ClassB(rclcpp::Node::SharedPtr node) : node_(node) {

    // your code here
}

Then in ClassA file:

class ClassA : public rclcpp::Node {
  public:
    ClassA() : Node("class_a") {

      // your code here

      // use one-time timer to initiate class B 
      timer = this->create_wall_timer(500ms, std::bind(&ClassA::initialization, this));
    }

  private:

    rclcpp::TimerBase::SharedPtr timer;

    std::shared_ptr<ClassB> class_b;

    void initialization() {
      // get node pointer, pass into Class B
      class_b = std::make_shared<ClassB>(shared_from_this());

      // replace timer with loop callback after initialization finished
      timer = this->create_wall_timer(500ms, std::bind(&UsingLibCpp::timer_callback, this)); 
    }

    void timer_callback() {
      // your code here

      // use Class B function
      class_b->class_b_function();
    }

I finally got it work after 2 weeks of digging. Too bad ROS2 documentation is still lacking in program style like this. Hope it helps

edit flag offensive delete link more

Question Tools

3 followers

Stats

Asked: 2019-08-16 16:05:33 -0600

Seen: 2,913 times

Last updated: Mar 09 '21