Coding examples and challenges

official

#1

Discussion of Coding examples and challenges block from the LED Cube module.


#2

Hi Guys,
Finally got some time for myself to do some coding and I have created a Flux Capacitor program.
Yes I am still waiting to get my Hover Board(the one from the movie not the crappy baby segway) :grinning:
Enjoy my code!
Coyote

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

//   The Pin number on the Arduino the pixel LED's are connected too
#define PIN            6

//   How many NeoPixels are attached to the Arduino?
#define NUMPIXELS      96

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

uint32_t color_A = pixels.Color(255, 0, 0);
uint32_t color_B = pixels.Color(255, 128, 0);
uint32_t color_C = pixels.Color(255, 255, 0);
uint32_t color_D = pixels.Color(0, 255, 0);
uint32_t color_Red = pixels.Color(255, 0, 0);
uint32_t color_Orange = pixels.Color(255, 128, 0);
uint32_t color_Yellow = pixels.Color(255, 255, 0);
uint32_t color_Green = pixels.Color(0, 255, 0);
uint32_t color_Blue = pixels.Color(0, 0, 255);
uint32_t color_DkBlue = pixels.Color(0, 0, 102);
uint32_t color_LtBlue = pixels.Color(0, 204, 204);
uint32_t color_White = pixels.Color(255, 255, 255);
uint32_t color_Black = pixels.Color(0, 0, 0);
int wait = 400;

void setup() { 
  pixels.begin(); // This initializes the NeoPixel library.
  Serial.begin(9600); // initialize serial communication at 9600 bits per second:
}

void loop() {
  flux_capacitor();
  clear_all();
 }

void flux_capacitor(){
  for(int i=0; i<=5; i++){
    switch(i){
      case 0:
        color_A = color_DkBlue;
        color_B = color_Black;
        color_C = color_Black;
        color_D = color_Black;
        break;
      case 1:
        color_A = color_LtBlue;
        color_B = color_DkBlue;
        color_C = color_Black;
        color_D = color_Black;
        break;
      case 2:
        color_A = color_DkBlue;
        color_B = color_LtBlue;
        color_C = color_DkBlue;
        color_D = color_Black;
        break;
      case 3:
        color_A = color_Black;
        color_B = color_DkBlue;
        color_C = color_LtBlue;
        color_D = color_DkBlue;
        break;
      case 4:
        color_A = color_Black;
        color_B = color_Black;
        color_C = color_DkBlue;
        color_D = color_LtBlue;
        break;
      case 5:
        color_A = color_Black;
        color_B = color_Black;
        color_C = color_Black;
        color_D = color_DkBlue;
        break;
      default:
        color_A = color_Yellow;
        color_B = color_Black;
        color_C = color_Yellow;
        color_D = color_Black;
        break;
    }

    pixels.setPixelColor(0, color_A);
    pixels.setPixelColor(28, color_A);
    pixels.setPixelColor(47, color_A);
    
    pixels.setPixelColor(5, color_B);
    pixels.setPixelColor(25, color_B);
    pixels.setPixelColor(42, color_B);
    
    pixels.setPixelColor(10, color_C);
    pixels.setPixelColor(22, color_C);
    pixels.setPixelColor(37, color_C);
    
    pixels.setPixelColor(15, color_D);
    pixels.setPixelColor(19, color_D);
    pixels.setPixelColor(32, color_D);
    
    pixels.show();
    if (wait <= 100){
      delay(100);
    } else {
      delay(wait);
    }
  }
  if (wait <= 0){
    wait = 400;
  } else {
    wait -=10;
  }
  Serial.println(wait);
}

void clear_all(){
  for(int i=0; i<pixels.numPixels(); i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}

#3

I created a sketch to assign random colors to random LEDs, but I can’t see how to post the code without the editor screwing it up.


#4

Have you tried the code formatting button, to the right of bold & italic? That should preserve formatted code text.

//Example
#define PIN 6

The button looks like </>.


#5

I just tried this! This is awesome! :sunglasses:


#6

Thanks mkenig. It didn’t initially work, but I finally beat it into submission.

I found some time to play with the LED cube and created a sketch to assign colors randomly to pixels. Now I need to figure out something neat to do with the IMU.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

// Randomly display random colors on the LED cube

#define PIN 6

uint8_t wait = 10;  // change to increase or decrease flash rate of colors changing
uint8_t maxIntensity = 50;  // max color value is 255. Set to lower value to reduce intensity of colors
const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;
const uint8_t numPixelsPerFace = numRows * numCols; // not needed, just added to reduce computations
const uint16_t numPixels = numFaces * numPixelsPerFace;
uint8_t face = 0;
uint8_t row = 0;
uint8_t col = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  randomSeed(analogRead(0));
}

