Calculate Wheel Slip Angle in Ammo.js Raycast Vehicle

This article explains how to calculate the lateral slip angle of a wheel in an ammo.js raycast vehicle simulation. By determining the difference between the direction a wheel is pointing and its actual direction of travel, you can implement realistic tire physics, drifting mechanics, tire smoke, and traction control systems in your JavaScript 3D physics applications.

Understanding the Slip Angle

The slip angle (denoted as \(\alpha\)) is the angle between the direction a wheel is oriented (its forward vector) and the vector of its actual velocity.

To calculate this in ammo.js, we must determine the wheel’s world-space orientation and its velocity in the world, project that velocity onto the wheel’s local axes, and compute the angle.


Step-by-Step Calculation

1. Retrieve Wheel and Vehicle Data

First, access the specific wheel’s world transform and the vehicle’s rigid body to calculate positional velocity.

// Assume 'vehicle' is your Ammo.btRaycastVehicle instance
// 'wheelIndex' is the index of the target wheel (0 to 3)
const wheelInfo = vehicle.getWheelInfo(wheelIndex);
const chassisBody = vehicle.getRigidBody();

// Get the wheel's world transform
const wheelTransform = wheelInfo.get_m_worldTransform();
const wheelOrigin = wheelTransform.getOrigin();
const wheelBasis = wheelTransform.getBasis();

2. Extract Wheel Direction Vectors

Using the basis matrix of the wheel’s world transform, extract the local forward and right vectors in world space. In ammo.js, row vectors represent the local axes:

// Row 0 is the Right/Axle vector (X-axis)
const wheelRight = wheelBasis.getRow(0); 

// Row 2 is the Forward/Rolling vector (Z-axis)
const wheelForward = wheelBasis.getRow(2); 

3. Calculate Wheel Velocity in World Space

To find the exact velocity of the wheel, you must account for both the linear velocity of the chassis and its angular velocity (rotation). Use the relative position of the wheel to the chassis’s center of mass.

const chassisTransform = chassisBody.getWorldTransform();
const chassisOrigin = chassisTransform.getOrigin();

// Calculate relative position vector from chassis center of mass to wheel
const relativePos = new Ammo.btVector3(
    wheelOrigin.x() - chassisOrigin.x(),
    wheelOrigin.y() - chassisOrigin.y(),
    wheelOrigin.z() - chassisOrigin.z()
);

// Get the exact world-space velocity at this relative point
const wheelVelocity = chassisBody.getVelocityInLocalPoint(relativePos);

4. Project Velocity onto Wheel Axes

Project the wheel’s velocity vector onto the wheel’s forward and right vectors using dot products. This gives you the longitudinal speed (forward/backward) and lateral speed (sideslip).

const lateralVel = wheelVelocity.dot(wheelRight);
const longitudinalVel = wheelVelocity.dot(wheelForward);

5. Compute the Slip Angle

Use the arc tangent function (Math.atan2) with the lateral and longitudinal velocities to get the slip angle in radians.

let slipAngle = 0;

// Prevent division by zero or noisy values at extremely low speeds
if (Math.abs(longitudinalVel) > 0.1) {
    slipAngle = Math.atan2(lateralVel, Math.abs(longitudinalVel));
} else {
    slipAngle = 0;
}

// Convert to degrees if needed
const slipAngleDegrees = slipAngle * (180 / Math.PI);

Using Math.abs(longitudinalVel) ensures that the slip angle remains logical even when the vehicle is rolling backward.


Clean-up

To avoid memory leaks in your game loop, remember to manually destroy any temporary btVector3 objects created during this calculation if they are not managed by a temporary vector pool:

Ammo.destroy(relativePos);
Ammo.destroy(wheelVelocity);