diff --git a/lerobot/common/cameras/realsense/camera_realsense.py b/lerobot/common/cameras/realsense/camera_realsense.py index 9242b8d0..c39e3469 100644 --- a/lerobot/common/cameras/realsense/camera_realsense.py +++ b/lerobot/common/cameras/realsense/camera_realsense.py @@ -66,7 +66,7 @@ class RealSenseCamera(Camera): from lerobot.common.cameras import ColorMode # Basic usage with serial number - config = RealSenseCameraConfig(serial_number="1234567890") # Replace with actual SN + config = RealSenseCameraConfig(serial_number_or_name="1234567890") # Replace with actual SN camera = RealSenseCamera(config) camera.connect() @@ -82,7 +82,7 @@ class RealSenseCamera(Camera): # Example with depth capture and custom settings custom_config = RealSenseCameraConfig( - serial_number="1234567890", # Replace with actual SN + serial_number_or_name="1234567890", # Replace with actual SN fps=30, width=1280, height=720, @@ -99,7 +99,7 @@ class RealSenseCamera(Camera): depth_camera.disconnect() # Example using a unique camera name - name_config = RealSenseCameraConfig(name="Intel RealSense D435") # If unique + name_config = RealSenseCameraConfig(serial_number_or_name="Intel RealSense D435") # If unique name_camera = RealSenseCamera(name_config) # ... connect, read, disconnect ... ``` @@ -117,12 +117,10 @@ class RealSenseCamera(Camera): self.config = config - if config.name is not None: # NOTE(Steven): Do we want to continue supporting this? - self.serial_number = self._find_serial_number_from_name(config.name) - elif config.serial_number is not None: - self.serial_number = str(config.serial_number) + if isinstance(config.serial_number_or_name, int): + self.serial_number = str(config.serial_number_or_name) else: - raise ValueError("RealSenseCameraConfig must provide either 'serial_number' or 'name'.") + self.serial_number = self._find_serial_number_from_name(config.serial_number_or_name) self.fps = config.fps self.color_mode = config.color_mode diff --git a/lerobot/common/cameras/realsense/configuration_realsense.py b/lerobot/common/cameras/realsense/configuration_realsense.py index c3eae8f0..ed1f76e7 100644 --- a/lerobot/common/cameras/realsense/configuration_realsense.py +++ b/lerobot/common/cameras/realsense/configuration_realsense.py @@ -40,9 +40,7 @@ class RealSenseCameraConfig(CameraConfig): fps: Requested frames per second for the color stream. width: Requested frame width in pixels for the color stream. height: Requested frame height in pixels for the color stream. - name: Optional human-readable name to identify the camera. - serial_number: Optional unique serial number to identify the camera. - Either name or serial_number must be provided. + serial_number_or_name: unique serial number or human-readable name to identify the camera. color_mode: Color mode for image output (RGB or BGR). Defaults to RGB. use_depth: Whether to enable depth stream. Defaults to False. rotation: Image rotation setting (0°, 90°, 180°, or 270°). Defaults to no rotation. @@ -54,8 +52,7 @@ class RealSenseCameraConfig(CameraConfig): - Only 3-channel color output (RGB/BGR) is currently supported. """ - name: str | None = None - serial_number: int | None = None + serial_number_or_name: int | str color_mode: ColorMode = ColorMode.RGB use_depth: bool = False rotation: Cv2Rotation = Cv2Rotation.NO_ROTATION # NOTE(Steven): Check if draccus can parse to an enum @@ -75,8 +72,3 @@ class RealSenseCameraConfig(CameraConfig): raise ValueError( f"`rotation` is expected to be in {(Cv2Rotation.NO_ROTATION, Cv2Rotation.ROTATE_90, Cv2Rotation.ROTATE_180, Cv2Rotation.ROTATE_270)}, but {self.rotation} is provided." ) - - if bool(self.name) and bool(self.serial_number): - raise ValueError( - f"One of them must be set: name or serial_number, but {self.name=} and {self.serial_number=} provided." - ) diff --git a/tests/cameras/test_realsense.py b/tests/cameras/test_realsense.py index 9f198564..3ca9db97 100644 --- a/tests/cameras/test_realsense.py +++ b/tests/cameras/test_realsense.py @@ -51,13 +51,13 @@ def mock_rs_config_enable_device_bad_file(rs_config_instance, sn): def test_abc_implementation(): """Instantiation should raise an error if the class doesn't implement abstract methods/properties.""" - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) _ = RealSenseCamera(config) @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_connect(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -66,7 +66,7 @@ def test_connect(mock_enable_device): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_connect_already_connected(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -76,7 +76,7 @@ def test_connect_already_connected(mock_enable_device): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_bad_file) def test_connect_invalid_camera_path(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) with pytest.raises(ConnectionError): @@ -85,7 +85,7 @@ def test_connect_invalid_camera_path(mock_enable_device): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_invalid_width_connect(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42, width=99999, height=480, fps=30) + config = RealSenseCameraConfig(serial_number_or_name=42, width=99999, height=480, fps=30) camera = RealSenseCamera(config) with pytest.raises(ConnectionError): @@ -94,7 +94,7 @@ def test_invalid_width_connect(mock_enable_device): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_read(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30) + config = RealSenseCameraConfig(serial_number_or_name=42, width=640, height=480, fps=30) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -103,7 +103,7 @@ def test_read(mock_enable_device): def test_read_before_connect(): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) with pytest.raises(DeviceNotConnectedError): @@ -112,7 +112,7 @@ def test_read_before_connect(): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_disconnect(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -122,7 +122,7 @@ def test_disconnect(mock_enable_device): def test_disconnect_before_connect(): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) with pytest.raises(DeviceNotConnectedError): @@ -131,7 +131,7 @@ def test_disconnect_before_connect(): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_async_read(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30) + config = RealSenseCameraConfig(serial_number_or_name=42, width=640, height=480, fps=30) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -148,7 +148,7 @@ def test_async_read(mock_enable_device): @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_async_read_timeout(mock_enable_device): - config = RealSenseCameraConfig(serial_number=42, width=640, height=480, fps=30) + config = RealSenseCameraConfig(serial_number_or_name=42, width=640, height=480, fps=30) camera = RealSenseCamera(config) camera.connect(warmup=False) @@ -163,7 +163,7 @@ def test_async_read_timeout(mock_enable_device): def test_async_read_before_connect(): - config = RealSenseCameraConfig(serial_number=42) + config = RealSenseCameraConfig(serial_number_or_name=42) camera = RealSenseCamera(config) with pytest.raises(DeviceNotConnectedError): @@ -182,7 +182,7 @@ def test_async_read_before_connect(): ) @patch("pyrealsense2.config.enable_device", side_effect=mock_rs_config_enable_device_from_file) def test_rotation(mock_enable_device, rotation): - config = RealSenseCameraConfig(serial_number=42, rotation=rotation) + config = RealSenseCameraConfig(serial_number_or_name=42, rotation=rotation) camera = RealSenseCamera(config) camera.connect(warmup=False)