New: LED Power / Battery Management New on the FastLED 2.1 branch:

New: LED Power / Battery Management
New on the FastLED 2.1 branch: some power management functions which are not yet integrated into the main FastLED APIs, but which are working and useful, especially for battery-powered projects.

Here’s how it works: you specify the maximum power (in milliamps) that you want your LEDs to draw, and then these new functions will automatically adjust the master brightness control to keep the power consumption (approximately) at or below the maximum that you set. Keep your wearable up and running all night!

These functions are not integrated into the FastLED “API” yet – so using these functions will take a little bit of work! But given how many FastLED projects are heading out to the playa, the land of battery power, I wanted to share this code with everyone sooner rather than later. Our hope is to get it eventually integrated in a way that makes it clean for people who want to use it, and zero-cost for people who don’t. In the meantime, it works and you can try it out.

How To Use It
Grab the latest FastLED v2.1 branch from https://github.com/FastLED/FastLED/archive/FastLED2.1.zip and install it, replacing your old FastLED folder. Now…

In setup(), specify the maximum power you want your project to draw, like this:
set_max_power_in_volts_and_milliamps( 5, 500); //5v 500mA

Now comment out your existing calls to FastLED.show() and replace them with this:
show_at_max_brightness_for_power();

Similarly, replace your old calls to FastLED.delay(ms) with this:
delay_at_max_brightness_for_power( ms);

(I told you the new functions weren’t integrated into the FastLED API, didn’t I? Yeah. They’re not. They’re “wrappers” around FastLED.show() and FastLED.delay() right now.)

Now compile and run your code as usual. Everything should work pretty much as before, but with the brightness automatically managed to keep you within the power envelope you’ve specified.

An interesting way to test this is to set the maximum power draw very low, say 100mA, and then re-run your code. How do you know it’s doing anything? Well, funny you should ask…

LED indicator
The new power management functions have a built-in indicator for when the power draw is being capped: the Arduino’s on-board LED (usually on pin 13). When the power cap kicks in, the on-board LED lights up to let you know. You can change the indicator LED pin number with set_max_power_indicator_LED( pin). Setting it to zero disables the indicator function.

Caveats: The new code currently adds roughly 1K to your code size on AVR, and takes up 5 additional bytes of SRAM. The power computations are approximate. They seem about right, if a tad conservative. The API will change.

I’ve tested this code on a few different AVR and ARM boards, at 12 volts and 5 volts, and with power limits ranging from 50mA to 6,000mA, and so far it all seems to work as intended. It has not been exhaustively tested, but it might be worth a few minutes of your time to experiment with it, especially if you have a battery-powered project. As always, please let us know what you find.

Explore
It’s interesting to take your old animation, in which you’ve limited the master brightness control with setBrightness to a lower value, and instead set the brightness (back) to 255, but set the maximum power draw to something lower, like 100mA or 500mA, or 1000mA, and see what you get. Typically you’ll see more dynamic range in pixel brightness, with no additional peak power draw; the dimmest parts won’t be dimmer, but the brightest parts may be brighter!

Please consider this my ‘playa gift’ to you. Let me know if you try it out, and what you find! I have a million ideas for future directions here, but the basic functions are useful enough that I wanted to share them now.

Personal testimonial: I used these power management functions to run a wearable string of twenty pixels running a nice blinky animation off of a set of three AA alkaline batteries… for 47 hours…

Oh my god. You’re my hero! Well, you were already my hero, but this is off the hook. I can’t wait to play with it.

Awesome work as usual, thanks.

I’ve got this hooked in to my 640-led project now, theoretical maximum draw therefore 640 * 0.06 = 38.4A.

set_max_power_in_volts_and_milliamps(5, 10000);

