Beispiel #1
0
    def reset(self):
        """Reset."""
        if not self._done and self._num_steps > 0:
            for obs in self.observations:
                obs.on_episode_end()
            for reward_fn in self.reward_fns:
                reward_fn.on_episode_end()

        self._num_steps = 0
        self._episode_reward = 0.0
        self._done = False

        if self.config.MAX_STEPS is not None:
            if self.config.MAX_STEPS == 0:
                self._done = True

        if self.is_simulation:
            self.simulator.reset()
            self.simulator.start()

        self._reset()

        for obs in self.observations:
            obs.on_episode_start()
        for reward_fn in self.reward_fns:
            reward_fn.on_episode_start()

        logger.info('episode: %d', self.num_episodes)

        self._obs_data = None
        self._prev_obs_data = None
        self._obs_step = None

        return self.get_observation()
Beispiel #2
0
def convert_wrl_to_obj(wrl_paths, output_dir, body_name=''):
    """Convert a WRL files into .obj files using meshconv.

    Args:
        wrl_paths: List of paths to the input WRL files.
        output_dir: Output directory.
        body_name: Name of the body.

    Returns:
        obj_filenames: List of filenames of the output OBJ files.
    """
    num_pieces = len(wrl_paths)
    obj_filenames = []

    for i, wrl_path in enumerate(wrl_paths):
        basename = '%s_vhacd_%d_of_%d' % (body_name, i, num_pieces)
        filename = '%s.obj' % (basename)
        obj_filenames.append(filename)
        obj_path = os.path.join(output_dir, basename)

        command = MESHCONV_COMMAND.format(input_path=wrl_path,
                                          output_path=obj_path)
        logger.info(command)
        os.system(command)

    return obj_filenames
Beispiel #3
0
    def __call__(self, data):
        """Call function.

        Args:
            data: The input data.
        """
        # Create a file for saving the episode data.
        if self._num_entries_this_file == 0:
            if self._use_random_name:
                timestamp = time_utils.get_timestamp_as_string()
            else:
                timestamp = '%06d' % (self._num_files)
            filename = 'data_%s.pickle' % (timestamp)
            self._output_path = os.path.join(self._output_dir, filename)
            self._num_files += 1
            if self._file:
                self._file.close()

            self._file = open(self._output_path, 'wb')

        # Append the episode to the file.
        logger.info('Saving data to file %s (%d / %d)...', self._output_path,
                    self._num_entries_this_file, self._num_entries_per_file)
        num_entries = self.write(data)

        # Update the cursor.
        self._num_entries_this_file += num_entries
        self._num_entries_this_file %= self._num_entries_per_file
Beispiel #4
0
def main():
    args = parse_args()

    if args.input_pattern[-4:] != '.obj':
        input_pattern = '%s.obj' % (args.input_pattern)
    else:
        input_pattern = args.input_pattern

    input_paths = glob.glob(input_pattern)
    logger.info('Found %d .obj files at %s.', len(input_paths), input_pattern)

    for i, input_path in enumerate(input_paths):
        logger.info('Processing object %d / %d.', i, len(input_paths))

        output_dir = input_path.replace('textured.obj', '')

        if args.decompose:
            process_object(input_path,
                           output_dir=output_dir,
                           rgba=args.rgba,
                           scale=args.scale,
                           mass=args.mass,
                           density=args.density)
        else:
            create_urdf(input_path,
                        output_dir=output_dir,
                        rgba=args.rgba,
                        scale=args.scale,
                        mass=args.mass)
Beispiel #5
0
    def _sample(self, position, body_mask, num_episodes, num_steps):
        num_bodies = int(np.sum(body_mask))
        body_id = int(num_episodes) % int(num_bodies)

        position = position[:num_bodies]
        target_position = position[body_id:body_id+1]

        base_angle = (num_episodes * SEED) % (2 * np.pi)

        if num_steps == 0:
            self.last_end = None

        for i in range(self.max_attemps):

            start = np.random.uniform(-1., 1., [2])

            delta_angle = np.random.uniform(-0.25 * np.pi, 0.25 * np.pi)
            angle = base_angle + delta_angle
            # angle = base_angle

            motion = [1.0 * np.cos(angle), 1.0 * np.sin(angle)]
            motion = np.array(motion, dtype=np.float32)
            motion += np.random.uniform(-0.3, 0.3, [2])
            motion = np.clip(motion, -1.0, 1.0)

            waypoints = self.get_waypoints(start, motion)

            # Check if is_safe.
            is_safe = self.is_waypoint_clear(
                waypoints[0], None, position, self.start_margin)
            if not is_safe:
                continue

            # Check if is_effective.
            is_effective = not self.is_waypoint_clear(
                waypoints[0],
                waypoints[1],
                target_position,
                self.motion_margin)

            if not is_effective:
                continue

            if is_effective and is_safe:
                x = ((waypoints[1][0] - self.cspace_offset[0]) /
                     (self.cspace_range[0]))
                y = ((waypoints[1][1] - self.cspace_offset[1]) /
                     (self.cspace_range[1]))
                self.last_end = np.asarray([x, y])
                break

        if i == self.max_attemps - 1:
            logger.info('HeuristicSampler did not find a good sample.')

        start = np.array(start, dtype=np.float32)
        motion = np.array(motion, dtype=np.float32)
        action = np.concatenate([start, motion], axis=-1)
        return action
Beispiel #6
0
def main():
    args = parse_args()

    logger.info('Creating the FrankaPanda command line client...')
    franka_panda_cli = FrankaPandaCLI(args.mode, args.env_config, args.debug,
                                      args.assets_dir)

    logger.info('Running the Franka_Panda command line client...')
    franka_panda_cli.start()