void loop()
{
  face = random(0, numFaces);
  row = random(0, numRows);
  col = random(0, numCols);
  strip.setPixelColor(getPixel(face, row, col), strip.Color(random(0, maxIntensity),
    random(0, maxIntensity), random(0,maxIntensity)));
  strip.show();
  delay(wait);
}

uint8_t getPixel(uint8_t face, uint8_t row, uint8_t col)
{
  // make sure indexes are valid
  if(face < numFaces && row < numRows && col < numCols)
  {
    return (face * numPixelsPerFace) + (row * numCols) + col;
  }

  // return 0 if invalid index
  return 0;
}

#7

That’s some cool code. Makes it a bit hypnotic watching the changing shifting colour pattern.


#8

Here are two more sketches for the LED cube. The first one flashes a random color on each face. The second one fills each face with a random color in a spiral in and then out pattern.

FlashFaces.ino:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

// Flash random colors on faces of LED cube

#define PIN 6

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

// these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint8_t wait = 50;         // reduce value to increase flash rate
uint8_t maxIntensity = 50;  // max value is 255. Set to lower value to reduce intensity of colors

Adafruit_NeoPixel thimbleCube = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  thimbleCube.begin();
  thimbleCube.show(); // Initialize all pixels to 'off'
  randomSeed(analogRead(0));
}

void loop()
{
  uint16_t pixelOffset(0);
  for (uint8_t face = 0; face < numFaces; face++)
  {
    uint32_t color = thimbleCube.Color(random(0, maxIntensity), random(0, maxIntensity), random(0,maxIntensity));
    for (uint8_t row = 0; row < numRows; row++)
    {
      for (uint8_t col = 0; col < numCols; col++)
      {
        thimbleCube.setPixelColor(pixelOffset++, color);
     }
    }
    thimbleCube.show();
    delay(wait);
  }
}

SpiralLights.ino:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

// Fill faces with a random color using a spiral in then out pattern.

typedef enum {FALSE, TRUE} bool;

// Set blankBetweenFills to TRUE to blank out the cube colors between pattern fills.
bool blankBetweenFills(FALSE);

#define PIN 6

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

// these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint8_t wait = 50;         // reduce value to increase flash rate
uint8_t maxIntensity = 50;  // max value is 255. Set to lower value to reduce intensity of colors

// pixel positions for pattern
uint8_t spiralIn[] = {0,1,2,3,7,11,15,14,13,12,8,4,5,6,10,9};
uint8_t spiralOut[] = {9,10,6,5,4,8,12,13,14,15,11,7,3,2,1,0};

uint32_t faceColor[numFaces];

Adafruit_NeoPixel thimbleCube = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  thimbleCube.begin();
  thimbleCube.show(); // Initialize all pixels to 'off'
  randomSeed(analogRead(0));
}

void loop()
{
  uint16_t pixelOffset(0);
  getFaceColors();
  for (uint16_t pixel = 0; pixel < numPixelsPerFace; ++pixel)
  {
    for (uint8_t face = 0; face < numFaces; ++face)
    {
      pixelOffset = face * numPixelsPerFace;
      thimbleCube.setPixelColor(pixelOffset + spiralIn[pixel], faceColor[face]);
    }
    thimbleCube.show();
    delay(wait);
  }
  delay(wait);
  getFaceColors();
  for (uint16_t pixel = 0; pixel < numPixelsPerFace; ++pixel)
  {
    for (uint8_t face = 0; face < numFaces; ++face)
    {
      pixelOffset = face * numPixelsPerFace;
      thimbleCube.setPixelColor(pixelOffset + spiralOut[pixel], faceColor[face]);
    }
    thimbleCube.show();
    delay(wait);
  }

  // blackout faces before repeating the pattern
  if (blankBetweenFills)
  {
    paintCube(0);
  }
  delay(wait);
}

void getFaceColors()
{
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    faceColor[face] = thimbleCube.Color(random(0, maxIntensity), random(0, maxIntensity), random(0,maxIntensity));
  }  
}

void paintCube(uint32_t color)
{
  for (uint8_t pixel = 0; pixel < numPixels; ++pixel)
  {
    thimbleCube.setPixelColor(pixel, color);
  }
  thimbleCube.show();
}

#9

Those are fantastic, great job!


#10

New Sketch here, I call this one the Rainbow Swirl Snake.
As you can see it utilizes an array to set the led order.

#include <Adafruit_NeoPixel.h>  // Spiral colors around the cube.
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN            6        // The Pin number on the Arduino the pixel LED's are connected too

