Joystick Controlled Light Show

Have you ever seen one of those automated light shows and wondered how they are done? Using an Arduino, a few bits of extra hardware and some patience, Wayne and his daughter have tackled the idea and taken their first steps into a larger world. They have taken on a massive project of creating a light show for a 20 foot tall Christmas tree!

This project was submitted by one of our members.  You can see more of our member's projects here.

Not a member yet?  Sign up here.

Their Bright Idea

Their idea is to have several different patterns that randomly switch while the tree is on and to also give the user some control with a joystick. Eight strands of green lights make up the bulk of the tree, strung down from the tip. On the interior are 12 light spheres controlled through two solid state relays. Finally at the top of the tree is a group of red lights that provide some pomp and circumstance for the finale.

With a project like this, there is obviously a lot of hardware and plenty of software to go along with it. While developing things it is often the best course to use a prototype for easier debugging and that is exactly what Wayne and his daughter did.

Arduino Joystick Light Controller

Spreading the Holiday Joy(stick)

The joystick gives this project something many other light shows lack: user interaction! Using the stick, a user can select which strand of lights to ignite by moving in the relevant direction. The user can also activate a secondary light show with spheres of lights on the interior of the tree and a final group of red lights at the peak of the tree.

While integrating the joystick, there are several signals to take into account. They had the X and Y signals which will be analog; as such they have been attached to separate analog inputs on the Arduino. The stick can also be actuated on the Z axis as a simple button read from a digital input. They have extrapolated the position of the joystick through the X and Y data collected through the analog inputs and from there activated the selected strand.

Separately, the Z axis of the stick is monitored and once pressed, the interior of the tree comes to life with all the spheres sparkling randomly culminating in the red lights shooting out of the top of the tree.

Arduino Joystick Light Controller

Beyond the Hardware

So there is a lot going on here already! Monitoring and handling analog data as well as listening for the button press might make us forget about programming the light patterns. While this may seem like a daunting task, getting a light show to look good doesn’t have to be complicated! Wayne has created nine different patterns that alternate randomly throughout the green strands. The ‘random’ function gives them an integer to use as a key for choosing the next light pattern. Simply storing the last key and checking against the new one prevents the program from executing the same pattern twice in a row!

As for specific patterns, they have implemented progressive lighting from bottom to top as well as top to bottom. There is sparkling lights, rotating lights, flashing lights and several others. Putting in a few clever loops, they were able to cut down on the code and get it to work for them instead of the other way around!

The Sky’s the Limit

While the project is already very far along, Wayne has more to tackle with the project before completion. There is more tuning to do with the joystick (trust me, get used to tuning) to make it more precise. All the work so far has been done with not a lot of experience so who knows what they can accomplish with more work!

This is what Wayne had to say about their experience:

“I was introduced to Arduino/sketches by my brother just 2 months ago and have really enjoyed the lecture series from Programming Electronic Academy. I have joined forces with my 9 yo daughter to learn/build together. Can’t wait for more lectures. Cheers.”

-Wayne

Once all the precision is there and the bugs are worked out, they will move from the prototype to the full 20 foot tree! In the meantime have a look at their quick demo video and take a browse through the code. They’ve made great strides so far and we’re excited to see the final product!

Arduino Code:

const int xPin = A0;     //X axis of joystick
const int yPin = A1;     //Y axis of joystick
const int zPin = 13;     //Z axis of joystick

int Pin;
int pinBehind;
int pinBehindNext;
int randomBulb;
int randomStars;
int randomLighting;
int randomDelay;
int previousRandomLightingScheme = 0;
int joystickPositionX;
int joystickPositionY;
int joystickPositionZ;


void setup() 
{
  Serial.begin(9600);  //Initiate serial communication

  // Sets pins 2-12 as output
  for (int Pin = 2; Pin < 13; Pin++) {
    pinMode(Pin, OUTPUT);
  }
  
  pinMode (xPin, INPUT); // sets x axis of joystick as input
  pinMode (yPin, INPUT); // sets y axis of joystick as input
  pinMode (zPin, INPUT); // sets z axis of joystick as input

  // Sets pins 16-19 as output
  for (int Pin = 16; Pin <=19; Pin++) {
    pinMode (Pin, OUTPUT);
  }
}


