Skip to content

Commit 6017c38

Browse files
committed
Fix tests
* Fix x1 anchor pose test in isaaclab_arena/tests/test_xr_anchor_pose.py to adapt to the new XrCfg * Fix G1DecoupledWBCPinkAction to no crash for zero norm quaternion inputs from the isaaclab_arena/tests/test_device_and_retargeter_registry.py test
1 parent 99e1780 commit 6017c38

File tree

3 files changed

+55
-39
lines changed

3 files changed

+55
-39
lines changed

isaaclab_arena/tests/test_device_and_retargeter_registry.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ def _test_all_devices_and_retargeters_in_registry(simulation_app):
6464
for _ in tqdm.tqdm(range(NUM_STEPS)):
6565
with torch.inference_mode():
6666
actions = torch.zeros(env.action_space.shape, device=env.unwrapped.device)
67-
if embodiment_name == "g1_wbc_pink":
68-
# G1 WBC pink action: wrist quats at 5:9 and 12:16 (wxyz); identity = (1,0,0,0)
69-
actions[..., 5] = 1.0
70-
actions[..., 12] = 1.0
7167
env.step(actions)
7268

7369
# Close the environment using safe teardown

isaaclab_arena/tests/test_xr_anchor_pose.py

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -89,42 +89,56 @@ def _test_gr1t2_xr_anchor_pose(simulation_app) -> bool:
8989

9090

9191
def _test_g1_xr_anchor_pose(simulation_app) -> bool:
92-
"""Test G1 XR anchor pose at origin and with robot transformation."""
92+
"""Test G1 XR anchor config: fixed prim-relative anchor (pelvis), independent of initial pose."""
93+
from isaaclab.devices.openxr.xr_cfg import XrAnchorRotationMode
94+
9395
from isaaclab_arena.assets.asset_registry import AssetRegistry
9496
from isaaclab_arena.utils.pose import Pose
9597

96-
# Test 1: XR anchor at origin (no initial pose)
9798
asset_registry = AssetRegistry()
9899
embodiment = asset_registry.get_asset_by_name("g1_wbc_pink")()
99100
xr_cfg = embodiment.get_xr_cfg()
100101

101-
expected_pos = embodiment._xr_offset.position_xyz
102-
expected_rot = embodiment._xr_offset.rotation_wxyz
102+
# G1 uses a fixed prim-relative XrCfg: anchor offset and rotation are constant
103+
expected_pos = (0.0, 0.0, -1.0)
104+
expected_rot = (0.70711, 0.0, 0.0, -0.70711)
105+
expected_anchor_prim = "/World/envs/env_0/Robot/pelvis"
103106

107+
np.testing.assert_allclose(
108+
xr_cfg.anchor_pos,
109+
expected_pos,
110+
rtol=1e-5,
111+
err_msg=f"G1 XR anchor_pos should be fixed offset: expected {expected_pos}, got {xr_cfg.anchor_pos}",
112+
)
113+
np.testing.assert_allclose(
114+
xr_cfg.anchor_rot,
115+
expected_rot,
116+
rtol=1e-5,
117+
err_msg=f"G1 XR anchor_rot should be fixed: expected {expected_rot}, got {xr_cfg.anchor_rot}",
118+
)
104119
assert (
105-
xr_cfg.anchor_pos == expected_pos
106-
), f"XR anchor position should match offset at origin: expected {expected_pos}, got {xr_cfg.anchor_pos}"
120+
xr_cfg.anchor_prim_path == expected_anchor_prim
121+
), f"G1 XR anchor_prim_path should be pelvis: expected {expected_anchor_prim}, got {xr_cfg.anchor_prim_path}"
122+
assert xr_cfg.fixed_anchor_height is True, "G1 XR fixed_anchor_height should be True"
107123
assert (
108-
xr_cfg.anchor_rot == expected_rot
109-
), f"XR anchor rotation should match offset at origin: expected {expected_rot}, got {xr_cfg.anchor_rot}"
124+
xr_cfg.anchor_rotation_mode == XrAnchorRotationMode.FOLLOW_PRIM_SMOOTHED
125+
), "G1 XR anchor_rotation_mode should be FOLLOW_PRIM_SMOOTHED"
110126

