Skip to content

[USD] Make PhysX tendon fragments schema- and instance-specific - #7534

Merged
ooctipus merged 6 commits into
isaac-sim:developfrom
ooctipus:fix/tendon-multi-apply-selection
Sep 4, 2026
Merged

[USD] Make PhysX tendon fragments schema- and instance-specific#7534
ooctipus merged 6 commits into
isaac-sim:developfrom
ooctipus:fix/tendon-multi-apply-selection

Conversation

@ooctipus

@ooctipus ooctipus commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fix PhysX tendon properties being authored under the applied-schema token, such as
    PhysxTendonAxisRootAPI:index_finger:stiffness. PhysX reads the schema-declared property
    namespace, physxTendon:index_finger:stiffness.
  • Give each concrete tendon fragment one USD schema and an instance_names selector for one,
    several, or all existing instances.
  • Rename the fragments to match their USD schemas exactly and remove compatibility aliases before
    this API is released.
  • Keep the fixed/spatial family writers as the only public write entry points. Multiple-apply
    parsing remains a private PhysX implementation detail.

This is a focused alternative to #7527. It fixes tendon authoring without introducing a generic
multiple-apply fragment convention in core.

Why the old namespace was wrong

A joint prim can carry both applied-schema instances:

apiSchemas = [
    PhysxTendonAxisRootAPI:index_finger,
    PhysxTendonAxisAPI:index_finger,
]

Those tokens identify the API type and arbitrary instance name; they are not property prefixes.
Both schemas declare properties in the shared physxTendon namespace on the same prim:

physxTendon:index_finger:stiffness = 10
physxTendon:index_finger:gearing = [1]

The previous writers concatenated the applied-schema token and field name. That produced custom
attributes which looked plausible in USD but were ignored by PhysX.

Public API and ownership

Fragment USD schema Property ownership
PhysxTendonAxisRootCfg PhysxTendonAxisRootAPI whole fixed-tendon dynamics and length limits
PhysxTendonAxisCfg PhysxTendonAxisAPI gearing, force_coefficient, and joint_axis for one joint contribution
PhysxTendonAttachmentRootCfg PhysxTendonAttachmentRootAPI whole spatial-tendon dynamics; attachment/leaf topology remains asset-authored

The names deliberately follow the concrete USD schemas. “Fixed” and “spatial” remain family-level
concepts in FixedTendonFragment, SpatialTendonFragment, fixed_tendons_props, and
spatial_tendons_props; they no longer obscure which schema owns a concrete config.

Every concrete fragment accepts:

instance_names: str | list[str] | None = None
  • A string selects one existing schema instance.
  • A list selects that subset.
  • None broadcasts to every matching instance on each targeted prim.

The prim-path expression selects prims; instance_names selects instances on those prims. The
fragments tune already-authored topology and never create a missing tendon instance.

Breaking migration

No aliases are retained:

Previous API Replacement
PhysxFixedTendonCfg PhysxTendonAxisRootCfg
PhysxSpatialTendonCfg PhysxTendonAttachmentRootCfg
isaaclab_physx.sim.schemas.apply_fixed_tendon isaaclab.sim.schemas.apply_fixed_tendon_properties
isaaclab_physx.sim.schemas.apply_spatial_tendon isaaclab.sim.schemas.apply_spatial_tendon_properties

PhysxTendonAxisCfg is the new config for per-joint PhysxTendonAxisAPI properties.

Configuration examples

The selector supports broadcast, one instance, or a subset:

PhysxTendonAxisRootCfg(stiffness=10.0)  # all authored root instances
PhysxTendonAxisRootCfg(instance_names="index_finger", stiffness=10.0)
PhysxTendonAxisRootCfg(instance_names=["index_finger", "middle_finger"], stiffness=10.0)

In a USD-file spawner, mapping keys select prims relative to the asset and fragments select schema
instances and properties:

from isaaclab import sim as sim_utils
from isaaclab_physx.sim.schemas import (
    PhysxTendonAttachmentRootCfg,
    PhysxTendonAxisCfg,
    PhysxTendonAxisRootCfg,
)

