Understanding Newton Joint Types: D6, Ball, Prismatic, Revolute, Fixed, and Cable
Newton physics engine represents mechanical connections through a dual-layer system where JointType provides the public API catalog (D6, Ball, Prismatic, Revolute, Fixed, Cable) while JointDoFType handles internal solver representation with specific degrees-of-freedom constraints.
The newton-physics/newton repository implements a sophisticated rigid-body simulation framework that categorizes mechanical connections through distinct Newton joint types. Understanding the relationship between the user-facing enumeration and the internal solver representation is essential for correctly configuring robotic mechanisms, character joints, and physics-based animations.
The Two-Layer Architecture: JointType vs. JointDoFType
Newton’s joint system separates public interface from internal implementation through two complementary enumerations defined in separate modules.
JointType: The Public API Surface
The JointType enumeration in newton/_src/sim/enums.py (lines 46-69) serves as the primary contract for users, importers, and external tools such as USD Physics and MuJoCo. It defines the categorical joint types that appear in scene descriptions and configuration files.
# From newton/_src/sim/enums.py
class JointType(enum.IntEnum):
PRISMATIC = 0 # 1 translational DoF
REVOLUTE = 1 # 1 rotational DoF
BALL = 2 # 3 rotational DoF (quaternion)
FIXED = 3 # 0 DoF – fully locked
FREE = 4 # 6 DoF (7 coordinates – 3 pos + 4 quat)
DISTANCE = 5 # 6 DoF, distance constraint
D6 = 6 # Generic 6-DoF joint (any combination)
CABLE = 7 # 1 linear stretch + 1 isotropic bend/twist DoF
JointDoFType: The Internal Solver Representation
The JointDoFType enumeration in newton/_src/solvers/kamino/_src/core/joints.py (lines 87-124) encodes the internal representation that couples degrees-of-freedom (DoF), coordinate count, and constraint sets. This abstraction allows the Kamino solver to allocate state vectors and constraint rows efficiently.
Each variant stores:
num_coords: Scalar values needed for configuration (e.g., quaternion = 4)num_dofs: Independent velocity componentsnum_cts: Bilateral kinematic constraints imposed
Complete Guide to Newton Joint Types
The following sections detail each joint type’s behavior, coordinate requirements, and constraint structure as implemented in the Newton physics engine.
D6 (Generic 6-DoF)
The D6 joint provides generic 6-DoF configurability, supporting any combination of translational and rotational axes. Internally, the solver maps specific D6 configurations to specialized JointDoFType variants including CARTESIAN, CYLINDRICAL, UNIVERSAL, and GIMBAL based on the enabled axes.
- Coordinates: Up to 7 (depends on enabled axes)
- DoFs: Up to 6 (3 translational + 3 rotational)
- Constraints:
6 - num_enabled_axes(or 0 for free)
Ball (Spherical)
The Ball joint permits three rotational degrees of freedom while locking all translation. It uses a quaternion representation internally to avoid gimbal lock, mapping to the SPHERICAL JointDoFType.
- Coordinates: 4 (quaternion)
- DoFs: 3 (rotational)
- Constraints: 3 (translational constraints)
Prismatic
The Prismatic joint allows motion along a single translational axis, functioning like a piston or linear guide. It constrains all rotation and two translation axes, corresponding to the PRISMATIC JointDoFType.
- Coordinates: 1 (linear distance)
- DoFs: 1 (translational)
- Constraints: 5 (
T_y,T_z,R_x,R_y,R_z)
Revolute
The Revolute joint permits rotation around a single axis, acting as a hinge. It constrains all three translations and two rotations, mapping to the REVOLUTE JointDoFType.
- Coordinates: 1 (angle)
- DoFs: 1 (rotational)
- Constraints: 5 (
T_x,T_y,T_z,R_y,R_z)
Fixed
The Fixed joint rigidly attaches two bodies, allowing zero relative motion. It applies six bilateral constraints to lock all degrees of freedom, corresponding to the FIXED JointDoFType.
- Coordinates: 0
- DoFs: 0
- Constraints: 6 (fully locked)
Cable
The Cable joint is currently a specialized JointType entry representing flexible connections with 1 linear stretch degree of freedom and 1 isotropic bend/twist degree of freedom. Unlike other joints, it does not yet have a dedicated JointDoFType variant; the engine treats it as a special case in the solver.
- Coordinates: 2
- DoFs: 2 (1 translational + 1 rotational)
- Constraints: 4
Mapping Between Representations
The conversion between public JointType and internal JointDoFType occurs through explicit mapping tables in newton/_src/solvers/kamino/_src/core/joints.py (lines 66-80).
The static method JointDoFType.to_newton() implements this mapping:
# Mapping table from JointDoFType.to_newton (lines 66-80)
_MAP_TO_NEWTON = {
JointDoFType.FREE: JointType.FREE,
JointDoFType.REVOLUTE: JointType.REVOLUTE,
JointDoFType.PRISMATIC: JointType.PRISMATIC,
JointDoFType.SPHERICAL: JointType.BALL,
JointDoFType.FIXED: JointType.FIXED,
# D6-family joints map to the generic D6 type
JointDoFType.CARTESIAN: JointType.D6,
JointDoFType.CYLINDRICAL: JointType.D6,
JointDoFType.UNIVERSAL: JointType.D6,
JointDoFType.GIMBAL: JointType.D6,
}
This explicit dictionary approach makes the system extensible—adding a new joint type requires only adding entries to the enum and updating the mapping table.
Practical Implementation Examples
Creating a Revolute Joint Descriptor
To instantiate a revolute joint in Newton, use the JointDescriptor class from newton.geometry with JointDoFType.REVOLUTE:
from newton.geometry import JointDescriptor, JointActuationType, JointDoFType
# A simple revolute joint that is position-controlled
rev_joint = JointDescriptor(
name="elbow",
act_type=JointActuationType.POSITION,
dof_type=JointDoFType.REVOLUTE,
bid_B=0, # base body index
bid_F=1, # follower body index
B_r_Bj=[0.0, 0.0, 0.0], # joint origin in base frame
F_r_Fj=[0.0, 0.0, 0.0], # joint origin in follower frame
k_p_j=1.0, # PD proportional gain
k_d_j=0.1, # PD derivative gain
)
print(rev_joint) # human-readable summary
print("Newton JointType →", rev_joint.dof_type.to_newton())
Source: JointDescriptor definition in newton/_src/solvers/kamino/_src/core/joints.py (lines 81-95).
Converting JointType to JointDoFType
When importing scenes from external formats like USD, you may need to convert the generic JointType back to a specific JointDoFType:
from newton._src.sim.enums import JointType
from newton._src.solvers.kamino._src.core.joints import JointDoFType
import numpy as np
# Suppose we read a joint from a USD file – it says type is D6
joint_type = JointType.D6
# Infer the most specific DoF type (requires extra info such as axis count)
# Here we assume a cylindrical joint (1 translational + 1 rotational)
dof_type = JointDoFType.from_newton(
type=joint_type,
q_count=2, qd_count=2,
dof_dim=(1, 1), # 1 translational, 1 rotational axis
limit_lower=np.array([-1e3, -np.pi]),
limit_upper=np.array([1e3, np.pi]),
)
print(dof_type) # JointDoFType.CYLINDRICAL
Source: JointDoFType.from_newton logic in newton/_src/solvers/kamino/_src/core/joints.py (lines 86-112).
Running the Basic Joints Demo
Newton includes a ready-to-run demonstration that visualizes all supported joint types:
uv run -m newton.examples basic_joints
This command executes the example script at newton/examples/basic/example_basic_joints.py, which constructs a miniature world, adds bodies with each joint type (D6, Ball, Prismatic, Revolute, Fixed, and Cable), and renders a snapshot to docs/images/examples/example_basic_joints.jpg.
Summary
- Newton joint types are defined by two complementary enumerations: the public
JointTypeinnewton/_src/sim/enums.pyand the internalJointDoFTypeinnewton/_src/solvers/kamino/_src/core/joints.py. - D6 joints provide generic 6-DoF configurability, mapping internally to specialized
JointDoFTypevariants (CARTESIAN,CYLINDRICAL,UNIVERSAL,GIMBAL) based on enabled axes. - Ball, Prismatic, Revolute, and Fixed joints correspond directly to
SPHERICAL,PRISMATIC,REVOLUTE, andFIXEDinternal types with specific coordinate counts and constraint structures. - Cable joints are currently represented as a specialized
JointTypewith 2 DoFs (stretch and twist) without a dedicatedJointDoFTypevariant. - Conversion between representations uses explicit mapping tables in
JointDoFType.to_newton()andJointDoFType.from_newton(), making the system extensible through pure PythonIntEnummodifications.
Frequently Asked Questions
What is the difference between JointType and JointDoFType in Newton?
JointType is the public-facing enumeration defined in newton/_src/sim/enums.py that serves as the primary contract for users and external tools like USD Physics or MuJoCo importers. JointDoFType is the internal solver representation in newton/_src/solvers/kamino/_src/core/joints.py that encodes mathematical properties including coordinate count, degrees of freedom, and bilateral constraint requirements for the physics solver.
How do I choose between a Ball joint and a D6 joint in Newton?
Choose a Ball joint when you need three rotational degrees of freedom with locked translation, such as for shoulder or hip joints in character animation, as it uses a quaternion representation that avoids gimbal lock. Choose a D6 joint when you need a configurable combination of specific translational and rotational axes, such as for robotic joints requiring prismatic motion along one axis combined with rotation around another, which the solver internally maps to specialized types like CYLINDRICAL or UNIVERSAL.
Where are Newton joint types defined in the source code?
The public JointType enumeration is defined in newton/_src/sim/enums.py (lines 46-69), while the internal JointDoFType enumeration and conversion logic reside in newton/_src/solvers/kamino/_src/core/joints.py (lines 87-124 for DoF definitions, lines 66-80 for the mapping table). The high-level JointDescriptor class used to instantiate joints is also located in the joints.py file (lines 81-95).
Can I create custom joint types in Newton?
Yes, the explicit mapping architecture between JointDoFType and JointType makes the system extensible without hidden magic. To create a custom joint, add a new member to JointDoFType with appropriate num_coords, num_dofs, and num_cts values in newton/_src/solvers/kamino/_src/core/joints.py, add a corresponding entry in the _MAP_TO_NEWTON dictionary (lines 66-80), and optionally expose a new JointType value in newton/_src/sim/enums.py for external API compatibility.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →