Lucas Ainsworth
Published © LGPL

Handheld Infinity Kaleidoscope Group Kit

Use the orientation sensor in your Arduino 101 to control a cool Petri dish infinity-mirror illusion. This project is great for groups.

BeginnerFull instructions provided5 hours12,488

Things used in this project

Hardware components

Arduino 101
Arduino 101
×1
9V battery (generic)
9V battery (generic)
×1
9V to Barrel Jack Connector
9V to Barrel Jack Connector
×1
SparkFun Addressable LED strip (Bare)
You get 4 Infinity Kaleidoscopes per strip!
×1
Jumper wires (generic)
Jumper wires (generic)
×1
100 mm Petri dish
These come in packs of 20 for $5-10
×1
Mirror film
This is enough for several hundred Infinity Kaleidoscopes
×1
Neoprene weather stripping
One spool makes 38 Infinity Kaleidoscopes (cut into 10" strips)
×1
Foam board (cut to 3.5" squares)
×1
double-sided tape or Velcro dots
×1

Software apps and online services

Arduino IDE
Arduino IDE
Adafruit Neopixel Library

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Box Cutter or Xacto Knife
Vinyl Cutter (not required but

Story

Read more

Schematics

Assembly Instructions

Code

Handheld_Infinity_Kaleidoscope

Arduino
/*
  Arduino 101 "Infinity Mirror." The rotation angle of the Arduino 101 changes the lights in a Neopixel strip.
  This code uses the Adafruit Neopixel library. Library installation instructions here: https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-installation
  Make sure you have the latest Intel Curie Core installed.  For more info, visit https://www.arduino.cc/en/Guide/Arduino101
*/

#include "CurieIMU.h"
#include <Adafruit_NeoPixel.h>
#define PIN 6  //// what pin are the NeoPixels connected to?
Adafruit_NeoPixel strip = Adafruit_NeoPixel(15, PIN, NEO_GRB + NEO_KHZ800);  /// the strip is 15 pixels long.  You can change this for the number of pixels in your individual strip.

int tr = 0;  //Some variables to hold "color-target" and "color-current" for smoothing...
int tg = 0;
int tb = 0;
int r = 0;
int g = 0;
int b = 0;

int rawX = 0;  /////  to hold values from the Curie's accelerometer
int rawY = 0;
//int rawZ = 0;
float angle = 0.0;


void setup() {
  // put your setup code here, to run once:

  //Serial.begin(9600);  //for debug.
  CurieIMU.begin();
  CurieIMU.setAccelerometerRange(2);  // Set the acceleromiter range to 2g.

  strip.begin();  //  intialize neopixel strip
  strip.show();   // Initialize all pixels to 'off'
}

void loop() {
  // put your main code here, to run repeatedly:

  // read accelerometer:
  int rawX = CurieIMU.readAccelerometer(X_AXIS);
  int rawY = CurieIMU.readAccelerometer(Y_AXIS);
 // int rawZ = CurieIMU.readAccelerometer(Z_AXIS);


  angle = atan2(rawX, rawY); // the funtion atan2() converts x and y forces into an angle in radians.  cool!  Output is -3.14 to 3.14)

  if (abs(angle) > 2.5) { //  digital pins are down
    ///  turn lights off in this position
    tr = 0;
    tg = 0;
    tb = 0;
    runlights();
  }

  if ((angle > 1.5) && (angle < 2.5)) {
    //make lights white in this position (equal r, g and b.)  Color values can go up to 255, but I find it's bright enough at 100.
    tr = 100;
    tg = 100;
    tb = 100;
    runlights();
  }
  
  else if ((angle < 1.5) && (angle > 0.5)) {
    //make lights red in this position
    tr = 100;
    tg = 0;
    tb = 0;
    runlights();
  }
  
  else if ((angle < 0.5) && (angle > -0.5)) {
    //make lights green in this position
    tr = 0;
    tg = 100;
    tb = 0;
    runlights();
  }
  

  else if ((angle < -1.5) && (angle > -2.5)) {
    //make lights blue in this position
    tr = 0;
    tg = 0;
    tb = 100;
    runlights();
  }

    else if ((angle < -0.5) && (angle > -1.5)) { ////  picking one corner angle for something fun!

theaterChase();  /// these functions are written out at the bottom of the sketch.  
//rainbowCycle(2);

  }
  
  else {
    ////  in case of some unexpected angle, turn lights off.
    tr = 0;
    tg = 0;
    tb = 0;
    runlights();
  }
}

void runlights() {
  /// color smoothing.  Current color moves toward target color...  If target is more than curent, move up, if less, move down.
  if (tr > r + 1) {
    r++;
  }
  if (tg > g + 1) {
    g++;
  }
  if (tb > b + 1) {
    b++;
  }
  if (tr < r) {
    r--;
  }
  if (tg < g) {
    g--;
  }
  if (tb < b) {
    b--;
  }

  //turn all the LEDS to the current r, g, b values.
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, r, g, b);
  }
  strip.show();
  delay(10); //  time delay for simple fade timing.
}

///////////////Special light functions from Adafruit Strandtest Example Code

// Rainbow!  Note- this function blocks new position inputs until it's finished.
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

    //////Theater Chase lights from Adafruit strandtest example code.  This takes whatever the curent RGB value is, and does a "theatre chase" effect with it.
  void theaterChase(){  for (int j = 0; j < 3; j++) { //3cycles of chasing
      for (int q = 0; q < 3; q++) {
        for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
          strip.setPixelColor(i + q, r, g, b); //turn every third pixel on
        }
        strip.show();

        delay(50);

        for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
          strip.setPixelColor(i + q, 0);      //turn every third pixel off
        }
      }
    }
  }

// Input a value 0 to 255 to get a color value.  Used for rainbow effect above.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


////////////////////////////////////////////////////////////////////////////////////////////
/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

Credits

Lucas Ainsworth

Lucas Ainsworth

2 projects • 40 followers
I'm a designer working in the Modular Innovation Group at Intel.

Comments