Esempio n. 1
0
 def update(self, action):
     # A colored trace for each joint
     joint_pos = np.array([pbp.get_link_pose(self.uid, i)[0] for i in self.joint_ids])
     if self.last is not None:
         m = len(joint_pos)
         for i in range(n):
             p.addUserDebugLine(
                         lineFromXYZ=joint_pos[i], 
                         lineToXYZ=self.last[i], lineColorRGB=[(n-i)/(n+1), 0.9, i/(n+1)], lineWidth=1, lifeTime=360)
     self.last = joint_pos
def plan_cartesian_motion_from_links(robot,
                                     selected_links,
                                     target_link,
                                     waypoint_poses,
                                     max_iterations=200,
                                     custom_limits={},
                                     get_sub_conf=False,
                                     **kwargs):
    lower_limits, upper_limits = get_custom_limits(robot,
                                                   get_movable_joints(robot),
                                                   custom_limits)
    selected_movable_joints = prune_fixed_joints(robot, selected_links)
    assert (target_link in selected_links)
    selected_target_link = selected_links.index(target_link)
    sub_robot = clone_body(robot,
                           links=selected_links,
                           visual=False,
                           collision=False)  # TODO: joint limits
    sub_movable_joints = get_movable_joints(sub_robot)
    #null_space = get_null_space(robot, selected_movable_joints, custom_limits=custom_limits)
    null_space = None

    solutions = []
    for target_pose in waypoint_poses:
        for iteration in range(max_iterations):
            sub_kinematic_conf = inverse_kinematics_helper(
                sub_robot,
                selected_target_link,
                target_pose,
                null_space=null_space)
            if sub_kinematic_conf is None:
                remove_body(sub_robot)
                return None
                # continue
            set_joint_positions(sub_robot, sub_movable_joints,
                                sub_kinematic_conf)
            # pos_tolerance=1e-3, ori_tolerance=1e-3*np.pi
            if is_pose_close(get_link_pose(sub_robot, selected_target_link),
                             target_pose, **kwargs):
                set_joint_positions(robot, selected_movable_joints,
                                    sub_kinematic_conf)
                kinematic_conf = get_configuration(robot)
                if not all_between(lower_limits, kinematic_conf, upper_limits):
                    remove_body(sub_robot)
                    return None
                if not get_sub_conf:
                    solutions.append(kinematic_conf)
                else:
                    solutions.append(sub_kinematic_conf)
                break
        else:
            remove_body(sub_robot)
            return None
    remove_body(sub_robot)
    return solutions
Esempio n. 3
0
    def _compute_ik(self,
                    robot_uid,
                    ik_joints,
                    tool_link,
                    target_pose,
                    max_iterations=8,
                    custom_limits={}):
        lower_limits, upper_limits = get_custom_limits(
            robot_uid, get_movable_joints(robot_uid), custom_limits)
        selected_links = get_link_subtree(
            robot_uid, ik_joints[0])  # TODO: child_link_from_joint?
        selected_movable_joints = prune_fixed_joints(robot_uid, selected_links)
        assert (tool_link in selected_links)
        selected_target_link = selected_links.index(tool_link)
        sub_robot = clone_body(robot_uid,
                               links=selected_links,
                               visual=False,
                               collision=False)  # TODO: joint limits
        sub_movable_joints = get_movable_joints(sub_robot)

        for _ in range(max_iterations):
            # TODO: stop is no progress
            # TODO: stop if collision or invalid joint limits
            # kinematic_conf = inverse_kinematics_helper(robot_uid, tool_link, target_pose)
            sub_kinematic_conf = inverse_kinematics_helper(
                sub_robot, selected_target_link, target_pose)
            if sub_kinematic_conf is None:
                remove_body(sub_robot)
                return []
            set_joint_positions(sub_robot, sub_movable_joints,
                                sub_kinematic_conf)
            if is_pose_close(get_link_pose(sub_robot, selected_target_link),
                             target_pose):  #, **kwargs):
                set_joint_positions(robot_uid, selected_movable_joints,
                                    sub_kinematic_conf)
                kinematic_conf = get_configuration(robot_uid)
                if not all_between(lower_limits, kinematic_conf, upper_limits):
                    remove_body(sub_robot)
                    return []
                break
        else:
            remove_body(sub_robot)
            return []
        remove_body(sub_robot)
        conf = [
            kinematic_conf[i] for i, jt in enumerate(selected_movable_joints)
            if jt in ik_joints
        ]
        # TODO in RFL case, the base_link will give us 17 joint, needs some pruning according to the ik_joints
        return [conf]
