import logging import importlib from lerobot.utils.control_utils import is_headless # recursive call, inspired from gello_software: def instantiate_from_dict(cfg, ignore_cameras=False): """Instantiate objects from configuration.""" if isinstance(cfg, dict) and "_target_" in cfg: module_path, class_name = cfg["_target_"].rsplit(".", 1) cls = getattr(importlib.import_module(module_path), class_name) kwargs = {k: v for k, v in cfg.items() if k != "_target_"} # pp_dict ={k: instantiate_from_dict(v, ignore_cameras) for k, v in kwargs.items()} # print(pp_dict) return cls(**{k: {} if ignore_cameras and k == 'cameras' else instantiate_from_dict(v, ignore_cameras) for k, v in kwargs.items()}) elif isinstance(cfg, dict): return {k: {} if ignore_cameras and k == 'cameras' else instantiate_from_dict(v, ignore_cameras) for k, v in cfg.items()} elif isinstance(cfg, list): return [instantiate_from_dict(v, ignore_cameras) for v in cfg] else: return cfg def init_keyboard_listener(events: dict = None, on_press: callable = None, on_release: callable = None): """ Initializes a non-blocking keyboard listener for real-time user interaction. This function sets up a listener for specific keys (right arrow, left arrow, escape) to control the program flow during execution, such as stopping recording or exiting loops. It gracefully handles headless environments where keyboard listening is not possible. Returns: A tuple containing: - The `pynput.keyboard.Listener` instance, or `None` if in a headless environment. - A dictionary of event flags (e.g., `exit_early`) that are set by key presses. """ # Allow to exit early while recording an episode or resetting the environment, # by tapping the right arrow key '->'. This might require a sudo permission # to allow your terminal to monitor keyboard events. if events is None: events = {} events["exit_early"] = False events["rerecord_episode"] = False events["stop_recording"] = False if is_headless(): logging.warning( "Headless environment detected. On-screen cameras display and keyboard inputs will not be available." ) listener = None return listener, events # Only import pynput if not in a headless environment from pynput import keyboard if on_press is None: def on_press(key): try: if key == keyboard.Key.right: print("Right arrow key pressed. Exiting loop...") events["exit_early"] = True elif key == keyboard.Key.left: print("Left arrow key pressed. Exiting loop and rerecord the last episode...") events["rerecord_episode"] = True events["exit_early"] = True elif key == keyboard.Key.esc: print("Escape key pressed. Stopping data recording...") events["stop_recording"] = True events["exit_early"] = True except Exception as e: print(f"Error handling key press: {e}") listener = keyboard.Listener(on_press=on_press, on_release=on_release) listener.start() return listener, events