# Robot keeps driving after the remote connection drops: add a failsafe stop

> Add a failsafe: record the time of the last command and stop the motors if no new command arrives within a short limit.

Canonical: https://roboticsengineering.in/fix/robot-keeps-driving-after-signal-lost-failsafe-stop/ | Published: 2026-11-03 | Updated: 2026-11-04

**Stop the motors if no command has arrived for a short time.**

## What the message means

If the last command stays active when the link drops, the robot runs away. Wireless links drop often.

## Fix it in this order

1. Save the time of each received command with millis().
2. In the main loop, compare the time since the last command with a limit such as half a second.
3. Set speed to zero when the limit passes.
4. Send commands repeatedly, not only on change.
5. Add a physical power switch you can reach.
6. Test by switching off the remote while the robot drives.

## Why it happens

If a remote or a Bluetooth link drops, the last command stays in force and the robot keeps driving. A failsafe stops the motors when no valid command has arrived for a short time.

Record the time of every command and stop the motors when too much time has passed. A timeout of a few hundred milliseconds is a common starting point.

```
unsigned long lastCmd = 0;
void onCommand() { lastCmd = millis(); }

void loop() {
  if (millis() - lastCmd > 500) stopMotors();   // your function
}
```

Example sketch: change pins and values for your own wiring. It has not been bench-tested on your hardware.

## If you see this, do this

| You see | Do this |
| --- | --- |
| Robot runs on after disconnect | No timeout. |
| Stops during normal use | Limit too short or commands too rare. |

## Related

[millis timing](https://roboticsengineering.in/fix/arduino-delay-blocks-robot-use-millis/), [WebSocket drops](https://roboticsengineering.in/fix/esp32-websocket-disconnects-after-seconds/).

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

## Why this happens

A robot’s code usually changes its motor command only when a new message arrives. If the message stops, because the radio dropped, the app closed or the link failed, nothing in the code tells the motors to change, so the last command stays active and the robot carries on. Some RC receivers do the same in hardware: by default they may hold the last value, so a failsafe must be set in the receiver itself.

The remedy is a watchdog in software: record the time of each valid command, and in the main loop stop the motors if the age exceeds a limit. It needs to be independent of the message handler, since the handler is exactly what stops running.

## How to confirm the cause

- Lift the wheels off the floor, drive, then switch off the transmitter or move out of range. Record whether the wheels stop and how long that takes.
- Print the age of the last command (`millis() - lastCmd`) every 100 ms. It should stay low while linked and grow when it breaks.
- Check the receiver’s failsafe setting in its manual. Holding last value is a common default.
- Test a pulled power wire on the controller. If outputs go to an undefined state, the motor driver needs a pull-down on the enable pin.
- Check whether blocking code (long delays, waiting for serial) stops the watchdog from running.

## Worked example

A timeout of 300 ms is an example; choose it to be well above the normal message interval.

```
unsigned long lastCmd = 0;
const unsigned long TIMEOUT = 300;   // ms

void onCommand(int speed) {
  setMotors(speed);
  lastCmd = millis();
}

void loop() {
  readRadio();                       // calls onCommand() when data arrives
  if (millis() - lastCmd > TIMEOUT) setMotors(0);
}
```

## Common mistakes

- Setting the timeout shorter than the normal gap between messages, so the robot stutters.
- Putting delay() calls in the loop so the check runs late.
- Resetting the timer on any received byte, including garbage.
- Testing with the wheels on the floor.
- Relying on software alone with no hardware fallback.

## If this did not fix it

- Buffered old data: Bluetooth or serial input that arrives late and looks like fresh commands.
- A hung processor never reaches the check; add a hardware watchdog timer reset.
- Motor driver inputs float when the controller resets; add pull-down resistors.
- The stop only sets speed to zero but leaves a brake or direction pin active.
