Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions scripts/environments/teleoperation/teleop_se3_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,7 @@ def reset_task_success():

teleop_interface.add_callback("R", reset_recording_instance)
teleop_interface.add_callback("N", reset_task_success)
print(teleop_interface)

teleop_interface.display_controls()
rate_limiter = RateLimiter(args_cli.step_hz)

# reset environment
Expand Down
36 changes: 19 additions & 17 deletions source/leisaac/leisaac/devices/device_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import omni
import torch
from leisaac.utils.math_utils import rotvec_to_euler
from prettytable import PrettyTable


class DeviceBase(ABC):
Expand Down Expand Up @@ -60,13 +61,12 @@ def advance(self) -> Any:


class Device(DeviceBase):
def __init__(self, env, device_type: str, verbose: bool = True):
def __init__(self, env, device_type: str):
"""
Args:
env (RobotEnv): The environment which contains the robot(s) to control
using this device.
device_type: The type of the device.
verbose: Whether to display the controls.
"""
self.env = env
self.device_type = device_type
Expand All @@ -86,9 +86,18 @@ def __init__(self, env, device_type: str, verbose: bool = True):
self._reset_state = False
self._additional_callbacks = {}

# display controls
if verbose:
self._display_controls()
# display control table
self._display_controls_table = PrettyTable()
self._display_controls_table.title = f"Teleoperation Controls for {self.device_type}"
self._display_controls_table.field_names = ["Key", "Description"]
self._display_controls_table.align["Description"] = "l"
# basic controls
self._display_controls_table.add_row(["B", "start control"])
self._display_controls_table.add_row(["R", "reset simulation and set task success to False"])
self._display_controls_table.add_row(["N", "reset simulation and set task success to True"])
self._display_controls_table.add_row(["Control+C", "quit"])
self._display_controls_table.add_divider()
self._add_device_control_description()

def __del__(self):
"""Release the keyboard interface."""
Expand Down Expand Up @@ -164,21 +173,14 @@ def _stop_keyboard_listener(self):
self._input.unsubscribe_to_keyboard_events(self._keyboard, self._keyboard_sub)
self._keyboard_sub = None

def _display_controls(self):
def _add_device_control_description(self):
"""
Method to pretty print controls.
Add device control description to the display control table.
"""
raise NotImplementedError

def print_command(char, info):
char += " " * (30 - len(char))
print(f"{char}\t{info}")

print("teleoperation controls:")
print_command("b", "start control")
print_command("r", "reset simulation and set task success to False")
print_command("n", "reset simulation and set task success to True")
print_command("Control+C", "quit")
print("")
def display_controls(self):
print(self._display_controls_table)

