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

Subscribing 2 topics of different types in a callback function

asked 2011-12-21 02:35:12 -0600

alfa_80 gravatar image

updated 2011-12-21 03:16:48 -0600

I would like to ask, How do I subscribe 2 topics with different message types (say one is LaserScan and another is Pose) using a callback function? How to realize this in a better way? Could someone point me to some references or any code snippet will be helpful.

EDIT: If one wants to get what I'm actually aiming at is like this, you can think I want to get 2 values from those 2 topics and do a addition of those 2 values there, and can further publish it the new result of the addition.

edit retag flag offensive close merge delete

6 Answers

Sort by ยป oldest newest most voted
1

answered 2011-12-21 02:59:59 -0600

DimitriProsser gravatar image

updated 2011-12-21 03:09:12 -0600

Callback functions are type-specific. If you try to pass an incorrect message type to a callback function, it will error out. Maybe it would help if you included some more information as to what you're trying to accomplish, but as a general rule, you need a separate callback for each message type.

If you wanted to, you could try something like this:

void velocityCallback(const geometry_msgs::Twist::ConstPtr& msg)
{
   previous_velocity_msg_ = *msg;
   velocity_updated_ = true;

   if(velocity_updated_ && wheel_odom_updated_)
       genericFunction();
}

void wheelOdomCallback(const nav_msgs::Odometry::ConstPtr& msg)
{
   previous_wheel_odom_ = *msg;
   wheel_odom_updated_ = true;

   if(velocity_updated_ && wheel_odom_updated_)
       genericFunction();
}

EDIT: If you need to access data from both message types in a node, you should use class variables to store the previous messages. See the above code. If you stored them as such, genericFunction() could access the value like a global variable.

edit flag offensive delete link more

Comments

If one callback I build for one subscription, how do I manipulate them altogether. I need to get access to both of them in one "area" so that I can perform data manipulation there. If it's "local" for each of them, is there any way to achieve this?
alfa_80 gravatar image alfa_80  ( 2011-12-21 03:04:18 -0600 )edit
But then, how do I get access the data from both of them? I don't want to do it in main function.
alfa_80 gravatar image alfa_80  ( 2011-12-21 03:10:25 -0600 )edit
A solution is to keep received data in node class member variables , and play with them alltogether in other node class functions out from the callbacks. Remind to protect variable manipulation with mutexes because of callbacks run in separated threads, and concurrency arises.
Andreu gravatar image Andreu  ( 2011-12-21 03:13:37 -0600 )edit
@DimitriProsser: I still couldn't see the use of this "if(velocity_updated_ && wheel_odom_updated_)" condition, is it incomplete? seems illogical..
alfa_80 gravatar image alfa_80  ( 2011-12-21 03:39:29 -0600 )edit
@Andreu: How do I "protect variable manipulation with mutexes", any good reference for that?
alfa_80 gravatar image alfa_80  ( 2011-12-21 03:40:15 -0600 )edit
@DimitriProsser: Thanks a lot..Now, I can see the use of it. Oh, by the way, how do I "protect variable manipulation with mutexes" as pointed by Andreu? Thanks in advance.
alfa_80 gravatar image alfa_80  ( 2011-12-21 03:45:09 -0600 )edit
I've added an extra answer to illustrate mutex/callback utilisation. Hope it helps. Kind Regards ! Andreu
Andreu gravatar image Andreu  ( 2011-12-21 04:03:57 -0600 )edit
@Andreu has a good suggestion for mutexes.
DimitriProsser gravatar image DimitriProsser  ( 2011-12-21 04:12:56 -0600 )edit
3

answered 2011-12-21 04:02:49 -0600

An example on how to protect callbacks with mutextes. You can use POSIX mutexes, then you have to change enter()/exit() by pthread_mutex_lock()/_unlock(). Please see that

myNode::myCallback(const my_msgs::m1::ConstPtr& msg)
{
   mutex.enter();
   this->a = msg->a;
   mutex.exit();
}
myNode::myCallback(const my_msgs::m2::ConstPtr& msg)
{
   mutex.enter();
   this->b = msg->b;
   mutex.exit();
}
myNode::process()
{
   mutex.enter();
   std::cout << this->a + this->b << std::endl;
   mutex.exit();
}
edit flag offensive delete link more

Comments

