Rocket Lander Thruster Stabilization in Matter.js
This article explains how to build a 2D autonomous rocket lander simulation using the Matter.js 2D physics engine. You will learn how to initialize the physical environment, construct a rigid rocket body, calculate corrective thrust using a Proportional-Derivative (PD) control loop, and apply directional thruster impulses directly to the body to stabilize both its orientation and descent rate for a soft landing.
1. Setting Up the Matter.js Environment
Begin by importing the necessary Matter.js modules to establish the physics world, rendering canvas, and update runner.
const { Engine, Render, Runner, Bodies, Body, Composite, Vector, Events } = Matter;
const engine = Engine.create();
const world = engine.world;
// Set gravity appropriate for a planetary descent
world.gravity.y = 0.5;
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);2. Creating the Lander and Landing Pad
The rocket lander requires a physical body with defined dimensions, mass, and rotational inertia. Add a ground body to act as the landing platform.
// Rocket dimensions
const rocketWidth = 20;
const rocketHeight = 60;
// Create the rocket body
const rocket = Bodies.rectangle(400, 100, rocketWidth, rocketHeight, {
mass: 10,
frictionAir: 0.01,
angle: (Math.random() - 0.5) * 0.5 // Initial random tilt
});
// Create the ground
const ground = Bodies.rectangle(400, 580, 800, 40, { isStatic: true });
Composite.add(world, [rocket, ground]);3. Thruster Physics Concepts
Stabilizing a descent requires two independent control operations:
- Attitude Stabilization (Rotation): Regulating the
angle to ensure the rocket points upright (
angle = 0). This is achieved using side Reaction Control System (RCS) thrusters that exert force offset from the center of mass, producing rotational torque. - Descent Velocity Control (Altitude): Applying upward force along the longitudinal axis of the rocket using the main thruster to prevent crash impact.
In Matter.js, forces are applied using
Body.applyForce(body, position, force). Applying a force at
an offset from body.position introduces angular
acceleration.
4. Implementing Attitude Control via a PD Controller
To prevent overshooting and perpetual oscillation, use a Proportional-Derivative (PD) controller for the attitude thrusters. The controller computes corrective force based on the current angle error (Proportional) and the angular speed (Derivative).
function calculateAttitudeThrust(rocket) {
const targetAngle = 0;
const currentAngle = rocket.angle;
const currentAngularVelocity = rocket.angularVelocity;
// Controller gains
const kP = 0.05; // Proportional gain (corrects position error)
const kD = 0.3; // Derivative gain (dampens oscillation)
// Compute torque output
const angleError = targetAngle - currentAngle;
return (kP * angleError) - (kD * currentAngularVelocity);
}5. Implementing Descent Speed Regulation
The main thruster slows the vehicle down as it approaches the surface. Compute the upward thrust required by evaluating vertical velocity and altitude.
function calculateMainThrust(rocket, groundY) {
const targetVelocity = 1.0; // Safe touchdown speed (pixels per frame)
const altitude = groundY - rocket.position.y;
// Apply thrust if descending faster than desired, scaling with proximity
if (rocket.velocity.y > targetVelocity) {
const kP_descent = 0.0008;
return -Math.min(0.02, (rocket.velocity.y - targetVelocity) * kP_descent);
}
return 0;
}6. Executing Thrusters in the Simulation Loop
Hook into the Matter.js beforeUpdate event. This step
runs before every physics calculation, allowing you to compute errors
and apply vector forces dynamically.
Events.on(engine, 'beforeUpdate', () => {
// 1. Attitude stabilization (RCS impulses)
const torque = calculateAttitudeThrust(rocket);
// Calculate the position of the top of the rocket
const topOffset = Vector.rotate({ x: 0, y: -rocketHeight / 2 }, rocket.angle);
const topPos = Vector.add(rocket.position, topOffset);
// Apply lateral impulse perpendicular to rocket orientation at the top tip
const rcsForce = Vector.rotate({ x: torque, y: 0 }, rocket.angle);
Body.applyForce(rocket, topPos, rcsForce);
// 2. Main thruster impulses (counteracting gravity)
const mainThrustMagnitude = calculateMainThrust(rocket, 560);
if (mainThrustMagnitude < 0) {
// Force direction aligned with the rocket's longitudinal axis
const thrusterForce = Vector.rotate({ x: 0, y: mainThrustMagnitude }, rocket.angle);
// Bottom position of the rocket
const bottomOffset = Vector.rotate({ x: 0, y: rocketHeight / 2 }, rocket.angle);
const bottomPos = Vector.add(rocket.position, bottomOffset);
Body.applyForce(rocket, bottomPos, thrusterForce);
}
});7. Tuning for Stability
- Oscillation: If the rocket tilts back and forth
aggressively, reduce
kPor increasekDto add damping. - Sluggish Correction: If the lander fails to right
itself before hitting the ground, increase
kP. - Hard Landing: If the descent rate remains high,
increase
kP_descentor the maximum allowed force cap incalculateMainThrust.