void loop() {
  joystickPositionX = analogRead(xPin); //joystickPositionX is set to analog read value of xPin
  joystickPositionY = analogRead(yPin); //joystickPositionY is set to analog read value of yPin
  joystickPositionZ = digitalRead(zPin); //joystickPositionZ is set to digital read value of zPin

  /*
  * While the joystick's X OR Y position are more than 5 points away from center (515)
  * OR the joystick's Z axis is pressed, run this code
  */
  while ((abs(joystickPositionX - 515) > 5) || (abs (joystickPositionY - 515) > 5) || (joystickPositionZ == 0)) { 
    // Debugging
    Serial.print("X: "); //print "X"
    Serial.print(joystickPositionX); // print joystick's x axis position
    Serial.print("\tY: "); //tab over and print "Y"
    Serial.print(joystickPositionY); //print joystick's y axis position
    Serial.print("\tZ: "); //tab over and print "Z"
    Serial.println(joystickPositionZ); //print joystick's z axis position
    delay(5);//delay 5ms
    
    /* 
     *  This block is checking the position of the joystick
     *  and taking the requisite action ie lighting the correct
     *  strand of lights
     */
    if (joystickPositionY >= 1000 && joystickPositionX >1000)
      {digitalWrite(2, HIGH);}
    else if(joystickPositionY < 1000 && joystickPositionX <= 1000)
      {digitalWrite(2, LOW);}
    
    if (joystickPositionX >= 1000)
      {digitalWrite(3, HIGH);} // joystick pushed to right and reads > 1000 will turn on pin
    else if (joystickPositionX < 1000)
      {digitalWrite(3, LOW);} // otherwise pin will be off
    
    if (joystickPositionX >= 1000 && joystickPositionY <=20)
      {digitalWrite(4, HIGH);}
    else if (joystickPositionX < 1000 && joystickPositionY >20)
      {digitalWrite(4, LOW);}
    
    if (joystickPositionY <= 20)
      {digitalWrite(5, HIGH);} // joystick pushed down and reads < 20 will turn on pin
    else if (joystickPositionY > 20)
      {digitalWrite(5, LOW);} // otherwise pin will be off
    
    if (joystickPositionY <=20 && joystickPositionX <= 20)
      {digitalWrite(6, HIGH);}
    else if (joystickPositionY >20 && joystickPositionX > 20)
      {digitalWrite(6, LOW);}
    
    if (joystickPositionX <= 20) 
      {digitalWrite(7, HIGH);} // joystick pushed to left and reads < 20 will turn on pin
    else if (joystickPositionX > 20)
      {digitalWrite(7, LOW);} // otherwise pin will be off
    
    if (joystickPositionX <=20 && joystickPositionY >=1000)
      {digitalWrite(8, HIGH);}
    else if (joystickPositionX >20 && joystickPositionY <1000)
      {digitalWrite(8, LOW);}
    
    if (joystickPositionY >= 1000)
      {digitalWrite(9, HIGH);} // joystick pushed up and reads > 1000 will turn on pin
    else if (joystickPositionY < 1000)
      {digitalWrite(9, LOW);} // otherwise pin will be off
    
    /*
     * Checks for Z axis press, activates red lights around the top
     */
    if (joystickPositionZ == 0) {
      
      // Flashes the lights at the top randomly 50 times
      for (int counter = 0; counter <50; counter++) {
        randomBulb = random(10, 13); //Create a random number for pins 10-12
        Serial.print("Random bulb:  ");
        Serial.println(randomBulb); //Print randomBulb number
        digitalWrite(randomBulb, HIGH); //turn on the pin
        delay(100);
        digitalWrite(randomBulb, LOW); // turn off the pin
        
        randomBulb = random (16, 19); //Create random number for pins 16-18
        Serial.print("Random bulb:  ");
        Serial.println(randomBulb); //Print randomBulb number
        digitalWrite(randomBulb, HIGH); //turn on the pin
        delay(100);
        digitalWrite(randomBulb, LOW); // turn off the pin
      }
      digitalWrite(19, HIGH); //this pin will light a bunch of red lights at the top of the tree
      delay(5000);// keep red lights on for 5 secs
      digitalWrite(19, LOW); //turn off the red lights
    }
    
    // Update all pin positions before exiting the while loop
    joystickPositionX = analogRead(xPin);
    joystickPositionY = analogRead(yPin);
    joystickPositionZ = digitalRead(zPin);
  } // end while
  
  // Turn off pins 2 thru 12 after while loop is complete
  for (int Pin = 2; Pin <13; Pin++) {
    digitalWrite(Pin, LOW);
  }
  
  
  
  randomLighting = random(0, 10); //generates random number 0 thru 9
  
  // Ensure random numbers are not equal to previous
  while (randomLighting == previousRandomLightingScheme) {
    randomLighting = random(0, 10); //will generate another random number if the same as the previous random number
  } 
  
  Serial.print("Lighting Scheme:  "); //print 
  Serial.println(randomLighting); //Print random lighting number
  previousRandomLightingScheme = randomLighting; //sets previous random number to the current number 
  
  /*
   * This is where the light patterns are stored
   * The patterns are chosen based on the randomLighting number
   */
  // executes if random number is 0 - stars light up from low to high 
  if (randomLighting == 0) {
    randomDelay = random (100, 500);  //create random delay number

    // loop from the lowest to the highest pin with random delay
    for (int Pin = 2; Pin <10; Pin++) {
      digitalWrite(Pin, HIGH);  // turn on the pin
      delay(randomDelay); // random delay
      digitalWrite(Pin, LOW);  // turn off the pin
    }
    delay(500);
  } 
  
  else if (randomLighting == 1) { //executes if random number is 1 - stars light up from high to low
    randomDelay = random (100, 500); //create random delay number
    
    // loop from the highest pin to the lowest with random delay
    for (int Pin = 9; Pin >= 2; Pin--) {
      digitalWrite(Pin, HIGH);  //turn on the pin
      delay(randomDelay); // random delay
      digitalWrite(Pin, LOW); // turn the pin off
    }
    delay(500);
  }
  
  else if (randomLighting == 2) { //executes if random number is 2 - fast flickering stars
    delay(3000);//Delay 3 seconds for effect
    for (int Pin = 10; Pin <13; Pin++) {  // turn on pins 10-12 and 16-18 all at once
      digitalWrite(Pin, HIGH);
      digitalWrite(Pin + 6, HIGH);
    }
    for (int counter = 0; counter <200; counter++) { // count and perform 200 times
      randomStars = random(2, 10); //Create a random number and assign it to the randomStars variable
      Serial.print("Random fast:  ");
      Serial.println(randomStars); //Print random fast number
      digitalWrite(randomStars, HIGH); //turn on the pin
      delay(50);
      digitalWrite(randomStars, LOW); // turn off the pin
      delay(1);
    }
    for (int Pin = 10; Pin <13; Pin++) {  // turn of pins 10-12 and 16-18 all at once
      digitalWrite(Pin, LOW); 
      digitalWrite(Pin + 6, LOW);
    }
  }
  
  else if (randomLighting == 3) { //executes if random number is 3 - slow flickering stars
    for (int counter = 0; counter <40; counter++) { // count and perform 40 times
      randomStars = random(2, 10); //Create a random number and assign it to the randomStars variable
      Serial.print("Random slow:  ");
      Serial.println(randomStars); //Print random slow number
      digitalWrite(randomStars, HIGH); //turn on the pin
      delay(300);
      digitalWrite(randomStars, LOW); // turn off the pin
      delay(1);
    }
  }
  
  else if (randomLighting == 4) { //executes if random number is 4 - stars light up high to low and then low to high
    for (int Pin = 2; Pin <10; Pin++) {  // loop from the lowest to the highest pin
      digitalWrite(Pin, HIGH);  // turn on the pin
      delay(500);  // delay
      digitalWrite(Pin, LOW);  // turn off the pin
    }
    for (int Pin = 9; Pin >= 2; Pin--) {  // loop from the highest pin to the lowest
      digitalWrite(Pin, HIGH);//turn on the pin
      delay(500); //delay
      digitalWrite(Pin, LOW); // turn the pin off
    }
    delay(1);
  }
  
  else if (randomLighting == 5) { //executes if random number is 5 - Green light lights rotate around the light bulbs in the middle
    for (int Pin = 10; Pin <13; Pin++) {  // turn on pins 10-12 and 16-18 all at once - these are th emiddle bulbs
      digitalWrite(Pin, HIGH);  
      digitalWrite(Pin + 6, HIGH);
    }
    for (int counter = 0; counter <10; counter++) { // count and perform 10 times - green lights rotating around in a circle
      for (int Pin = 2; Pin <10; Pin++) {  // loop from the lowest to the highest pin with lighting up 
                                      // pins 3 and 6 positions behind lead pin
        digitalWrite(Pin, HIGH);  // turn on the pin
        if (Pin <=4) {
          delay(500);
        } else if (Pin > 4 && Pin < 8) { // once led pin is at pin 5 the pin behind will turn on
                                      //but then stops when reaches pin 7 
          pinBehind = Pin - 3; 
          digitalWrite(pinBehind, HIGH); //turn on the pin
          delay(500);
        } else if (Pin > 7) { //once led pin is at pin 8 the pin behind and pinBehindNext will turn on
          pinBehind = Pin - 3;
          pinBehindNext = Pin - 6;
          digitalWrite(pinBehind, HIGH); //turn on the pin
          digitalWrite(pinBehindNext, HIGH); //turn on the pin
          delay(500);
        }
        digitalWrite(Pin, LOW);  // turn off the pin
        digitalWrite(pinBehind, LOW); //turn off the pin
        digitalWrite(pinBehindNext, LOW); // turn off the pin
      }
    }
    for (int Pin = 10; Pin <13; Pin++) {  // turn off pins 10-12 and 16-18 all at once
      digitalWrite(Pin, LOW);
      digitalWrite(Pin + 6, LOW);
    }
    delay(500);
  }
  
  else if (randomLighting == 6) { //executes if random number is 6 - turns on all starts at once with random delay
    for (int counter = 0; counter <5; counter++) { // count and perform 5 times
      for (int Pin = 9; Pin >= 2; Pin--) {  // turn on all pins at once
        digitalWrite(Pin, HIGH); //turn on the pin
      } 
      randomDelay = random (1000, 5000);
      delay(randomDelay);
      for (int Pin = 9; Pin >= 2; Pin--) {  // turn off all pins at once
        digitalWrite(Pin, LOW); //turn off the pin
      } 
      delay(500);
    }
  }
  
  else if (randomLighting == 7) { //executes if random number is 7 - turns on all stars at once for 15 seconds
    for (int Pin = 9; Pin >= 2; Pin--) {   // turn on all pins at once for 15 secs
      digitalWrite(Pin, HIGH); //turn on the pin
    }  
    for (int counter = 0; counter <75; counter++) { // count and perform 75 times or for a total of 15 secs
      randomBulb = random(10, 13); //Create a random number 
      Serial.print("Random bulb:  ");
      Serial.println(randomBulb); //Print randomBulb number
      digitalWrite(randomBulb, HIGH); //turn on the pin
      delay(100);
      digitalWrite(randomBulb, LOW); // turn off the pin
      
      randomBulb = random (16, 19); //Create random number
      Serial.print("Random bulb:  ");
      Serial.println(randomBulb); //Print randomBulb number
      digitalWrite(randomBulb, HIGH); //turn on the pin
      delay(100);
      digitalWrite(randomBulb, LOW); // turn off the pin
    }
    for (int Pin = 9; Pin >= 2; Pin--) {  // turn off all pins at once
      digitalWrite(Pin, LOW); //turn off the pin
    }  
    delay(500);
  }
  
  else if (randomLighting == 8) { //executes if random number is 8 - stars light up from low to high but stay on unitl all light up
    randomDelay = random (100, 500);  //create random delay number
    for (int Pin = 2; Pin <10; Pin++) {  // loop from the lowest to the highest pin with random delay
      digitalWrite(Pin, HIGH);  // turn on the pin
      delay(randomDelay); // random delay
    }
    for (int Pin = 2; Pin <10; Pin++) {  // turn off all pins at once
      digitalWrite(Pin, LOW); //turn off the pin
    }  
    delay (500);
  }
    
  else if (randomLighting == 9) { //executes if random number is 9 - stars light up from high to low but stay light
    randomDelay = random (100, 500); //create random delay number
    for (int Pin = 9; Pin >= 2; Pin--) {   // loop from the highest pin to the lowest with random delay
      digitalWrite(Pin, HIGH);  //turn on the pin
      delay(randomDelay); // random delay
    }
    for (int Pin = 2; Pin <10; Pin++) {  // turn off all pins at once
      digitalWrite(Pin, LOW); //turn off the pin
    }  
    delay (500);
  }
} // end loop
installing Arduino libraries

Installing Arduino Libraries | Beginners Guide

IoT sewage project

Pumping poo! An IoT sewage project

ESP32 webOTA updates

How to update ESP32 firmware using web OTA [Guide + Code]

error message Brackets Thumbnail V1

expected declaration before ‘}’ token [SOLVED]

Compilation SOLVED | 1

Compilation error: expected ‘;’ before [SOLVED]

Learn how to structure your code

Leave a Comment