Beispiel #7
0
def main():
    args = parse_args()

    logger.info('Creating the Sawyer command line client...')
    sawyer_cli = SawyerCLI(args.mode, args.env_config, args.debug,
                           args.assets_dir)

    logger.info('Running the Sawyer command line client...')
    sawyer_cli.start()
Beispiel #8
0
    def _reset(self):
        """Reset."""
        observations = super(PushEnv, self)._reset()

        self._reset_camera(
            self.camera,
            intrinsics=self.config.KINECT2.DEPTH.INTRINSICS,
            translation=self.config.KINECT2.DEPTH.TRANSLATION,
            rotation=self.config.KINECT2.DEPTH.ROTATION,
            intrinsics_noise=self.config.KINECT2.DEPTH.INTRINSICS_NOISE,
            translation_noise=self.config.KINECT2.DEPTH.TRANSLATION_NOISE,
            rotation_noise=self.config.KINECT2.DEPTH.ROTATION_NOISE)

        if self.use_recording:
            hostname = socket.gethostname().split('.')[0]
            self.recording_camera = self._create_camera(
                height=self.config.RECORDING.CAMERA.HEIGHT,
                width=self.config.RECORDING.CAMERA.WIDTH,
                intrinsics=self.config.RECORDING.CAMERA.INTRINSICS,
                translation=self.config.RECORDING.CAMERA.TRANSLATION,
                rotation=self.config.RECORDING.CAMERA.ROTATION)

            recording_tmp_dir = os.path.join('/tmp', 'recording')
            if not os.path.exists(recording_tmp_dir):
                os.makedirs(recording_tmp_dir)

            if self.task_name is None:
                recording_output_dir = os.path.join(
                    self.config.RECORDING.OUTPUT_DIR, 'data_collection')
            else:
                recording_output_dir = os.path.join(
                    self.config.RECORDING.OUTPUT_DIR,
                    '%s_layout%02d' % (self.task_name, self.layout_id))

            if not os.path.exists(recording_output_dir):
                logger.info('Saving recorded videos to %s ...',
                            recording_output_dir)
                os.makedirs(recording_output_dir)

            if self.video_writer is not None:
                self.video_writer.release()
                shutil.copyfile(self.recording_tmp_path,
                                self.recording_output_path)

            name = '%s_%s.avi' % (hostname,
                                  time_utils.get_timestamp_as_string())
            resolution = (self.config.RECORDING.CAMERA.WIDTH,
                          self.config.RECORDING.CAMERA.HEIGHT)
            self.recording_tmp_path = os.path.join(recording_tmp_dir, name)
            self.recording_output_path = os.path.join(recording_output_dir,
                                                      name)
            self.video_writer = cv2.VideoWriter(
                self.recording_tmp_path, cv2.VideoWriter_fourcc(*'XVID'),
                self.config.RECORDING.FPS, resolution)

        return observations
Beispiel #9
0
    def __init__(self, time_step=1e-3, use_visualizer=True, worker_id=0):
        """
        Initialization function.

        Args:
            time_step: The time step of the simulation. Run real-time
                simulation if it is set to None.
            use_visualizer: If use the visualizer.
            worker_id: The key of the simulation client.
        """
        logger.info('pybullet API Version: %s.' % (pybullet.getAPIVersion()))

        if use_visualizer:
            self._uid = pybullet.connect(pybullet.GUI)
            pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_SHADOWS, 1)
            pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_GUI, 0)
            assert worker_id == 0
            logger.info('Connected client %d to GUI.', self._uid)
        else:
            logger.info('Use worker_id %d for the simulation.', worker_id)
            self._uid = pybullet.connect(pybullet.DIRECT, key=worker_id)
            logger.info('Connected client %d to DIRECT.', self._uid)

        self._time_step = time_step
        self._start_time = None
        self._num_steps = None

        self._gravity = None
Beispiel #10
0
def collect(tf_env,
            tf_policy,
            output_dir,
            checkpoint=None,
            num_iterations=500000,
            episodes_per_file=500,
            summary_interval=1000):
    """A simple train and eval for SAC."""
    if not os.path.isdir(output_dir):
        logger.info('Making output directory %s...', output_dir)
        os.makedirs(output_dir)

    global_step = tf.compat.v1.train.get_or_create_global_step()
    with tf.compat.v2.summary.record_if(
            lambda: tf.math.equal(global_step % summary_interval, 0)):

        # Make the replay buffer.
        replay_buffer = tfrecord_replay_buffer.TFRecordReplayBuffer(
            data_spec=tf_policy.trajectory_spec,
            experiment_id='exp',
            file_prefix=os.path.join(output_dir, 'data'),
            episodes_per_file=episodes_per_file)
        replay_observer = [replay_buffer.add_batch]

        collect_policy = tf_policy
        collect_op = dynamic_step_driver.DynamicStepDriver(
            tf_env, collect_policy, observers=replay_observer,
            num_steps=1).run()

        with tf.compat.v1.Session() as sess:
            # Initialize training.
            try:
                common.initialize_uninitialized_variables(sess)
            except Exception:
                pass

            # Restore checkpoint.
            if checkpoint is not None:
                if os.path.isdir(checkpoint):
                    train_dir = os.path.join(checkpoint, 'train')
                    checkpoint_path = tf.train.latest_checkpoint(train_dir)
                else:
                    checkpoint_path = checkpoint

                restorer = tf.train.Saver(name='restorer')
                restorer.restore(sess, checkpoint_path)

            collect_call = sess.make_callable(collect_op)
            for _ in range(num_iterations):
                collect_call()
