Drive fragment schema writers by prim path expressions#6640
Draft
vidurv-nvidia wants to merge 16 commits into
Draft
Drive fragment schema writers by prim path expressions#6640vidurv-nvidia wants to merge 16 commits into
vidurv-nvidia wants to merge 16 commits into
Conversation
The fragment target resolver stopped descending at the first schema-bearing prim on each branch, so on assets with nested rigid-body hierarchies (child links authored under their parent link prims, as produced by the URDF importer in Isaac Sim 6.0 and later) only the outermost link received rigid-body and mass fragment properties. The legacy writers gained full-subtree traversal for these families in isaac-sim#6377, so the fragment writers diverged from legacy parity. Add a stop_at_carrier flag to the resolver, mirroring apply_nested's stop_on_success: rigid-body and mass writers now collect every carrier in the subtree, while collision keeps the legacy stop-at-carrier traversal. Extend the nested-target regression tests with a nested child link so the flat-asset, parity, and direct-writer tests all cover the nested topology.
The rigid-body fragment writer now resolves its targets from a prim path expression via find_matching_prims instead of inferring them by subtree traversal: existing carriers matched by the expression (a trailing ** token reaches the whole subtree) are modified in place. Applying a fresh RigidBodyAPI is now explicit through the new create_if_missing flag, which anchors a single matched non-carrier prim and raises when the expression matches several. Zero matched targets warn and return False instead of silently anchoring, since inventing a body the asset's joints never reference changes its dynamics. The USD-file spawner passes an explicit subtree expression, while the shape and mesh spawners opt into creation on their bare container prims.
The converter authors a fresh RigidBodyAPI on the exact xform prim it creates, so it must opt into creation now that the fragment writer only modifies matched carriers by default.
The mass writer now matches targets with a prim path expression (a trailing ** token selects a prim and its whole subtree) instead of traversing the subtree of a single prim. Creation of UsdPhysics.MassAPI is explicit via create_if_missing: with multiple matches it only lands on prims that already carry a rigid body (non-bodies are skipped with a warning), while a single exact-prim match is anchored unconditionally since the shape and mesh spawners author mass before the rigid body. Unmatched expressions warn and return False instead of raising.
The writer now resolves its targets with find_matching_prims from an explicit prim path expression instead of inferring roots by subtree traversal; callers select the subtree with a trailing '**' token. Nested articulation roots now raise a ValueError instead of being silently pruned to the outermost root, and a fresh root anchor is only applied when requested via the new create_if_missing flag rather than implicitly when no root is found.
Target joints for apply_joint_drive_properties with an explicit prim path expression instead of a subtree traversal from a root prim; the spawner call site now passes a trailing-** expression. A new create_if_missing flag applies the axis-appropriate UsdPhysics.DriveAPI (angular for revolute, linear for prismatic) on matched joints lacking it, distinct from ensure_drives_exist which seeds a minimal stiffness on fully-passive drives. Zero matches now warn instead of raising.
The collision family writer now matches its targets with a prim path expression (trailing ** selects a prim and its whole subtree) instead of inferring them by subtree traversal. Creating the CollisionAPI anchor is opt-in via create_if_missing and, unlike rigid bodies, is allowed on multiple matched prims to cover the bare-prim shape and mesh spawner case. Mesh-collision fragments are dispatched only to geometry prims, since cooking attributes and the approximation token are meaningless elsewhere.
The core apply_fixed_tendon_properties and apply_spatial_tendon_properties writers now resolve their targets from a prim path expression (with a trailing ** token selecting a whole subtree) instead of relying on the backend fragment funcs to descend. The PhysX multi-instance tendon tuner and the MuJoCo MjcTendon tuner are strictly per-prim now; a fragment succeeds when it tunes at least one matched target, so mixed-backend target sets compose. The from-files spawner appends /** to keep tuning tendon schemas authored on descendant joint prims.
All fragment writers now resolve targets through prim path expressions, so the stop-at-carrier traversal helper has no callers left. Also accept path-like objects (e.g. Sdf.Path) in the expression matcher and fix a test passing the stage positionally into the create_if_missing slot.
Spawner cfgs gain per-family *_prim_path fields that select which prims of the spawned asset receive schema fragments. Patterns are relative to the spawn prim: each /-separated token is a per-level regex and a trailing ** matches a prim and all its descendants. None keeps the spawner default (whole subtree for USD assets, the exact authored prim for shapes/meshes) and an empty string targets the spawn prim itself. New create-if-missing flags are threaded through for the mass, articulation-root, and joint-drive writers.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Reworks the fragment schema writers from implicit subtree-traversal targeting to explicit prim-path-expression targeting. Supersedes #6635 (closed): this branch contains its nested-hierarchy fix and regression tests, so nested URDF-importer assets are handled here. The fragment path is experimental with no external consumers yet, hence the outright breaking change.
Motivation
The fragment writers inferred their targets by traversing the spawn prim's subtree with family-specific policies (stop-at-carrier vs. descend, implicit fresh-API anchoring on bare prims). Every recent writer bug (#6501, the #6377 divergence, #6635) came from that inference. This PR removes the guessing: the caller states which prims to author on, and the writer matches, filters, and writes.
Changes
find_matching_primsgains a trailing**token — a prim and all of its descendants at any depth, traversing instance proxies.**anywhere else raises.apply_rigid_body/collision/mass/articulation_root/joint_drive/fixed_tendon/spatial_tendon_properties): first argument is now a prim path expression; a shared matcher splits matches into targets (carry the family's defining API / are joints / carry tendon instances), creation candidates, and skipped instanced prims. Empty fragment list stays a no-op; zero targets warns and returnsFalse.create_if_missingreplaces implicit fresh-API anchoring. Family rules: rigid and articulation root error on more than one candidate; mass creates on matched rigid bodies (unconditionally for a single exact-prim match — the shape/mesh spawner case); collision creates on every candidate; joint drive applies the axis-appropriateDriveAPI(distinct fromensure_drives_exist, which keeps its activation semantics); tendons are modify-only._tune_multi_instance_tendon, Newtonapply_mujoco_fixed_tendon) no longer descend subtrees — the core writer owns targeting; funcs tune the given prim only.*_props_prim_pathfields (relative to the spawn prim,None= previous behavior,""= the spawn prim itself) plusmass/articulation/joint_drivecreate flags, onRigidObjectSpawnerCfgandFileCfg(shared by the USD/URDF/MJCF paths).Breaking changes and migration
Fragment-path only; the legacy
modify_*/define_*writers are untouched. Direct writer callers: passf"{prim_path}/**"to recover subtree behavior; addcreate_if_missing=Truewhere a fresh API on a bare prim was expected; expect a warning +Falseinstead ofValueErrorfor paths that match nothing. Spawner-config users are unaffected — theNonedefaults reproduce the previous placement exactly (locked by a fragment-vs-legacy parity test on flat and nested assets).Test coverage
Every semantic change was written test-first and shown to fail against the previous writers. 219 tests across the schema/spawner/converter suites pass; the only red in the sweep is
test_newton_material_fragment_authors_all_six_newton_attrs, which fails identically on the base commit (pre-existing resolver drift, unrelated).Type of change
Checklist
pre-commitchecks with./isaaclab.sh --formatCONTRIBUTORS.mdor my name already exists there