Robotics StackExchange | Archived questions

Delay when subscribing to usb_cam/image_raw

I'm having latency issues when using message_filters

After inspection, it was found that it was caused by the delay of the subscribed usb_cam/image_raw.

I used rostopic delay /usb_cam/image_raw to check the delay, the average delay is 0.036s, not sure if this is too long.

Wrote a test program that only subscribes to usb_cam/image_raw, queue_size=1.

class listener:
    def __init__(self):
        self.sub = rospy.Subscriber("usb_cam/image_raw", ImageMsg, self.callback, queue_size=1)

    def callback(self, Cam_img):
        print('---sub---')
        print(Cam_img.header)
        print("================")
        rospy.sleep(3.0)

def main(args):
    rospy.init_node('message_test', anonymous=True)
    ls = listener()
    try:
        rospy.spin()
    except KeyboardInterrupt:
        print("Shutting down")

if __name__ == '__main__':
    main(sys.argv)

The message header is printed every 3 seconds, but the timestamp does not have an interval of 3 seconds after execution.

Here is the output:

---sub---
seq: 47809
stamp: 
  secs: 1666068526
  nsecs: 467627916
frame_id: "c920_camera"
================
---sub---
seq: 47810
stamp: 
  secs: 1666068526
  nsecs: 503613919
frame_id: "c920_camera"
================
---sub---
seq: 47811
stamp: 
  secs: 1666068526
  nsecs: 535569917
frame_id: "c920_camera"
================
---sub---
seq: 47812
stamp: 
  secs: 1666068526
  nsecs: 567602916
frame_id: "c920_camera"
================

How can I reduce the delay?

Thanks in advance.

Asked by Gojigu on 2022-10-17 23:59:21 UTC

Comments

Answers

First, what purpose serves sleeping in your callback? Right now, each message will be put in a queue that waits for the callback to finish before starting again. What you might want to do is printing one message over 20 instead.

Asked by Vic on 2022-10-18 02:29:47 UTC

Comments

Thank you for your reply.

Because there are other tasks in the original program that require execution time, use rospy.sleep to replace the waiting time of other programs.

When using queue_size = 1, shouldn't the latest message be obtained after the callback is completed once?

I found that if the program is executed for a period of time, the step of the timestamp will sometimes be larger, but this situation is irregular

Screenshot

Asked by Gojigu on 2022-10-18 02:58:20 UTC

Because there are other tasks in the original program that require execution time

Try not overloading your callbacks. A callback should be bare-minimum contents, like getting a message and raising a flag (setting a bool to true for example) that the main program will process. A task requiring execution time greater than one millisecond does not belong in a callback.

Asked by Vic on 2022-10-19 06:21:06 UTC

Because there are other tasks in the original program that require execution time

Try not overloading your callbacks. A callback should be bare-minimum contents, like getting a message and raising a flag (setting a bool to true for example) that the main program will process. A task requiring execution time greater than one millisecond does not belong in a callback.

Asked by Vic on 2022-10-19 06:21:15 UTC

A task requiring execution time greater than one millisecond does not belong in a callback.

that's a rather strong statement which I believe is not necessarily universally true.

There are plenty of (good) nodes doing much more work than what you state would be acceptable in callbacks.

Asked by gvdhoorn on 2022-10-19 06:29:12 UTC

Strong statement indeed. Let me reformulate.

A callback's execution time should be less than your node's rate.

Asked by Vic on 2022-10-19 06:43:40 UTC

@Vic is right in that - if you care about performance - then your code needs to spend as little time as possible inside a subscribe callback. As written, your code is locking up the entire ros subsystem for this node - no publishing, no handling of incoming messages, no timers firing for the entire 3 seconds.

The reason your timestamps have unexpected values is that there is message queuing outside of ros. The operating system is buffering incoming messages that are arriving from other ros node(s) - ros begins to handle them when you finally return from the subscribe callback.

Asked by Mike Scheutzow on 2022-10-19 18:51:59 UTC

@Mike Scheutzow: IIRC rospy uses a more multi-threading approach to handling events (so subscription callbacks). I'm not sure a sleep(..) in one callback blocks event processing completely. It's quite nuanced. See #q9543 fi.

Asked by gvdhoorn on 2022-10-20 09:41:30 UTC

@gvdhoorn Thanks for that link. I have just tested multiple publishers to the same topic, and what you say is correct. This is disturbing to me, because 99% of the subscriber callback code that I've reviewed is not thread-safe. The only reason things don't blow up more is because typically a ros topic has only 1 publisher.

Asked by Mike Scheutzow on 2022-10-23 09:29:42 UTC

You can reduce the time if you use au faster PC with less load. Try some real-time kernel settings.

Because your constrains are real-time, but USB is not real-time. There are many software layers. Pictures are a big structure. With small payload and software generated data it is easier to get more consistent data. With the c920 you get maybe compressd images which hast first be converted to raw images, an other processing step.

for topic analysis you may use

rostopic hz  usb_cam/image_raw

as here described to get the analytics.

Otherwise you use python with real-time demands, you have to use c++ for better results

Asked by duck-development on 2022-10-18 16:56:57 UTC

Comments

I think his limits come more from heavy callback than python/C++ raw performances

Asked by Vic on 2022-10-19 06:22:10 UTC

Thank you all for your explanations and suggestions.

I learned that there shouldn't be too many instructions in the callback that take time to process. Since I am not that familiar with ROS and Python, it may take some time to modify the program.

For I only need to receive an image message once, I will temporarily use rospy.wait_for_message to avoid using image subscribe.

Asked by Gojigu on 2022-10-19 20:36:37 UTC

Comments