Bimanual IKΒΆ

Same as 01_basic_ik.py, but with two end effectors!

All examples can be run by first cloning the PyRoki repository, which includes the pyroki_snippets implementation details.

 1import time
 2import viser
 3from robot_descriptions.loaders.yourdfpy import load_robot_description
 4import numpy as np
 5
 6import pyroki as pk
 7from viser.extras import ViserUrdf
 8import pyroki_snippets as pks
 9
10
11def main():
12    """Main function for bimanual IK."""
13
14    urdf = load_robot_description("yumi_description")
15    target_link_names = ["yumi_link_7_r", "yumi_link_7_l"]
16
17    # Create robot.
18    robot = pk.Robot.from_urdf(urdf)
19
20    # Set up visualizer.
21    server = viser.ViserServer()
22    server.scene.add_grid("/ground", width=2, height=2)
23    urdf_vis = ViserUrdf(server, urdf, root_node_name="/base")
24
25    # Create interactive controller with initial position.
26    ik_target_0 = server.scene.add_transform_controls(
27        "/ik_target_0", scale=0.2, position=(0.41, -0.3, 0.56), wxyz=(0, 0, 1, 0)
28    )
29    ik_target_1 = server.scene.add_transform_controls(
30        "/ik_target_1", scale=0.2, position=(0.41, 0.3, 0.56), wxyz=(0, 0, 1, 0)
31    )
32    timing_handle = server.gui.add_number("Elapsed (ms)", 0.001, disabled=True)
33
34    while True:
35        # Solve IK.
36        start_time = time.time()
37        solution = pks.solve_ik_with_multiple_targets(
38            robot=robot,
39            target_link_names=target_link_names,
40            target_positions=np.array([ik_target_0.position, ik_target_1.position]),
41            target_wxyzs=np.array([ik_target_0.wxyz, ik_target_1.wxyz]),
42        )
43
44        # Update timing handle.
45        elapsed_time = time.time() - start_time
46        timing_handle.value = 0.99 * timing_handle.value + 0.01 * (elapsed_time * 1000)
47
48        # Update visualizer.
49        urdf_vis.update_cfg(solution)
50
51
52if __name__ == "__main__":
53    main()