33#
44# SPDX-License-Identifier: BSD-3-Clause
55
6+ from isaaclab_newton .physics import MJWarpSolverCfg , NewtonCfg
67from isaaclab_physx .physics import PhysxCfg
78
89import isaaclab .envs .mdp as mdp
910import isaaclab .sim as sim_utils
11+ from isaaclab .actuators import ImplicitActuatorCfg
1012from isaaclab .assets import ArticulationCfg , RigidObjectCfg
1113from isaaclab .envs import DirectMARLEnvCfg
1214from isaaclab .managers import EventTermCfg as EventTerm
1719from isaaclab .sim .spawners .materials .physics_materials_cfg import RigidBodyMaterialCfg
1820from isaaclab .utils import configclass
1921
22+ from isaaclab_tasks .direct .shadow_hand .shadow_hand_env_cfg import ShadowHandRobotCfg
23+ from isaaclab_tasks .utils import PresetCfg
24+
2025from isaaclab_assets .robots .shadow_hand import SHADOW_HAND_CFG
2126
2227
2328@configclass
2429class EventCfg :
25- """Configuration for randomization."""
30+ """Configuration for randomization (PhysX path).
31+
32+ Note: this config is currently not wired into ``ShadowHandOverEnvCfg.events`` -
33+ it is kept as a reference for future event-randomization work. The event
34+ terms here use PhysX-only APIs (rigid-body materials, fixed tendons), so
35+ they would need a Newton variant before being enabled in the env.
36+ """
2637
2738 # -- robot
2839 robot_physics_material = EventTerm (
@@ -113,6 +124,182 @@ class EventCfg:
113124 )
114125
115126
127+ # Reuse the single-agent Shadow Hand Newton port (USD path, ``rot`` reapplication
128+ # workaround, effort limits, joint regex). The multi-agent variant only diverges
129+ # in actuator gains (stiffness/damping bumped for the catch task) and adds a
130+ # ``distal_passive`` override for the J0 USD-baked values.
131+ _SHADOW_HAND_NEWTON_CFG = ShadowHandRobotCfg ().newton
132+
133+
134+ def _newton_shadow_hand_cfg (
135+ prim_path : str , init_pos : tuple [float , float , float ], init_rot : tuple [float , float , float , float ]
136+ ) -> ArticulationCfg :
137+ """Newton Shadow Hand cfg parameterized by per-robot ``prim_path`` and init pose.
138+
139+ Two overrides versus the single-agent Newton port:
140+
141+ * ``fingers`` actuator: ``stiffness=20.0`` / ``damping=2.0`` (vs PhysX's
142+ ``5.0`` / ``0.5`` on wrists and ``1.0`` / ``0.1`` on fingers). PhysX layers
143+ ``fixed_tendons_props(limit_stiffness=30, damping=0.1)`` and runs
144+ ``solver_position_iteration_count=8`` per substep — both amplify the
145+ effective torque per unit nominal gain. Newton's MJWarp implicit-PD path
146+ has neither, so a larger nominal gain is needed for comparable joint
147+ authority. ``20.0`` / ``2.0`` is the smallest tested setting at which
148+ MAPPO learns the catch (mean reward at iter 200 / 2048 envs goes from
149+ ~27 at PhysX-mirrored gains to ~777).
150+ * ``distal_passive`` actuator on the four ``robot0_(FF|MF|RF|LF)J0`` joints
151+ with ``stiffness=10.0`` / ``damping=0.1``. The Newton USD bakes
152+ ``stiffness=286 / damping=57`` on these joints from the MJCF→USD
153+ translation, which fights the ``MjcTendon`` coupling and bounces the
154+ ball. ``stiffness=10`` (1/3 of PhysX ``limit_stiffness=30``) keeps the
155+ joints near-passive while the tendon constraint dominates.
156+ """
157+ return _SHADOW_HAND_NEWTON_CFG .replace (
158+ prim_path = prim_path ,
159+ init_state = _SHADOW_HAND_NEWTON_CFG .init_state .replace (pos = init_pos , rot = init_rot ),
160+ actuators = {
161+ "fingers" : _SHADOW_HAND_NEWTON_CFG .actuators ["fingers" ].replace (stiffness = 20.0 , damping = 2.0 ),
162+ "distal_passive" : ImplicitActuatorCfg (
163+ joint_names_expr = ["robot0_(FF|MF|RF|LF)J0" ],
164+ stiffness = 10.0 ,
165+ damping = 0.1 ,
166+ friction = 1e-2 ,
167+ armature = 2e-3 ,
168+ ),
169+ },
170+ )
171+
172+
173+ @configclass
174+ class RightRobotCfg (PresetCfg ):
175+ physx = SHADOW_HAND_CFG .replace (prim_path = "/World/envs/env_.*/RightRobot" ).replace (
176+ init_state = ArticulationCfg .InitialStateCfg (
177+ pos = (0.0 , 0.0 , 0.5 ),
178+ rot = (0.0 , 0.0 , 0.0 , 1.0 ),
179+ joint_pos = {".*" : 0.0 },
180+ )
181+ )
182+ newton = _newton_shadow_hand_cfg (
183+ prim_path = "/World/envs/env_.*/RightRobot" ,
184+ init_pos = (0.0 , 0.0 , 0.5 ),
185+ init_rot = (0.0 , 0.0 , 0.0 , 1.0 ),
186+ )
187+ default = physx
188+
189+
190+ @configclass
191+ class LeftRobotCfg (PresetCfg ):
192+ physx = SHADOW_HAND_CFG .replace (prim_path = "/World/envs/env_.*/LeftRobot" ).replace (
193+ init_state = ArticulationCfg .InitialStateCfg (
194+ pos = (0.0 , - 1.0 , 0.5 ),
195+ rot = (0.0 , 0.0 , 1.0 , 0.0 ),
196+ joint_pos = {".*" : 0.0 },
197+ )
198+ )
199+ newton = _newton_shadow_hand_cfg (
200+ prim_path = "/World/envs/env_.*/LeftRobot" ,
201+ init_pos = (0.0 , - 1.0 , 0.5 ),
202+ init_rot = (0.0 , 0.0 , 1.0 , 0.0 ),
203+ )
204+ default = physx
205+
206+
207+ @configclass
208+ class ObjectCfg (PresetCfg ):
209+ """Hand-over object preset.
210+
211+ Both backends spawn the same procedural sphere as a free rigid body:
212+ Newton's :class:`~isaaclab_newton.assets.RigidObject` resolves the
213+ asset via the ``UsdPhysics.RigidBodyAPI`` that
214+ :class:`~isaaclab.sim.RigidBodyPropertiesCfg` applies. The Newton
215+ variant drops PhysX-only knobs (per-shape solver iterations, sleep
216+ thresholds, max depenetration velocity, custom physics material).
217+ """
218+
219+ physx = RigidObjectCfg (
220+ prim_path = "/World/envs/env_.*/object" ,
221+ spawn = sim_utils .SphereCfg (
222+ radius = 0.0335 ,
223+ visual_material = sim_utils .PreviewSurfaceCfg (diffuse_color = (0.8 , 1.0 , 0.0 )),
224+ physics_material = sim_utils .RigidBodyMaterialCfg (static_friction = 0.7 ),
225+ rigid_props = sim_utils .RigidBodyPropertiesCfg (
226+ kinematic_enabled = False ,
227+ disable_gravity = False ,
228+ enable_gyroscopic_forces = True ,
229+ solver_position_iteration_count = 8 ,
230+ solver_velocity_iteration_count = 0 ,
231+ sleep_threshold = 0.005 ,
232+ stabilization_threshold = 0.0025 ,
233+ max_depenetration_velocity = 1000.0 ,
234+ ),
235+ collision_props = sim_utils .CollisionPropertiesCfg (),
236+ mass_props = sim_utils .MassPropertiesCfg (density = 500.0 ),
237+ ),
238+ init_state = RigidObjectCfg .InitialStateCfg (pos = (0.0 , - 0.39 , 0.54 ), rot = (0.0 , 0.0 , 0.0 , 1.0 )),
239+ )
240+ newton = RigidObjectCfg (
241+ prim_path = "/World/envs/env_.*/object" ,
242+ spawn = sim_utils .SphereCfg (
243+ radius = 0.0335 ,
244+ visual_material = sim_utils .PreviewSurfaceCfg (diffuse_color = (0.8 , 1.0 , 0.0 )),
245+ rigid_props = sim_utils .RigidBodyPropertiesCfg (
246+ kinematic_enabled = False ,
247+ disable_gravity = False ,
248+ enable_gyroscopic_forces = True ,
249+ ),
250+ collision_props = sim_utils .CollisionPropertiesCfg (),
251+ mass_props = sim_utils .MassPropertiesCfg (density = 500.0 ),
252+ ),
253+ init_state = RigidObjectCfg .InitialStateCfg (pos = (0.0 , - 0.39 , 0.54 ), rot = (0.0 , 0.0 , 0.0 , 1.0 )),
254+ )
255+ default = physx
256+
257+
258+ @configclass
259+ class ShadowHandOverSceneCfg (PresetCfg ):
260+ """Scene preset.
261+
262+ PhysX supports ``clone_in_fabric=True`` for faster cloning. Newton's
263+ cloning path does not, so the Newton variant disables Fabric cloning.
264+ """
265+
266+ physx : InteractiveSceneCfg = InteractiveSceneCfg (
267+ num_envs = 2048 , env_spacing = 1.5 , replicate_physics = True , clone_in_fabric = True
268+ )
269+ newton : InteractiveSceneCfg = InteractiveSceneCfg (
270+ num_envs = 2048 , env_spacing = 1.5 , replicate_physics = True , clone_in_fabric = False
271+ )
272+ default : InteractiveSceneCfg = physx
273+
274+
275+ @configclass
276+ class PhysicsCfg (PresetCfg ):
277+ """Physics-backend preset (PhysX vs Newton/MJWarp).
278+
279+ Newton settings mirror the single-agent ShadowHand Newton port: elliptic
280+ cone, ``impratio=10`` (favors normal contacts over friction), 100 solver
281+ iterations, 2 substeps. Empirically converges on the single-agent ShadowHand
282+ tasks; tuning may be needed for handover-specific contact dynamics.
283+ """
284+
285+ physx = PhysxCfg (bounce_threshold_velocity = 0.2 )
286+ newton = NewtonCfg (
287+ solver_cfg = MJWarpSolverCfg (
288+ solver = "newton" ,
289+ integrator = "implicitfast" ,
290+ njmax = 200 ,
291+ nconmax = 70 ,
292+ impratio = 10.0 ,
293+ cone = "elliptic" ,
294+ update_data_interval = 2 ,
295+ iterations = 100 ,
296+ ),
297+ num_substeps = 2 ,
298+ debug_mode = False ,
299+ )
300+ default = physx
301+
302+
116303@configclass
117304class ShadowHandOverEnvCfg (DirectMARLEnvCfg ):
118305 # env
@@ -131,25 +318,11 @@ class ShadowHandOverEnvCfg(DirectMARLEnvCfg):
131318 static_friction = 1.0 ,
132319 dynamic_friction = 1.0 ,
133320 ),
134- physics = PhysxCfg (
135- bounce_threshold_velocity = 0.2 ,
136- ),
321+ physics = PhysicsCfg (),
137322 )
138323 # robot
139- right_robot_cfg : ArticulationCfg = SHADOW_HAND_CFG .replace (prim_path = "/World/envs/env_.*/RightRobot" ).replace (
140- init_state = ArticulationCfg .InitialStateCfg (
141- pos = (0.0 , 0.0 , 0.5 ),
142- rot = (0.0 , 0.0 , 0.0 , 1.0 ),
143- joint_pos = {".*" : 0.0 },
144- )
145- )
146- left_robot_cfg : ArticulationCfg = SHADOW_HAND_CFG .replace (prim_path = "/World/envs/env_.*/LeftRobot" ).replace (
147- init_state = ArticulationCfg .InitialStateCfg (
148- pos = (0.0 , - 1.0 , 0.5 ),
149- rot = (0.0 , 0.0 , 1.0 , 0.0 ),
150- joint_pos = {".*" : 0.0 },
151- )
152- )
324+ right_robot_cfg : RightRobotCfg = RightRobotCfg ()
325+ left_robot_cfg : LeftRobotCfg = LeftRobotCfg ()
153326 actuated_joint_names = [
154327 "robot0_WRJ1" ,
155328 "robot0_WRJ0" ,
@@ -181,27 +354,7 @@ class ShadowHandOverEnvCfg(DirectMARLEnvCfg):
181354 ]
182355
183356 # in-hand object
184- object_cfg : RigidObjectCfg = RigidObjectCfg (
185- prim_path = "/World/envs/env_.*/object" ,
186- spawn = sim_utils .SphereCfg (
187- radius = 0.0335 ,
188- visual_material = sim_utils .PreviewSurfaceCfg (diffuse_color = (0.8 , 1.0 , 0.0 )),
189- physics_material = sim_utils .RigidBodyMaterialCfg (static_friction = 0.7 ),
190- rigid_props = sim_utils .RigidBodyPropertiesCfg (
191- kinematic_enabled = False ,
192- disable_gravity = False ,
193- enable_gyroscopic_forces = True ,
194- solver_position_iteration_count = 8 ,
195- solver_velocity_iteration_count = 0 ,
196- sleep_threshold = 0.005 ,
197- stabilization_threshold = 0.0025 ,
198- max_depenetration_velocity = 1000.0 ,
199- ),
200- collision_props = sim_utils .CollisionPropertiesCfg (),
201- mass_props = sim_utils .MassPropertiesCfg (density = 500.0 ),
202- ),
203- init_state = RigidObjectCfg .InitialStateCfg (pos = (0.0 , - 0.39 , 0.54 ), rot = (0.0 , 0.0 , 0.0 , 1.0 )),
204- )
357+ object_cfg : ObjectCfg = ObjectCfg ()
205358 # goal object
206359 goal_object_cfg : VisualizationMarkersCfg = VisualizationMarkersCfg (
207360 prim_path = "/Visuals/goal_marker" ,
@@ -212,8 +365,8 @@ class ShadowHandOverEnvCfg(DirectMARLEnvCfg):
212365 ),
213366 },
214367 )
215- # scene
216- scene : InteractiveSceneCfg = InteractiveSceneCfg ( num_envs = 2048 , env_spacing = 1.5 , replicate_physics = True )
368+ # scene - use ShadowHandOverSceneCfg so that --preset newton disables clone_in_fabric automatically
369+ scene : ShadowHandOverSceneCfg = ShadowHandOverSceneCfg ( )
217370
218371 # reset
219372 reset_position_noise = 0.01 # range of position at reset
0 commit comments