ericBcreator
Published © LGPL

NeoPixel Multiple Ring Animation

A simple project trying out animations on a matrix of 5 NeoPixel rings.

IntermediateShowcase (no instructions)1 hour1,009
NeoPixel Multiple Ring Animation

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Multiple neopixel ring
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Adafruit Neopixel wiring diagram

Code

6 ring neopixel animation

Arduino
/*
**********************************************************************
* Neopixel Multiple Ring animation by ericBcreator
* Designed to be used with an Arduino UNO, Nano or compatible device.
**********************************************************************
* version 1.0 - Last update 20200118 by ericBcreator
*
* This code is free for personal use, not for commercial purposes.
* Please leave this header intact.
*
* contact: ericBcreator@gmail.com
**********************************************************************
* Components:
* - Arduino Nano
* - Multi Neopixel Ring, 6 rings with 1+2+8+12+16+32 leds
**********************************************************************
*/ 

//
// debug settings
//

//#define DEBUG                                 // print debug messages
//#define DEBUGCHECKPIXEL0                      // visual check which pixel is at 0 (after MAIN_PIXEL_OFFSET), sets it off after the startup fade in (also the 0 pixel of a 2nd ring)

#ifdef DEBUG
  #define DEBUGPRINT(x)   Serial.print(x)
  #define DEBUGPRINTLN(x) Serial.println(x)
#else
  #define DEBUGPRINT(x)
  #define DEBUGPRINTLN(x)
#endif

//
// definitions
//

#define SIGNAL_PIN              6               // @EB-setup the digital output pin
#define NUM_OF_PIXELS          93               // the number of pixels
#define MAIN_PIXEL_OFFSET       1               // offset for pixel 0

byte ledNumOfRings  = 6;                        // number of rings
int ledPos[][2] = {                             // positions of the leds for each ring. note: start with 0
  { 0, 31},
  {32, 55},
  {56, 71},
  {72, 83},
  {84, 91},
  {92, 92}
};

//
// includes
//

#include <Adafruit_NeoPixel.h>

//
// settings
//

int maxBrightness = 30;
int ledBrightness = maxBrightness;

int flowDelay = 60;

int circleDelay = 20;

int fadeStep = 2;

int sparkleDelay = 40;
int sparkleCount = 350;
int sparkleRandomMax = 100;
int sparkleRandomLimit = 40;

int ringsDelay = 40;
int ringsCycleDelay = 475;
int ringsCount = 350;

int circleFadeDelay = 40;
int circleFadeCycleDelay = 60;
int circleFadeCount = NUM_OF_PIXELS * 5;

//
// setup variables
//

int pixelOffset = 0;
int colorRange = 0;

uint32_t stripColor[NUM_OF_PIXELS + 6];

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_OF_PIXELS, SIGNAL_PIN, NEO_GRB + NEO_KHZ800); // grb

//
// setup
//

void setup() {
  #ifdef DEBUGPRINT
    Serial.begin(115200);
    DEBUGPRINTLN("Setup");
  #endif

  randomSeed(analogRead(0));

  pixels.begin();
  setPixelColors(true, 0, false);

  #ifdef DEBUGCHECKPIXEL0
    DEBUGPRINTLN("Check pixel 0");
    setOneLedRing(1, 0, pixels.Color(20, 20, 20));
    pixels.show();
    checkAndDelay(7500);
  #endif
}

//
// main loop
//

void loop() {  
  DEBUGPRINTLN("Main loop");

  setStripColorsRainbow();
  circleIn();
  circleOut();
  flow();

  rainbow();
  circleFade();
  ringsFade();
  
  sparkleFade();

} // loop

//
// functions
//

unsigned long checkAndDelay(int delayTime) {
  unsigned long startTime = millis();
  unsigned long result = 0;
  
  while ((millis() - startTime) < delayTime) {
    delay(1);
  }
  return 0;
} // checkAndDelay

//
// functions for animations
//