spawn = sim_utils.UsdFileCfg(
    usd_path="/path/to/hand.usd",
    fixed_tendons_props={
        "/joints/index_root": [
            PhysxTendonAxisRootCfg(
                instance_names="index_finger",
                stiffness=10.0,
                damping=0.2,
            ),
            PhysxTendonAxisCfg(
                instance_names="index_finger",
                gearing=[1.0],
                joint_axis=["rotX"],
            ),
        ],
        "/joints/index_distal": [
            PhysxTendonAxisCfg(
                instance_names="index_finger",
                gearing=[-0.5],
                joint_axis=["rotX"],
            ),
        ],
    },
    spatial_tendons_props={
        "/attachments/cable_root": [
            PhysxTendonAttachmentRootCfg(
                instance_names=["flexor", "extensor"],
                stiffness=20.0,
                damping=0.4,
            ),
        ],
    },
)

The family writers can also be called directly:

from isaaclab.sim.schemas import apply_fixed_tendon_properties, apply_spatial_tendon_properties

apply_fixed_tendon_properties(prim_path_expr, fixed_fragments, stage)
apply_spatial_tendon_properties(prim_path_expr, spatial_fragments, stage)

Architecture boundary

  • Core owns family-level prim targeting and fragment dispatch.
  • Each PhysX config declares its exact schema through private _usd_applied_schema metadata.
  • One private _tune_tendon_schema implementation selects instances and resolves canonical
    property names/types with Usd.SchemaRegistry.
  • There is no public per-prim tendon applier, MultiApplyFragment, apply_schema_instances, or
    public schema-name parsing helper.
  • This does not reuse the drive path: drive instance names are selected from joint type (angular
    or linear), while tendon instance names are arbitrary asset-authored identifiers.

Relationship to #7161

The Shadow Hand asset in #7161 already authors its tendon topology, and runtime tendon actions write
through the tensor API. That migration does not need this spawn-time schema fix, but it can rebase on
this PR to use the corrected public fragments.

Test plan

  • Focused tendon behavior: 18 passed under Kit.
  • Existing schema suite: 44 passed under Kit (90 expected deprecation warnings).
  • Codeless OpenUSD/PhysX schema coverage: 1 passed without Kit.
  • Ruff, formatting, RST, license, codespell, LFS-pointer, and exact-base changelog checks pass.

The complete PR is net-negative against develop: 471 additions and 642 deletions (−171 lines).

The focused tests cover canonical namespace authoring, one/list/all instance selection, concrete
schema ownership, root/child traversal, spatial-root isolation, legacy-writer regression, and
codeless schema resolution. Tests of internal metadata strings, public-symbol absence, constructor
field ordering, and other implementation details were removed.

Release backport

  • Backport this pull request to the active release branch after it merges into develop

@ooctipus
ooctipus requested a review from a team September 3, 2026 10:48
@github-actions github-actions Bot added bug Something isn't working documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Sep 3, 2026
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR corrects PhysX tendon property namespaces, adds instance-selective fixed and spatial tendon fragments, and separates fixed-tendon root properties from per-axis properties.

  • Resolves canonical multiple-apply property names from registered USD schema definitions.
  • Adds PhysxFixedTendonAxisCfg and its writer for per-joint tendon contributions.
  • Adds instance_names selection while preserving broadcast behavior when it is None.
  • Updates legacy writers, documentation, exports, changelogs, and Kit/codeless tests.

Confidence Score: 4/5

The PR should not merge until an explicitly requested but nonexistent tendon instance produces a surfaced error instead of silently leaving the asset unchanged.

The new selector returns a false result for absent explicit names, while the production spawn path ignores that result, allowing requested tendon configuration to be dropped without diagnostics.

Files Needing Attention: source/isaaclab_physx/isaaclab_physx/sim/schemas/schemas.py; source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py

Important Files Changed

