Project tutorial

Holiday Shadow Theater © LGPL

Build a beautiful Holiday Shadow Theater and control the animated scene with your phone.

  • 7,719 views
  • 7 comments
  • 65 respects

Components and supplies

Ardgen 101
Arduino 101 & Genuino 101
×1
SparkFun Adressable RGB LED Strip
I use this one for easy connectivity but any addressable LED strip will work (with minor adjustments.)
×1
SparkFun Male Barrel Jack adapter
You can often find these at a local electronics store
×1
SparkFun Female Barrel Jack Adapter
×1
SparkFun 3xAA Battery Holder with Switch
×1
SparkFun AA battery
This is a generic battery that can come from anywhere. I just chose SparkFun to keep the supplier list short. You need 3AA batteries.
×3
Pololu Step Up Regulator 12v
This is a convenient way to power the Arduino 101 with the same batteries that power the LED strip.
×1
Regular printer paper- 4 sheets 8.5x 11"
×1
Cardstock paper 100lb, 4 sheets of 8.5 x 11"
×1
White 3/16" Foam Core, enough for four 8.5 x11" pieces
×1

Necessary tools and machines

Hy gluegun
Hot glue gun (generic)
09507 01
Soldering iron (generic)
Xacto knife
Spare xacto blades (#11)
Wire strippers, 12-20 AWG
Access to a printer (that can print on cardstock)
Small screwdriver to tighten the terminals on the barrel jack connectors.

Apps and online services

About this project

Overview

This project uses an Arduino 101, a strip of addressable LEDs, foam-core and cardstock paper to create a phone-controllable animated Shadow Theater. The electronics are used non-destructively, so you can easily use them later for another project. Here's a handy Sparkfun wishlist with 99% of the electronics.

How it works:

One strip of addressable LEDs is wrapped over a piece of foam-core in the middle of the Shadow Theater. The lights near the bottom are slowly fired in sequence and shine through pinholes to create an animated shadow. Lights further up are channeled into the buildings on top, and the last LED on the strip is used to shine on the whole scene, creating the main shadow.

The Arduino 101 has a Bluetooth radio built-in, and I use a quick prototyping app called Blynk to remotely control the scene. In the example code you can control the colors in the buildings, turn on a flickering fire, and control the brightness of the main shadow light.

Sliders on the Blynk app let you turn the main light up and down, and control the lights in the buildings

Part One: Setting up the Electronics

Step 1

Collect the end harness from your LED strip by cutting about 1 cm from the end of the lights. Strip the wire ends.

Step 2

Break apart the bent header pins that came with your voltage regulator, and solder two of them to the ends of the green and yellow wires. This will let you easily plug them into the pins of the Arduino 101.

Step 3

Next solder the red wire to the VIN terminal on the Voltage Regulator, and solder two straight headers into the GND and VOUT pins as shown.

Step 4

Now connect the barrel jack adapters. First strip the ends of the wires coming from your battery case, then mount them in the terminals of the male barrel jack and tighten with a screwdriver. RED goes to the (+) terminal, BLACK goes to the (-) terminal.

Next connect the female barrel jack adapter onto to the loose wires coming from the beginning of the LED strip. YELLOW goes to the (-) terminal, and RED goes to the (+).

Step 5

Now connect your harness to the Arduino 101. The GREEN wire goes to PIN 6, the YELLOW wire goes to the GND pin near #13.

With the two header pins on the voltage regulator, GND goes to GND and VOUT goes to the "Vin" pin on the Arduino 101. Don't get this wrong! Plugging in backwards leads to smells and burns. I know this.

Part Two: Assembling the Foam-Core Stage.

Print the foam-core pattern on regular printer paper (4 sheets) and print out the cardstock pattern on cardstock paper (4 sheets.)

Step 1

Take the printed foam-core pattern pages and use them to cut out your foam-core pieces. You can lay a pattern on the foam-core, then lightly trace the outline with a hobby knife to transfer the lines through.

Step 2

Once you have the pieces cut, start by assembling the LED strip holder like so:

Now take your LED strip and attach the first LED to the bottom with tape or hot glue, and wrap your LEDs as shown. The idea is to keep the LED strip intact. It doesn't need to be a super tight wrap.

Once you've made three wraps, leave the tail end free and secure the top with tape or hot glue.

Step 3

This LED strip has addressable LEDs, meaning you can more or less say, "hey, you in the middle, turn red!" But they don't answer to "hey you," so you need to know their numbers.

The LEDs below the crease will shine out the back of the Shadow Theater and be used for animation. In the example below, my animation lights are 0, 1, 2, 20, 21, 22, 40, 41, 42. Two LEDs in the top section will shine up into the houses. I use LED 23 to shine up into the back house, and 25 to simulate firelight in the front houses.

Count out your LEDs and draw a simple reference map that makes sense to you so you can enter appropriate LED numbers into the code later. Remember to start your count at the beginning of the strip starting with zero, because computers.

Step 4

Glue the LED holder down onto the foam-core bottom piece. Position it as shown and so the wide stripe of lights is roughly centered lengthwise with the base.

Now add the curved foam-core side pieces on the ends with hot glue as shown.

Step 5

Now add the light dividers and the foam-core top piece. The light dividers keep the animation lights from spilling up into the houses, and vice-versa. Position the largest divider close to the crease in the LED holder, and position the smaller divider above it so at least one LED is between them (see photos below.) Position the top piece so it's square with the base as shown in the slideshow below and secure with hot glue.

Step 6

Attach the end of the LED strip to the front top edge with hot glue so the last LED in the string can shine on the scene. This is the main shadow LED.

Part Three: Programming the Arduino 101, and setting up Blynk

Connect a USB programming cable to the Arduino 101, and connect the LED strip, battery pack and Arduino 101 all together (leave the power switch on the battery pack to "off.")

You'll need the Arduino IDE installed on your computer, with the Intel Curie Core (see Arduino 101 getting started.) You'll also need to install the Adafruit Neopixel library, and the Blynk library.

If you're new to Arduino, it's a good idea to run some basic example sketches to be sure everything's working OK.

Step 1

Install the Blynk app on your phone.

Blynk is a great tool for rapid proof-of-concept building and remote controlling your Arduino 101. BLE support still has some bugs, but Blynk is by far the fastest way I've found to control any Arduino 101 project from a phone.

Step 2

Load the example code in your Arduino IDE and change the LED pixel numbers if necessary using the map you made earlier.

The program animates through the LED numbers in the "pos[ ]" array to create the illusion of falling snow. Change these numbers if needed to match your setup, (the animation LEDs are the ones below the crease on your LED holder.) Arrange the numbers in the order you want them to fire. The lights project through pinholes to make the "snow," so lighting from the bottom to top will make snow appear to fall down, left to right will make snow appear to blow from right to left.

//#snow animation lights 
int pos[] = {0, 1, 2, 20, 21, 22, 40, 41, 42}; 

Next set how many pixels will animate

//#how many animation pixels are in the array above? 
int numLeds = 9;  

Then set the pixel that is at the end of the strand shining on the scene (on a 60 pixel strip, this is pixel #59.)

//#main shadow-casting LED at the end of the strand. 
int shadowPixel = 59;

Choose a pixel for the lights that will shine up into the rear house. This pixel should be between the two light dividers.

//#pixel for the lights in the rear house
int lightHousePixel = 23;  

Finally, set the number of the pixel that will be shining up into the front houses to be the "fire pixel." This pixel should be just in front of the smaller light divider.

//#Pixel for flickering firelight in the front houses 
int firePixel = 24; 

When the code above is changed as needed, you can compile and upload to your Arduino 101. Once the code is successfully uploaded, disconnect your USB cable and turn the power switch on the battery pack to "on." You should see the shadowPixel turn on, and the animation pixels will light in sequence. The house and fire pixels will be off until you control them with Blynk.

Step 3

Loading your Blynk app:

Open the Blynk app on your phone and press the "scan" button near the upper right. Scan this QR code and the controller interface should automatically load and you'll be all set.

When loaded, the interface should look like this:

If you prefer to build your Blynk interface manually instead of scanning the code above, start with with a BLE widget and 3 sliders set to output 0-100 to VO, V1 and V2.

Step 4

Connect over BLE to your Arduino 101. Tap the BLE widget and if your Arduino 101 is powered on, you should see "ShadowTheater." Connect, then hit the "play" arrow icon in the upper right to control your project. You may need to reconnect after your phone goes to sleep.

OK all done with the hard stuff, now on to crafting! You can turn everything off until the final reveal.

Part Four: Card stock silhouettes, buildings, and final touches

Step 1

Find your four printed card-stock sheets. Using a hobby knife and fresh blades, cut out the background silhouette. Change the blade frequently! Cutting with a dull blade is super frustrating. I changed the blade 3 times cutting out this silhouette.

Step 2

Cut out the house pieces and attach the backs with hot glue. The printed sides should face back, so you can't see any ink from the front. Scroll through the photos below.

Step 3

Add the houses to the stage. You can use hot glue or tape. Try to close all gaps so the light goes into the houses but doesn't spill around the sides.

Step 4

Now fold the sides of the silhouette sheet and attach the bottom to the back edge of the stage with hot glue. (face the printed side away from the viewer.)

Step 5

Cut out a snow scene to project on the wall behind the shadow theater. You can use pins or toothpicks, or cut out intricate shapes. Once the sheet is done, hot glue it to the curved edges to create a projection surface.

Step 6

Attach the left side and front sheets with hot glue.

Loosely attach the right side sheet with tape, so you can still get at the inside to turn the power on and off at the battery case.

All done! Find a dark area with a wall nearby to try it out! When you first turn the power on, the Shadow Theater should cast a scene shadow and falling snow. With the Blynk app, you can control the main light, and the lights in the buildings.

Schematics

Foam-Core patterns (4 pages 8x11)
Print these out on regular printer paper to use as guides for cutting foam-core. You can place them on top and trace with a hobby knife to transfer the pattern through.
Cardstock Patterns
Print on 8.5 x 11" cardstock paper (4 sheets.) These make the houses, sides, and shadow-silhouettes
Cardstock Pattern for Laser Cutter or Vinyl Cutter
If you're lucky enough to have access to a laser cutter or a vinyl cutter, you can use this pattern to cut out your cardstock pieces.
30bn6Le68V1Lpp2spRMw.svg

Code

Shadow Theater Arduino SketchArduino
This sketch uses the Adafruit NeoPixel Library and the Blynk Library. It lets you remote control LEDs in an addressable LED string to create effects in a Shadow Theater.
/*
   Copyright (c) 2016 Intel Corporation.  All rights reserved.
   See license notice at end of file.
*/


///////////////////////THESE ARE THE VARIABLES YOU SHOULD CHANGE TO MATCH YOUR SHADOW THEATER SETUP////////////////////////////////////////

//snow animation lights

int pos[] = {0, 1, 2, 20, 21, 22, 40, 41, 42}; // which LEDs are available for animation?  They will be called in order from left to right.

int numLeds = 9;  //how many animation pixels are in the array above?

int shadowPixel = 59;///  main shadow-casting LED at the end of the strand.

int lightHousePixel = 23; //pixel for the lights in the rear house

int firePixel = 24;  //pixel for flickering firelight for front houses.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



#include <Adafruit_NeoPixel.h>
#include <BlynkSimpleCurieBLE.h>
#include <CurieBLE.h>

#define PIN 6

int v0 = 0;  //variables to hold incoming values from Blynk
int v1 = 0;
int v2 = 0;

int fadeup = 0;   //variables for light animation smoothing
int fadedown = 0;

int firetimer = 0; /// variables to make the fire flicker
int fireinterval = 50;
int flicker = 0;

unsigned long lightcounter = 0;  //variable for counting through the animating lights forever

int stp = 0;  ///light steps for ainimation.  One for the current light to turn it on, and one for the old light to turn it off.
int stpOld = 0;

unsigned long timer = 0;
int interval = 0;


char auth[] = "YourAuthToken";  ///  The Auth Token isn't used by Blynk for BLE currently. If it's turned on in the future, you can get your auth token from your Blynk App and paste it inside the "".

BLEPeripheral  blePeripheral;  ///set up the BLE connection

Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);  ////  set up the light strip.  If your LED strip has more or less than 60 pixels, change the first number to match your strip.


void setup() {
  delay(1000);
  timer = millis();
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  blePeripheral.setLocalName("ShadowTheatre");
  blePeripheral.setDeviceName("ShadowTheatre");
  blePeripheral.setAppearance(384);

  Blynk.begin(auth, blePeripheral);

  blePeripheral.begin();
  
  interval = 350;  //time interval of 350ms for snow animation
}


void loop() {
  Blynk.run(); //Blynk stuff for real-time controll
  blePeripheral.poll();
  
  ////////turn on the shadow pixel and control with Blynk
  strip.setPixelColor(shadowPixel, 200 - v2, 160 - v2, 160 - v2); //turns shadow light on, v2 (sent from Blynk app) changes the light.


  //fire
  if ((millis() - firetimer) > fireinterval) {
    firetimer = millis();
    flicker = random(0, 40);  //when a set time interval passes, change the brightness of the fire randomly between 0 and 40.
  }
  if (v0 > 1) {  
    strip.setPixelColor(firePixel, 80 + v0 + flicker, v0 + flicker, 0);  // the fire = the brightness of the slider in Blink, + the flicker value, weighted towards red
  }
  else {
    strip.setPixelColor(firePixel, 0, 0, 0);  //only turn on the fire if the Blynk slider is > 0.
  }

  //houselights
  if (v1 > 1) {
    strip.setPixelColor(lightHousePixel, 200 - v1, v1, 0);  ///  if the Houselights Slider in Blynk is >0, control the house lights in the rear house. else turn off.
  }
  else {
    strip.setPixelColor(lightHousePixel, 0, 0, 0);  
  }

  //snow animation
  if ((millis() - timer) > interval) { //every time the interval passes, move one step forward and reset fades
    stpOld = stp;
    timer = millis();
    lightcounter++;
    stp = (lightcounter % numLeds) ; /// counts over and over from zero to numLeds-1
    fadeup = 0;   //reset fade values every time the interval passes
    fadedown = 170;
  }

  fadeup += 2;
  fadeup = constrain(fadeup, 0, 170);
  
  fadedown -= 2;
  fadedown = constrain(fadedown, 0, 170);
  
  for (int i = 0; i < numLeds; i++) {  //turn all animation LEDs off.
    strip.setPixelColor(pos[i], 0, 0, 0);
  }
  strip.setPixelColor(pos[stp], fadeup, fadeup, fadeup);  ///Set the selected pixel to the current "fadeup" value
  strip.setPixelColor(pos[stpOld], fadedown, fadedown, fadedown);  //Set the old pixel to the current "fadedown" value
  
  strip.show();  //finally, send all the current color values out to the LED strip for display.
}



////  when new signals come in from Blynk, they update the global variables v0, v1, and v2.
BLYNK_WRITE(V0) //The Fireplace Slider Widget is writing to pin V0
{
  v0 = param.asInt();
}
BLYNK_WRITE(V1) //The Houselights Slider Widget is writing to pin V1
{
  v1 = param.asInt();
} BLYNK_WRITE(V2) //Main Shadow LED Slider Widget is writing to pin V2
{
  v2 = param.asInt();
}


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

The Magnetic Field and RGB Tester

Project tutorial by Kutluhan Aktar

  • 249 views
  • 0 comments
  • 5 respects

Development Board for AtTiny MCU

by Vincenzo G.

  • 120 views
  • 0 comments
  • 4 respects

Version 2.0 Advanced Attendance System (Without Ethernet)

Project tutorial by GadgetProgrammers

  • 2,902 views
  • 5 comments
  • 44 respects

How To Use DS18B20 Water Proof Temperature Sensor

Project showcase by IoTBoys

  • 163 views
  • 0 comments
  • 3 respects

Ultrasonic Security System

Project tutorial by Krepak

  • 354 views
  • 0 comments
  • 6 respects
Add projectSign up / Login