def propose_grasps(pc, radius, num_grasps=1, vis=False):
    output_grasps = []

    for _ in range(num_grasps):
        center_index = np.random.randint(pc.shape[0])
        center_point = pc[center_index, :].copy()
        d = np.sqrt(np.sum(np.square(pc - np.expand_dims(center_point, 0)),
                           -1))
        index = np.where(d < radius)[0]
        neighbors = pc[index, :]

        eigen_values, eigen_vectors = cov_matrix(center_point, neighbors)
        direction = eigen_vectors[:, 2]

        direction = choose_direction(direction, center_point)

        surface_orientation = trimesh.geometry.align_vectors([0, 0, 1],
                                                             direction)
        roll_orientation = tra.quaternion_matrix(
            tra.quaternion_about_axis(np.random.uniform(0, 2 * np.pi),
                                      [0, 0, 1]))
        gripper_transform = surface_orientation.dot(roll_orientation)
        gripper_transform[:3, 3] = center_point

        translation_transform = np.eye(4)
        translation_transform[2, 3] = -np.random.uniform(0.0669, 0.1122)

        gripper_transform = gripper_transform.dot(translation_transform)
        output_grasps.append(gripper_transform.copy())

    if vis:
        draw_scene(pc, grasps=output_grasps)
        mlab.show()

    return np.asarray(output_grasps)
Пример #2
0
def spherical_rotate(max_rot_degrees):
    """Calculate a random rotation matrix using angle magnitudes in max_rot."""

    assert isinstance(max_rot_degrees, tuple) and len(max_rot_degrees) == 3

    xrot, yrot, zrot = max_rot_degrees

    # Build the global rotation matrix using quaternions
    q_xr = tf.quaternion_about_axis(rand_step(xrot), [1, 0, 0])
    q_yr = tf.quaternion_about_axis(rand_step(yrot), [0, 1, 0])
    q_zr = tf.quaternion_about_axis(rand_step(zrot), [0, 0, 1])

    # Multiply global and local rotations
    rotation = tf.quaternion_multiply(q_xr, q_yr)
    rotation = tf.quaternion_multiply(rotation, q_zr)
    return tf.quaternion_matrix(rotation)
Пример #3
0
def cable(a, b, thick=0.20):
    """
    Rigid cable (segment) between two points.

    TODO: this extrusion approach and rotation can be improved using extrude along like cable_catenary does.
    """
    a = np.array(a)
    b = np.array(b)

    #path = ddd.line([a, b])
    #path_section = ddd.point(name="Cable").buffer(thick * 0.5, resolution=1, cap_style=ddd.CAP_ROUND)
    #cable = path_section.extrude_path(path)

    length = np.linalg.norm(b - a)
    cable = ddd.point(name="Cable").buffer(thick * 0.5, resolution=1).extrude(length + thick).translate([0, 0, -thick * 0.5])
    cable = cable.merge_vertices().smooth(math.pi)
    cable = ddd.uv.map_cylindrical(cable, split=False)

    vector_up = [0, 0, 1]
    vector_dir = (b - a) / length
    rot_axis = np.cross(vector_up, vector_dir)
    rot_angle = math.asin(np.linalg.norm(rot_axis))
    if rot_angle > 0.00001:
        rotation = transformations.quaternion_about_axis(rot_angle, rot_axis / np.linalg.norm(rot_axis))
        cable = cable.rotate_quaternion(rotation)
    cable = cable.translate(a)

    return cable
Пример #4
0
 def load_dice_nodes(self, scene_setup: SceneSetup):
     """Creates internal list of dice nodes, including calculating pose rotation and translation, from a given SceneSetup."""
     for dice_setup in [
             dice_setup for dice_setup in scene_setup.dice_setups
             if dice_setup.exists
     ]:
         dice_node = pyrender.Node(mesh=self.dice_mesh, matrix=np.eye(4))
         quaternion_y_rotation = quaternion_about_axis(
             dice_setup.rotation_y_degrees * np.pi / 180, [0, 1, 0])
         side_axis = [0, 0, 1
                      ] if dice_setup.side_rotation_around_z else [1, 0, 0]
         quaternion_side_rotation = quaternion_about_axis(
             dice_setup.side_rotation_times * np.pi / 2, side_axis)
         dice_node.rotation = np.roll(
             quaternion_multiply(quaternion_y_rotation,
                                 quaternion_side_rotation), -1)
         dice_node.translation = (dice_setup.x, 0, dice_setup.z)
         self.dice_nodes.append(dice_node)
