DIY Smart Brake Light: Build a G-Force Sensing Bike Light

By Amy Allen December 02, 2025
DIY Smart Brake Light: Build a G-Force Sensing Bike Light

In This Guide

We are bridging the gap between basic safety gear and IoT technology. Here is what we are building today:

  • Understanding the MPU-6050 Accelerometer
  • Bill of Materials & Wiring Schematics
  • Coding the Deceleration Logic
  • 3D Printing and Weatherproofing the Enclosure

Standard bike tail lights are passive; they blink regardless of what the rider is doing. In modern traffic, you need to communicate your intentions clearly. By integrating a simple gyroscope and accelerometer into your lighting rig, we can build a light that flares bright red the moment you hit the brakes.

For the hobby bicyclist who loves to tinker, this project offers the perfect balance of utility and coding challenge. We will be using an Arduino microcontroller to read G-force data and drive a Neopixel LED ring, creating a "smart" safety device for under $20.


The Hardware Stack

To keep this unit compact enough to mount on a seat post, we need a small footprint. We are skipping the Raspberry Pi for this build—it's overkill and too power-hungry. Instead, we are using the Arduino Pro Micro (or Nano) coupled with the MPU-6050.

Bill of Materials
  • Arduino Pro Micro (5V)
  • MPU-6050 (3-Axis Accelerometer/Gyro)
  • WS2812B LED Ring (12 or 16 bits)
  • LiPo Battery (3.7V, 500mAh) + TP4056 Charger
  • Slide Switch & 3D Printed Case

Why the MPU-6050? This sensor communicates via I2C and is incredibly sensitive. It can detect the subtle pitch change of your bike climbing a hill versus the sharp G-force spike of squeezing the caliper brakes.


Wiring the Logic

The wiring is straightforward I2C communication. Since we are dealing with a moving vehicle, soldering connections is mandatory. Breadboards will not survive the vibrations of the road.

MPU-6050 Pin Arduino Pin Description
VCC 5V / VCC Power input
GND GND Common Ground
SCL A5 (or Pin 3 on Pro Micro) I2C Clock
SDA A4 (or Pin 2 on Pro Micro) I2C Data
Power Management Warning

If you are using a standard 5V Arduino, ensure your LiPo battery runs through a 5V boost converter or plug it into the `RAW` pin if the voltage regulator can handle the drop. Undervoltage can cause the accelerometer to freeze up mid-ride.


The Braking Algorithm

The code logic is where the magic happens. We don't want the light to trigger just because you hit a pothole. We need to filter the data to isolate longitudinal deceleration.

Step 1: Calibration

In your `setup()` loop, take 100 readings while the bike is stationary. Average these to find your "zero" point. This accounts for the angle at which you mounted the device on your seat post.

Step 2: Smoothing Data

Raw accelerometer data is noisy. Implementation of a Running Average or a Kalman Filter is essential. For this application, a simple weighted average works well:

currentAccel = (currentAccel * 0.9) + (newReading * 0.1);

Step 3: The Trigger

When the smoothed acceleration value drops below a specific negative threshold (indicating rapid slowing), switch the LED state from "Blink/Cruising" to "Solid Red/High Brightness."


Enclosure & Mounting

Electronics and rain do not mix. For the housing, PLA is acceptable for prototyping, but PETG or ABS is recommended for outdoor durability and UV resistance.

Design your case with a tight tolerance for the lens. Use a clear acrylic circle or print a thin layer of translucent filament to diffuse the harshness of the Neopixels.

Waterproofing Tip

Don't rely solely on the 3D print for waterproofing. Once your electronics are tested and working, coat the PCB (avoiding the barometer hole on the sensor if it has one) with Conformal Coating or clear nail polish to prevent corrosion.

The Source Code

Below is the complete sketch for the brake light. Before uploading, ensure you have installed the Adafruit MPU6050 and Adafruit NeoPixel libraries via the Arduino Library Manager.

BrakeLight_v1.ino C++
#include <Adafruit_NeoPixel.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

// --- CONFIGURATION ---
#define LED_PIN    6       // Pin connected to Neopixel Ring
#define LED_COUNT  12      // Number of LEDs on your ring
#define BRIGHT_DIM 30      // Brightness for cruising (0-255)
#define BRIGHT_MAX 255     // Brightness for braking (0-255)

// Sensitivity Threshold (Negative value for deceleration)
// Adjust this based on road tests. -2.0 is usually a good start.
#define BRAKE_THRESHOLD -2.0 

// Hardware Objects
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
Adafruit_MPU6050 mpu;

// Global Variables for Smoothing
float calibratedZero = 0;
float currentAccel = 0;
float alpha = 0.9; // Smoothing factor (Higher = smoother but more lag)

void setup() {
  Serial.begin(115200);

  // 1. Initialize LEDs
  strip.begin();
  strip.show(); 
  strip.setBrightness(BRIGHT_MAX);

  // 2. Initialize Sensor
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      // Flash Red to indicate error
      colorWipe(strip.Color(255, 0, 0), 50);
      delay(500);
      colorWipe(strip.Color(0, 0, 0), 50);
      delay(500);
    }
  }

  // 3. Calibration Sequence
  // Bike must be still during this phase!
  Serial.println("Calibrating... Keep bike still.");
  float total = 0;
  for(int i=0; i<100; i++) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    // Assuming Y-axis is pointing forward/backward
    total += a.acceleration.y; 
    delay(10);
  }
  calibratedZero = total / 100.0;
  
  // Flash Green to indicate ready
  colorWipe(strip.Color(0, 255, 0), 20);
  delay(500);
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // Get raw Y-axis acceleration (longitudinal)
  float rawAccel = a.acceleration.y;

  // Subtract the calibration offset
  float correctedAccel = rawAccel - calibratedZero;

  // Apply Low Pass Filter (Smoothing)
  currentAccel = (currentAccel * alpha) + (correctedAccel * (1.0 - alpha));

  // --- LOGIC CHECK ---
  // If deceleration is stronger than threshold
  if (currentAccel < BRAKE_THRESHOLD) {
    // BRAKING: All Red, Full Brightness
    setAllColor(255, 0, 0); 
  } else {
    // CRUISING: Red, Dimmed (Tail light mode)
    // Optional: Add a "Knight Rider" scanner effect here for visibility
    setAllColor(BRIGHT_DIM, 0, 0); 
  }

  delay(50); // Loop rate ~20Hz
}

// --- HELPER FUNCTIONS ---

// Set all LEDs to a specific RGB color
void setAllColor(int r, int g, int b) {
  for(int i=0; i

Ready to share your build?

Join the Great Meets community and join The Maker Team group for the 3D printer files for this project. Post your own variations and get feedback from other Maker cyclists!