Low-battery death spiral
(Or “How I learned to stop worrying and love the brown-out reset.”)
TL;DR = You should think about what you want to happen when your project’s batteries run way down; you can use an EEPROM flag to help detect when you’re hitting a “brown-out” like this.
Electronics need a certain minimum voltage to operate correctly. If the voltage drops too low (a “brown out”), they start behaving completely randomly, which can be bad. Think about a garage door controller starting to operate completely randomly. Yeah. Bad. So most microcontrollers (like Arduino) have a brown-out detector, and they automatically reset themselves if the voltage gets too low.
So suppose you have an electronics project, like my #ExcellentBirds project, which sits there ‘ready’ for a while using less power, and then does something that uses more power. This is a pretty common pattern of interactivity: wait for event, react to event.
The thing is: reacting to the event (in my case, having the Birds start playing MP3 of birdsong) uses more power than just sitting there and waiting, and drawing more current like that causes a voltage drop.
So what happens as the batteries approach the end of their useful life is this: sitting and waiting for something to happen, they are putting out “enough” voltage and all is well. But when they start playing birdsong MP3, that takes more power, and the voltage drops… below the brown-out level. This causes the brown-out detector to kick in, and the whole circuit to suddenly reset.
Of course, once it’s reset, and no longer playing an MP3, the voltage recovers, and everything is fine… until it tries playing an MP3 again. And then it browns-out and stops abruptly in the middle of the audio, etc., etc., Lather. Rinse. Repeat.
What to do about it?
I think the key to working with this situation is detecting that it is happening, which is tricky because when the Arduino is reset, it forgets almost everything. However, there is one part of the Arduino memory which persists: EEPROM. Values in EEPROM persist across reboots and resets and brown-outs.
So, here’s the pattern for detecting that you’ve browned-out due to overexertion:
-
BEFORE your code does something that’s going to draw substantially more power, store a value in EEPROM which means “I’m doing that thing!” (e.g. “I’m playing an MP3!”)
-
AFTER successfully completing the higher-power activity, replace that EEPROM value with a different one which means “I’m not doing that thing.” (“I finished playing the MP3”.)
-
In your setup() function, CHECK the EEPROM flag. If it says “I’m doing that thing!” it means that (for some reason) the program was reset while it was ‘doing that thing.’ And in this case, you can use that to infer that you probably had a brown-out/reset!
If you did have a brown-out, now you have to decide what to do about it: just sit there and blink “S-O-S” on the Arduino LED? Try doing the high-power operation again, but at a reduced intensity? (e.g., quieter MP3 playback or dimmer LED animation or raise the garage door more slowly)
In my case, I don’t want the birdsong MP3 to play and then be cut off and then play again, so what I do when I’ve detected brown-out/reset is drop into a ‘fail safe’ mode, which blinks out a “please change my batteries” signal, but does not try bursting into MP3 song again until it’s been manually reset.
If I were making a battery-powered LED animation, I’d probably try cutting the maximum brightness in half, and trying again: better to have dimmer blinkies than none.
So in summary: you should think about what you want to happen when your project has a brown-out, and you can use an EEPROM flag to help detect it. After that, it’s up to you to decide what to do about it.