Пример #5
0
    def get_empty_scene(self):
        """Creates an empty scene with a camera and spot light."""
        scene = pyrender.Scene(ambient_light=[0.2, 0.2, 0.2],
                               bg_color=[0.1, 0.1, 0.1])

        camera = pyrender.PerspectiveCamera(yfov=np.pi / 3.0, aspectRatio=1)
        camera_pose = translation_matrix([0, 3, 4]) @ quaternion_matrix(
            quaternion_about_axis(np.deg2rad(-45.0), [1, 0, 0]))
        scene.add(camera, pose=camera_pose)

        light = pyrender.SpotLight(color=np.ones(3),
                                   intensity=3.0,
                                   innerConeAngle=np.pi / 16.0)
        scene.add(light, pose=camera_pose)

        return scene
Пример #6
0
def sample_multiple_grasps(number_of_candidates,
                           mesh,
                           gripper_name,
                           systematic_sampling,
                           surface_density=0.005 * 0.005,
                           standoff_density=0.01,
                           roll_density=15,
                           type_of_quality='antipodal',
                           min_quality=-1.0,
                           silent=False):
    """Sample a set of grasps for an object.

    Arguments:
        number_of_candidates {int} -- Number of grasps to sample
        mesh {trimesh} -- Object mesh
        gripper_name {str} -- Name of gripper model
        systematic_sampling {bool} -- Whether to use grid sampling for roll

    Keyword Arguments:
        surface_density {float} -- surface density, in m^2 (default: {0.005*0.005})
        standoff_density {float} -- density for standoff, in m (default: {0.01})
        roll_density {float} -- roll density, in deg (default: {15})
        type_of_quality {str} -- quality metric (default: {'antipodal'})
        min_quality {float} -- minimum grasp quality (default: {-1})
        silent {bool} -- verbosity (default: {False})

    Raises:
        Exception: Unknown quality metric

    Returns:
        [type] -- points, normals, transforms, roll_angles, standoffs, collisions, quality
    """
    origins = []
    orientations = []
    transforms = []

    standoffs = []
    roll_angles = []

    gripper = create_gripper(gripper_name)

    if systematic_sampling:
        # systematic sampling. input:
        # - Surface density:
        # - Standoff density:
        # - Rotation density:
        # Resulting number of samples:
        # (Area/Surface Density) * (Finger length/Standoff density) * (360/Rotation Density)
        surface_samples = int(np.ceil(mesh.area / surface_density))
        standoff_samples = np.linspace(
            gripper.standoff_range[0], gripper.standoff_range[1],
            max(1, (gripper.standoff_range[1] - gripper.standoff_range[0]) /
                standoff_density))
        rotation_samples = np.arange(0, 1 * np.pi, np.deg2rad(roll_density))

        number_of_candidates = surface_samples * \
            len(standoff_samples) * len(rotation_samples)

        tmp_points, face_indices = mesh.sample(surface_samples,
                                               return_index=True)
        tmp_normals = mesh.face_normals[face_indices]

        number_of_candidates = len(tmp_points) * \
            len(standoff_samples) * len(rotation_samples)
        print("Number of samples ", number_of_candidates, "(", len(tmp_points),
              " x ", len(standoff_samples), " x ", len(rotation_samples), ")")

        points = []
        normals = []

        position_idx = []

        pos_cnt = 0
        cnt = 0

        batch_position_idx = []
        batch_points = []
        batch_normals = []
        batch_roll_angles = []
        batch_standoffs = []
        batch_transforms = []

        for point, normal in tqdm(zip(tmp_points, tmp_normals),
                                  total=len(tmp_points),
                                  disable=silent):
            for roll in rotation_samples:
                for standoff in standoff_samples:
                    batch_position_idx.append(pos_cnt)
                    batch_points.append(point)
                    batch_normals.append(normal)
                    batch_roll_angles.append(roll)
                    batch_standoffs.append(standoff)

                    orientation = tra.quaternion_matrix(
                        tra.quaternion_about_axis(roll, [0, 0, 1]))
                    origin = point + normal * standoff

                    batch_transforms.append(
                        np.dot(
                            np.dot(
                                tra.translation_matrix(origin),
                                trimesh.geometry.align_vectors([0, 0, -1],
                                                               normal)),
                            orientation))

                    cnt += 1
            pos_cnt += 1

            if cnt % 1000 == 0 or cnt == len(tmp_points):
                valid = raycast_collisioncheck(np.asarray(batch_transforms),
                                               np.asarray(batch_points), mesh)
                transforms.extend(np.array(batch_transforms)[valid])
                position_idx.extend(np.array(batch_position_idx)[valid])
                points.extend(np.array(batch_points)[valid])
                normals.extend(np.array(batch_normals)[valid])
                roll_angles.extend(np.array(batch_roll_angles)[valid])
                standoffs.extend(np.array(batch_standoffs)[valid])

                batch_position_idx = []
                batch_points = []
                batch_normals = []
                batch_roll_angles = []
                batch_standoffs = []
                batch_transforms = []

        points = np.array(points)
        normals = np.array(normals)
        position_idx = np.array(position_idx)
    else:
        points, face_indices = mesh.sample(number_of_candidates,
                                           return_index=True)
        normals = mesh.face_normals[face_indices]

        # generate transformations
        for point, normal in tqdm(zip(points, normals),
                                  total=len(points),
                                  disable=silent):
            # roll along approach vector
            angle = np.random.rand() * 2 * np.pi
            roll_angles.append(angle)
            orientations.append(
                tra.quaternion_matrix(
                    tra.quaternion_about_axis(angle, [0, 0, 1])))

            # standoff from surface
            standoff = (gripper.standoff_range[1] - gripper.standoff_range[0]) * np.random.rand() \
                + gripper.standoff_range[0]
            standoffs.append(standoff)
            origins.append(point + normal * standoff)

            transforms.append(
                np.dot(
                    np.dot(tra.translation_matrix(origins[-1]),
                           trimesh.geometry.align_vectors([0, 0, -1], normal)),
                    orientations[-1]))

    verboseprint("Checking collisions...")
    collisions = in_collision_with_gripper(mesh,
                                           transforms,
                                           gripper_name=gripper_name,
                                           silent=silent)

    verboseprint("Labelling grasps...")
    quality = {}
    quality_key = 'quality_' + type_of_quality
    if type_of_quality == 'antipodal':
        quality[quality_key] = grasp_quality_antipodal(
            transforms,
            collisions,
            object_mesh=mesh,
            gripper_name=gripper_name,
            silent=silent)
    elif type_of_quality == 'number_of_contacts':
        quality[quality_key] = grasp_quality_point_contacts(
            transforms,
            collisions,
            object_mesh=mesh,
            gripper_name=gripper_name,
            silent=silent)
    else:
        raise Exception("Quality metric unknown: ", quality)

    # Filter out by quality
    quality_np = np.array(quality[quality_key])
    collisions = np.array(collisions)

    f_points = []
    f_normals = []
    f_transforms = []
    f_roll_angles = []
    f_standoffs = []
    f_collisions = []
    f_quality = []

    for i, _ in enumerate(transforms):
        if quality_np[i] >= min_quality:
            f_points.append(points[i])
            f_normals.append(normals[i])
            f_transforms.append(transforms[i])
            f_roll_angles.append(roll_angles[i])
            f_standoffs.append(standoffs[i])
            f_collisions.append(int(collisions[i]))
            f_quality.append(quality_np[i])

    points = np.array(f_points)
    normals = np.array(f_normals)
    transforms = np.array(f_transforms)
    roll_angles = np.array(f_roll_angles)
    standoffs = np.array(f_standoffs)
    collisions = f_collisions
    quality[quality_key] = f_quality

    return points, normals, transforms, roll_angles, standoffs, collisions, quality
