# How Joint Motors in Box3D Drive Rotational and Linear Motion with Force Limits

> Learn how Box3D joint motors generate rotational and linear motion. Discover how force limits ensure physically stable actuation for your simulations. Achieve precise control.

- Repository: [Erin Catto/box3d](https://github.com/erincatto/box3d)
- Tags: deep-dive
- Published: 2026-08-01

---

**Box3D joint motors compute constraint impulses to achieve target velocities, then clamp those impulses using user-defined force limits scaled by the time step, ensuring physically stable actuation.**

Box3D, the open-source 3D physics engine by Erin Catto, implements motor-driven joints that actively propel rigid bodies while respecting Newtonian force constraints. These joint motors in Box3D operate through a three-stage solver process that converts desired velocities into impulsive forces, making them essential for robotics, vehicle simulations, and mechanical actuators.

## How Joint Motors Compute Constrained Motion

The motor architecture is shared across `MotorJoint`, `RevoluteJoint`, and `PrismaticJoint`, with all implementations following a consistent three-phase pattern inside the velocity solver.

### Stage 1: Target Velocity Specification

Users specify desired motion through API setters that store target velocities in the joint structure. For the 6-DOF **MotorJoint**, you set linear and angular velocities independently.

In [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c), lines 16-22 handle linear velocity storage, while lines 30-36 store angular velocity targets:

```c
// Linear velocity target (line 16-22)
void b3MotorJoint_SetLinearVelocity(b3JointId jointId, b3Vec3 velocity)

// Angular velocity target (line 30-36)  
void b3MotorJoint_SetAngularVelocity(b3JointId jointId, b3Vec3 omega)

```

For single-axis joints, **RevoluteJoint** uses `b3RevoluteJoint_SetMotorSpeed` (line 90-96 in [`src/revolute_joint.c`](https://github.com/erincatto/box3d/blob/main/src/revolute_joint.c)) to set rotational velocity, while **PrismaticJoint** uses `b3PrismaticJoint_SetMotorSpeed` (line 96-102 in [`src/prismatic_joint.c`](https://github.com/erincatto/box3d/blob/main/src/prismatic_joint.c)) for linear motion along the joint axis.

### Stage 2: Spring-Damping Correction

Optionally, MotorJoint applies soft spring forces before velocity correction. When `linearHertz` or `angularHertz` are non-zero, the solver resolves spring constraints that pull bodies toward target relative poses.

This occurs in [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c) starting at line 302, where the angular spring block (lines 302-322) and linear spring calculations compute restorative impulses based on the specified frequency and damping ratio.

### Stage 3: Impulse Limiting with Force Caps

After spring resolution, the solver computes the impulse required to achieve the target velocity, then clamps it to respect user-defined force limits. This clamping converts Newton limits (or N·m for torque) into impulse limits by multiplying by the time step `context->h`.

In [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c), lines 94-108 handle linear velocity impulse clamping:

```c
float maxImpulse = context->h * joint->maxVelocityForce;
b3Vec3 oldImpulse = joint->linearVelocityImpulse;
joint->linearVelocityImpulse = b3Add(oldImpulse, impulse);

if (b3LengthSquared(joint->linearVelocityImpulse) > maxImpulse*maxImpulse) {
    joint->linearVelocityImpulse = b3MulSV(maxImpulse,
                                         b3Normalize(joint->linearVelocityImpulse));
}

```

The angular equivalent appears at lines 128-144, using `maxVelocityTorque` instead of `maxVelocityForce`. This pattern ensures the motor never exceeds the specified force budget, regardless of how large the velocity error becomes.

## Motor Joint Types and APIs

Box3D provides three distinct motor implementations optimized for different degrees of freedom.

### MotorJoint: 6-DOF Linear and Angular Control

**MotorJoint** simultaneously drives translation and rotation with separate force and torque limits. Setters for these limits appear in [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c) at lines 44-70:

- `b3MotorJoint_SetMaxVelocityForce` (line 58): Caps linear motor force in Newtons
- `b3MotorJoint_SetMaxVelocityTorque` (line 44): Caps angular motor torque in Newton-meters

This joint type maintains four distinct limit values: `maxVelocityForce`, `maxVelocityTorque`, `maxSpringForce`, and `maxSpringTorque`.

### RevoluteJoint: Rotational Motors with Torque Limits

**RevoluteJoint** provides single-axis rotation using motor speed and maximum torque parameters. The implementation in [`src/revolute_joint.c`](https://github.com/erincatto/box3d/blob/main/src/revolute_joint.c) exposes:

- `b3RevoluteJoint_SetMotorSpeed` (lines 90-96): Sets target angular velocity in radians per second
- `b3RevoluteJoint_SetMaxMotorTorque` (lines 105-112): Sets the torque limit in N·m

The solver clamps the accumulated `motorImpulse` variable to stay within `[-maxMotorTorque * h, maxMotorTorque * h]`.

### PrismaticJoint: Linear Motors with Force Limits

**PrismaticJoint** constrains motion to a single axis while allowing motorized translation. Found in [`src/prismatic_joint.c`](https://github.com/erincatto/box3d/blob/main/src/prismatic_joint.c), the API includes:

- `b3PrismaticJoint_SetMotorSpeed` (lines 96-102): Target linear velocity along the joint axis
- `b3PrismaticJoint_SetMaxMotorForce` (lines 111-118): Maximum force in Newtons

Like RevoluteJoint, the solver applies the same impulse-clamping pattern to ensure the motor force never exceeds the user-defined cap.

## Code Examples

### Example 1: 6-DOF MotorJoint with Velocity and Force Limits

```c
b3WorldId worldId = b3CreateWorld(&worldDef);
b3BodyId bodyA = b3CreateBody(worldId, &bodyDefA);
b3BodyId bodyB = b3CreateBody(worldId, &bodyDefB);

/* Create motor joint */
b3MotorJointDef mjDef = b3DefaultMotorJointDef();
mjDef.base.bodyIdA = bodyA;
mjDef.base.bodyIdB = bodyB;
b3JointId mjId = b3CreateMotorJoint(worldId, &mjDef);

/* Target velocities */
b3MotorJoint_SetLinearVelocity(mjId, (b3Vec3){1.0f, 0.0f, 0.0f});   // 1 m/s along X
b3MotorJoint_SetAngularVelocity(mjId, (b3Vec3){0.0f, 0.5f, 0.0f}); // 0.5 rad/s about Y

/* Force/torque limits */
b3MotorJoint_SetMaxVelocityForce(mjId, 200.0f);   // ≤ 200 N
b3MotorJoint_SetMaxVelocityTorque(mjId, 150.0f); // ≤ 150 N·m

/* Optional spring softening */
b3MotorJoint_SetLinearHertz(mjId, 5.0f);
b3MotorJoint_SetLinearDampingRatio(mjId, 0.7f);

```

### Example 2: RevoluteJoint Rotation with Torque Limit

```c
b3RevoluteJointDef rjDef = b3DefaultRevoluteJointDef();
rjDef.base.bodyIdA = bodyA;
rjDef.base.bodyIdB = bodyB;
b3JointId rjId = b3CreateRevoluteJoint(worldId, &rjDef);

b3RevoluteJoint_EnableMotor(rjId, true);
b3RevoluteJoint_SetMotorSpeed(rjId, 2.0f);          // 2 rad/s
b3RevoluteJoint_SetMaxMotorTorque(rjId, 80.0f);       // ≤ 80 N·m

```

### Example 3: PrismaticJoint Linear Motion with Force Limit

```c
b3PrismaticJointDef pjDef = b3DefaultPrismaticJointDef();
pjDef.base.bodyIdA = bodyA;
pjDef.base.bodyIdB = bodyB;
b3JointId pjId = b3CreatePrismaticJoint(worldId, &pjDef);

b3PrismaticJoint_EnableMotor(pjId, true);
b3PrismaticJoint_SetMotorSpeed(pjId, 3.0f);          // 3 m/s along axis
b3PrismaticJoint_SetMaxMotorForce(pjId, 120.0f);     // ≤ 120 N

```

## Summary

- **Box3D joint motors** use a three-stage solver: target velocity specification, optional spring-damping, and impulse clamping with force limits.
- **Force limits** are converted to impulse limits by multiplying by the simulation time step (`context->h`), ensuring consistent behavior across different timestep sizes.
- **MotorJoint** provides full 6-DOF control with separate linear force and angular torque caps, while **RevoluteJoint** and **PrismaticJoint** offer single-axis rotation and translation motors respectively.
- All motor implementations in [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c), [`src/revolute_joint.c`](https://github.com/erincatto/box3d/blob/main/src/revolute_joint.c), and [`src/prismatic_joint.c`](https://github.com/erincatto/box3d/blob/main/src/prismatic_joint.c) share the same fundamental impulse-clamping architecture for stable physics simulation.

## Frequently Asked Questions

### How do force limits convert to impulse limits in Box3D?

Box3D converts force limits to impulse limits by multiplying the user-specified maximum force (in Newtons) or torque (in N·m) by the simulation time step `context->h`. This occurs in [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c) at lines 94-108 for linear forces and lines 128-144 for angular torques, ensuring the accumulated impulse never exceeds what the force limit could produce in a single timestep.

### What is the difference between MotorJoint and RevoluteJoint motors?

**MotorJoint** is a 6-DOF constraint that can simultaneously drive linear and angular velocities with separate force and torque limits, as implemented in [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c). **RevoluteJoint** is a single-degree-of-freedom rotational hinge that only drives angular velocity around one axis using `b3RevoluteJoint_SetMotorSpeed` and `b3RevoluteJoint_SetMaxMotorTorque`, as found in [`src/revolute_joint.c`](https://github.com/erincatto/box3d/blob/main/src/revolute_joint.c) lines 90-112.

### Can spring drives and velocity motors operate simultaneously?

Yes. In [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c), the solver first resolves spring constraints (lines 302-322) to pull bodies toward target poses, then applies velocity motor constraints (lines 85-112) to drive relative motion. The force limits `maxSpringForce` and `maxVelocityForce` are evaluated independently, allowing both soft positioning and hard velocity control to coexist.

### Where are motor parameters stored in the Box3D source?

Motor parameters reside in joint-specific structures defined in the source files. [`src/motor_joint.c`](https://github.com/erincatto/box3d/blob/main/src/motor_joint.c) stores `maxVelocityForce` and `maxVelocityTorque` in the `b3MotorJoint` struct (setters at lines 44-70), while [`src/revolute_joint.c`](https://github.com/erincatto/box3d/blob/main/src/revolute_joint.c) stores `motorSpeed` and `maxMotorTorque` in `b3RevoluteJoint` (lines 90-112). These values persist across simulation steps and are accessed during the `b3SolveMotorJoint` or corresponding solve functions.