def test_client(fixed_waam_setup, viewer):
    # https://github.com/gramaziokohler/algorithmic_details/blob/e1d5e24a34738822638a157ca29a98afe05beefd/src/algorithmic_details/accessibility/reachability_map.py#L208-L231
    urdf_filename, semantics, _ = fixed_waam_setup
    move_group = 'robotA'

    with PyChoreoClient(viewer=viewer) as client:
        robot = client.load_robot(urdf_filename)
        robot.semantics = semantics
        robot_uid = client.get_robot_pybullet_uid(robot)
        tool_link_name = robot.get_end_effector_link_name(group=move_group)

        # * draw EE pose
        tool_link = link_from_name(robot_uid, tool_link_name)
        tcp_pose = get_link_pose(robot_uid, tool_link)
        draw_pose(tcp_pose)

        assert robot_uid in get_bodies()

        wait_if_gui()
Esempio n. 5
0
def descartes_demo(viewer=True, scaling_test=False, draw_graph=True):
    connect(use_gui=viewer)
    with HideOutput():
        robot = load_pybullet(KUKA_ROBOT_URDF, fixed_base=True)

    # * adjust camera pose (optional)
    # has_gui checks if the GUI mode is enabled
    if has_gui():
        camera_base_pt = (0,0,0)
        camera_pt = np.array(camera_base_pt) + np.array([1, -0.5, 1])
        set_camera_pose(tuple(camera_pt), camera_base_pt)

    cprint('Hello robot world! <ctrl+left mouse> to pan', 'green')
    wait_if_gui()

    ik_joints = get_movable_joints(robot)
    ik_joint_names = get_joint_names(robot, ik_joints)
    print('ik joint names: {}'.format(ik_joint_names))

    lower_limits, upper_limits = get_custom_limits(robot, ik_joints)
    print('joint lower limit: {}'.format(lower_limits))
    print('joint upper limit: {}'.format(upper_limits))
    # we can also read these velocities from the SRDF file (using e.g. COMPAS_FAB)
    # I'm a bit lazy, just handcode the values here
    vel_limits = {0 : 6.28318530718,
                  1 : 5.23598775598,
                  2 : 6.28318530718,
                  3 : 6.6497044501,
                  4 : 6.77187749774,
                  5 : 10.7337748998}

    # set the robot to a "comfortable" start configuration, optional
    robot_start_conf = [0,-np.pi/2,np.pi/2,0,0,0]
    set_joint_positions(robot, ik_joints, robot_start_conf)

    tool_link = link_from_name(robot, EE_LINK_NAME)
    robot_base_link = link_from_name(robot, ROBOT_BASE_LINK_NAME)
    # tool_from_root = get_relative_pose(robot, root_link, tool_link)

    # * draw EE pose
    if has_gui() :
        tcp_pose = get_link_pose(robot, tool_link)
        draw_pose(tcp_pose)

    circle_center = np.array([0.6, 0, 0.2])
    circle_r = 0.1
    # * generate multiple circles
    ee_poses = []
    full_angle = 2*2*np.pi
    # total num of path pts, one path point per 5 degree
    n_pt = int(full_angle / (np.pi/180 * 5))
    # full_angle = np.pi
    for a in np.linspace(0.0, full_angle, num=n_pt):
        pt = circle_center + circle_r*np.array([np.cos(a), np.sin(a), 0])
        circ_pose = multiply(Pose(point=pt, euler=Euler(yaw=a+np.pi/2)), Pose(euler=Euler(roll=np.pi*3/4)))
        draw_pose(circ_pose, length=0.01)
        ee_poses.append(circ_pose)

    # def get_ee_sample_fn(roll_gen, pitch_gen, yaw_gen):
    #     def ee_sample_fn(ee_pose):
    #         # a finite generator
    #         for roll, pitch, yaw in product(roll_gen, pitch_gen, yaw_gen):
    #             yield multiply(ee_pose, Pose(euler=Euler(roll=roll, pitch=pitch, yaw=yaw)))
    #     return ee_sample_fn
    # roll_sample_size = 3
    # pitch_sample_size = 3
    # yaw_sample_size = 1
    # delta_roll = np.pi/12
    # delta_pitch = np.pi/12
    # roll_gen = np.linspace(-delta_roll, delta_roll, num=roll_sample_size)
    # pitch_gen = np.linspace(-delta_pitch, delta_pitch, num=pitch_sample_size)
    # yaw_gen = np.linspace(0.0, 2*np.pi, num=yaw_sample_size)
    # ee_sample_fn = get_ee_sample_fn(roll_gen, pitch_gen, yaw_gen)

    # for ep in ee_sample_fn(ee_poses[0]):
    #     draw_pose(ep, length=0.03)

    # * baseline, keeping the EE z axis rotational dof fixed
    st_time = time.time()
    path = plan_cartesian_motion(robot, robot_base_link, tool_link, ee_poses)
    print('Solving time: {}'.format(elapsed_time(st_time)))
    if path is None:
        cprint('Gradient-based ik cartesian planning cannot find a plan!', 'red')
    else:
        cprint('Gradient-based ik cartesian planning find a plan!', 'green')
        time_step = 0.03
        for conf in path:
            set_joint_positions(robot, ik_joints, conf)
            wait_for_duration(time_step)
        if draw_graph:
            print('drawing graph...')
            plot_joint_val(path, lower_limits, upper_limits, method='GradIK')
    print('='*20)

    # * Now, let's try if using ladder graph without releasing the ee dof can give us a good trajectory
    # you should be doing something similar in your picture, right?

    # First, we will need ikfast to obtain ik solution variance, same in Descartes
    ik_fn = ikfast_kuka_kr6_r900.get_ik

    # we have to specify ik fn wrapper and feed it into pychoreo
    def get_sample_ik_fn(robot, ik_fn, robot_base_link, ik_joints, tool_from_root=None):
        def sample_ik_fn(world_from_tcp):
            if tool_from_root:
                world_from_tcp = multiply(world_from_tcp, tool_from_root)
            return sample_tool_ik(ik_fn, robot, ik_joints, world_from_tcp, robot_base_link, get_all=True)
        return sample_ik_fn
    # ik generation function stays the same for all cartesian processes
    sample_ik_fn = get_sample_ik_fn(robot, ik_fn, robot_base_link, ik_joints)

    # we ignore self collision in this tutorial, the collision_fn only considers joint limit now
    # See : https://github.com/yijiangh/pybullet_planning/blob/dev/tests/test_collisions.py
    # for more info on examples on using collision function
    collision_fn = get_collision_fn(robot, ik_joints, obstacles=[],
                                       attachments=[], self_collisions=False,
                                    #    disabled_collisions=disabled_collisions,
                                    #    extra_disabled_collisions=extra_disabled_collisions,
                                       custom_limits={})

    # Let's check if our ik sampler is working properly
    # uncomment the following if you want to play with this
    # for p in ee_poses:
    #     print('-'*5)
    #     pb_q = inverse_kinematics(robot, tool_link, p)
    #     if pb_q is None:
    #         cprint('pb ik can\'t find an ik solution', 'red')
    #     qs = sample_ik_fn(p)
    #     if qs is not None:
    #         cprint('But Ikfast does find one! {}'.format(qs[0]), 'green')
    #         # set_joint_positions(robot, ik_joints, qs[0])
    #         # wait_if_gui()
    #     else:
    #         cprint('ikfast can\'t find an ik solution', 'red')

    # * Ok, now we have the ik sampler and collision function ready, let's see if we can find a valid cartesian trajectory!
    ee_vel = 0.005 # m/s

    # st_time = time.time()
    # path, cost = plan_cartesian_motion_lg(robot, ik_joints, ee_poses, sample_ik_fn, collision_fn, \
    #     custom_vel_limits=vel_limits, ee_vel=ee_vel)
    # print('Solving time: {}'.format(elapsed_time(st_time)))
    # if path is None:
    #     cprint('ladder graph (w/o releasing dof) cartesian planning cannot find a plan!', 'red')
    # else:
    #     cprint('ladder graph (w/o releasing dof) cartesian planning find a plan!', 'green')
    #     cprint('Cost: {}'.format(cost), 'yellow')
    #     time_step = 0.03
    #     for conf in path:
    #         # cprint('conf: {}'.format(conf))
    #         set_joint_positions(robot, ik_joints, conf)
    #         wait_for_duration(time_step)
    #     if draw_graph:
    #         print('drawing graph...')
    #         plot_joint_val(path, lower_limits, upper_limits, method='IKFast+LadderGraph')
    # print('='*20)

    # * Now, let's see if releasing EE z axis dof can bring down the cost
    # First, let's build an end effector pose sampler to release the EE z axis dof!
    ## * EE z axis dof generator
    def get_ee_sample_fn(roll_gen, pitch_gen, yaw_gen):
        def ee_sample_fn(ee_pose):
            # a finite generator
            for roll, pitch, yaw in product(roll_gen, pitch_gen, yaw_gen):
                yield multiply(ee_pose, Pose(euler=Euler(roll=roll, pitch=pitch, yaw=yaw)))
        return ee_sample_fn

    # by increasing this number we can see the cost go down
    roll_sample_size = 10
    pitch_sample_size = 10
    yaw_sample_size = 10
    delta_roll = np.pi/6
    delta_pitch = np.pi/6
    delta_yaw = np.pi/6
    roll_gen = np.linspace(-delta_roll, delta_roll, num=roll_sample_size)
    pitch_gen = np.linspace(-delta_pitch, delta_pitch, num=pitch_sample_size)
    yaw_gen = np.linspace(-delta_yaw, delta_yaw, num=yaw_sample_size)
    ee_sample_fn = get_ee_sample_fn(roll_gen, pitch_gen, yaw_gen)

    st_time = time.time()
    path, cost = plan_cartesian_motion_lg(robot, ik_joints, ee_poses, sample_ik_fn, collision_fn, sample_ee_fn=ee_sample_fn, \
        custom_vel_limits=vel_limits, ee_vel=ee_vel)
    print('Solving time: {}'.format(elapsed_time(st_time)))

    # TODO: plot ee z axis deviation plot

    # the ladder graph cost is just summation of all adjacent joint difference
    # so the following assertion should be true
    # conf_array = np.array(path)
    # conf_diff = np.abs(conf_array[:-1,:] - conf_array[1:,:])
    # np_cost = np.sum(conf_diff)
    # assert np.allclose(np_cost, cost), '{} - {}'.format(np_cost, cost)

    if path is None:
        cprint('ladder graph (releasing EE z dof) cartesian planning cannot find a plan!', 'red')
    else:
        cprint('ladder graph (releasing EE z dof) cartesian planning find a plan!', 'cyan')
        cprint('Cost: {}'.format(cost), 'yellow')
        time_step = 0.03
        for conf in path:
            # cprint('conf: {}'.format(conf))
            set_joint_positions(robot, ik_joints, conf)
            wait_for_duration(time_step)
        if draw_graph:
            print('drawing graph...')
            plot_joint_val(path, lower_limits, upper_limits, method='IKFast+LadderGraph+release z dof-res{}'.format(yaw_sample_size))
    print('='*20)

    # Now, let's do a scaling test:
    # if scaling_test:
        # res_sc = list(range(4,30))
        # cost_sc = []
        # for res in res_sc:
        #     yaw_sample_size = res
        #     yaw_gen = np.linspace(0.0, 2*np.pi, num=yaw_sample_size)
        #     ee_sample_fn = get_ee_sample_fn(yaw_gen)
        #     path, cost = plan_cartesian_motion_lg(robot, ik_joints, ee_poses, sample_ik_fn, collision_fn, sample_ee_fn=ee_sample_fn)
        #     assert path is not None
        #     cost_sc.append(cost)
        #     if res % 5 == 0:
        #         if draw_graph:
        #             plot_joint_val(path, lower_limits, upper_limits, method='IKFast+LadderGraph+release z dof-res{}'.format(yaw_sample_size))

        # fig, ax = plt.subplots()
        # ax.plot(res_sc, cost_sc)
        # ax.set(xlabel='yaw angle discr resolution', ylabel='total joint difference cost',
        #        title='Total joint diff scaling test')
        # ax.grid()
        # fig.savefig(os.path.join(HERE, 'images', 'tota_diff-scaling.png'))
        # # plt.show()

    wait_if_gui('Press enter to exit')