uint8_t timer = 100;            // The higher the number, the slower the timing.
uint8_t ledPins[] = {
  10, 6, 5, 9, 13, 14, 15, 11, 7, 3, 2, 1, 0, 4, 8, 12, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51, 64, 65, 66, 67, 71, 20, 21, 22, 23, 36, 37, 38, 39, 52, 53, 54, 55, 68, 69, 70, 74, 75, 24, 25, 26, 27, 40, 41, 42, 43, 56, 57, 58, 59, 72, 73, 77, 78, 79, 28, 29, 30, 31, 44, 45, 46, 47, 60, 61, 62, 63, 76, 80, 81, 82, 83, 87, 91, 95, 94, 93, 92, 88, 84, 85, 86, 90, 89
};                              // an array of led numbers
uint8_t ledCount = 96;          // the number of leds (i.e. the length of the array)

Adafruit_NeoPixel thimbleSwirl = Adafruit_NeoPixel(ledCount, PIN, NEO_GRB + NEO_KHZ800);

uint32_t colorRed = thimbleSwirl.Color(25, 0, 0);
uint32_t colorOrange = thimbleSwirl.Color(25, 12, 0);
uint32_t colorYellow = thimbleSwirl.Color(25, 25, 0);
uint32_t colorGreen = thimbleSwirl.Color(0, 25, 0);
uint32_t colorBlue = thimbleSwirl.Color(0, 0, 25);
uint32_t colorPurple = thimbleSwirl.Color(25, 0, 25);
uint32_t colorBlack = thimbleSwirl.Color(0, 0, 0);

void setup() {
  thimbleSwirl.begin();
  thimbleSwirl.show();           // Initialize all pixels to 'off'
}

void loop() {                   // the array elements are numbered from 0 to (ledCount - 1).
                                // loop from the lowest led to the highest:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    int offSet1 = thisLed + 10;
    if (offSet1 >= ledCount){
      offSet1 -= ledCount;
    }
    int offSet2 = thisLed + 20;
    if (offSet2 >= ledCount){
      offSet2 -= ledCount;
    }
    int offSet3 = thisLed + 30;
    if (offSet3 >= ledCount){
      offSet3 -= ledCount;
    }
    int offSet4 = thisLed + 40;
    if (offSet4 >= ledCount){
      offSet4 -= ledCount;
    }
    int offSet5 = thisLed + 50;
    if (offSet5 >= ledCount){
      offSet5 -= ledCount;
    }
    int offSet6 = thisLed + 60;
    if (offSet6 >= ledCount){
      offSet6 -= ledCount;
    }
                                // turn the leds on:
    thimbleSwirl.setPixelColor(ledPins[offSet6], colorRed);
    thimbleSwirl.setPixelColor(ledPins[offSet5], colorOrange);
    thimbleSwirl.setPixelColor(ledPins[offSet4], colorYellow);
    thimbleSwirl.setPixelColor(ledPins[offSet3], colorGreen);
    thimbleSwirl.setPixelColor(ledPins[offSet2], colorBlue);
    thimbleSwirl.setPixelColor(ledPins[offSet1], colorPurple);
    thimbleSwirl.setPixelColor(ledPins[thisLed], colorBlack);
    thimbleSwirl.show();
    delay(timer);
  }
}

Happy Coding
Coyote


#11

Nice effect Coyote.

I just got back from a mini-vacation in Napa and now need to finish a spinner sketch.

Isn’t anybody else creating sketches for the LED cube?


#12

I’m still waiting for the toolkit because I don’t have too many tools. I got by fine on the robot, but didn’t have to cut much there (like stripping wires). Also, I’m proud to say my wife and I have a two-week old :slight_smile: Our first is 3.5 years old, so we’re adjusting to the new family of four.


#13

Congrats on new addition. I subscribed to Thimble for grand kids 12, 5 and 3. So far the 12 year old would rather play Mindcraft than solder, but I have hopes for the younger two.


#14

Wow, Easter long weekend and I got a few hours to myself to program. Amazing :slight_smile:

So anyway here is my latest cube animation. I built this on top of code styled by @Grandpa because I like the way he is using objects.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

//  scrolling patterns

#define PIN 6              //  pin the cube connects too

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

//  these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint16_t wait = 300;       //  reduce value to increase speed
uint8_t steps = 4;         //  number of steps in animation

Adafruit_NeoPixel thimbleCheck = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

// pixel positions for patterns
uint8_t checks[] = {0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0};
uint8_t slashs[] = {0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0,1,0,0,1,0,0,1,1,0,1,1,0,1,1,0,0};
uint8_t caps[] = {1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0};
uint8_t rings[] = {1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0};