… on full-white shows me drawing 180W out of the wall (whoops, it’s a 100W PSU :slight_smile:

set_max_power_in_volts_and_milliamps(5, 5000);

… gives me 150W.

set_max_power_in_volts_and_milliamps(5, 3100);

draws about 93W, which is the same as the normal setBrightness(128);

And it seems to go fairly linear from there—1650 gives me a 45W draw, the same as setBrightness(64). Is this expected behaviour? Can I run any diagnostics for you @Mark_Kriegsman ?

Two things. First, I’m going to be all skeptical about the PSU and measurement setup, and then second I’ll dig in and see if we can calibrate this better for you.

First, the poking and proding:
OK, so with a 100W PSU, any power draw at or near the 100W limit is going to be jinky, and any data we collect up there isn’t useful – the PSU itself isn’t going to be anything like linear or efficient. At all. Or to paraphrase that thought: drawing 180W from a 100W power supply isn’t going to give useful data to calibrate with.
As a side note, I also have some questions about the efficiency of the PSU, and how many of the watts going into it as mains AC are coming out of it as 5V DC (versus being exhaled as heat). I take it you’re measuring wattage between the PSU and the wall, vs measuring on the 5V output side of the PSU? Do you have any good way of measuring the actual amps or watts between the PSU and the LEDs?

Also, with such a huge setup (I do love the pictures), at only 5V the power drawn by the first LED on each string will be much higher than the power drawn by the last LED on each string, because of the rather serious voltage drop along the strips when everything is full-on white.

OK, now for part two: let’s do some calibration.
I like that it’s linear in the “sweet spot” of the PSU’s range, where the PSU is supposed to be operating. That gives me some hope.
However, you said that a setting of 1650mA was giving you a maximum of 45W draw. Watts = Amps x Volts, so 1650mA @ 5V should equal a maximum of 82W – putting aside all voltage drop issues and so on, see above. SO that means that what the code thinks will draw 82W is actually only drawing 45W. And that means that the code is being overly conservative (estimating too high) about how many mA each LED is actually using.

Let me ask you to try an experiment: open up power_mgt.cpp in the library, and around lines 17…19 you’ll see some constants for how much power each LED takes. They’re all set to 14mA…16mA, which are values I was seeing when I measured directly – but your mileage is clearly varying! So go in and actually change those values to be, let’s say, 10mA for Red and 9mA for Green and Blue. Now recompile and re-run your sketches … bearing in mind that if we want linear, meaningful data, we have to stay under about 80W, I’d say.

Also, as a side note, you might want to use
set_max_power_in_milliwatts( mW );
if you’re measuring power draw in Watts. Just to keep the numbers all lined up.

Finally, instead of using all-white pixels, which incurs the highest voltage drop along the strips, and subsequent net-falloff-in-power-consumption at the far end, try using a pure, fully saturated hue, e.g., CHSV( anything, 255, 255) and let me know what effect that has.

I suspect we have calibration issues with the constants – but that with 640 pixels at 5V the voltage drop along each strip when they’re full on pure white is playing a significant role too.

Also, you’re roasting your power supply. (You knew that already. :smiley: ) But I’d say that above 80% of the rated power of the PSU, the power-in vs power-out isn’t going to be anything like linear.

Ok, so let me know what you find, and Thanks for helping out!

Wait: lets make this simpler. Don’t use the new code for a moment, and set brightness to 255. What’s the wattage with all pixels blacked out? That’s “total dark current”. Divide by number of pixels, and multiply by 1000 to get dark current in milliwatts.

Now light 100 pixels pure Red. (Best is to spread the lit ones around, not bunch up at the head or tail of the strip.) OK, what’s the wattage now? Subtract out the total dark current, to isolate the “100-pixel Red current” in Watts. Multiply by ten and you should now have the per-pixel Red current in milliwatts – suitable for entering in to the new code as gRed_mW on line 17 of power_mgt.h. Since you’re entering mW, and not mA, don’t forget to delete the “times 5” in there.

Repeat the 100-pixel power measurement for Green and Blue. Bam. Now you should be all calibrated up.

Let me know what readings you get!

Agreed, try to pull 200W out of a 100W PSU and all bets are off. But I will not hear a word against my power bus on this project, I’ve been bitten in the arse by that before and over-engineered this one to hell :-).