Пример #7
0
def generate_candidates(mesh_properties):
    """Generates grasp candidates via predicted 6DoF pose of gripper."""

    bbox = mesh_properties['bbox']
    work2obj = mesh_properties['work2obj']
    obj2grip = mesh_properties['obj2grip']

    # Extract the bounding box corners and planes of the object
    _, planes = get_corners_and_plances(bbox)

    xyz_grid = [to_rad(x, y, z)
                for x in range(0, 360, GLOBAL_X) \
                for y in range(0, 360, GLOBAL_Y) \
                for z in range(0, 360, GLOBAL_Z)]

    total_trials = len(xyz_grid)**2

    # Angles holds the information about global and local rotations
    # Matrices holds information about the final transformation.
    angles = np.empty((total_trials, 6))
    matrices = np.empty((total_trials, 12))

    # Going to extend a vector along z-direction of palm. The extra 1 o the end
    # is for multiplying with a 4x4 HT matrix
    palm_axis = np.atleast_2d([0, 0, 10, 1]).T

    curr_trial = 0
    success = 0

    # Exhaustively evaluate local and global rotations
    for gx, gy, gz in xyz_grid:
        for lx, ly, lz in xyz_grid:

            # Monitor our status, print something every 10%
            if curr_trial % int(0.1 * total_trials) == 0:
                print 'Trial %d/%d, successful: %d'%\
                (curr_trial, total_trials, success)

            curr_trial += 1

            # Build the global rotation matrix using quaternions
            q_gx = tf.quaternion_about_axis(gx + rand_step(GLOBAL_X),
                                            [1, 0, 0])
            q_gy = tf.quaternion_about_axis(gy + rand_step(GLOBAL_Y),
                                            [0, 1, 0])
            q_gz = tf.quaternion_about_axis(gz + rand_step(GLOBAL_Z),
                                            [0, 0, 1])

            # Build the local rotation matrix using quaternions
            q_lx = tf.quaternion_about_axis(lx + rand_step(GLOBAL_X),
                                            [1, 0, 0])
            q_ly = tf.quaternion_about_axis(ly + rand_step(GLOBAL_Y),
                                            [0, 1, 0])
            q_lz = tf.quaternion_about_axis(lz + rand_step(GLOBAL_Z),
                                            [0, 0, 1])

            # Multiply global and local rotations
            global_rotation = tf.quaternion_multiply(q_gx, q_gy)
            global_rotation = tf.quaternion_multiply(global_rotation, q_gz)
            global_rotation = tf.quaternion_matrix(global_rotation)

            local_rotation = tf.quaternion_multiply(q_lx, q_ly)
            local_rotation = tf.quaternion_multiply(local_rotation, q_lz)
            local_rotation = tf.quaternion_matrix(local_rotation)

            rotation = np.dot(np.dot(global_rotation, obj2grip),
                              local_rotation)

            # Don't want to test any candidates that are below the workspace
            workspace2grip = np.dot(work2obj, rotation)
            if workspace2grip[2, 3] < 0:
                continue

            # Check if a line from the center of the grippers palm intersects
            # with the planes of the object
            line_start = rotation[:3, 3]
            line_end = np.dot(rotation, palm_axis).flatten()[:3]

            for plane in planes:
                itx_plane = intersect_plane(line_start, line_end, *plane)

                if intersect_box(itx_plane, bbox) is False:
                    continue

                angles[success] = np.asarray([gx, gy, gz, lx, ly, lz])
                matrices[success] = rotation[:3].flatten()
                success = success + 1
                break

    # Only keep the successful transformations
    angles = np.asarray(angles)[:success]
    matrices = np.asarray(matrices)[:success]

    return angles, matrices