// basic pixel colours
uint32_t colorRed = thimbleCheck.Color(25, 0, 0);
uint32_t colorOrange = thimbleCheck.Color(25, 12, 0);
uint32_t colorYellow = thimbleCheck.Color(25, 25, 0);
uint32_t colorGreen = thimbleCheck.Color(0, 25, 0);
uint32_t colorBlue = thimbleCheck.Color(0, 0, 25);
uint32_t colorPurple = thimbleCheck.Color(25, 0, 25);
uint32_t colorBlack = thimbleCheck.Color(0, 0, 0);

void setup() {
  thimbleCheck.begin();
  thimbleCheck.show();     //  Initialize all pixels to 'off'
}

void loop()
{
  //  scrolling pixels around the sides
  for (uint8_t stepNum = 0; stepNum < steps; ++stepNum){
    for (uint8_t face = 1; face < (numFaces - 1); ++face){
      uint16_t pixelOffset = face * numPixelsPerFace;
      for (uint16_t pixel = 0; pixel < numPixelsPerFace; ++pixel){
        uint16_t checkPosition =  stepNum * numPixelsPerFace + pixel;
        if (checks[checkPosition] == 1){  //  change checks to slashes for other scrolling layout
          thimbleCheck.setPixelColor(pixelOffset + pixel, colorBlue);  //  change for other colours
        } else {
          thimbleCheck.setPixelColor(pixelOffset + pixel, colorBlack);  //  change for other colours or leave black
        }
      }
    }
    // top and bottom pixels
    for (uint8_t face = 0; face < 2; ++face){
      if (face >= 1){
        face = 5;
      }
      uint16_t pixelOffset = face * numPixelsPerFace;
      for (uint16_t pixel = 0; pixel < numPixelsPerFace; ++pixel){
        uint16_t checkPosition =  stepNum * numPixelsPerFace + pixel;
        if (caps[checkPosition] == 1){  //  change caps to rings for other top and bottom layout
          thimbleCheck.setPixelColor(pixelOffset + pixel, colorBlue);  //  change for other colours
        } else {
          thimbleCheck.setPixelColor(pixelOffset + pixel, colorBlack);  //  change for other colours or leave black
        }
      }
    }

    thimbleCheck.show();   // show this frame and pause
    delay(wait);
  }
}

You may also note that while this example is creating a scrolling blue check(Police style), it can be changed to red(Fire Department style). I also have a slashes array there and orange colour to have a scrolling orange slash(Emergency Services style).

Happy coding!
Coyote


#15

Here’s a variation on @Coyote72’s scrolling blue check code - this divides each face into four squares and flashes alternate squares between white and the selected color (red, green or blue).

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

// Fill faces with a random color using a spiral in then out pattern.

typedef enum {FALSE, TRUE} bool;

// Set blankBetweenFills to TRUE to blank out the cube colors between pattern fills.
bool blankBetweenFills(TRUE);

#define PIN 6

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

// these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint8_t wait = 500;         // reduce value to increase flash rate
uint8_t maxIntensity = 100;  // max value is 255. Set to lower value to reduce intensity of colors

// pixel positions for pattern
const uint8_t numPixelsPerPattern = 8;
uint8_t pattern1[numPixelsPerPattern] = {0,1,4,5,10,11,14,15};
uint8_t pattern2[numPixelsPerPattern] = {2,3,6,7,8,9,12,13};

Adafruit_NeoPixel thimbleCube = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

uint32_t redColor = thimbleCube.Color(maxIntensity, 0, 0);
uint32_t greenColor = thimbleCube.Color(0, maxIntensity, 0);
uint32_t blueColor = thimbleCube.Color(0, 0, maxIntensity);

// set to red, green or blue
uint32_t selectedColor = blueColor;
 
uint32_t whiteColor = thimbleCube.Color(maxIntensity, maxIntensity, maxIntensity);

void setup() {
  thimbleCube.begin();
  thimbleCube.show(); // Initialize all pixels to 'off'
}

void loop()
{
  uint16_t pixelOffset(0);
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    pixelOffset = face * numPixelsPerFace;
    for (uint8_t pixel = 0; pixel < numPixelsPerPattern; ++pixel)
    {
      thimbleCube.setPixelColor(pixelOffset + pattern1[pixel], selectedColor);
      thimbleCube.setPixelColor(pixelOffset + pattern2[pixel], whiteColor);
    }
  }
  thimbleCube.show();
  delay(wait);

