diff --git a/crates/re_ui/src/lib.rs b/crates/re_ui/src/lib.rs index 3f15e4ae099e..034052bfd0bf 100644 --- a/crates/re_ui/src/lib.rs +++ b/crates/re_ui/src/lib.rs @@ -310,7 +310,7 @@ impl ReUi { if response.changed() { state.last_update = instant::Instant::now(); } - if state.delay_ms < state.last_update.elapsed().as_millis() as f32 { + if state.delay_ms <= state.last_update.elapsed().as_millis() as f32 { *value = Num::from_f64(state.value as f64); } response diff --git a/crates/re_viewer/src/depthai/api.rs b/crates/re_viewer/src/depthai/api.rs index 32b83793c5bd..b020e48a26e9 100644 --- a/crates/re_viewer/src/depthai/api.rs +++ b/crates/re_viewer/src/depthai/api.rs @@ -52,6 +52,34 @@ impl BackendCommChannel { ); } + pub fn set_dot_brightness(&mut self, brightness: u32) { + self.ws.send( + serde_json + ::to_string( + &(WsMessage { + kind: WsMessageType::SetDotBrightness, + data: WsMessageData::SetDotBrightness(brightness), + ..Default::default() + }) + ) + .unwrap() + ); + } + + pub fn set_flood_brightness(&mut self, brightness: u32) { + self.ws.send( + serde_json + ::to_string( + &(WsMessage { + kind: WsMessageType::SetFloodBrightness, + data: WsMessageData::SetFloodBrightness(brightness), + ..Default::default() + }) + ) + .unwrap() + ); + } + pub fn receive(&mut self) -> Option { self.ws.receive() } diff --git a/crates/re_viewer/src/depthai/depthai.rs b/crates/re_viewer/src/depthai/depthai.rs index 5e770cdcb208..a7761b06547f 100644 --- a/crates/re_viewer/src/depthai/depthai.rs +++ b/crates/re_viewer/src/depthai/depthai.rs @@ -323,6 +323,10 @@ pub struct DeviceConfig { #[serde(default = "StereoDepthConfig::default_as_option")] pub depth: Option, pub ai_model: AiModel, + #[serde(skip)] + pub dot_brightness: u32, + #[serde(skip)] + pub flood_brightness: u32, } impl Default for DeviceConfig { @@ -333,6 +337,8 @@ impl Default for DeviceConfig { depth_enabled: true, depth: Some(StereoDepthConfig::default()), ai_model: AiModel::default(), + dot_brightness: 0, + flood_brightness: 0, } } } @@ -809,6 +815,12 @@ impl State { } re_log::warn!("{}", warning.message); } + WsMessageData::SetDotBrightness(_brightness) => { + re_log::debug!("Set dot brightness received from backend.") + } + WsMessageData::SetFloodBrightness(_brightness) => { + re_log::debug!("Set flood brightness received from backend.") + } } } @@ -874,6 +886,16 @@ impl State { } } + pub fn set_dot_brightness(&mut self, brightness: u32) { + println!("Setting dot brightness to {}", brightness); + self.backend_comms.set_dot_brightness(brightness); + } + + pub fn set_flood_brightness(&mut self, brightness: u32) { + println!("Setting flood brightness to {}", brightness); + self.backend_comms.set_flood_brightness(brightness); + } + pub fn reset(&mut self) { *self = Self::default(); } diff --git a/crates/re_viewer/src/depthai/ws.rs b/crates/re_viewer/src/depthai/ws.rs index 15d64dba209a..a15fcd2ec6a9 100644 --- a/crates/re_viewer/src/depthai/ws.rs +++ b/crates/re_viewer/src/depthai/ws.rs @@ -83,6 +83,8 @@ pub enum WsMessageData { Devices(Vec), DeviceProperties(depthai::DeviceProperties), Pipeline((depthai::DeviceConfig, RuntimeOnly)), + SetFloodBrightness(u32), + SetDotBrightness(u32), Error(depthai::Error), Info(depthai::Info), Warning(depthai::Warning), @@ -94,6 +96,8 @@ pub enum WsMessageType { Devices, DeviceProperties, Pipeline, + SetFloodBrightness, + SetDotBrightness, Error, Info, Warning, @@ -149,6 +153,12 @@ impl<'de> Deserialize<'de> for BackWsMessage { WsMessageType::Warning => { WsMessageData::Warning(serde_json::from_value(message.data).unwrap_or_default()) } + WsMessageType::SetDotBrightness => { + WsMessageData::SetDotBrightness(serde_json::from_value(message.data).unwrap()) + } + WsMessageType::SetFloodBrightness => { + WsMessageData::SetFloodBrightness(serde_json::from_value(message.data).unwrap()) + } }; Ok(Self { diff --git a/crates/re_viewer/src/ui/device_settings_panel.rs b/crates/re_viewer/src/ui/device_settings_panel.rs index bb58ae97fb60..263d923db422 100644 --- a/crates/re_viewer/src/ui/device_settings_panel.rs +++ b/crates/re_viewer/src/ui/device_settings_panel.rs @@ -341,6 +341,33 @@ impl DeviceSettingsPanel { } }, ); + let dot_drag = ctx.re_ui.labeled_dragvalue( + ui, + egui::Id::from("Dot brightness [mA]"), + None, + "Dot brightness [mA]", + &mut device_config.dot_brightness, + 0..=1200); + if dot_drag.drag_released() { + ctx.depthai_state.set_dot_brightness(device_config.dot_brightness); + } else if dot_drag.changed() && !dot_drag.dragged() { + // Dragging isn't ongoing, but the value changed + ctx.depthai_state.set_dot_brightness(device_config.dot_brightness); + } + let flood_drag = ctx.re_ui.labeled_dragvalue( + ui, + egui::Id::from("Flood light brightness [mA]"), + None, + "Flood light brightness [mA]", + &mut device_config.flood_brightness, + 0..=1500, + ); + if flood_drag.drag_released() { + ctx.depthai_state.set_flood_brightness(device_config.flood_brightness); + } else if flood_drag.changed() && !flood_drag.dragged() { + // Dragging isn't ongoing, but the value changed + ctx.depthai_state.set_flood_brightness(device_config.flood_brightness); + } ctx.re_ui.labeled_toggle_switch( ui, "LR Check", diff --git a/rerun_py/depthai_viewer/_backend/config_api.py b/rerun_py/depthai_viewer/_backend/config_api.py index 3cc2d2155a12..e8bc8fdc7d1c 100644 --- a/rerun_py/depthai_viewer/_backend/config_api.py +++ b/rerun_py/depthai_viewer/_backend/config_api.py @@ -1,7 +1,7 @@ import asyncio import atexit import json -from enum import Enum +from enum import Enum, auto from multiprocessing import Queue from queue import Empty as QueueEmptyException from signal import SIGINT, signal @@ -37,12 +37,14 @@ class Action(Enum): UPDATE_PIPELINE = 0 - SELECT_DEVICE = 1 - GET_SUBSCRIPTIONS = 2 - SET_SUBSCRIPTIONS = 3 - GET_PIPELINE = 4 - RESET = 5 # When anything bad happens, a reset occurs (like closing ws connection) - GET_AVAILABLE_DEVICES = 6 + SELECT_DEVICE = auto() + GET_SUBSCRIPTIONS = auto() + SET_SUBSCRIPTIONS = auto() + GET_PIPELINE = auto() + SET_FLOOD_BRIGHTNESS = auto() + SET_DOT_BRIGHTNESS = auto() + RESET = auto() # When anything bad happens, a reset occurs (like closing ws connection) + GET_AVAILABLE_DEVICES = auto() def dispatch_action(action: Action, **kwargs) -> Message: # type: ignore[no-untyped-def] @@ -123,6 +125,22 @@ async def ws_api(websocket: WebSocketServerProtocol) -> None: print("Missing device id") continue await send_message(websocket, dispatch_action(Action.SELECT_DEVICE, device_id=device_id)) + elif message_type == MessageType.SET_FLOOD_BRIGHTNESS: + data = message.get("data", {}) + flood_brightness = data.get(message_type, None) + if flood_brightness is None: + print("Missing", message_type) + continue + await send_message( + websocket, dispatch_action(Action.SET_FLOOD_BRIGHTNESS, flood_brightness=flood_brightness) + ) + elif message_type == MessageType.SET_DOT_BRIGHTNESS: + data = message.get("data", {}) + dot_brightness = data.get(message_type, None) + if dot_brightness is None: + print("Missing dot", message_type) + continue + await send_message(websocket, dispatch_action(Action.SET_DOT_BRIGHTNESS, dot_brightness=dot_brightness)) else: print("Unknown message type: ", message_type) continue diff --git a/rerun_py/depthai_viewer/_backend/device.py b/rerun_py/depthai_viewer/_backend/device.py index f22388e80518..55560699a259 100644 --- a/rerun_py/depthai_viewer/_backend/device.py +++ b/rerun_py/depthai_viewer/_backend/device.py @@ -87,7 +87,7 @@ class Device: def __init__(self, device_id: str, store: Store): self.id = device_id - self.set_oak(OakCamera(device_id)) + self.set_oak(OakCamera(device_id, args={"irFloodBrightness": 0, "irDotBrightness": 0})) self.store = store self._packet_handler = PacketHandler(self.store, self.get_intrinsic_matrix) print("Oak cam: ", self._oak) @@ -261,7 +261,7 @@ def reconnect_to_oak(self) -> Message: if self.id in available_devices: break try: - self.set_oak(OakCamera(self.id)) + self.set_oak(OakCamera(self.id, args={"irFloodBrightness": 0, "irDotBrightness": 0})) return InfoMessage("Successfully reconnected to device") except RuntimeError as e: print("Failed to create oak camera") diff --git a/rerun_py/depthai_viewer/_backend/main.py b/rerun_py/depthai_viewer/_backend/main.py index 24c096a80800..eef06f557c18 100644 --- a/rerun_py/depthai_viewer/_backend/main.py +++ b/rerun_py/depthai_viewer/_backend/main.py @@ -135,6 +135,20 @@ def handle_action(self, action: Action, **kwargs) -> Message: # type: ignore[no return self.store.pipeline_config # type: ignore[return-value] elif action == Action.RESET: return self.on_reset() + elif action == Action.SET_FLOOD_BRIGHTNESS: + self.store.set_flood_brightness(kwargs.get("flood_brightness", 0)) + print("Set flood: ", kwargs.get("flood_brightness", 0)) + if self._device: + self._device._oak.device.setIrFloodLightBrightness(self.store.flood_brightness) + return InfoMessage("Floodlight set successfully") + return ErrorMessage("No device selected") + elif action == Action.SET_DOT_BRIGHTNESS: + print("Set dot: ", kwargs.get("dot_brightness", 0)) + self.store.set_dot_brightness(kwargs.get("dot_brightness", 0)) + if self._device: + self._device._oak.device.setIrLaserDotProjectorBrightness(self.store.dot_brightness) + return InfoMessage("Dot projector set successfully") + return ErrorMessage("No device selected") return ErrorMessage(f"Action: {action} not implemented") def run(self) -> None: @@ -142,7 +156,7 @@ def run(self) -> None: while True: try: action, kwargs = self.action_queue.get(timeout=0.0001) - print("Handling action: ", action) + # print("Handling action: ", action) self.result_queue.put(self.handle_action(action, **kwargs)) except QueueEmptyException: pass diff --git a/rerun_py/depthai_viewer/_backend/messages.py b/rerun_py/depthai_viewer/_backend/messages.py index 10358dbb8cb4..c7d30d6d1bab 100644 --- a/rerun_py/depthai_viewer/_backend/messages.py +++ b/rerun_py/depthai_viewer/_backend/messages.py @@ -12,6 +12,8 @@ class MessageType: PIPELINE = "Pipeline" # Get or Set pipeline DEVICES = "Devices" # Get device list DEVICE = "DeviceProperties" # Get or set device + SET_FLOOD_BRIGHTNESS = "SetFloodBrightness" # Set floodlight + SET_DOT_BRIGHTNESS = "SetDotBrightness" # Set floodlight ERROR = "Error" # Error message INFO = "Info" # Info message WARNING = "Warning" # Warning message diff --git a/rerun_py/depthai_viewer/_backend/store.py b/rerun_py/depthai_viewer/_backend/store.py index dbf074715e5a..c81297958150 100644 --- a/rerun_py/depthai_viewer/_backend/store.py +++ b/rerun_py/depthai_viewer/_backend/store.py @@ -12,6 +12,8 @@ class Store: _pipeline_config: Optional[PipelineConfiguration] = None _subscriptions: List[Topic] = [] _send_message_queue: Queue # type: ignore[type-arg] + _dot_brightness: int = 0 + _flood_brightness: int = 0 def __init__(self) -> None: self._send_message_queue = Queue() @@ -22,6 +24,12 @@ def set_pipeline_config(self, pipeline_config: PipelineConfiguration) -> None: def set_subscriptions(self, subscriptions: List[Topic]) -> None: self._subscriptions = subscriptions + def set_dot_brightness(self, brightness: int) -> None: + self._dot_brightness = brightness + + def set_flood_brightness(self, brightness: int) -> None: + self._flood_brightness = brightness + def reset(self) -> None: self._pipeline_config = None self._subscriptions = [] @@ -34,5 +42,13 @@ def pipeline_config(self) -> Optional[PipelineConfiguration]: def subscriptions(self) -> List[Topic]: return self._subscriptions + @property + def dot_brightness(self) -> int: + return self._dot_brightness + + @property + def flood_brightness(self) -> int: + return self._flood_brightness + def send_message_to_frontend(self, message: Message) -> None: self._send_message_queue.put(message)