This is normally not needed, all callbacks occur in the same thread, unless you explicitly set them up multi-threaded.
joq gravatar image joq  ( 2011-12-21 05:01:41 -0600 )edit
@Andreu: What is the header I need to include in order to be able to use mutex stuff? I just wanna try because it seems that one value is wrongly read(keep reading 0 value).
alfa_80 gravatar image alfa_80  ( 2011-12-22 18:40:29 -0600 )edit
#include <pthread.h>
Andreu gravatar image Andreu  ( 2011-12-22 21:28:53 -0600 )edit
Andreu gravatar image Andreu  ( 2011-12-22 21:29:30 -0600 )edit
@Andreu: Thanks a lot!
alfa_80 gravatar image alfa_80  ( 2011-12-23 02:33:40 -0600 )edit
2

answered 2012-04-25 05:36:37 -0600

IvanShindev gravatar image

I believe the best way to do this is to use the boost::shared_ptr<synchronizer>. For example the openni node uses this to synchronize a depth_msg and rgb_msg and pass them as arguments to callback a function. The following code is from the openni_nodelet.cpp:

boost::shared_ptr<synchronizer> depth_rgb_sync_; //from header file

SyncPolicy sync_policy (4); // queue size

depth_rgb_sync_.reset (new Synchronizer (sync_policy));

depth_rgb_sync_->registerCallback (boost::bind (&OpenNINodelet::publishXYZRGBPointCloud, this, _1, _2));

depth_rgb_sync_->add < 1 > (rgb_msg);

depth_rgb_sync_->add < 0 > (depth_msg);

and the callback function is:

void OpenNINodelet::publishXYZRGBPointCloud (const sensor_msgs::ImageConstPtr& depth_msg, const sensor_msgs::ImageConstPtr& rgb_msg) const {}

So you can subscribe to 2 different topics, each having their own message, and in their callback functions you can add the msg to the boost synchronizer. For example in the first callback you can do depth_rgb_sync_->add < 1 > (rgb_msg) and in the second one depth_rgb_sync_->add < 0 > (depth_msg) where depth_rgb_sync_ will be replaced by your boost::shared_ptr<synchronizer> and rgb_msg and depth_msg will be replaced by the messages of the 2 topics. When both messages are received the boost synchronizer will call your function with the 2 msgs as arguments.

Hope this help. Ivan

edit flag offensive delete link more
0

answered 2011-12-21 04:01:23 -0600

Bill Smart gravatar image

If what you want is a callback that is triggered when messages come in at (approximately) the same time on two (or more) separate topics, you should look at message_filters.

edit flag offensive delete link more

Comments

This is complicated somehow to implement. Could you supply a code snippet to mimic the functionality that I describe to have "a callback that is triggered when messages come in at (approximately) the same time on two (or more) separate topics".
alfa_80 gravatar image alfa_80  ( 2011-12-21 04:55:27 -0600 )edit
The example you gave above was taking a value from each of two messages, adding them up, and publishing a message with their sum. This seems straightforward; am I missing something?
Bill Smart gravatar image Bill Smart  ( 2011-12-21 07:44:16 -0600 )edit
yes, this example is for simplicity, the message_filters also sounds interesting because I can have time control there. But I guess the above code snippet given by @DimitriProsser also I can ensure both message comes "in pair".
alfa_80 gravatar image alfa_80  ( 2011-12-21 18:52:26 -0600 )edit
Dimitri's code will pair up the messages, but it won't ensure that the messages that it pairs are close to each other in time. You might not care about this but, if you do, message_filters might be the right solution.
Bill Smart gravatar image Bill Smart  ( 2011-12-26 09:02:09 -0600 )edit
0

answered 2011-12-21 03:00:25 -0600

sam gravatar image

updated 2011-12-21 03:01:07 -0600

Why you want to do this? Is it a reasonable case?

What I know is writing 2 callbacks and each callback call the same function.

Therefore, you can implement that function deal with 2 cases of callback events.

I haven't trying,just an idea.

edit flag offensive delete link more

Comments

Please use comments to ask for clarifications rather than answers.
mjcarroll gravatar image mjcarroll  ( 2011-12-21 03:11:51 -0600 )edit
I have ask for clarifications and also give my answers that 'writing 2 callbacks and each callback call the same function, and you can implement that function deal with 2 cases of callback events'.
sam gravatar image sam  ( 2011-12-22 02:07:04 -0600 )edit
Thanks anyway.
alfa_80 gravatar image alfa_80  ( 2011-12-22 02:15:55 -0600 )edit
0

answered 2011-12-21 03:07:55 -0600

The best way is to create two sparated callbacks , and associate each callback to each topic with the subscribe() function (ros::NodeHandle::subscribe(), see this.

Otherwise, I don't see why you should use a single callback for both topics ? Do you have a motivation about this requirement ?

kind regards,

andreu

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2011-12-21 02:35:12 -0600

Seen: 9,133 times

Last updated: Apr 25 '12