Source code for omni.isaac.lab.devices.keyboard.se2_keyboard

# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Keyboard controller for SE(2) control."""

import numpy as np
import weakref
from collections.abc import Callable

import carb
import omni

from ..device_base import DeviceBase


[docs]class Se2Keyboard(DeviceBase): r"""A keyboard controller for sending SE(2) commands as velocity commands. This class is designed to provide a keyboard controller for mobile base (such as quadrupeds). It uses the Omniverse keyboard interface to listen to keyboard events and map them to robot's task-space commands. The command comprises of the base linear and angular velocity: :math:`(v_x, v_y, \omega_z)`. Key bindings: ====================== ========================= ======================== Command Key (+ve axis) Key (-ve axis) ====================== ========================= ======================== Move along x-axis Numpad 8 / Arrow Up Numpad 2 / Arrow Down Move along y-axis Numpad 4 / Arrow Right Numpad 6 / Arrow Left Rotate along z-axis Numpad 7 / Z Numpad 9 / X ====================== ========================= ======================== .. seealso:: The official documentation for the keyboard interface: `Carb Keyboard Interface <https://docs.omniverse.nvidia.com/dev-guide/latest/programmer_ref/input-devices/keyboard.html>`__. """
[docs] def __init__(self, v_x_sensitivity: float = 0.8, v_y_sensitivity: float = 0.4, omega_z_sensitivity: float = 1.0): """Initialize the keyboard layer. Args: v_x_sensitivity: Magnitude of linear velocity along x-direction scaling. Defaults to 0.8. v_y_sensitivity: Magnitude of linear velocity along y-direction scaling. Defaults to 0.4. omega_z_sensitivity: Magnitude of angular velocity along z-direction scaling. Defaults to 1.0. """ # store inputs self.v_x_sensitivity = v_x_sensitivity self.v_y_sensitivity = v_y_sensitivity self.omega_z_sensitivity = omega_z_sensitivity # acquire omniverse interfaces self._appwindow = omni.appwindow.get_default_app_window() self._input = carb.input.acquire_input_interface() self._keyboard = self._appwindow.get_keyboard() # note: Use weakref on callbacks to ensure that this object can be deleted when its destructor is called self._keyboard_sub = self._input.subscribe_to_keyboard_events( self._keyboard, lambda event, *args, obj=weakref.proxy(self): obj._on_keyboard_event(event, *args), ) # bindings for keyboard to command self._create_key_bindings() # command buffers self._base_command = np.zeros(3) # dictionary for additional callbacks self._additional_callbacks = dict()
def __del__(self): """Release the keyboard interface.""" self._input.unsubscribe_from_keyboard_events(self._keyboard, self._keyboard_sub) self._keyboard_sub = None def __str__(self) -> str: """Returns: A string containing the information of joystick.""" msg = f"Keyboard Controller for SE(2): {self.__class__.__name__}\n" msg += f"\tKeyboard name: {self._input.get_keyboard_name(self._keyboard)}\n" msg += "\t----------------------------------------------\n" msg += "\tReset all commands: L\n" msg += "\tMove forward (along x-axis): Numpad 8 / Arrow Up\n" msg += "\tMove backward (along x-axis): Numpad 2 / Arrow Down\n" msg += "\tMove right (along y-axis): Numpad 4 / Arrow Right\n" msg += "\tMove left (along y-axis): Numpad 6 / Arrow Left\n" msg += "\tYaw positively (along z-axis): Numpad 7 / Z\n" msg += "\tYaw negatively (along z-axis): Numpad 9 / X" return msg """ Operations """
[docs] def reset(self): # default flags self._base_command.fill(0.0)
[docs] def add_callback(self, key: str, func: Callable): """Add additional functions to bind keyboard. A list of available keys are present in the `carb documentation <https://docs.omniverse.nvidia.com/dev-guide/latest/programmer_ref/input-devices/keyboard.html>`__. Args: key: The keyboard button to check against. func: The function to call when key is pressed. The callback function should not take any arguments. """ self._additional_callbacks[key] = func
[docs] def advance(self) -> np.ndarray: """Provides the result from keyboard event state. Returns: 3D array containing the linear (x,y) and angular velocity (z). """ return self._base_command
""" Internal helpers. """ def _on_keyboard_event(self, event, *args, **kwargs): """Subscriber callback to when kit is updated. Reference: https://docs.omniverse.nvidia.com/dev-guide/latest/programmer_ref/input-devices/keyboard.html """ # apply the command when pressed if event.type == carb.input.KeyboardEventType.KEY_PRESS: if event.input.name == "L": self.reset() elif event.input.name in self._INPUT_KEY_MAPPING: self._base_command += self._INPUT_KEY_MAPPING[event.input.name] # remove the command when un-pressed if event.type == carb.input.KeyboardEventType.KEY_RELEASE: if event.input.name in self._INPUT_KEY_MAPPING: self._base_command -= self._INPUT_KEY_MAPPING[event.input.name] # additional callbacks if event.type == carb.input.KeyboardEventType.KEY_PRESS: if event.input.name in self._additional_callbacks: self._additional_callbacks[event.input.name]() # since no error, we are fine :) return True def _create_key_bindings(self): """Creates default key binding.""" self._INPUT_KEY_MAPPING = { # forward command "NUMPAD_8": np.asarray([1.0, 0.0, 0.0]) * self.v_x_sensitivity, "UP": np.asarray([1.0, 0.0, 0.0]) * self.v_x_sensitivity, # back command "NUMPAD_2": np.asarray([-1.0, 0.0, 0.0]) * self.v_x_sensitivity, "DOWN": np.asarray([-1.0, 0.0, 0.0]) * self.v_x_sensitivity, # right command "NUMPAD_4": np.asarray([0.0, 1.0, 0.0]) * self.v_y_sensitivity, "LEFT": np.asarray([0.0, 1.0, 0.0]) * self.v_y_sensitivity, # left command "NUMPAD_6": np.asarray([0.0, -1.0, 0.0]) * self.v_y_sensitivity, "RIGHT": np.asarray([0.0, -1.0, 0.0]) * self.v_y_sensitivity, # yaw command (positive) "NUMPAD_7": np.asarray([0.0, 0.0, 1.0]) * self.omega_z_sensitivity, "Z": np.asarray([0.0, 0.0, 1.0]) * self.omega_z_sensitivity, # yaw command (negative) "NUMPAD_9": np.asarray([0.0, 0.0, -1.0]) * self.omega_z_sensitivity, "X": np.asarray([0.0, 0.0, -1.0]) * self.omega_z_sensitivity, }