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:

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.