@@ -1629,18 +1629,27 @@ def modify_joint_drive_properties(
16291629"""
16301630
16311631
1632+ def _applied_schema_instance (applied_schema , schema_type : str ) -> str | None :
1633+ """Return an applied multiple-apply schema's instance when its type matches exactly."""
1634+ applied_type , instance = Usd .SchemaRegistry .GetTypeNameAndInstance (str (applied_schema ))
1635+ return instance if applied_type == schema_type and instance else None
1636+
1637+
16321638def _is_fixed_tendon_target (prim : Usd .Prim ) -> bool :
1633- """Whether a prim carries a fixed-tendon representation (PhysX multi-apply instance or MjcTendon prim) ."""
1639+ """Whether a prim carries a fixed-tendon representation."""
16341640 if prim .GetTypeName () == "MjcTendon" :
16351641 return True
1636- return any ("PhysxTendonAxisRootAPI" in s for s in prim .GetAppliedSchemas ())
1642+ fixed_types = {"PhysxTendonAxisRootAPI" , "PhysxTendonAxisAPI" }
1643+ return any (
1644+ _applied_schema_instance (schema , schema_type )
1645+ for schema in prim .GetAppliedSchemas ()
1646+ for schema_type in fixed_types
1647+ )
16371648
16381649
16391650def _is_spatial_tendon_target (prim : Usd .Prim ) -> bool :
1640- """Whether a prim carries a spatial-tendon multi-apply instance."""
1641- return any (
1642- "PhysxTendonAttachmentRootAPI" in s or "PhysxTendonAttachmentLeafAPI" in s for s in prim .GetAppliedSchemas ()
1643- )
1651+ """Whether a prim carries a spatial-tendon root instance."""
1652+ return any (_applied_schema_instance (schema , "PhysxTendonAttachmentRootAPI" ) for schema in prim .GetAppliedSchemas ())
16441653
16451654
16461655def apply_fixed_tendon_properties (
@@ -1651,8 +1660,8 @@ def apply_fixed_tendon_properties(
16511660 The prims to author on are matched with :func:`~isaaclab.sim.utils.find_matching_prims`:
16521661 ``prim_path_expr`` is a plain regular expression over whole prim paths, so ``[^/]+``
16531662 selects one path segment and ``/World/Robot/.*`` every descendant of a prim. A matched prim is a
1654- fixed-tendon target when it carries an applied ``PhysxTendonAxisRootAPI`` multi-apply
1655- instance or is a ``MjcTendon`` prim.
1663+ fixed-tendon target when it carries an applied ``PhysxTendonAxisRootAPI`` or
1664+ ``PhysxTendonAxisAPI`` instance, or is a ``MjcTendon`` prim.
16561665
16571666 Fixed tendons are a *tune-not-apply* family: the tendon topology is authored in the source
16581667 asset, so this writer never creates instances -- it only dispatches each fragment via its
@@ -1740,27 +1749,33 @@ def modify_fixed_tendon_properties(
17401749 # check if prim has fixed tendon applied on it or if the mjc tendon prim exiss
17411750 applied_schemas = tendon_prim .GetAppliedSchemas ()
17421751 prim_type = tendon_prim .GetTypeName ()
1743- if not any ("PhysxTendonAxisRootAPI" in s for s in applied_schemas ) and prim_type != "MjcTendon" :
1752+ if (
1753+ not any (_applied_schema_instance (schema , "PhysxTendonAxisRootAPI" ) for schema in applied_schemas )
1754+ and prim_type != "MjcTendon"
1755+ ):
17441756 return False
17451757
17461758 # resolve all available instances of the schema since it is multi-instance
17471759 cfg = cfg .to_dict ()
17481760 if prim_type != "MjcTendon" :
17491761 for schema_name in applied_schemas :
1750- if "PhysxTendonAxisRootAPI" not in schema_name :
1762+ instance_name = _applied_schema_instance (schema_name , "PhysxTendonAxisRootAPI" )
1763+ if instance_name is None :
17511764 continue
1752- # set into PhysX API by attribute prefix schema_name: (e.g. PhysxTendonAxisRootAPI:default:stiffness)
17531765 for attr_name , value in cfg .items ():
1766+ template = f"physxTendon:__INSTANCE_NAME__:{ to_camel_case (attr_name , 'cC' )} "
1767+ attribute = Usd .SchemaRegistry .MakeMultipleApplyNameInstance (template , instance_name )
17541768 safe_set_attribute_on_usd_prim (
17551769 tendon_prim ,
1756- f" { schema_name } : { to_camel_case ( attr_name , 'cC' ) } " ,
1770+ attribute ,
17571771 value ,
17581772 camel_case = False ,
17591773 )
17601774 else :
17611775 # NOTE: ``mjc:*`` branch (``MjcTendon`` prim) kept inline; future split candidate into isaaclab_newton.
17621776 # only stiffness and damping in the cfg map to mjc attributes
1763- for attr_name , value in cfg .items ():
1777+ for attr_name in ("stiffness" , "damping" ):
1778+ value = cfg .get (attr_name )
17641779 safe_set_attribute_on_usd_prim (
17651780 tendon_prim , f"mjc:{ to_camel_case (attr_name , 'cC' )} " , value , camel_case = False
17661781 )
@@ -1781,8 +1796,7 @@ def apply_spatial_tendon_properties(
17811796 The prims to author on are matched with :func:`~isaaclab.sim.utils.find_matching_prims`:
17821797 ``prim_path_expr`` is a plain regular expression over whole prim paths, so ``[^/]+``
17831798 selects one path segment and ``/World/Robot/.*`` every descendant of a prim. A matched prim is a
1784- spatial-tendon target when it carries an applied ``PhysxTendonAttachmentRootAPI`` or
1785- ``PhysxTendonAttachmentLeafAPI`` multi-apply instance.
1799+ spatial-tendon target when it carries an applied ``PhysxTendonAttachmentRootAPI`` instance.
17861800
17871801 Spatial tendons are a *tune-not-apply* family: the tendon topology is authored in the
17881802 source asset, so this writer never creates instances -- it only dispatches each fragment
@@ -1837,16 +1851,14 @@ def modify_spatial_tendon_properties(
18371851 through length and limit constraints. For instance, it can be used to set up an equality constraint
18381852 between a driven and passive revolute joints.
18391853
1840- The schema comprises of attributes that belong to the `PhysxTendonAxisRootAPI `_ schema.
1854+ The schema comprises attributes that belong to the `PhysxTendonAttachmentRootAPI `_ schema.
18411855
18421856 .. note::
18431857 This function is decorated with :func:`apply_nested` that sets the properties to all the prims
18441858 (that have the schema applied on them) under the input prim path.
18451859
18461860 .. _spatial tendon: https://nvidia-omniverse.github.io/PhysX/physx/5.4.1/_api_build/classPxArticulationSpatialTendon.html
1847- .. _PhysxTendonAxisRootAPI: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/104.2/class_physx_schema_physx_tendon_axis_root_a_p_i.html
18481861 .. _PhysxTendonAttachmentRootAPI: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/104.2/class_physx_schema_physx_tendon_attachment_root_a_p_i.html
1849- .. _PhysxTendonAttachmentLeafAPI: https://docs.omniverse.nvidia.com/kit/docs/omni_usd_schema_physics/104.2/class_physx_schema_physx_tendon_attachment_leaf_a_p_i.html
18501862
18511863 Args:
18521864 prim_path: The prim path to the tendon attachment.
@@ -1870,20 +1882,21 @@ def modify_spatial_tendon_properties(
18701882 tendon_prim = stage .GetPrimAtPath (prim_path )
18711883 # check if prim has spatial tendon applied on it
18721884 applied_schemas = tendon_prim .GetAppliedSchemas ()
1873- has_spatial = any (
1874- "PhysxTendonAttachmentRootAPI" in s or "PhysxTendonAttachmentLeafAPI" in s for s in applied_schemas
1875- )
1885+ has_spatial = any (_applied_schema_instance (schema , "PhysxTendonAttachmentRootAPI" ) for schema in applied_schemas )
18761886 if not has_spatial :
18771887 return False
18781888
18791889 cfg = cfg .to_dict ()
18801890 for schema_name in applied_schemas :
1881- if "PhysxTendonAttachmentRootAPI" not in schema_name and "PhysxTendonAttachmentLeafAPI" not in schema_name :
1891+ instance_name = _applied_schema_instance (schema_name , "PhysxTendonAttachmentRootAPI" )
1892+ if instance_name is None :
18821893 continue
18831894 for attr_name , value in cfg .items ():
1895+ template = f"physxTendon:__INSTANCE_NAME__:{ to_camel_case (attr_name , 'cC' )} "
1896+ attribute = Usd .SchemaRegistry .MakeMultipleApplyNameInstance (template , instance_name )
18841897 safe_set_attribute_on_usd_prim (
18851898 tendon_prim ,
1886- f" { schema_name } : { to_camel_case ( attr_name , 'cC' ) } " ,
1899+ attribute ,
18871900 value ,
18881901 camel_case = False ,
18891902 )
0 commit comments