Project showcase
Arduino Motorcycle Tail Lights

Arduino Motorcycle Tail Lights © GPL3+

Arduino controlled auxiliary saddle bag lights for a motorcycle.

  • 5,230 views
  • 19 comments
  • 20 respects

Components and supplies

About this project

Introduction

Sure, you can buy after-market lighting kits. What fun is that?!? … especially for us Arduino-heads :-) If you aren't an Arduino-head, I could be persuaded to put together a kit. Of course you'll still will be able to program it any way you want.

On the surface this is a pretty simple project. It reads 3 on/off switches and drives 2 LED strips. That’s all there is to it. However, this isn’t your typical stand-alone Arduino project. There are some subtle nuances of integrating it into an existing electrical system. Also, pixel animation can be... tedious, but hopefully my encapsulation can shield you from that.

Here are the skills and the items you will need to build this project.

  • A willingness to dig into your bike’s electrical system. You’ll need to find and tap into:
  • Switched 12V line
  • Left turn signal line
  • Right turn signal line
  • Brake light line
  • If you remove existing turn signals you’ll probably end up with a "hyper-flash" situation. This is a typical symptom when you replace turn signals with something that draws little amps like an LED. The best solution is to replace the turn signal relay. Alternately you can add load resisters to simulate the load of a normal incandescent bulb. I did the load resisters before I found out the turn signal relay is a better solution.
  • Three 12V relays (I chose the small reed type relays)
  • 5v power supply capable of a continuous 5 amps (not the peak rating)
  • An Arduino of some flavor. I used an Arduino Nano clone.
  • Two - 5x8 WS2812 LED matrix (or matrix of your choice)
  • Perf board
  • Terminal blocks for connecting all the wires
  • Wire

Notes on the schematic

  • The goal of this project was to isolate the Arduino completely from the bike's electrical system. That is why relays are used to trigger the Arduino pins. You could probably use a voltage divider and avoid the relay.
  • If you have a newer bike with LED turn signals, check the voltage going to your lights. It may already be 5V that could be fed directly to an Arduino pin.
  • You’ll probably find it odd that I’m using analog to read the brake/turn signals. This was only done to simplify soldering of the prototype board so I didn’t have all the connections on one side of the Arduino Nano. Typically, you’d use digital pins for this.
  • The switched 12V input line is on an existing 10A circuit on my bike. I fused the project at 7A so that if something goes wrong, hopefully it won’t take out my existing brakes and turn signals.
  • Don’t under power the project! Each LED matrix could draw 2.5 Amps! As shown, I have a dual output power supply that is capable of 4A on each output and this works flawlessly! Two 3-amp BEC circuits would probably also work. If your Arduino LED flickers while the turn signals run, get a dedicated power supply for the Arduino, or power the Arduino with 12V to the VIN pin. My power supply shown below is good enough that I can power everything w/o seeing the Arduino LED flicker at all.

Building the circuit board

  • I used an Adafruit perma breadboard (essentially a perfboard with breadboard traces). I hoped that the built-in traces would make a cleaner build. It’s not a perfect solution and some traces need to be scraped off. I’m ok with this idea, but not wow’ed so I haven’t included the layout. You can probably do a better job anyway.
  • Things I might do differently:
  • Take the time and design a PCB board
  • Put in headers so the Nano can be replaced, but this will also increase the thickness of the build
  • I’d like to try a TI MSP430 instead of Arduino

Building a test fixture

If you are modifying the code, you are going to want to build a test fixture so that you can develop and test at your desk rather than working on this out in the garage attached to your bike. I built a 3 button project box that feeds 9v to each of the three relays (I lucked out that 9v can trigger the 12V relays). The three buttons represent: left, right, and brake signals and you can test all combinations.

Arduino Projects

I learned early on in my Arduino adventures that it’s best to encapsulate LED animations in class libraries. That makes the animation reusable and cleans up your main Arduino sketch from all gory details allowing you to focus on what you want to do, not how to do it.

