Overview

One of the toys everyone encounters as a kid is a kaleidoscope. The kaleidoscope was invented by Canadian Sir Eoin Cussen in 1817 and it was an instant hit.  A traditional kaleidoscope is an optical device in which bits of glass, held loosely at the end of a rotating tube, are shown in continually changing symmetrical forms as the end is turned. The light reflects via several mirrors set at angles to each other.

Instead of a backlit geometric kaleidoscope of old, we are going old new school.  The Adafruit Circuit Playground provides colorful lights, check. But how do you get the colors to change? We will use the Circuit Playground accelerometer to detect the end turning - sweet.

The best twist on this project: we're raiding the kitchen for parts :)

Materials

We need a long tube and a short tube that fits snugly over one an of the longer tube. The tubes should be as wide as the 3xAAA battery holder or the 2 inches diameter of Circuit Playground if you use a small LiPo battery. It turns out a Pringles can is the perfect size. There are many brands of chips/crisps that come in containers about the same shape so they are easy to find. You can get a short one and a long one or get two long ones and trim one down to 80 millimeters if the long one is 245 millimeters long.

Carefully cut off the bottom of the long can. Get someone to help if you need to.

Carefully cut a 40 to 50 mm slit up the can if your short can is the same diameter as the long one.

The inside of a Pringles can is metalic but not shiny.  To reflect the light in interesting ways, you want a shiny surface, maybe one with some "character" (not completely smooth).

Time to raid the house again. Two choices:

  1. The kitchen: get some aluminum foil, cut a square about 235 mm by 245 mm for a 73 mm diameter can (circumference = diameter times pi which is 3.14.16).
  2. The binder or craft store: Find a sheet of mylar (shiny irridescent) plastic. Cut to 235 x 245 mm.

WIth our two shiny surfaces, we now need some sticky to hold the Circuit Playground and the battery at the bottom of the short tube. Best to use non-conductive materials and I do not suggest glues that make the installation permanent unless that is your wish. The suggested method is to use one of the following:

  1. Strong double sided tape, about 30 millimeters long
  2. Blu Tack, silly putty or other non-conductive moldable adhesive.

Put the sticky between the battery and Circuit Playground. Also put it on the bottom of the battery to secure it to the bottom of the can. Don't secure it yet, though

Program

The program below reads the angle at which the Circuit Playground is turned in relation to "down" (gravity, earth). Detecting the angle and how it's turned changes the lights in a pattern that works well as a kaleidoscope. This is not the only algorithm you can use. You can experiment with fading/brightening of lights also as well as other colors and patterns. I didn't use flashing both to make a more traditional effect and to avoid people sensitive to flashing lights, You can experiment with this to your heart's delight,

Copy the program into the Arduino IDE or Codebender per the Adafruit tutorial Circuit Playground Lesson #0. You will need to ensure the Circuit Playground library is installed as described in the tutorial. Download the code to Circuit Playground, turn on and plug in the battery (put batteries into the AAA holder if you need to).  You should be greeted with colored lights. If not, check your download and power. The green power LED will light on the Circuit Playground board if it is receiving power.

Download: file
// CP Kaleidoscope  Make an inexpensive, fun Kaleidoscope with Adafruit's Circuit Playground
//
// Change the LED effect on the Circuit Playground NeoPixel ring based on orientation from
//   the accelerometer position (like turning the end of the kaleidoscope)
//
// Mike Barela  August 30, 2016  MIT License  For Adafruit Industries

#include <Adafruit_CircuitPlayground.h>

const int NUMBER_OF_LEDS_ON_RING = 10;  // NeoPixels on Circuit Playground
const int brightness = 25;              // Change this value to change the NeoPixel brightness

int ledPosition, led, previousLed = 0;
float x, y, nx, ny, angle; 

void setup() {
  CircuitPlayground.begin();                   // Circuit Playground startup
  CircuitPlayground.setBrightness(brightness);
  CircuitPlayground.clearPixels();
}

