Skip to content

Add NewtonJointAPI and newton:jointModel - #72

Merged
andrewkaufman merged 6 commits into
mainfrom
joint-api-schema
Jul 3, 2026
Merged

Add NewtonJointAPI and newton:jointModel#72
andrewkaufman merged 6 commits into
mainfrom
joint-api-schema

Conversation

@andrewkaufman

@andrewkaufman andrewkaufman commented Jun 26, 2026

Copy link
Copy Markdown
Member

Description

Add NewtonJointAPI and NewtonArticulationRootAPI.newton:jointModel, extending the Newton USD schema package with joint-level solver configuration and an articulation-level coordination paradigm token.

Motivation

Newton's JointDofConfig has several per-DOF parameters (armature, passive damping, dry friction, velocity limit, limit spring stiffness/damping) that have no representation in the standard UsdPhysics schemas (PhysicsLimitAPI, PhysicsDriveAPI, joint type attributes). These parameters are needed to fully describe joint behavior for Newton simulations imported from MJCF/URDF sources or authored directly in USD.

Additionally, Newton supports both maximal-coordinate (joints constrain free bodies) and reduced-coordinate (joints grant DOFs) paradigms. The existing PhysicsArticulationRootAPI has no way to express which paradigm an articulation uses.

newton:jointModel on NewtonArticulationRootAPI

Adds a uniform token newton:jointModel attribute with allowed values "maximal" (default) and "reduced":

  • "maximal": Joints constrain degrees of freedom between otherwise-free bodies.
  • "reduced": Stacked joints grant degrees of freedom to bodies that would otherwise be rigidly attached. DOF ordering within compound joints is determined by traversal order.

This declares the coordination paradigm at articulation scope. There is no known use case for mixing paradigms within a single articulation, so a per-joint attribute was not warranted. The newton:jointModel token follows the same uniform token *Model pattern established by newton:massModel on NewtonMassAPI.

In the "reduced" paradigm, multiple single-DOF joint prims connecting the same body pair ("stacked joints") are merged by the importer into a single compound D6 joint. Each source joint prim retains its own attributes — Newton's importer maps each prim's scalar values to the corresponding DOF in the resulting compound joint. This merging behavior is why NewtonJointAPI attributes only need to broadcast per-joint rather than per-DOF: the per-DOF variance can already be expressed by authoring distinct values on each source joint prim before merging. Other reduced coordinate engines (e.g. mujoco-c) may not even need to merge to a compound joint. Maximal engines (e.g. physx) could choose to support merging in cases that can be handled gracefully & to emit descriptive warnings/errors in cases that cannot be (e.g. non-orthogonal coordinate frames).

NewtonJointAPI

A single-apply schema on PhysicsJoint prims with six attributes that broadcast uniformly to every DOF of the joint:

Attribute Type Default Description
newton:armature float 0 Artificial per-DOF inertia for solver stability
newton:damping float 0 Passive velocity-proportional damping (always active)
newton:friction float 0 Dry friction opposing motion (MuJoCo frictionloss)
newton:velocityLimit float inf Maximum DOF velocity; inf means unlimited
newton:limitStiffness float -inf Limit spring stiffness; -inf defers to engine default
newton:limitDamping float -inf Limit spring damping; -inf defers to engine default

