Simulate ABS in Matter.js with Angular Velocity
This article explains how to simulate an Anti-lock Braking System (ABS) in the Matter.js 2D physics engine by dynamically monitoring wheel slip and modulating wheel angular velocity. By algorithmically preventing a wheel from coming to a complete rotational halt while the vehicle chassis is still moving, you can prevent sliding, maintain optimal tire friction, and simulate realistic vehicle dynamics directly in the browser.
The Mechanics of Wheel Slip
In real-world vehicle dynamics, braking performance depends on the slip ratio (\(S\)). Slip measures the difference between the linear speed of the vehicle body (\(v\)) and the tangential surface speed of the rotating wheel (\(\omega \times r\)):
\[S = \frac{v - (\omega \cdot r)}{v}\]
- \(S = 0\): The wheel rolls freely without slipping.
- \(0 < S < 0.2\): The wheel provides optimal braking friction.
- \(S = 1\): The wheel is completely locked (\(\omega = 0\)), causing the tire to skid and significantly reducing lateral steering control and stopping efficiency.
To simulate ABS, the control loop must detect when \(S\) exceeds a predefined threshold (typically between 0.15 and 0.20) and reduce or reverse the braking force applied to the wheel's angular velocity.
Setting Up the Vehicle in Matter.js
A standard vehicle setup consists of a main body (chassis) and circular bodies (wheels) attached via pin or spring constraints.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Events, Body } = Matter;
// Create chassis and wheel
const chassis = Bodies.rectangle(400, 300, 200, 40, { density: 0.002 });
const wheelRadius = 30;
const wheel = Bodies.circle(340, 330, wheelRadius, {
friction: 0.9,
density: 0.005
});
// Attach wheel with an axle constraint
const axle = Constraint.create({
bodyA: chassis,
pointA: { x: -60, y: 30 },
bodyB: wheel,
stiffness: 1,
length: 0
});Implementing the ABS Control Loop
To modulate wheel angular velocity, hook into Matter.js's
beforeUpdate event. In this hook, calculate the current
slip ratio, determine whether ABS should intervene, and override
wheel.angularVelocity.
1. Calculating Slip
Calculate the forward velocity vector of the chassis relative to the wheel's rotational direction. For a 2D side-view simulation moving horizontally along the X-axis:
function getSlipRatio(chassis, wheel, wheelRadius) {
const forwardSpeed = Math.abs(chassis.velocity.x);
if (forwardSpeed < 0.1) return 0; // Ignore low speeds to prevent division by zero
// Linear speed from rotation
const rotationalLinearSpeed = Math.abs(wheel.angularVelocity * wheelRadius);
// Calculate slip ratio
return (forwardSpeed - rotationalLinearSpeed) / forwardSpeed;
}2. Modulating Angular Velocity
When the user applies the brakes, standard mechanics reduce
wheel.angularVelocity down to zero. With ABS enabled, if
the calculated slip ratio passes the critical threshold, the system
temporarily eases the deceleration or clamps the angular velocity to an
optimal rolling speed.
let isBraking = false;
const MAX_SLIP_THRESHOLD = 0.20;
const OPTIMAL_SLIP_TARGET = 0.15;
const BRAKE_DECELERATION = 0.05; // Base braking torque effect
Events.on(engine, 'beforeUpdate', () => {
if (!isBraking) return;
const forwardSpeed = chassis.velocity.x;
const absSpeed = Math.abs(forwardSpeed);
// If the vehicle has practically stopped, bring the wheel to a complete rest
if (absSpeed < 0.2) {
Body.setAngularVelocity(wheel, 0);
return;
}
const currentSlip = getSlipRatio(chassis, wheel, wheelRadius);
if (currentSlip > MAX_SLIP_THRESHOLD) {
// ABS Intervention: Release brake pressure to allow the wheel to speed back up
// Target an angular velocity that keeps slip at the optimal threshold
const targetRotationalSpeed = (absSpeed * (1 - OPTIMAL_SLIP_TARGET)) / wheelRadius;
const sign = Math.sign(forwardSpeed);
// Nudge angular velocity toward target to simulate hydraulic pulsing
const correctedAngularVelocity = wheel.angularVelocity + (sign * targetRotationalSpeed - wheel.angularVelocity) * 0.3;
Body.setAngularVelocity(wheel, correctedAngularVelocity);
} else {
// Normal Braking: Decrement angular velocity
const sign = Math.sign(wheel.angularVelocity);
let newAngularVelocity = wheel.angularVelocity - sign * BRAKE_DECELERATION;
// Prevent counter-rotation while braking forward
if (Math.sign(newAngularVelocity) !== sign) {
newAngularVelocity = 0;
}
Body.setAngularVelocity(wheel, newAngularVelocity);
}
});Fine-Tuning Parameters for Realism
- Pulsing Frequency: Real-world ABS pulses the brakes multiple times per second (15–20 Hz). You can simulate this discrete behavior by wrapping the intervention in a timer or frame counter, oscillating the brake force between zero and maximum rather than smoothing it.
- Surface Friction: Adjust
wheel.frictionand the ground body'sfriction. On lower-friction surfaces (e.g.,friction = 0.1for ice), wheels lock up significantly faster, forcing the ABS algorithm to intervene more aggressively. - Brake Bias: If multiple wheels are simulated, run the calculation separately per wheel. This allows independent wheel modulation to prevent the vehicle from rotating unexpectedly under heavy braking.