Beispiel #11
0
    def _sample_body_poses(self, num_samples, body_config, max_attemps=32):
        """Sample body poses.

        Args:
            num_samples: Number of samples.
            body_config: Configuration of the body.
            max_attemps: Maximum number of attemps to find a feasible
                placement.

        Returns:
            List of poses.
        """
        while True:
            movable_poses = []

            for i in range(num_samples):
                num_attemps = 0
                is_valid = False
                while not is_valid and num_attemps <= max_attemps:
                    pose = Pose.uniform(x=body_config.POSE.X,
                                        y=body_config.POSE.Y,
                                        z=body_config.POSE.Z,
                                        roll=body_config.POSE.ROLL,
                                        pitch=body_config.POSE.PITCH,
                                        yaw=body_config.POSE.YAW)

                    # Check if the new pose is distant from other bodies.
                    is_valid = True
                    for other_pose in movable_poses:
                        dist = np.linalg.norm(pose.position[:2] -
                                              other_pose.position[:2])

                        if dist < body_config.MARGIN:
                            is_valid = False
                            num_attemps += 1
                            break

                if not is_valid:
                    logger.info(
                        'Cannot find the placement of body %d. '
                        'Start re-sampling.', i)
                    break
                else:
                    movable_poses.append(pose)

            if i == num_attemps:
                break

        return movable_poses
Beispiel #12
0
    def _reset_scene(self):
        """Reset the scene in simulation or the real world.
        """
        super(Grasp4DofEnv, self)._reset_scene()

        # Reload graspable object.
        if self.config.SIM.GRASPABLE.RESAMPLE_N_EPISODES:
            if (self.num_episodes %
                    self.config.SIM.GRASPABLE.RESAMPLE_N_EPISODES == 0):
                self.graspable_path = None

        if self.graspable_path is None:
            if self.config.SIM.GRASPABLE.USE_RANDOM_SAMPLE:
                self.graspable_path = random.choice(self.all_graspable_paths)
            else:
                self.graspable_index = ((self.graspable_index + 1) %
                                        len(self.all_graspable_paths))
                self.graspable_path = (
                    self.all_graspable_paths[self.graspable_index])

        pose = Pose.uniform(x=self.config.SIM.GRASPABLE.POSE.X,
                            y=self.config.SIM.GRASPABLE.POSE.Y,
                            z=self.config.SIM.GRASPABLE.POSE.Z,
                            roll=self.config.SIM.GRASPABLE.POSE.ROLL,
                            pitch=self.config.SIM.GRASPABLE.POSE.PITCH,
                            yaw=self.config.SIM.GRASPABLE.POSE.YAW)
        pose = get_transform(source=self.table_pose).transform(pose)
        scale = np.random.uniform(*self.config.SIM.GRASPABLE.SCALE)
        logger.info('Loaded the graspable object from %s with scale %.2f...',
                    self.graspable_path, scale)
        self.graspable = self.simulator.add_body(self.graspable_path,
                                                 pose,
                                                 scale=scale,
                                                 name=GRASPABLE_NAME)
        logger.debug('Waiting for graspable objects to be stable...')
        self.simulator.wait_until_stable(self.graspable)

        # Reset camera.
        self._reset_camera(
            self.camera,
            intrinsics=self.config.KINECT2.DEPTH.INTRINSICS,
            translation=self.config.KINECT2.DEPTH.TRANSLATION,
            rotation=self.config.KINECT2.DEPTH.ROTATION,
            intrinsics_noise=self.config.KINECT2.DEPTH.INTRINSICS_NOISE,
            translation_noise=self.config.KINECT2.DEPTH.TRANSLATION_NOISE,
            rotation_noise=self.config.KINECT2.DEPTH.ROTATION_NOISE)
Beispiel #13
0
def run_convex_decomposition(input_path,
                             output_path='output.wrl',
                             log_path='log.txt'):
    """Run the convex decomposition with V-HACD.

    Args:
        input_path: Path to the input OBJ file.
        output_path: Path to the output WRL file.
        log_path: Path to the log file.
    """
    # TODO(kuanfang): Temporally remove the constraints of number of groups for
    # simplicity, will add it back if we find it necessary in the future.
    command = VHACD_COMMAND.format(input_path=input_path,
                                   output_path=output_path,
                                   log_path=log_path)
    logger.info(command)
    os.system(command)
Beispiel #14
0
def parse_config_files_and_bindings(args):
    if args.env_config is None:
        env_config = None
    else:
        env_config = YamlConfig(args.env_config).as_easydict()

    if args.policy_config is None:
        policy_config = None
    else:
        policy_config = YamlConfig(args.policy_config).as_easydict()

    if args.config_bindings is not None:
        parsed_bindings = ast.literal_eval(args.config_bindings)
        logger.info('Config Bindings: %r', parsed_bindings)
        env_config.update(parsed_bindings)
        policy_config.update(parsed_bindings)

    return env_config, policy_config
Beispiel #15
0
    def _reset_scene(self):
        """Reset the scene in simulation or the real world."""
        super(PushEnv, self)._reset_scene()

        # Simulation.
        if self.is_simulation:
            self.num_movable_bodies = np.random.randint(
                low=self.min_movable_bodies, high=self.max_movable_bodies + 1)

            self._load_movable_bodies()

            if self.layouts is not None:
                layout = self.layouts[self.layout_id]
                self._load_tiles(layout.region,
                                 layout.size,
                                 layout.offset,
                                 z_offset=0.001 - 0.025,
                                 rgba=layout.region_rgba)
                if layout.goal is not None:
                    self._load_tiles(layout.goal,
                                     layout.size,
                                     layout.offset,
                                     z_offset=0.0015 - 0.025,
                                     rgba=layout.goal_rgba)
        else:
            self.num_movable_bodies = self.max_movable_bodies
            logger.info('Assume there are %d movable objects on the table.',
                        self.num_movable_bodies)

        self.movable_body_mask = np.array(
            [1] * self.num_movable_bodies + [0] *
            (self.max_movable_bodies - self.num_movable_bodies))

        # Attributes
        self.attributes = {
            'num_episodes': self.num_episodes,
            'num_steps': self.num_steps,
            'layout_id': self.layout_id,
            'movable_body_mask': self.movable_body_mask,
            'is_safe': True,
            'is_effective': True,
        }