void flow() {
  DEBUGPRINTLN("  Anim: Walk");

  // blue circle in and out
  setStripColors(true, 0, "B");    inToOut(true);  outToIn(false);
  setStripColors(true, 0, "RG");   inToOut(true);  outToIn(false);

  // multiple colors circle in and out  
  setStripColors(true, 0, "R");    inToOut(true);
  setStripColors(true, 0, "G");    inToOut(true);
  setStripColors(true, 0, "B");    inToOut(true);
  setStripColors(true, 0, "RB");   inToOut(true);
  setStripColors(true, 0, "GB");   inToOut(true);
  setStripColors(true, 0, "RG");   inToOut(true);
  setStripColors(true, 0, "RGB");  inToOut(true);
  outToIn(false);

  // RGB circle in and out
  setStripColors(false, 0, "R"); setStripColors(false, 1, "G"); setStripColors(false, 2, "B");  
  setStripColors(false, 3, "R"); setStripColors(false, 4, "G"); setStripColors(false, 5, "B");

  inToOut(true);  inToOut(false);
  inToOut(true);  inToOut(false);

  outToIn(true);  outToIn(false);
 
  inToOut(true);  outToIn(false);
  inToOut(true);  outToIn(false);

} // flow()

void inToOut(bool onOff) {
  for (int i = ledNumOfRings - 1; i >= 0; i--) { 
    setPixelColors(false, i, onOff); 
    checkAndDelay(flowDelay); 
  }    
} // inToOut

void outToIn(bool onOff) {
  for (int i = 0; i <= ledNumOfRings; i++) {     
    setPixelColors(false, i, onOff); 
    checkAndDelay(flowDelay); 
  }    
} // outToIn

void circleIn() {
  DEBUGPRINTLN("  Anim: Circle in");
  
  for (int i = 0; i < NUM_OF_PIXELS; i++) {
    setOneLed(i - MAIN_PIXEL_OFFSET, stripColor[(i + pixelOffset) % NUM_OF_PIXELS]);
    pixels.show();
    checkAndDelay(circleDelay);
  }
} // circleIn

void circleOut() {
  DEBUGPRINTLN("  Anim: Circle out");
  
  for (int i = 0; i < NUM_OF_PIXELS; i++) {
    setOneLed(i - MAIN_PIXEL_OFFSET, 0);
    pixels.show();    
    checkAndDelay(circleDelay);
  }
} // circleOut

void rainbow() {
  DEBUGPRINTLN("  Anim: Rainbow");
  
  for (int j = 0; j < 4 * 256; j++) {
    for (int h = ledNumOfRings - 1; h >= 0; h--) {
      for (int i = ledPos[h][0]; i <= ledPos[h][1]; i++) {
        stripColor[i] = wheel((i+j) & 255);
      }
      setPixelColors(false, h, true); 
    }
  }
} // rainbow

void sparkleFade() {
  DEBUGPRINTLN("  Anim: Fading sparkles");
  
  int j, i, maxLoop, pixel;
  int fadePos[NUM_OF_PIXELS] = {};
  int fadeDir[NUM_OF_PIXELS] = {};
  
  maxLoop = sparkleCount + (maxBrightness / fadeStep);

  for (j = 0; j < maxLoop; j++) {
    if (j < sparkleCount) {                                     // stop adding sparkles after reaching the max...
      setStripColorsRainbowCycle();
      if (random(sparkleRandomMax) < sparkleRandomLimit) {
        pixel = random(NUM_OF_PIXELS);
        if (fadeDir[pixel] == 0)
          fadeDir[pixel] = 1;
      }
    } else if (j == sparkleCount) {                             // ...then fade out the sparkles 
      for (i = 0; i < NUM_OF_PIXELS; i++) {
        if (fadeDir[i] == 1) 
          fadeDir[i] = 2;
      }      
    }
    
    plotFadingPixels(fadePos, fadeDir);
    checkAndDelay(sparkleDelay);
  }
} // sparkleFade

