Spaces:
Sleeping
Sleeping
| # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved. | |
| # NVIDIA CORPORATION and its licensors retain all intellectual property | |
| # and proprietary rights in and to this software, related documentation | |
| # and any modifications thereto. Any use, reproduction, disclosure or | |
| # distribution of this software and related documentation without an express | |
| # license agreement from NVIDIA CORPORATION is strictly prohibited. | |
| import math | |
| import unittest | |
| import warp as wp | |
| import warp.sim | |
| from warp.tests.unittest_utils import * | |
| wp.init() | |
| def build_ant(num_envs): | |
| builder = wp.sim.ModelBuilder() | |
| for i in range(num_envs): | |
| wp.sim.parse_mjcf( | |
| os.path.join(os.path.dirname(__file__), "../../examples/assets/nv_ant.xml"), | |
| builder, | |
| up_axis="y", | |
| ) | |
| coord_count = 15 | |
| dof_count = 14 | |
| coord_start = i * coord_count | |
| dof_start = i * dof_count | |
| # base | |
| builder.joint_q[coord_start : coord_start + 3] = [i * 2.0, 0.70, 0.0] | |
| builder.joint_q[coord_start + 3 : coord_start + 7] = wp.quat_from_axis_angle((1.0, 0.0, 0.0), -math.pi * 0.5) | |
| # joints | |
| builder.joint_q[coord_start + 7 : coord_start + coord_count] = [0.0, 1.0, 0.0, -1.0, 0.0, -1.0, 0.0, 1.0] | |
| builder.joint_qd[dof_start + 6 : dof_start + dof_count] = [1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0] | |
| return builder | |
| def build_complex_joint_mechanism(chain_length): | |
| builder = wp.sim.ModelBuilder() | |
| com0 = wp.vec3(1.0, 2.0, 3.0) | |
| com1 = wp.vec3(4.0, 5.0, 6.0) | |
| com2 = wp.vec3(7.0, 8.0, 9.0) | |
| ax0 = wp.normalize(wp.vec3(-1.0, 2.0, 3.0)) | |
| ax1 = wp.normalize(wp.vec3(4.0, -1.0, 2.0)) | |
| ax2 = wp.normalize(wp.vec3(-3.0, 4.0, -1.0)) | |
| # declare some transforms with nonzero translation and orientation | |
| tf0 = wp.transform(wp.vec3(1.0, 2.0, 3.0), wp.quat_from_axis_angle((1.0, 0.0, 0.0), math.pi * 0.25)) | |
| tf1 = wp.transform(wp.vec3(4.0, 5.0, 6.0), wp.quat_from_axis_angle((0.0, 1.0, 0.0), math.pi * 0.5)) | |
| tf2 = wp.transform(wp.vec3(7.0, 8.0, 9.0), wp.quat_from_axis_angle((0.0, 0.0, 1.0), math.pi * 0.75)) | |
| parent = -1 | |
| for i in range(chain_length): | |
| b0 = builder.add_body(com=com0) | |
| builder.add_joint_fixed(parent=parent, child=b0, parent_xform=tf1, child_xform=tf0) | |
| assert builder.articulation_count == 1 | |
| b1 = builder.add_body(com=com1) | |
| builder.add_joint_revolute(parent=b0, child=b1, parent_xform=tf1, child_xform=tf2, axis=ax1) | |
| builder.joint_q[-1] = 0.3 | |
| builder.joint_qd[-1] = 1.0 | |
| b2 = builder.add_body(com=com2) | |
| builder.add_joint_universal(parent=b1, child=b2, parent_xform=tf2, child_xform=tf0, axis_0=ax0, axis_1=ax1) | |
| builder.joint_q[-2:] = [0.3, 0.5] | |
| builder.joint_qd[-2:] = [1.0, -1.0] | |
| b3 = builder.add_body(com=com0) | |
| builder.add_joint_ball(parent=b2, child=b3, parent_xform=tf0, child_xform=tf1) | |
| builder.joint_q[-4:] = list(wp.quat_from_axis_angle(ax0, 0.7)) | |
| builder.joint_qd[-3:] = [1.0, -0.6, 1.5] | |
| b4 = builder.add_body(com=com1) | |
| builder.add_joint_compound( | |
| parent=b3, | |
| child=b4, | |
| parent_xform=tf2, | |
| child_xform=tf1, | |
| axis_0=(0, 0, 1), | |
| axis_1=(1, 0, 0), | |
| axis_2=(0, 1, 0), | |
| ) | |
| builder.joint_q[-3:] = [0.3, 0.5, 0.27] | |
| builder.joint_qd[-3:] = [1.23, -1.0, 0.5] | |
| b5 = builder.add_body(com=com2) | |
| builder.add_joint_prismatic( | |
| parent=b4, | |
| child=b5, | |
| parent_xform=tf2, | |
| child_xform=tf0, | |
| axis=ax0, | |
| ) | |
| builder.joint_q[-1] = 0.92 | |
| builder.joint_qd[-1] = -0.63 | |
| b6 = builder.add_body(com=com0) | |
| builder.add_joint_d6( | |
| parent=b5, | |
| child=b6, | |
| parent_xform=tf0, | |
| child_xform=tf2, | |
| linear_axes=[ax0, ax1, wp.cross(ax0, ax1)], | |
| angular_axes=[ax1, ax2, wp.cross(ax1, ax2)], | |
| ) | |
| builder.joint_q[-6:] = [0.3, 0.5, 0.7, 0.9, 1.1, 1.3] | |
| builder.joint_qd[-6:] = [1.0, -1.0, 0.5, 0.8, -0.3, 0.1] | |
| b7 = builder.add_body(com=com1) | |
| builder.add_joint_free( | |
| parent=b6, | |
| child=b7, | |
| parent_xform=tf1, | |
| child_xform=tf2, | |
| ) | |
| builder.joint_q[-7:] = [0.5, -0.9, 1.4] + list(wp.quat_rpy(0.3, -0.5, 0.7)) | |
| builder.joint_qd[-6:] = [1.0, -1.0, 0.5, 0.8, -0.3, 0.1] | |
| b8 = builder.add_body(com=com2) | |
| builder.add_joint_distance( | |
| parent=b7, | |
| child=b8, | |
| parent_xform=tf1, | |
| child_xform=tf2, | |
| ) | |
| builder.joint_q[-7:] = [-0.3, -0.7, 0.2] + list(wp.quat_rpy(0.1, 0.1, 0.4)) | |
| builder.joint_qd[-6:] = [-0.34, 0.5, -0.6, -0.4, 0.2, 0.1] | |
| # D6 joint that behaves like a fixed joint | |
| b9 = builder.add_body(com=com0) | |
| builder.add_joint_d6( | |
| parent=b8, | |
| child=b9, | |
| parent_xform=tf0, | |
| child_xform=tf2, | |
| linear_axes=[], | |
| angular_axes=[], | |
| ) | |
| b10 = builder.add_body(com=com0) | |
| builder.add_joint_d6( | |
| parent=b9, | |
| child=b10, | |
| parent_xform=tf1, | |
| child_xform=tf2, | |
| linear_axes=[ax1], | |
| angular_axes=[ax2, ax0], | |
| ) | |
| builder.joint_q[-3:] = [0.3, 0.5, 0.7] | |
| builder.joint_qd[-3:] = [1.0, -1.0, 0.5] | |
| b11 = builder.add_body(com=com1) | |
| builder.add_joint_d6( | |
| parent=b10, | |
| child=b11, | |
| parent_xform=tf1, | |
| child_xform=tf2, | |
| linear_axes=[ax1, ax0, wp.cross(ax1, ax0)], | |
| angular_axes=[], | |
| ) | |
| builder.joint_q[-3:] = [0.3, 0.5, 0.7] | |
| builder.joint_qd[-3:] = [1.0, -1.0, 0.5] | |
| b12 = builder.add_body(com=com2) | |
| builder.add_joint_d6( | |
| parent=b11, | |
| child=b12, | |
| parent_xform=tf1, | |
| child_xform=tf2, | |
| linear_axes=[], | |
| angular_axes=[ax1, ax2, wp.cross(ax1, ax2)], | |
| ) | |
| builder.joint_q[-3:] = [0.3, 0.5, 0.7] | |
| builder.joint_qd[-3:] = [1.0, -1.0, 0.5] | |
| parent = b12 | |
| return builder | |
| def check_fk_ik(builder, device): | |
| model = builder.finalize(device) | |
| state = model.state() | |
| q_fk = model.joint_q.numpy() | |
| qd_fk = model.joint_qd.numpy() | |
| wp.sim.eval_fk(model, model.joint_q, model.joint_qd, None, state) | |
| q_ik = wp.zeros_like(model.joint_q) | |
| qd_ik = wp.zeros_like(model.joint_qd) | |
| wp.sim.eval_ik(model, state, q_ik, qd_ik) | |
| # adjust numpy print settings | |
| # np.set_printoptions(precision=4, floatmode="fixed", suppress=True) | |
| # print("q:") | |
| # print(np.array(q_fk)) | |
| # print(q_ik.numpy()) | |
| # print("qd:") | |
| # print(np.array(qd_fk)) | |
| # print(qd_ik.numpy()) | |
| assert_np_equal(q_ik.numpy(), q_fk, tol=1e-4) | |
| assert_np_equal(qd_ik.numpy(), qd_fk, tol=1e-4) | |
| def test_fk_ik_ant(test, device): | |
| builder = build_ant(3) | |
| check_fk_ik(builder, device) | |
| def test_fk_ik_complex_joint_mechanism(test, device): | |
| builder = build_complex_joint_mechanism(2) | |
| check_fk_ik(builder, device) | |
| devices = get_test_devices() | |
| class TestKinematics(unittest.TestCase): | |
| pass | |
| add_function_test(TestKinematics, "test_fk_ik_ant", test_fk_ik_ant, devices=devices) | |
| add_function_test( | |
| TestKinematics, "test_fk_ik_complex_joint_mechanism", test_fk_ik_complex_joint_mechanism, devices=devices | |
| ) | |
| if __name__ == "__main__": | |
| wp.build.clear_kernel_cache() | |
| unittest.main(verbosity=2, failfast=False) | |