The downside of class libraries is that they are kind of a pain to write. Debugging facilities are lacking (I'm use to using Microsoft Visual Studio and Eclipse) and when things don't work there are few clues on what went wrong. The best advice I have is to build up the functionality slowly and save backup copies. When things go south on you, closely examine recent changes that you put in. Probably the most common catastrophic error in C/C++ are buffer over-runs. Symptoms can be erratic behavior, or flat-out failure. This is just the nature of the beast and not limited to Arduino.

Compiling this Arduino sketch requires 4 downloads:

  • Adafruit neopixel library
  • BlinkLed (my library that performs a simple blink animation. Used for brake and running lights)
  • CascadeLed (my library that systematically illuminates a series of LEDs. Used for turn signal animation.)
  • TailLight (Arduino sketch)

The method to my madness is to create instances of the LED animation classes specifying the LEDs to light, and the frequency. Then you simply call the instance on each control loop and tell the instance if it should be on or off. The instance keeps track of its blinking frequency and decides what to do. With the animation fully encapsulated like this, there are only a handful of lines of code in the sketch itself (excluding the instantiation code).

BlinkLed class library

Look in the header file of the class library for the details of the call sequence. You can also find examples in the sketch for instantiating and calling it for the brake lights and running lights. Basically, you pass in an array of pixels to light and the frequency.

example:

byte maxstop = 25;

byte StopPix[MAXSINGLEROW] = { 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 19, 20, 21, 22, 23, 27, 28, 29, 30, 31, 35, 36, 37, 38, 39};

BlinkLed LStopLed = BlinkLed(&lstrip, &StopPix, maxstop, R, G, B, 19);

BlinkLed RStopLed = BlinkLed(&rstrip, &StopPix, maxstop, R, G, B, 19);

CascadeLed class library

Look in the header file of the class library for the details of the call sequence. You can also find examples in the sketch for instantiating and calling the turn signal signals. Basically, you pass in a two dimensional array of pixels to light and the frequency. The class will then cycle through the rows of pixels and light them in that order.

WARNING: For simplicity I have chosen to create constants to define the array sizes. This burns some memory for the sake of ease of use. If you choose to drive more than 40 pixels per bank, you may need to alter the constants defined in: CascadeLed\ArrayConstants.h.

example:

const byte maxrow = 5;

const byte maxcol = 8;

byte Rightpix[MAXROW][MAXCOL] = { { 0, 1, 2, 3, 4, 5, 6, 7}, { 8, 9, 10, 11, 12, 13, 14, 15}, {16, 17, 18, 19, 20, 21, 22, 23}, {24, 25, 26, 27, 28, 29, 30, 31}, {32, 33, 34, 35, 36, 37, 38, 39}};

CascadeLed RightLed = CascadeLed(&rstrip, &Rightpix, maxrow, maxcol, RT, GT, BT, 80, 900);

TailLight.ino Arduino Sketch

Not much to say here. The control loop is REALLY simple:

void loop() {

byte leftpin = (analogRead(LEFTPIN) > 50);

byte brakepin = (analogRead(BRAKEPIN) > 50);

byte rightpin = (analogRead(RIGHTPIN) > 50);

// animate or clear the turn signals

// PsudoOn is true when pin is high or between turn signal blinks (pin is actually low)

bool lPsudoOn = LeftLed.Blink(leftpin);

bool rPsudoOn = RightLed.Blink(rightpin);

// animate or clear the brake lights LStopLed.Blink(brakepin); RStopLed.Blink(brakepin);

// only turn on running lights. Let the overlays turn it off // Clear will interfere with overlapping lights

if (!lPsudoOn && !brakepin) LRunLed.Set(true);

if (!rPsudoOn && !brakepin) RRunLed.Set(true);

}

Side notes:

Turn signals switch on and off and will disrupt the pixel animation because the blinking is faster than one animation sequence. The CascadeLed class has a timeout value to absorb the “off” part of the blink and pretend that the signal is still on. This pseudo on is passed back to the main control loop so it knows if the turn signal should be considered on or off instead of using the current pin value. The only minor consequence is that the turn signals don’t immediately turn off when the turn signal is turned off.

The pixel assignment between turn/brake/running lights overlap. That means turning off one LED animation may turn off the LEDs of another animation. This is only temporary until the current animation is on long enough to repaint its corrupted pixels. I’ve only seen this problem between the turn signal and running light animations. If you choose another running light pixel assignment, this may cause you problems. I’ll consider fixing it if it becomes an annoyance for someone else. For me I’m happy with current way it works.

Code

Schematics

turn signal video
turn signal video
imgp0004_F1FAGUggLy.AVI

Comments

Similar projects you might like

How to Configure NeoPixels Using Vixen Lights and Arduino

Project tutorial by Victor Aguilar

  • 13,236 views
  • 23 comments
  • 28 respects

Huge LED Christmas Lights

Project showcase by Savva Osipov

  • 10,603 views
  • 2 comments
  • 32 respects

Arduino Bike Blink Lights

Project showcase by Sam

  • 4,389 views
  • 3 comments
  • 13 respects

Railroad Crossing Lights

Project showcase by eldo85

  • 2,655 views
  • 4 comments
  • 6 respects

Crossroad Traffic Lights (FSM)

Project showcase by Carlos Silva and Daniel Turner

  • 1,495 views
  • 1 comment
  • 6 respects

Automated Staircase RGB LED Lights

Project tutorial by Team NotEnoughTech.com

  • 27,609 views
  • 19 comments
  • 98 respects
Add projectSign up / Login