0
$\begingroup$

Rosanswers logo

Hello ROS community.

I am building a specific application where I have two subscriber callbacks as written below:

def callback1(msg):
    X = msg.X

def callback2(msg):
    desX = msg.desX
    publish(desX)
    while duration < 1 sec:
        if equal(X, desX):
            return True
    return False

The callbacks are oversimplified for easier understanding, and I also assume X is some global variable (or object attribute), so that both callbacks can access it.

callback1 is a sensor measurement coming in at 20 Hz.

callback2 is called on user request, but let's assume it can be called at more than 1 Hz.

In a single threaded mode, this will not work, since callback2 blocks callback1 and the sensor measurement is not read properly. I would like to implement this multi-threaded, but with following requirements:

  1. callback1 is blocking, i.e. two of them cannot be performed at the same time,
  2. callback2 is preemptable, i.e. if another call is made the previous one will be canceled,
  3. It should be done in C++.

My initial idea was to have a separate callback queue for callback2 and have the callback1 in the global queue in the single-threaded callback manner, like mentioned here under point 2.

I would like to know how to implement this given the additional requirement that the callback2 is preemptable. Also, any other design recommendations are more than welcome!


Originally posted by hamzamerzic on ROS Answers with karma: 111 on 2016-12-19

Post score: 0


Original comments

Comment by spmaniato on 2016-12-19:
Why not have the two callbacks simply update the global/member variables and then implement the logic in a main loop or a roscpp Timer ? You could also use a ROS Action for callback2 (instead of a plain subscriber)

Comment by hamzamerzic on 2016-12-19:
In case of using a timer, what would be a good design? Have a timer which periodically checks if equal(X, desX), and takes into consideration the timestamp to publish False on exceeding the max duration? Also, regarding placing the logic in main, are there any pr's of doing that?

Comment by spmaniato on 2016-12-19:
You can do a ros::Timer that triggers every so often and does that check or you can have a while loop running at some ros::Rate. They are similar, although the ROS wiki recommends Timers.

Comment by spmaniato on 2016-12-19:
And here some more info: http://wiki.ros.org/roscpp/Overview/Time#Sleeping_and_Rates and http://wiki.ros.org/roscpp_tutorials/Tutorials/Timers

Comment by hamzamerzic on 2016-12-20:
Thanks a lot, this solution works fine.

$\endgroup$

2 Answers 2

0
$\begingroup$

Rosanswers logo

(1) sounds like a pretty typical use for locks, or just a single callback queue.

(2) ROS doesn't natively support callback preemption. If you want it, you'll have to build it yourself. This probably means having a few locks or mutexes and inserting preemption points into your callback, where it can abort early if there's another callback waiting.

(3) Do it in C++


Originally posted by ahendrix with karma: 47576 on 2016-12-19

This answer was NOT ACCEPTED on the original site

Post score: 2


Original comments

Comment by gvdhoorn on 2016-12-19:
What about modelling this on top of Actions?

Comment by ahendrix on 2016-12-19:
Actionlib would make this easier, but even in actionlib, the server needs to have preemption points within the algorithm where it actively checks if the goal has been cancelled.

Comment by gvdhoorn on 2016-12-19:
Obviously. It would probably be good if the OP could describe his requirements in a bit more detail. I'm not sure whether we're not actually solving an xy-problem here.

Comment by hamzamerzic on 2016-12-19:
I am aware this could be implemented using actionlib, but it seems like an overkill here? Could you please elaborate more on 1? Do you mean separating callback1 and callback2 into different single callback queues? If so, how would I spin that so that they don't block each other?

Comment by ahendrix on 2016-12-19:
you think actionlib is overkill, but creating your own solution isn't? I think you have it backwards.

Comment by hamzamerzic on 2016-12-20:
IMHO if adding a Timer and two extra variables can solve it, then using actionlib is probably an overkill. But if that solution is the most maintainable one, I would definitely go for it.

Comment by gvdhoorn on 2016-12-20:
From reading your own answer, I think actionlib would have been much cleaner and a more conceptually nicer way to model this all. But if it works for you the way you have it now, I'm not going to suggest anything different.

Comment by hamzamerzic on 2016-12-20:
Thank you for the feedback! I will try implementing the solution using actionlib as well. I will post it here, since the way I imagined the solution to be did not seem that clean, so I might be missing something.

Comment by InderpreetSingh on 2020-06-03:
Hi, I am running into the same problem, can you elaborate how did you finally solve it?

$\endgroup$
0
$\begingroup$

Rosanswers logo

I decided to go with the solution of having multiple callback queues by adapting the answer found here.

callback1 is thus kept in the global ROS queue, while callback2 is run asynchronously.

To make the callback2 preemptable, I added a variable which stores the time stamp of the most recent callback, and a check for a more recent time stamp in the while loop of the callback which is used for preemption. Some care had to be taken to avoid race condition, but it was rather simple with atomic variables or mutex locks.


Originally posted by hamzamerzic with karma: 111 on 2016-12-20

This answer was ACCEPTED on the original site

Post score: 0

$\endgroup$

Your Answer

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