Skip to content

Commit fd31035

Browse files
committed
Update camera_ui_node to first check state before attempting to modify camera_node
1 parent 19d3499 commit fd31035

File tree

3 files changed

+83
-10
lines changed

3 files changed

+83
-10
lines changed

coffee_ws/src/coffee_vision_ui/coffee_vision_ui/camera_ui_node.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from rclpy.node import Node
2929
from python_qt_binding.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QVBoxLayout, QWidget
3030
from python_qt_binding.QtCore import QTimer
31+
from std_msgs.msg import String
3132

3233
# Import our modular components
3334
from .ros_interface import CameraController, FrameReceiver
@@ -72,12 +73,15 @@ def __init__(self, node):
7273

7374
# Initialize ROS communication components
7475
self.camera_controller = CameraController(node)
75-
self.frame_receiver = FrameReceiver(node, 'camera_frame')
76+
self.frame_receiver = FrameReceiver(node, '/coffee_bot/camera/image_raw')
7677

7778
# Initialize UI components
7879
self.camera_display = CameraDisplay()
7980
self.control_panel = ControlPanel()
8081

82+
# Set up state query publisher
83+
self.state_query_pub = node.create_publisher(String, '/coffee_bot/camera/query/state', 10)
84+
8185
# Set up connection timeout monitoring
8286
self.connection_timer = QTimer()
8387
self.connection_timer.timeout.connect(self._check_connection)
@@ -86,8 +90,8 @@ def __init__(self, node):
8690
self.init_ui()
8791
self.setup_connections()
8892

89-
# Request initial camera scan after a short delay
90-
QTimer.singleShot(1000, self.control_panel.refresh_cameras_requested.emit)
93+
# Query camera_node state instead of sending commands
94+
QTimer.singleShot(1000, self._query_camera_node_state)
9195

9296
def init_ui(self):
9397
"""Initialize the user interface layout and components."""
@@ -120,6 +124,7 @@ def setup_connections(self):
120124
self.camera_controller.cameras_updated.connect(self.control_panel.update_camera_list)
121125
self.camera_controller.camera_status_updated.connect(self.control_panel.update_status)
122126
self.camera_controller.diagnostics_ready.connect(self.control_panel.show_diagnostics)
127+
self.camera_controller.state_received.connect(self.control_panel.sync_to_camera_state)
123128

124129
# Control panel to camera controller connections
125130
self.control_panel.camera_selected.connect(self.camera_controller.select_camera)
@@ -130,6 +135,24 @@ def setup_connections(self):
130135

131136
self.node.get_logger().info('Signal connections established between all components')
132137

138+
def _query_camera_node_state(self):
139+
"""Query camera_node for its current state instead of sending commands"""
140+
self.node.get_logger().info('Querying camera_node for current state')
141+
142+
# Send state query
143+
query_msg = String()
144+
query_msg.data = "get_state"
145+
self.state_query_pub.publish(query_msg)
146+
147+
# Set up one-time listener for state response
148+
QTimer.singleShot(2000, self._setup_state_listener)
149+
150+
def _setup_state_listener(self):
151+
"""Set up listener for state response from camera_node"""
152+
# The state response comes through the same topic as camera list updates
153+
# We'll handle it in the existing camera_controller callback
154+
self.node.get_logger().info('Listening for camera_node state response')
155+
133156
def _check_connection(self):
134157
"""Periodically check frame receiver connection status."""
135158
self.frame_receiver.check_connection_timeout()

coffee_ws/src/coffee_vision_ui/coffee_vision_ui/ros_interface/camera_controller.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class CameraController(QObject):
3737
cameras_updated = pyqtSignal(list) # Available cameras: [(index, name), ...]
3838
camera_status_updated = pyqtSignal(str) # Current camera status
3939
diagnostics_ready = pyqtSignal(str) # Diagnostic information
40+
state_received = pyqtSignal(dict) # Full camera state for synchronization
4041

4142
def __init__(self, node):
4243
"""
@@ -156,19 +157,27 @@ def _camera_status_callback(self, msg):
156157

157158
def _available_cameras_callback(self, msg):
158159
"""
159-
Handle available cameras list from camera_node.
160+
Handle available cameras list or state response from camera_node.
160161
161162
Args:
162-
msg: String message containing JSON list of cameras
163+
msg: String message containing JSON list of cameras or full state
163164
"""
164165
try:
165-
cameras_data = json.loads(msg.data)
166-
# Expected format: [{"index": 0, "name": "Camera 0"}, ...]
167-
cameras_list = [(cam["index"], cam["name"]) for cam in cameras_data]
168-
self.cameras_updated.emit(cameras_list)
166+
data = json.loads(msg.data)
167+
168+
# Check if this is a full state response (has camera_index, high_quality, etc.)
169+
if isinstance(data, dict) and 'camera_index' in data:
170+
# This is a state response - emit for state sync
171+
self.node.get_logger().info("Received camera_node state for synchronization")
172+
self.state_received.emit(data)
173+
else:
174+
# This is a regular camera list
175+
# Expected format: [{"index": 0, "name": "Camera 0"}, ...]
176+
cameras_list = [(cam["index"], cam["name"]) for cam in data]
177+
self.cameras_updated.emit(cameras_list)
169178
except json.JSONDecodeError as e:
170179
self.node.get_logger().error(f"Error parsing cameras data: {e}")
171-
except KeyError as e:
180+
except (KeyError, TypeError) as e:
172181
self.node.get_logger().error(f"Invalid camera data format: {e}")
173182

174183
def _diagnostics_callback(self, msg):

coffee_ws/src/coffee_vision_ui/coffee_vision_ui/widgets/control_panel.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,5 +296,46 @@ def set_settings(self, settings):
296296
self.camera_combo.setCurrentIndex(i)
297297
self.current_camera_index = camera_index
298298
break
299+
finally:
300+
self._updating_controls = False
301+
302+
def sync_to_camera_state(self, state_data):
303+
"""
304+
Sync control panel to camera_node state without triggering commands.
305+
306+
Args:
307+
state_data: Dictionary with current camera state
308+
"""
309+
self._updating_controls = True
310+
try:
311+
# Sync camera selection
312+
if 'camera_index' in state_data and 'available_cameras' in state_data:
313+
self.available_cameras = [
314+
(cam["index"], cam["name"])
315+
for cam in state_data['available_cameras']
316+
]
317+
self.camera_combo.clear()
318+
319+
current_camera_index = state_data['camera_index']
320+
for i, (idx, name) in enumerate(self.available_cameras):
321+
self.camera_combo.addItem(name, idx)
322+
if idx == current_camera_index:
323+
self.camera_combo.setCurrentIndex(i)
324+
self.current_camera_index = current_camera_index
325+
326+
# Sync quality setting
327+
if 'high_quality' in state_data:
328+
self.high_quality = state_data['high_quality']
329+
self.quality_checkbox.setChecked(self.high_quality)
330+
331+
# Sync face detection setting
332+
if 'face_detection_enabled' in state_data:
333+
self.face_detection_enabled = state_data['face_detection_enabled']
334+
self.face_detection_checkbox.setChecked(self.face_detection_enabled)
335+
336+
# Update status
337+
camera_count = len(self.available_cameras)
338+
self.update_status(f"Synced with camera_node - {camera_count} camera(s) available")
339+
299340
finally:
300341
self._updating_controls = False

0 commit comments

Comments
 (0)