Inflatable LED ball responds to bumps with bright lights.

First topic

Hey, this one’s about how I crammed a bunch of LEDs, accelerometer, and a battery into a clear inflatable ball. It worked, it was great fun for weeks, the ball eventually popped. I call it another completed project. :heavy_check_mark:

Reactive LED ball prototype
Reactive LED ball prototype

Hassles

Tuning the accelerometer was a small pile of trouble. Getting the ball to respond to the right frequency of successive acceleration peaks but not ‘double-trigger’ (“bounce” might be confusing here) proved tricky.

I ended up with a floor (baseline reading), threshhold (must peak past here to trigger), and de-bounce time (delay before another trigger is allowed). I have the LEDs fading quickly after each trigger to accentuate the next trigger.

You can see here how when I kick it it ‘double-triggers’ both from successive impacts and from some springy-ness netween the central tube and the outer ball.

Reactive LED ball prototype
Reactive LED ball prototype

Full Code

//This program loops through very fast and if the total acceleration is greater than the threshhold, it will increment the hue and set the brightness of the LEDs up to a mapped value. Otherwise it will slowly decrease the brightness of the LEDs.
#include <MPU9250_asukiaaa.h>

#include "FastLED.h"
//#include "printf.h"
//#define FASTLED_INTERRUPT_RETRY_COUNT 5
#define DATA_PIN  4
#define NUM_LEDS  144
//#define BRIGHTNESS  30
#define LED_TYPE  WS2811
#define COLOR_ORDER GRB
#define UPDATES_PER_SECOND  100

CRGB leds[NUM_LEDS];
int h = 0; //prelim hue value
int s = 255; //saturation value
int v = 0;   //prelim brightness value
int sampleLength = 40;  //milliseconds between brightness adjustments
int accelThreshhold = 230; //threshhold for peak detection based on (sum of measured accelerations in each axis * 100)
int accelLimit = 400;   //typical max acceleration - used to map measured acceleration values to brightness range
int hueIncrement = 32;  //amount to jump down the hue scale
int vLowerBound = 15; //lowest brightness to return to after acceleration spike
int lastPeak = 0;     //initialize acceleration peak time placeholder
int vMax = 235;       //max allowable brightness
int vIncrement = 4;   //every sampleLength, lower the brightness this much
int peakDelay = 2 00;  //peaks in accelleration must be at least this many milliseconds apart to be detected

MPU9250 mySensor;
uint8_t sensorId;
float aX, aY, aZ, aSqrt, gX, gY, gZ, mDirection, mX, mY, mZ;

void setup() {
  //while(!Serial);
  Serial.begin(115200);
  Serial.println("started");
  Wire.begin();
  mySensor.setWire(&Wire);
  mySensor.beginAccel();
  sensorId = mySensor.readId();
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
}

void loop() {
  mySensor.accelUpdate();
  aX = mySensor.accelX();
  aY = mySensor.accelY();
  aZ = mySensor.accelZ();

  double accelTotal = (abs(aX) + abs(aY) + abs(aZ))*100; //sum of measured accelerations in each axis * 100;
  if (accelTotal > accelThreshhold && millis() - lastPeak > peakDelay) {
    lastPeak = millis();
    v = map(constrain(accelTotal, 1, accelLimit), 1, accelLimit, 15, vMax);  //set up map of acceleration values to brightness values
    h = int(random(1, 255));
    Serial.println("Peak detected!");
    Serial.println("Acceleration: " + String(int(accelTotal))); //print accelTotal
    Serial.println("HSV Values: " + String(h) + ", " + String(s) + ", " + String(v)); //print HSV values
  }
  EVERY_N_MILLISECONDS(sampleLength) {  //slowly lower the brightness to 15
    if (v > vLowerBound) {
      v = v - vIncrement;
      Serial.println("Brightness now: " + String(v));
    }
  }
  FastLED.setBrightness(v);                 //publish to LEDs
  fill_solid(leds, NUM_LEDS, CHSV(h, s, v));
  FastLED.show();
}