Sunday, February 17, 2013

SpiroGraph 3D Laser Project [with Arduino]

Objective:  Reflect a laser beam off mirrors mounted on three fans to display a 'wild' 3D spirograph type pattern on any surface.  Provide fan speed control (manual or automatic) to adjust the displayed patterns.  Full electrical schematic and source code follows.
-----
If you are not interested in the build and just want to see the result, below is a short video.  If you want to really "trip" out you can watch the 20 minute version.  If you turn up the volume you can hear the fans speeds changing.




-----
If you read through the site, you can see I have been using other micro controllers (MSP430, PIC, PICAXE, Freescale Freedom, etc.)  The Arduino platform is certainly one of the most popular and I wanted to give it a try.

I approached this as an Arduino tutorial project because it combines a lot of basics that go into many projects.  I would recommend it to anyone interested in learning the Arduino because:
  • It's cool (maybe even relaxing) to watch.  Be the envy of your friends...
  • The parts are cheap; many probably already in your kit.
  • Demonstrates reading multiple ADC (Analog to Digital) voltage inputs.
  • Demonstrates multiple PWM (Pulse Width Modulation) outputs to vary LED brightness and control motor speeds.
  • Demonstrates random number generation with the Arduino.
  • Demonstrates using arrays for both variables and pin I/O assignments.
  • Demonstrates the Arduino "mapvalue" scaling function.
  • Demonstrates output of Arduino debug values to the PC screen.
  • Demonstrates multiple voltages being used for a project (12VDC, 5VDC, and 3.3VDC).
  • Demonstrates other program control stuff, etc....
If you are trying to learn the Arduino (or really, any other micro controller) this project beats the hell out of just a "Hello World" blinking LED.  The effect is guaranteed to impress your friends at the next Rave Party.
----
For the project you will need a few items:
  • Arduino (I used the Nano pictured above; $9USD shipped)
  • Laser Diode (check eBay for red ones that sell for ~$1.50USD shipped)
  • Three DC fans or motors (I rescued three 24VDC instrument cooling fans)
  • Three small mirrors and double sided tape to attach then to each fan center
  • Three 10K pots (used to control the fan speed independently)
  • Three LEDs and three 330 ohm resistors
  • AC/DC Power adaptor (I rescued an 18VDC wall wart)
  • LM7805 voltage regulator to tame the output from the wall wart to 5VDC
  • L78L33 voltage regulator (provides a 3.3VDC for the laser diode)
  • TC4469 Quad Motor Driver to provide controlled power to the fans
-----
First thing we need to do is arrange the three fan motors in a box pattern.  I fixed them together with yellow zip ties.  The "wall" on the far left is just a fan housing and where we will mount the red laser diode.  There is a better pic of that later.
-----
Here is a pic of the red laser diode mounted on a thick wire.  You can also see one of the small mirrors mounted to one of the fan's center with double sided tape.  
-----
The red laser beam is aimed so that it reflects off each mirror as it spins, and finally, on onto a wall, etc.  The path of the laser on the spinning mirrors is kinda like this:
-----
Next thing you will need to do connect up a bunch of wires per the schematic below.  Since there is voltage on the project that is higher that the Arduino, the LEDs, or the laser can handle pay special attention when connecting the voltage regulators (LM7805 and L78L33) and components or you will "cook" something.  Also, don't try to skimp out and go without the TC4469 to drive the fans.  The Arduino can't source enough current to drive the fans.  Motor drivers are common in projects so this is a good time learn how to use them anyway.   Click on the schematic to make to bigger.
-----
After connecting everything up, the mess will look something like this:
-----
We still need to program the Arduino Nano to control the project; read the POT locations, adjust the fan speeds and LED brightness, speed change delays, etc.  Simply copy and paste the source code below into the Arduino IDE (Integrated Development Enviroment) installed on your PC.  Then download the source code "sketch" into the Nano.  If this step seems daunting check out this page on the official Arduino site.
/*
 **************************************
 ***** www.WhiskeyTangoHotel.Com  *****
 **************************************
 Project Name: Spyrograph Laser (3 axis)

 Start Date:  Feb 2013

 Program Rev History and Notes: 
 Project controls 3 * 24VDC fans (with mirrors attached to the center).  A laser is
 shined onto the mirror.  A '3D' pattern is drawn on the wall with the laser.

 If a control POT is full up, the fans speed is random.
 If a control POT is full down, the fan turns off.
 Else the control POT varies the fan speed manually.

 ***************************************
 */

