Generalized vs Maximal Coordinates in Newton Solvers: What's the Difference?
Generalized coordinates use joint-space variables that require forward kinematics to derive body poses, while maximal coordinates store full 6-DOF body states directly in world space, eliminating the need for forward kinematics passes.
The Newton physics engine provides two distinct coordinate representations for rigid-body dynamics, each optimized for different simulation scenarios. Understanding whether a solver uses generalized (articulation) or maximal (world-space) coordinates is essential for correctly initializing states, handling collisions, and optimizing performance.
What Are Generalized Coordinates?
Generalized coordinates represent articulated systems through a reduced set of variables corresponding to joint degrees of freedom (DOF) rather than individual body poses. In this representation, the state vector contains only the independent variables needed to describe the mechanism's configuration.
Implementation in Newton
In newton/solvers.py, generalized-coordinate solvers operate on joint_q (joint positions) and joint_qd (joint velocities) as the primary state variables. Rigid-body poses (body_q and body_qd) are derived quantities computed via forward kinematics (FK) each simulation step.
According to the solver capabilities table in newton/solvers.py (lines 64-66), generalized-coordinate support is explicitly marked for Featherstone and MuJoCo solvers.
Solver Types Using Generalized Coordinates
- SolverFeatherstone: Implements articulated-body algorithms using reduced coordinates
- SolverMuJoCo: Wraps MuJoCo's native generalized-coordinate dynamics
What Are Maximal Coordinates?
Maximal coordinates represent each rigid body independently using its full 6-DOF pose in world space, regardless of joint constraints. This approach stores the complete transformation for every body, treating joints as constraints between these independent bodies rather than as the primary coordinate variables.
Implementation in Newton
Maximal-coordinate solvers in Newton store state directly in body_q (body poses) and body_qd (body twists). As documented in newton/solvers.py (lines 81-84), these solvers include XPBD, Semi-Implicit, Kamino, and VBD implementations.
Because body variables already contain the world-space pose, no forward kinematics pass is required to obtain body positions for collision detection or constraint resolution.
Solver Types Using Maximal Coordinates
- SolverXPBD: Extended Position-Based Dynamics using maximal coordinates
- SolverSemiImplicit: Semi-implicit Euler integration with world-space bodies
- SolverKamino: Specialized for deformable and rigid coupling
- SolverVBD: Velocity-Based Dynamics solver
Key Differences Between Generalized and Maximal Coordinates
The choice between coordinate representations affects memory layout, computational cost, and constraint handling:
| Aspect | Generalized Coordinates | Maximal Coordinates |
|---|---|---|
| State variables | joint_q, joint_qd (reduced DOFs) |
body_q, body_qd (6 DOF per body) |
| Forward kinematics | Required each step to derive body_q |
Not required; poses stored directly |
| Linear system size | Smaller (joint count) | Larger (body count × 6) |
| Joint limits | Simple bounds on joint_q |
Constraint equations between bodies |
| Collision handling | Computed after FK; contacts external to solver | Integrated into solver constraints |
| Numerical drift | Potential drift in body velocity conversion | Direct integration, tighter precision |
As noted in newton/tests/test_body_velocity.py, generalized-coordinate solvers require calling eval_fk after setting joint_qd to propagate velocities to body space (lines 24-26), while maximal-coordinate solvers write directly to body_qd (lines 13-15).
How to Detect Coordinate Type in Code
The test suite in newton/tests/test_kinematic_links.py provides a helper pattern (lines 84-86) to determine if a solver uses maximal coordinates by checking its type against the maximal-coordinate solver classes.
import newton
def is_maximal(solver: newton.solvers.SolverBase) -> bool:
"""Return True if the solver works on maximal (world‑space) coordinates."""
# Mirrors the test helper _uses_maximal_coordinates
return isinstance(
solver,
newton.solvers.SolverXPBD
| newton.solvers.SolverSemiImplicit
| newton.solvers.SolverVBD,
)
Setting Initial Velocities Correctly
The initialization pattern differs based on coordinate representation. The following example from the Newton test patterns shows how to set body velocities for both solver types:
import newton
import warp as wp
import numpy as np
def set_initial_velocity(state, solver, vel_body):
"""Set angular+linear velocity for a single free body.
* `vel_body` – 6‑element array [lin_x, lin_y, lin_z, ang_x, ang_y, ang_z].
* For generalized solvers we set `joint_qd` and run FK.
* For maximal solvers we set `body_qd` directly.
"""
vel = np.asarray(vel_body, dtype=np.float32).reshape(1, 6)
if is_maximal(solver):
# Maximal‑coordinate solvers (XPBD, SemiImplicit, VBD)
state.body_qd.assign(vel) # body‑space twist
else:
# Generalized‑coordinate solvers (MuJoCo, Featherstone)
state.joint_qd.assign(vel) # joint‑space twist
# Propagate to body space so the solver sees a consistent pose
newton.eval_fk(state.model, state.joint_q, state.joint_qd, state)
Choosing the Right Solver for Your Simulation
Select your coordinate representation based on the dominant physics in your scene:
Use generalized coordinates (SolverFeatherstone, SolverMuJoCo) when:
- Your simulation is dominated by articulated mechanisms (robot arms, humanoids, kinematic chains)
- You need the smallest possible linear system for performance
- Joint limits and motor constraints are the primary concern
- You can afford the forward kinematics overhead each step
Use maximal coordinates (SolverXPBD, SolverSemiImplicit, SolverKamino, SolverVBD) when:
- Your simulation involves many contacts, collisions, or soft-body coupling
- You need to handle both articulated and free bodies with the same solver
- You want to avoid numerical drift from FK conversions
- You prefer direct integration of body twists for sub-microsecond precision
Summary
- Generalized coordinates store state in
joint_qandjoint_qd, requiringeval_fkto derive body poses, and are used bySolverFeatherstoneandSolverMuJoCo. - Maximal coordinates store full 6-DOF poses in
body_qandbody_qd, need no forward kinematics, and are used bySolverXPBD,SolverSemiImplicit,SolverKamino, andSolverVBD. - The coordinate type determines how you initialize velocities: use
joint_qd+eval_fkfor generalized,body_qddirectly for maximal. - Choose generalized coordinates for pure articulation dynamics with minimal DOFs, and maximal coordinates for contact-rich simulations requiring unified body handling.
Frequently Asked Questions
Which is faster, generalized or maximal coordinates?
Generalized coordinates typically yield smaller linear systems and faster articulation dynamics because they only solve for joint DOFs rather than 6 DOF per body. However, maximal coordinates eliminate the forward kinematics overhead and handle contacts more efficiently within the solver loop. For robot arms with few contacts, generalized coordinates are usually faster; for debris simulations or character ragdolls with many collisions, maximal coordinates often perform better.
Can I switch between coordinate types mid-simulation?
No, the coordinate representation is determined by the solver class you instantiate at initialization. SolverFeatherstone and SolverMuJoCo always use generalized coordinates, while SolverXPBD and others always use maximal coordinates. To change representations, you must create a new solver instance and reinitialize the state variables (joint_q vs body_q).
Do maximal coordinate solvers handle joint limits?
Yes, but they implement joint limits as constraints between bodies rather than simple bounds on coordinate variables. In generalized coordinates, joint limits are direct bounds on joint_q values. In maximal coordinates, the solver adds constraint equations to the linear system to enforce joint limits, which increases system size but allows for more complex limit geometries and coupling effects.
Why does Newton require eval_fk for generalized solvers?
Generalized solvers operate on joint_q and joint_qd as the canonical state, but collision detection and rendering require world-space body poses (body_q). The newton.eval_fk function computes these derived poses via forward kinematics. This call is required after setting joint velocities and before stepping the solver to ensure body-space quantities remain consistent with the joint-space source of truth, as demonstrated in newton/tests/test_body_velocity.py.
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 →