void ringsFade() {
  DEBUGPRINTLN("  Anim: Fading rings");

  static long int startCycleTime;
  
  int j, i, maxLoop;
  int ringNum = ledNumOfRings - 1, ringDir = -1;
  int fadePos[NUM_OF_PIXELS] = {};
  int fadeDir[NUM_OF_PIXELS] = {};
  
  maxLoop = ringsCount + (maxBrightness / fadeStep);

  for (j = 0; j < maxLoop; j++) {
    if (j < ringsCount) {
      setStripColorsRainbowCycle();
      if ((millis() - startCycleTime) > ringsCycleDelay) {
        startCycleTime = millis();
        for (int i = ledPos[ringNum][0]; i <= ledPos[ringNum][1]; i++)
          fadeDir[i] = 1;
        ringNum += ringDir;       
        
        if (ringNum < 0) { ringNum = 0; ringDir = -ringDir; }
        if (ringNum >= ledNumOfRings) { ringNum = ledNumOfRings - 1; ringDir = -ringDir; }
      }      
    } else if (j == ringsCount) {
      for (i = 0; i < NUM_OF_PIXELS; i++) {
        if (fadeDir[i] == 1) 
          fadeDir[i] = 2;
      }      
    }
    
    plotFadingPixels(fadePos, fadeDir);
    checkAndDelay(ringsDelay);
  }
} // ringsFade

void circleFade() {
  DEBUGPRINTLN("  Anim: Fading circle");

  static long int startCycleTime;
  
  int j, i, maxLoop;  
  int pixelNum = 0, pixelDir = -1;
  int fadePos[NUM_OF_PIXELS] = {};
  int fadeDir[NUM_OF_PIXELS] = {};
  
  maxLoop = circleFadeCount + (maxBrightness / fadeStep);

  for (j = 0; j < maxLoop; j++) {
    if (j < circleFadeCount) {
      setStripColorsRainbowCycle();
      if ((millis() - startCycleTime) > circleFadeCycleDelay) {
        startCycleTime = millis();
        fadeDir[pixelNum] = 1;
        pixelNum += pixelDir;
        
        if (pixelNum < 0) { pixelNum = 0; pixelDir = -pixelDir; }
        if (pixelNum >= NUM_OF_PIXELS) { pixelNum = NUM_OF_PIXELS - 1; pixelDir = -pixelDir; }
      }      
    } else if (j == circleFadeCount) {
      for (i = 0; i < NUM_OF_PIXELS; i++) {
        if (fadeDir[i] == 1) 
          fadeDir[i] = 2;
      }      
    }
    
    plotFadingPixels(fadePos, fadeDir);
    checkAndDelay(circleFadeDelay);
  }
} // ringsFade

void plotFadingPixels(int fadePos[], int fadeDir[]) {
  int r, g, b, i;
  uint32_t pixelColor;
  
  for (i = 0; i < NUM_OF_PIXELS; i++) {
    if (fadeDir[i] == 0) 
      pixels.setPixelColor(i, 0); 
      
    else {
      if (fadeDir[i] == 1) {
        fadePos[i] += fadeStep;
        if (fadePos[i] >= maxBrightness) {
          fadeDir[i] = 2;
          fadePos[i] = maxBrightness;
        }
      } else {
        fadePos[i] -= fadeStep;            
        if (fadePos[i] <= 0) {
          fadeDir[i] = 0;
          fadePos[i] = 0;
        }
      }
      
      pixelColor = stripColor[i];
      r = (pixelColor >> 16) * fadePos[i] / maxBrightness;
      g = ((pixelColor >> 8) & 0xFF) * fadePos[i] / maxBrightness;
      b = (pixelColor & 0xFF) * fadePos[i] / maxBrightness;
      pixelColor = pixels.Color(r, g, b);
      pixels.setPixelColor(i, pixelColor); 
    }
  }
  
  pixels.show();
} // plotFadingPixels

//
// functions for settings colors
//

