Robotics StackExchange | Archived questions

[ros2] Issue with subscribing to topic using SingleThreadedExecutor and Node in ROS2.

hi all,

The code below seems to work well as I expected, but it doesn't.

class MyClass : public rclcpp::Node
{
public:
  MyClass()
  : Node("my_class")
  {
    subscription_ = this->create_subscription<std_msgs::msg::String>(
      "test", 10, std::bind(&MyClass::MyCallback, this, _1));
  }

private:
  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
  void MyCallback(const std_msgs::msg::String::SharedPtr msg) const
  {
    RCLCPP_INFO(rclcpp::get_logger("MyClass"), "Subscribed : '%s'", msg->data.c_str());
  }
};


int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
/*
  // work well 
  rclcpp::executors::SingleThreadedExecutor single_exec;
  auto a = std::make_shared<MyClass>();
  single_exec.add_node(a);
  single_exec.spin();

  // work well 
  rclcpp::spin(std::make_shared<MyClass>());

*/  
  // not work
  rclcpp::executors::SingleThreadedExecutor single_exec;
  single_exec.add_node(std::make_shared<MyClass>());
  single_exec.spin();

  rclcpp::shutdown();
  return 0;
}

The MyClass is derived from rclcpp::Node, and the shared pointer is implicitly convertible to a shared pointer to rclcpp::Node. The addnode function in the executor takes a shared pointer to rclcpp::Node, so the call to addnode should succeed. However, when I run the code upper, it doesn't subscribe to the topic and can't be found on the ros2 node list command; it just blocks.

If I replace the executor code with either of the ones in the comments, it works well.

Asked by leeminju531 on 2023-04-05 04:57:15 UTC

Comments

Answers

When you created a shared_ptr node as you did in the commented code, it exists in "main" scope. On the other hand, when you just create the node as input argument, it will not be available outside of single_exec.add_node.

Since rclcpp::executors::SingleThreadedExecutor inherits from rclcpp::executor::Executor(link to doc), it also offers APIs tsuch as remove_node, so I guess the shared pointer to a rclcpp::Node cannot just got removed after calling add_node.

I would go with the first "work well".

Asked by GuimingChen on 2023-04-06 08:39:42 UTC

Comments

Thank you for your comments. Both add_node and rclcpp::spin take the same shared_ptr as an input parameter, which was initially confusing to me.

The rclcpp::spin() function takes ownership of the shared_ptr and keeps it alive for the duration of the spin loop. However, single_exec.add_node(std::make_shared<MyClass>()) creates a shared_ptr to a MyClass instance, but that shared_ptr is not held onto by anything outside of the add_node() function call, as you mentioned earlier. As a result, the MyClass instance is immediately destroyed after the call to add_node(), and the subscription is lost (it looks like it takes a weak_ptr).

Thanks a lot!

Asked by leeminju531 on 2023-04-06 10:07:46 UTC