Final Project Report
Seasons – Yuke Zhang (Alina) – Gottfried Haider
A. CONCEPTION AND DESIGN:
The concept of my project Seasons is to show the changes in four seasons through the travelling process. My inspiration for this project came from my personal experience of traveling, which made me feel relaxed and relieved. In order to create the atmosphere of traveling, I used a train to move on the route back and forth, which could trigger sensors to open different videos and lights. This idea came from a sightseeing train traveling through mountains and rivers in Arasiyama, Kyoto, Japan, I travelled in which during the spring break. On top of that, thinking of my past experiences with trying some facilities in Disneyland, the tourists often sit in a car or a boat and experienced different scenes in the film through visual and auditory displays. It turned out to be quite interactive. These were the reasons for me to create a moving train in order to represent the traveling process. Also, the “season-changing “ ideas came from a picture on the internet: a man took a photo of a tree every day for a year. Behind the photo, we could see how seasons change and realize the magic of nature (for example, in the spring, there were birds and flowers, which looked dynamic and flourishing; however, in the winter, the leaves had fallen down, seeming lifeless). So, these were perhaps the reasons why I chose to do the project with videos because the videos contained various information that could express the beauty of seasons better. Therefore, I combined those traveling memories and elements during recent years and created an interactive project called Seasons.
To be more specific to introduce the project itself, the users interact with my project by holding the stick on the train, moving it back and forth on the track. Each time when the train stops in front of a tree, the light of that tree will turn to a specific color to that season (four colors light in total) and different videos, which represent the characteristics of four seasons: spring, summer, autumn, and winter. In my opinion, it is not difficult for users to realize the meaning of designing this project, because the big title SEASONS above the laptop instruct them. By trying to move the train, they can soon realize the changing of seasons by showing both videos and light. In this situation, all I need to do is to express the specialty of the videos (they are shot and edited by myself when travelling!).
Because I worked on this project on my own, sometimes the ideas were limited to only one person’s inspiration. However, during the user testing, I got many brilliant suggestions, which did help me a lot. For instance, a Learning Assistant suggested I change the transparent tree with diverse colors of lights by using and controlling simple neopixels. Besides, the professor advised me to make the track and the trees into a diorama, which would make the project visually beautiful. Apart from that, someone suggested forcing the train to move on the track instead of letting it jump above or run out of the track. I took the suggestions and made the adaptations from the advice because they were some specific details, truly making my project better. I think those effective adjustments are the reasons why some audiences are fascinated by my project.
B. FABRICATION AND PRODUCTION:
To begin with, in the first four days, I focused on the main part (interaction with sensors and videos). I used the cardboard to build up the whole project. Although I didn’t fully understand how to write the code to transform from Arduino to Processing, I finally solved the problem with the help of the professor.
After taking some suggestions in user testing, I started to deal with the neopixels and it came to the most difficult part. As I had four trees in four different places, I chose to cut the neopixel strip into small pieces and soldered them with single wires. The process should be easy, but actually, it was the most difficult part of the whole process. To be more specific, since the neopixel is small, it was hard to solder the wires, which means the wires tended to stick together or dropped out of the neopixel easily. In this case, the neopixel couldn’t work well because of the unstable condition they had. At that time, as I planned to put another neopixel strip on the top of my videos from the laptop, the number of neopixels was so much that the circuit could not hold them. In this case, the only thing I needed to do was to change, although I worked on fixing little neopixels for around 10 hours. I was stuck at this point for a while. Suddenly, I came up with the idea to replace the little neopixel with a long strip and control the ones in the strip that match different trees, since the distance of the trees was calculated.
Then, the last important issue I needed to solve was the code with videos. To make the videos smoother when touching the capacitive sensor, I reached out to the professor for some help and made each video effectively play without being interrupted by other videos, and other videos stop playing when touching one specific sensor. Also, as the capacitive sensor could only keep for almost 3 seconds, the professor helped me to change the code to a continuation when touching the sensor, keeping playing the original one until touching the next sensor. Finally, we transformed the processing instruction back to Arduino to make the trees lit the same as the continuations of the video.
Besides those significant problems, other making process was quite simple, but they still needed lots of effort. For example, to begin with, I chose the capacitive sensors, which were quite sensitive but needed effort to make the train connect with the sensor, because the wooden train itself wasn’t conductive. I also did many laser cuts (including the trees, and all the elements in the diorama) of the boards and managed to make the diorama, which needed many calculations of distances in advance. Moreover, I used some paint to make the whole project more beautiful and more engaging with colors, which was the thing I didn’t try before.
C. CONCLUSIONS:
In conclusion, from my point of view, my project Seasons has reached its original goal because the users from different ages enjoy the process of testing and using my project. First, I want to express my own feelings and my own life through this interactive project, therefore, I hope the audience will strike a chord with me about the beauty and scenery in different seasons in life. Besides, there are some connotations about the changing of seasons, like the distinct characteristics and moods of different seasons, which reveal the changing of time. I hope the audience can feel that through touching different sensors and watching the changing of lights and videos. Last, with the little train and sensors engaging in the interactive process, I hope the users can imagine they are on the journey by experiencing the interactive process and feel the meaning of traveling.
One of the users even thought I could change this little model to a large project that could be used by the general public, which made me feel very excited because I found my personal value through the process of showing my artworks to the public. In order to make my project align with the definition of interaction, I made a stick on the train and the transparent board, making users move the train by hand on their own in order to experience the feeling of traveling to various seasons. Also, the different colors of the trees give the instruction for the audience to stop at the tree and enjoy the lights, while the video provides the audience with a direct excitement of scenery in four seasons both visually and auditory, since the styles of the music of seasons were distinct and the edited videos showed three mixed scenes from each season, which has become an attractive scene to the audience.
From the failures that I have made during the whole process (dealing with little neopixels), I would say that communication with people could be helpful because individuals have different personal experiences, which might contribute to my confusing parts of building the project. Also, when encountering these problems, we need to give up a traditional way of thinking (which means we need to figure out something new instead of fixing one thing continuously). By doing this, I finally made accomplishments and I appreciate those trial and error. For the achievements, I simply felt so great after correcting the mistake and reaching success.
If I had more time, I would first improve my project with more adaptation of the videos, because I got some advice from user testing and the final presentation that the videos played for seasons can be shown randomly and I could make some transitions between the videos in different seasons or adjust the speed of playing the video according to the speed of moving the train. Another thing that I could change is the diorama. I could make it more complex, which means that, instead of a normal rectangle track, I could make the train track into a circle in order to show the circulation of time and seasons. As for the diorama itself, I would perhaps make it more interesting with more layers and some irregular shapes, creating an atmosphere of rolling mountains and some huge trees, showing an authentic feeling of travelling.
Overall, my individual final project Seasons not only helped me to become familiar with the techniques of building a project (including coding and the methods of using machines) but also provided me with a chance to reach out to various people (classmates and professors) for help and inspiration, which will benefit my future study in IMA!
D. DISASSEMBLY:
E. APPENDIX
Video:
https://drive.google.com/file/d/1plJ3-9OY0rB1FtIzuy7J8OfpwUsTUAU4/view?usp=drive_link
Pictures:
Code:
Arduino:
#include <FastLED.h> #define NUM_OF_VALUES_FROM_PROCESSING 1 int processing_values[NUM_OF_VALUES_FROM_PROCESSING]; // How many leds in your strip? #define NUM_LEDS 24 // For led chips like WS2812, which have a data line, ground, and power, you just // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, // ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN // Clock pin only needed for SPI based chipsets when not using hardware SPI #define DATA_PIN1 8 #define DATA_PIN2 9 // Define the array of leds CRGB leds1[24]; CRGB leds2[24]; int sensorVal1; int sensorVal2; int sensorVal3; int sensorVal4; void setup() { Serial.begin(9600); FastLED.addLeds<NEOPIXEL, DATA_PIN1 >(leds1, NUM_LEDS); // GRB ordering is assumed FastLED.addLeds<NEOPIXEL, DATA_PIN2 >(leds2, NUM_LEDS); // GRB ordering is assumed FastLED.setBrightness(70); // external 5V needed for full brightness pinMode(2, INPUT); pinMode(3, INPUT); pinMode(5, INPUT); pinMode(4, INPUT); for(int i = 0; i < 24; i = i + 1){ leds2[i] = CRGB(random(0, 256), random(0, 256), random(0, 256)); FastLED.show(); // delay(50); } } long lastColorChange; void loop() { getSerialData(); if(millis() - lastColorChange > 1000){ for(int i = 0; i < NUM_LEDS; i = i + 1){ leds2[i] = CRGB(random(255), random(255), random(255)); } lastColorChange = millis(); } //delay(500); // read the input pin sensorVal1 = digitalRead(2); // print out the value of the sensor if(processing_values[0] == 0){ leds1[1] = CRGB::Pink; leds1[2] = CRGB::Pink; }else{ leds1[1] = CRGB::Black; leds1[2] = CRGB::Black; } FastLED.show(); // read the input pin sensorVal2 = digitalRead(3); // print out the value of the sensor if(processing_values[0] == 1){ leds1[8] = CRGB::Green; leds1[9] = CRGB::Green; }else{ leds1[8] = CRGB::Black; leds1[9] = CRGB::Black; } FastLED.show(); // read the input pin sensorVal3 = digitalRead(4); // print out the value of the sensor if(processing_values[0] == 2){ leds1[14] = CRGB::Orange; leds1[15] = CRGB::Orange; }else{ leds1[14] = CRGB::Black; leds1[15] = CRGB::Black; } FastLED.show(); // read the input pin sensorVal4 = digitalRead(5); // print out the value of the sensor if(processing_values[0] == 3){ leds1[21] = CRGB::Blue; leds1[22] = CRGB::Blue; }else{ leds1[21] = CRGB::Black; leds1[22] = CRGB::Black; } FastLED.show(); Serial.print(sensorVal1); Serial.print(","); Serial.print(sensorVal2); Serial.print(","); Serial.print(sensorVal3); Serial.print(","); Serial.println(sensorVal4); } void getSerialData() { staticint tempValue = 0; // the "static" makes the local variable retain its value between calls of this function staticint tempSign = 1; staticint valueIndex = 0; while(Serial.available()){ char c = Serial.read(); if(c >= '0' && c <= '9'){ // received a digit: // multiply the current value by 10, and add the character (converted to a number) as the last digit tempValue = tempValue * 10 + (c - '0'); }elseif(c == '-'){ // received a minus sign: // make a note to multiply the final value by -1 tempSign = -1; }elseif(c == ',' || c == '\n'){ // received a comma, or the newline character at the end of the line: // update the processing_values array with the temporary value if(valueIndex < NUM_OF_VALUES_FROM_PROCESSING){ // should always be the case, but double-check processing_values[valueIndex] = tempValue * tempSign; } // get ready for the new data by resetting the temporary value and sign tempValue = 0; tempSign = 1; if(c == ','){ // move to dealing with the next entry in the processing_values array valueIndex = valueIndex + 1; }else{ // except when we reach the end of the line // go back to the first entry in this case valueIndex = 0; } } } }
import processing.video.*; import processing.serial.*; Movie[] movies = new Movie[4]; int lastVideoPlayed = -1; Serial serialPort; int NUM_OF_VALUES_FROM_PROCESSING = 1; /* CHANGE THIS ACCORDING TO YOUR PROJECT */ /* This array stores values you might want to send to Arduino */ int processing_values[] = new int[NUM_OF_VALUES_FROM_PROCESSING]; int NUM_OF_VALUES_FROM_ARDUINO = 4; /* CHANGE THIS ACCORDING TO YOUR PROJECT */ /* This array stores values from Arduino */ int arduino_values[] = new int[NUM_OF_VALUES_FROM_ARDUINO]; void setup() { //size(1600, 900); fullScreen(); movies[0] = new Movie(this, "spring.mp4"); movies[1] = new Movie(this, "summer.mp4"); movies[2] = new Movie(this, "autumn.mp4"); movies[3] = new Movie(this, "winter.mp4"); printArray(Serial.list()); // put the name of the serial port your Arduino is connected // to in the line below - this should be the same as you're // using in the "Port" menu in the Arduino IDE serialPort = new Serial(this, "/dev/cu.usbmodem101", 9600); } void draw() { getSerialData(); if (movies[0].available()) { movies[0].read(); image(movies[0], 0, 0, width, height); } if (movies[1].available()) { movies[1].read(); image(movies[1], 0, 0, width, height); } if (movies[2].available()) { movies[2].read(); image(movies[2], 0, 0, width, height); } if (movies[3].available()) { movies[3].read(); image(movies[3], 0, 0, width, height); } if (arduino_values[0] == 1) { if (lastVideoPlayed != -1 && lastVideoPlayed != 0) { movies[lastVideoPlayed].stop(); } movies[0].play(); lastVideoPlayed = 0; } else if (arduino_values[1] == 1) { if (lastVideoPlayed != -1 && lastVideoPlayed != 1) { movies[lastVideoPlayed].stop(); } movies[1].play(); lastVideoPlayed = 1; } else if (arduino_values[2] == 1) { // stop any other playing video if (lastVideoPlayed != -1 && lastVideoPlayed != 2) { movies[lastVideoPlayed].stop(); } movies[2].play(); lastVideoPlayed = 2; } else if (arduino_values[3] == 1) { // stop any other playing video if (lastVideoPlayed != -1 && lastVideoPlayed != 3) { movies[lastVideoPlayed].stop(); } movies[3].play(); lastVideoPlayed = 3; } processing_values[0] = lastVideoPlayed; sendSerialData(); } void getSerialData() { while (serialPort.available() > 0) { String in = serialPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII if (in != null) { print("From Arduino: " + in); String[] serialInArray = split(trim(in), ","); if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) { for (int i=0; i<serialInArray.length; i++) { arduino_values[i] = int(serialInArray[i]); } } } } } void sendSerialData() { String data = ""; for (int i=0; i<processing_values.length; i++) { data += processing_values[i]; // if i is less than the index number of the last element in the values array if (i < processing_values.length-1) { data += ","; // add splitter character "," between each values element } // if it is the last element in the values array else { data += "\n"; // add the end of data character "n" } } // write to Arduino serialPort.write(data); print("To Arduino: " + data); // this prints to the console the values going to Arduino }