xfu314's picture
Add phantom project with submodules and dependencies
96da58e
"""
Utility functions for grabbing user inputs
"""
import numpy as np
import robosuite as suite
import robosuite.utils.transform_utils as T
from robosuite.devices import *
from robosuite.models.robots import *
from robosuite.robots import *
def choose_environment():
"""
Prints out environment options, and returns the selected env_name choice
Returns:
str: Chosen environment name
"""
# get the list of all environments
envs = sorted(suite.ALL_ENVIRONMENTS)
# Select environment to run
print("Here is a list of environments in the suite:\n")
for k, env in enumerate(envs):
print("[{}] {}".format(k, env))
print()
try:
s = input("Choose an environment to run " + "(enter a number from 0 to {}): ".format(len(envs) - 1))
# parse input into a number within range
k = min(max(int(s), 0), len(envs))
except:
k = 0
print("Input is not valid. Use {} by default.\n".format(envs[k]))
# Return the chosen environment name
return envs[k]
def choose_controller():
"""
Prints out controller options, and returns the requested controller name
Returns:
str: Chosen controller name
"""
# get the list of all controllers
controllers_info = suite.controllers.CONTROLLER_INFO
controllers = list(suite.ALL_CONTROLLERS)
# Select controller to use
print("Here is a list of controllers in the suite:\n")
for k, controller in enumerate(controllers):
print("[{}] {} - {}".format(k, controller, controllers_info[controller]))
print()
try:
s = input("Choose a controller for the robot " + "(enter a number from 0 to {}): ".format(len(controllers) - 1))
# parse input into a number within range
k = min(max(int(s), 0), len(controllers) - 1)
except:
k = 0
print("Input is not valid. Use {} by default.".format(controllers)[k])
# Return chosen controller
return controllers[k]
def choose_multi_arm_config():
"""
Prints out multi-arm environment configuration options, and returns the requested config name
Returns:
str: Requested multi-arm configuration name
"""
# Get the list of all multi arm configs
env_configs = {
"Single Arms Opposed": "single-arm-opposed",
"Single Arms Parallel": "single-arm-parallel",
"Bimanual": "bimanual",
}
# Select environment configuration
print("A multi-arm environment was chosen. Here is a list of multi-arm environment configurations:\n")
for k, env_config in enumerate(list(env_configs)):
print("[{}] {}".format(k, env_config))
print()
try:
s = input(
"Choose a configuration for this environment "
+ "(enter a number from 0 to {}): ".format(len(env_configs) - 1)
)
# parse input into a number within range
k = min(max(int(s), 0), len(env_configs))
except:
k = 0
print("Input is not valid. Use {} by default.".format(list(env_configs)[k]))
# Return requested configuration
return list(env_configs.values())[k]
def choose_robots(exclude_bimanual=False):
"""
Prints out robot options, and returns the requested robot. Restricts options to single-armed robots if
@exclude_bimanual is set to True (False by default)
Args:
exclude_bimanual (bool): If set, excludes bimanual robots from the robot options
Returns:
str: Requested robot name
"""
# Get the list of robots
robots = {
"Sawyer",
"Panda",
"Jaco",
"Kinova3",
"IIWA",
"UR5e",
}
# Add Baxter if bimanual robots are not excluded
if not exclude_bimanual:
robots.add("Baxter")
# Make sure set is deterministically sorted
robots = sorted(robots)
# Select robot
print("Here is a list of available robots:\n")
for k, robot in enumerate(robots):
print("[{}] {}".format(k, robot))
print()
try:
s = input("Choose a robot " + "(enter a number from 0 to {}): ".format(len(robots) - 1))
# parse input into a number within range
k = min(max(int(s), 0), len(robots))
except:
k = 0
print("Input is not valid. Use {} by default.".format(list(robots)[k]))
# Return requested robot
return list(robots)[k]
def input2action(device, robot, active_arm="right", env_configuration=None):
"""
Converts an input from an active device into a valid action sequence that can be fed into an env.step() call
If a reset is triggered from the device, immediately returns None. Else, returns the appropriate action
Args:
device (Device): A device from which user inputs can be converted into actions. Can be either a Spacemouse or
Keyboard device class
robot (Robot): Which robot we're controlling
active_arm (str): Only applicable for multi-armed setups (e.g.: multi-arm environments or bimanual robots).
Allows inputs to be converted correctly if the control type (e.g.: IK) is dependent on arm choice.
Choices are {right, left}
env_configuration (str or None): Only applicable for multi-armed environments. Allows inputs to be converted
correctly if the control type (e.g.: IK) is dependent on the environment setup. Options are:
{bimanual, single-arm-parallel, single-arm-opposed}
Returns:
2-tuple:
- (None or np.array): Action interpreted from @device including any gripper action(s). None if we get a
reset signal from the device
- (None or int): 1 if desired close, -1 if desired open gripper state. None if get a reset signal from the
device
"""
state = device.get_controller_state()
# Note: Devices output rotation with x and z flipped to account for robots starting with gripper facing down
# Also note that the outputted rotation is an absolute rotation, while outputted dpos is delta pos
# Raw delta rotations from neutral user input is captured in raw_drotation (roll, pitch, yaw)
dpos, rotation, raw_drotation, grasp, reset = (
state["dpos"],
state["rotation"],
state["raw_drotation"],
state["grasp"],
state["reset"],
)
# If we're resetting, immediately return None
if reset:
return None, None
# Get controller reference
controller = robot.controller if not isinstance(robot, Bimanual) else robot.controller[active_arm]
gripper_dof = robot.gripper.dof if not isinstance(robot, Bimanual) else robot.gripper[active_arm].dof
# First process the raw drotation
drotation = raw_drotation[[1, 0, 2]]
if controller.name == "IK_POSE":
# If this is panda, want to swap x and y axis
if isinstance(robot.robot_model, Panda):
drotation = drotation[[1, 0, 2]]
else:
# Flip x
drotation[0] = -drotation[0]
# Scale rotation for teleoperation (tuned for IK)
drotation *= 10
dpos *= 5
# relative rotation of desired from current eef orientation
# map to quat
drotation = T.mat2quat(T.euler2mat(drotation))
# If we're using a non-forward facing configuration, need to adjust relative position / orientation
if env_configuration == "single-arm-opposed":
# Swap x and y for pos and flip x,y signs for ori
dpos = dpos[[1, 0, 2]]
drotation[0] = -drotation[0]
drotation[1] = -drotation[1]
if active_arm == "left":
# x pos needs to be flipped
dpos[0] = -dpos[0]
else:
# y pos needs to be flipped
dpos[1] = -dpos[1]
# Lastly, map to axis angle form
drotation = T.quat2axisangle(drotation)
elif controller.name == "OSC_POSE":
# Flip z
drotation[2] = -drotation[2]
# Scale rotation for teleoperation (tuned for OSC) -- gains tuned for each device
drotation = drotation * 1.5 if isinstance(device, Keyboard) else drotation * 50
dpos = dpos * 75 if isinstance(device, Keyboard) else dpos * 125
elif controller.name == "OSC_POSITION":
dpos = dpos * 75 if isinstance(device, Keyboard) else dpos * 125
else:
# No other controllers currently supported
print("Error: Unsupported controller specified -- Robot must have either an IK or OSC-based controller!")
# map 0 to -1 (open) and map 1 to 1 (closed)
grasp = 1 if grasp else -1
# Create action based on action space of individual robot
if controller.name == "OSC_POSITION":
action = np.concatenate([dpos, [grasp] * gripper_dof])
else:
action = np.concatenate([dpos, drotation, [grasp] * gripper_dof])
# Return the action and grasp
return action, grasp