/ Flora_Demos / Example_4_Accelerometer_LED / Example_4_Accelerometer_LED.ino
Example_4_Accelerometer_LED.ino
  1  // SPDX-FileCopyrightText: 2019 Tony DiCola for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  // Example of rotating accelerometer to change NeoPixel color.
  6  // Author: Tony DiCola
  7  // License: MIT
  8  #include <Adafruit_NeoPixel.h>
  9  #include <Wire.h>
 10  #include <SPI.h>
 11  #include <Adafruit_LIS3DH.h>
 12  #include <Adafruit_Sensor.h>
 13  
 14  
 15  #define PIXEL_PIN        8  // Pin connected to NeoPixels.  Use 8 for the NeoPixel built into Flora V2.
 16  
 17  #define PIXEL_COUNT      1  // Number of NeoPixels.
 18  
 19  #define PIXEL_TYPE       NEO_GRB + NEO_KHZ800  // NeoPixel type, stick with default unless using different pixels.
 20                                                 // See the NeoPixel Uberguide for information on different types:
 21                                                 //   https://learn.adafruit.com/adafruit-neopixel-uberguide/overview
 22  
 23  #define COLOR_MIN        Adafruit_NeoPixel::Color(255, 0, 0)  // RGB color for minimum axis value.
 24  
 25  #define COLOR_MAX        Adafruit_NeoPixel::Color(0, 0, 255)  // RGB color for maximum axis value.
 26  
 27  #define AXIS_MIN         -2000  // Minimum axis value, when at this or below the pixel color is the minimum color above.
 28  
 29  #define AXIS_MAX         2000   // Maximum axis value, when at this or above the pixel color is the maximum color above.
 30  
 31  #define ACCEL_RANGE      LIS3DH_RANGE_4_G  // Range of acceleration values for the LIS3DH.  Can
 32                                             // change to 2G, 4G, 8G, or 16G values.
 33  
 34  #define SAMPLE_SIZE      4                 // Number of samples to use for a moving average of
 35                                             // on each accelerometer axis.  This smoothes out the
 36                                             // readings so they're less noisey.
 37  
 38  
 39  // Create NeoPixel object.
 40  Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
 41  
 42  // Create LIS3DH accelerometer library object, this will by default use an I2C connection.
 43  Adafruit_LIS3DH accel = Adafruit_LIS3DH();
 44  
 45  // Keep a moving average of the last few accelerometer samples to smooth out the readings.
 46  // This helps reduce random noise and spikes/jumps in the data.
 47  long x_samples[SAMPLE_SIZE] = { 0 };
 48  long y_samples[SAMPLE_SIZE] = { 0 };
 49  long z_samples[SAMPLE_SIZE] = { 0 };
 50  
 51  
 52  void lightPixels(uint32_t color, Adafruit_NeoPixel& strip) {
 53    // Light all the NeoPixels in the strip with the provided color.
 54    for (int i=0; i < strip.numPixels(); ++i) {
 55      strip.setPixelColor(i, color);
 56    }
 57    strip.show();
 58  }
 59  
 60  uint32_t colorLerp(float x, float x0, float x1, uint32_t c0, uint32_t c1)
 61  {
 62    // Simple linear interpolation of a color within the range c0, c1 based on
 63    // a value x that falls within the range of x0, x1.  The Arduino map function
 64    // is similar but only works on signed integer values.
 65    // First clamp x to be in the provided range.
 66    x = constrain(x, x0, x1);
 67    // Next compute the scaling factor based on X's position between x0 and x1.
 68    float scale = (x-x0)/(x1-x0);
 69    // Pull out the red, green, blue component values from each min/max color.
 70    uint8_t c0_red   = (c0 >> 16) & 0xFF;
 71    uint8_t c1_red   = (c1 >> 16) & 0xFF;
 72    uint8_t c0_green = (c0 >> 8) & 0xFF;
 73    uint8_t c1_green = (c1 >> 8) & 0xFF;
 74    uint8_t c0_blue  = c0 & 0xFF;
 75    uint8_t c1_blue  = c1 & 0xFF;
 76    // Scale each color component independently, then reassemble into a new color.
 77    uint8_t red   = c0_red   + (c1_red   - c0_red  ) * scale;
 78    uint8_t green = c0_green + (c1_green - c0_green) * scale;
 79    uint8_t blue  = c0_blue  + (c1_blue  - c0_blue ) * scale;
 80    return Adafruit_NeoPixel::Color(red, green, blue);
 81  }
 82  
 83  void addSample(long newSample, long* samples) {
 84    // Add a new sample to the array of samples.  Will shift out the earliest sample
 85    // to make room for the new sample.
 86    memmove(samples, samples+1, SAMPLE_SIZE-1);
 87    samples[SAMPLE_SIZE-1] = newSample;
 88  }
 89  
 90  long avgSample(long* samples) {
 91    // Return the average sample value in the provided array of samples.
 92    long result = 0;
 93    for (int i=0; i < SAMPLE_SIZE; ++i) {
 94      result += samples[i];
 95    }
 96    return result/SAMPLE_SIZE;
 97  }
 98  
 99  void setup() {
100    // Initialize serial port to print accelerometer output.
101    Serial.begin(9600);
102    // Initialize LIS3DH accelerometer library.
103    if (!accel.begin()) {
104      Serial.println("Couldn't find LIS3DH, is it connected?");
105      while(1);
106    }
107    accel.setRange(ACCEL_RANGE);
108    // Initialize NeoPixels.
109    pixels.begin();
110  }
111  
112  void loop() {
113    // Take an accelerometer reading and add to lists of samples.
114    accel.read();
115    addSample(accel.x, x_samples);
116    addSample(accel.y, y_samples);
117    addSample(accel.z, z_samples);
118    // Now print out the average X, Y, Z sample values.
119    long x = avgSample(x_samples);
120    long y = avgSample(y_samples);
121    long z = avgSample(z_samples);
122    Serial.print("X:  ");
123    Serial.print(x); 
124    Serial.print("  \tY:  ");
125    Serial.print(y); 
126    Serial.print("  \tZ:  ");
127    Serial.println(z);
128    // Map the Y axis accelerometer value to a pixel color and light the pixels.
129    uint32_t color = colorLerp(y, AXIS_MIN, AXIS_MAX, COLOR_MIN, COLOR_MAX);
130    lightPixels(color, pixels);
131    // Delay to slow things down and prevent spamming serial port.
132    delay(100);
133  }
134