void setStripColors(bool allRings, byte ringNum, String colorType) {
  int r = 0, g = 0, b = 0;
  int startRingNum = ringNum, endRingNum = ringNum;

  if (colorType.indexOf("R") >= 0) r = ledBrightness;
  if (colorType.indexOf("G") >= 0) g = ledBrightness; 
  if (colorType.indexOf("B") >= 0) b = ledBrightness;

  if (allRings) { startRingNum = 0; endRingNum = ledNumOfRings - 1; }

  for (int h = startRingNum; h <= endRingNum; h++) {  
    for (int i = ledPos[h][0]; i <= ledPos[h][1]; i++) {
      stripColor[i] = pixels.Color(r, g, b);
    }
  }
}

void setStripColorsRGB() {
  int r, g, b;
  colorRange = 2;
  
  r = ledBrightness;
  g = ledBrightness;  
  b = ledBrightness;

  for (int i = 0; i < NUM_OF_PIXELS ; i += 3) {
    stripColor[i] = pixels.Color(r, 0, 0);    
    stripColor[i+1] = pixels.Color(0, g, 0);
    stripColor[i+2] = pixels.Color(0, 0, b);
  }
}

void setStripColorsRainbow() {  
  for (int i = 0; i < NUM_OF_PIXELS; i++)
    stripColor[i] = wheel((i * 255 / NUM_OF_PIXELS));
}

void setStripColorsRainbowCycle() {
  static byte startPos;
  for (int i = 0; i < NUM_OF_PIXELS; i++)
    stripColor[i] = wheel((startPos + i) & 255);

  startPos += 2;
  startPos = startPos & 255;
}

void setPixelColors(bool allRings, byte ringNum, bool onOff) {
  int pixelCol;
  int startRingNum = ringNum, endRingNum = ringNum;

  if (allRings) { startRingNum = 0; endRingNum = ledNumOfRings - 1; }

  for (int h = startRingNum; h <= endRingNum; h++) {  
    for (int i = ledPos[h][0]; i <= ledPos[h][1]; i++) {
      pixelCol = i + pixelOffset;
      
      if (pixelCol > ledPos[h][1]) pixelCol = ledPos[h][0];
      if (pixelCol < ledPos[h][0]) pixelCol = ledPos[h][1];      

      if (onOff)
        setOneLedRing(h, i, stripColor[pixelCol]);
      else
        setOneLedRing(h, i, 0);
    }
  }
  
  pixels.show();
} // setPixelColors

void setOneLedRing(int ringNum, int pixel, uint32_t color) {
  int targetPixel;

  targetPixel = pixel + MAIN_PIXEL_OFFSET;
  if (targetPixel > ledPos[ringNum][1])
    targetPixel = ledPos[ringNum][0];

  pixels.setPixelColor(targetPixel, color); 
} // setOneLedRing

void setOneLed(int pixel, uint32_t color) {
  int targetPixel;

  targetPixel = pixel + MAIN_PIXEL_OFFSET;
  if (targetPixel > NUM_OF_PIXELS)
    targetPixel = NUM_OF_PIXELS;

  pixels.setPixelColor(targetPixel, color); 
} // setOneLedRing

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t wheel(byte wheelPos) {
  int r, g, b;
  wheelPos = 255 - wheelPos;
  
  if (wheelPos < 85) {
    r = 255 - wheelPos * 3;
    g = 0;
    b = wheelPos * 3;  
  } else if (wheelPos < 170) {
    wheelPos -= 85;
    r = 0;
    g = wheelPos * 3;
    b = 255 - wheelPos * 3;
  } else {
    wheelPos -= 170;
    r = wheelPos * 3;
    g = 255 - wheelPos * 3;
    b = 0;
  }

  r = (float) (r * ledBrightness / 255);
  g = (float) (g * ledBrightness / 255);
  b = (float) (b * ledBrightness / 255);
  
  return pixels.Color(r, g, b);
} // wheel

Credits

ericBcreator

ericBcreator

7 projects • 119 followers

Comments