Beispiel #16
0
    def __init__(self, output_dir, num_entries_per_file, use_random_name=True):
        """Initialize.

        Args:
            output_dir: Output directory.
            num_entries_per_file: Number of entries in each file.
            use_random_name: Use randomly generated name if True.
        """
        self._output_dir = output_dir
        self._num_entries_per_file = num_entries_per_file
        self._use_random_name = use_random_name

        self._file = None
        self._output_path = None
        self._num_files = 0
        self._num_entries_this_file = 0

        if not os.path.isdir(output_dir):
            logger.info('Making output directory %s...', output_dir)
            os.makedirs(output_dir)
Beispiel #17
0
def parse_config_files_and_bindings(args):
    """Parse the config files and the bindings.

    Args:
        args: The arguments.

    Returns:
        env_config: Environment configuration.
        policy_config: Policy configuration.
    """
    if args.env_config is None:
        env_config = dict()
    else:
        env_config = YamlConfig(args.env_config).as_easydict()

    if args.policy_config is None:
        policy_config = dict()
    else:
        policy_config = YamlConfig(args.policy_config).as_easydict()

    if args.config_bindings is not None:
        parsed_bindings = ast.literal_eval(args.config_bindings)
        logger.info('Config Bindings: %r', parsed_bindings)
        env_config.update(parsed_bindings)
        policy_config.update(parsed_bindings)

    logger.info('Environment Config:')
    pprint.pprint(env_config)
    logger.info('Policy Config:')
    pprint.pprint(policy_config)

    return env_config, policy_config
Beispiel #18
0
    def step(self, action):
        """Take a step.

        See parent class.
        """
        observation, reward, done, info = super(PushEnv, self).step(action)

        if done and reward >= self.config.SUCCESS_THRESH:
            self.num_successes += 1
            self.num_successes_by_step[self._num_steps] += 1

        if done:
            logger.info(
                'num_successes: %d, success_rate: %.3f',
                self.num_successes,
                self.num_successes / float(self._num_episodes + 1e-14),
            )
            text = ('num_successes_by_step: ' +
                    ', '.join(['%d'] * int(self.config.MAX_STEPS + 1)))

            logger.info(text, *self.num_successes_by_step)

            logger.info(
                'num_total_steps %d, '
                'unsafe: %.3f, ineffective: %.3f, useful: %.3f',
                self.num_total_steps,
                self.num_unsafe / float(self.num_total_steps + 1e-14),
                self.num_ineffective / float(self.num_total_steps + 1e-14),
                self.num_useful / float(self.num_total_steps + 1e-14))

        return observation, reward, done, info
Beispiel #19
0
    def step(self, action):
        """Take a step.

        See parent class.
        """
        if self._done:
            raise ValueError('The environment is done. Forget to reset?')

        self._execute_action(action)
        self._num_steps += 1

        observation = self.get_observation()

        reward, termination = self.get_reward()

        self._episode_reward += reward
        self._done = (self._done or termination)

        if self.config.MAX_STEPS is not None:
            if self.num_steps >= self.config.MAX_STEPS:
                self._done = True

        logger.info('step: %d, reward: %.3f', self.num_steps, reward)

        if self._done:
            self._num_episodes += 1
            self._total_reward += self.episode_reward
            logger.info(
                'episode_reward: %.3f, avg_episode_reward: %.3f',
                self.episode_reward,
                float(self.total_reward) / (self._num_episodes + 1e-14),
            )

        if self.debug:
            self.render()

        return observation, reward, self._done, None
Beispiel #20
0
def main():
    args = parse_args()

    if os.path.isdir(args.log_dir):
        logger.warn('Output directory %s already exists.',
                    os.path.abspath(args.log_dir))

    processes = []
    for key in range(args.num_copies):
        logger.info('Starting copy %d / %d...', key, args.num_copies)

        hostname = socket.gethostname()
        hostname = hostname.split('.')[0]
        log_dir = os.path.abspath(args.log_dir)
        log_dir = os.path.join(log_dir, 'logs')
        if not os.path.isdir(log_dir):
            logger.info('Making output directory %s...', log_dir)
            os.makedirs(log_dir)

        log_path = os.path.join(log_dir, '%s_%02d.log' % (hostname, key))

        command = '%s >> %s' % (args.command, log_path)
        logger.info('Run the command: %s', command)
        process = subprocess.Popen(command, shell=True)
        processes.append(process)

    def cleanup():
        for ind, process in enumerate(processes):
            process.kill()
            logger.info('Killed process %d.', ind)

    atexit.register(cleanup)

    logger.info('All copies have been started. Running episode generation...')

    while True:
        pass
