Hi,
I have been working on a Python class that will allow me to spawn an object in gazebo, take an image of the object, and then delete that object, for a given number of objects that I provide. I am able to spawn the objects, and have written a subscriber that is able to take images using a sensor. However, the images that are saved are not being taken in the order I am asking them to. Starting the script, I seem to be getting images out of order. For example, if I set it to spawn 5 objects without deleting for clarity, and take an image each time a new object is spawned, I could have 1 image without any objects, 3 images with 2 objects present, and the last image with 3 objects present. Sometimes I even get images with objects in positions that were set the last time I ran the script.
I thought this was because my publisher and subscriber were working at different rates, so looking at the answers on this forum I added queue_size=1
and buff_size = 2***30
, to make sure that it was taking the last image that was sent. However, the problem is still there and nothing has changed. I have also tried increasing the time delay which has not helped, and was trying to find a way to delete the subscriber queue each time so that the latest message was definitely the one being read, but I have been unable to do so. I am not sure how to solve this and was wondering if anyone had a solution to this or an idea of why this was happening? I have attached my code below. Thanks!
import numpy as np
import rospy, tf, time
from gazebo_msgs.srv import SpawnModel, DeleteModel, GetModelState
from geometry_msgs.msg import *
from take_photo import ImageNode
# ROS Image message
from sensor_msgs.msg import Image
# ROS Image message -> OpenCV2 image converter
from cv_bridge import CvBridge, CvBridgeError
# OpenCV2 for saving an image
import cv2
import os
class ImageCollection():
def __init__(self, number_spawn, model_path, time_delay=3.0):
print("Waiting for gazebo services...")
#rospy.init_node("spawn_products_in_bins")
rospy.wait_for_service("gazebo/delete_model")
rospy.wait_for_service("gazebo/spawn_sdf_model")
rospy.wait_for_service("gazebo/get_model_state")
print("Got it.")
self.delete_model = rospy.ServiceProxy("gazebo/delete_model", DeleteModel)
self.spawn_model = rospy.ServiceProxy("gazebo/spawn_sdf_model", SpawnModel)
self.model_coordinates = rospy.ServiceProxy("gazebo/get_model_state", GetModelState)
# Instantiate CvBridge
self.bridge = CvBridge()
self.image_number = 0
self.number_spawn = number_spawn
self.time_delay = time_delay
self.model_path = model_path
# Create a directory to store images
self.folder_path = "Gazebo_Images"
try:
os.mkdir(self.folder_path)
except:
print("Folder already exists, appending to that folder...")
# Initialize the node
rospy.init_node('image_listener')
# Define your image topic
self.image_topic = "/wamv/sensors/cameras/front_left_camera/image_raw"
# Set up your subscriber and define its callback
# rospy.Subscriber(image_topic, Image, self.image_callback)
# rospy.spin()
def spawn(self):
with open(self.model_path, "r") as f:
product_xml = f.read()
# Determine a random position for the buoy (function has not been shown here but is just a random generator)
bin_x, bin_y = self.generate_random_position()
self.item_name = "croc_{0}".format(self.image_number)
print("Spawning model: %s" % self.item_name)
# Want to give the object a random yaw
random_yaw = np.random.random()
orient = Quaternion(*tf.transformations.quaternion_from_euler(0,0,random_yaw*np.pi))
item_pose = Pose(Point(x=bin_x, y=bin_y, z=0), orient)
self.spawn_model(self.item_name, product_xml, "", item_pose, "world")
def start_taking_images(self):
# Start image taking node
rospy.Subscriber(self.image_topic, Image, self.image_callback, queue_size = 1, buff_size = 2**30)
rospy.spin()
def image_callback(self, msg):
# Spawn objects
self.spawn()
print("Received an image!")
try:
# Convert your ROS Image message to OpenCV2
cv2_img = self.bridge.imgmsg_to_cv2(msg, "bgr8")
except CvBridgeError as e:
print(e)
# Save your OpenCV2 image as a png
time.sleep(self.time_delay)
cv2.imwrite(self.folder_path+'/croc_{}'.format(self.image_number)+'.png', cv2_img)
print("Saved Image!")
#print("Deleting model: %s" % self.item_name)
#self.delete_model(self.item_name)
self.image_number += 1
if self.image_number == self.number_spawn:
self.shutdown()
def shutdown(self):
# shutdown the ROS node
print("Shutting down ImageNode after taking {} image(s)...".format(self.image_number))
rospy.signal_shutdown("ROS is shutting down ImageNode")
if __name__ == "__main__":
# Number of objects to spawn
number = 2
# Spawning crocodile
spawner = ImageCollection(number, "crocodile_buoy/model.sdf", time_delay=3.0)
spawner.start_taking_images()
Originally posted by jdastoor3 on ROS Answers with karma: 13 on 2021-12-10
Post score: 0
Original comments
Comment by osilva on 2021-12-10:
Hi @jdastoor3 your question is clear. Unfortunately I don’t know the answer as I’ll need time to study it more. However why not use a rosbag to save your pictures instead of trying to handle in the node?
Comment by jdastoor3 on 2021-12-10:
I was unaware that was a possibility. Would that avoid the issues I have been having? I found this script, would that be a good place to start? Sorry, I am new to ROS.
Comment by osilva on 2021-12-10:
Yes a good place and search for ‘rosbag tutorials’. It will be a lot faster
Comment by osilva on 2021-12-10:
Take a look at this thread, hope it helps: https://stackoverflow.com/questions/38700271/python-converting-image-time-series-to-ros-bag