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_q and joint_qd, requiring eval_fk to derive body poses, and are used by SolverFeatherstone and SolverMuJoCo.
  • Maximal coordinates store full 6-DOF poses in body_q and body_qd, need no forward kinematics, and are used by SolverXPBD, SolverSemiImplicit, SolverKamino, and SolverVBD.
  • The coordinate type determines how you initialize velocities: use joint_qd + eval_fk for generalized, body_qd directly 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →