U4eake's showleds, arming and low battery warning leds

Following up on the success of my relay low battery warning leds I have expanded that code to include a complete lightshow and to be compatible with the newest ACM codes (2.1.1) and the APM1 hardware.  APM2 hardware MAY work, but I don't have APM2 at this time, so no guarantees.

Credits to Bill Sanford and Max Levine whose work has been an inspiration and a basis for these leds.


1) Software side :

By using the agmatthews userhooks it is now much simpler to upgrade to a new firmware without having to change the code each time.  You just have to copy 2 files and change setting in the APM_config.h.  The needed files AND my config.h file (for version 2.1.1r5) are in the following file : U4eake_showleds.zip 

Updated files for ArduCopter 2.5 (compile with arduino1.0 relax patch) : u4-showleds.zip  These still work for ArduCopter 2.5.3.

Update files for ArduCopter 2.6 : Showleds_ACM2.6.zip  Because motors were put in a library, every motor_armed in the showleds code had to be modified to motors.armed().  Also you have to put

#define COPTER_LEDS 0

into your APM_Config.h file to disable the new copterleds, which are enabled by default.

You need to copy the usercode.pde and the usercode.h files into your arducopter directory (overwriting the files already there) and add the settings below to your APM_config.h.  DO NOT just copy my APM_config.h, it is only included as an example to clarify the settings.

#define MOTOR_LEDS 0                                   // 0 = off, 1 = on
#define SHOW_LEDS 1                                    // set to 1 to enable AN7-AN15 controlled led lightshow
#define RELAY_LEDS 0                                    // set to 1 to use the old relay led low battery warning

#define COPTER_LEDS 0


#define LOW_VOLTAGE 9.9
#define MID_VOLTAGE 10.6
#define VOLT_DIV_RATIO 3.33

#define INPUT_VOLTAGE 5.26

Also uncomment the 50hz agmatthews userhook and the mediumloop userhook (remove the // in front of it) so it looks like this :

#define USERHOOK_50HZLOOP userhook_50Hz();

#define USERHOOK_MEDIUMLOOP userhook_MediumLoop();


The voltages can be adjusted to match your desires.  If you have a 4S battery for example, you should put higher values, like 13.2V for the LOW_VOLTAGE.  INPUT_VOLTAGE is the voltage that goes into the APM (usually the voltage from you ubec).  VOLT_DIV_RATIO is an calibration value that you can adjust so that your reported battery voltage corresponds to the real battery voltage.


After compiling the code with arduino and uploading it to the APM board, you also need to set battery monitoring to option 3 : battery volts



That's it for the software modifications if you have a hexa or are happy with the patterns as they are !  On a quad or octo you may want to adjust the patterns a bit, but I'll explain that further down this blog (see Adjusting Patterns).


The code and blink patterns are optimised for use on my hexa (6 leds strips on the arms + 2 spare ones).  

The leds will go on when motors are armed and out when disarmed.  During flight, different flashing patterns can be selected with Ch7. The other use of Ch7 is not affected, so you can still use it for simple or recording waypoints. The leds will flash with the last pattern in this file when ch7 is high (recording waypoint or simple)
When battery gets below the first threshold (MID_VOLTAGE = 10.6V), the ledshow is overridden and the leds will flash with following pattern : led 1,3,5 on/off and led 2,4,6 off/on. So if the first ones are off, the others are on and vice versa.
When second threshold (LOW_VOLTAGE)is reached (9.9V) the leds will flash quicker.


2) Hardware :

The code uses the AN8 tot AN15 analog ports (portK) on the oilpan of APM1.  In the picture you can see them labelled  AN0-AN15.  AN8 to AN15 are the ones on the right (4x2 pins)



You can either connect 1 led directly to each port (the ports can supply 40mA current) or you can use a ULN2803 darlington transistor chip to drive the leds according to the following shedule (thx to Max Levine for this schematic) :


This shedule is for a quad and uses a ULN2003.  The ULN2803 has 8 ports instead of 7 and if I remember correctly it can supply a little more currrent (500mA per port).  A typical hobbyking 12V ledstrip of 1m (60 leds) consumes about 300mA, so normally you should be able to hang 1m of ledstrip on each of the 8 ports.  That should be plenty !!

You can get the ULN2803 in your local electronics shop or online here : Canadadrones - ULN2803

The darlington chip lets each input control the output directly across on the other side of the chip.  So nr1 in the picture above, controls output 16,   Nr 2 controls output 15 and so on.  If you look at the pinout picture of the oilpan, you'll see that nr 1 is connected to AN8 and nr2 is connected to AN10, so AN8 in the pictures above controls the red leds, and AN10 controls the green leds.  Get it ? ;-)


