0
$\begingroup$

Rosanswers logo

I'm trying to debug a very rare instance (that happens randomly) in my node when I will be waiting for a specific message and it never gets received. I've created a very rough code example to help illustrate how things are happening. My actual code has a lot more subscribers and classes, but this should get the point across.

Key Points

+ `spinOnce()` is being called inside a `createTimer()` callback + Messages are not being added to subscribers queue. (verified) + Messages are being published by publisher. (verified) + After the `TimerCallback()` function completes, messages will get received again.

Publisher Node:

int main(int argc, char** argv)
{
  ros::init(argc, argv, "Publisher");
  ros::NodeHandle node;
  ros::Rate r(1);
  publisher = node->advertise<Message_type>(topic_string, 1, true);
  int count = 0;
  while (ros::ok())
  {
    count++;
    publisher.publish(Message_type(count));
    r.sleep();
  }
}

Subscriber Node:

bool message_received_ = false; void ImportantCallback(const Message_type& msg) { ROS_INFO_STREAM("count: " subscribe(topic_string, 1, ImportantCallback, this); InitializeSubscribers(node); plan_timer_ = node->createTimer (ros::Duration(0.01), &TimerCallback, this); while (ros::ok()) { ros::spinOnce(); r.sleep(); } }

Any ideas are greatly appreciated.


Originally posted by cpagravel on ROS Answers with karma: 156 on 2017-04-20

Post score: 1

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

Recursively calling spinOnce() can be dangerous. You might end up calling your TimerCallback() recursively, particularly with the timer's duration being so short.

As an alternative to recursively calling spinOnce(), you could try using a separate callback queue for the timer. See here for how this works:

http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning#Advanced:_Using_Different_Callback_Queues

If you want to ignore all data received on other topics until a particular message is received, there might be better ways to do it. For example removing subscribers (sub.shutdown()) and re-creating them when ready to handle data again - although this is costly in destroying and setting up connections. Another would be a flag that tells other subscriber callbacks to ignore all received data until that particular message is received.


Originally posted by Geoff with karma: 4203 on 2017-04-20

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by cpagravel on 2017-04-21:
I had performed some experiments and found out that the timer callbacks are specially handled. I.e. once you're in a timer callback function, a call to spinOnce() will not trigger another time callback until your timer callback function has completed.

Comment by cpagravel on 2017-04-21:
It seems the problem might have been fixed by avoiding the use of the timer callbacks, but I don't understand why. I also did some experiments to test the limit on recursively calling spinOnce() inside my callbacks (with the use of infinite loops). It seemed that, aside from the timer callback...

Comment by cpagravel on 2017-04-21:
spinOnce() functioned as normal.

Comment by Geoff on 2017-04-23:
Yeah, I made a mistake when I was reading the code and docs. It turns out that the CallbackQueue class is actually designed to handle things like callbacks calling the queue again. See #9 in http://wiki.ros.org/roscpp/Internals . So the first part of my answer is wrong, I think.

$\endgroup$

Your Answer

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