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
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 ..
.. 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 ..
.. 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 ..
.. 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 .... 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: Thanks for your hints. I'll try and let you know!