After the brainsurgery it will look something like this :


Now you just have to put a heatshrink over the ULN2803 chip and tuck all the wires away nicely.

CAREFULL : in the picture above I had soldered the wires to the wrong ports (side of the compass).  That's what you get when working on your copter till 4 in the morning...  It took me a day to figure out why my leds didn't work as expected.  So you have to solder your wires on the OTHER SIDE (side of the usb connector).  I didn't have a picture of when I soldered it right.

Finally you'll also have to set up your board for battery monitoring (option 3 : total voltage) by soldering the voltage dividers and connecting battery voltage to AN0, which is explained in the wiki here :  Voltage sensors on APM1


3) Adjusting the blinking patterns

First you'll have to understand a little about bitmath in arduino : http://www.arduino.cc/playground/Code/BitMath

To save processor cycles I've opted to drive the portK of the atmega1280 using direct portmanipulation. 

If the above all sounds too complicated : here's the simple explanation.

In the usercode you'll often find something like PORTK = B00101010;  This instruction actually turns leds on and off.  0 means off and 1 means on.  Each number turns 1 port off or on, and the first number after B turns port AN15 on. So the ports are B-AN15-AN14-AN13-AN12-AN11-AN10-AN9-AN8 of shorter written : BAN15...AN8

If you would now like to turn the red leds on and the others off in the picture above, this would be PORTK = B00000001; (turns AN8 on, and AN8 is connect to nr1 on the darlington, which turns on red leds)

If you wanna turn the 2 blue ledstrips on and the others off it would be PORTK = B01010000; (ports AN12 and AN14 on, which are connect through the darlington to blue leds)

All 4 strips on would be PortK = B01010101;

Ofcourse for hexa's and octo's this depends on which AN port you have soldered to which nr on the ULN2803.


Now we can turn leds on and off, but they still don't blink or "rotate".  For the blinking a counter is used and depending on the counter, leds are switched on and off.  The counter runs in the 10hz or 50hz loop, so you can time the blinking.  If counter =5 when in the 10hz loop will correspond to half a second.  

For "rotating" arms I use the bitmath again, more precisely the bitshift operators << and >>.  These simple shift all bit a few places.  so 00000001 << 1 becomes 00000010.  The 1 shifts 1 place.  By now you understood that this is an easy way to make the leds "rotate".  Just shift the B00000001 1 place each loop cycle and your 'on' leds will shift an arm each cycle, making them look asif they rotate.


4) TO DO

On the 8 port ULN2803 there are still 2 ports left unused on my hexa.  I'm planning to use those to replicate the gps status light and maybe a failsafe warning light.  I've also thought about using them to drive leds in the form of a smiley :-)  Other ideas are always welcome !


I'm using the relay now to ignite fireworks on the hexa.  But that's a story for another blog ;-)


That's about all I can think of telling you, and by now my fingers are tired and my brain is mushy.

I hope you enjoy these leds and don't scare too many people with your new UFO ;-)  Feel free to ask questions in the comments below if something is not clear.

Ow, and ofcourse I assume that you know what you're doing if you solder on your board.  I take NO responsability if something goes wrong and you break it !  Do this at your own risk ! 





E-mail me when people leave their comments –

You need to be a member of diydrones to add comments!