Filename Overview
source/isaaclab_physx/isaaclab_physx/sim/schemas/schemas.py Adds schema-aware, instance-selective tendon writers, but unmatched explicit selections silently no-op through the spawn path.
source/isaaclab_physx/isaaclab_physx/sim/schemas/schemas_cfg.py Splits root and per-axis fixed-tendon configuration and adds documented instance selectors.
source/isaaclab/isaaclab/sim/schemas/schemas.py Tightens tendon target detection and corrects legacy PhysX multiple-apply property namespaces.
source/isaaclab/test/sim/test_tendon_fragments.py Broadly covers schema ownership, namespace resolution, instance subsets, broadcasting, dispatch, and backend compatibility, but not absent non-empty instance names.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    C[Spawn tendon fragment] --> P[Core prim-path targeting]
    P --> S{Fragment schema}
    S -->|Fixed root| R[PhysxTendonAxisRootAPI]
    S -->|Fixed axis| A[PhysxTendonAxisAPI]
    S -->|Spatial root| T[PhysxTendonAttachmentRootAPI]
    R --> I[Select existing instance names]
    A --> I
    T --> I
    I --> U[Resolve canonical USD property template]
    U --> W[Author physxTendon instance properties]
Loading

Reviews (1): Last reviewed commit: "Make PhysX tendon fragments instance-sel..." | Re-trigger Greptile

Comment on lines 109 to 111
instances = _selected_tendon_instances(prim, schema_type, cfg.instance_names)
if not instances:
return False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Unmatched instances silently no-op

When instance_names contains an absent or misspelled tendon name, this branch returns False, but the production spawn path discards that result. The requested tendon properties are therefore not authored and PhysX runs with the asset's unchanged values without reporting the invalid selection.

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The PhysX tendon update correctly adopts the schema-owned physxTendon:<instance>:* namespace, splits fixed-tendon root and axis properties, and adds instance selection. One user-visible compatibility change still needs release documentation: spatial-tendon matching no longer accepts leaf-only prims.

  • Design and architecture: The RootAPI/AxisAPI split follows the USD schema boundary, while schema-template resolution remains private to isaaclab_physx and core retains family targeting and dispatch. The narrowing of spatial-tendon targets to attachment roots is coherent with that ownership model but changes prior core behavior and must be documented.
  • API: The new PhysxFixedTendonAxisCfg and apply_fixed_tendon_axis APIs are exported and documented, and selector fields preserve existing positional field order. However, leaf-only spatial-tendon targets now return failure rather than being accepted, without corresponding migration guidance in the isaaclab changelog fragment.
  • Implementation: Canonical multiple-apply parsing and schema-derived property templates avoid the previous ignored custom attributes. The changed _is_spatial_tendon_target predicate and legacy spatial writer consistently restrict tuning to PhysxTendonAttachmentRootAPI; the remaining action is to document that callers must target attachment-root prims rather than leaf-only prims.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.

"PhysxTendonAttachmentRootAPI" in s or "PhysxTendonAttachmentLeafAPI" in s for s in prim.GetAppliedSchemas()
)
"""Whether a prim carries a spatial-tendon root instance."""
return any(_applied_schema_instance(schema, "PhysxTendonAttachmentRootAPI") for schema in prim.GetAppliedSchemas())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Warning · Api — Spatial leaf targets dropped without changelog note

_is_spatial_tendon_target and modify_spatial_tendon_properties now match only PhysxTendonAttachmentRootAPI, so a prim carrying only PhysxTendonAttachmentLeafAPI stops being a valid target: the writer warns "No spatial-tendon targets matched" and returns False where it previously returned True. The isaaclab changelog fragment records only the namespace fix and the fixed-tendon extension; add this narrowing with migration guidance to target the attachment-root prim.

@ooctipus
ooctipus requested a review from hujc7 as a code owner September 3, 2026 11:30
@kellyguo11

Copy link
Copy Markdown
Contributor

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 3, 2026
@ooctipus
ooctipus merged commit 29bcb09 into isaac-sim:develop Sep 4, 2026
51 of 52 checks passed
@isaaclab-bot

isaaclab-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Backported to release/3.0.0 as 798f04c.

isaaclab-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants