Drone Motor Failure and Landing in Matter.js
This article explains how to simulate motor failure and emergency landing dynamics for a multirotor drone using the Matter.js 2D physics engine. By breaking down drone physics into rigid-body components, asymmetric thrust calculations, aerodynamic drag, and reactive emergency descent logic, developers can create realistic aeronautical failure scenarios.
Modeling the Base Drone Physics
In Matter.js, a 2D quadcopter or hexacopter is typically modeled as a single rectangular rigid body or a composite body with distinct thrust points representing the left and right motor sets.
const { Bodies, Body, Vector } = Matter;
const drone = Bodies.rectangle(400, 200, 120, 20, {
mass: 1.5,
frictionAir: 0.02, // Simulates ambient aerodynamic drag
restitution: 0.1 // Low bounce for realistic impact
});Normal flight requires applying vertical forces at offset points relative to the drone’s center of mass:
- Left Motor Force: Applied at
(-width / 2, 0)relative to the center. - Right Motor Force: Applied at
(+width / 2, 0)relative to the center.
When both forces equal half of mass * gravity, the drone
hovers. Differential thrust generates torque, allowing the drone to
rotate and translate laterally.
Simulating Motor Failure
A motor failure event is modeled by abruptly reducing or completely zeroing out the thrust vector of one motor point.
let droneState = {
leftMotorThrust: 0.015,
rightMotorThrust: 0.015,
failedMotor: null // 'left', 'right', or null
};
function triggerMotorFailure(side) {
droneState.failedMotor = side;
if (side === 'left') droneState.leftMotorThrust = 0;
if (side === 'right') droneState.rightMotorThrust = 0;
}Once a motor fails, asymmetric thrust introduces extreme angular acceleration. If the remaining motor continues firing at hover power, the drone spins rapidly along its z-axis and falls because net upward thrust drops below gravitational force.
Emergency Landing Dynamics and Control
Real-world drones cannot maintain standard flight with a single rotor failure in a quadcopter configuration, but they can execute an emergency landing strategy: reducing remaining thrust to limit rotational velocity while keeping the descent speed survivable.
1. Angular Velocity Mitigation
To prevent violent tumbling, the emergency controller dynamically throttles the surviving motor based on current orientation and angular velocity:
function updateEmergencyFlight(drone, droneState) {
if (!droneState.failedMotor) return;
// Detect deviation from level horizon (drone.angle = 0)
const angle = drone.angle;
const angularVelocity = drone.angularVelocity;
// Apply intermittent thrust on surviving motor only when oriented upward
const isUpright = Math.cos(angle) > 0.5; // Within ~60 degrees of upright
if (isUpright && drone.velocity.y > 2) {
// Pulse thrust to brake vertical descent without over-rotating
const brakeForce = 0.012;
if (droneState.failedMotor === 'left') {
applyMotorForce(drone, 1, brakeForce); // Fire right motor
} else {
applyMotorForce(drone, -1, brakeForce); // Fire left motor
}
}
}2. Passive Aerodynamic Stabilization
In Matter.js, rotational drag can be supplemented using custom torque damping. As the drone tumbles, air resistance counters rapid spinning:
// Apply rotational damping during descent
drone.torque = -drone.angularVelocity * 0.5;3. Force Application Loop
The forces must be mapped from the drone's local coordinate space to
the global world space in the engine's beforeUpdate
event:
function applyMotorForce(drone, localXOffset, magnitude) {
const angle = drone.angle;
const forceVector = Vector.rotate({ x: 0, y: -magnitude }, angle);
const positionVector = {
x: drone.position.x + (localXOffset * (drone.bounds.max.x - drone.bounds.min.x) / 2) * Math.cos(angle),
y: drone.position.y + (localXOffset * (drone.bounds.max.x - drone.bounds.min.x) / 2) * Math.sin(angle)
};
Body.applyForce(drone, positionVector, forceVector);
}Impact and Structural Damage Handling
When the drone hits the ground, impact forces determine whether the
emergency landing was successful or fatal. Listen to the
collisionStart event to calculate the impact impulse:
Matter.Events.on(engine, 'collisionStart', (event) => {
event.pairs.forEach((pair) => {
if (pair.bodyA === drone || pair.bodyB === drone) {
const impactSpeed = Vector.magnitude(drone.velocity);
const survivableSpeedLimit = 5.0; // Units per tick
if (impactSpeed > survivableSpeedLimit) {
// Catastrophic crash
drone.isStatic = true; // Stop movement or trigger debris spawning
} else {
// Successful emergency landing
droneState.leftMotorThrust = 0;
droneState.rightMotorThrust = 0;
}
}
});
});Using this setup, the drone transitions realistically from controlled flight to a torque-imbalanced tumble, applies emergency descent management, and resolves landing forces against the terrain.