111-
# Test 2: XR anchor with robot position
112-
robot_pose = Pose(position_xyz=(0.5, 1.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0)) # No rotation
127+
# With initial pose set, config is unchanged (anchor is relative to pelvis prim, not world)
128+
robot_pose = Pose(position_xyz=(0.5, 1.0, 0.0), rotation_wxyz=(1.0, 0.0, 0.0, 0.0))
113129
embodiment.set_initial_pose(robot_pose)
114-
xr_cfg = embodiment.get_xr_cfg()
115-
116-
# G1 offset is (0.0, 0.0, -1.0)
117-
expected_pos = (
118-
robot_pose.position_xyz[0] + embodiment._xr_offset.position_xyz[0], # 0.5 + 0.0 = 0.5
119-
robot_pose.position_xyz[1] + embodiment._xr_offset.position_xyz[1], # 1.0 + 0.0 = 1.0
120-
robot_pose.position_xyz[2] + embodiment._xr_offset.position_xyz[2], # 0.0 + (-1.0) = -1.0
121-
)
122-
130+
xr_cfg_after = embodiment.get_xr_cfg()
123131
np.testing.assert_allclose(
124-
xr_cfg.anchor_pos,
132+
xr_cfg_after.anchor_pos,
125133
expected_pos,
126134
rtol=1e-5,
127-
err_msg=f"XR anchor position incorrect with robot pose: expected {expected_pos}, got {xr_cfg.anchor_pos}",
135+
err_msg="G1 XR anchor_pos should remain fixed after set_initial_pose",
136+
)
137+
np.testing.assert_allclose(
138+
xr_cfg_after.anchor_rot,
139+
expected_rot,
140+
rtol=1e-5,
141+
err_msg="G1 XR anchor_rot should remain fixed after set_initial_pose",
128142
)
129143

130144
return True
@@ -176,13 +190,13 @@ def test_gr1t2_xr_anchor_pose():
176190
assert result, "GR1T2 XR anchor pose test failed"
177191

178192

179-
# def test_g1_xr_anchor_pose():
180-
# """Test G1 XR anchor pose behavior."""
181-
# result = run_simulation_app_function(
182-
# _test_g1_xr_anchor_pose,
183-
# headless=HEADLESS,
184-
# )
185-
# assert result, "G1 XR anchor pose test failed"
193+
def test_g1_xr_anchor_pose():
194+
"""Test G1 XR anchor pose behavior."""
195+
result = run_simulation_app_function(
196+
_test_g1_xr_anchor_pose,
197+
headless=HEADLESS,
198+
)
199+
assert result, "G1 XR anchor pose test failed"
186200

187201

188202
def test_xr_anchor_multiple_positions():
@@ -196,5 +210,5 @@ def test_xr_anchor_multiple_positions():
196210

197211
if __name__ == "__main__":
198212
test_gr1t2_xr_anchor_pose()
199-
# test_g1_xr_anchor_pose()
213+
test_g1_xr_anchor_pose()
200214
test_xr_anchor_multiple_positions()

isaaclab_arena_g1/g1_env/mdp/actions/g1_decoupled_wbc_pink_action.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,22 @@ def process_actions(self, actions: torch.Tensor):
215215
"""
216216
# Extract upper body left/right arm pos/quat from actions
217217
left_arm_pos = actions_clone[:, LEFT_WRIST_POS_START_IDX:LEFT_WRIST_POS_END_IDX].squeeze(0).cpu()
218-
left_arm_quat = actions_clone[:, LEFT_WRIST_QUAT_START_IDX:LEFT_WRIST_QUAT_END_IDX].squeeze(0).cpu()
218+
left_arm_quat = actions_clone[:, LEFT_WRIST_QUAT_START_IDX:LEFT_WRIST_QUAT_END_IDX].squeeze(0).cpu().numpy()
219219
right_arm_pos = actions_clone[:, RIGHT_WRIST_POS_START_IDX:RIGHT_WRIST_POS_END_IDX].squeeze(0).cpu()
220-
right_arm_quat = actions_clone[:, RIGHT_WRIST_QUAT_START_IDX:RIGHT_WRIST_QUAT_END_IDX].squeeze(0).cpu()
220+
right_arm_quat = actions_clone[:, RIGHT_WRIST_QUAT_START_IDX:RIGHT_WRIST_QUAT_END_IDX].squeeze(0).cpu().numpy()
221+
222+
# Replace zero-norm quaternions with identity (e.g. zero actions from env.step(zeros))
223+
_IDENTITY_QUAT_WXYZ = np.array([1.0, 0.0, 0.0, 0.0], dtype=np.float64)
224+
for q in (left_arm_quat, right_arm_quat):
225+
if np.linalg.norm(q) < 1e-8:
226+
q[:] = _IDENTITY_QUAT_WXYZ
221227

222228
# Convert from pos/quat to 4x4 transform matrix
223229
# Scipy requires quat xyzw, IsaacLab uses wxyz so a conversion is needed
224-
left_arm_quat = np.roll(left_arm_quat, -1)
225-
right_arm_quat = np.roll(right_arm_quat, -1)
226-
left_rotmat = R.from_quat(left_arm_quat).as_matrix()
227-
right_rotmat = R.from_quat(right_arm_quat).as_matrix()
230+
left_arm_quat_xyzw = np.roll(left_arm_quat, -1)
231+
right_arm_quat_xyzw = np.roll(right_arm_quat, -1)
232+
left_rotmat = R.from_quat(left_arm_quat_xyzw).as_matrix()
233+
right_rotmat = R.from_quat(right_arm_quat_xyzw).as_matrix()
228234

229235
left_arm_pose = np.eye(4)
230236
left_arm_pose[:3, :3] = left_rotmat

0 commit comments

Comments
 (0)