Join diydrones


  • Thanks for the insight u4! Rob also seemed to point at the fast loop as a worry even with direct access. So, I am going to try it with all direct access and no 50hz stuff. I have already rewritten somewhat extensive changes to your LED show code. The throttle varied stuff is now done at 10hz, and I added GPS status to the mix. The GPS stuff required me to put get rid of "showleds()" and move it inside the main 10hz loop (still a #if). There are probably better ways, but I'm not much of a programmer. I also took liberty to refit some of your flashing patterns for a quad, and I brewed up some of my own patterns too, since there are so many slots to fill ;).

    I'll report back after testing; going to take some time to verify AC3 looptimes aren't taking a hit in auto modes. I'm keeping optimistic about direct access and no 50hz... fingers crossed.

  • 100KM

    The direct port manipulations I use in showleds uses VERY little cpu resources.  They are set in 1 or 2 clockcycles.  the if-then statements also use only a few clockcycles, which is neglectable compared to the other stuff the processor has to do.  Furthermore there is only 1 option (fast rotating arms) that uses the 50Hz loop (you could comment that one out), all the others only use the 10hz loop.  

    So I think it is UNlikely that there will be timing problems, but ofc the devs wanna play it safe and not get any complaints about strange issues.

    It is true that copterLEDs used to cause some timingproblems, but that was because it doesn't use direct port manipulation, it uses DigitalWrite() to set the ports, which is a function that consumes rather a lot of processorcycles, because it does a some checks to ensure compatibility with all arduino boards.

  • u4,

    Thanks for the response. I was informed by the devs that there is likely to be problems with looptime if I were to do the LED show with AC3. So the recommended method is to just use a JDrone's IO board. Too bad, because I think with a few ANDs to filter those 3 sensor ports, I could have done it quick and easy. I will have to take another look at this when I get a PIX board; I'm sure it will have enough extra power to handle it.


  • 100KM

    Hi Kevin,

    Sounds like your well on your way.  I too have recently assembled me a AC3.0 quad and I'll probably put some leds on it soon.  That may get me interested in porting my code to AC3.

    Anyway, what you're saying makes sense.  

    First I would make sure that the AN0-8 are really connected to portF by changing 1 of them in the 1hz loop for example and connecting a single led and resistor to it. 

    Now if I recall correctly, I once forgot to do the DDRK=11111111 statement and the whole ledshow didn't work, (leds only went on VERY faintly) cause the ports were not configured as output..  I believe configuring a port as output just turns the internal pull-up resistor off, so the port can supply some power (40mA per port, 200mA max in total).  It means you probably won't damage anything if the ports stay configured as inputs (if you shortcircuit a port that's configured as output, you may burn it) , BUT they probably will affect measurments of any attached sensors.  So just leaving the pins configured as inputs probably won't do it.

    However, there is a bitmath trick to only change certain ports and leave the rest in the state they were in. It was something with the AND and XOR operators or something.  Check the bitmath part on the arduino website, it was explained there how to do it, but I didn't bother getting to the bottom of it for my code cause I didn't need it. (nothing else attached to portK on my old APM1.)

  • u4, I have AC3 leds working on my APM2.5 quad, but you know... boring. So I am using AN0-2 for V, A, and RSSI, and wanted to control the light show with just AN4-8. I've looked in to porting your light show over to APM2.5, but being a newb I figure I should ask the boss first.

    I planned on just copying your code, and making the following changes:

    1) "DDRK=11111111" to "DDRF=11110000"

    2) Change all "PORTK=..." to PORTF=..."

    3) Change some of the bitmasks here and there (obviously hex patterns won't adapt easily) to work with a quadcopter... for example PORTK=00001111 changed to PORTF=11110000.

    I am worried that this is not going to work as planned for many reasons. As is, I am concerned how some of the patterns will behave. For example rotating arms changes the X's in PORTF=1010XXXX... maybe that can change for example my RSSI to an output? I was hoping by leaving the last 4 bits 0 in the DDRF statement, the user code will not have any affect on V/A/RSSI measurement.

    Your code is too cool to be left behind. I think it would be great to see this carry on with AC3/APM2.

    Thanks in advance,


  • Greetings U4,

    I've got AC3 leds working on my APM2.5, but they lack pizzazz. So I have been looking in to porting your code for 2.5 quads. I'm not a talented programmer, but sometimes I get lucky; so I am full of wanton ideas. Usually I just try them out, but in this case I'm afraid I'll fry my APM2.5. I researched the subject high and low, and came up with the following.

    On APM2, AN0-8 are (based on others posts) connected to portF. I am measuring voltage, current and RSSI signals with AN0-2. I only need to control 4 sets of LEDs; so I figured AN4-8 would work. I went through your 2.6 code and changed "DDRK=111111111" to "DDRF=11110000"... do I sound confused yet? (hope not) I also changed all the "PORTK =" to "PORTF =". Sound good, yes/no? I am worried my sensors on AN0-2 may cause problems, since for example rotating LEDs goes through PORTF=1010XXXX; I'm worried switching those X's will mess things up, but maybe leaving the DDRF=11110000 means the user hook will not affect the normal function of AN0-3 (aka prtF0-3)?

    I apologize for puking up my confusions on your page. I wouldn't be surprised if there is something fundamentally wrong with my approach, but I'm not enough of a programmer to know. So I figured I should ask the boss. If my plan sounds sane, I'll go ahead and test it. However stop me now if I'm about to do something that will require hot air to fix.

    BTW, like most, I don't care about risking the ULN chip since I have 9 more on hand.

    Thanks in advance,


  • To save some time to collect components and solder you can buy it here. Plug & Play.


  • Works great for GPS, ARM & Buzz(arm). In fact I have only sat LED option to "107" and no compiling at all.
    Running v3.0.1 on APM2.5.2

  • Has anyone been able to get this working with the latest AC3.0 firmware?  I get a compile error... :-(

  • Thank you Gustavo! I will try :) Regards from Greece!

This reply was deleted.