Return to Robotics Tutorials

Preventing Runaway Robots - A Watchdog Circuit

So you've spent hours building your robot and you're finally ready to power it up... You haven't perfected the code, but it should be close enough to see it work. You flip the switch and it runs for a while -- until suddenly it takes off at full speed into a wall and crashes into a dozen pieces!

What causes a robot to go out of control?

Nearly every robot has the potential for out-of-control conditions. Generally, the robot wheels are powered by high-current motor controllers that accept RC, serial or analog inputs. If the motor controller observes a bad or locked-up input signal, it can power the motors at arbitrary velocity and potentially persist until the unit is shut down. Depending on the type of robot and environment, this can be a potentially dangerous situation.

Bad input vs Loss of input

A motor controller is designed for a particular range in input values; input outside of this range can lead to unpredictable (or even maximum throttle) behavior! On the other hand, what seems like a safe operating speed for your robot could prove treacherous if it happens to lose signal while driving in motion. Depending on how the motor controller is configured, a loss of input may retain the last input control, leading to continuous drive without being able to stop it.

Loss of control via RC input

With a motor controller configured for operation in RC mode, the controller generally samples a periodic PWM (pulse-width-modulated) signal ranging from 1000us to 2000us in length. This periodic signal repeats with a period of approx 20ms (ie. 50 times per second), closely paralleling what you would use to drive a servo motor. A pulse stream with a 1500us (1.5ms) high time typically causes the motors to stop rotation. Pulses shorter than 1500us lead to greater speeds in one direction, while pulses longer than 1500us lead to greater speeds in the opposite direction.

Consider a robot that is operating by an onboard microcontroller such as a Raspberry Pi or Arduino. To use the motor controller's RC mode, a pair of PWM signal streams need to be generated. Some processors include hardware PWM outputs, but often there are too few or non-existent. The solution is to use an external PWM generator or else bit-banging the PWM ("soft PWM") from the processor. An external PWM generator (such as the PCA9685) is very convenient since it can generate up to 16 PWM outputs, all initiated from an occasional I2C command, freeing up the processor for other tasks. The downside of this convenience is seen if the processor ever locks up and stops issuing new I2C commands. In this scenario, a lack of input to the PWM generator will result in a continuous drive command to the motor controller, leading to a certain crash!

How to fix Runaway Robot Operation

To avoid the runaway situation requires that additional safeguards are put in place to detect unexpected/undesirable behavior/input and then shut down the motors as appropriate. Some people may attempt to implement this detection logic on the main processor, but this is dangerous since a lockup in the main code may also prevent the detection logic from working.

In general, a separate circuit should be integrated, allowing for a backup or redundant detection methodology to operate despite any lockup in the main robot code. In some cases, this monitoring circuit is called a watchdog.

Implement a Watchdog Circuit

After experiencing a few runaway situations with my 4WD rover, it was clear that a watchdog circuit was going to be essential. I identified that my motor controller (RoboClaw) provides a pin input that can be configured as an Emergency Stop. This is a very convenient feature: while the signal is high, the robot can operate as normal, but if the signal is ever dropped low, the robot motors are shut down immediately.

Selecting conditions for emergency stop

To control this E-Stop input, I build a simple watchdog circuit using an ATtiny85 microprocessor that monitors an input pin for transitions. It expects that the input signal (let's call it WDOG) is toggled at least 4 times a second. If it does not observe a change (low-to-high or high-to-low) within 250ms, then an output signal (HALT) is asserted. I can then connect this HALT signal to the motor controller's E-Stop input.

The WDOG input on the ATtiny85 is connected to an output from my microcontroller (Raspberry Pi). This GPIO output is toggled by the main loop very frequently (much faster than 4 Hz), thus keeping the watchdog from timing out and causing an emergency stop. If my main robot code ever encounters a lockup condition (eg. spinning endlessly in a PS2 read loop), the watchdog will shut down the motors automatically.

Robot Watchdog - C Code for Arduino / AVR

I am currently run the following on an ATtiny85, a cheap ($1) 8-bit microcontroller:

// Processor watchdog circuit with Arduino
// by Calvin Hass (
// - Intended to halt a motor controller with emergency stop
//   if the processor locks up.

// Define IO pins - change as desired
#define PIN_WDOG  0 // Input (active high)
#define PIN_LED   1 // Output (active high) [Optional]
#define PIN_HALT  2 // Output (active low)

// Define timeout in milliseconds
#define WDOG_TIMEOUT  250

unsigned        m_nWdogStateLast;
unsigned long   m_nWdogTimeLast;

// Setup code, to run once:
void setup() {
  pinMode(PIN_HALT, OUTPUT); // Halt Motors
  pinMode(PIN_LED,  OUTPUT); // LED
  pinMode(PIN_WDOG, INPUT);  // WDOG

  m_nWdogStateLast = digitalRead(PIN_WDOG);
  // Start off halted
  m_nWdogTimeLast = 0;


// Main code, to run repeatedly:

void loop() {
  unsigned      nWdogStateCur;
  unsigned long nWdogTimeCur;

  nWdogStateCur = digitalRead(PIN_WDOG);
  nWdogTimeCur = millis();

  if (m_nWdogStateLast == 0) {
    // Was low, look for rising edge
    if (nWdogStateCur == 1) {
      // Reset watchdog & flip state
      m_nWdogStateLast = 1;
      m_nWdogTimeLast = nWdogTimeCur;
    } // nWdogStateCur
  } else {
    // Was high, look for falling edge
    if (nWdogStateCur == 0) {
      // Reset watchdog & flip state
      m_nWdogStateLast = 0;
      m_nWdogTimeLast = nWdogTimeCur;
    } // wDogStateCur

  // Did the watchdog timeout?
  // TODO: Handle wrap condition
  if ((nWdogTimeCur - m_nWdogTimeLast) >= WDOG_TIMEOUT) {
    // Timeout - Turn on HALT
  } else {
    // No timeout - Disable HALT


Reader's Comments:

Please leave your comments or suggestions below!


Leave a comment or suggestion for this page:

(Never Shown - Optional)