Introduction: DIY Givi V56 Motorcycle Topbox Light Kit With Integrated Signals
As a motorcycle rider, I'm all too familiar with being treated like I'm invisible on the road. One thing I always add to my bikes is a top box which usually has an integrated light. I recently upgraded to a new bike and bought the Givi V56 Monokey box since it had lots of space for items. This box has a spot for a factory light kit which consists of two strips of LEDs for each side. The problem is this kit is about $70 and only does brakes. There is an aftermarket kit that probably does similar things and might be a bit easier to install, but your price goes up to $150. Being a resourceful person and looking for an excuse to try out the addressable LED strips, I decided to make an integrated system that not only would have brake lights, but running lights (on whenever moving), turn signals, and hazard lights. Just for the heck of it, I even added a startup sequence.... because I could. Note that this took a lot of work to do though I had a lot of things to figure out. Despite the work, I'm rather happy with how this turned out. Hopefully this ends up being useful to someone else.
The basic operation of how this system works is the Arduino unit looks for signals on the pins: brake light, left turn light, and right turn light. In order to read the 12 volt signal from the motorcycle, I used optoisolators to convert the 12V signal to a 5V signal that Arduino can read. The code then waits for one of these signals then outputs the commands to the LED strip using the FastLED library. That's the basics, now to get into the details.
Attachments
Supplies
These are the things that I used because for the most part I already had them lying around. Obviously, they can be exchanged out as needed:
- Arduino - I used a nano for size considerations but you can use whatever you feel like as long as you have five pins to use.
- 5V regulator - I used an L7805CV that was capable of 1.5 amps. This project will use 0.72 amps for the LEDs plus the power for the nano, so 1.5 works great for this project.
- Capacitors - you will need one 0.33 uF and one 0.1 uF for the voltage regulator to operate properly.
- 3x optoisolators - to do the signal conversion from 12V to 5V. I used PC817X type which only have four pins which is all we need.
- Resistors - you will need two types, three of each type. The first needs to be enough to reduce the current through the optoisolator IR LED. You will need at least 600 ohm, but 700 would be a better idea to handle changing voltages on the motorcycle. The other needs to be somewhere between 10k and 20k for a quick signal on the other side of the optoisolator.
- Prototype board - I had some that were small enough to fit inside a small project box with a slight amount of trimming.
- Project box - big enough to fit the components, but small enough to be easy to fit.
- Wire - I used Cat 6 ethernet wire because I had a lot of it sitting around. This has eight wires all color coded which helped with all the different connections and was a large enough gauge to handle the current draws.
- Plugs - anywhere you want the system to be easily removable. I used a waterproof plug to allow the top box to be removed and to handle any rain or water that gets on it. I also needed smaller plugs for the LED strips so I didn't have to drill large holes.
- Zip ties and zip tie adhesive mounts to hold everything in place.
- Shrink wrap to tidy up the connections.
Step 1: Building the Circuit
Obviously, if you're following my build, you won't have to go through the amount of testing I did. First thing I did was to make sure my code worked and I could properly get a signal from the optoisolators as well as properly control the LED strips. It took a moment to figure out how best to attach the signal pins to the isolators but through trial and error I found the right orientation. I just used a standard prototype board since I was only building one and figuring out a trace pattern would have taken more time than it was worth. The top part of the circuit board looks great, but the bottom does look like a bit of a mess, but at least it's functional.
The basic design starts with inputting the 12V power from a switched source (a wire that is only on when the motorcycle is on). A wiring diagram can really help to find this wire. This is fed into one side of the voltage regulator. A 0.33 uF capacitor ties this input to the ground on the voltage regulator which then feeds back to the ground on the motorcycle. The output of the voltage regulator will have a 0.1uF capacitor tied into it to ground. These capacitors help to smooth out the voltage from the regulator. If you can't find them in the picture of the circuit board, they are underneath the voltage regulator. From there, the 5V line goes to the Vin on the Arduino, to the power pin that will feed the LED strips, and two the Source side of the optoisolator that will feed into the Arduino pins providing the needed 5V signal.
As for the optoisolators, there are two sides: one with an IR LED and the other with a transistor with and IR detector. We want to use the IR LED side to measure the 12V signal. Since the LED has a forward voltage of 1.2V, we need a current limiting resistor in series. 12V - 1.2V = 10.8V and to run the LED at 18 mA (I always like to run less than 20 mA for lifetime reasons), you will need a resistor of R = 10.8V/0.018A = 600 ohm. Voltages on vehicles also tend to run higher, potentially up to 14V, so it's better to plan for that, which is about 710 ohm, though 700 would be more than reasonable. The output for the LED side then feeds back to ground. For the output side of the optoisolator, the input will use the 5V signal from the regulator then the output will connect to another resistor before going to ground. This resistor just needs to be around 10k - 20k ohm, at least that's what my datasheet showed. This will give a quick signal measurement since we're not dealing with a noisy environment. The output to the Arduino pin will come off between the resistor and the output of the optoisolator so that when the signal is off the pin is low and when the signal is on the pin is high.
The LED strip lights have three wires associated with them: Power, ground, and data. Power needs to be 5V. This project uses 12 LEDs total (though I have more LEDS on the strips but I'm only using every third LED) and each takes 60mA when white light is used at full brightness. This gives a total of 720 mA. We're well within the output power for the voltage regulator, so we're good. Just make sure that the wire is a large enough gauge to handle the power, I used 24 gauge Cat 6 ethernet wire. Ethernet wire was something that I had sitting around and it has 8 color coded wires so it worked out well for this project. The only wires that then need to go to the topbox itself is the power and ground (which both get split between the strips) and two data lines (one for each strip).
The rest of the wiring is connecting to the pins on the arduino and feeding it power. The pins that were used for this project were the following:
- Vin - connected to 5V
- Gnd - connected to ground
- Pin2 - connected to Left strip data line
- Pin3 - connected to Right strip data line
- Pin4 - connected to Brake signal from the optoisolator
- Pin5 - connected to Left turn signal from the optoisolator
- Pin6 - connected to Right turn signal from the optoisolator
Step 2: Wiring and Installing
Once the circuit is built, the time comes to actually wire this into place. Using your wiring schematic for your bike, you will need to locate the following:
- Switched power supply
- Ground
- Brake Signal In
- Left Turn Signal In
- Right Turn Signal In
For mine, there was a single plug that had all of these on it, so I just used that. With enough time, I might have been able to find the same plug style and just make a plug in module, but I didn't, so I just removed the insulation in places and soldered the new wire to it. I used plugs on these spliced connections so that I could remove the rest should I ever need to in the future. From there I placed the Arduino, which is now in a sealed project box, under the seat where I attached it. The output cable then runs along the rack frame to a waterproof plug, then enters the box and runs along the back to the lid where it splits for each side. The wires run along the inside of the lid to the point where the connections for the LEDs are at. The wire is help in place using zip ties attached to Outdoor grade zip tie mounts with an adhesive backing. You can find these in the cable installation section at a home improvement store
I used two mini JST plugs on the LED strips because I needed a plug small enough to go through a hole of minimum diameter and because I wanted to make sure there was enough wire to handle the current requirements. Again, it may have been overkill and I didn't have any small plugs with three wires handy. The hole in the box for the light strip wires to pass through were sealed up to keep water out. As for positioning the LED strips, because there is a slight mismatch in spacing (there was about 1 - 1.5 mm difference in spacing between the holes in the reflector and the LEDs) I positioned them so that they would split the difference between the LED and the hole as much as possible. I then used hot glue to tack them in place and sealant to fully seal the area. The LED strips themselves are waterproof, so no issue if they get wet. Although it seems like a lot to install, this makes the system easier to remove in the future or replace parts are needed because it could happen.
Step 3: The Code
My source code should be at the beginning of this Instructable. I always comment my code heavily so it's easier to understand later on. Disclaimer: I'm not a professional code writer. The code was written in a method that was easier to get going first and some improvements were made, but I know it could be more refined. I'm also using a heavy amount of the delay() function for timing which is not as ideal. However, the signals that the unit is receiving are not fast signals in comparison, so I still felt justified to keep them over using something like millis(). I'm also a very busy father and husband so spending time to improve something that will ultimately not change the function isn't high on the list.
For this project, only one library is required which is the FastLED library. This has all the code for controlling the WS2811/WS2812B type LED strips. From there, I'll cover the basic functions that will be used.
The first other than the standard definitions is to declare your two strips. You will use the following code for each strip:
FastLED.addLeds<WS2812B, 2,RGB>(leds[0], NUM_LEDS);
This line of code sets up Pin 2 defines this strip as strip 0 with the number of LEDs defined by the constant NUM_LEDS, which in my case is set to 16. To define the second strip, the 2 will become 3 (for pin3) and the strip will be labeled strip 1.
The next line that will be important is color definition.
leds[0][1] = Color_high CRGB(r,g,b);
This line of code is used though in different looks (most of my use a constant). Basically, this code sends a value to each of the LED channels (red, green, blue) that defines each brightness. The brightness value can be defined by a number 0 - 255. By changing the level of brightness for each channel, you can define different colors. For this project, I want a white color to keep the light as bright as possible. So the only changes I do is to set the brightness level the same across all three channels.
The next set of code is used for individually lighting each light. Note that for each strip, each LED has an address that starts at 0 for the one closest to the data line connection all the way up to the highest number LED you have minus 1. Example, these are 16 LED strips, so the highest is 16 - 1 = 15. The reason for this is because the first LED is labeled 0.
for (int i = NUM_LEDS-1; i > -1; i = i - 3) { // This will change the light for every third LED going from the last to first.<br> leds[0][i] = Color_low; // Set strip 0 LED color to the chosen color. leds[1][i] = Color_low; // Set strip 1 LED color to the chosen color. FastLED.show(); // Show the set colors. leds[0][i] = CRGB::Black; // Turn off set color in prep for next color. leds[1][i] = CRGB::Black; delay(150); } FastLED.show(); // Show the set colors.
The way this code works is that a variable (i) is used within a for loop as the LED address which is then referenced to the full number of LEDs (NUM_LEDS). The reason for this is that I want the lights to start at the end of the strip rather than the beginning. The setting is output to both strips (leds[0] and leds[1]) then a command to show the change is issued. After that this light is turned off (CRGB::Black) and the next light is lit. The Black reference is a specific color in the FastLED library so I don't have to issue 0,0,0 for each channel though they would do the same thing. The For loop advances 3 LEDs at a time (i = i-3) since I'm only using every other LED. By the end of this loop, the light sequence will go from one LED to the next with only one lit per strip, sort of a Knight Rider effect. If you want to keep each light lit so that the bar builds, you would just remove the lines that turn the LEDs off which happens in the next set of code in the program.
for (int i = 0; i < dim; i++) { // Quickly fade lights to running light level. <br> rt = rt + 1; gt = gt + 1; bt = bt + 1; for (int i = 9; i < NUM_LEDS; i = i +3) { // This will light up the last three lights for the position light. leds[0][i] = CRGB( rt, gt, bt); // Set strip 0 LED color to the chosen color. leds[1][i] = CRGB( rt, gt, bt); // Set strip 1 LED color to the chosen color. } FastLED.show(); delay(3); }
The last example of code that I use for the LEDs is a fade loop. Here, I use temporary slots for the brightness for each channel (rt, gt, bt) and increment them by 1 with a delay between each showing to achieve the appearance I want. Also note that this code is only changing the last three LEDs as this is fading in the running lights so i starts at 9 rather than 0.
The rest of the LED code is iterations of these. Everything else is focused around looking for a signal on the three different wires. The Loop() area of the code looks for brake lights, which it will flash once before staying on (this is adjustable if desired) or looking for turn signals. For this code, because I couldn't assume the left and right turn lights would turn on exactly the same time for hazards, I have the code look for either one first, then after a small delay I check to see if both are on indicating the hazard lights are on. The one tricky part I had was turn signals because the light will go out for some period so how do I tell the difference between the signal still on but in the off period and a cancelled signal? What I came up with was implementing a delay loop that is set to continue longer than the delay between signal flashes. If the turn signal is still on, then the signal loop will continue. If the signal does not come back on when the delay ends, then it goes back to the start of the loop(). To adjust the length of the delay, change the number for the constant lightDelay remembering for every 1 in lightDelay the delay changes by 100ms.
while (digitalRead(leftTurn) == LOW) { for(int i = 0; i < lightDelay; i++) { leftTurnCheck(); if(digitalRead(leftTurn) == HIGH) { leftTurnLight(); } delay(100); } for (int i = 0; i < NUM_LEDS; i = i +3) { // This will change the light for every third LED going from the last to first. leds[0][i] = CRGB( 0, 0, 0); // Set strip 0 LED color to the chosen color. } for (int i = 9; i < NUM_LEDS; i = i +3) { // This will set up the running lights which only use the last three. leds[0][i] = Color_low; // Set strip 0 LED color to the chosen color. } FastLED.show(); // Output settings return; // Once turn signal is no longer on, go back to loop. }
Hopefully the rest of the code is self explanatory. It's just a repeating set of checking and acting upon signals.
Step 4: Results
The amazing part was that this system worked the first time I wired it to the bike. Now, to be fair I heavily tested it on the bench prior to this, but I still expected to have an issue or an adjustment. Turns out that I didn't need to make any adjustments to the code as well as the connections. As you can see in the video, the system goes though the startup sequence (which you don't have to have), then defaults into running lights. After that it looks for the brakes in which case it will light up all LEDs to full brightness and flash them once before remaining on till the brakes are released. When a turn signal is used, I made a scrolling effect for the side that the turn is indicated and the other side will be either running lights or brake light if on. Hazard lights will just blink in time with the other lights.
Hopefully with these additional lights, I will be more visible to other people. At the very least, it's a nice addition to make my box stand out a bit more than others while providing utility. I hope this project is useful to someone else as well even if they are not working with a motorcycle top box lighting. Thanks!
33 Comments
Question 2 years ago on Introduction
Hi there, awesome project and I'm keen to make, with some minor amendments to fit my Givi E52 top box. By no means have a got the knowledge you have and when buying some of the components, I wasn't able to exactly match up the resistors you mentioned. My local hobby electronic store (NZ) supplied me with what I guess is close, but if I could be a pain, could I ask: what are the specific resistor colour bands for your set-up? Sincere thanks.
Answer 2 years ago
The resistors aren't super critical. You just need them in about the right area. For the smaller resistor, you want something around 600 to 800 ohms. I would not go with a lower value than 600 to avoid burning out the LED. For the larger resistor, you want around 10,000 - 20,000 ohms. You can look up a color code chart to see what these correspond to. I don't know them off the top of my head. Otherwise, if the values are close you should be fine.
Reply 2 years ago
Thanks so much for the advice. Turns out the resistors I bought were within the ranges you mentioned. I have to say it's been my first dabble into the Arduino world and just with this small project, and despite a few small mistakes, I think I've learned so much from you. The detail you've gone into has been super helpful. I thought I'd made a mistake with the indicator sequence until I re-read your code comment about lighting up, "....strip once". I made an assumption that on my test bed, if I kept the power on, it would keep looping, but now I understand it's looking for the distinct power 'pulse' (for want of a better word) to repeat the sequence - I hope I've got that right? One last question though if I may; the left, right and brake power entering the Optoisolator (referencing X1, X2, X3 on your schematic) is 12V - have I got that right?
Reply 2 years ago
Glad it's been a good learning project. Yes, the voltage coming in should be 12V (same as the battery your motorcycle uses). The optoisolators make it easy to convert from 12 volts to 5 volts while isolating the two electrical systems more. However, that's why the resistors have to be large enough to reduce the current through the LED inside the optoisolator so it doesn't burn out.
Reply 10 months ago
Sorry to bother you again. My lights have been working flawlessly for the past 2 years. I've just upgraded the turn signal and brake light bulbs from the standard wedge filament to wedge LED. After changing the bulbs, when I activate the turn signal, the Arduino completes the first sequence, lighting first to last, but will not loop. If I change the bulbs back to the original filament style, the Arduino works flawlessly. I've been refreshing my self with the Arduino code, but I can't see what I might need to change.
PS: I had to change a relay to slow the indicator flash rate to suit the LED bulbs, and the flash rate is the same now as per the filament bulbs. I changed the brake bulbs for the same type of LED, and the Arduino sequence for the brake light flash works perfectly, so I'm a little confused and unsure where to start with the turn signal issue.
Any suggestions on where I might start?
Reply 9 months ago
So it's hard to say for sure, but my guess is that the LED bulbs you put in are dropping the voltage too much to be picked up by the optoisolators. If your pick up point for the signal is past the bulb rather than before, then there will be a voltage drop from running through the LEDs. I would try taking a multimeter and measure the voltage that you get going to the circuit board. If you're getting around 12V, then you really have a mystery. If you are getting something 1-2 volts, then that's the issue. To fix that, you would either need to change the pickup point to be before the LED bulb or find some way to trigger a signal change with low voltage (ie: using a transistor as a switch). Not sure which is easier. Good luck with that!
2 years ago
Awesome job, brother! I already bought all components i didn't yet have, except the jst connectors. Which brings me to my question: why are there two connectors for each led strip? I really don't see anything to explain that, in the text, in the images, or in the diagram.
A photo of the entire thing laid out on a table would have done wonders, but I'd be more than happy with just an explanation or something.
Also: how did you test it on the bench? how did you emulate in code turning the signals on or off, or braking or whatever? Did you attach (temporarily) buttons on the signal input line, to turn the 12v on or off, or what?
I'm really loving this (if you can't tell), and i'm looking forward to starting to work on it! As soon as the electronic part is done, i'll start messing with the code (i want to design my own start up sequence, and maybe even a different light up pattern for signals or braking or whatever) - this is the most fun part!
Cheers,
John
Reply 2 years ago
The reason I had two connectors per line was because I was concerned the current draw on those small wires would be too much and wanted extra current capacity. It might have been fine but I decided to just be safe. Again, I used what I had on hand. A single connector that has a larger gauge wire would be just fine. For testing on the bench, I just connected a power wire by hand to the contact as needed to simulate the tests. I had a small 12V battery that I was using to test the system. Lots of ways to do things though. Hope that helps.
Reply 2 years ago
That helped immensely, THANK YOU!
Now, to get the kid to bed, so that i have some time to play! :D
Reply 2 years ago
Too tired to solder the led strips tonight (it's 1am),but if nothing comes up, tomorrow I'll be doing the first tests (after double checking everything). My leds are spaced differently, so I'll have to mess with the code a bit. I don't even have a topcase yet, so I'll have plenty of time to play with them.
In your diagram, the optoisolators are mirrored, and it confused me for a bit, but i believe i got it right eventually. As previously mentioned, i'll double check tomorrow.
Question: should I cut the power to the breadboard when uploading the code? Or at least disconnect the Vin?
Reply 2 years ago
The optoisolators should be setup so the 12 V is on the LED side with the appropriate resistor then the 5V side on the transistor side. I would disconnect the Vin when programming so there isn't any unintentional power conflicts.
Reply 2 years ago
You mean the 6-700ohm resistor should be on the anode, 12V side (e.g. brake input), and the 20k resistor should be on the 5V Vcc from the L7805? In the wiring diagram, you placed the 6-700R on the cathode, and the 20k on the emitter, towards ground. I've added a diagram with the "redone" pc817, please tell me if this OR the original diagram is correct, I'd hate to start testing and blow something up.. :
Reply 2 years ago
My schematic is how I put it together. I can't claim to have followed all BKMs as I'm not a professional electronic circuit designer. However, with those two parts I don't think it will matter which side you put the resistor from a function standpoint. They are there just to limit the current flow. Would be worse to leave them out than to put them on different sides. Go with whichever method you like more.
Reply 2 years ago
Thanks for your patience, man! I got it working, i need to work the code a lot more - my led strips are 10 leds each, so i have to go through it to adapt it. I changed the i + 3's and -3's to 2's, but that's just to see if everything lights up. Well, it does, but there's no repeating, and it stays lit on high, so it's far from done..
However, the L7805CV is BOILING.. do you think this is due to the errors in code, that maybe confuses the nano into shooting more power into each led, or is that a result of some bad wiring? Or is it as simple as - there's 20 leds lit (not my intention), compared to the 12 you were running.. maybe it's a combination of all, and they're overloading the voltage regulator..
Edit, six hours later: i limited the leds to 3 per strip, and it still gets just as hot (i'm powering from a 12V 3A power adapter - as far as i know, increased amperage should not influence anything, so it shouldn't get any hotter than that when powered from the 14,3V 12A battery of my bike (charging voltage).. The L78 seems to be working fine otherwise, and even measured it separately - it puts out constant 4.99V (and doesn't get hot outside the circuit, of course). Still, i'd appreciate a second opinion.
2nd edit: read up on it, and it's apparently the way the L78 works.. i need a serious heat sink for it, since the voltage difference and the current draw are pretty high, which means the L78 is eating up several watts..
Reply 2 years ago
I was going to say to calculate the current draw. I made my light strip skip lights so that I would keep current draw down. A heat sink certainly helps, but you may need a second Voltage regulator to supply power to the LEDs (or maybe one for each if they're drawing a lot). I usually try to stay below 80% of the regulator's output.
Reply 2 years ago
Solved the heating problem: replaced the L78 for a LM2596.
Not the prettiest thing, but it works.
Bonus: test setup. Don't have uni diodes to "fake" hazzards, so i just have to press both turn signal buttons at the same time, but it does the job.
All that's left now is to buy a topcase and mount them..
Reply 2 years ago
Glad you got it working!
Reply 1 year ago
Almost exactly one year later, and my new topcase will arrive in a couple of days. Due to its design (clone of a Givi V47N), i'll add two additional LED strips (all four will now be WS2813b, two on the base and two on the lid), so I've started modifying the code. I'll also replace the LM2596 with an even cooler running 5A capable XL4015 (gonna be limiting CV and CC).
I am truly grateful for this tutorial of yours, brother, as well as for all the help you've given to me and the others that have commented!
I've created a circuit diagram, which should make it MUCH easier for others to follow. Feel free to include it in your post, if you so choose.
Edit: Dug around a bit, and some people recommended adding capacitors on the LED strips, so i included these in the diagram, but i might not include them in my actual design. As well as some resistors on the data wires, to reduce noise. These i'll include - i'll start with a 220ohm on each data wire, close to the Nano pins, and if there's interference or something, i'll add one close to the strip as well.
Best of luck!
John
Edit: Had to remove the schematic, it was incorrect.
Reply 1 year ago
Thanks for the update. I'm limited both by time and resources when it came to making my diagram and was just glad to have something that worked. Look forward to seeing the final product.
2 years ago on Step 4
Nice project, I made it for a friend and adjusted to give red lights for
brake and yellow for turn signals. I plan to cut individual led's and
position them to align holes perfectly and glue in place and then just
solder them together with wires. Basically create custom led's per meter
strip :) I have only one question, I have white light in the startup
sequence and not sure why, cannot figure it from code. I am working with
Arduino for the first time.
https://youtu.be/tjFY3Zb-n_o