Add an awesome set of LED lights to your car or truck with this project! Includes fully animated indicator lights, automatic dimming and more!
Daytime Running Lights, or DRL for short, are being added to more and more modern cars, usually in the form of an LED array that remains constantly illuminated. Their purpose isn’t to allow the driver to see, so much as to be seen. Most are automatic and don’t need the driver to switch on the headlights.
This begs the question, why build our own? There are many aftermarket options online that can be hooked up in an hour or two to most cars. We wanted something more robust and customisable, so that it can be programmed for all types of applications and vehicle setups.
The important thing to realise is that our circuits in this project can be used in many different setups. If you have some high-current application needed for lighting, this circuit can be adapted to suit your needs. It’s a boilerplate setup that can be built for almost any vehicle or DIY electronics lighting project in general.
There are a few reasons we wanted to look into designing our own. Many cars have retrofitting kits for modern LED lights, but many are poor quality and have cheap chrome plastic. Additionally, they have some pretty horrible light animations and can have jarring flicker too. And finally, we wanted to show off the process of designing a high-current LED driver - because it’s fun!
The Prototype - Constant Current Driver
We’re dealing with some pretty bright LEDs in this project and, unfortunately, power doesn’t come for free! We need to make sure we’re driving these LEDs in the correct way. But, before that, let’s get back to basics to understand the fundamentals.
The first circuit most people make with an Arduino is usually lighting up an LED. In this circuit, we usually add a resistor to limit the current.
LEDs have a current they are capable of running continuously at. For most small 3mm or 5mm LEDs, that is usually around the 20mA mark, which Arduinos can happily output. The resistor value is typically chosen to approximate this current limit.
Every LED has a ‘forward voltage’ which dictates how much voltage ‘drops’ across it when running. If we feed 5V into the positive side of the LED, the negative side is equal to 5V, minus the forward voltage.
If we have a red LED, which usually has a forward voltage of around 1.8V, we know that the voltage on the negative side is around 3.2V. Using a basic application of Ohm’s law, we can calculate what resistor value we need:
So, we can use a 160Ω resistor for correctly limiting the current in this circuit. With small LEDs like this one, this is a perfectly acceptable approach that can be used for all sorts of applications.
Why can’t we use this approach with more power-hungry LEDs? Just calculate the correct value resistor and use that to limit the current, right? Unfortunately, this method of current-limiting relies on the forward voltage of the LED staying constant. As a high-power LED heats up, its forward voltage drops substantially. If the forward voltage of the LED drops, the current increases through the circuit thanks to the current-limiting resistor conducting more. And, guess what happens when more current flows through an already hot LED? Yep, that’s correct - more heat!
Needless to say, this is bad. It’s called thermal runaway and can occur in a few different areas in electronics in many different ways. It’s a very easy way to kill components that would otherwise last tens of thousands of hours.
The only way to keep the current constant in this circuit is to - well, feed a constant current into it! No matter what the forward voltage of the LED is, our ideal circuit should change its own voltage to keep the current the same. There are many different approaches to building a constant current driver circuit, ranging from just using a laboratory power supply with a resistor to full-blown dedicated ICs that can manage it all for you.
We opted for a transistor-driven current limiting circuit as below.
Transistors can be a mystifying topic for many, especially those that come from software backgrounds, where most things are dealt with by saying something is “ON” or “OFF”. Electrons, silicon and diodes can be frustrating and difficult to work with, but with a little bit of thinking, this is fundamentally a very logical circuit.
Instead of just letting the resistor limit the current, we’re also using a transistor to reduce the current draw of the LEDs. The first critical component of this circuit is the current flowing into the base on the left side. We do this by first setting a voltage there - which we used two 2kΩ resistors for. If we feed 5V into the circuit with an Arduino, this would normally equal 2.5V at the base since these two resistors act as a voltage divider. There are also many circuit diagrams online that use clamping diodes or even LEDs to set this voltage too.
How much current a transistor lets through its Collector-Emitter path - i.e. where the LED current needs to flow - is directly proportional to its Base-Emitter path. We know there is roughly a 0.7V drop across the Base and Emitter, which applies to most general purpose small-signal silicon bipolar transistors. Given this, the remaining base-emitter voltage after the 0.7V drop comes off the 2.5V flowing from base to ground can be used to regulate the current with a resistor. This is quite a small value, but whatever value we choose will directly affect the current draw of the LEDs.
Why is this approach better than just using a single resistor? Let’s say, for instance, the LEDs heat up, and the forward voltage drop across it changes, causing more current to flow. As the current flows out of the emitter and across the resistor, it will increase the voltage drop across it too. This then decreases the voltage between the base and emitter, as the difference between the voltage at the emitter, which has risen due to the resistor, is now less because the voltage at the base is still fixed by the voltage divider resistors. The lower voltage difference also means a reduced current, which partially turns off the transistor, reducing the current flowing in its collector-emitter path, which reduces the LED current. In this way, the system acts as a self-sustaining feedback loop.
This circuit isn’t perfect. It’s possible to improve on the performance of this circuit by adding more transistors to ‘smooth out’ the constant current driver, but this gets complicated and space-consuming, increases the build complexity, and does not provide a big enough improvement to justify that for this case.
To check that everything we’re doing is running as we expect it to, we ran a simulation in the classic software LTspice. If you haven’t heard of it before, you’re missing out. When we first opened the software, it was confusing and antiquated in terms of its keyboard shortcuts, UI and general usage. However, after a bit of practice using the software, it becomes incredibly intuitive and has some extremely powerful simulation features.
We wanted to test our constant current LED driver and ensure that the resistor values we picked were appropriate.
To do this, we first built up the circuit in LTspice. While a few of the components we planned to use in the software were present in the software, many weren’t - and so we either had to source some online libraries to model the parts, or use close approximations.
We can then use a SPICE directive to tell the software what to simulate. In our case, we wanted to check how the driver responds to different battery voltages. Do the LEDs begin to draw more current? How much power does the transistor dissipate?
We entered this as a simulation command:
.dc V1 0 16 0.01
This just tells LTspice to do a ‘DC Sweep’ of the voltage source V1 (our battery source) from 0V to 16V, simulating the circuit every 0.01V. Essentially, it tests the circuit with 1600 different voltages (0.00V, 0.01V, 0.02V and so forth) and plots the results on a graph.
After simulating, we can click on any node in the circuit to see the voltage at that point.
You can see how the voltage drop increases across the resistor as the battery voltage increases.
Let’s check the current through the LEDs by clicking directly on the LED component.
Great, we seem to be maintaining a relatively constant 150-160mA when operating at anything over 10V! One last thing, let’s check how much power our transistor is dissipating. Because it’s acting as a current sink, it’ll be generating a fair amount of heat depending on the load.
We can find the power draw of an individual component by Alt-clicking on it, which we did with our BD139 transistor:
Phew, good thing we checked! At 14.4V - the voltage at which most car alternators run close to - the transistor dissipates close to a full watt of power. These BD139’s are rated for 1.25W of power, however, any less and we’d run into serious issues. The classic BC547 transistor included in many Arduino kits would overheat very quickly!
This LTspice simulation also lets us verify a few other things too, including the current drawn from our Arduino (2.15mA per LED driver), the voltage drop across key components and the effect of the logic voltage on the LED drivers.
Let’s build the fundamental version of our circuit to test if everything is working!
We built this test circuit on a small breadboard with basic components. We first added a potentiometer to let us test different bias values for the transistor.
Before trying the BD139, we also tried some other transistors we had on hand - in this case, a BC337 - to test the heat dissipation. Initially, we tried to run four LEDs but found that the voltage drop wasn’t enough to supply the transistor and allow it to effectively control the current.
After some further experimentation, swapping to the BD139, and reducing the number of series LEDs per driver to three, we were happy with its performance. We managed to get the LEDs running at 145mA to 150mA, roughly in line with the LTspice simulations.
The camera does not give justice with regard to how bright these LEDs are. During testing, we had to cover them with duct tape because even looking in the general direction was painful. And, this was only three! In our final build, we ended up using 18 per light! We’ll definitely need to ensure we aren’t dazzling drivers with these.
We let the driver run for a few hours to test thermal drift, and we observed the milliamps drawn creeping up by around 1-2mA per hour. However, this quickly returned to normal after letting the LEDs cool for a minute or two. This is more than acceptable for the long-life use of these LEDs.
We also want to include an indicator in our DRLs, which will illuminate amber whenever the car’s indicators are turned on. We want to take it one step further than just being a static strip, though. Many new cars will include sequential indicators, which fill up like a progress bar whenever the indicators are turned on. They’re eye-catching as well as being easy to see and very modern.
There are a variety of ways to do this with electronics, however, we decided to go with a slightly different, unconventional approach. We’ve all heard of the extremely popular NeoPixel LEDs, which run on the WS2812B chip. However, we discovered recently that it’s actually possible to source the chip that internally drives the LEDs, without any of the LEDs! It’s called the WS2811, and various suppliers here in Australia sell them - they are a little harder to find than the standard LED strips, though.
Why would this be useful? Because the WS2811 chips break the Red, Green and Blue LEDs out to individual wires, we can wire any LEDs we want to them! If we connect amber LEDs (in the case of vehicle indicators) to the outputs, we can control three LEDs with just one wire, including full PWM control! To control, say, thirty LEDs at once, we only need 10 WS2811 chips and one Data wire!
There are other solutions to controlling LEDs at once, however, they are much more complex. We could, for example, use a full PWM LED driver chip for each LED, but this would require many wires to connect and would be a soldering nightmare. We could even multiplex LEDs, however, this would significantly reduce brightness and introduce a lot of flickering.
The downside of this method is that code becomes somewhat complicated, requiring some careful bit manipulation to get the LED sequence harder. We’re also using PWM to our advantage to add in “fill fading”, where LEDs will fade in as the strip lights up. It’s a small change, but with many LEDs and slower speeds, the “progress” bar effect is significantly improved.
We tested our indicator circuit by first soldering some wires directly onto the WS2811 chips. These are very finicky chips, so don’t bend the legs! If you have access to a breakout board to solder the chips onto, we suggest using that instead.
We then placed it into a breadboard and added our amber LEDs onto the R, G and B outputs after joining the board to our previous driver board.
By pairing it with an Arduino Uno, we wrote a preliminary sketch that detects when an indicator signal is detected. Once it is, it turns off the white DRL lights, and starts animating the indicator ‘strip’ - or three LEDs in our case. When the indicator signal is no longer present, it turns back on the main white DRLs. We have more detail about how this works in our code section.
Great, we’ve tested everything, so let’s put together our final build!
The Main Build:
|60x 4.8mm Superbright Amber LEDs||LEDsales: 4.8mmAMBERLED||Z1068||-|
|36x 8mm 0.5W White LEDs||LEDsales: 0.5W_CW_8MM||Z6372||SS102010268|
|12x BD139 Power Transistor||ZT2189||Z1645||-|
|1x Arduino Nano||XC4414||R0565||DF-FIT0119|
|20x WS2811 IC||Little Bird Electronics: AF-1378||R0704||DF-FIT0119|
|3x 4N25/4N28 Optocouplers||ZD1928||R0545||DF-FIT0119|
|24x 2kΩ Resistors*||RR0579||R0582||DF-FIT0119|
|12x 5.6Ω Resistors*||RR0590||W2370||-|
|3x 300Ω Resistors*||RR0559||W2341||-|
|3x 10kΩ Resistors*||RR0596||S6037||-|
|60x 4.8mm Superbright Amber LEDs||LEDsales: 4.8mmAMBERLED|
|36x 8mm 0.5W White LEDs||LEDsales: 0.5W_CW_8MM|
|12x BD139 Power Transistor||ZT2189|
|1x Arduino Nano||XC4414|
|20x WS2811 IC||Little Bird Electronics: AF-1378|
|3x 4N25/4N28 Optocouplers||ZD1928|
|24x 2kΩ Resistors*||RR0579|
|12x 5.6Ω Resistors*||RR0590|
|3x 300Ω Resistors*||RR0559|
|3x 10kΩ Resistors*||RR0596|
* Quantity Required, May be sold in packs ^ The appropriate type should be picked for your vehicle.
Let’s dig into the main build! But first, let’s look into how our lights will operate from a broader viewpoint. To simplify the coding and electronics, we opted to control both sets of lights from one Arduino. This would remove the need to have two Arduinos, one for each light.
The Arduino Nano we’re choosing to use for this project is physically separated from both lights, and can be mounted separately. It monitors when the car turns on, when indicators are used, and, optionally, if headlights are enabled for a dimming function.
This also opens up an opportunity to connect more lights and accessories to our system. Perhaps a GPS tracker or remote engine immobiliser if that’s your thing?
The outside world is a nasty place, unfortunately. When exposed to rain, dust and mud, electronics tend to corrode, short-circuit and cause all sorts of havoc.
There are a variety of ways of prolonging the life of this project, starting with choosing a good material to build the LED enclosures out of. 3D Printing is the easiest choice, and the one we went with.
It’s really important to consider what type of plastic to use if you’re going this route. Standard PLA will quickly melt and degrade in direct sunlight, and is not fully watertight (although with careful design, it can be close). Carbon fibre, nylon or polycarbonate, as we experimented with, are great options to try.
While our experiments with polycarbonate did work, they were very messy and we need to invest more time, practice, and material into getting PC or nylon printing well.
However, there are many other options to consider instead of, or in addition to, good ol’ 3D printing. You may consider potting your project in epoxy resin, which both insulates and protects electronics from water and vibration-based short-circuits.
You could also invest in a PCB to further clean up this circuit and provide additional protection. We recommend looking into an aluminium PCB for a high grade of protection - together with potting, conformal coating and/or a waterproof enclosure. This would put it on par with a commercial light system!
We ended up building this project in standard PLA, which is not perfect but prints very reliably. It's fine for a prototype. We modelled a few parts in Fusion 360, which are designed for a big strip of LEDs on both sides.
Each enclosure unit comes with slots for a 4.8mm or 5mm LED and a 8mm LED, all of which should be press-fit. We spent a few design iterations tuning the leg sizes so the friction alone should hold in the LEDs. There are 30 indicator LEDs and 18 white LEDs for the DRLs themselves. We had to go through a few design iterations before we found something that worked.
Optionally, you can spray paint your DRL enclosures for more protection against the elements. We were doing this anyway, as we ran out of black PLA and had to print it in yellow PLA. We added two layers of primer coat, followed by a few layers of black coat. The longer you let it dry, the better chance it’ll hold onto the surface!
Let’s solder in our Amber LEDs for the indicators. We’re using wide-angle Super Bright Amber LEDs for this, which, although they don’t have a ludicrous lux output, they can be seen from a distance and are easy to work with.
Because we don’t have a dedicated circuit board for this, we need to solder things in situ. This is another reason why we recommend potting this project when you’re finished - it’ll decrease the chance that something breaks due to vibration or stress.
To begin with, we glued our WS2811 chips upside-down in the dedicated slots. They should pop into the slots and stay there once the glue dries. Be aware that many forms of super glue (or gorilla glue in our case) will dissolve spray paint.
Be extremely careful that they are glued in the right orientation - the R, G, and B output pins should face the Amber LEDs. Trust us, you do not want to unglue and resolder new chips once they’re in there. We learnt that once and didn’t make that mistake again.
Before popping in the LEDs, we suggest using an LED tester to quickly check each LED is okay. It’ll only take a second or two for each LED, and it’ll save a lot of hassle should one be faulty! We reviewed an excellent LED Tester from LEDsales in DIYODE Issue 50, and it's the one we used. It might be a worthy addition to your workshop, too!
In any case, we continued adding the LEDs to the enclosure, making sure that the cathode (the negative side and the shorter leg) of each is inserted into the bottom slot.
The LED legs then need to be carefully cut and soldered to the pins of the WS2811 chip. Take this slow as it’s easy to mess up. Use a fine-tipped iron and don’t go crazy with solder. It’s easy to break the legs off these little guys!
The top LED legs - the anode - need to be connected together all the way along.
We then added some more wires to support the 5V and Ground lines for the WS2811 chips. Again, take this slow and make good solder joints. It’s an absolute pain to find tiny solder bridges and short-circuits later.
After adding some breakout wires and some bridging jumpers to connect the chaining data lines of the chips, we can finally do a test! This was pretty nerve-wracking, as building just one DRL indicator set took us nearly three hours. We’ll definitely consider a PCB next time!
Phew, it works properly! We simulated an indicator signal by plugging in a ground wire to the Arduino repeatedly, and sure enough, the indicator filled up like a progress bar just like we wanted.
The LEDs are nice and bright, so it appears that the WS2811 chips are working just fine. The Arduino was running on some test code we wrote before assembling the build.
Soldering White LEDs
Next, let’s solder in the LEDs that will be illuminated most of the time when the car is running! These are extremely bright, so we’re looking forward to testing them on the road - ideally without dazzling other drivers. In the case that it does, we’ll have to add some software-driven dimming or perhaps reposition the lights.
The White LEDs are, thankfully, much easier to solder in. They’re not dependent on fiddly chip soldering, and just need to be soldered in a particular order. Essentially, there are three controllable LED sections, each with two LED drivers as we designed and tested earlier.
So, the LEDs need to be soldered in as this diagram shows. Each of the ‘output’ lines are connected to the control Arduino. There are twelve control lines in total.
Finally, we’re putting together our main control board. At its heart is an Arduino Nano, mounted on a perfboard. It uses optocouplers to convert the car’s indicators and headlight signals into digital signals the Arduino can read. Onboard also are the transistor drivers and screw terminals for connecting wires to the lights themselves.
We used a breadboard layout perfboard to build everything on. We love these as it's convenient to transfer circuits from a breadboard prototype to a permanent circuit. To begin with, we soldered in some headers to support our Arduino Nano. We used an Arduino Nano with a USB-C port for better compatibility and durability.
Next up, we can begin soldering in our BD139 transistors to handle the white DRL lights. There will need to be twelve in total, controlled by six PWM pins.
Each needs one 5.6Ω and two 2kΩ resistors, which are added alongside the transistors on the row. We had to solder some in vertically to make it all fit. Since this perfboard has under-side copper bridges, we don’t need to add additional jumper wires to connect them together.
Be absolutely sure the transistors are inserted in the right orientation, otherwise, you’ll know very quickly once the circuit is turned on thanks to the presence of smoke! The text on the front of the transistors should face towards you if the Arduino Nano faces right.
We soldered in six on each row, mirroring them on the other side. We also added signal wires to the Arduino, which allows it to control the state of each. This means that each DRL has six transistors and three control lines from the Arduino - basic animations can be created in this case.
Next up, we can add the optocouplers that read the headlight and indicator states from the car. Because these are all 12V logic level, we can’t feed them directly into the Arduino Nano. The optocouplers use an LED to convert these signals to a safe level. We’re using 4N25 optocouplers here, but any with similar specifications and pinout should work.
We first soldered in the optocouplers themselves, and three wires for the indicator and headlight signals. These can be T-tapped into your car's electrical lines. Be absolutely sure to insulate and protect these against chafing and metal chassis parts as they will otherwise cause a serious short-circuit. We also added a 300Ω resistor to limit the current and any potential voltage spikes that might appear from the car’s battery.
The other side of the optocouplers is the logic (5V) side. We used some 10kΩ pullup resistors and some headers to form a simple Active-Low circuit for the Arduino to read. We connected the junction of these circuits to A3, A4 and A5 of the Arduino respectively, which we’ll read as digital inputs in the code.
Once we’ve finished the control board, we can then secure it in the vehicle. Because ours is only a testing prototype, we’re mounting ours in the bumper of the car. For permanent installations, we recommend using potting compound and a heat resistant case.
At DIYODE, we like to pump a ton of power into things and watch them either work properly or blow up spectacularly. This means that we may not have your best interests in mind, especially when dealing with legal requirements of lighting on your vehicle. Australian Design Rules are particularly stringent when it comes to this, so if you’re building this project in Australia, be sure to check you’re following the rules. The most important guideline we found was that lighting must not dazzle drivers in any way, so be sure to check that the lights aren’t excessively bright. Regardless, we’re not legal experts, so please read the ADRs yourself before building and using a project like this. If you’re an international reader, please research and follow the relevant legislation in your area.
It’s now time to install the project into the vehicle. Clearly, this will vary greatly depending on your model, but the general electrical requirements should stay fairly consistent. If you’re not confident doing this, you should consult an auto-electrician to do the wiring for you. Remember, we’re not dealing with basic 5V electronics anymore - we’re dealing with car batteries that can cause a lot of damage if handled incorrectly.
We first need to find a 12V ‘ACC’ or Accessory signal that only turns on when your car's ignition is on, or better yet, only when the engine is running. This guarantees that our DRLs can’t drain the battery when the alternator isn’t running. The least intrusive way of doing this is using a fuse tap, which allows you to add another wire to an existing fuse location. These typically include slots for two fuses - one for the original signal, and one for the wire that goes to our DRL lights. Even though our lights are quite low power, drawing around 20W maximum, fusing is incredibly important in case of a malfunction, causing an excessive amount of current draw.
The Mazda 3 we’re installing this on doesn’t have a ‘ACC’ fuse because each component that would normally be connected to it has its own dedicated fuse.
To actually mount the lights to the vehicle, we used double-sided tape as a temporary installation method. When we’re ready to mount the project - after potting the electronics - we’ll drill and secure the enclosure to the car.
The code for this project is simple on paper, but actually has a number of important tasks to handle. It’s vital that it’s reliable and doesn’t have strange or intermittent glitches - we definitely don’t want indicators coming on randomly when we’re driving down the road.
The first thing to keep in mind is that we’ve tried to make the code as cross-compatible and customisable as possible. So, whether you’re making a big light strip to go across your 4WD’s bullbar, or a few LEDs to help supplement some fading old headlights, this code can be adapted quite easily.
The following two parameters are probably the most important.
//How long does it take the full bar
//to fill in milliseconds?
#define FILL_TIME 600
//How long do our indicators have to be
//off before the regular
//driving lights come back on?
#define DRIVING_LIGHTS_COOLDOWN 1000
You will likely need to change these parameters based on how fast the indicators on your car turn on and off. Most indicators will cycle every 1.2s-1.4s, so our progress bar will need to fill before the indicator turns off. We left ours at 600ms to turn on in time.
We also need to specify how long the Arduino should wait when the indicator signal is off, before turning the regular DRLs back on. We left ours at 1 second.
There are many other parameters to customise too, including how many amber indicators you have and the pin assignments for your white DRLs. We’ve left everything in the project files if you want to check it out.
After installing everything and uploading the code, we turned the car on, hoping we didn’t make any electrical mistakes - again, see an Auto electrician if you’re not confident with this! Currently, our installation isn’t permanent. We’ve secured them well enough to not fall off, but the units aren’t weatherproofed enough to survive tough weather.
Sure enough, the white LED lights sprung to life and immediately were visible for a very reasonable distance at daytime. At nighttime, the lights acted more like headlights thanks to their significant power output so we ended up dimming them with software PWM. Most car headlights have designs intended to reduce glare for oncoming drivers, whilst our ‘low-tech’ LEDs are great at throwing out tons of unregulated light!
The indicators worked well, however, they weren’t quite as bright as we’d like them to be. Because they’re only running at 20mA compared to the DRL’s far mightier 150mA, they pale in comparison. They’re much more visible in overcast conditions and at night - they look awesome with their “progress bar” style fillup animation.
Where To From Here?
This project was built to upgrade an older car with newer safety features, and is highly dependent on your exact car model. As such, there will need to be some adaptation done to suit your specific car model and purpose. If you’re planning on designing a large light bar, then perhaps investing in some higher-power LEDs might be right down your alley. Just remember to drive them appropriately.
One interesting trend we’ve seen in modern cars is using full-length light bars for the rear taillights and even front lights - it’s common on new Porsches and is extremely eye-catching. It's an awesome retro addition to new cars - but what about older cars? We’d love to see this retrofitted to older cars with LEDs - muscle cars are a great candidate! Cleverer makers could even integrate animated indicators as we’ve shown into the brake lights.
Obviously, this whole project has a fairly niche appeal, but the techniques and circuits we’ve used in it can be used for a large variety of applications. Hopefully, this project was enlightening! (Get it? Okay, we won’t use that one again.) If we’ve inspired you to make anything cool, let us know what creations you come up with on social media!