Project tutorial

Handheld Infinity Kaleidoscope Group Kit © LGPL

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

  • 7,222 views
  • 4 comments
  • 52 respects

Components and supplies

Ardgen 101
Arduino 101 & Genuino 101
×1
Tens70
9V battery (generic)
×1
Adafruit industries ada80 image 75px
9V to Barrel Jack Connector
×1
SparkFun Addressable LED strip (Bare)
You get 4 Infinity Kaleidoscopes per strip!
×1
11026 02
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

Necessary tools and machines

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

Apps and online services

Ide web
Arduino IDE
Adafruit Neopixel Library

About this project

This project is great for workshops and group projects. It's basically a micro-sized version of the Kaleidoscope Infinity Mirror in a petri dish! If you make a big batch (20 kits or more) the per-unit cost is about $10 + the cost of an Arduino 101. The electronics are reusable for other projects. For example, you can also use these electronics to make an animated Shadow Theater.

PART 1: Preparing the Kits

Once the kits are prepped, assembly time for groups is about 30min. You can use double-stick tape to attach parts, or velcro dots to reuse these kits over and over.

Decide how many kits you want to make. Petri dishes come in packs of 20. Each LED strip will make 4. The 3" mirrors come in packs of 5. One roll of mirror film will make probably hundreds! 20 kits is a good target, but tailor the parts list to your needs.

Step 1. Foam Core

Using a ruler and box cutter, cut your foam core board into 3.5" squares. You need one 3.5 x 3.5" square per kit.

Step 2. LEDs

Cut the LED strips into 4 segments. First make note of the directional arrows on the strip, and cut through the copper pads after the first LED. Now count 14 LEDs and cut again. Repeat until you have 4 segments of 14 LEDs with 3 LEDs remaining at the tail. You'll need one 14 LED segment for each kit you're making.

Step 3. Prep the Wires

Cut your solid-core wire into approximately 6" segments. Each LED strand needs one wire for signal, one for power, and one for ground. You can use any color you like, but the standard convention is red for power, black for ground, and green or yellow for signal. Once you've cut all your wires, go back and strip about 1/4" from both ends of the wires.

Step 4. Soldering Wires On

This will seem like a lot of soldering, but it can actually go quite fast once you're set up. Helping Hands are very... helpful for this step if you have them.

Take one of your 14 LED strips, and use the printed arrows to find the beginning. (The LED strands are directional- it won't work if the wires are soldered on the output end!)

First melt some solder onto the three copper pads marked DIN, +5V, and GND.

Next, lay a wire end against one of the solder pads while heating with the soldering iron. The solder should melt and encapsulate the wire. Make sure the wire color matches the pad! +5V is Red, GND is Black, and DIN is Green or Yellow.

Repeat this process for all of the strips you're making.

Step 5. Prepare Circles of Mirror Film

Cut the mirror film into roughly 3" diameter circles, one for each kit. You can use a jar lid or similar to draw lines and cut with scissors, or if you have access to a craft vinyl cutter, you can make short work of it by cutting 12 or so circles at a time. The circles don't have to be perfect, they just need to roughly fit inside a petri dish without crinkling at the edges.

Step 6. Stick the Mirrored Film Inside the Petri Dishes.

Find your Petri dishes. Each dish has a base and a lid. For this project, the deeper side of the dish works better, but you could use both sides in a pinch to make 40 mirrors from a 20-pack of Petri dishes.

It's hard to see, but the mirror film actually has a clear film layer on one side. Carefully peel the film off the back and apply the mirror to the inside surface of a petri dish. It doesn't need to be perfect, but get it as centered as you can, and try to work any air bubbles out to the sides.

Step 7. Apply the Neoprene Weather Stripping to the Petri Dish.

First cut your neoprene tape into 10" strips. You'll need one strip per-kit.

Peel the sticky backing off the neoprene, and carefully adhere it along the inside edge of the Petri dish, trying to get it as flush with the bottom as possible. There should be a small gap where the two ends don't quite reach each-other.

Step 8. Add Velcro Dots or Double-Sided Tape.

Gather your foam core squares, your 3" mirrors, 9v batteries, and Arduino 101s. When each kit is assembled, the Arduino 101 and the battery will be stuck to one side of the foam core, and the mirror will be stuck on the opposite side. You can choose if you want to use double-sided tape or Velcro dots. Tape is a little faster to prep, but Velcro allows you a assemble and disassemble the kits over and over.

First lay one of the mirrors on a square of foam-core and outline it with a pencil. Do this for all the squares.

Next apply some Velcro dots to the circle, and add the counterpart dots to the mirror.

On the other side, add dots for the Arduino 101 and the battery, and place the counterpart dots on the back of the Arduino 101 and battery.

Part 2. Uploading Code to the Arduino 101

Step 1. Connect an Arduino 101 to your computer with a USB cable.

Load the example code attached, or visit Arduino Create to program in your web browser.

If you are using the Arduino IDE, make sure you have the latest Curie Core installed. Set the Board Manager to Arduino / Genuino 101, and select the appropriate port. Then upload the example code.

Whats happening?

In the example code:

First we set up R, G, B variables that we can send to the LED 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; 

Then we start reading the accelerometer values from the Curie IMU, and convert the x, y forces into an angle.

  //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) 

Then we basically divide the circle of angles into regions we can use to control the colors.

This example code is far from scientific! Try turning on the “rainbow” function, or change some color values…

 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); 
}

Part 3. Packing the Kits.

In large resealable bags assemble the parts for a kit. Print one instruction sheet per kit.

Each kit should have:

1x Instruction sheet

1x Arduino 101

1x LED strip with wires

1x 3" Mirror

1x Petri dish with mirrored film and neoprene tape

1x Foam core square with Velcro dots or double-sided tape

1x 9v Battery

1x 9v Battery clip

Part 4. Kit Assembly.

That's it! Have fun playing with your handheld infinity kaleidoscopes!

This code can be easily re-purposed for other tilt-to-control-light projects. Kitty Yeung uses this example code unchanged in her TinyTILE light-up dress.

Schematics

Assembly Instructions

Code

Handheld_Infinity_KaleidoscopeArduino
/*
  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
*/

Comments

Similar projects you might like

Magic Lamp

by Nekhil ravi

  • 1,010 views
  • 3 comments
  • 12 respects

PuzzleBox

Project tutorial by Arduino

  • 205 views
  • 0 comments
  • 1 respect

Arduino MKR GSM 1400 and DTMF

by Arduino_Genuino

  • 3,910 views
  • 0 comments
  • 9 respects

Love You Pillow

Project tutorial by Arduino

  • 2,447 views
  • 0 comments
  • 5 respects

Infrared Replicator

Project tutorial by Gustavo Gonnet

  • 3,836 views
  • 6 comments
  • 26 respects
Add projectSign up / Login