Projects‎ > ‎Modifications‎ > ‎


Motivation and Inspiration

There are plenty of commercial bike lights available, and many cost just a few bucks. So why build one from scratch? This is a valid question, but I think it has just as valid of an answer: because nothing available is that good. With that in mind, this project has two clear cut goals.

1. To greatly increase the bike's visibility to motorists, pedestrians, and whatever can see.
2.To greatly increase the bike rider's ability to see what is ahead when riding after dark.

The second of these goals is easily achieved with a few ultra-bright lights in the front of the bicycle, but the first goal (and realistically more important of the two) needs a little more help. To solve this problem a complete lighting system consisting of front, rear, and side lights was conceived. The overall style of the lights resembles that of a vintage cruiser motorcycle, sleek and appealing. The side lights will be more reminiscent of a big rig to enable someone viewing the bike perpendicularly to easily see it. Any other features can be added as the design is under way.

Conceptual Design and Overview

With a custom build, pretty much anything is possible. That said, I started with the basics and added features until I was happy. There are still a few things I could add to the programming and hardware in future versions, but I'm happy with the current "v3" build which contains the following lights and attributes:
  • Headlights - Dim and bright modes selectable
  • Taillights - On with dims or brights
  • Brakes - On when either brake lever is pulled; initially flash
  • Blinkers - Left and right, on with switch
  • Sidelights - On with dims or brights; flash with blinkers
  • Hazards - Flashes all blinkers and sidelights
  • Dash Lights - On with switch (illuminates cyclometer)
  • Sneak Mode - Brights on; all other lights off
  • Compact Control Panel - Attached to handlebar
  • Long Battery Life - Uses 2 parallel 12V 2.2Ah NiMH batteries
  • Main Switch - Semi-hidden; easily accessible
  • Visually Appealing - Does not look cheap, junky, or out of place

Hardware Design

Very typically, I design and build the mechanics and electronics at the same time to be sure they play nicely together. Although this was the case for most of this project, I began solely with mechanical concerns. After years of trying to use hollowed out flashing light shells, I stumbled upon a collection of sealed replacement automobile headlights in the clearance isle. These pieces were exactly what I had been looking for. Initially I had planned to build two systems, one each for mine and my wife's bikes; however, I ended up breaking two of the larger glass headlamps trying to figure out how to unseal them. After multiple failed attempts to "cook" the silicon glue that holds the shell and face together (as was suggested by numerous online sites) and a dozen or so hours of trying to cut the faces off with a Dremel, I decided to (carefully) break the glass faces off and replace them with a thin sheet of plexiglass.

To control the lights, there are a variety of different types of switches to be used. Aside from the main power switch which will be a standard 12V rocker, two momentary-on push buttons are used for the dims and brights, a slide switch will turn the dash lights on or off, a push-on/push-off button is used for the hazards, and an on-off-on momentary toggle switch controls the left and right blinkers. For the brakes, a normally on, momentary-off switch is embedded into the plastic under each of the brake levers such that when the brakes are pulled, the buttons are depressed, closing the switches. When the brakes are released, the brake cable tension will pull the levers back against the buttons which opens the switches.

Another trick I have learned when working with large LED arrays is to use a sheet of craft foam to hold the LEDs as opposed to soldering them to a large and expensive board. The foam is usually one or two bucks for a square yard as opposed to five bucks for one perf-board. The only downside to doing this is that you have to manually poke each lead hole with a sharp pick. Trying to push the LEDs through without a guide hole will destroy the leads. Once they are in place, the leads can be twisted together and soldered on the reverse of the foam. As long as you don't need a lot of heat dissipation, this is an ideal material to use.

The 1st generation headlight was created pretty quickly and was not without flaws, but these were addressed in the next generation headlight which is currently used in the system. Deciding where and how to mount the lights posed yet another problem. My first thought was to fasten the headlight to the plastic piece holding the front reflector just above the fender. This would still allow a front basket or bag to be used on the handlebars, but the plastic piece could not support the weight of the headlight and didn't look right anyway. The headlight was remounted at the top of the front fork, just under the handlebar.

The taillight was a bit easier to deal with thanks to the book rack I installed over the rear fender. At the end of the rack is a removable plastic piece which must have been intended for a small license plate. I was able to drill two small holes into one of the metal headlamps and bolt this plastic piece to it. Then, the taillight was inserted back into the rear of the rack. The taillight housing was eventually painted black to match it's surroundings.

Electrical Design

After sketching a few rough ideas in my notebook, I went to work designing a circuit layout with Eagle PCB designer. My first draft consisted of a network of logic gates and flip-flops. The output of each gates would then provide the gate voltage necessary to "turn on" or "turn off" a group of logic level MOSFETs. These transistors would then provide the current channel for the LED strings. Unlike a typical automobile which uses two completely separate lights for "dim" and "bright," my design uses the same group of LEDs for both. Each group of LEDs is then connected to two MOSFETs, each with a different sized current limiting resistor. In this setup, only one of the MOSFETs would be on at a time providing either a low current path (dim) or a high current path (bright) for the LEDs. This same idea is used with the brakes and taillights. The problem with this circuit is scalability. Adding more features means adding more parts.
CycleLux Version 1

It's time to turn to microcontrollers. I chose the Atmel ATtiny25 MCU because I am familiar with AVR chips and because I had a few of this model laying around. Although this MCU does not have many I/O pins, more can be added by use of a data bus. This chip has a built in universal serial interface (USI) which can act as a few different types of buses. I chose to use the serial peripheral interface (SPI) bus to communicate with an MCP23S17 I/O expander from Microchip, again, primarily because I had a few of those chips laying around.

