7474import sys
7575import tempfile
7676
77+ import numpy as np
7778import pytest
7879import torch
7980import warp as wp
110111 "docs/superpowers/specs/2026-04-28-ovphysx-wheel-gaps-for-marco.md."
111112)
112113
114+ _MATERIAL_GAP_REASON = (
115+ "Requires a ``RIGID_BODY_MATERIAL`` TensorType (or a view-helper) on the "
116+ "ovphysx wheel side. ``Articulation.root_view`` is a per-tensor-type "
117+ "bindings dict on OVPhysX, so ``root_view.get_material_properties()`` / "
118+ "``set_material_properties()`` / ``max_shapes`` are not available. See "
119+ "docs/superpowers/specs/2026-04-28-ovphysx-wheel-gaps-for-marco.md."
120+ )
121+
122+
123+ def _read_binding_to_torch (articulation : Articulation , tensor_type : int , device : str | torch .device ) -> torch .Tensor :
124+ """Read an OVPhysX TensorBinding into a torch tensor on *device*.
125+
126+ Test-side adapter for the verbatim PhysX mirror. PhysX cross-checks the
127+ data class against the simulation via ``articulation.root_view.get_X()``
128+ accessors; on OVPhysX, ``root_view`` is a per-tensor-type bindings dict
129+ (no view-level getters), so we read the binding directly into a CPU
130+ numpy buffer (CPU-only types) and move the result to *device*.
131+ """
132+ binding = articulation .root_view [tensor_type ]
133+ np_buf = np .zeros (binding .shape , dtype = np .float32 )
134+ binding .read (np_buf )
135+ return torch .from_numpy (np_buf ).to (device )
136+
113137
114138# ---------------------------------------------------------------------------
115139# Session-level OvPhysxManager patches
@@ -1617,7 +1641,7 @@ def test_setting_velocity_limit_implicit(sim, num_articulations, device, vel_lim
16171641 sim .reset ()
16181642
16191643 # read the values set into the simulation
1620- physx_vel_limit = wp . to_torch (articulation . root_view . get_dof_max_velocities ()). to ( device )
1644+ physx_vel_limit = _read_binding_to_torch (articulation , TT . DOF_MAX_VELOCITY , device )
16211645 # check data buffer
16221646 torch .testing .assert_close (articulation .data .joint_velocity_limits .torch , physx_vel_limit )
16231647 # check actuator has simulation velocity limit
@@ -1666,7 +1690,7 @@ def test_setting_velocity_limit_explicit(sim, num_articulations, device, vel_lim
16661690 sim .reset ()
16671691
16681692 # collect limit init values
1669- physx_vel_limit = wp . to_torch (articulation . root_view . get_dof_max_velocities ()). to ( device )
1693+ physx_vel_limit = _read_binding_to_torch (articulation , TT . DOF_MAX_VELOCITY , device )
16701694 actuator_vel_limit = articulation .actuators ["joint" ].velocity_limit
16711695 actuator_vel_limit_sim = articulation .actuators ["joint" ].velocity_limit_sim
16721696
@@ -1730,7 +1754,7 @@ def test_setting_effort_limit_implicit(sim, num_articulations, device, effort_li
17301754 sim .reset ()
17311755
17321756 # obtain the physx effort limits
1733- physx_effort_limit = wp . to_torch (articulation . root_view . get_dof_max_forces ()). to ( device = device )
1757+ physx_effort_limit = _read_binding_to_torch (articulation , TT . DOF_MAX_FORCE , device )
17341758
17351759 # check that the two are equivalent
17361760 torch .testing .assert_close (
@@ -1784,7 +1808,7 @@ def test_setting_effort_limit_explicit(sim, num_articulations, device, effort_li
17841808 usd_default_effort_limit = 80.0
17851809
17861810 # collect limit init values
1787- physx_effort_limit = wp . to_torch (articulation . root_view . get_dof_max_forces ()). to ( device )
1811+ physx_effort_limit = _read_binding_to_torch (articulation , TT . DOF_MAX_FORCE , device )
17881812 actuator_effort_limit = articulation .actuators ["joint" ].effort_limit
17891813 actuator_effort_limit_sim = articulation .actuators ["joint" ].effort_limit_sim
17901814
@@ -1941,16 +1965,19 @@ def test_body_root_state(sim, num_articulations, device, with_offset):
19411965
19421966 # create com offsets — apply offset to the Arm body
19431967 num_bodies = articulation .num_bodies
1944- com = wp . to_torch (articulation . root_view . get_coms () )
1968+ com = _read_binding_to_torch (articulation , TT . BODY_COM_POSE , device )
19451969 link_offset = [1.0 , 0.0 , 0.0 ] # the offset from CenterPivot to Arm frames
19461970 new_com = torch .tensor (offset , device = device ).repeat (num_articulations , 1 , 1 )
19471971 com [:, arm_idx , :3 ] = new_com .squeeze (- 2 )
1948- articulation .root_view .set_coms (
1949- wp .from_torch (com .cpu (), dtype = wp .float32 ), wp .from_torch (env_idx .cpu (), dtype = wp .int32 )
1972+ # PhysX uses ``root_view.set_coms``; OVPhysX wraps the wheel
1973+ # ``BODY_COM_POSE`` write in :meth:`set_coms_index` (wp.transformf contract).
1974+ articulation .set_coms_index (
1975+ coms = wp .from_torch (com .contiguous (), dtype = wp .transformf ),
1976+ env_ids = wp .from_torch (env_idx , dtype = wp .int32 ),
19501977 )
19511978
19521979 # check they are set
1953- torch .testing .assert_close (wp . to_torch (articulation . root_view . get_coms ()) , com . cpu () )
1980+ torch .testing .assert_close (_read_binding_to_torch (articulation , TT . BODY_COM_POSE , device ) , com )
19541981
19551982 for i in range (50 ):
19561983 # perform step
@@ -2059,15 +2086,17 @@ def test_write_root_state(sim, num_articulations, device, with_offset, state_loc
20592086 offset = torch .tensor ([0.0 , 0.0 , 0.0 ]).repeat (num_articulations , 1 , 1 )
20602087
20612088 # create com offsets
2062- com = wp . to_torch (articulation . root_view . get_coms () )
2063- new_com = offset
2089+ com = _read_binding_to_torch (articulation , TT . BODY_COM_POSE , device )
2090+ new_com = offset . to ( device )
20642091 com [:, 0 , :3 ] = new_com .squeeze (- 2 )
2065- articulation .root_view .set_coms (
2066- wp .from_torch (com .cpu (), dtype = wp .float32 ), wp .from_torch (env_idx .cpu (), dtype = wp .int32 )
2092+ # See test_body_root_state for the PhysX → OVPhysX setter substitution.
2093+ articulation .set_coms_index (
2094+ coms = wp .from_torch (com .contiguous (), dtype = wp .transformf ),
2095+ env_ids = wp .from_torch (env_idx , dtype = wp .int32 ),
20672096 )
20682097
20692098 # check they are set
2070- torch .testing .assert_close (wp . to_torch (articulation . root_view . get_coms () ), com )
2099+ torch .testing .assert_close (_read_binding_to_torch (articulation , TT . BODY_COM_POSE , device ), com )
20712100
20722101 rand_state = torch .zeros (num_articulations , 13 , device = device )
20732102 rand_state [..., :7 ] = articulation .data .default_root_pose .torch
@@ -2443,7 +2472,7 @@ def test_write_joint_frictions_to_sim(sim, num_articulations, device, add_ground
24432472 # update buffers
24442473 articulation .update (sim .cfg .dt )
24452474
2446- friction_props_from_sim = wp . to_torch (articulation . root_view . get_dof_friction_properties () )
2475+ friction_props_from_sim = _read_binding_to_torch (articulation , TT . DOF_FRICTION_PROPERTIES , "cpu" )
24472476 joint_friction_coeff_sim = friction_props_from_sim [:, :, 0 ]
24482477 joint_dynamic_friction_coeff_sim = friction_props_from_sim [:, :, 1 ]
24492478 joint_viscous_friction_coeff_sim = friction_props_from_sim [:, :, 2 ]
@@ -2483,7 +2512,7 @@ def test_write_joint_frictions_to_sim(sim, num_articulations, device, add_ground
24832512 sim .step ()
24842513 articulation .update (sim .cfg .dt )
24852514
2486- friction_props_from_sim_2 = wp . to_torch (articulation . root_view . get_dof_friction_properties () )
2515+ friction_props_from_sim_2 = _read_binding_to_torch (articulation , TT . DOF_FRICTION_PROPERTIES , "cpu" )
24872516 joint_friction_coeff_sim_2 = friction_props_from_sim_2 [:, :, 0 ]
24882517 friction_dynamic_coef_sim_2 = friction_props_from_sim_2 [:, :, 1 ]
24892518 friction_viscous_coeff_sim_2 = friction_props_from_sim_2 [:, :, 2 ]
@@ -2499,6 +2528,7 @@ def test_write_joint_frictions_to_sim(sim, num_articulations, device, add_ground
24992528@pytest .mark .parametrize ("device" , ["cuda:0" , "cpu" ])
25002529@pytest .mark .parametrize ("articulation_type" , ["panda" ])
25012530@pytest .mark .isaacsim_ci
2531+ @pytest .mark .xfail (reason = _MATERIAL_GAP_REASON , strict = False )
25022532def test_set_material_properties (sim , num_articulations , device , add_ground_plane , articulation_type ):
25032533 """Test getting and setting material properties (friction/restitution) of articulation shapes."""
25042534 articulation_cfg = generate_articulation_cfg (articulation_type = articulation_type )
0 commit comments