// now reverse the colors
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    pixelOffset = face * numPixelsPerFace;
    for (uint8_t pixel = 0; pixel < numPixelsPerPattern; ++pixel)
    {
      thimbleCube.setPixelColor(pixelOffset + pattern1[pixel], whiteColor);
      thimbleCube.setPixelColor(pixelOffset + pattern2[pixel], selectedColor);
    }
  }
  thimbleCube.show();
  delay(wait);
}

#16

I do not understand this coding at all. I’ve poured through the codes that you have put up and managed to come up with something very basic… don’t judge!

Take a look… I’m actually pretty proud that it turns anything on at all! I would love it if someone could help me understand the code that I’m creating here. I’ve started a new thread asking for some basics to understand the absolute fundamentals. Any help would be appreciated!

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN            6

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS      96

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() { 
  pixels.begin(); // This initializes the NeoPixel library.
  randomSeed(analogRead(0));
}
int a[]=  {2,1,4};
int b[]= {4,3,6,9,12};
int c[]= {2,11,14};
int d[]= {8,0,2,5,7,8,10,13,15};

void loop(){
  stripe(a,0);
  //delay(100);
  stripe(a,16);
  // delay(100);
  stripe(a,32);
  //delay(100);
  stripe(a,48);
  //delay(100);
  stripe(a,64);
  delay(500);
  stripe(a,80);
  //delay(100);
  stripe(b,0);
  //delay(100);
  stripe(b,16);
  //delay(100);
  stripe(b,32);
  //delay(100);
  stripe(b,48);
  //delay(100);
  stripe(b,64);
  //delay(100);
  stripe(b,80);
  delay(500);
  stripe(c,0);
  //delay(100);
  stripe(c,16);
  //delay(100);
  stripe(c,32);
  //delay(100);
  stripe(c,48);
  //delay(100);
  stripe(c,64);
  //delay(100);
  stripe(c,80);
  delay(500);
  fill(d,0);
  fill(d,16);
  fill(d,32);
  fill(d,48);
  fill(d,64);
  fill(d,80);
  delay(1000);
  clear_all();
  delay(1000);
}

void clear_all(){
  for(int i=0; i<pixels.numPixels(); i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}


void stripe(int letter[], int offset){
  for(int i=1;i<=letter[0];i++){
    pixels.setPixelColor(letter[i]+offset, pixels.Color(0,0,10)); // Moderately bright green color.
  } 
  pixels.show();
}

void fill(int letter[],int offset){
  for(int i=1;i<=letter[0];i++){
    pixels.setPixelColor(letter[i]+offset, pixels.Color(10,0,0));
  }
  pixels.show();
}

#17

Looks neat!


#18

Here’s a sketch that expands out from each face and then falls back in. The colors change with each cycle. Reduce variable wait to get an interesting affect.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 6

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

// these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint8_t wait = 100;         // reduce value to increase flash rate
uint8_t maxIntensity = 50;  // max value is 255. Set to lower value to reduce intensity of colors

// pixel positions for pattern
const uint8_t numPixelsPerOuter(12);
const uint8_t numPixelsPerInner(4);
uint8_t outerPixels[] = {0,1,2,3,4,7,8,11,12,13,14,15};
uint8_t innerPixels[] = {5,6,9,10};

Adafruit_NeoPixel thimbleCube = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

uint32_t outerColor;
uint32_t innerColor;

void setup()
{
  thimbleCube.begin();
  thimbleCube.show(); // Initialize all pixels to 'off'
  randomSeed(analogRead(0));
}

void loop()
{
  uint16_t pixelOffset(0);
  outerColor = thimbleCube.Color(random(0, maxIntensity), random(0, maxIntensity), random(0,maxIntensity));
  innerColor = thimbleCube.Color(random(0, maxIntensity), random(0, maxIntensity), random(0,maxIntensity));
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    pixelOffset = face * numPixelsPerFace;
    for (uint8_t outer = 0; outer < numPixelsPerOuter; ++outer)
    {
      thimbleCube.setPixelColor(pixelOffset + outerPixels[outer], outerColor);        
    }
  }
  thimbleCube.show();
  delay(wait);
  paintCube(0);
  delay(wait);
      
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    pixelOffset = face * numPixelsPerFace;
    for (uint8_t inner = 0; inner < numPixelsPerInner; ++inner)
    {
      thimbleCube.setPixelColor(pixelOffset + innerPixels[inner], innerColor);        
    }
  }
  thimbleCube.show();
  delay(wait);
  paintCube(0);
  delay(wait*4);
      
  for (uint8_t face = 0; face < numFaces; ++face)
  {
    pixelOffset = face * numPixelsPerFace;
    for (uint8_t inner = 0; inner < numPixelsPerInner; ++inner)
    {
      thimbleCube.setPixelColor(pixelOffset + innerPixels[inner], innerColor);        
    }
  }
  thimbleCube.show();
  delay(wait);
  paintCube(0);
  delay(wait);
}