Beispiel #21
0
def process_object(input_path,
                   output_dir,
                   rgba,
                   scale=1.0,
                   mass=0.1,
                   density=None):
    """Process a single object.

    Args:
        input_path: The path to the input .obj file.
        output_dir: The directory of the processed model, including the .urdf
            file, and the decomposed .obj files.
        rgba: The color of the visual model.
        scale: The scale of the model.
        mass: The mass of the whole object.
        density: The density of the whole object.
    """
    body_name = os.path.splitext(os.path.basename(input_path))[0]

    # Copy the mesh(visual model) to the output directory (with the URDF file).
    # logger.info('Copying the mesh from %s to %s...'
    #             % (input_path, output_dir))
    # command = 'cp %s %s' % (input_path, output_dir)
    # logger.info(command)
    # os.system(command)

    if output_dir is None:
        output_dir = os.path.dirname(input_path)

    output_dir = os.path.join(output_dir, body_name)

    if not os.path.isdir(output_dir):
        os.makedirs(output_dir)

    tmp_dir = os.path.join(output_dir, 'tmp')
    if not os.path.isdir(tmp_dir):
        os.mkdir(tmp_dir)

    tmp_output_path = os.path.join(tmp_dir, 'output.wrl')

    # Run V-HACD to generate the collision meshes (as .wrl files).
    logger.info('Running the V-HACD convex decomposition...')
    log_path = os.path.join('./meshes', 'log.txt')
    run_convex_decomposition(input_path=input_path,
                             output_path=tmp_output_path,
                             log_path=log_path)

    # Split the V-HACD results (as the .wrl file) into pieces.
    logger.info('Splitting the V-HACD results at: %s...' % (tmp_output_path))
    wrl_paths = split_wrl_file(tmp_output_path, tmp_dir=tmp_dir)

    # Convert each .wrl file (each piece of V-HACD results) into .obj file.
    logger.info('Converting the split V-HACD results to .obj format.')
    vhacd_filenames = convert_wrl_to_obj(wrl_paths, output_dir, body_name)

    # Read the mesh and compute the mesh properties.
    logger.info('Reading the obj file at: %s...' % (input_path))
    vertices, triangles = mesh_utils.read_from_obj(input_path)
    centroid = mesh_utils.compute_centroid(vertices, triangles)
    volume = mesh_utils.compute_volume(vertices, triangles)
    surface_area = mesh_utils.compute_surface_area(vertices, triangles)

    if mass is None:
        raise ValueError('The volume is problematic. Do not use the density.')
        mass = volume * density
        # mass = surface_area * args.density
    else:
        mass = mass

    logger.info('Object Information: \n'
                '\tbody_name: %s\n'
                '\tcentroid: %s\n'
                '\tvolume: %f\n'
                '\tsurface_area: %f\n'
                '\tmass: %f\n' %
                (body_name, centroid, volume, surface_area, mass))

    # Create the URDF file.
    urdf_path = os.path.join(output_dir, body_name + '.urdf')
    logger.info('Writing the URDF files at: %s...' % (urdf_path))

    # Create the visual meshes.
    with open('./tools/templates/visual_template.xml', 'r') as f:
        visual_template = f.read()

    visual_text = ''
    for vhacd_filename in vhacd_filenames:
        visual_text += visual_template.format(filename=vhacd_filename,
                                              scale=scale)

    # Create the collision meshes.
    with open('./tools/templates/collision_template.xml', 'r') as f:
        collision_template = f.read()

    collision_text = ''
    for vhacd_filename in vhacd_filenames:
        collision_text += collision_template.format(filename=vhacd_filename,
                                                    scale=scale)

    if rgba is None:
        rgba = random_rgba()

    # Write to the URDF file.
    with open('./tools/templates/urdf_template.xml', 'r') as f:
        urdf_template = f.read()

    with open(urdf_path, 'w') as f:
        urdf_text = urdf_template.format(body_name=body_name,
                                         mass=mass,
                                         ixx=1,
                                         iyy=1,
                                         izz=1,
                                         ixy=0,
                                         ixz=0,
                                         iyz=0,
                                         cx=centroid[0],
                                         cy=centroid[1],
                                         cz=centroid[2],
                                         visual=visual_text,
                                         collision=collision_text,
                                         rgba=rgba)

        f.write(urdf_text)

    # Clean up the temporal directory.
    logger.info('Removing the tmp folder...')
    command = 'rm -rf %s' % tmp_dir
    logger.info(command)
    os.system(command)
Beispiel #22
0
def main():
    args = parse_args()

    # Configuration.
    env_config, policy_config = parse_config_files_and_bindings(args)

    # Set the random seed.
    if args.seed is not None:
        random.seed(args.seed)
        np.random.seed(args.seed)

    # Simulator.
    if args.use_simulator:
        simulator = Simulator(worker_id=args.worker_id,
                              use_visualizer=bool(args.debug),
                              assets_dir=args.assets_dir)
    else:
        simulator = None

    # Environment.
    env_class = getattr(envs, args.env)
    env = env_class(simulator=simulator, config=env_config, debug=args.debug)

    # Policy.
    policy_class = getattr(policies, args.policy)
    policy = policy_class(env=env, config=policy_config)

    # Output directory.
    if args.output_dir is not None:
        hostname = socket.gethostname()
        hostname = hostname.split('.')[0]
        output_dir = os.path.abspath(args.output_dir)
        output_dir = os.path.join(output_dir, hostname, '%02d' % (args.key))
        if not os.path.isdir(output_dir):
            logger.info('Making output directory %s...', output_dir)
            os.makedirs(output_dir)

    # Generate and write episodes.
    logger.info('Start running...')
    env.reset()
    num_episodes_this_file = 0
    for episode_index, episode in generate_episodes(
            env,
            policy,
            num_steps=args.num_steps,
            num_episodes=args.num_episodes,
            timeout=args.timeout,
            debug=args.debug):

        if args.output_dir:
            # Create a file for saving the episode data.
            if num_episodes_this_file == 0:
                timestamp = time_utils.get_timestamp_as_string()
                filename = 'episodes_%s.hdf5' % (timestamp)
                output_path = os.path.join(output_dir, filename)
                logger.info('Created a new file %s...', output_path)

            # Append the episode to the file.
            logger.info('Saving episode %d to file %s (%d / %d)...',
                        episode_index, output_path, num_episodes_this_file,
                        args.num_episodes_per_file)

            with h5py.File(output_path, 'a') as fout:
                name = str(uuid.uuid4())
                group = fout.create_group(name)
                hdf5_utils.write_data_to_hdf5(group, episode)

        num_episodes_this_file += 1
        num_episodes_this_file %= args.num_episodes_per_file

        if args.pause:
            input('Press [Enter] to start a new episode.')