Design choices:

  • Single-apply with broadcast — The alternative is a multi-apply NewtonJointDofAPI keyed per DOF (analogous to PhysicsLimitAPI:rotX, PhysicsDriveAPI:angular, etc.), which would allow per-DOF variance on compound joints. We chose broadcast-only for this release for several reasons:

    1. Empirical data: Analysis of MuJoCo menagerie (the largest public collection of articulated USD-compatible models) shows 97.5% of joints are single-DOF hinges. For single-DOF joints, broadcast and per-DOF are identical — the schema distinction only matters for compound (multi-DOF) joints.

    2. Source format precedent: Both MJCF and URDF define armature, damping, and friction as scalar-per-joint, not per-axis. The per-DOF granularity in Newton's JointDofConfig exists to support D6 joints constructed by merging multiple single-DOF USD joints — but in that case, each source joint prim already carries its own scalar value. The importer maps each source prim's value to the corresponding DOF without needing a per-DOF schema on the merged result.

    3. Schema precedent: Both the PhysX joint extension (physxJoint:armature) and MuJoCo's USD schema (mjc:armature) chose per-joint broadcast for armature. Neither provides per-DOF granularity at the schema level.

    4. Authoring ergonomics: Multi-apply schemas are verbose and have poor discoverability in USD authoring tools. For the vast majority of users, a single newton:armature = 0.01 on a revolute joint is the entire interaction. Requiring NewtonJointDofAPI:angular.armature = 0.01 for the same result adds friction without benefit.

    5. Forward-compatible: A future NewtonJointDofAPI (multi-apply, per-DOF override) can be added with clear precedence semantics ("per-DOF wins if authored, otherwise broadcast applies") without breaking existing assets. Shipping both now would require defining that interaction before there's a demonstrated user need.

    A per-DOF multi-apply companion schema remains a candidate for a future release if users demonstrate need for per-DOF variance on compound joints authored directly as D6 (rather than merged from single-DOF source joints).

  • Degrees for angular attributes — consistent with UsdPhysicsLimitAPI, UsdPhysicsDriveAPI, and NewtonMimicAPI on the same prim. Avoids mixed-unit prims where some attributes are in radians and others in degrees.

  • Sentinel defaults (inf / -inf) — newton:velocityLimit = inf means unlimited (no velocity clamping). newton:limitStiffness = -inf and newton:limitDamping = -inf mean "defer to engine default" — the engine applies calibrated values that ensure solver stability without requiring authors to know implementation-specific magic numbers. This matches the existing sentinel pattern used by NewtonCollisionAPI.contactGap, NewtonMaterialAPI.contactStiffness, etc.

  • Limit spring semanticslimitStiffness and limitDamping define a soft spring that activates when the DOF position exceeds the range defined by PhysicsLimitAPI. This is how reduced-coordinate solvers (Featherstone, MuJoCo) enforce limits. Position-based solvers (XPBD) enforce limits as hard positional constraints and ignore these attributes entirely. The schema documents this solver-dependent behavior so authors understand when these values matter.

Checklist


Addendum: newton:jointModel replaced by newton:jointsAddMobility

Per reviewer feedback (chschuma-disney, jcarius-nv), the uniform token newton:jointModel attribute with "maximal" / "reduced" tokens has been replaced by a uniform bool newton:jointsAddMobility (default false):

  • false — joints constrain degrees of freedom between otherwise-free bodies.
  • true — stacked joints add degrees of freedom to bodies that would otherwise be rigidly attached.

Rationale: the maximal/reduced token names conflated authoring semantics with solver-internal data representations, implying the parameter could force a solver choice. A bool with an explicit name better communicates the actual meaning — whether joints in the articulation remove or add the possibility for motion — without leaking solver terminology into the scene description.

The regex only accepted '2025' or a range like '2025-2026', rejecting
bare '2026' for files created in the current year. Add the current year
as an accepted standalone value.
Declares the coordinate paradigm for joints in an articulation:
- "maximal": joints constrain DOFs between free bodies (default)
- "reduced": stacked single-DOF joints grant DOFs to otherwise-fixed
  bodies; engines may merge into compound joints or warn

Follows the uniform token *Model pattern established by newton:massModel.
Tests added to test_articulation.py including allowedTokens metadata.
Single-apply schema on PhysicsJoint prims providing six attributes that
broadcast uniformly to every DOF:

- newton:armature: artificial per-DOF inertia for solver stability
- newton:damping: passive velocity-proportional damping (always active)
- newton:friction: dry (Coulomb) friction effort opposing motion
- newton:velocityLimit: maximum DOF velocity (inf = unlimited)
- newton:limitStiffness: limit spring stiffness (-inf = engine default)
- newton:limitDamping: limit spring damping (-inf = engine default)

All attributes use degrees for angular DOFs. Hard minimum of 0 enforced
on armature, damping, friction, and velocityLimit. Limit spring
attributes activate when DOF position exceeds the range defined by the
joint limits; position-based solvers may ignore them.

Registered as NewtonPhysicsJointAPI in plugInfo.json with
apiSchemaCanOnlyApplyTo: ["PhysicsJoint"].
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@andrewkaufman andrewkaufman self-assigned this Jun 26, 2026
@andrewkaufman andrewkaufman mentioned this pull request Jun 26, 2026
1 task
@AlesBorovicka

Copy link
Copy Markdown

Its still unclear to me how we want to make a difference between soft and hard limit. Until this is resolved I would not push this.