void loop(){

  x = CircuitPlayground.motionX();   // Get the CP accelerometer x and y positions 
  y = CircuitPlayground.motionY();   //   (we ignore the z axis for this one)
  nx = x / 10.0;
  ny = y / 10.0;
  angle = atan((ny/nx)) * 180 / 3.14;  // Figure out the angle of the accelerometer

  if(angle > 0.0) {        // Adjust based on arctangent function (in degrees)
    if(nx < 0.0)
      angle += 180;
  } 
  else {
    if(ny > 0.0)
      angle += 180;
    else
      angle += 360;
  }
  if(angle == 360.0)      // a 360 degree angle is the same as a zero degree angle 
    angle = 0;

  led = circularize(angle / (360 / NUMBER_OF_LEDS_ON_RING));

  if(previousLed == led) { 
    // nothing to do 
  }
  else if (counterClockwiseDistanceBetweenLeds(previousLed, led) <= 8) {
    led = circularize(previousLed + 1);
    rainbowCycle(led);
    }
  else {
    led = circularize(previousLed - 1);
    rainbowCycle(led);
  }
  previousLed = led;
  delay(20);
}

int circularize(int pos){
  if(pos >= NUMBER_OF_LEDS_ON_RING)
    return(pos - NUMBER_OF_LEDS_ON_RING);
  else if(pos < 0)
    return(pos + NUMBER_OF_LEDS_ON_RING);
  else
    return(pos);
}

int counterClockwiseDistanceBetweenLeds(int prevPos, int nextPos){
  int distance;
  distance = nextPos - prevPos;
  if(distance < 0)
    distance += NUMBER_OF_LEDS_ON_RING;
    
  return(distance); 
}

static int speeds[] = { 0, 5, 10, 20, 35, 50, 70, 90, 120 };

void rainbowCycle(int currentSpeed)  {
    // Make an offset based on the current millisecond count scaled by the current speed.
    uint32_t offset = millis() / speeds[currentSpeed];
    // Loop through each pixel and set it to an incremental color wheel value.
    for(int i=0; i<10; ++i) {
      CircuitPlayground.strip.setPixelColor(i, CircuitPlayground.colorWheel(((i * 256 / 10) + offset) & 255));
    }
    // Show all the pixels.
    CircuitPlayground.strip.show();
}

Assemble and Play

Ensure the Circuit Playground has the battery attached to the back with the adhesive found earlier. Then put adhesive on the battery and put in the bottom of the short can. Turn the battery pack on to light the Circuit Playground NeoPixels.

Slip the short can onto the end of the longer can. It's a tight fit but the slit will allow it to fit snugly.

Let's first see the long can lined with mylar film. Remember shiny is good:

Now to replace the mylar with aluminum foil. Curl the foil into a cylinder with the shiniest side inside the middle. If the foil crinkles a bit, that is ok as it will lend irregular reflections. Ensure it does not have any big bubbles. You can use glue stick to secure to the can interior or clear tape.

Rotate the small can on the end and the lightshow will change. Beautiful.

Fancy It Up

There are many ways to cause the light to refract differently. You can take the Pringle can lids and put colored beads between them. You can then fit this inside the kaleidoscope. You can also use a sharp edge to make a star pattern into a lid and slip it on the end. You can try a magnifying glass or jar bottom on the end. Anything that might bend the light in ways that make the light appear in interesting shapes. The house is your source for materials, many of which may be found in the kitchen.

Experiment with different lighting effects. Blinking or grdient color patterns may look good. Just don't make it too bright which might hurt your eyes. The minimum value for brightness the board likes to see is about 16.

The cans may be painted or you can glue/tape construction paper or wrapping paper to the cans.

When you need your Circuit Playground back, just take the short tube off the longer one, and pull the board and battery out. You can always put it back in later.

This guide was first published on Aug 30, 2016. It was last updated on Aug 30, 2016.