def test_sensor_noise_robot(self): obs_config = ObservationConfig( joint_velocities_noise=GaussianNoise(0.01), joint_forces=False, task_low_dim_state=False) scene = Scene(self.pyrep, self.robot, obs_config) scene.load(ReachTarget(self.pyrep, self.robot)) obs1 = scene.get_observation() obs2 = scene.get_observation() self.assertTrue( np.array_equal(obs1.joint_positions, obs2.joint_positions)) self.assertFalse( np.array_equal(obs1.joint_velocities, obs2.joint_velocities))
def test_sensor_noise_images(self): cam_config = CameraConfig(rgb_noise=GaussianNoise(0.05, (.0, 1.))) obs_config = ObservationConfig(left_shoulder_camera=cam_config, joint_forces=False, task_low_dim_state=False) scene = Scene(self.pyrep, self.robot, obs_config) scene.load(ReachTarget(self.pyrep, self.robot)) obs1 = scene.get_observation() obs2 = scene.get_observation() self.assertTrue( np.array_equal(obs1.right_shoulder_rgb, obs2.right_shoulder_rgb)) self.assertFalse( np.array_equal(obs1.left_shoulder_rgb, obs2.left_shoulder_rgb)) self.assertTrue(obs1.left_shoulder_rgb.max() <= 1.0) self.assertTrue(obs1.left_shoulder_rgb.min() >= 0.0)
def task_smoke(task: Task, scene: Scene, variation=-1, demos=4, success=0.50, max_variations=3, test_demos=True): # -1 variations for all. print('Running task validator on task: %s' % task.get_name()) # Loading scene.load(task) # Number of variations variation_count = task.variation_count() if variation_count < 0: raise TaskValidationError( "The method 'variation_count' should return a number > 0.") if variation_count > MAX_VARIATIONS: raise TaskValidationError( "This task had %d variations. Currently the limit is set to %d" % (variation_count, MAX_VARIATIONS)) # Base rotation bounds base_pos, base_ori = task.base_rotation_bounds() if len(base_pos) != 3 or len(base_ori) != 3: raise TaskValidationError( "The method 'base_rotation_bounds' should return a tuple " "containing a list of floats.") # Boundary root root = task.boundary_root() if not root.still_exists(): raise TaskValidationError( "The method 'boundary_root' should return a Dummy that is the root " "of the task.") def variation_smoke(i): print('Running task validator on variation: %d' % i) attempt_result = False failed_demos = 0 for j in range(DEMO_ATTEMPTS): failed_demos = run_demos(i) attempt_result = (failed_demos / float(demos) <= 1. - success) if attempt_result: break else: print('Failed on attempt %d. Trying again...' % j) # Make sure we don't fail too often if not attempt_result: raise TaskValidationError( "Too many failed demo runs. %d of %d demos failed." % (failed_demos, demos)) else: print('Variation %d of task %s is good!' % (i, task.get_name())) if test_demos: print('%d of %d demos were successful.' % (demos - failed_demos, demos)) def run_demos(variation_num): fails = 0 for dr in range(demos): try: scene.reset() desc = scene.init_episode(variation_num, max_attempts=10) if not isinstance(desc, list) or len(desc) <= 0: raise TaskValidationError( "The method 'init_variation' should return a list of " "string descriptions.") if test_demos: demo = scene.get_demo(record=True) assert len(demo) > 0 except DemoError as e: fails += 1 print(e) except Exception as e: # TODO: check that we don't fall through all of these cases fails += 1 print(e) return fails variations_to_test = [variation] if variation < 0: variations_to_test = list( range(np.minimum(variation_count, max_variations))) # Task set-up scene.init_task() [variation_smoke(i) for i in variations_to_test]
class EnvironmentImpl(Environment): """Each environment has a scene.""" @staticmethod def all_task_names(): return tuple(o[0] for o in getmembers(tasks) if isclass(o[1])) def __init__(self, task_name: str, obs_config: ObservationConfig = ObservationConfig(task_low_dim_state=True), action_mode: ActionMode = ActionMode(), arm_name: str = "Panda", gripper_name: str = "Panda_gripper"): super(EnvironmentImpl, self).__init__(task_name) self._arm_name = arm_name self._gripper_name = gripper_name self._action_mode = action_mode self._obs_config = obs_config # TODO: modify the task/robot/arm/gripper to support early instantiation before v-rep launched self._task = None self._pyrep = None self._robot = None self._scene = None self._variation_number = 0 self._reset_called = False self._prev_ee_velocity = None self._update_info_dict() def init(self, display=False): if self._pyrep is not None: self.finalize() with suppress_std_out_and_err(): self._pyrep = PyRep() # TODO: TTT_FILE should be defined by robot, but now robot depends on launched pyrep self._pyrep.launch(join(DIR_PATH, TTT_FILE), headless=not display) self._pyrep.set_simulation_timestep(0.005) # TODO: Load arm and gripper from name self._robot = Robot(Panda(), PandaGripper()) self._scene = Scene(self._pyrep, self._robot, self._obs_config) self._set_arm_control_action() # Str comparison because sometimes class comparison doesn't work. if self._task is not None: self._task.unload() self._task = self._get_class_by_name(self._task_name, tasks)(self._pyrep, self._robot) self._scene.load(self._task) self._pyrep.start() def finalize(self): with suppress_std_out_and_err(): self._pyrep.shutdown() self._pyrep = None def reset(self, random: bool = True) -> StepDict: logging.info('Resetting task: %s' % self._task.get_name()) self._scene.reset() try: # TODO: let desc be constant desc = self._scene.init_episode(self._variation_number, max_attempts=MAX_RESET_ATTEMPTS, randomly_place=random) except (BoundaryError, WaypointError) as e: raise TaskEnvironmentError( 'Could not place the task %s in the scene. This should not ' 'happen, please raise an issues on this task.' % self._task.get_name()) from e ctr_loop = self._robot.arm.joints[0].is_control_loop_enabled() locked = self._robot.arm.joints[0].is_motor_locked_at_zero_velocity() self._robot.arm.set_control_loop_enabled(False) self._robot.arm.set_motor_locked_at_zero_velocity(True) self._reset_called = True self._robot.arm.set_control_loop_enabled(ctr_loop) self._robot.arm.set_motor_locked_at_zero_velocity(locked) # Returns a list o f descriptions and the first observation return {'s': self._scene.get_observation().get_low_dim_data(), "opt": desc} def step(self, last_step: StepDict) -> (StepDict, bool): # returns observation, reward, done, info if not self._reset_called: raise RuntimeError("Call 'reset' before calling 'step' on a task.") assert 'a' in last_step, "Key 'a' for action not in last_step, maybe you passed a wrong dict ?" # action should contain 1 extra value for gripper open close state arm_action = np.array(last_step['a'][:-1]) ee_action = last_step['a'][-1] current_ee = (1.0 if self._robot.gripper.get_open_amount()[0] > 0.9 else 0.0) if ee_action > 0.0: ee_action = 1.0 elif ee_action < -0.0: ee_action = 0.0 if self._action_mode.arm == ArmActionMode.ABS_JOINT_VELOCITY: self._assert_action_space(arm_action, (len(self._robot.arm.joints),)) self._robot.arm.set_joint_target_velocities(arm_action) elif self._action_mode.arm == ArmActionMode.DELTA_JOINT_VELOCITY: self._assert_action_space(arm_action, (len(self._robot.arm.joints),)) cur = np.array(self._robot.arm.get_joint_velocities()) self._robot.arm.set_joint_target_velocities(cur + arm_action) elif self._action_mode.arm == ArmActionMode.ABS_JOINT_POSITION: self._assert_action_space(arm_action, (len(self._robot.arm.joints),)) self._robot.arm.set_joint_target_positions(arm_action) elif self._action_mode.arm == ArmActionMode.DELTA_JOINT_POSITION: self._assert_action_space(arm_action, (len(self._robot.arm.joints),)) cur = np.array(self._robot.arm.get_joint_positions()) self._robot.arm.set_joint_target_positions(cur + arm_action) elif self._action_mode.arm == ArmActionMode.ABS_EE_POSE: self._assert_action_space(arm_action, (7,)) self._ee_action(list(arm_action)) elif self._action_mode.arm == ArmActionMode.DELTA_EE_POSE: self._assert_action_space(arm_action, (7,)) a_x, a_y, a_z, a_qx, a_qy, a_qz, a_qw = arm_action x, y, z, qx, qy, qz, qw = self._robot.arm.get_tip().get_pose() new_rot = Quaternion(a_qw, a_qx, a_qy, a_qz) * Quaternion(qw, qx, qy, qz) qw, qx, qy, qz = list(new_rot) new_pose = [a_x + x, a_y + y, a_z + z] + [qx, qy, qz, qw] self._ee_action(list(new_pose)) elif self._action_mode.arm == ArmActionMode.ABS_EE_VELOCITY: self._assert_action_space(arm_action, (7,)) pose = self._robot.arm.get_tip().get_pose() new_pos = np.array(pose) + (arm_action * DT) self._ee_action(list(new_pos)) elif self._action_mode.arm == ArmActionMode.DELTA_EE_VELOCITY: self._assert_action_space(arm_action, (7,)) if self._prev_ee_velocity is None: self._prev_ee_velocity = np.zeros((7,)) self._prev_ee_velocity += arm_action pose = self._robot.arm.get_tip().get_pose() pose = np.array(pose) new_pose = pose + (self._prev_ee_velocity * DT) self._ee_action(list(new_pose)) elif self._action_mode.arm == ArmActionMode.ABS_JOINT_TORQUE: self._assert_action_space(arm_action, (len(self._robot.arm.joints),)) self._torque_action(arm_action) elif self._action_mode.arm == ArmActionMode.DELTA_JOINT_TORQUE: cur = np.array(self._robot.arm.get_joint_forces()) new_action = cur + arm_action self._torque_action(new_action) else: raise RuntimeError('Unrecognised action mode.') if current_ee != ee_action: done = False while not done: done = self._robot.gripper.actuate(ee_action, velocity=0.04) self._pyrep.step() self._task.step() if ee_action == 0.0: # If gripper close action, the check for grasp. for g_obj in self._task.get_graspable_objects(): self._robot.gripper.grasp(g_obj) else: # If gripper opem action, the check for ungrasp. self._robot.gripper.release() self._scene.step() success, terminate = self._task.success() last_step['r'] = int(success) next_step = {'s': self._scene.get_observation().get_low_dim_data(), "opt": None} return last_step, next_step, terminate def name(self) -> str: return self._task_name # ------------- private methods ------------- # def _update_info_dict(self): # update info dict self._info["action mode"] = self._action_mode self._info["observation mode"] = self._obs_config # TODO: action dim should related to robot, not action mode, here we fixed it temporally self._info["action dim"] = (8,) self._info["action low"] = np.zeros(self._info["action dim"], dtype=np.float32) - 1. self._info["action high"] = np.zeros(self._info["action dim"], dtype=np.float32) + 1. self._info["state dim"] = (73,) self._info["state low"] = np.zeros(self._info["state dim"], dtype=np.float32) - 100. self._info["state high"] = np.zeros(self._info["state dim"], dtype=np.float32) + 100. self._info["reward low"] = -np.inf self._info["reward high"] = np.inf def _set_arm_control_action(self): self._robot.arm.set_control_loop_enabled(True) if self._action_mode.arm in (ArmActionMode.ABS_JOINT_VELOCITY, ArmActionMode.DELTA_JOINT_VELOCITY): self._robot.arm.set_control_loop_enabled(False) self._robot.arm.set_motor_locked_at_zero_velocity(True) elif self._action_mode.arm in (ArmActionMode.ABS_JOINT_POSITION, ArmActionMode.DELTA_JOINT_POSITION, ArmActionMode.ABS_EE_POSE, ArmActionMode.DELTA_EE_POSE, ArmActionMode.ABS_EE_VELOCITY, ArmActionMode.DELTA_EE_VELOCITY): self._robot.arm.set_control_loop_enabled(True) elif self._action_mode.arm in (ArmActionMode.ABS_JOINT_TORQUE, ArmActionMode.DELTA_JOINT_TORQUE): self._robot.arm.set_control_loop_enabled(False) else: raise RuntimeError('Unrecognised action mode.') def sample_variation(self) -> int: self._variation_number = np.random.randint(0, self._task.variation_count()) return self._variation_number def _assert_action_space(self, action, expected_shape): if np.shape(action) != expected_shape: raise RuntimeError( 'Expected the action shape to be: %s, but was shape: %s' % ( str(expected_shape), str(np.shape(action)))) def _torque_action(self, action): self._robot.arm.set_joint_target_velocities([(TORQUE_MAX_VEL if t < 0 else -TORQUE_MAX_VEL) for t in action]) self._robot.arm.set_joint_forces(np.abs(action)) def _ee_action(self, action): try: joint_positions = self._robot.arm.solve_ik(action[:3], quaternion=action[3:]) self._robot.arm.set_joint_target_positions(joint_positions) except IKError as e: raise InvalidActionError("Could not find a path.") from e self._pyrep.step() @staticmethod def _get_class_by_name(class_name: str, model: ModuleType) -> TaskClass: all_class_dict = {} for o in getmembers(model): if isclass(o[1]): all_class_dict[o[0]] = o[1] if class_name not in all_class_dict: raise NotImplementedError(f"No class {class_name} found in {model.__name__} !") return all_class_dict[class_name]