void paintCube(uint32_t color)
{
  for (uint8_t pixel = 0; pixel < numPixels; ++pixel)
  {
    thimbleCube.setPixelColor(pixel, color);
  }
  thimbleCube.show();
}

#19

Minor combination of the Thimble dice code and the MPU6050-test code. With the following, the rainbow will continue until you shake the cube for a bit to trigger the motion threshold, at which point the dice roll will occur. I’ve played around some with various constants/parameters to find some settings that were pleasing to me.

// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
//      2013-05-08 - added multiple output formats
//                 - added seamless Fastwire support
//      2011-10-07 - initial release

/* ============================================================================
  I2Cdev device library code is placed under the MIT license
  Copyright (c) 2011 Jeff Rowberg

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  =============================================================================
*/

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN 6
#define INTERRUPT_PIN 2
#define NUMPIXELS 96

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
MPU6050 accelgyro;

// MPU control/status vars
bool dmpReady = false;   // set true if DMP init was successful
uint8_t mpuIntStatus;    // holds actual interrupt status byte from MPU
uint8_t devStatus;       // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;     // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;      // count of all bytes currently in FIFO
uint8_t fifoBuffer[64];  // FIFO storage buffer

// orientation/motion vars
Quaternion q;         // [w, x, y, z]        quaternion container
VectorFloat gravity;  // [x, y, z]           gravity vector
float ypr[3];         // [yaw, pitch, roll]  yaw/pitch/roll container and gravity vector

int yawLast;
int pitchLast;
int rollLast;
int yaw;
int pitch;
int roll;

int motionMeter = 0;

long int rainbowTime = 0;
bool rainbowStart = true;

// Interrupt Service Routine
volatile bool mpuInterrupt = false;  // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
  mpuInterrupt = true;
}

// 0 0 0 0
// 0 0 0 0
// 0 0 0 0
// 0 0 0 0

// start dice
// 1 = 0400
// 2 = 8020
// 3 = 8420
// 4 = A0A0
// 5 = A4A0
// 6 = AAA0

static const unsigned int dice[] = {
  /* cube face:

    0 0 0 0
    0 0 0 0
    0 0 0 0
    0 0 0 0

    for a single die, we are using the 3x3 square in the upper left corner of a single face of the cube

    so, 1 is represented as:

    0 0 0 0 = 0 in hex
    0 1 0 0 = 8 in hex (convert 0100 in binary to hex)
    0 0 0 0 = 0 in hex
    0 0 0 0 = 0 in hex

    and 5 is represented as:

    1 0 1 0 = A in hex
    0 1 0 0 = 4 in hex
    1 0 1 0 = A in hex
    0 0 0 0 = 0 in hex
  */

  //  0  1  2  3
  //  4  5  6  7
  //  8  9 10 11
  // 12 13 14 15

  0x0400, // = 1
  0x8020, // = 2
  0x8420, // = 3
  0xA0A0, // = 4
  0xA4A0, // = 5
  0xAAA0  // = 6
};

void display_die_face(uint8_t number, uint8_t offset, uint32_t color) {
  uint8_t n = number - 1;
  if (n < 0) n = 0;
  for (int i = 3; i >= 0; i--) {
    for (int j = 3; j >= 0; j--) {
      if (dice[n] & (1 << (i * 4 + j)) ) {
        pixels.setPixelColor((3 - i) * 4 + (3 - j) + offset, color);
      }
    }
  }
  pixels.show();
}

void display_die(uint8_t number, uint32_t color) {
  uint8_t n = number - 1;
  if (n < 0) n = 0;
  switch (n % 6) {
    case 0:   //1
      display_die_face(1, 0, color);
      display_die_face(2, 16, color);
      display_die_face(3, 32, color);
      display_die_face(5, 48, color);
      display_die_face(4, 64, color);
      display_die_face(6, 80, color);
      break;
    case 1:   //2
      display_die_face(2, 0, color);
      display_die_face(6, 16, color);
      display_die_face(3, 32, color);
      display_die_face(1, 48, color);
      display_die_face(4, 64, color);
      display_die_face(5, 80, color);
      break;
    case 2:   //3
      display_die_face(3, 0, color);
      display_die_face(6, 16, color);
      display_die_face(5, 32, color);
      display_die_face(1, 48, color);
      display_die_face(2, 64, color);
      display_die_face(4, 80, color);
      break;
    case 3:   //4
      display_die_face(4, 0, color);
      display_die_face(6, 16, color);
      display_die_face(2, 32, color);
      display_die_face(1, 48, color);
      display_die_face(5, 64, color);
      display_die_face(3, 80, color);
      break;
    case 4:   //5
      display_die_face(5, 0, color);
      display_die_face(6, 16, color);
      display_die_face(4, 32, color);
      display_die_face(1, 48, color);
      display_die_face(3, 64, color);
      display_die_face(2, 80, color);
      break;
    case 5:   //6
      display_die_face(6, 0, color);
      display_die_face(3, 16, color);
      display_die_face(2, 32, color);
      display_die_face(4, 48, color);
      display_die_face(5, 64, color);
      display_die_face(1, 80, color);
      break;
  }
}