Beispiel #23
0
 def cleanup():
     for ind, process in enumerate(processes):
         process.kill()
         logger.info('Killed process %d.', ind)
Beispiel #24
0
    def _execute_action(self, action):  # NOQA
        """Execute the robot action.

        Args:
            action: A dictionary of mode and argument of the action.
        """
        self.attributes = {
            'num_episodes': self.num_episodes,
            'num_steps': self.num_steps,
            'layout_id': self.layout_id,
            'movable_body_mask': self.movable_body_mask,
            'is_safe': True,
            'is_effective': True,
        }

        waypoints = self._compute_all_waypoints(action)

        self.phase = 'initial'
        self.num_waypoints = 0
        self.interrupt = False
        self.start_status = self._get_movable_status()
        while (self.phase != 'done'):

            if self.is_simulation:
                self.simulator.step()

                if self.use_recording:
                    if (self.simulator.num_steps %
                            self.config.RECORDING.NUM_STEPS == 0):
                        self._record_screenshot()

                if not (self.simulator.num_steps % self.config.SIM.STEPS_CHECK
                        == 0):
                    continue

            # Phase transition.
            if self._is_phase_ready():
                self.phase = self._get_next_phase()
                if self.config.DEBUG and self.debug:
                    logger.info('phase: %s, num_waypoints: %d', self.phase,
                                self.num_waypoints)

                if self.is_simulation:
                    self.max_phase_steps = self.simulator.num_steps
                    if self.phase == 'motion':
                        self.max_phase_steps += (
                            self.config.SIM.MAX_MOTION_STEPS)
                    elif self.phase == 'offstage':
                        self.max_phase_steps += (
                            self.config.SIM.MAX_OFFSTAGE_STEPS)
                    else:
                        self.max_phase_steps += (
                            self.config.SIM.MAX_PHASE_STEPS)

                if self.phase == 'pre':
                    pose = waypoints[self.num_waypoints][0].copy()
                    pose.z = self.config.ARM.GRIPPER_SAFE_HEIGHT
                    self.robot.move_to_gripper_pose(pose)

                elif self.phase == 'start':
                    pose = waypoints[self.num_waypoints][0]
                    self.robot.move_to_gripper_pose(pose)

                elif self.phase == 'motion':
                    pose = waypoints[self.num_waypoints][1]
                    self.robot.move_to_gripper_pose(pose)

                elif self.phase == 'post':
                    self.num_waypoints += 1
                    pose = self.robot.end_effector.pose
                    pose.z = self.config.ARM.GRIPPER_SAFE_HEIGHT
                    self.robot.move_to_gripper_pose(pose)

                elif self.phase == 'offstage':
                    self.robot.move_to_joint_positions(
                        self.config.ARM.OFFSTAGE_POSITIONS)

            self.interrupt = False

            if self._check_singularity():
                self.interrupt = True

            if not self._check_safety():
                self.interrupt = True
                self.attributes['is_safe'] = False

            if self.interrupt:
                if self.phase == 'done':
                    self._done = True
                    break

        if self.is_simulation:
            self.simulator.wait_until_stable(self.movable_bodies)

        # Update attributes.
        self.end_status = self._get_movable_status()
        self.attributes['is_effective'] = self._check_effectiveness()

        self.num_total_steps += 1
        self.num_unsafe += int(not self.attributes['is_safe'])
        self.num_ineffective += int(not self.attributes['is_effective'])
        self.num_useful += int(self.attributes['is_safe']
                               and self.attributes['is_effective'])
Beispiel #25
0
    def _load_movable_bodies(self):
        """Load movable bodies."""
        assert self.simulator is not None

        is_valid = False
        while not is_valid:
            logger.info('Loading movable objects...')
            is_valid = True
            self.movable_bodies = []

            # Sample placements of the movable objects.
            is_target = False
            if self.layouts is None:
                movable_poses = self._sample_body_poses(
                    self.num_movable_bodies, self.movable_config)
            else:
                layout = self.layouts[self.layout_id]
                movable_poses = self._sample_body_poses_on_tiles(
                    self.num_movable_bodies, self.movable_config, layout)
                is_target = (layout.target is not None)

            for i in range(self.num_movable_bodies):

                if i == 0 and is_target:
                    path = random.choice(self.target_movable_paths)
                else:
                    path = random.choice(self.movable_paths)

                pose = movable_poses[i]
                scale = np.random.uniform(*self.movable_config.SCALE)
                name = 'movable_%d' % i

                # Add the body.
                body = self.simulator.add_body(path, pose, scale, name=name)

                if self.config.USE_RANDOM_RGBA:
                    r = np.random.uniform(0., 1.)
                    g = np.random.uniform(0., 1.)
                    b = np.random.uniform(0., 1.)
                    body.set_color(rgba=[r, g, b, 1.0], specular=[0, 0, 0])

                # Wait for the new body to be dropped onto the table.
                self.simulator.wait_until_stable(
                    body,
                    linear_velocity_threshold=0.1,
                    angular_velocity_threshold=0.1,
                    max_steps=500)

                # Change physical properties.
                mass = robot_env.get_config_value(self.movable_config.MASS)
                lateral_friction = robot_env.get_config_value(
                    self.movable_config.FRICTION)
                body.set_dynamics(mass=mass,
                                  lateral_friction=lateral_friction,
                                  rolling_friction=None,
                                  spinning_friction=None)
                self.movable_bodies.append(body)

            for body in self.movable_bodies:
                if body.position.z < self.table.position.z:
                    is_valid = False
                    break

            if not is_valid:
                logger.info('Invalid arrangement, reset the scene...')
                for i, body in enumerate(self.movable_bodies):
                    self.simulator.remove_body(body.name)

        logger.info('Waiting for movable objects to be stable...')
        self.simulator.wait_until_stable(self.movable_bodies)
