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

ros2 add arguments to callback

asked 2018-11-13 12:08:28 -0500

alsora gravatar image

updated 2018-11-14 16:22:57 -0500


I am trying to add an argument to a ROS2 subscriber callback.

The main objective was to print the name of the topic from inside the callback, so I tried to follow this ROS1 example, but it's not working.

These are the relevant parts of my code

Creation of the subscriber

rclcpp::Subscription<std_msgs::msg::Header>::SharedPtr subscriber =  this->create_subscription<std_msgs::msg::Header>(
  std::bind(&MultiNode::topic_callback, this, std::placeholders::_1, topic_name));

Callback implementation

void MultiNode::topic_callback(const std_msgs::msg::Header::SharedPtr msg, std::string topic_name)
    std::cout<< topic_name<<std::endl;

I get a very long sequence of errors which boils down to

error: no matching function for call to ‘rclcpp::AnySubscriptionCallback<std_msgs::msg::Header_<std::allocator<void> >, std::allocator<void> >::set(std::_Bind<std::_Mem_fn<void (MultiNode::*)(std::shared_ptr<std_msgs::msg::Header_<std::allocator<void> > >, std::__cxx11::basic_string<char>)>(MultiNode*, std::_Placeholder<1>, std::__cxx11::basic_string<char>)>)’
edit retag flag offensive close merge delete


See also #q289207

lucasw gravatar image lucasw  ( 2018-11-14 09:48:20 -0500 )edit

2 Answers

Sort by » oldest newest most voted

answered 2018-11-13 19:22:36 -0500

Karsten gravatar image

That's actually a known bug already.

We wrap each callback in a datatype called AnyCallback. The problem is as follows:

if you just call:

auto fcn = std::bind(callback_func, std::placeholders::_1, topic_name);

That fcn instance is of type std::_Bind<std::_Mem_fn<void (MultiNode::*)(std::shared_ptr<std_msgs::msg::Header_<std::allocator<void> > >, std::__cxx11::basic_string<char>)>(MultiNode*, std::_Placeholder<1>, std::__cxx11::basic_string<char>)> and thus has two arguments. Our custom AnyCallback requires though only one argument. So there is no call to wrap the callback with two arguments. That's all just to explain the error message you're getting.

Now, std::bind can actually be assigned to any type of std::function. Which is maybe weird, but works :)

so you can call what William suggested:

std::function<void(const std_msgs::msg::String::SharedPtr msg)> fcn = std::bind(callback_func, std::placeholders::_1, topic_name);

And this has correctly set only one argument, even though the second argument is still getting passed into the callback.

edit flag offensive delete link more

answered 2018-11-13 13:20:40 -0500

William gravatar image

Looks like there might be a bug in our code that allows for various types of callbacks in our code.

If you do something like this:

std::function<void(const std_msgs::msg::String::SharedPtr msg)> bound_callback_func =
  std::bind(callback_func, std::placeholders::_1, topic_name);

And then pass that to create_subscription() then it seems to work correctly.

But I can also reproduce your issue, do you think you could provide a simple, compilable example in an issue on rclcpp?

Please make sure that you follow the new issue guidelines.

Another alternative would be to use lambda to capture the topic name, for example:

auto callback_factory = [](const std::string & a_topic_name) {
  return [a_topic_name](const std_msgs::msg::String::SharedPtr msg) -> void {
    printf("topic_name: %s, data: %s\n", a_topic_name.c_str(), msg->data.c_str());

And then use it when making each subscription:

sub_ = create_subscription<std_msgs::msg::String>(topic_name, callback_factory("topic1"));
sub_ = create_subscription<std_msgs::msg::String>(topic_name, callback_factory("topic2"));
edit flag offensive delete link more


Question Tools



Asked: 2018-11-13 12:08:28 -0500

Seen: 5,801 times

Last updated: Nov 14 '18