|
10 | 10 | import pybullet as p
|
11 | 11 | import pybullet_data
|
12 | 12 |
|
13 |
| -visualize = False |
| 13 | +visualize = True |
14 | 14 |
|
| 15 | +TEST_DIR = os.path.dirname(__file__) |
15 | 16 |
|
16 | 17 | def _make_robot_translucent(robot_id, alpha=0.4):
|
17 | 18 | def make_transparent(link):
|
@@ -206,6 +207,73 @@ def test_ik_in_place_no_err():
|
206 | 207 | assert torch.allclose(sol.err_rot[0], torch.zeros(1, device=device), atol=1e-6)
|
207 | 208 |
|
208 | 209 |
|
| 210 | +def test_extract_serial_chain_from_tree(): |
| 211 | + pytorch_seed.seed(2) |
| 212 | + device = "cuda" if torch.cuda.is_available() else "cpu" |
| 213 | + # device = "cpu" |
| 214 | + urdf = "widowx/wx250s.urdf" |
| 215 | + full_urdf = os.path.join(TEST_DIR, urdf) |
| 216 | + chain = pk.build_serial_chain_from_urdf(open(full_urdf, mode="rb").read(), "ee_gripper_link") |
| 217 | + # chain = pk.SerialChain(chain, "ee_gripper_link", "base_link") |
| 218 | + chain = chain.to(device=device) |
| 219 | + |
| 220 | + # full chain should have DOF = 8, however since we are creating just a serial chain to ee_gripper_link, should be 6 |
| 221 | + # TODO pretty tree print |
| 222 | + """ |
| 223 | + / |
| 224 | + └── gripper_bar_link |
| 225 | + └── fingers_link |
| 226 | + ├── left_finger_link |
| 227 | + ├── right_finger_link |
| 228 | + └── ee_gripper_link |
| 229 | + """ |
| 230 | + |
| 231 | + # robot frame |
| 232 | + pos = torch.tensor([0.0, 0.0, 0.0], device=device) |
| 233 | + rot = torch.tensor([0.0, 0.0, 0.0], device=device) |
| 234 | + rob_tf = pk.Transform3d(pos=pos, rot=rot, device=device) |
| 235 | + |
| 236 | + # world frame goal |
| 237 | + M = 1000 |
| 238 | + # generate random goal joint angles (so these are all achievable) |
| 239 | + # use the joint limits to generate random joint angles |
| 240 | + lim = torch.tensor(chain.get_joint_limits(), device=device) |
| 241 | + goal_q = torch.rand(M, 7, device=device) * (lim[1] - lim[0]) + lim[0] |
| 242 | + |
| 243 | + # get ee pose (in robot frame) |
| 244 | + goal_in_rob_frame_tf = chain.forward_kinematics(goal_q) |
| 245 | + |
| 246 | + # transform to world frame for visualization |
| 247 | + goal_tf = rob_tf.compose(goal_in_rob_frame_tf) |
| 248 | + goal = goal_tf.get_matrix() |
| 249 | + goal_pos = goal[..., :3, 3] |
| 250 | + goal_rot = pk.matrix_to_euler_angles(goal[..., :3, :3], "XYZ") |
| 251 | + |
| 252 | + num_retries = 10 |
| 253 | + ik = pk.PseudoInverseIK(chain, max_iterations=30, num_retries=num_retries, |
| 254 | + joint_limits=lim.T, |
| 255 | + early_stopping_any_converged=True, |
| 256 | + early_stopping_no_improvement="all", |
| 257 | + # line_search=pk.BacktrackingLineSearch(max_lr=0.2), |
| 258 | + debug=False, |
| 259 | + lr=0.2) |
| 260 | + |
| 261 | + # do IK |
| 262 | + timer_start = timer() |
| 263 | + sol = ik.solve(goal_in_rob_frame_tf) |
| 264 | + timer_end = timer() |
| 265 | + print("IK took %f seconds" % (timer_end - timer_start)) |
| 266 | + print("IK converged number: %d / %d" % (sol.converged.sum(), sol.converged.numel())) |
| 267 | + print("IK took %d iterations" % sol.iterations) |
| 268 | + print("IK solved %d / %d goals" % (sol.converged_any.sum(), M)) |
| 269 | + |
| 270 | + # check that solving again produces the same solutions |
| 271 | + sol_again = ik.solve(goal_in_rob_frame_tf) |
| 272 | + assert torch.allclose(sol.solutions, sol_again.solutions) |
| 273 | + assert torch.allclose(sol.converged, sol_again.converged) |
| 274 | + |
| 275 | + |
209 | 276 | if __name__ == "__main__":
|
210 |
| - test_jacobian_follower() |
211 |
| - test_ik_in_place_no_err() |
| 277 | + # test_jacobian_follower() |
| 278 | + # test_ik_in_place_no_err() |
| 279 | + test_extract_serial_chain_from_tree() |
0 commit comments