This code and project is a proof of concept. The code works reasonably well, but needs a fair amount of work to make it a reliable.
When we first starting working on this project, I thought that the code would be the easy part. As I started working on the code, I quickly realized there are a lot of external factors that can give you erratic results from the accelerometer. Factors such as quick acceleration, bumpy roads, or slow braking gave me results that I wasn't prepared for.

Overall, though, this was a lot of fun to code, and it is a project that I will continue to tinker with until I am happy with the results. Here is the code that I came up with, and how it works.

You'll need to download and install the Adafruit_LSM303 library - we have a tutorial on installing arduino libraries here

Select Download Project Zip to get the Flora_Brakelight_Backpack.ino file.

// SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
//
// SPDX-License-Identifier: MIT

#include <Wire.h>
#include <Adafruit_LSM303.h>
#include <SPI.h>
#include <Adafruit_WS2801.h>

Adafruit_LSM303 lsm;

#define BRAKETHRESHOLD        350
#define BRAKETIMETHRESHOLD    200

int dataPin  = 2;    // Yellow wire on Adafruit Pixels
int clockPin = 3;    // Green wire on Adafruit Pixels
const int cPin = 11;
const int dPin = 6;

// Set the first variable to the NUMBER of pixels. 32 = 32 pixels in a row
// The LED strips are 32 LEDs per meter but you can extend/cut the strip
Adafruit_WS2801 strip = Adafruit_WS2801(36,dataPin,clockPin);

int start = 0;

int prevX = 0;
int currentX = 0;

int cState = 0;
int dState = 0;

long brakeTime = 0;

void setup() 
{
  Serial.begin(9600);
  
  // Start up the LED strip
  strip.begin();
  // Update the strip, to start they are all 'off'
  strip.show();
  // Try to initialise and warn if we couldn't detect the chip
  if (!lsm.begin())
  {
    Serial.println("Oops ... unable to initialize the LSM303. Check your wiring!");
    while (1);
  }
  pinMode(cPin, INPUT); 
  pinMode(dPin, INPUT);
}

void loop() 
{
  check_switches();      // when we check the switches we'll get the current state
  
  lsm.read();
  currentX = abs(lsm.accelData.x);
  
  if (start == 0){
    prevX = currentX;
    start = 1;
  }
  
  int i = currentX - prevX;

  if (abs(i) > BRAKETHRESHOLD) {
    brakeTime = millis();
    int strikes = 0;
    while ((abs(i) > BRAKETHRESHOLD) && (strikes < 3)) {
      if (abs(i) < BRAKETHRESHOLD) {
        strikes = strikes + 1; 
      }
      lsm.read();
      currentX = abs(lsm.accelData.x);
      i = currentX - prevX;
      
      if ((millis() - brakeTime) > BRAKETIMETHRESHOLD) {
        brakeLights(Color(255,0,0),250);
        while (abs(i) > BRAKETHRESHOLD) {
          lsm.read();
          currentX = abs(lsm.accelData.x);
          i = currentX - prevX;
          Serial.println(i);
          delay(100);
        }
        hideAll();
        brakeTime = millis();
        i = 0;
                  lsm.read();
          currentX = abs(lsm.accelData.x);
      }
    }
  }

  prevX = currentX;
  delay(200);
}

void check_switches()
{
  cState = digitalRead(cPin);
  dState = digitalRead(dPin);

  if (cState == HIGH) {     
    // left blinker
     Serial.println("left blink on"); 
    hideAll();
    leftTurn(Color(255,63,0),250);
    delay(300);
    Serial.println("left blink off");
    hideAll();
    delay(300);  
  }
  
  if (dState == HIGH) {     
    // right blinker
    Serial.println("right blink on"); 
    hideAll();
    rightTurn(Color(255,63,0),250);
    delay(300);
    Serial.println("right blink off");
    hideAll();
    delay(300);  
  }
}

