|
14 | 14 | from python_qt_binding.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QPushButton, QComboBox, QHBoxLayout, QCheckBox, QMessageBox |
15 | 15 | from python_qt_binding.QtGui import QImage, QPixmap |
16 | 16 | from python_qt_binding.QtCore import Qt, QTimer, pyqtSignal, QObject |
17 | | -from std_msgs.msg import Float32MultiArray, String |
| 17 | +from std_msgs.msg import Float32MultiArray, String, Bool, Int32 |
18 | 18 | from sensor_msgs.msg import Image |
19 | 19 | from geometry_msgs.msg import Point |
20 | 20 | from cv_bridge import CvBridge |
@@ -108,7 +108,7 @@ def __init__(self, node=None): |
108 | 108 | self.face_pub = node.create_publisher(String, 'face_detection_data', 10) |
109 | 109 | self.face_position_pub = node.create_publisher(Point, '/vision/face_position', 10) |
110 | 110 | self.face_position_pub_v2 = node.create_publisher(String, '/vision/face_position_v2', 10) |
111 | | - self.frame_pub = node.create_publisher(Image, 'camera_frame', 10) |
| 111 | + self.frame_pub = node.create_publisher(Image, '/coffee_bot/camera/image_raw', 10) |
112 | 112 | self.face_image_pub = node.create_publisher(Image, 'face_images', 10) |
113 | 113 | self.bridge = CvBridge() |
114 | 114 |
|
@@ -1157,6 +1157,9 @@ def __init__(self, executor): |
1157 | 1157 | self.ui = CameraViewer(self) |
1158 | 1158 | self.ui.show() |
1159 | 1159 |
|
| 1160 | + # Set up ROS control interface for separated UI communication |
| 1161 | + self._setup_ros_control_interface() |
| 1162 | + |
1160 | 1163 | # Start a background thread for ROS spinning |
1161 | 1164 | self.spinning = True |
1162 | 1165 | self.ros_thread = threading.Thread(target=self.spin_thread) |
@@ -1185,6 +1188,135 @@ def __init__(self, executor): |
1185 | 1188 | self.spinning = False |
1186 | 1189 | self.destroy_node() |
1187 | 1190 |
|
| 1191 | + def _setup_ros_control_interface(self): |
| 1192 | + """Set up ROS subscribers and publishers for separated UI control""" |
| 1193 | + self.get_logger().info('Setting up ROS control interface for separated UI communication') |
| 1194 | + |
| 1195 | + # Publishers for status updates to separated UI |
| 1196 | + self.camera_status_pub = self.create_publisher(String, '/coffee_bot/camera/status/info', 10) |
| 1197 | + self.available_cameras_pub = self.create_publisher(String, '/coffee_bot/camera/status/available', 10) |
| 1198 | + self.diagnostics_pub = self.create_publisher(String, '/coffee_bot/camera/status/diagnostics', 10) |
| 1199 | + |
| 1200 | + # Subscribers for commands from separated UI |
| 1201 | + self.camera_select_sub = self.create_subscription( |
| 1202 | + Int32, '/coffee_bot/camera/cmd/select', self._on_camera_select_command, 10) |
| 1203 | + self.quality_control_sub = self.create_subscription( |
| 1204 | + Bool, '/coffee_bot/camera/cmd/quality', self._on_quality_change_command, 10) |
| 1205 | + self.face_detection_sub = self.create_subscription( |
| 1206 | + Bool, '/coffee_bot/camera/cmd/face_detection', self._on_face_detection_command, 10) |
| 1207 | + self.camera_refresh_sub = self.create_subscription( |
| 1208 | + String, '/coffee_bot/camera/cmd/refresh', self._on_camera_refresh_command, 10) |
| 1209 | + |
| 1210 | + # Subscriber for state queries from separated UI |
| 1211 | + self.state_query_sub = self.create_subscription( |
| 1212 | + String, '/coffee_bot/camera/query/state', self._on_state_query, 10) |
| 1213 | + |
| 1214 | + self.get_logger().info('ROS control interface setup complete') |
| 1215 | + |
| 1216 | + def _on_camera_select_command(self, msg): |
| 1217 | + """Handle camera selection command from separated UI""" |
| 1218 | + camera_index = msg.data |
| 1219 | + self.get_logger().info(f'Received camera selection command: {camera_index}') |
| 1220 | + |
| 1221 | + # Forward command to the integrated UI if it exists |
| 1222 | + if hasattr(self, 'ui') and hasattr(self.ui, 'change_camera'): |
| 1223 | + # Find the combo box index for this camera index |
| 1224 | + for i in range(self.ui.camera_combo.count()): |
| 1225 | + if self.ui.camera_combo.itemData(i) == camera_index: |
| 1226 | + self.ui.camera_combo.setCurrentIndex(i) |
| 1227 | + break |
| 1228 | + |
| 1229 | + # Publish status update |
| 1230 | + status_msg = String() |
| 1231 | + status_msg.data = f"Camera selection changed to index {camera_index}" |
| 1232 | + self.camera_status_pub.publish(status_msg) |
| 1233 | + |
| 1234 | + def _on_quality_change_command(self, msg): |
| 1235 | + """Handle quality change command from separated UI""" |
| 1236 | + high_quality = msg.data |
| 1237 | + self.get_logger().info(f'Received quality change command: {"high" if high_quality else "standard"}') |
| 1238 | + |
| 1239 | + # Forward command to the integrated UI if it exists |
| 1240 | + if hasattr(self, 'ui') and hasattr(self.ui, 'quality_checkbox'): |
| 1241 | + self.ui.quality_checkbox.setChecked(high_quality) |
| 1242 | + |
| 1243 | + # Publish status update |
| 1244 | + status_msg = String() |
| 1245 | + status_msg.data = f"Quality changed to {'high (1080p)' if high_quality else 'standard (480p)'}" |
| 1246 | + self.camera_status_pub.publish(status_msg) |
| 1247 | + |
| 1248 | + def _on_face_detection_command(self, msg): |
| 1249 | + """Handle face detection toggle command from separated UI""" |
| 1250 | + enabled = msg.data |
| 1251 | + self.get_logger().info(f'Received face detection command: {"enabled" if enabled else "disabled"}') |
| 1252 | + |
| 1253 | + # Forward command to the integrated UI if it exists |
| 1254 | + if hasattr(self, 'ui') and hasattr(self.ui, 'face_detection_checkbox'): |
| 1255 | + self.ui.face_detection_checkbox.setChecked(enabled) |
| 1256 | + |
| 1257 | + # Publish status update |
| 1258 | + status_msg = String() |
| 1259 | + status_msg.data = f"Face detection {'enabled' if enabled else 'disabled'}" |
| 1260 | + self.camera_status_pub.publish(status_msg) |
| 1261 | + |
| 1262 | + def _on_camera_refresh_command(self, msg): |
| 1263 | + """Handle camera refresh command from separated UI""" |
| 1264 | + self.get_logger().info('Received camera refresh command') |
| 1265 | + |
| 1266 | + # Forward command to the integrated UI if it exists |
| 1267 | + if hasattr(self, 'ui') and hasattr(self.ui, 'scan_cameras'): |
| 1268 | + self.ui.scan_cameras() |
| 1269 | + |
| 1270 | + # Publish status update |
| 1271 | + status_msg = String() |
| 1272 | + status_msg.data = "Camera scan completed" |
| 1273 | + self.camera_status_pub.publish(status_msg) |
| 1274 | + |
| 1275 | + def _on_state_query(self, msg): |
| 1276 | + """Handle state query from separated UI and respond with current camera state""" |
| 1277 | + self.get_logger().info('Received state query from separated UI') |
| 1278 | + |
| 1279 | + # Gather current state from integrated UI |
| 1280 | + current_state = {} |
| 1281 | + |
| 1282 | + if hasattr(self, 'ui'): |
| 1283 | + # Get current camera index |
| 1284 | + current_camera_index = -1 |
| 1285 | + if hasattr(self.ui, 'camera_combo') and self.ui.camera_combo.count() > 0: |
| 1286 | + current_camera_index = self.ui.camera_combo.itemData(self.ui.camera_combo.currentIndex()) |
| 1287 | + current_state['camera_index'] = current_camera_index |
| 1288 | + |
| 1289 | + # Get quality setting |
| 1290 | + high_quality = False |
| 1291 | + if hasattr(self.ui, 'quality_checkbox'): |
| 1292 | + high_quality = self.ui.quality_checkbox.isChecked() |
| 1293 | + current_state['high_quality'] = high_quality |
| 1294 | + |
| 1295 | + # Get face detection setting |
| 1296 | + face_detection = True |
| 1297 | + if hasattr(self.ui, 'face_detection_checkbox'): |
| 1298 | + face_detection = self.ui.face_detection_checkbox.isChecked() |
| 1299 | + current_state['face_detection_enabled'] = face_detection |
| 1300 | + |
| 1301 | + # Get available cameras |
| 1302 | + available_cameras = [] |
| 1303 | + if hasattr(self.ui, 'available_cameras'): |
| 1304 | + available_cameras = [ |
| 1305 | + {"index": idx, "name": name} |
| 1306 | + for idx, name in self.ui.available_cameras |
| 1307 | + ] |
| 1308 | + current_state['available_cameras'] = available_cameras |
| 1309 | + |
| 1310 | + # Publish current state as JSON |
| 1311 | + import json |
| 1312 | + state_msg = String() |
| 1313 | + state_msg.data = json.dumps(current_state) |
| 1314 | + self.available_cameras_pub.publish(state_msg) # Reuse existing publisher |
| 1315 | + |
| 1316 | + self.get_logger().info(f'Published current state: camera_index={current_state.get("camera_index", -1)}, ' |
| 1317 | + f'high_quality={current_state.get("high_quality", False)}, ' |
| 1318 | + f'face_detection={current_state.get("face_detection_enabled", True)}') |
| 1319 | + |
1188 | 1320 | def spin_thread(self): |
1189 | 1321 | """Background thread for ROS spinning""" |
1190 | 1322 | while self.spinning: |
|
0 commit comments