void roll_die(uint32_t color) {
  long r = random(20, 40);
  for (int i = 1; i < r; i++) {
    clear_all();
    display_die(i % 7, color);
    delay(30 + 10 * (i));
  }
}

// One-time Setup
void setup() {

  pixels.begin();
  clear_all();
  randomSeed(analogRead(0));

  // join I2C bus (I2Cdev library doesn't do this automatically)
#if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE)
  Wire.begin();
  Wire.setClock(400000);
#elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
  Fastwire::setup(400, true);
#endif

  Serial.begin(115200);

  // initialize device
  Serial.println(F("Initializing I2C devices..."));
  accelgyro.initialize();
  pinMode(INTERRUPT_PIN, INPUT);

  // verify connection
  Serial.println(F("Testing device connections..."));
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

  Serial.println(F("Initializing DMP..."));
  devStatus = accelgyro.dmpInitialize();

  // run IMU_Zero.ino example to get offsets based on indivual MPU6050 unit
  accelgyro.setXAccelOffset(-3195);
  accelgyro.setYAccelOffset(-2411);
  accelgyro.setZAccelOffset(5027);
  accelgyro.setXGyroOffset(53);
  accelgyro.setYGyroOffset(-17);
  accelgyro.setZGyroOffset(54);

  if (devStatus == 0) {                   // make sure it worked (returns 0 if so)
    Serial.println(F("Enabling DMP..."));  // turn on the DMP, now that it's ready
    accelgyro.setDMPEnabled(true);

    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);  // enable Arduino interrupt detection
    mpuIntStatus = accelgyro.getIntStatus();

    Serial.println(F("DMP ready! Waiting for first interrupt..."));  // set our DMP Ready flag so the main loop() function knows it's okay to use it
    dmpReady = true;

    packetSize = accelgyro.dmpGetFIFOPacketSize();  // get expected DMP packet size for later comparison
  }
}

// Clear all pixels
void clear_all() {
  for (int i = 0; i < pixels.numPixels(); i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
}

// 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) {
  WheelPos = 255 - WheelPos;

  if (WheelPos < 85) {
    return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }

  if (WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }

  WheelPos -= 170;
  return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

// Set an entire cube side to one color
void colorSide(uint8_t startLED, uint32_t color) {
  startLED *= 16;
  for (int i = startLED; i < startLED + 16; i++) {
    pixels.setPixelColor(i, color);
  }
  pixels.show();
}

// Repeated loop
void loop() {

  // if programming failed, don't try to do anything
  if (!dmpReady) return;

  // wait for MPU interrupt or extra packet(s) available
  while (!mpuInterrupt && fifoCount < packetSize) {
  }

  // reset interrupt flag and get INT_STATUS byte
  mpuInterrupt = false;
  mpuIntStatus = accelgyro.getIntStatus();

  // get current FIFO count
  fifoCount = accelgyro.getFIFOCount();

  // check for overflow (this should never happen unless our code is too inefficient)
  if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
    // reset so we can continue cleanly
    accelgyro.resetFIFO();
    Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
  }
  else if (mpuIntStatus & 0x02) {
    while (fifoCount < packetSize) fifoCount = accelgyro.getFIFOCount();

    // read a packet from FIFO
    accelgyro.getFIFOBytes(fifoBuffer, packetSize);

    // track FIFO count here in case there is > 1 packet available
    // (this lets us immediately read more without waiting for an interrupt)
    fifoCount -= packetSize;

    accelgyro.dmpGetQuaternion(&q, fifoBuffer);
    accelgyro.dmpGetGravity(&gravity, &q);
    accelgyro.dmpGetYawPitchRoll(ypr, &q, &gravity);

    yaw = 100 * ypr[0];
    pitch = 100 * ypr[1];
    roll = 100 * ypr[2];

    Serial.print(yaw); Serial.print(", ");
    Serial.print(pitch); Serial.print(", ");
    Serial.println(roll);

    bool yawCheck = abs(yaw) < abs(yawLast) + 1
                    && abs(yaw) > abs(yawLast) - 1;
    bool pitchCheck = abs(pitch) < abs(pitchLast) + 1
                      && abs(pitch) > abs(pitchLast) - 1;
    bool rollCheck = abs(roll) < abs(rollLast) + 1
                     && abs(roll) > abs(rollLast) - 1;

    if (yawCheck && pitchCheck && rollCheck) {
      motionMeter--;
    }
    else {
      motionMeter++;
    }

    yawLast = yaw;
    pitchLast = pitch;
    rollLast = roll;
  }

  if (motionMeter > 500) {
    motionMeter = 500;
  }
  else if (motionMeter < 0) {
    motionMeter = 0;
  }

  Serial.println(motionMeter);

  if (motionMeter > 100) {
    rainbowStart = true;
    roll_die(Wheel(random(255)));
    delay(3000);
    motionMeter = 0;
    accelgyro.resetFIFO();
  }

  else {

    if (rainbowStart) {
      rainbowStart = false;
      rainbowTime = millis();
    }

    long int j = (millis() - rainbowTime) / 5;

    for (int i = 0; i < pixels.numPixels(); i++) {
      pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
    }
    pixels.show();
  }
}

