Monday, September 4, 2017

Arduino / MOSFET Controlled High Bright LED Motorcycle Light

In our modern world, high bright LEDs can be purchased cheaply to provide low current draw auxiliary lighting to any vehicle.  Then it is only a simple matter of connecting the LED to 12VDC and head down the road enjoying your new found wattage.  However, there is no fun in the easy way.  Follow the instructions below to build your own custom high bright LED driver.
-----
OBJECTIVE: A high bright LED for installation on a Kawasaki KLR650 motorcycle with six programmable modes:
-----
To keep the project simple, an Ardunio Nano is used to control the Gate Voltage (Vgs) of a MOSFET.  When Vgs is HIGH the MOSFET switches on and the high bright LED turns on.  By using Pulse Width Modulation (PWM) on the Arduino the brightness of the high bright LED can be easily controlled.
-----
You will need the parts in the schematic.  All are readily available from Amazon or a host of electronic parts distributors.  Of course, the 12VDC power source is provided by the vehicle. 
---
On the bench the rig will look and function something like this:
 ----
The schematic leaves out some details that could be helpful.  To control the MODE selection and the STROBE effect we used a handlebar mounted switch. I also drilled a small hole to mount the STATUS LED into the handlebar switch.  With coded flashes, the STATUS LED lets the rider know the current mode of the rig.  Pressing the GREEN button selects the next mode.  Move the turn signal switch to "R" to turn on the STROBE effect.  The image below provides some real world connection details.  If you get the same handlebar switch we recommend buzzing out the wires first to verify them because the unit came with no diagram and low cost manufactures often change these details.
----
After you use the Arduino IDE to download the source code provided below into your Ardunio Nano you will need to mount to high bright LED.  We got a mounting bracket from eBay.  In the end it came out pretty nice.
-----
Here is a video of the rig running through all the modes.  The quick strobe at the beginning is a wake up self test.  The high bright LED swamps out the camera light sensor and doesn't provide a good indication of the actual effect.  One note:  It turns out Apple has a patent on the Breathing LED pattern (well, for a sleep indicator anyway).  Use the "breathing LED" portion of the code with caution or, I guess,  risk a cease and desist order.
-----
Here is the Arduino source code for the rig.  Good luck!
//------------------------------------------------------------------------
/*
KLR650 Aux LED Driver
July 2019
WhiskeyTangoHotel.Com
Ardunio Nano (should work with other Arduinos)

Program controls a IRF510 MOSFET to drive a High Bright LED Array
(I recommend a heat sink on the MOSFET, but it should be fine without it)
A button switch selects between modes
A switch sets the LED to fast strobe mode
*/

// MODES:
// 0 = OFF, Bright Examples (vars set below):
// 1 = Low% Bright
// 2 = Higher% Bright
// 3 = FULL BRIGHT
// 4 = Breath

int Number_of_Modes = 4;  // Needed for program control.
int LED_Mode = 1;  // LED_Mode sets the startup condition and is changed with button pushes in the main loop.
int Status_LED = 3;   // PWM output pin for the LED status light.
int FET_Drive = 5;  // PWM output pin to drive the gate on the MOSFET.
int mode_buttonPin = 4;  // Mode changing push button (wired to GND via 10K)
int strobe_buttonPin = 8;  // Mode changing push button (wired to GND via 10K)
boolean buttonState = LOW;  // for the mode_ and strobe_ detect

// Percent brightness of the 3 modes.  Example:  35% = .35, 100% = 1.00
// LED_Mode = 0 is OFF
float MODE1_Bright = .20;
float MODE2_Bright = .50;
// LED_Mode = 3 is FULL Bright: digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
// LED_Mode = 4 is Breath

int Breath_Rate = 15;  //Higher is faster
int Breath_Max_Bright = 170;
int Breath_Min_Bright = 20;
int Flash_delay = 50;  // sets delay for strobe mode and self test (50 is a good start)

void setup()
{
  // Serial commands are for debugging
  //Serial.begin(9600);
  //Serial.print(LED_Mode);
  //Serial.println();
  pinMode(Status_LED, OUTPUT);      // sets the digital pins as output
  pinMode(FET_Drive, OUTPUT);
  pinMode(mode_buttonPin, INPUT); // initialize the mode pushbutton pin as an input.  If HIGH change modes
  pinMode(strobe_buttonPin, INPUT); // if HIGH quick stobe/flash mode

  digitalWrite(Status_LED, 0);  // 0 turns the LED OFF
  digitalWrite(FET_Drive, 0);  

  // Self test loop.  Quick flash the status and high bright LED
  for (int i = 0; i <= 4; i++) {
    digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
    digitalWrite(FET_Drive, 255);
    delay(Flash_delay);   
    digitalWrite(Status_LED, 0);  // 0 turns the LED OFF
    digitalWrite(FET_Drive, 0);
    delay(Flash_delay);
  } // endSelf Test Loop
}   //end Setup