Unfortunately my wall meter is as good as I’ve got, I don’t really have the cabling to measure current directly.

But I’ve taken some measurements.

Firstly, setBrightness() off, all 640 pixels on full white: 176W (with 5.03V at the PSU terminals and 4.26V at the far end of the last strip. Voltage drop does not appear to be a problem here.)

All black, (5.03V to 5.01V at the far end): 7.6W

100 Red LEDs
17.6W - 7.6W = 10W/100pixel * 10 = 100mW

100 Green LEDs
12.4W - 7.6W = 4.8W/100pixel * 10 = 48mW

100 Blue LEDs
17.6W - 7.6W = 10W/100pixel * 10 = 100mW

… which is more than your measurements. Colour me surprised.

Nice work on the voltage (non)drop!
So try plugging in your findings:
12mW/px dark energy
100mW/px Red
48mW/px Green
100mW/px Blue

For those who like to think in mA, these numbers are:
dark energy=2.4mA/px,
Red=20mA/px,
Green=9.6mA/px,
Blue=20mA/px.

And again, I’m also wondering what the efficiency of the PSU is; these numbers seem high to me, and yet they are what you measured so we’ll assume that they’re correct – at the point you’re measuring them.

If the PSU is 80% efficient (which appears to be a good, if optimistic, guess), that means that the “real” numbers for your setup are something like: dark=10mW(2mA), Red=80mW(16mA), Green=38mW(8mA), Blue=80mW(16mA). And those numbers look a lot more like the values I originally measured from the WS2811/WS2812/LPD8806s I looked at.

Remind me again what kind of pixels these are?

OK, cool. So if you plug those numbers (12,100,48,100) into power_mgt.cpp, does the configured Watt limit roughly match the measured Watt consumption?

In a word, no, unfortunately.

set_max_power_in_milliwatts(80000);

on full-white shows me 178W at the wall, or thereabouts.

OK. I’ll step through the math to make sure I’m not overflowing somewhere. In the meantime, could you try a handful of lower numbers, like 5 watts, 10, 20, 30, 40, and 50? I’m preparing to make a plotted chart…

Also, another clue (possibly): the Teensy’s LED isn’t lighting up. I haven’t changed it from the default pin 13.

set_max_power_in_milliwatts(70000); = 178W
set_max_power_in_milliwatts(50000); = 176W
set_max_power_in_milliwatts(50000); = 176W
set_max_power_in_milliwatts(40000); = 175W
set_max_power_in_milliwatts(30000); = 138W (this I noticed immediately)
set_max_power_in_milliwatts(20000); = 93W
set_max_power_in_milliwatts(10000); = 46W
set_max_power_in_milliwatts(5000); = 22W

… but still no LED on the teensy, even when I got under 30000.

Thank you very much for the data… and the LED info is helpful… and confusing. I mean… clearly, something is being ratcheted down as you lower the max milliwatts… so I’d expect to see the LED light up… I’m reviewing the code again.

And now I’m going to go actually try this on a teensy. Stay tuned.

I’ve just been trying this on my Teensy 3.1 and can confirm it’s not working… In fact with that 2.1 library downloaded and installed I can’t get FastLED to work at all…

As soon as I switch back to one I cloned from Github it all works though (but without the power management functions)
Edit: actually, seems my problem is something much deeper with moving from 2.0 -> 2.1… I’ll make another post about it separately.

Matt: what symptoms are you seeing? I’m running this on a Teensy 3 right in front of me and it seems basically functional. (I’m working out what’s up with Robert and the power functions now…)

Also, I’m finding that on Teensy, you have to do this explicitly in setup():

pinMode(13, OUTPUT);
set_max_power_indicator_LED( 13);

I’ve just created a new post in the Support area, but as basically switching to 2.1 has totally broken even the Blink example sketch… it lights up the whole strip (solidly) instead of just blinking one LED. Teensy 3.1, LPD8806 with Data on 11, Clock on 12.