Beispiel #26
0
def create_urdf(input_path, output_dir, rgba, scale=1.0, mass=0.1):
    """Process a single object.

    Args:
        input_path: The path to the input .obj file.
        output_dir: The directory of the processed model, including the .urdf
            file, and the decomposed .obj files.
        rgba: The color of the visual model.
        scale: The scale of the model.
        mass: The mass of the whole object.
    """
    body_name = os.path.splitext(os.path.basename(input_path))[0]
    body_path = '%s.obj' % (body_name)

    # Read the mesh and compute the mesh properties.
    logger.info('Reading the obj file at: %s...' % (input_path))
    vertices, triangles = mesh_utils.read_from_obj(input_path)
    centroid = mesh_utils.compute_centroid(vertices, triangles)
    volume = mesh_utils.compute_volume(vertices, triangles)
    surface_area = mesh_utils.compute_surface_area(vertices, triangles)

    logger.info('Object Information: \n'
                '\tbody_name: %s\n'
                '\tcentroid: %s\n'
                '\tvolume: %f\n'
                '\tsurface_area: %f\n'
                '\tmass: %f\n' %
                (body_name, centroid, volume, surface_area, mass))

    # Create the URDF file.
    if output_dir is None:
        output_dir = os.path.dirname(input_path)

    urdf_path = os.path.join(output_dir, body_name + '.urdf')
    logger.info('Writing the URDF files at: %s...' % (urdf_path))

    # Create the visual meshes.
    with open('./tools/templates/visual_template.xml', 'r') as f:
        visual_template = f.read()
        visual_text = visual_template.format(filename=body_path,
                                             scale=scale,
                                             cx=-centroid[0],
                                             cy=-centroid[1],
                                             cz=-centroid[2])

    # Create the collision meshes.
    with open('./tools/templates/collision_template.xml', 'r') as f:
        collision_template = f.read()
        collision_text = collision_template.format(filename=body_path,
                                                   scale=scale,
                                                   cx=-centroid[0],
                                                   cy=-centroid[1],
                                                   cz=-centroid[2])

    if rgba is None:
        rgba = random_rgba()

    # Write to the URDF file.
    with open('./tools/templates/urdf_template.xml', 'r') as f:
        urdf_template = f.read()

    with open(urdf_path, 'w') as f:
        urdf_text = urdf_template.format(
            body_name=body_name,
            mass=mass,
            ixx=1,
            iyy=1,
            izz=1,
            ixy=0,
            ixz=0,
            iyz=0,
            cx=0,  #centroid[0],
            cy=0,  #centroid[1],
            cz=0,  #centroid[2],
            visual=visual_text,
            collision=collision_text,
            rgba=rgba)

        f.write(urdf_text)
Beispiel #27
0
    def _sample_body_poses_on_tiles(self,
                                    num_samples,
                                    body_config,
                                    layout,
                                    safe_drop_height=0.2,
                                    max_attemps=32):
        """Sample tile poses on the tiles.

        Args:
            num_samples: Number of samples.
            body_config: Configuration of the body.
            layout: Configuration of the layout.
            safe_drop_height: Dropping height of the body.
            max_attemps: Maximum number of attemps to find a feasible
                placement.

        Returns:
            List of poses.
        """
        tile_size = layout.size
        tile_offset = layout.offset

        while True:
            movable_poses = []

            for i in range(num_samples):
                num_attemps = 0
                is_valid = False

                if i == 0 and layout.target is not None:
                    tile_config = layout.target
                else:
                    tile_config = layout.obstacle

                while not is_valid and num_attemps <= max_attemps:
                    num_tiles = len(tile_config)
                    tile_id = np.random.choice(num_tiles)
                    tile_center = tile_config[tile_id]
                    x_range = [
                        tile_offset[0] + (tile_center[0] - 0.5) * tile_size,
                        tile_offset[0] + (tile_center[0] + 0.5) * tile_size
                    ]
                    y_range = [
                        tile_offset[1] + (tile_center[1] - 0.5) * tile_size,
                        tile_offset[1] + (tile_center[1] + 0.5) * tile_size
                    ]
                    z = self.table_pose.position.z + safe_drop_height
                    pose = Pose.uniform(x=x_range,
                                        y=y_range,
                                        z=z,
                                        roll=[-np.pi, np.pi],
                                        pitch=[-np.pi / 2, np.pi / 2],
                                        yaw=[-np.pi, np.pi])

                    is_valid = True
                    for other_pose in movable_poses:
                        dist = np.linalg.norm(pose.position[:2] -
                                              other_pose.position[:2])

                        if dist < body_config.MARGIN:
                            is_valid = False
                            num_attemps += 1
                            break

                if not is_valid:
                    logger.info(
                        'Cannot find the placement of body %d. '
                        'Start re-sampling.', i)
                    break
                else:
                    movable_poses.append(pose)

            if i == num_attemps:
                break

        return movable_poses