#20

Here’s one I call fountain, assuming the cube is sitting with the wire leads on top. The colors flow out the top, cascade down the sides and flow back in the bottom.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 6

const uint8_t numFaces = 6;
const uint8_t numRows = 4;
const uint8_t numCols = 4;

// these variables are not required, just added to reduce computations
const uint8_t numPixelsPerFace = numRows * numCols;
const uint16_t numPixels = numFaces * numPixelsPerFace;

uint8_t wait = 500;         // reduce value to increase flash rate
uint8_t maxIntensity = 50;  // max value is 255. Set to lower value to reduce intensity of colors

// pixel positions for pattern
const uint8_t numPixelsPerOuter(12);
const uint8_t numPixelsPerInner(4);
uint8_t outerPixels[] = {0,1,2,3,4,7,8,11,12,13,14,15};
uint8_t innerPixels[] = {5,6,9,10};

Adafruit_NeoPixel thimbleCube = Adafruit_NeoPixel(numPixels, PIN, NEO_GRB + NEO_KHZ800);

uint32_t currentColor;

void setup()
{
  thimbleCube.begin();
  thimbleCube.show(); // Initialize all pixels to 'off'
  randomSeed(analogRead(0));
}

void loop()
{
  uint16_t pixelOffset(0);
  currentColor = thimbleCube.Color(random(0, maxIntensity), random(0, maxIntensity), random(0,maxIntensity));
  uint8_t face(0);
  pixelOffset = face * numPixelsPerFace;
  for (uint8_t inner = 0; inner < numPixelsPerInner; ++inner)
  {
    thimbleCube.setPixelColor(pixelOffset + innerPixels[inner], currentColor);
  }
  thimbleCube.show();
  delay(wait);
  for (uint8_t outer = 0; outer < numPixelsPerOuter; ++outer)
  {
    thimbleCube.setPixelColor(pixelOffset + outerPixels[outer], currentColor);        
  }
  thimbleCube.show();
  delay(wait);

  for (uint8_t row = 0; row < numRows; ++row)
  {
    for (uint8_t face = 1; face < numFaces - 1; ++face)
    {
      pixelOffset = face * numPixelsPerFace;
      for (uint8_t col = 0; col < numCols; ++col)
      {
        thimbleCube.setPixelColor(pixelOffset + row * numCols + col, currentColor);        
      }    
    }
    thimbleCube.show();
    delay(wait);
  }

  face = 5;
  pixelOffset = face * numPixelsPerFace;  
  for (uint8_t outer = 0; outer < numPixelsPerOuter; ++outer)
  {
    thimbleCube.setPixelColor(pixelOffset + outerPixels[outer], currentColor);        
  }
  thimbleCube.show();
  delay(wait);
  for (uint8_t inner = 0; inner < numPixelsPerInner; ++inner)
  {
    thimbleCube.setPixelColor(pixelOffset + innerPixels[inner], currentColor);
  }
  thimbleCube.show();
  delay(wait);

  // uncomment this line to black out cube between colors.
  //paintCube(0);
}

void paintCube(uint32_t color)
{
  for (uint8_t pixel = 0; pixel < numPixels; ++pixel)
  {
    thimbleCube.setPixelColor(pixel, color);
  }
  thimbleCube.show();
}