// Array starts at VAL 0.  PWM outputs for mirror motors on D9, 10, 11
int Mirror[] = {
  9, 10, 11};

// PWM outpts for LED status monitors,  They mimic the fan speed
int Led[] = {
  3, 5, 6};

// Analog pins.  Read Pots that control mirror motors
int Pot[] = {
  1, 2, 3};

int potvalue[3];  // Store the value of the Pot[] (this value will be 0-1023)
int mapvalue[3];  // We take the potvalue and rescale it for PWM outputs

int DelayVal = 2000;      // how fast for the PWM randon speed hold in mSecs
int KnobBuffer = 10;      // how much of the top end or bottom end of the pot to ignore for random or off fan
int FullSpin = 0;         // always 0. We want to hit mirrors with full power at program start
int MaxSpin = 0;          // 0 is full blast. largest val for PWM on mirros during run mode
int MinSpin = 200;        // 255 is off.  lowest speed/PWM for mirrors

void setup()
{
  //Serial.begin(9600);  // Comment in final version, just for debug...

  for (int i = 0; i<=2; i++) { 
    pinMode(Mirror[i], OUTPUT);      // sets the digital pins as output
    pinMode(Mirror[i], OUTPUT);
    pinMode(Mirror[i], OUTPUT);
  }

  for (int i = 0; i<=2; i++) {  
    pinMode(Led[i], OUTPUT);      // sets the digital pins as output
    pinMode(Led[i], OUTPUT);
    pinMode(Led[i], OUTPUT);
  }

  randomSeed(analogRead(0));    // Pin 0 is connected to nothing and will read 'noise' to generate a random seed

  //Spin the fan up full Speed to start and
  //Blink the LEDs as a self test
  for (int i = 0; i<=2; i++) {  
    digitalWrite(Mirror[i],0); // 0 (full low PWM applies full power the the fans)
    digitalWrite(Mirror[i],0);
    digitalWrite(Mirror[i],0);
  }

  for (int i = 0; i <= 50; i++) {  // Blink the LEDs
    digitalWrite(Led[0], 0);       // 0 turns the LED on
    digitalWrite(Led[1], 0);
    digitalWrite(Led[2], 0);
    delay(20);

    digitalWrite(Led[0], 255);     // 1 turns the LED off
    digitalWrite(Led[1], 255);
    digitalWrite(Led[2], 255);
    delay(20);
  } // endSelf Test Loop

}   //end Setup()

void loop()
{
  // Use Array values in a 'for loop' to Read the POTs and control the LEDs and Fans

  for (int i = 0; i<=2; i++) {  
    potvalue[i] = analogRead(Pot[i]);    // read the position of one of the three POTs
    
    //the mapvalue function will rescale the potvalues (0 to 1023) to a range for PWM output (255 to 0)
    mapvalue[i] = map(potvalue[i], 0, 1023, MinSpin, MaxSpin);   // on LOW (0) from the Arduino would turn fan full on due to TC4469 inverted input.

    if (mapvalue[i] <= KnobBuffer) {   // is pot near full up position randomize that mirror speed
      mapvalue[i] = random(MaxSpin, MinSpin);  
      delay(DelayVal);  // if we are random speeding the mirror then delay to allow for the speed adjustment to settle
    }

    if (mapvalue[i] >= MinSpin) {  // if POT is full down then
      mapvalue[i] = 255;           // turn off this fan (255 is off due to TC4469 inverted input.
    }

    analogWrite(Mirror[i],mapvalue[i]);   // Spin the fan to the selected or calulated speed.  0 = full; 255 = off
    analogWrite(Led[i], mapvalue[i]);     // LED brightness mimics fan speed.  0 = bright; 255 = off

    /* Serial.prints below are for debug.  Remove in final version.
    Serial.print(mapvalue[i]);
    Serial.print("   ");
    delay(500);
    */

    } //end control array for loop

    //Serial.println();  //Serial.print for debug.  Remove in final version.

}  // end void()  end of program code
-----
After you clean up all the wiring, the finished goods will tidy up nicely:



-----
If all goes well (which it will after you sort through your wiring errors, etc) you will be rewarded with your own laser light show.  Time to get out that Pink Floyd album and enjoy your work. 




-----
If you're still with me, thanks or checking out the build page.  This is a great project because it has a high visual effect; a 'wow' factor.  Good luck.
-----
Link back: Hack A Day
Link back: Hacked Gadgets
-----