Beispiel #28
0
    def get_observation(self):
        """Returns the observation data of the current step."""
        images = self.camera.frames()
        image = images['rgb']
        depth = images['depth']
        point_cloud = self.camera.deproject_depth_image(depth)

        # Crop.
        if self.crop_max is not None and self.crop_min is not None:
            crop_mask = np.logical_and(
                np.all(point_cloud >= self.crop_min, axis=-1),
                np.all(point_cloud <= self.crop_max, axis=-1))
            point_cloud = point_cloud[crop_mask]

        # Segment.
        if self.env.simulator:
            segmask = images['segmask']
            segmask = segmask.flatten()
            segmask = pc_utils.convert_segment_ids(segmask, self.body_ids)
            point_cloud = pc_utils.group_by_labels(point_cloud, segmask,
                                                   self.num_bodies,
                                                   self.num_points)
        else:
            point_cloud = pc_utils.remove_table(point_cloud)
            segmask = pc_utils.cluster(point_cloud,
                                       num_clusters=self.num_bodies,
                                       method='dbscan')
            point_cloud = point_cloud[segmask != -1]
            segmask = pc_utils.cluster(point_cloud,
                                       num_clusters=self.num_bodies)
            point_cloud = pc_utils.group_by_labels(point_cloud, segmask,
                                                   self.num_bodies,
                                                   self.num_points)

        # Confirm target.
        if self.confirm_target:
            # Click the target position.
            self.target_position = None
            self.depth = depth
            self.ax.cla()
            self.ax.imshow(image)
            logger.info('Please click the target object...')
            while self.target_position is None:
                plt.pause(1e-3)
            logger.info('Target Position: %r', self.target_position)

            # Exchange the target object with the first object.
            centers = np.mean(point_cloud, axis=1)
            dists = np.linalg.norm(centers -
                                   self.target_position[np.newaxis, :],
                                   axis=-1)
            target_id = dists.argmin()
            if target_id != 0:
                tmp = copy.deepcopy(point_cloud)
                point_cloud[0, :] = tmp[target_id, :]
                point_cloud[target_id, :] = tmp[0, :]

            # Show the segmented point cloud.
            pc_utils.show2d(point_cloud, self.camera, self.ax, image=image)

        return point_cloud
Beispiel #29
0
 def __del__(self):
     pybullet.disconnect(physicsClientId=self.uid)
     logger.info('Disconnected client %d to pybullet server.', self._uid)
Beispiel #30
0
    def _reset_scene(self):
        """Reset the scene in simulation or the real world.
        """

        # Configure debug visualizer
        if self._debug and self.is_simulation:
            visualizer_info = self.simulator.physics.get_debug_visualizer_info(['yaw', 'pitch', 'dist', 'target'])

            # Adjust the camera view to your own need.
            visualizer_info['dist'] = 1.5
            visualizer_info['yaw'] = 50
            visualizer_info['pitch'] = -20

            self.simulator.physics.reset_debug_visualizer(camera_distance=visualizer_info['dist'],
                                                         camera_yaw=visualizer_info['yaw'],
                                                         camera_pitch=visualizer_info['pitch'],
                                                         camera_target_position=visualizer_info['target'])
        
        super(FrankaPandaGraspEnv, self)._reset_scene()

        # Reload graspable object.
        if self.config.SIM.GRASPABLE.RESAMPLE_N_EPISODES:
            if (self.num_episodes %
                    self.config.SIM.GRASPABLE.RESAMPLE_N_EPISODES == 0):
                self.graspable_path = None

        if self.graspable_path is None:
            if self.config.SIM.GRASPABLE.USE_RANDOM_SAMPLE:
                self.graspable_path = random.choice(
                    self.all_graspable_paths)
            else:
                self.graspable_index = ((self.graspable_index + 1) %
                                        len(self.all_graspable_paths))
                self.graspable_path = (
                    self.all_graspable_paths[self.graspable_index])

        pose = Pose.uniform(x=self.config.SIM.GRASPABLE.POSE.X,
                            y=self.config.SIM.GRASPABLE.POSE.Y,
                            z=self.config.SIM.GRASPABLE.POSE.Z,
                            roll=self.config.SIM.GRASPABLE.POSE.ROLL,
                            pitch=self.config.SIM.GRASPABLE.POSE.PITCH,
                            yaw=self.config.SIM.GRASPABLE.POSE.YAW)
        pose = get_transform(source=self.table_pose).transform(pose)
        scale = np.random.uniform(*self.config.SIM.GRASPABLE.SCALE)
        logger.info('Loaded the graspable object from %s with scale %.2f...',
                    self.graspable_path, scale)
        self.graspable = self.simulator.add_body(self.graspable_path, pose, scale=scale, name=GRASPABLE_NAME, baseMass=0.1)
        # self.graspable = self.simulator.add_body(self.graspable_path, pose, scale=scale * 0.01, name=GRASPABLE_NAME, collisionFrameOrientation=[-0.5, -0.5, 0.5, 0.5], visualFrameOrientation=[-0.5, -0.5, 0.5, 0.5], baseMass=0.1)
        
        logger.debug('Waiting for graspable objects to be stable...')
        # Change some properties of the object compensating for
        # artifacts due to simulation
        self.table.set_dynamics(contact_damping=100., contact_stiffness=100.)
        self.graspable.set_dynamics(
            lateral_friction=1.,
            rolling_friction=0.001,
            spinning_friction=0.001,
            contact_damping=100.,
            contact_stiffness=100.)
        self.simulator.wait_until_stable(self.graspable)

        # Reset camera.
        self._reset_camera(
            self.camera,
            intrinsics=self.config.KINECT2.DEPTH.INTRINSICS,
            translation=self.config.KINECT2.DEPTH.TRANSLATION,
            rotation=self.config.KINECT2.DEPTH.ROTATION,
            intrinsics_noise=self.config.KINECT2.DEPTH.INTRINSICS_NOISE,
            translation_noise=self.config.KINECT2.DEPTH.TRANSLATION_NOISE,
            rotation_noise=self.config.KINECT2.DEPTH.ROTATION_NOISE)