Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |