@@ -408,6 +408,74 @@ def test_equality_weld(gs_sim, mj_sim, gs_solver):
408408 simulate_and_check_mujoco_consistency (gs_sim , mj_sim , qpos , num_steps = 300 , tol = tol )
409409
410410
411+ def test_dynamic_weld (show_viewer , tol ):
412+ scene = gs .Scene (
413+ show_viewer = show_viewer ,
414+ show_FPS = False ,
415+ )
416+ plane = scene .add_entity (
417+ gs .morphs .Plane (),
418+ )
419+ cube = scene .add_entity (
420+ gs .morphs .Box (
421+ size = (0.04 , 0.04 , 0.04 ),
422+ pos = (0.65 , 0.0 , 0.02 ),
423+ ),
424+ surface = gs .surfaces .Plastic (color = (1 , 0 , 0 )),
425+ )
426+ robot = scene .add_entity (
427+ gs .morphs .MJCF (
428+ file = "xml/universal_robots_ur5e/ur5e.xml" ,
429+ ),
430+ )
431+ scene .build (n_envs = 4 , env_spacing = (3.0 , 3.0 ))
432+
433+ end_effector = robot .get_link ("ee_virtual_link" )
434+
435+ # Compute up and down robot configurations
436+ ee_pos_up = np .array ((0.65 , 0.0 , 0.5 ), dtype = gs .np_float )
437+ ee_pos_down = np .array ((0.65 , 0.0 , 0.15 ), dtype = gs .np_float )
438+ qpos_up = robot .inverse_kinematics (
439+ link = end_effector ,
440+ pos = np .tile (ee_pos_up , (4 , 1 )),
441+ quat = np .tile (np .array ((0.0 , 1.0 , 0.0 , 0.0 ), dtype = gs .np_float ), (4 , 1 )),
442+ )
443+ qpos_down = robot .inverse_kinematics (
444+ link = end_effector ,
445+ pos = np .tile (ee_pos_down , (4 , 1 )),
446+ quat = np .tile (np .array ((0.0 , 1.0 , 0.0 , 0.0 ), dtype = gs .np_float ), (4 , 1 )),
447+ )
448+
449+ # move to pre-grasp pose
450+ robot .control_dofs_position (qpos_up )
451+ for i in range (120 ):
452+ scene .step ()
453+
454+ # reach
455+ robot .control_dofs_position (qpos_down )
456+ for i in range (70 ):
457+ scene .step ()
458+
459+ # add weld constraint and move back up
460+ scene .sim .rigid_solver .add_weld_constraint (cube .base_link .idx , end_effector .idx , envs_idx = (0 , 1 , 2 ))
461+ robot .control_dofs_position (qpos_up )
462+ for i in range (60 ):
463+ scene .step ()
464+ cubes_pos , cubes_quat = cube .get_pos (), cube .get_quat ()
465+ assert_allclose (torch .diff (cubes_quat , dim = 0 ), 0.0 , tol = 1e-3 )
466+ assert_allclose (torch .diff (cubes_pos [[0 , 1 , 2 ]], dim = 0 ), 0.0 , tol = tol )
467+ assert_allclose (cubes_pos [- 1 ] - cubes_pos [0 ], ee_pos_down - ee_pos_up , tol = 1e-2 )
468+
469+ # drop
470+ scene .sim .rigid_solver .delete_weld_constraint (cube .base_link .idx , end_effector .idx , envs_idx = (0 , 1 ))
471+ for i in range (110 ):
472+ scene .step ()
473+ cubes_pos , cubes_quat = cube .get_pos (), cube .get_quat ()
474+ assert_allclose (torch .diff (cubes_quat , dim = 0 ), 0.0 , tol = 1e-3 )
475+ assert_allclose (torch .diff (cubes_pos [[0 , 1 , 3 ]], dim = 0 ), 0.0 , tol = 1e-2 )
476+ assert_allclose (cubes_pos [2 ] - cubes_pos [0 ], ee_pos_up - ee_pos_down , tol = 1e-3 )
477+
478+
411479@pytest .mark .required
412480@pytest .mark .parametrize ("xml_path" , ["xml/one_ball_joint.xml" ])
413481@pytest .mark .parametrize ("gs_solver" , [gs .constraint_solver .CG , gs .constraint_solver .Newton ])
@@ -2300,7 +2368,7 @@ def _check_entity_positions(relative, tol):
23002368 entities [(False , True )].set_dofs_velocity (door_vel , 6 )
23012369 entities [(True , False )].set_dofs_velocity (door_vel )
23022370 entities [(True , True )].set_dofs_velocity (door_vel )
2303- link_1 = np . array ([ entities [(True , True )].link_start ], dtype = gs . np_int )
2371+ link_1 = entities [(True , True )].link_start
23042372 for key in ((False , False ), (False , True )):
23052373 link_2 = entities [key ].link_start
23062374 scene .rigid_solver .add_weld_constraint (link_1 , link_2 )
0 commit comments