Ask Your Question
0

How to be 100% sure that only one callback is being executed at a time?

asked 2018-04-05 04:27:50 -0500

schizzz8 gravatar image

updated 2018-06-22 04:05:00 -0500

Hi all,

I'll try to better explain my problem. I'm writing a node that subscribes to rgb and depth image topics. Since the frame rate of the rgb-d camera is 30Hz, I guess my callback is executed 30 times per second. Now, my problem is that I have to perform heavy computations and the code in the callback is executed in ~0.2s (i.e. 5Hz).

Is there a way to execute the callback not for every frame published by the camera but just at certain time intervals? That is, how can I skip some frames while the callback is still running?

Thanks.

edit retag flag offensive close merge delete

Comments

The callback will only be executed at 30Hz if that is possible. If processing takes too long, the queue_size setting will determine what happens with messages that arrive in the meantime.

I'm slightly confused by your question text though: it doesn't seem to correspond to the title. With ..

gvdhoorn gravatar image gvdhoorn  ( 2018-06-23 04:22:40 -0500 )edit

.. a regular ros::spin(), all callbacks are processed sequentially, as it employs a single-threaded processing model. So that would answer the question in the title.

The question in your text is different though: there you ask how to 'overlay' a synchronous, periodic sampling style on ..

gvdhoorn gravatar image gvdhoorn  ( 2018-06-23 04:24:08 -0500 )edit

.. an asynchronous, event-based dataflow system like pub-sub in ROS.

That is possible, but less than ideal (due to undersampling, risk of lost events, etc). Setting the queue size for your subscriber to something appropriate already subsamples the event stream, but the exact rate at which that ..

gvdhoorn gravatar image gvdhoorn  ( 2018-06-23 04:26:20 -0500 )edit

.. happens will depend on how long processing in the callback actually takes, how the process that hosts your node is scheduled, etc.

A more deterministic approach could be to use the Cache, from the message_filters pkg. That will store ..

gvdhoorn gravatar image gvdhoorn  ( 2018-06-23 04:27:21 -0500 )edit

.. incoming msgs for you in a circular buffer, from which you can retrieve messages based on their timestamp.

If you need determinism (or as much as you can expect from a non-real-time pub-sub middleware), I'd take a look at Cache and try to avoid implementing schemes with flags.

gvdhoorn gravatar image gvdhoorn  ( 2018-06-23 04:29:44 -0500 )edit

@gvdhoorn: Thanks for your hints. I'll try and let you know!

schizzz8 gravatar image schizzz8  ( 2018-06-25 03:33:11 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
2

answered 2018-06-22 19:12:21 -0500

updated 2018-06-22 20:16:41 -0500

Hi @schizzz8,

I have created a simple publisher at 30hz and a subscriber that simulates a process that takes 0.2 seconds (works at 5hz).

This script demonstrates that you can receive an image and do not have its value updated while you are processing it.

I'm using two variables to control the flow: new_msg and processing. I think it can help you.

It is written in python, but you can use the same logic (basically because it does not rely on ROS Python topic queue, which could be or not different of ROScpp).

Publisher (Simulating your camera publisher)

#!/usr/bin/env python

import rospy
from std_msgs.msg import Int32

def publisher():

    pub = rospy.Publisher('topic_name', Int32, queue_size=10)
    rospy.init_node('publisher')
    r = rospy.Rate(30) # 30hz

    count = 1
    msg = Int32()
    while not rospy.is_shutdown():
        msg.data = count
        count = count + 1 if count < 30 else 1
        pub.publish(msg)
        rospy.loginfo(msg)
        r.sleep()

if __name__ == "__main__":
    publisher()

Subscriber (Simulating your script that processes a given image)

#!/usr/bin/env python

import rospy
from std_msgs.msg import Int32

processing = False
new_msg = False

msg = None
def callback(data):
    global processing, new_msg, msg
    if not processing:
        new_msg = True
        msg = data

def listener():
    global processing, new_msg, msg
    rospy.init_node('subscriber')
    rospy.Subscriber("topic_name", Int32, callback)
    # just to use the sleep method
    r = rospy.Rate(5)
    while not rospy.is_shutdown():
        if new_msg:
            # set processing to True
            new_msg = False
            processing = True
            # simulate a process that takes 0.2 seconds
            rospy.loginfo(msg)
            r.sleep()
            # uncomment below to see the same value being "processed"
            # rospy.loginfo(msg)
            # r.sleep()
            # set processing to False
            processing = False

if __name__ == "__main__":
    listener()

I hope it can help you. You can see it being executed at this video (https://youtu.be/XoirEyK4J2A)

Cheers

edit flag offensive delete link more

Comments

What exactly is this supposed to demonstrate? Can you please update your answer with some explanation?

jayess gravatar image jayess  ( 2018-06-22 20:06:24 -0500 )edit
1

Hi, I'm demonstrating that it's possible to have the same value being processed, not updating it even after a callback call, in a process that can take longer than the callback rate I have updated with this explanation. Thanks

marcoarruda gravatar image marcoarruda  ( 2018-06-22 20:17:37 -0500 )edit
0

answered 2018-04-05 04:40:15 -0500

Chaos gravatar image

updated 2018-04-05 04:42:16 -0500

Hi! Try something like this:

...
ros::Rate rate(<yourFrequency>);
...
while (ros::ok())
{
ros::spinOnce();
rate.sleep();
}

Also, be sure to set the right buffer length for your subscriber, in order to prevent your node to elaborate old data.

edit flag offensive delete link more

Comments

It's the first thing I checked, but I don't think that solves my problem, because spinOnce will call all the pending callbacks (without skipping any) http://wiki.ros.org/roscpp/Overview/C...

schizzz8 gravatar image schizzz8  ( 2018-04-05 04:42:13 -0500 )edit

Also, be sure to set the right buffer length for your subscriber, in order to prevent your node to elaborate old data: do you mean that if I set the buffer length equal to one, I will skip old frames?

schizzz8 gravatar image schizzz8  ( 2018-04-05 04:45:08 -0500 )edit

Yes! The buffer works like a FIFO queue. If you set it to "1" the callback will elaborate only the newest incoming data.

Chaos gravatar image Chaos  ( 2018-04-05 04:46:49 -0500 )edit

I'll try, thanks!

schizzz8 gravatar image schizzz8  ( 2018-04-05 05:07:56 -0500 )edit

If it works, remember to set the post as solved

Chaos gravatar image Chaos  ( 2018-04-05 05:08:43 -0500 )edit

I just have one last question, I'm using message_filters to get synchronized rgb and depth frame, where do I set the buffer length?

schizzz8 gravatar image schizzz8  ( 2018-04-05 05:09:33 -0500 )edit

With the message_filters synchronization policy, only the newest incoming data are elaborated by the callback.

Chaos gravatar image Chaos  ( 2018-04-05 05:12:43 -0500 )edit

found it, no worries!

schizzz8 gravatar image schizzz8  ( 2018-04-05 05:15:53 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2018-04-05 04:27:50 -0500

Seen: 1,585 times

Last updated: Jun 22 '18