The result was a much cleaner circuit with a lot fewer parts and more control possibilities. The I/O expander reads in data from switches and drives the MOSFET gates to turn the LED strings on or off. For power, any regulator will do as long as it is within the voltage range of all of the chips. For the MOSFETs I was using, I needed a logic level of 5 volts.

CycleLux Version 3

Software Design

The overall flow of the software is pretty straightforward:
  1. Idle until some switch is pressed.
  2. Decide what outputs to drive based on the switch input states.
  3. Loop back to the beginning.

Check out the CycleLux program files!

Rather than try to get the USI module on the MCU working, I wrote a simple "bit bang" algorithm to communicate with the MCP23S17. In this code example, the CLEAR_XX and SET_XX macros, as well as the user defined pins DO (data out), DI (data in), and SCK (serial clock), are defined in a header file.

// Bit Bang 8 Bits on SPI Data Bus
unsigned char SPI_bitBang(uint8_t byte)
  uint8_t bit = 0;
  for(bit = 0; bit < 8; bit++)
    if(byte & 0x80) SET_DO;        // If bit(7) of "byte" is high
    else CLEAR_DO;                 // if bit(7) of "byte" is low
    byte <<= 1;                    // Shift "byte" to the left by one bit
    SET_SCK;                       // Serial Clock Rising Edge
    byte |= (PINB & U_DI);         // Set bit(0) of "byte" to data in value
    CLEAR_SCK;                     // Serial Clock Falling Edge
  return byte;                     // Returns shifted data in value

One major concern I had was switch bounce. If the switches "bounce" when being pressed, the MCU will think they are being pressed and depressed multiple times in a row and will set the output states to some random value. To remedy this, whenever the MCU recognizes that a switch has been pressed, it delays for so many milliseconds before checking the switch state again and deciding what to do.

unsigned char debounce_switch(void)

  uint8_t state = 0x00;
  delay_ms(MS_DEBOUNCE);                       // Delay for so long
  state = read_MCP23S17(MCP_000_RD, GPIOA);    // Check Button Status
  return state;                                // return switch state

unsigned char check_switch(uint8_t input)
  uint8_t state = 0x00;
  switches = read_MCP23S17(MCP_000_RD, GPIOA); // Check Button Status
  if(switches & input){                        // Check for a particular switch
    switches = debounce_switch();              // Debounce Switch
    if(switches & input) state = 1;            // Check again after debounce
  return state;                                // return switch state

The next challenge to overcome was creating the interrupt routines that flash the left, right, and side lights, but this was handled using simple counters and delays. The program would check the current state of each blinker output and simply toggle that state when the appropriate counter was up.

Finally, a routine to rapidly flash the brakes was added. This was a bit more complicated then the simple blinker flashing because the brakes will only flash a few times before remaining constantly on instead of continuously flashing. For this to work, a second counter was incremented with each flash of the brakes until a set number was reached. At that time, the brake flashing routine would be skipped, and they would remain on as long as the brake lever(s) were held in.

Planning for the Future

The Long Road Bike Trail Ahead

With the entire system installed and working perfectly, the only thing left to do is plan for future versions. The only known major problem is a crack on the back side of the headlight housing which has been generously coated in multiple layers of epoxy. A metal housing would be more durable and potentially lighter than the solid glass housing currently in use. Another little quirk which I decided not to work out in the software was an unexpected flashing ability of the head/taillights. Whenever the dim switch is held in indefinitely, the software will run through it's normal de-bounce routine and toggle the lights accordingly. That means that while the button is held in, the lights will continuously turn on and off each time the software recycles. Similarly, when the bright switch is held in, the bright and dim lights will toggle back and forth each time the software recycles. This could be a useful feature if flashing the headlights would ever be more useful than turning on the hazards. I may write the ability to select this mode without having to hold in the button into a future version of the code.

Also, I would eventually like to replace the bulky circuit with a surface mount board housing all of the parts and switches, but I have plenty enough else to keep me busy then to try and upgrade things that are working fine as is.

The Completed System    


Here is a video of the project from start to finish including the various lighting mode tests.

My wife and I were wanting a new set of bikes, so we decided on two 7-speed beach cruisers. Of course, I got the joy of assembling them piece by piece.

We really enjoy the look and feel of these bikes. We also get a lot of compliments on them.

Not much progress was made trying to cut off the lamp face.

Manually poking all of the lead holes can be a real pain!

The original headlight placing didn't work out as planned or look that good.

The taillight fits like a glove.

The back of the first generation headlight...what a mess!

LEDs on the first generation headlight...the clear LEDs serve as dim and bright lights.

The second generation headlight fitted inside of the lamp housing looks much nicer than the original. Even the yellow and orange blinkers are clear when not illuminated, and the black backing is less noticeable.

The taillight is modeled after the 2nd gen. headlight. Here, the LED leads are being twisted in preparation for soldering.

The completed MCU circuit on a breadboard for testing.

It's a mess of wires after the switches and indicators are soldered to the first generation control board.

The 2nd generation controller is much cleaner than the first. It forgoes the soldered perf-board in favor of pin to pin soldering. This reduced the size immensely and gave better access to the chips which may need replaced.

Plexiglass and hot glue make up the casing for the control box. A coating of liquid electric tape will seal it and provide the desired color of black. The bottom panel is still removable for access to the chips.

The control box is mounted in an easily accessible spot under the right hand gear shift. All of the buttons are reachable by the thumb, so the hands never have to leave the grips.

Each aspect of the system must be tested. Here, the side and taillights are working properly when the dim lights are turned on. The appropriate side lights will also blink as a turn signal.

The headlight and side lights shine in the dark.

Visibility has gone from 0% to something a bit more favorable.

If you are considering a similar project, check out the attached zip file containing all of the source files for the MCU as well as the latest schematic for use in Eagle PCB layout designer!