mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-25 02:36:11 +00:00
feat(camera): add manual exposure, gain, and white balance options for RealSense cameras
The RealSense camera integration lacked sensor-level controls, causing issues like unstable lighting from auto-exposure hunting. This adds optional `exposure`, `gain`, and `white_balance` fields to RealSenseCameraConfig that disable the corresponding auto modes and apply fixed values when set.
This commit is contained in:
@@ -191,6 +191,7 @@ class RealSenseCamera(Camera):
|
|||||||
) from e
|
) from e
|
||||||
|
|
||||||
self._configure_capture_settings()
|
self._configure_capture_settings()
|
||||||
|
self._configure_sensor_options()
|
||||||
self._start_read_thread()
|
self._start_read_thread()
|
||||||
|
|
||||||
# NOTE(Steven/Caroline): Enforcing at least one second of warmup as RS cameras need a bit of time before the first read. If we don't wait, the first read from the warmup will raise.
|
# NOTE(Steven/Caroline): Enforcing at least one second of warmup as RS cameras need a bit of time before the first read. If we don't wait, the first read from the warmup will raise.
|
||||||
@@ -339,6 +340,59 @@ class RealSenseCamera(Camera):
|
|||||||
self.new_frame_event.clear()
|
self.new_frame_event.clear()
|
||||||
return self._async_read(timeout_ms=10000, read_depth=read_depth)
|
return self._async_read(timeout_ms=10000, read_depth=read_depth)
|
||||||
|
|
||||||
|
def _get_color_sensor(self) -> "rs.sensor":
|
||||||
|
"""Returns the color sensor from the active pipeline profile."""
|
||||||
|
if self.rs_profile is None:
|
||||||
|
raise RuntimeError(f"{self}: rs_profile must be initialized before use.")
|
||||||
|
|
||||||
|
device = self.rs_profile.get_device()
|
||||||
|
for sensor in device.query_sensors():
|
||||||
|
if sensor.get_info(rs.camera_info.name) == "RGB Camera":
|
||||||
|
return sensor
|
||||||
|
raise RuntimeError(f"{self}: no RGB Camera sensor found on device.")
|
||||||
|
|
||||||
|
def _configure_sensor_options(self) -> None:
|
||||||
|
"""Applies manual sensor options (exposure, gain, white balance) to the color sensor.
|
||||||
|
|
||||||
|
When exposure or gain is set, auto-exposure is disabled first. When white_balance
|
||||||
|
is set, auto white balance is disabled first. Skipped entirely if no options are set.
|
||||||
|
"""
|
||||||
|
config = self.config
|
||||||
|
if config.exposure is None and config.gain is None and config.white_balance is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
color_sensor = self._get_color_sensor()
|
||||||
|
|
||||||
|
if (config.exposure is not None or config.gain is not None) and color_sensor.supports(
|
||||||
|
rs.option.enable_auto_exposure
|
||||||
|
):
|
||||||
|
color_sensor.set_option(rs.option.enable_auto_exposure, 0)
|
||||||
|
logger.info(f"{self} auto-exposure disabled.")
|
||||||
|
|
||||||
|
if config.exposure is not None:
|
||||||
|
if color_sensor.supports(rs.option.exposure):
|
||||||
|
color_sensor.set_option(rs.option.exposure, config.exposure)
|
||||||
|
logger.info(f"{self} exposure set to {config.exposure}.")
|
||||||
|
else:
|
||||||
|
logger.warning(f"{self} sensor does not support manual exposure.")
|
||||||
|
|
||||||
|
if config.gain is not None:
|
||||||
|
if color_sensor.supports(rs.option.gain):
|
||||||
|
color_sensor.set_option(rs.option.gain, config.gain)
|
||||||
|
logger.info(f"{self} gain set to {config.gain}.")
|
||||||
|
else:
|
||||||
|
logger.warning(f"{self} sensor does not support manual gain.")
|
||||||
|
|
||||||
|
if config.white_balance is not None:
|
||||||
|
if color_sensor.supports(rs.option.enable_auto_white_balance):
|
||||||
|
color_sensor.set_option(rs.option.enable_auto_white_balance, 0)
|
||||||
|
logger.info(f"{self} auto white balance disabled.")
|
||||||
|
if color_sensor.supports(rs.option.white_balance):
|
||||||
|
color_sensor.set_option(rs.option.white_balance, config.white_balance)
|
||||||
|
logger.info(f"{self} white balance set to {config.white_balance}.")
|
||||||
|
else:
|
||||||
|
logger.warning(f"{self} sensor does not support manual white balance.")
|
||||||
|
|
||||||
@check_if_not_connected
|
@check_if_not_connected
|
||||||
def read_depth(self, timeout_ms: int = 200) -> NDArray[Any]:
|
def read_depth(self, timeout_ms: int = 200) -> NDArray[Any]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ class RealSenseCameraConfig(CameraConfig):
|
|||||||
use_depth: Whether to enable depth stream. Defaults to False.
|
use_depth: Whether to enable depth stream. Defaults to False.
|
||||||
rotation: Image rotation setting (0°, 90°, 180°, or 270°). Defaults to no rotation.
|
rotation: Image rotation setting (0°, 90°, 180°, or 270°). Defaults to no rotation.
|
||||||
warmup_s: Time reading frames before returning from connect (in seconds)
|
warmup_s: Time reading frames before returning from connect (in seconds)
|
||||||
|
exposure: Manual exposure value for the color sensor. When set, auto-exposure is
|
||||||
|
disabled and this fixed value is used. Valid range depends on the camera model
|
||||||
|
(e.g., 1-10000 for D400 series). Defaults to None (auto-exposure).
|
||||||
|
gain: Manual gain value for the color sensor. When set, auto-exposure is disabled
|
||||||
|
and this fixed gain is used. Valid range depends on the camera model
|
||||||
|
(e.g., 16-248 for D400 series). Defaults to None (auto).
|
||||||
|
white_balance: Manual white balance value for the color sensor. When set, auto
|
||||||
|
white balance is disabled and this fixed value is used. Valid range depends on
|
||||||
|
the camera model (e.g., 2800-6500 for D400 series). Defaults to None (auto).
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
- Either name or serial_number must be specified.
|
- Either name or serial_number must be specified.
|
||||||
@@ -61,6 +70,9 @@ class RealSenseCameraConfig(CameraConfig):
|
|||||||
use_depth: bool = False
|
use_depth: bool = False
|
||||||
rotation: Cv2Rotation = Cv2Rotation.NO_ROTATION
|
rotation: Cv2Rotation = Cv2Rotation.NO_ROTATION
|
||||||
warmup_s: int = 1
|
warmup_s: int = 1
|
||||||
|
exposure: int | None = None
|
||||||
|
gain: int | None = None
|
||||||
|
white_balance: int | None = None
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
self.color_mode = ColorMode(self.color_mode)
|
self.color_mode = ColorMode(self.color_mode)
|
||||||
|
|||||||
Reference in New Issue
Block a user