0
$\begingroup$

Rosanswers logo

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.


Originally posted by alfa_80 on ROS Answers with karma: 1053 on 2011-12-21

Post score: 0

$\endgroup$

3 Answers 3

0
$\begingroup$

Rosanswers logo

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.


Originally posted by DimitriProsser with karma: 11163 on 2011-12-21

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by alfa_80 on 2011-12-25:
@joq: I've tried one using "message_filters" but having a difficulty that is still unresolved (http://answers.ros.org/question/3407/message_filters-related-issue), if you know the fix for it, kindly suggest so that I can try.

Comment by joq on 2011-12-25:
This approach is OK, but for that many synchronized messages I would use message_filters, as suggested by @Bill Smart. Otherwise, the timing gets complicated.

Comment by alfa_80 on 2011-12-25:
Wow, even 4 ypu have, that's promising for my case too. Thanks a lot for the information.

Comment by DimitriProsser on 2011-12-25:
I do it with 4 in a single node, so yes, 3 is fine.

Comment by alfa_80 on 2011-12-25:
@DimitriProsser: Is it possible/reliable if I would have 3 topics of different types (instead of 2), then, I just add another callback function and some variables that you have demonstrated accordingly?

Comment by alfa_80 on 2011-12-24:
@DimitriProsser: You are totally right, one of my callbacks is not subscribing properly. Now, it's fixed. Thanks a lot!

Comment by alfa_80 on 2011-12-22:
Did this kind of code ever work for you?

Comment by alfa_80 on 2011-12-22:
Actually the callback is getting something from ROS_INFO as I can see the messages from rxconsole, nevertheless, one of the 2 values is consistently publishing 0.

Comment by alfa_80 on 2011-12-22:
What do you mean? I didn't get it..

Comment by DimitriProsser on 2011-12-22:
The only way that could happen would be if you're not getting a callback properly.

Comment by alfa_80 on 2011-12-22:
@DimitriProsser: After trying it, it doesn't seem to work with this approach, could you please revise it, if possible. Only one variable I got the value, the other one, always gives value of 0(zero).

Comment by alfa_80 on 2011-12-22:
Do you guys know maybe something to do with design pattern the kind of code that Dimitri gave? factory method or any related?

Comment by alfa_80 on 2011-12-22:
What a good discussion!

Comment by Andreu on 2011-12-21:
Thanks Joq ! I had misunderstood that callbacks run as an independent thread so that mutexes were required. So, it's time to remove all my mutexes from all my nodes ...

Comment by joq on 2011-12-21:
Unless you do something explicit (and unusual) while declaring your callbacks, you are guaranteed they will not run concurrently. Hence, no mutex is needed.

Comment by alfa_80 on 2011-12-21:
@joq: Could you clarify a bit a about that.

Comment by joq on 2011-12-21:
Note that mutexes are normally unnecessary (see below).

Comment by DimitriProsser on 2011-12-21:
That's correct.

Comment by alfa_80 on 2011-12-21:
@DimitriProsser: In case I want to adapt the mutexes as suggested by @Andreu, your code should be something like, "mutex.enter(); previous_velocity_msg_ = *msg; mutex.exit(); and accordingly for "previous_wheel_odom_ = *msg;" Am I right? "

Comment by alfa_80 on 2011-12-21:
@Andreu: Thanks a lot for the mutexes stuff..

Comment by DimitriProsser on 2011-12-21:
@Andreu has a good suggestion for mutexes.

Comment by Andreu on 2011-12-21:
I've added an extra answer to illustrate mutex/callback utilisation. Hope it helps. Kind Regards ! Andreu

Comment by alfa_80 on 2011-12-21:
@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.

Comment by alfa_80 on 2011-12-21:
@Andreu: How do I "protect variable manipulation with mutexes", any good reference for that?

Comment by alfa_80 on 2011-12-21:
@DimitriProsser: I still couldn't see the use of this "if(velocity_updated_ && wheel_odom_updated_)" condition, is it incomplete? seems illogical..

Comment by Andreu on 2011-12-21:
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.

Comment by alfa_80 on 2011-12-21:
But then, how do I get access the data from both of them? I don't want to do it in main function.

Comment by alfa_80 on 2011-12-21:
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?

$\endgroup$
0
$\begingroup$

Rosanswers logo

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();
}

Originally posted by Andreu with karma: 169 on 2011-12-21

This answer was NOT ACCEPTED on the original site

Post score: 3


Original comments

Comment by alfa_80 on 2011-12-23:
@Andreu: Thanks a lot!

Comment by Andreu on 2011-12-22:
Full specs of pthread API at http://users.actcom.co.il/~choo/lupg/tutorials/multi-thread/multi-thread.html

Comment by Andreu on 2011-12-22:
#include <pthread.h>

Comment by alfa_80 on 2011-12-22:
@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).

Comment by joq on 2011-12-21:
This is normally not needed, all callbacks occur in the same thread, unless you explicitly set them up multi-threaded.

$\endgroup$
0
$\begingroup$

Rosanswers logo

I believe the best way to do this is to use the boost::shared_ptr. 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 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 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


Originally posted by IvanShindev with karma: 51 on 2012-04-25

This answer was NOT ACCEPTED on the original site

Post score: 2

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.