Joints#

Joints govern the relative motion of pairs of rigid bodies — for example a hinge that lets a door swing but otherwise holds it fixed to its frame. A joint couples a dynamic rigid body to another dynamic body, a kinematic body, or a static coordinate frame.

If both jointed bodies belong to the same articulation, the joint becomes an articulation joint, which is more restrictive but more precise — refer to Articulations. This page covers regular joints and the concepts (frames, drives, limits) shared by both.

Joint types and drive/limit APIs (UsdPhysics.Joint, DriveAPI, LimitAPI) are core UsdPhysics and work with stock usd-core. PhysX-specific extensions (PhysxLimitAPI, gear/rack-and-pinion, mimic, tendons) are codeless. Refer to Physics Schemas.

The Python examples on this page are fragments, not complete files. Each one extends a script that already created a stage and registered the codeless PhysX schemas, as shown in Setting Up a USD Stage and a Physics Scene; before using a fragment that refers to joint_prim or to the rigid bodies at /World/rigidBody0 and /World/rigidBody1, define those prims in the surrounding script.

Joint Frames#

A joint references two bodies, body0 and body1, with world poses G_0 and G_1. It associates a local pose with each body, L_0 and L_1 (constant, never modified by the simulation), and develops a pose J from its position along and rotation around the three axes. Every joint enforces:

[ G_0 \cdot L_0 \cdot J = G_1 \cdot L_1 ]

If the joint connects to a static frame, the corresponding G is constant. The solver produces body and joint velocities that satisfy this equation while enforcing the rule each joint type places on the form of J. For example, a fixed joint permits only the identity J; a prismatic joint allows non-zero position along a single axis with identity rotation; a revolute joint allows only rotation about a single axis.

Local frames are authored with localPos0/localRot0/localPos1/localRot1 on the joint:

from pxr import Sdf, UsdPhysics, Gf

joint = UsdPhysics.Joint.Define(stage, "/World/joint")
joint.CreateBody0Rel().SetTargets([Sdf.Path("/World/rigidBody0")])
joint.CreateBody1Rel().SetTargets([Sdf.Path("/World/rigidBody1")])
joint.CreateLocalPos0Attr().Set(Gf.Vec3f(0.0, 10.0, 0.0))
joint.CreateLocalRot0Attr().Set(Gf.Quatf(1.0))
joint.CreateLocalPos1Attr().Set(Gf.Vec3f(0.0, 0.0, 0.0))
joint.CreateLocalRot1Attr().Set(Gf.Quatf(1.0))

Joint Drive#

A joint drive applies a force to reach a target position, a target velocity, or both, following a PD-controller spring model:

[ driveForce = stiffness \cdot (position - targetPosition) + damping \cdot (velocity - targetVelocity) ]

  • Pure position drive: non-zero stiffness, zero damping.

  • Pure velocity drive: zero stiffness, non-zero damping.

  • Damped harmonic motion: both non-zero with a zero target velocity.

Drives are authored per axis with UsdPhysics.DriveAPI and can be force or acceleration drives (acceleration drives behave as if the body had unit mass):

from pxr import UsdPhysics

drive = UsdPhysics.DriveAPI.Apply(joint_prim, UsdPhysics.Tokens.angular)
drive.CreateTypeAttr(UsdPhysics.Tokens.force)     # or acceleration
drive.CreateStiffnessAttr(0.0)
drive.CreateDampingAttr(100.0)
drive.CreateTargetVelocityAttr(200.0)
drive.CreateTargetPositionAttr(0.0)

A drive is not guaranteed to reach its target unless its stiffness/damping dominate the other forces acting on the body, and limits take priority over drives.

For articulations, drive targets, stiffness, damping, and the drive model are read and written in bulk at runtime through the ARTICULATION_DOF_* tensor types — refer to the Tensor Bindings (deprecated) reference.

Joint Limits#

Limits impose lower/upper bounds on a joint’s angular or linear motion, applied to the joint pose J. Author them per axis with UsdPhysics.LimitAPI, or with the type-specific lowerLimit/upperLimit attributes on revolute/prismatic joints. Setting the lower limit above the upper limit locks that axis.

PhysxLimitAPI (codeless) extends a limit with restitution/bounce or with soft (spring) behavior:

from pxr import Sdf

joint_prim.ApplyAPI("PhysxLimitAPI", "transY")   # instance name = axis
joint_prim.CreateAttribute("physxLimit:transY:restitution", Sdf.ValueTypeNames.Float).Set(1.0)

Disabling Joints#

Remove the joint prim from the stage, or set a break force so the joint is permanently disabled after it exerts more than a threshold force (physics:breakForce / physics:breakTorque on UsdPhysics.Joint).