def _convert_delta_from_frame(self, delta_action: np.ndarray) -> np.ndarray:
"""
Expand Down
27 changes: 13 additions & 14 deletions source/leisaac/leisaac/devices/gamepad/so101_gamepad.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,19 @@ def __del__(self):
super().__del__()
self._gamepad.stop()

def __str__(self) -> str:
"""Returns: A string containing the information of gamepad controller."""
msg = "Gamepad Controller for SO101 Single Arm (SE(3) Control).\n"
msg += f"\tGamepad name: {self._gamepad.name}\n"
msg += f"\ttarget frame: {self.target_frame}\n"
msg += "\t----------------------------------------------\n"
msg += "\tForward / Backward: Left stick Y (forward / backward)\n"
msg += "\tLeft / Right: Left stick X (left / right)\n"
msg += "\tUp / Down: Right stick Y (forward / backward)\n"
msg += "\tRotate (Yaw) Left/Right: Right stick X (left / right)\n"
msg += "\tRotate (Pitch) Up/Down: LB / LT\n"
msg += "\tGripper Open / Close: RT / RB\n"
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
self._display_controls_table.add_row(["Left Stick Y (forward)", "forward"])
self._display_controls_table.add_row(["Left Stick Y (backward)", "backward"])
self._display_controls_table.add_row(["Left Stick X (left)", "left"])
self._display_controls_table.add_row(["Left Stick X (right)", "right"])
self._display_controls_table.add_row(["Right Stick Y (up)", "up"])
self._display_controls_table.add_row(["Right Stick Y (down)", "down"])
self._display_controls_table.add_row(["Right Stick X (left)", "rotate_left"])
self._display_controls_table.add_row(["Right Stick X (right)", "rotate_right"])
self._display_controls_table.add_row(["LB", "rotate_up"])
self._display_controls_table.add_row(["LT", "rotate_down"])
self._display_controls_table.add_row(["RT", "gripper_open"])
self._display_controls_table.add_row(["RB", "gripper_close"])

def get_device_state(self):
return self._convert_delta_from_frame(self._delta_action)
Expand Down
27 changes: 13 additions & 14 deletions source/leisaac/leisaac/devices/keyboard/so101_keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,19 @@ def __init__(self, env, sensitivity: float = 1.0):
body_idxs, _ = self.robot_asset.find_bodies(self.target_frame)
self.target_frame_idx = body_idxs[0]

def __str__(self) -> str:
"""Returns: A string containing the information of keyboard controller."""
msg = "Keyboard Controller for SO101 Single Arm (SE(3) Control).\n"
msg += f"\tKeyboard name: {self._input.get_keyboard_name(self._keyboard)}\n"
msg += f"\ttarget frame: {self.target_frame}\n"
msg += "\t----------------------------------------------\n"
msg += "\tForward / Backward: W / S\n"
msg += "\tLeft / Right: A / D\n"
msg += "\tUp / Down: Q / E\n"
msg += "\tRotate (Yaw) Left / Right: J / L\n"
msg += "\tRotate (Pitch) Up / Down: K / I\n"
msg += "\tGripper Open / Close: U / O\n"
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
self._display_controls_table.add_row(["W", "forward"])
self._display_controls_table.add_row(["S", "backward"])
self._display_controls_table.add_row(["A", "left"])
self._display_controls_table.add_row(["D", "right"])
self._display_controls_table.add_row(["Q", "up"])
self._display_controls_table.add_row(["E", "down"])
self._display_controls_table.add_row(["J", "rotate_left"])
self._display_controls_table.add_row(["L", "rotate_right"])
self._display_controls_table.add_row(["K", "rotate_up"])
self._display_controls_table.add_row(["I", "rotate_down"])
self._display_controls_table.add_row(["U", "gripper_open"])
self._display_controls_table.add_row(["O", "gripper_close"])

def get_device_state(self):
return self._convert_delta_from_frame(self._delta_action)
Expand Down
21 changes: 10 additions & 11 deletions source/leisaac/leisaac/devices/lekiwi/lekiwi_gamepad.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,16 @@ def __init__(self, env, sensitivity: float = 1.0):
self._vel_command = np.zeros(3)
self._joint_names = self.env.scene["robot"].data.joint_names

def __str__(self) -> str:
"""Returns: A string containing the information of gamepad controller."""
msg = "Gamepad Controller for LeKiwi Control).\n"
msg += f"\tGamepad name: {self._gamepad.name}\n"
msg += "\t----------------------------------------------\n"
msg += "\tForward / Backward: hats-UP / hats-DOWN\n"
msg += "\tLeft / Right: hats-LEFT / hats-RIGHT\n"
msg += "\tRotate (Theta) Left / Right: buttons-X / buttons-B\n"
msg += "\tSpeed Level up / down: buttons-Y / buttons-A\n"
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
super()._add_device_control_description()
self._display_controls_table.add_row(["hats-UP", "forward"])
self._display_controls_table.add_row(["hats-DOWN", "backward"])
self._display_controls_table.add_row(["hats-LEFT", "left"])
self._display_controls_table.add_row(["hats-RIGHT", "right"])
self._display_controls_table.add_row(["buttons-X", "rotate_left"])
self._display_controls_table.add_row(["buttons-B", "rotate_right"])
self._display_controls_table.add_row(["buttons-Y", "speed_up"])
self._display_controls_table.add_row(["buttons-A", "speed_down"])

def get_device_state(self):
arm_action = super().get_device_state()
Expand Down
22 changes: 11 additions & 11 deletions source/leisaac/leisaac/devices/lekiwi/lekiwi_keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ def __init__(self, env, sensitivity: float = 1.0):
self._vel_command = np.zeros(3)
self._joint_names = self.env.scene["robot"].data.joint_names

def __str__(self) -> str:
"""Returns: A string containing the information of keyboard controller."""
msg = "Keyboard Controller for LeKiwi Control).\n"
msg += f"\tKeyboard name: {self._input.get_keyboard_name(self._keyboard)}\n"
msg += "\t----------------------------------------------\n"
msg += "\tForward / Backward: UP / DOWN\n"
msg += "\tLeft / Right: LEFT / RIGHT\n"
msg += "\tRotate (Theta) Left / Right: Z / X\n"
msg += "\tSpeed Level: 1 / 2 / 3\n"
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
super()._add_device_control_description()
self._display_controls_table.add_row(["UP", "forward"])
self._display_controls_table.add_row(["DOWN", "backward"])
self._display_controls_table.add_row(["LEFT", "left"])
self._display_controls_table.add_row(["RIGHT", "right"])
self._display_controls_table.add_row(["Z", "rotate_left"])
self._display_controls_table.add_row(["X", "rotate_right"])
self._display_controls_table.add_row(["1", "speed_level_1"])
self._display_controls_table.add_row(["2", "speed_level_2"])
self._display_controls_table.add_row(["3", "speed_level_3"])

def get_device_state(self):
arm_action = super().get_device_state()
Expand Down
22 changes: 11 additions & 11 deletions source/leisaac/leisaac/devices/lekiwi/lekiwi_leader.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,17 @@ def __init__(self, env, port: str = "/dev/ttyACM0", recalibrate: bool = False):
self._vel_command = np.zeros(3)
self._joint_names = self.env.scene["robot"].data.joint_names

def __str__(self) -> str:
"""Returns: A string containing the information of lekiwi leader."""
msg = "Keyboard Controller for LeKiwi Wheel Control).\n"
msg += f"\tKeyboard name: {self._input.get_keyboard_name(self._keyboard)}\n"
msg += "\t----------------------------------------------\n"
msg += "\tForward / Backward: UP / DOWN\n"
msg += "\tLeft / Right: LEFT / RIGHT\n"
msg += "\tRotate (Theta) Left / Right: Z / X\n"
msg += "\tSpeed Level: 1 / 2 / 3\n"
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
self._display_controls_table.add_row(["UP", "forward"])
self._display_controls_table.add_row(["DOWN", "backward"])
self._display_controls_table.add_row(["LEFT", "left"])
self._display_controls_table.add_row(["RIGHT", "right"])
self._display_controls_table.add_row(["Z", "rotate_left"])
self._display_controls_table.add_row(["X", "rotate_right"])
self._display_controls_table.add_row(["1", "speed_level_1"])
self._display_controls_table.add_row(["2", "speed_level_2"])
self._display_controls_table.add_row(["3", "speed_level_3"])
self._display_controls_table.add_row(["so101-leader", "move so101-leader to control so101-follower"])

def get_device_state(self):
arm_action = self.so101_leader.get_device_state()
Expand Down
20 changes: 9 additions & 11 deletions source/leisaac/leisaac/devices/lerobot/bi_so101_leader.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,15 @@ def __init__(
self.left_so101_leader._stop_keyboard_listener()
self.right_so101_leader._stop_keyboard_listener()

def __str__(self) -> str:
"""Returns: A string containing the information of bi-so101 leader."""
msg = "Bi-SO101-Leader device for SE(3) control.\n"
msg += "\t----------------------------------------------\n"
msg += "\tMove Bi-SO101-Leader to control Bi-SO101-Follower\n"
msg += (
"\tIf SO101-Follower can't synchronize with Bi-SO101-Leader, please add --recalibrate and rerun to"
" recalibrate Bi-SO101-Leader.\n"
)
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
self._display_controls_table.add_row(["bi-so101-leader", "move bi-so101-leader to control bi-so101-follower"])
self._display_controls_table.add_row([
"[TIPS]",
(
"If Bi-SO101-Follower can't synchronize with Bi-SO101-Leader, please add --recalibrate and rerun to"
" recalibrate Bi-SO101-Leader"
),
])

def reset(self):
self.left_so101_leader.reset()
Expand Down
20 changes: 9 additions & 11 deletions source/leisaac/leisaac/devices/lerobot/so101_leader.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,15 @@ def __init__(
# connect
self.connect()

def __str__(self) -> str:
"""Returns: A string containing the information of so101 leader."""
msg = "SO101-Leader device for SE(3) control.\n"
msg += "\t----------------------------------------------\n"
msg += "\tMove SO101-Leader to control SO101-Follower\n"
msg += (
"\tIf SO101-Follower can't synchronize with SO101-Leader, please add --recalibrate and rerun to recalibrate"
" SO101-Leader.\n"
)
msg += "\t----------------------------------------------\n"
return msg
def _add_device_control_description(self):
self._display_controls_table.add_row(["so101-leader", "move so101-leader to control so101-follower"])
self._display_controls_table.add_row([
"[TIPS]",
(
"If SO101-Follower can't synchronize with SO101-Leader, please add --recalibrate and rerun to"
" recalibrate SO101-Leader"
),
])

def get_device_state(self):
return self._bus.sync_read("Present_Position")
Expand Down
5 changes: 3 additions & 2 deletions source/leisaac/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ classifiers = [
]
requires-python = ">=3.10"
dependencies = [
"psutil",
"pyserial",
"deepdiff",
"feetech-servo-sdk",
"prettytable>=3.14.0",
"psutil",
"pygame>=2.5.1,<2.7.0",
"pyserial",
]

[project.urls]
Expand Down