diff --git a/design_reference/Canadian team's awesome rover diagram - THANKS CANADA!!.png b/design_reference/Canadian team's awesome rover diagram - THANKS CANADA!!.png new file mode 100644 index 0000000..3441561 Binary files /dev/null and b/design_reference/Canadian team's awesome rover diagram - THANKS CANADA!!.png differ diff --git a/ground_station/.idea/inspectionProfiles/Project_Default.xml b/ground_station/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..cb8673d --- /dev/null +++ b/ground_station/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/ground_station/.idea/inspectionProfiles/profiles_settings.xml b/ground_station/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..3b31283 --- /dev/null +++ b/ground_station/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/ground_station/.idea/workspace.xml b/ground_station/.idea/workspace.xml index 991b2b2..0f9c69f 100644 --- a/ground_station/.idea/workspace.xml +++ b/ground_station/.idea/workspace.xml @@ -20,25 +20,15 @@ - - - - - - - - - - - - - + - - - + + + + + @@ -57,7 +47,7 @@ - + @@ -69,10 +59,11 @@ - - + + - + + @@ -81,7 +72,7 @@ - + @@ -90,6 +81,18 @@ + + + + + + + + + + + + @@ -117,6 +120,7 @@ DEFINITION_ORDER + @@ -145,7 +149,6 @@ - @@ -217,6 +220,7 @@ + @@ -453,28 +457,28 @@ - + + - + + - - - - - + - + + + @@ -513,10 +517,94 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -543,13 +631,12 @@ - - + @@ -561,15 +648,12 @@ - - - - + @@ -579,26 +663,29 @@ - - + + - + - - - + + + + + + - + - - + + @@ -607,6 +694,6 @@ - AAAAsC92Kuu3oLrABnhEDJd2fqLpSLKMDnz1RoGljcqcyx6rWWvT/BV+wcLNHGnvYk97nqnk/pKm4cGIiar9MRU3nZkNwyjJxPVtt3haC8iDCZdLJZ6CmktPYqrohRIav09rau96cPFO/I//1EIneIP/1ljcNiibrP6ukAATwUH19NLQaGz1/EYXXVq+qowSGeFE7dAFp107pLkmub5CsKj/8zF+PCqHoF8AEDn937Vn/JpXGWVGlieBMxMrucAQD8JqIA== + AAAAsNHwc2N+8Zbshoe1tr2XDVkf8aGU/l0YnN7t0gOfSXYMOeQZo2dVv+GbvgrFH5EF+uviJzRPHArF3uX1Vb0CuhmnSE0NSLdGfSjyMrpWsoZyS3WBI979X8Y/8lSe/g2O65pafrceXlU4ySEbA9w/JNU42PtXijURL7sXfaZ8kxhE5bYQlRppUyBo5g/qgzvj275mbp6uuZ5w9ssFsOzrJGsGulioJmZ9L9P6O6PVj2sPT2AEw+jC8eGiiappc0lWOA== \ No newline at end of file diff --git a/ground_station/Framework/VideoSystems/RoverVideoCoordinator.py b/ground_station/Framework/VideoSystems/RoverVideoCoordinator.py index abc218d..8f3d7a3 100644 --- a/ground_station/Framework/VideoSystems/RoverVideoCoordinator.py +++ b/ground_station/Framework/VideoSystems/RoverVideoCoordinator.py @@ -13,9 +13,13 @@ import RoverVideoReceiver ##################################### # Global Variables ##################################### -CAMERA_TOPIC_PATH = "/cameras" +CAMERA_TOPIC_PATH = "/cameras/" EXCLUDED_CAMERAS = ["zed"] +PRIMARY_LABEL_MAX = (640, 360) +SECONDARY_LABEL_MAX = (256, 144) +TERTIARY_LABEL_MAX = (256, 144) + ##################################### # RoverVideoCoordinator Class Definition @@ -48,6 +52,7 @@ class RoverVideoCoordinator(QtCore.QThread): # Camera variables self.camera_threads = {} self.valid_cameras = [] + self.disabled_cameras = [] # Setup cameras self.__get_cameras() @@ -57,17 +62,57 @@ class RoverVideoCoordinator(QtCore.QThread): self.secondary_label_current_setting = 0 self.tertiary_label_current_setting = 0 + self.primary_label_max_resolution = -1 + self.secondary_label_max_resolution = -1 + self.tertiary_label_max_resolution = -1 + def run(self): self.logger.debug("Starting Video Coordinator Thread") - while self.run_thread_flag: + self.__set_max_resolutions() # Do this initially so we don't try to disable cameras before they're set up + self.msleep(500) - self.msleep(100) + while self.run_thread_flag: + self.__set_max_resolutions() + # self.__toggle_background_cameras_if_needed() + self.msleep(10) self.__wait_for_camera_threads() self.logger.debug("Stopping Video Coordinator Thread") + def __set_max_resolutions(self): + self.primary_label_max_resolution = self.camera_threads[ + self.valid_cameras[self.primary_label_current_setting]].current_max_resolution + self.secondary_label_max_resolution = self.camera_threads[ + self.valid_cameras[self.secondary_label_current_setting]].current_max_resolution + self.tertiary_label_max_resolution = self.camera_threads[ + self.valid_cameras[self.tertiary_label_current_setting]].current_max_resolution + + if self.primary_label_max_resolution != PRIMARY_LABEL_MAX: + self.camera_threads[self.valid_cameras[self.primary_label_current_setting]].change_max_resolution_setting( + PRIMARY_LABEL_MAX) + + if self.secondary_label_max_resolution != SECONDARY_LABEL_MAX and self.secondary_label_current_setting != self.primary_label_current_setting: + self.camera_threads[self.valid_cameras[self.secondary_label_current_setting]].change_max_resolution_setting( + SECONDARY_LABEL_MAX) + + if self.tertiary_label_max_resolution != TERTIARY_LABEL_MAX and self.tertiary_label_current_setting != self.primary_label_current_setting: + self.camera_threads[self.valid_cameras[self.tertiary_label_current_setting]].change_max_resolution_setting( + TERTIARY_LABEL_MAX) + + def __toggle_background_cameras_if_needed(self): + enabled = list({self.primary_label_current_setting, self.secondary_label_current_setting, + self.tertiary_label_current_setting}) + + for camera_index, camera_name in enumerate(self.valid_cameras): + if camera_index not in enabled: + self.camera_threads[camera_name].toggle_video_display() + self.disabled_cameras.append(camera_index) + elif camera_index in self.disabled_cameras: + self.camera_threads[camera_name].toggle_video_display() + self.disabled_cameras.remove(camera_index) + def __get_cameras(self): topics = rospy.get_published_topics(CAMERA_TOPIC_PATH) @@ -140,4 +185,3 @@ class RoverVideoCoordinator(QtCore.QThread): def on_kill_threads_requested__slot(self): self.run_thread_flag = False - diff --git a/ground_station/Framework/VideoSystems/RoverVideoReceiver.py b/ground_station/Framework/VideoSystems/RoverVideoReceiver.py index d2645f0..5f982ce 100644 --- a/ground_station/Framework/VideoSystems/RoverVideoReceiver.py +++ b/ground_station/Framework/VideoSystems/RoverVideoReceiver.py @@ -17,7 +17,7 @@ from sensor_msgs.msg import CompressedImage ##################################### # Global Variables ##################################### -FONT = cv2.FONT_HERSHEY_TRIPLEX +CAMERA_TOPIC_PATH = "/cameras/" ##################################### @@ -44,11 +44,23 @@ class RoverVideoReceiver(QtCore.QThread): # ########## Class Variables ########## self.camera_title_name = self.camera_name.replace("_", " ").title() - self.topic_path = "/cameras/" + self.camera_name + "/image_640x360/compressed" + self.topic_base_path = CAMERA_TOPIC_PATH + self.camera_name + self.camera_topics = {} + + self.current_max_resolution = None + + self.current_camera_settings = { + "resolution": None, + "quality_setting": 80, + + } + + self.previous_camera_settings = self.current_camera_settings.copy() + + self.temp_topic_path = CAMERA_TOPIC_PATH + self.camera_name + "/image_640x360/compressed" # Subscription variables - self.video_subscriber = rospy.Subscriber(self.topic_path, CompressedImage, - self.__image_data_received_callback) # type: rospy.Subscriber + self.video_subscriber = None # type: rospy.Subscriber # Image variables self.raw_image = None @@ -72,6 +84,7 @@ class RoverVideoReceiver(QtCore.QThread): self.camera_name_opencv_640x360_image = None self.__create_camera_name_opencv_images() + self.__get_camera_available_resolutions() def run(self): self.logger.debug("Starting \"%s\" Camera Thread" % self.camera_title_name) @@ -82,12 +95,45 @@ class RoverVideoReceiver(QtCore.QThread): else: self.__show_video_disabled() - self.msleep(18) + self.msleep(10) self.logger.debug("Stopping \"%s\" Camera Thread" % self.camera_title_name) + def __get_camera_available_resolutions(self): + topics = rospy.get_published_topics(self.topic_base_path) + + resolution_options = [] + + for topics_group in topics: + main_topic = topics_group[0] + camera_name = main_topic.split("/")[3] + resolution_options.append(camera_name) + + resolution_options = list(set(resolution_options)) + + for resolution in resolution_options: + # Creates a tuple in (width, height) format that we can use as the key + group = int(resolution.split("image_")[1].split("x")[0]), int(resolution.split("image_")[1].split("x")[1]) + self.camera_topics[group] = self.topic_base_path + "/" + resolution + "/compressed" + + def __update_camera_subscription_and_settings(self): + if self.current_camera_settings["resolution"] != self.previous_camera_settings["resolution"]: + + if self.video_subscriber: + self.video_subscriber.unregister() + new_topic = self.camera_topics[self.current_camera_settings["resolution"]] + self.video_subscriber = rospy.Subscriber(new_topic, CompressedImage, self.__image_data_received_callback) + + self.new_frame = False + while not self.new_frame: + self.msleep(10) + + self.previous_camera_settings["resolution"] = self.current_camera_settings["resolution"] + def __show_video_enabled(self): - if self.new_frame: + self.__update_camera_subscription_and_settings() + if self.new_frame and self.current_camera_settings["resolution"]: + # if self.raw_image: opencv_image = self.bridge.compressed_imgmsg_to_cv2(self.raw_image, "rgb8") self.__create_final_pixmaps(opencv_image) @@ -103,8 +149,6 @@ class RoverVideoReceiver(QtCore.QThread): self.image_ready_signal.emit(self.camera_name) def __create_final_pixmaps(self, opencv_image): - - height, width, _ = opencv_image.shape if width != 1280 and height != 720: @@ -155,14 +199,21 @@ class RoverVideoReceiver(QtCore.QThread): self.camera_name_opencv_640x360_image = \ cv2.resize(camera_name_opencv_image, (camera_name_width_buffered / 2, camera_name_height_buffered / 2)) + def change_max_resolution_setting(self, resolution_max): + self.current_max_resolution = resolution_max + self.current_camera_settings["resolution"] = resolution_max + def toggle_video_display(self): if self.video_enabled: - self.video_subscriber.unregister() + if self.video_subscriber: + self.video_subscriber.unregister() self.new_frame = True self.video_enabled = False else: - self.video_subscriber = rospy.Subscriber(self.topic_path, CompressedImage, - self.__image_data_received_callback) + new_topic = self.camera_topics[self.current_camera_settings["resolution"]] + self.video_subscriber = rospy.Subscriber(new_topic, CompressedImage, self.__image_data_received_callback) + # self.video_subscriber = rospy.Subscriber(self.temp_topic_path, CompressedImage, + # self.__image_data_received_callback) self.video_enabled = True def connect_signals_and_slots(self):