Break force is ignored for articulation joints, and articulation joints cannot be removed at runtime — refer to Articulations.

Joint Types#

Table 1. Joint type support as a regular joint and as an articulation joint

The following table lists each joint type and whether it is supported on the CPU and on the GPU in each role:

Type

Description

Regular, CPU

Regular, GPU

Articulation, CPU

Articulation, GPU

D6

Configurable free/limited/locked per axis (up to 3 translational + 3 rotational)

Yes

Yes

Yes, linear axes must be locked

Yes, linear axes must be locked

Distance

Limits distance between the two bodies

Yes

No

No

No

Fixed

No relative motion

Yes

Yes

Yes

Yes

Prismatic

Linear motion along one axis

Yes

Yes

Yes

Yes

Revolute

Rotation about one axis

Yes

Yes

Yes

Yes

Spherical

Rotation about three axes (ball-and-socket)

Yes

Yes

Yes

Yes

The following figures show a revolute joint and a prismatic joint, with the allowed rotation and the allowed translation marked on each:

Revolute joint Prismatic joint

Each concrete type has its own UsdPhysics schema — UsdPhysics.RevoluteJoint, PrismaticJoint, FixedJoint, SphericalJoint, DistanceJoint, and the generic Joint (D6). A representative revolute joint with a velocity drive and limits:

from pxr import Sdf, UsdPhysics

revolute = UsdPhysics.RevoluteJoint.Define(stage, "/World/revoluteJoint")
revolute.CreateBody0Rel().SetTargets([Sdf.Path("/World/rigidBody0")])
revolute.CreateBody1Rel().SetTargets([Sdf.Path("/World/rigidBody1")])
revolute.CreateAxisAttr(UsdPhysics.Tokens.y)
revolute.CreateLowerLimitAttr(-90.0)
revolute.CreateUpperLimitAttr(90.0)

drive = UsdPhysics.DriveAPI.Apply(revolute.GetPrim(), UsdPhysics.Tokens.angular)
drive.CreateTypeAttr(UsdPhysics.Tokens.force)
drive.CreateDampingAttr(100.0)
drive.CreateTargetVelocityAttr(200.0)

Type-specific notes:

  • D6 — lock/limit/free each axis through LimitAPI per axis token (transX/rotX/…). Angular limits form a pyramid, not a cone. For angular drives, use the same stiffness/damping for the rotY and rotZ axes (mixing different values is undefined); rotX can differ. Supports a distance limit (upper bound only).

  • Distance — set minDistance, maxDistance, or both; either alone is valid. A soft-constraint spring is available through PhysxPhysicsDistanceJointAPI.

  • Prismatic / Revolute — single-axis linear / angular motion; both support drives and lowerLimit/upperLimit.

  • Spherical — a cone limit around a chosen principal axis through coneAngle0Limit/coneAngle1Limit. No drive; motion around the principal axis cannot be limited; soft limits are unsupported. When these limits bite, prefer a D6 joint with locked linear axes.

Meta Joints#

Meta joints couple two other joints:

  • Gear joint (PhysxPhysicsGearJoint) couples two revolute joints by a gear ratio: |w1| = |w0| * R.

  • Rack-and-pinion joint (PhysxPhysicsRackAndPinionJoint) couples a revolute joint to a prismatic joint by a ratio: |w| = |V| * R.

Both reference their two source joints (hinge0/hinge1, or hinge/prismatic) and are defined by prim type with codeless schemas:

gear = stage.DefinePrim("/World/gearJoint", "PhysxPhysicsGearJoint")
gear.CreateRelationship("physics:body0").SetTargets(["/World/gear0"])
gear.CreateRelationship("physics:body1").SetTargets(["/World/gear1"])
gear.CreateRelationship("physxGearJoint:hinge0").SetTargets(["/World/revoluteJoint0"])
gear.CreateRelationship("physxGearJoint:hinge1").SetTargets(["/World/revoluteJoint1"])

Gear and rack-and-pinion joints are CPU-only (they run through the CPU pipeline even in GPU simulation). For articulations, prefer mimic joints, which implement the same coupling with native GPU acceleration.

PhysX Joint Schema#

The codeless PhysX Schema provides PhysxJointAxisAPI (per-axis armature, friction, max joint velocity) and PhysxDrivePerformanceEnvelopeAPI (actuator performance limits). These only apply to joints that are part of an articulation and are covered in Articulations.

Joint Instancing#

PhysxPhysicsJointInstancer (codeless) is the counterpart to rigid-body point instancing: it instances joints between point-instanced bodies. Instanced joints can reference only point-instanced bodies, scenegraph instancing is not supported for joints, and joint instancing is not supported for articulation joints. Refer to Rigid Body instancing.