xfu314's picture
Add phantom project with submodules and dependencies
96da58e
"""
Driver class for Keyboard controller.
"""
import numpy as np
from pynput.keyboard import Controller, Key, Listener
from robosuite.devices import Device
from robosuite.utils.transform_utils import rotation_matrix
class Keyboard(Device):
"""
A minimalistic driver class for a Keyboard.
Args:
pos_sensitivity (float): Magnitude of input position command scaling
rot_sensitivity (float): Magnitude of scale input rotation commands scaling
"""
def __init__(self, pos_sensitivity=1.0, rot_sensitivity=1.0):
self._display_controls()
self._reset_internal_state()
self._reset_state = 0
self._enabled = False
self._pos_step = 0.05
self.pos_sensitivity = pos_sensitivity
self.rot_sensitivity = rot_sensitivity
# make a thread to listen to keyboard and register our callback functions
self.listener = Listener(on_press=self.on_press, on_release=self.on_release)
# start listening
self.listener.start()
@staticmethod
def _display_controls():
"""
Method to pretty print controls.
"""
def print_command(char, info):
char += " " * (10 - len(char))
print("{}\t{}".format(char, info))
print("")
print_command("Keys", "Command")
print_command("q", "reset simulation")
print_command("spacebar", "toggle gripper (open/close)")
print_command("w-a-s-d", "move arm horizontally in x-y plane")
print_command("r-f", "move arm vertically")
print_command("z-x", "rotate arm about x-axis")
print_command("t-g", "rotate arm about y-axis")
print_command("c-v", "rotate arm about z-axis")
print("")
def _reset_internal_state(self):
"""
Resets internal state of controller, except for the reset signal.
"""
self.rotation = np.array([[-1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, -1.0]])
self.raw_drotation = np.zeros(3) # immediate roll, pitch, yaw delta values from keyboard hits
self.last_drotation = np.zeros(3)
self.pos = np.zeros(3) # (x, y, z)
self.last_pos = np.zeros(3)
self.grasp = False
def start_control(self):
"""
Method that should be called externally before controller can
start receiving commands.
"""
self._reset_internal_state()
self._reset_state = 0
self._enabled = True
def get_controller_state(self):
"""
Grabs the current state of the keyboard.
Returns:
dict: A dictionary containing dpos, orn, unmodified orn, grasp, and reset
"""
dpos = self.pos - self.last_pos
self.last_pos = np.array(self.pos)
raw_drotation = (
self.raw_drotation - self.last_drotation
) # create local variable to return, then reset internal drotation
self.last_drotation = np.array(self.raw_drotation)
return dict(
dpos=dpos,
rotation=self.rotation,
raw_drotation=raw_drotation,
grasp=int(self.grasp),
reset=self._reset_state,
)
def on_press(self, key):
"""
Key handler for key presses.
Args:
key (str): key that was pressed
"""
try:
# controls for moving position
if key.char == "w":
self.pos[0] -= self._pos_step * self.pos_sensitivity # dec x
elif key.char == "s":
self.pos[0] += self._pos_step * self.pos_sensitivity # inc x
elif key.char == "a":
self.pos[1] -= self._pos_step * self.pos_sensitivity # dec y
elif key.char == "d":
self.pos[1] += self._pos_step * self.pos_sensitivity # inc y
elif key.char == "f":
self.pos[2] -= self._pos_step * self.pos_sensitivity # dec z
elif key.char == "r":
self.pos[2] += self._pos_step * self.pos_sensitivity # inc z
# controls for moving orientation
elif key.char == "z":
drot = rotation_matrix(angle=0.1 * self.rot_sensitivity, direction=[1.0, 0.0, 0.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates x
self.raw_drotation[1] -= 0.1 * self.rot_sensitivity
elif key.char == "x":
drot = rotation_matrix(angle=-0.1 * self.rot_sensitivity, direction=[1.0, 0.0, 0.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates x
self.raw_drotation[1] += 0.1 * self.rot_sensitivity
elif key.char == "t":
drot = rotation_matrix(angle=0.1 * self.rot_sensitivity, direction=[0.0, 1.0, 0.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates y
self.raw_drotation[0] += 0.1 * self.rot_sensitivity
elif key.char == "g":
drot = rotation_matrix(angle=-0.1 * self.rot_sensitivity, direction=[0.0, 1.0, 0.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates y
self.raw_drotation[0] -= 0.1 * self.rot_sensitivity
elif key.char == "c":
drot = rotation_matrix(angle=0.1 * self.rot_sensitivity, direction=[0.0, 0.0, 1.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates z
self.raw_drotation[2] += 0.1 * self.rot_sensitivity
elif key.char == "v":
drot = rotation_matrix(angle=-0.1 * self.rot_sensitivity, direction=[0.0, 0.0, 1.0])[:3, :3]
self.rotation = self.rotation.dot(drot) # rotates z
self.raw_drotation[2] -= 0.1 * self.rot_sensitivity
except AttributeError as e:
pass
def on_release(self, key):
"""
Key handler for key releases.
Args:
key (str): key that was pressed
"""
try:
# controls for grasping
if key == Key.space:
self.grasp = not self.grasp # toggle gripper
# user-commanded reset
elif key.char == "q":
self._reset_state = 1
self._enabled = False
self._reset_internal_state()
except AttributeError as e:
pass