Clarify that limitStiffness = inf is interpreted as a hard limit by
solvers supporting both soft and hard modes. limitDamping is ignored
in that case (no spring to damp). Range updated from [0, inf) to
[0, inf] to reflect that inf is a valid authored value.

Addresses review feedback from AlesBorovicka on soft vs hard limit
distinction.

@andrewkaufman andrewkaufman left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Its still unclear to me how we want to make a difference between soft and hard limit

Per offline discussion with @AlesBorovicka: documented that limitStiffness = inf is interpreted as a hard limit by solvers that support both soft and hard modes. limitDamping is explicitly noted as ignored in that case (no spring to damp). Range updated to [0, inf] to reflect that inf is a valid authored value, not excluded.

We could alternatively use a bool newton:limitSpringEnabled = true or token newton:limitMode = "soft" attribute if we feel that is more explicit. Its just a little odd for the newton solvers that only support one or the other.

@rubengrandia

Copy link
Copy Markdown
Member

Minor point, but I think the description around armature can be improved. Currently it only refers to it as "artifical" and makes it seem this is just for solver stability. However, this parameter is also used to model true system dynamics such as rotor inertia in actuators. With the current description a novice user might think that anything other than 0 is cheating and hurting sim2real.

Comment thread newton_usd_schemas/generatedSchema.usda Outdated

@jcarius-nv jcarius-nv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Lefrt a few comments, looks good to me otherwise, thank you!

Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Comment thread newton_usd_schemas/generatedSchema.usda
Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Comment thread newton_usd_schemas/generatedSchema.usda Outdated
havess
havess previously approved these changes Jun 30, 2026
…tics

- armature: describe as reflected inertia from gears/rotors/transmissions,
  not just 'artificial' stability aid
- friction: remove 'must be moving' claim; note constraint-based solvers
  may also resist motion at zero velocity (static friction)
- limitStiffness/limitDamping: replace prescriptive 'position-based solvers
  always enforce hard limits' with solver-neutral note that some solvers
  may ignore the attribute
- limitDamping: clarify damping applies to velocity in any direction while
  limit is exceeded, not only the penetrating direction

@andrewkaufman andrewkaufman left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed most comments & asked another question about the jointModel attribute

Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Comment thread newton_usd_schemas/generatedSchema.usda
Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Comment thread newton_usd_schemas/generatedSchema.usda Outdated
Per chschuma-disney suggestion: a bool with clear docstring is more
explicit than a token enum whose values (maximal/reduced) conflate
authoring semantics with solver internals.

- newton:jointsAddMobility (default false) on NewtonArticulationRootAPI
- false = joints constrain DOFs between otherwise-free bodies
- true = stacked joints add DOFs to otherwise-rigid bodies
- Updated tests accordingly

@andrewkaufman andrewkaufman left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I changed to the jointsAddMobility bool in da17c01

@andrewkaufman
andrewkaufman merged commit 3d1f56d into main Jul 3, 2026
19 checks passed
@andrewkaufman
andrewkaufman deleted the joint-api-schema branch July 3, 2026 16:33
Ligo04 added a commit to Ligo04/newton-usd-schemas that referenced this pull request Jul 9, 2026
* Add NewtonJointAPI and newton:jointModel (newton-physics#72)

* Fix license_format.py to accept current-year-only copyright headers
* Add newton:jointModel attribute to NewtonArticulationRootAPI
* Add NewtonJointAPI schema for joint solver configuration

Single-apply schema on PhysicsJoint prims providing six attributes that
broadcast uniformly to every DOF:

- newton:armature: artificial per-DOF inertia for solver stability
- newton:damping: passive velocity-proportional damping (always active)
- newton:friction: dry (Coulomb) friction effort opposing motion
- newton:velocityLimit: maximum DOF velocity (inf = unlimited)
- newton:limitStiffness: limit spring stiffness (-inf = engine default)
- newton:limitDamping: limit spring damping (-inf = engine default)

* Update for v0.4.0

* Fix copyright regex to accept start years ending in 5-9

The pattern 20[0-9][0-4] only matched start years ending in 0-4, so
ranges like 2025-2026 failed validation even though __fix generates
them. Widen to 20[0-9][0-9].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: Ligo <1569731402@qq.com>
Co-authored-by: Andrew Kaufman <akaufman@nvidia.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants