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.
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.
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