def ur_demo(viewer=True, robot_path=UR_ROBOT_URDF, ee_path=EE_PATH, \
    workspace_path=MIT_WORKSPACE_PATH, attach_obj_path=ATTACH_OBJ_PATH, obstacle_obj_path=OBSTACLE_OBJ_PATH):

    # * this will create the pybullet GUI
    # setting viewers=False will enter GUI-free mode
    connect(use_gui=viewer)
    cprint(
        "Welcome to pybullet! <Ctrl+left mouse> to rotate, <Ctrl+middle mouse> to move the camera, <Ctrl+right mouse> to zoom",
        'green')
    cprint('But the space is empty, let\'s load our robot!', 'yellow')
    # wait_for_user is your friend! It will pause the console, but having a separate thread keeping
    # the GUI running so you can rotate and see
    wait_for_user()

    # * This is how we load a robot from a URDF, a workspace from a URDF, or simply a mesh object from an obj file
    # Notice that the pybullet uses *METER* by default, make sure you scale things properly!
    robot = load_pybullet(robot_path, fixed_base=True)
    workspace = load_pybullet(workspace_path, fixed_base=True)
    ee_body = create_obj(ee_path)

    # this will print all the bodies' information in your console
    dump_world()
    cprint(
        'You just loaded a robot, a workspace (with many static objects as its link, I modeled our good old MIT 3-412 shop here), '
        + 'and an end effector (it\'s inside the robot base now)', 'green')
    wait_for_user()

    # * adjust camera pose (optional)
    # has_gui checks if the GUI mode is enabled
    if has_gui():
        camera_base_pt = (0, 0, 0)
        camera_pt = np.array(camera_base_pt) + np.array([1, -0.5, 0.5])
        set_camera_pose(tuple(camera_pt), camera_base_pt)

    # * each joint of the robot are assigned with an integer in pybullet
    ik_joints = get_movable_joints(robot)
    ik_joint_names = get_joint_names(robot, ik_joints)
    cprint('Joint {} \ncorresponds to:\n{}'.format(ik_joints, ik_joint_names),
           'green')
    robot_start_conf = [0, -1.65715, 1.71108, -1.62348, 0, 0]
    cprint("This is before updating pose", 'yellow')
    wait_for_user()
    # * set joint configuration, the robot's pose will be updated
    set_joint_positions(robot, ik_joints, robot_start_conf)
    cprint("This is after set joint pose: {}".format(robot_start_conf),
           'green')
    wait_for_user()

    tool_attach_link_name = 'ee_link'
    tool_attach_link = link_from_name(robot, tool_attach_link_name)

    # * attach the end effector
    ee_link_pose = get_link_pose(robot, tool_attach_link)
    set_pose(ee_body, ee_link_pose)
    ee_attach = create_attachment(robot, tool_attach_link, ee_body)
    # we need to call "assign()" to update the attachment to the current end effector pose
    ee_attach.assign()

    # let's load a bar element (obj) and a box (pybullet primitive shape) into the world
    attached_bar_body = create_obj(attach_obj_path)
    box_body = create_obj(obstacle_obj_path)
    cprint('We loaded a box to our scene!', 'green')
    wait_for_user()

    # * attach the bar
    ee_link_from_tcp = Pose(point=(0.094, 0, 0))
    set_pose(attached_bar_body, multiply(ee_link_pose, ee_link_from_tcp))
    bar_attach = create_attachment(robot, tool_attach_link, attached_bar_body)
    bar_attach.assign()
    cprint('The bar element is attached to the robot', 'green')
    wait_for_user()

    attachments = [ee_attach, bar_attach]

    # * Let's do some collision checking
    # * specify disabled link pairs for collision checking (because they are adjacent / impossible to collide)
    # link name corresponds to the ones specified in the URDF
    # again, each robot link is assigned with an integer index in pybullet
    robot_self_collision_disabled_link_names = [
        ('base_link', 'shoulder_link'), ('ee_link', 'wrist_1_link'),
        ('ee_link', 'wrist_2_link'), ('ee_link', 'wrist_3_link'),
        ('forearm_link', 'upper_arm_link'), ('forearm_link', 'wrist_1_link'),
        ('shoulder_link', 'upper_arm_link'), ('wrist_1_link', 'wrist_2_link'),
        ('wrist_1_link', 'wrist_3_link'), ('wrist_2_link', 'wrist_3_link')
    ]
    self_collision_links = get_disabled_collisions(
        robot, robot_self_collision_disabled_link_names)
    cprint('self_collision_links disabled: {}'.format(self_collision_links),
           'yellow')

    extra_disabled_link_names = [('base_link', 'MIT_3412_robot_base_plate'),
                                 ('shoulder_link', 'MIT_3412_robot_base_plate')
                                 ]
    extra_disabled_collisions = get_body_body_disabled_collisions(
        robot, workspace, extra_disabled_link_names)
    cprint('extra disabled: {}'.format(extra_disabled_collisions), 'yellow')

    print('#' * 10)
    cprint('Checking robot links self-collision', 'green')
    collision_fn = get_collision_fn(robot,
                                    ik_joints,
                                    obstacles=[],
                                    attachments=attachments,
                                    self_collisions=True,
                                    disabled_collisions=self_collision_links)
    conf = [-1.029744, -1.623156, 2.844887, -0.977384, 1.58825, 0.314159]
    # self collision, this should return true
    # this function will first set the robot's joint configuration (together with the attachment)
    # and check collision
    # notice that turning on the diagnosis flag here will show you where the collision is happening
    cprint(
        'Notice that the diagnosis mode will zoom the camera to where the collision is detected. Move the camera around if you can\'t see what\'s going on there.',
        'yellow')
    assert collision_fn(conf, diagnosis=True)

    print('#' * 10)
    cprint('Checking robot links - holding attachment self-collision', 'green')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[],
        attachments=attachments,
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions)
    conf = [0.03500, -2.26900, 2.44300, 1.117, 1.6579, 0.105]
    assert collision_fn(conf, diagnosis=True)
    print('\n')

    print('#' * 10)
    cprint('Checking robot links to obstacles (w/o links) collision', 'green')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[box_body],
        attachments=attachments,
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions)
    conf = [
        -0.105, -0.76800000000000002, 1.292, -0.61099999999999999, 1.484, 0.105
    ]
    assert collision_fn(conf, diagnosis=True)
    print('\n')

    print('#' * 10)
    cprint('Checking robot links to multi-link obstacle collision', 'green')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[workspace],
        attachments=[],
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions)
    conf = [
        -0.17499999999999999, -3.194, 0.33200000000000002, -1.6579999999999999,
        1.431, 0.105
    ]
    assert collision_fn(conf, diagnosis=True)
    print('\n')

    print('#' * 10)
    cprint('Checking attachment to obstacles (w/o links) collision', 'green')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[workspace, box_body],
        attachments=attachments,
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions)
    conf = [
        -2.8100000000000001, -1.484, -1.9199999999999999, -1.6579999999999999,
        1.431, 0.105
    ]
    assert collision_fn(conf, diagnosis=True)
    print('\n')

    print('#' * 10)
    cprint('Checking attachment to multi-link obstacle collision', 'green')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[workspace],
        attachments=attachments,
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions)
    conf = [
        -0.17499999999999999, -2.4780000000000002, 0.33200000000000002,
        -1.6579999999999999, 1.431, 0.105
    ]
    assert collision_fn(conf, diagnosis=True)
    print('\n')

    # * collision checking exoneration
    print('#' * 10)
    print('self-link collision disable')
    collision_fn = get_collision_fn(robot,
                                    ik_joints,
                                    obstacles=[],
                                    attachments=[],
                                    self_collisions=False)
    conf = [-1.029744, -1.623156, 2.844887, -0.977384, 1.58825, 0.314159]
    assert not collision_fn(conf, diagnosis=True)
    print('\n')

    print('#' * 10)
    cprint('robot links to obstacle collision exoneration', 'green')
    cprint(
        'In this example, the first collision function will check collision between the robot and the box, '
        + 'but the second collision function will ignore it.', 'yellow')
    collision_fn = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[box_body],
        attachments=[],
        self_collisions=True,
        disabled_collisions=self_collision_links,
    )
    collision_fn_disable = get_collision_fn(
        robot,
        ik_joints,
        obstacles=[box_body],
        attachments=[],
        self_collisions=True,
        disabled_collisions=self_collision_links,
        extra_disabled_collisions=extra_disabled_collisions.union([
            ((robot, link_from_name(robot,
                                    'forearm_link')), (box_body, BASE_LINK))
        ]),
    )
    conf = [
        -3.2639999999999998, -2.6880000000000002, -0.85499999999999998, -1.536,
        3.0369999999999999, -0.070000000000000007
    ]
    assert collision_fn(conf, diagnosis=True)
    assert not collision_fn_disable(conf, diagnosis=True)
    print('\n')

    # * joint value overflow checking & exoneration
    cprint('joint value overflow checking & exoneration', 'green')
    cprint(
        'collision_fn also checks for robot\'s joint limit as well. We can also exonerate it by passing custom_limits into the collision_fn',
        'yellow')

    def get_custom_limits_from_name(robot, joint_limits):
        return {
            joint_from_name(robot, joint): limits
            for joint, limits in joint_limits.items()
        }

    custom_limits = get_custom_limits_from_name(robot, {
        'shoulder_pan_joint': (-7.9, 0),
        'elbow_joint': (-8.0, 0)
    })
    collision_fn = get_collision_fn(robot, ik_joints)
    collision_fn_disable = get_collision_fn(robot,
                                            ik_joints,
                                            custom_limits=custom_limits)
    conf = [
        -7.8450000000000002, -2.1469999999999998, -7.99, -0.92500000000000004,
        1.78, 0.105
    ]
    assert collision_fn(conf, diagnosis=True)
    assert not collision_fn_disable(conf, diagnosis=True)
    print('\n')