void leftTurn(uint32_t c,uint8_t wait){
 innerLeftBottom(c);
 innerLeftTop(c);
   strip.show(); 
 delay(wait);
 hideAll();
 outerLeftTop(c);
 outerLeftBottom(c);
   strip.show(); 
 delay(wait);
 hideAll();
}

void rightTurn(uint32_t c,uint8_t wait){
 innerRightBottom(c);
 innerRightTop(c);
   strip.show(); 
 delay(wait);
 hideAll();
 outerRightTop(c);
 outerRightBottom(c);
   strip.show(); 
 delay(wait);
 hideAll();
}

void brakeLights(uint32_t c, uint8_t wait){
  innerRightBottom(c);
 innerRightTop(c);
 innerLeftBottom(c);
 innerLeftTop(c);
   strip.show(); 
 delay(wait);
 hideAll();
 outerLeftTop(c);
 outerLeftBottom(c);
 outerRightTop(c);
 outerRightBottom(c);
   strip.show(); 
 delay(wait);
 hideAll();
}


/* Helper functions */

//Input a value 0 to 384 to get a color value.
//The colours are a transition r - g - b - back to r

void outerRightBottom(uint32_t c){
  for (int i=0; i < 5; i++) {
    strip.setPixelColor(i, c);
  }
}
void outerRightTop(uint32_t c){
  for (int i=5; i < 10; i++) {
    strip.setPixelColor(i, c);
  }
}
void innerRightTop(uint32_t c){
  for (int i=10; i < 14; i++) {
    strip.setPixelColor(i, c);
  }
}
void innerRightBottom(uint32_t c){
  for (int i=14; i < 18; i++) {
    strip.setPixelColor(i, c);
  }
}

void innerLeftBottom(uint32_t c){
  for (int i=18; i < 22; i++) {
    strip.setPixelColor(i, c);
    strip.show();
  }
}

void innerLeftTop(uint32_t c){
  for (int i=22; i < 26; i++) {
    strip.setPixelColor(i, c);
  }
}

void outerLeftTop(uint32_t c){
  for (int i=26; i < 31; i++) {
    strip.setPixelColor(i, c);
  }
}
void outerLeftBottom(uint32_t c){
  for (int i=31; i < 36; i++) {
    strip.setPixelColor(i, c);
  }
}

void hideAll(){
  for(int i = 0; i > strip.numPixels();i++){
   strip.setPixelColor(i,Color(0,0,0));
  }
  strip.show();
}

// Create a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
  uint32_t c;
  c = r;
  c <<= 8;
  c |= g;
  c <<= 8;
  c |= b;
  return c;
}

Code Walkthrough

#include <Wire.h>
#include <Adafruit_LSM303.h>
#include <SPI.h>
#include <Adafruit_WS2801.h>

Adafruit_LSM303 lsm;

#define BRAKETHRESHOLD        350
#define BRAKETIMETHRESHOLD    200

The most important part of the code is the LSM303 library, the WS2801 library, and the BRAKETHRESHOLD, and BRAKETIMETHRESHOLD values. You will need to install the LSM303 library, which can be found here, and the WS2801 library, which can be found here.

The BRAKETHRESHOLD value will need to be tweaked to your liking. This value looks at the amount of force the accelerometer measures before it considers it worth investigating further. Similarly, the BRAKETIMETHRESHOLD value is the amount of time that the force exists before it will trigger the brake lights. This is an important part of the code, as it allows us to ignore things like big bumps in the road.

From there, the code is quite simple. If you press and hold the C button on the remote, the left blinker will activate on the backpack. If you press and hold the D button on the remote, the right blinker will activate on the backpack. Release either button to stop blinking. You could easily modify the sketch to press the button to turn on, and press again to turn off....or simply use the toggle type RF receiver which you can buy here.

This guide was first published on Feb 13, 2013. It was last updated on Feb 13, 2013.

This page (The Code) was last updated on Feb 13, 2013.

Text editor powered by tinymce.