Mike Is Making Stuff sticker

Heartbeat Failsafe Timing for ESP-NOW Controllers

By Mike · Published October 6, 2026 · Updated October 9, 2026

ESP-NOW makes ESP32 boards talk to each other directly, fast, and without a router, which makes it ideal for remote control: a handheld controller sending commands to a robot, a light rig, or a piece of machinery. But wireless links drop, controllers run out of range, and batteries die, and a remote system that keeps executing its last command after the link dies is a hazard. A heartbeat failsafe fixes this: the controller sends a regular "I'm alive" signal, and if the receiver misses too many heartbeats, it shuts the system down safely.

Heartbeat Failsafe Timing for ESP-NOW Controllers

Why the failsafe has to be in the receiver

It is tempting to put the safety logic in the controller, but the controller is the thing that disappears. The receiver is the device attached to the motors, the relays, the moving parts, so the receiver is where the decision to stop must live. The receiver's rule is simple: commands are only valid while heartbeats keep arriving. No heartbeat, no motion. This design fails safe by default, because every failure mode, dead controller, lost link, crashed receiver firmware, results in the same thing: silence, which the receiver interprets as stop.

This also means the failsafe must not depend on any single message getting through. Wireless links lose packets routinely, so one missed heartbeat cannot mean shutdown or the system would stutter constantly. The failsafe triggers on consecutive missed heartbeats, a count you choose based on the heartbeat rate and the system's tolerance for delay.

Choosing the heartbeat interval

The heartbeat interval sets how quickly the receiver notices a dead link. Send a heartbeat every 100 milliseconds and the receiver can detect a failure within a few hundred milliseconds; send one every second and detection takes seconds. Faster heartbeats mean faster failsafe response but more radio traffic and more power consumption, which matters for battery-powered controllers.

Match the interval to the hazard. A slow-moving camera slider can tolerate a second of undetected link loss; a fast robot or anything with spinning cutters cannot. A common working point is a heartbeat every 100 to 250 milliseconds, which keeps the radio overhead modest while detecting failures well under a second. Whatever interval you choose, make it a named constant in the code, not a magic number, because you will tune it.

Setting the missed-beat threshold

The threshold is how many consecutive heartbeats can go missing before the failsafe trips. Too low, and normal packet loss causes nuisance shutdowns; too high, and a genuinely dead controller keeps the system running too long. Three to five missed beats is a practical starting range: at a 100-millisecond heartbeat, that means the failsafe trips after 300 to 500 milliseconds of silence, which rides through typical brief dropouts while still stopping quickly on a real failure.

Implement the check with timestamps, not counters alone. Record the time of the last received heartbeat, and in the main loop compare the current time against it. If the gap exceeds the threshold, trigger the failsafe. Timestamp comparison handles the case where the receiver's loop timing varies, and it makes the failsafe logic independent of how often the loop runs.

What the failsafe state does

Tripping the failsafe must put the system into a defined safe state, and that state depends on the machine. For a robot, it usually means stopping all motors, possibly with a controlled deceleration rather than an abrupt halt if momentum is a factor. For a relay-driven system, it means opening the relays to de-energize the loads. Define the safe state explicitly in the code as a function, and call it from the failsafe check, from the startup sequence, and from any error handler, so every path to safety goes through the same well-tested routine.

The system should stay in the failsafe state until it is deliberately reset, not resume automatically when heartbeats return. Automatic resumption after a dropout can cause unexpected motion if the operator has walked away or is handling the machine. Require a deliberate re-arm, a button press or a specific command sequence, before motion resumes.

Testing the failsafe honestly

Test by killing the controller mid-operation: power it off, walk it out of range, shield it. The receiver must stop the system within the designed time, every time. Test repeatedly, because a failsafe that works nine times out of ten is not a failsafe. Also test the edge cases: controller rebooting and rejoining, heartbeats arriving out of order, the receiver rebooting while the controller is transmitting.

A remote control system without a heartbeat failsafe is a remote control system waiting for its first accident. Build the heartbeat in from the start, tune the timing to the hazard, and test it like you mean it.

Related Guides

← Back to Resources