Esempio n. 7
0
 def get_link_frame_from_name(self, robot, link_name):
     robot_uid = robot.attributes['pybullet_uid']
     return frame_from_pose(
         get_link_pose(robot_uid, link_from_name(robot_uid, link_name)))
Esempio n. 8
0
 def tf_world_frame(self, base_to_pose, armname):
     basename = self.arms_base[armname]
     baseid = pyplan.link_from_name(self.id, basename)
     world_to_base = pyplan.get_link_pose(self.id, baseid)
     world_to_pose = pyplan.multiply(world_to_base, base_to_pose)
     return world_to_pose
Esempio n. 9
0
 def tf_arm_frame(self, pose, armname):
     basename = self.arms_base[armname]
     baseid = pyplan.link_from_name(self.id, basename)
     base_to_world = pyplan.invert(pyplan.get_link_pose(self.id, baseid))
     base_to_pose = pyplan.multiply(base_to_world, pose)
     return base_to_pose
def test_ik(fixed_waam_setup, viewer, ik_engine):
    urdf_filename, semantics, robotA_tool = fixed_waam_setup
    move_group = 'robotA'

    with PyChoreoClient(viewer=viewer) as client:
        robot = client.load_robot(urdf_filename)
        robot.semantics = semantics
        robot_uid = client.get_robot_pybullet_uid(robot)

        base_link_name = robot.get_base_link_name(group=move_group)
        ik_joint_names = robot.get_configurable_joint_names(group=move_group)
        tool_link_name = robot.get_end_effector_link_name(group=move_group)
        base_frame = robot.get_base_frame(group=move_group)

        if ik_engine == 'default-single':
            ik_solver = None
        elif ik_engine == 'lobster-analytical':
            ik_solver = InverseKinematicsSolver(robot, move_group,
                                                ik_abb_irb4600_40_255,
                                                base_frame, robotA_tool.frame)
        elif ik_engine == 'ikfast-analytical':
            ikfast_fn = get_ik_fn_from_ikfast(ikfast_abb_irb4600_40_255.get_ik)
            ik_solver = InverseKinematicsSolver(robot, move_group, ikfast_fn,
                                                base_frame, robotA_tool.frame)
        else:
            raise ValueError('invalid ik engine name.')

        ik_joints = joints_from_names(robot_uid, ik_joint_names)
        tool_link = link_from_name(robot_uid, tool_link_name)
        ee_poses = compute_circle_path()

        if ik_solver is not None:
            # replace default ik function with a customized one
            client.planner.inverse_kinematics = ik_solver.inverse_kinematics_function(
            )

        ik_time = 0
        failure_cnt = 0
        # ik function sanity check
        for p in ee_poses:
            frame_WCF = frame_from_pose(p)
            st_time = time.time()
            qs = client.inverse_kinematics(robot,
                                           frame_WCF,
                                           group=move_group,
                                           options={})
            ik_time += elapsed_time(st_time)

            if qs is None:
                cprint('no ik solution found!', 'red')
                # assert False, 'no ik solution found!'
                failure_cnt += 1
            elif isinstance(qs, list):
                if not (len(qs) > 0 and any([qv is not None for qv in qs])):
                    cprint('no ik solution found', 'red')
                    failure_cnt += 1
                if len(qs) > 0:
                    # cprint('{} solutions found!'.format(len(qs)), 'green')
                    for q in randomize(qs):
                        if q is not None:
                            assert isinstance(q, Configuration)
                            client.set_robot_configuration(robot, q)
                            # set_joint_positions(robot_uid, ik_joints, q.values)
                            tcp_pose = get_link_pose(robot_uid, tool_link)
                            assert_almost_equal(tcp_pose[0], p[0], decimal=3)
                            assert_almost_equal(quat_angle_between(
                                tcp_pose[1], p[1]),
                                                0,
                                                decimal=3)
            elif isinstance(qs, Configuration):
                # cprint('Single solutions found!', 'green')
                q = qs
                # set_joint_positions(robot_uid, ik_joints, q.values)
                client.set_robot_configuration(robot, q)
                tcp_pose = get_link_pose(robot_uid, tool_link)
                assert_almost_equal(tcp_pose[0], p[0], decimal=3)
                assert_almost_equal(quat_angle_between(tcp_pose[1], p[1]),
                                    0,
                                    decimal=3)
            else:
                raise ValueError('invalid ik return.')
            wait_if_gui('FK - IK agrees.')
        cprint(
            '{} | Success {}/{} | Average ik time: {} | avg over {} calls.'.
            format(ik_engine,
                   len(ee_poses) - failure_cnt, len(ee_poses),
                   ik_time / len(ee_poses), len(ee_poses)), 'cyan')
