Project showcase
NeoPixel Multiple Ring Animation

NeoPixel Multiple Ring Animation © LGPL

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

  • 997 views
  • 0 comments
  • 3 respects

Components and supplies

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

Apps and online services

About this project

A simple project, trying out a few animations on a NeoPixel matrix from AliExpress consisting of 5 LED rings and 1 LED in the center (93 LEDs in total).

Preparing the LED rings

The 6 components are fixed to each other but not electronically connected, you need to solder all 5V connections together, as well as all ground connections.

You also have to solder the DO (digital out) connection of a ring to the DI (digital in) of the next. Make sure the flow continues (from DO to DI) or else the rings won't function correctly.

It is not the tidiest soldering job but it works fine.

Setup

The setup is easy: connect the power input and ground of the NeoPixels to the 5V output and ground of the Arduino and connect the DIN to pin 3 (best practice to add a 470 Ohm in between).

Note: if you set the brightness too high or add more LEDs, you might need to use an external power supply. I had no problems using the USB input of the Nano to power the LEDs.

Code

6 ring neopixel animationArduino
/*
**********************************************************************
* 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

Schematics

Adafruit Neopixel wiring diagram
Leds wiring diagram luuoqxwbfh katx58ab0n

Comments

Similar projects you might like

Arduino Clock with Neopixel Ring Animation

Project tutorial by Alexander

  • 53,284 views
  • 44 comments
  • 78 respects

NeoPixel Christmas (Color) Animation

Project tutorial by ericBcreator

  • 2,400 views
  • 2 comments
  • 7 respects

Stereo NeoPixel Ring VU Meter

Project showcase by ericBcreator

  • 61,041 views
  • 348 comments
  • 139 respects

Simple wall clock using Adafruit 1/4 60 Ring Neopixel

Project tutorial by antiElectron

  • 12,606 views
  • 4 comments
  • 48 respects

Clock Arduino Nano NeoPixel Ring Alarm/Timer Function

Project in progress by WannaDuino

  • 15,085 views
  • 21 comments
  • 49 respects

A Model Lighthouse Using an Adafruit NeoPixel Ring

Project tutorial by Jeremy Lindsay

  • 1,710 views
  • 2 comments
  • 9 respects
Add projectSign up / Login