Пример #8
0
def test_nodes():

    x = Node()
    assert x.name is None
    assert x.camera is None
    assert x.children == []
    assert x.skin is None
    assert np.allclose(x.matrix, np.eye(4))
    assert x.mesh is None
    assert np.allclose(x.rotation, [0, 0, 0, 1])
    assert np.allclose(x.scale, np.ones(3))
    assert np.allclose(x.translation, np.zeros(3))
    assert x.weights is None
    assert x.light is None

    x.name = 'node'

    # Test node light/camera/mesh tests
    c = PerspectiveCamera(yfov=2.0)
    m = Mesh([])
    d = DirectionalLight()
    x.camera = c
    assert x.camera == c
    with pytest.raises(TypeError):
        x.camera = m
        x.camera = d
    x.camera = None
    x.mesh = m
    assert x.mesh == m
    with pytest.raises(TypeError):
        x.mesh = c
        x.mesh = d
    x.light = d
    assert x.light == d
    with pytest.raises(TypeError):
        x.light = m
        x.light = c

    # Test transformations getters/setters/etc...
    # Set up test values
    x = np.array([1.0, 0.0, 0.0])
    y = np.array([0.0, 1.0, 0.0])
    t = np.array([1.0, 2.0, 3.0])
    s = np.array([0.5, 2.0, 1.0])

    Mx = transformations.rotation_matrix(np.pi / 2.0, x)
    qx = np.roll(transformations.quaternion_about_axis(np.pi / 2.0, x), -1)
    Mxt = Mx.copy()
    Mxt[:3, 3] = t
    S = np.eye(4)
    S[:3, :3] = np.diag(s)
    Mxts = Mxt.dot(S)

    My = transformations.rotation_matrix(np.pi / 2.0, y)
    qy = np.roll(transformations.quaternion_about_axis(np.pi / 2.0, y), -1)
    Myt = My.copy()
    Myt[:3, 3] = t

    x = Node(matrix=Mx)
    assert np.allclose(x.matrix, Mx)
    assert np.allclose(x.rotation, qx)
    assert np.allclose(x.translation, np.zeros(3))
    assert np.allclose(x.scale, np.ones(3))

    x.matrix = My
    assert np.allclose(x.matrix, My)
    assert np.allclose(x.rotation, qy)
    assert np.allclose(x.translation, np.zeros(3))
    assert np.allclose(x.scale, np.ones(3))
    x.translation = t
    assert np.allclose(x.matrix, Myt)
    assert np.allclose(x.rotation, qy)
    x.rotation = qx
    assert np.allclose(x.matrix, Mxt)
    x.scale = s
    assert np.allclose(x.matrix, Mxts)

    x = Node(matrix=Mxt)
    assert np.allclose(x.matrix, Mxt)
    assert np.allclose(x.rotation, qx)
    assert np.allclose(x.translation, t)
    assert np.allclose(x.scale, np.ones(3))

    x = Node(matrix=Mxts)
    assert np.allclose(x.matrix, Mxts)
    assert np.allclose(x.rotation, qx)
    assert np.allclose(x.translation, t)
    assert np.allclose(x.scale, s)

    # Individual element getters
    x.scale[0] = 0
    assert np.allclose(x.scale[0], 0)

    x.translation[0] = 0
    assert np.allclose(x.translation[0], 0)

    x.matrix = np.eye(4)
    x.matrix[0, 0] = 500
    assert x.matrix[0, 0] == 1.0

    # Failures
    with pytest.raises(ValueError):
        x.matrix = 5 * np.eye(4)
    with pytest.raises(ValueError):
        x.matrix = np.eye(5)
    with pytest.raises(ValueError):
        x.matrix = np.eye(4).dot([5, 1, 1, 1])
    with pytest.raises(ValueError):
        x.rotation = np.array([1, 2])
    with pytest.raises(ValueError):
        x.rotation = np.array([1, 2, 3])
    with pytest.raises(ValueError):
        x.rotation = np.array([1, 2, 3, 4])
    with pytest.raises(ValueError):
        x.translation = np.array([1, 2, 3, 4])
    with pytest.raises(ValueError):
        x.scale = np.array([1, 2, 3, 4])