def test_circle_cartesian(fixed_waam_setup, viewer, planner_ik_conf):
    urdf_filename, semantics, robotA_tool = fixed_waam_setup
    planner_id, ik_engine = planner_ik_conf

    move_group = 'robotA'
    print('\n')
    print('=' * 10)
    cprint(
        'Cartesian planner {} with IK engine {}'.format(planner_id, ik_engine),
        'yellow')

    with PyChoreoClient(viewer=viewer) as client:
        robot = client.load_robot(urdf_filename)
        robot.semantics = semantics
        robot_uid = client.get_robot_pybullet_uid(robot)

        base_link_name = robot.get_base_link_name(group=move_group)
        ik_joint_names = robot.get_configurable_joint_names(group=move_group)
        tool_link_name = robot.get_end_effector_link_name(group=move_group)
        base_frame = robot.get_base_frame(group=move_group)

        if ik_engine == 'default-single':
            ik_solver = None
        elif ik_engine == 'lobster-analytical':
            ik_solver = InverseKinematicsSolver(robot, move_group,
                                                ik_abb_irb4600_40_255,
                                                base_frame, robotA_tool.frame)
        elif ik_engine == 'ikfast-analytical':
            ikfast_fn = get_ik_fn_from_ikfast(ikfast_abb_irb4600_40_255.get_ik)
            ik_solver = InverseKinematicsSolver(robot, move_group, ikfast_fn,
                                                base_frame, robotA_tool.frame)
        else:
            raise ValueError('invalid ik engine name.')

        init_conf = Configuration.from_revolute_values(np.zeros(6),
                                                       ik_joint_names)

        # replace default ik function with a customized one
        if ik_solver is not None:
            client.planner.inverse_kinematics = ik_solver.inverse_kinematics_function(
            )

        tool_link = link_from_name(robot_uid, tool_link_name)
        robot_base_link = link_from_name(robot_uid, base_link_name)
        ik_joints = joints_from_names(robot_uid, ik_joint_names)

        # * draw EE pose
        tcp_pose = get_link_pose(robot_uid, tool_link)
        draw_pose(tcp_pose)

        # * generate multiple circles
        circle_center = np.array([2, 0, 0.2])
        circle_r = 0.2
        # full_angle = np.pi
        # full_angle = 2*2*np.pi
        angle_range = (-0.5 * np.pi, 0.5 * np.pi)
        # total num of path pts, one path point per 5 degree
        ee_poses = compute_circle_path(circle_center, circle_r, angle_range)
        ee_frames_WCF = [frame_from_pose(ee_pose) for ee_pose in ee_poses]

        options = {'planner_id': planner_id}
        if planner_id == 'LadderGraph':
            client.set_robot_configuration(robot, init_conf)
            st_time = time.time()

            # options.update({'ik_function' : lambda pose: compute_inverse_kinematics(ikfast_abb_irb4600_40_255.get_ik, pose, sampled=[])})

            trajectory = client.plan_cartesian_motion(robot,
                                                      ee_frames_WCF,
                                                      group=move_group,
                                                      options=options)
            cprint(
                'W/o frame variant solving time: {}'.format(
                    elapsed_time(st_time)), 'blue')
            cprint(
                'Cost: {}'.format(
                    compute_trajectory_cost(trajectory,
                                            init_conf_val=init_conf.values)),
                'blue')
            print('-' * 5)

            f_variant_options = {'delta_yaw': np.pi / 3, 'yaw_sample_size': 5}
            options.update({
                'frame_variant_generator':
                PyChoreoFiniteEulerAngleVariantGenerator(
                    options=f_variant_options)
            })
            print('With frame variant config: {}'.format(f_variant_options))

        client.set_robot_configuration(robot, init_conf)
        st_time = time.time()
        trajectory = client.plan_cartesian_motion(robot,
                                                  ee_frames_WCF,
                                                  group=move_group,
                                                  options=options)
        cprint(
            '{} solving time: {}'.format(
                'With frame variant '
                if planner_id == 'LadderGraph' else 'Direct',
                elapsed_time(st_time)), 'cyan')
        cprint(
            'Cost: {}'.format(
                compute_trajectory_cost(trajectory,
                                        init_conf_val=init_conf.values)),
            'cyan')

        if trajectory is None:
            cprint(
                'Client Cartesian planner {} CANNOT find a plan!'.format(
                    planner_id), 'red')
        else:
            cprint(
                'Client Cartesian planning {} find a plan!'.format(planner_id),
                'green')
            wait_if_gui('Start sim.')
            time_step = 0.03
            for traj_pt in trajectory.points:
                client.set_robot_configuration(robot, traj_pt)
                wait_for_duration(time_step)

        wait_if_gui()