void stobe_on_button () {  // strobe/flash the LED when HIGH
  int buttonState = digitalRead(strobe_buttonPin);   // check if the pushbutton is pressed.
  if (buttonState == HIGH) {   // button is pressed, strobe the LEDs
    Serial.println(buttonState);
    digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
    digitalWrite(FET_Drive, 255);
    delay(Flash_delay);
   
    digitalWrite(Status_LED, 0);  // 0 turns the LED OFF
    digitalWrite(FET_Drive, 0);
    delay(Flash_delay);
    stobe_on_button ();  // check to see if strobe button is still pressed HIGH
  } // endif strobe_button HIGH 
}  // end of strobe_button function

void mode_change_button() {    // function to dectect the mode_buttonPin press to change modes (increment the state machine)
  int buttonState = digitalRead(mode_buttonPin);   // check if the pushbutton is pressed.
  if (buttonState == HIGH) {   // button is pressed, advance to next LED_Mode
    digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
    for (int x = 0; x < 25; x++) { // Quick flash the Status LED to confirm button press.
      digitalWrite(Status_LED, !digitalRead(Status_LED));  // toggle state of the on board blue LED. Shows program is running
      delay(100);  
    }  // endfor quick toogle Blue LED
     
    if (LED_Mode >= Number_of_Modes)  {  //  reset state machine to zer0 to recycle LED_Modes
      LED_Mode = 0;
    }
    else {
    LED_Mode = LED_Mode + 1;
    } 

  if (digitalRead(strobe_buttonPin) == HIGH) {
    LED_Mode = 0;  // this is a fast cycle to OFF.  The flash button AND the mode button are HIGH
  }
 
  }  // endif state_mode button pressed
}  // end of mode_change_button function

void loop()  {
  //Serial.print(LED_Mode);
  Serial.println(buttonState);
  Serial.println();

  // LED_Mode - OFF, no lights
  if (LED_Mode == 0) {
    analogWrite(Status_LED, 0);  // 0 turns the LED OFF
    analogWrite(FET_Drive, 0);   // 0 turns the MOSFET
  } // endif LED_Mode = 0

  // LED_Mode - Percent Brightness
  if (LED_Mode == 1) {
    analogWrite(FET_Drive, (255 *  MODE1_Bright));   // Percent Brightness = MODE1_Bright
    for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
      digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
      delay(100);      // endfor quick toogle Blue LED
      digitalWrite(Status_LED, 0);  // 0 turns LED OFF
      delay(100);      // endfor quick toogle Blue LED
    } //for match Status_LED with mode
    delay(600);
  } // endif LED_Mode = 1

    // LED_Mode - Percent Brightness
  if (LED_Mode == 2) {
    analogWrite(FET_Drive, (255 *  MODE2_Bright));   // Percent Brightness = MODE2_Bright
    for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
      digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
      delay(100);      // endfor quick toogle Blue LED
      digitalWrite(Status_LED, 0);  // 0 turns LED OFF
      delay(100);      // endfor quick toogle Blue LED
    } //for match Status_LED with mode
    delay(600);
  } // endif LED_Mode = 2

  // LED_Mode - Full Brightness
  if (LED_Mode == 3) {
    digitalWrite(FET_Drive, 255);   // FULL BRIGHT
    for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
      digitalWrite(Status_LED, 255);  // 255 turns LED FULL BRIGHT
      delay(100);      // endfor quick toogle Blue LED
      digitalWrite(Status_LED, 0);  // 0 turns LED OFF
      delay(100);      // endfor quick toogle Blue LED
    } //for match Status_LED with mode
    delay(600);
  } // endif LED_Mode = 3
 

  // LED_Mode - LED BREATHING
  if (LED_Mode == 4) {
    // Ramp up the brighness of the LED
    for (int i = Breath_Min_Bright; i <= Breath_Max_Bright; i++) {
      analogWrite(Status_LED, i);
      analogWrite(FET_Drive, i);
      float Breath_Delay = (exp(sin(i/2000.0*PI*10)) - 0.36787944)*108.0;
      delay(Breath_Delay/Breath_Rate);
      if (buttonState == HIGH) {   // check if the pushbutton is pressed.
        i = Breath_Max_Bright;
      }
    } 

    mode_change_button();  // check to see if mode_change button is pressed
    stobe_on_button ();   // check to see if strobe_button is pressed
   
    // Ramp down the brightness of the LED
    for (int i = Breath_Max_Bright; i >= Breath_Min_Bright; i--) {
      analogWrite(Status_LED, i);
      analogWrite(FET_Drive, i);
      float Breath_Delay = (exp(sin(i/2000.0*PI*10)) - 0.36787944)*108.0;
      delay(Breath_Delay/Breath_Rate);
      if (buttonState == HIGH) {   // check if the pushbutton is pressed.
        i = Breath_Min_Bright;
      }
    }
  } // endif LED_Mode 4

  mode_change_button();  // check to see if mode_change button is pressed
  stobe_on_button ();   // check to see if strobe_button is pressed

}
-----