62-362 Fall 2022 https://courses.ideate.cmu.edu/62-362/f2022 Electronic Logics && Creative Practice Tue, 06 Jun 2023 14:09:40 +0000 en-US hourly 1 https://wordpress.org/?v=6.0.8 Rain! Final Documentation (gprado) https://courses.ideate.cmu.edu/62-362/f2022/rain-final-documentation-gprado/ Sat, 17 Dec 2022 00:45:08 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12506 Rain!

Photos

Rain! Commercial

Narrative Description

A frosty white device composed of acrylic panels and a tear-drop shaped facade sits, a computer monitor, and a mouse sit on a table. The user begins the video by clicking on the play button with the mouse. The Rain! commercial plays, instructing the users how to turn on Rain! as well as showcasing a moral dilemma with using the device. The tear-drop contains a speaker centered on its face as well as an IR-proximity sensor just below the speaker. If the user decides to use Rain!, they set their hand directly in front of the sensor for about a second. The tear-drop plays two short messages, with a rectangular light accompanying the second message. These two messages, which berate the user, are narrated by a real yet snarky female voice. The first message corresponds to a certain live temperature range while the second message, along with the light, corresponds to a live sky condition. Once the second message is played, the rectangular light shuts off after about 4 seconds. 

Progression to Final Product

Wiring Particle Argon to Arduino UNO to establish serial communication to transmit API data

 

Arduino receiving API data from Particle Argon

 

Shot of Rain! commercial, filmed in the Media Lab

 

Implementing API values into MusicMaker MP3 Shield and NeoPixel code

 

Packaging Particle Arduino in back compartment of Rain!

 

Rain! setup at Effervescent Shadow Bazaar

Process Reflection

Updating this project for the end-of-semester IDeATe show was a very fun experience as it allowed me to move closer to the initial vision I had for Rain!. The main additions I incorporated included implementing actual live weather data and making a commercial/video to accompany the piece. I also decided to slightly modify the title by including an exclamation mark after “Rain” as I thought that would further emphasize the product-like nature of the project.

Implementing the live weather data was possibly the hardest task of the additions but the most rewarding in terms of what I learned. Researching and writing the code to incorporate data from OpenMeteo weather API was probably the most software I’ve ever written for a project, and this was incredibly valuable since I started off this semester with pretty simple coding knowledge. Using this API as well as establishing serial communication with Arduino was straightforward; coding with the received API values in Arduino proved to be extremely tricky. It involved a lot of experimentation, especially with if/else statements. Although this took many hours, going through this process of trying and experimenting was a critical way of gaining a better understanding of writing code.

One of the major additions I incorporated for this iteration of the project was to include a video element. Given the nature of the IDeATe show, I thought including something additional to my project would draw more attention and interaction with Rain!, and I ultimately decided on using video as the medium for that since I thought making a video would be fun. I wanted to include a dystopian element to Rain!, similar to the vibe in the techno-thriller show Black Mirror. To do this, I made the video a mixture between a commercial and “found footage”, with the latter showcasing the hidden, nefarious intentions of Rain!. I don’t have a lot of experience making short movies, so the quality of the video was hindered by this. However, I think I was able to showcase a humorous product with the commercial with a contrast of malintent in the “found footage” section.

With how loud the show was, it was very difficult to hear the video and Rain!. One would have to put their ears up close to the devices to be able to hear properly. I used the speakers on the computer monitor for the video; having separate speakers connected to the monitor for the video would have made the hearing situation better. As for Rain!, I don’t think there was else much I could do given the size of its speaker.

I plan on using Rain! personally in my dorm room as I really enjoy using it, especially as it is properly configured with live weather data. I do think it’s lacking in a bit of utility which would provide more incentive for its use. I plan on having Rain! provide the user with the current temperature in addition to the insults, perhaps with an intimidating text-to-speech generator to create the MP3 files for each temperature value.

Code

Arduino Uno

/*
Rain!
Gabriel Prado

Code implements live weather data from Particle Argon to initiate MP3 files and NeoPixels

Use of NeoPixels and Adafruit MusicMaker MP3 Shield libraries

*/

#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>


// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin



Adafruit_VS1053_FilePlayer musicPlayer = 
  
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
  
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif

// Which pin on the Arduino is connected to the NeoPixels?
#define PIN        6 // On Trinket or Gemma, suggest changing this to 1

// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 32 // Popular NeoPixel ring size


Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels

int temps[] = {"/track001.mp3" , "/track002.mp3", "/track003.mp3" , "/track004.mp3" , "/track005.mp3", "/track006.mp3",
"/track007.mp3" , "/track008.mp3", "/track009.mp3" , "/track010.mp3" , "/track011.mp3" , "/track012.mp3" , "/track013.mp3" ,
"/track014.mp3" , "/track015.mp3" , "/track016.mp3" , "/track017.mp3" , "/track018.mp3" , "/track019.mp3" , "/track020.mp3", 
"/track021.mp3" , "/track022.mp3" , "/track023.mp3" , "/track024.mp3" ,"/track025.mp3" , "/track026.mp3"}; //all MP3 files


#include <SoftwareSerial.h>

SoftwareSerial mySerial(5, 12); //pins used for serial connection to Particle Argon 

void setup() {
  pinMode(A0,INPUT);  //input for IR proximity sensor
  Serial.begin(9600);
  mySerial.begin(9600);

  musicPlayer.begin();
  SD.begin(CARDCS);
  
  musicPlayer.setVolume(10,10);
  
  #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif

  pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
  
}
int Temp = 0;
int Skies = 0;

void loop() {
  if(mySerial.available()){ //all actions occur within this if statement
    int TempRead = mySerial.parseFloat(); //Temperature value from API
    int SkiesRead = mySerial.parseFloat(); //Sky Condition value from API
    if (TempRead != 0){
      Temp = TempRead;
    }
    if (SkiesRead != 0){
      Skies = SkiesRead;
    }
    Serial.println(Temp);
    Serial.println(Skies);
    
    pixels.clear();

    
    if(analogRead(A0) >= 200){ //user presses finger on IV proximity sensor
      int a = Temp; //a is the live temperature in Farenheit
      if(a == 0 or a == 1 or a == 2 or a == 3 or a == 4 or a == 5 or a ==6){
           musicPlayer.playFullFile(temps[0]);
        }
      else if(a == 7 or a ==8 or a == 9 or a == 10 or a == 11 or a == 12){
           musicPlayer.playFullFile(temps[1]);
      }
     
      else if (a == 13 or a == 14 or a == 15 or a ==16 or a ==17 or a == 18 or a == 19){
          musicPlayer.playFullFile(temps[2]);
        }
      else if (a == 20 or a == 21 or a == 22){
         musicPlayer.playFullFile(temps[3]);
      }
      else if (a == 23 or a == 24){
         musicPlayer.playFullFile(temps[4]);
      }
      else if (a == 25 or a == 26 or a == 27 or a == 28 or a == 29){
        musicPlayer.playFullFile(temps[5]);
      }
      else if (a == 30 or a == 31 or a == 32 or a == 33 or a == 34){
        musicPlayer.playFullFile(temps[6]);
      }
      else if (a == 35 or a == 36 or a == 37 or a == 38 or a == 39){
          musicPlayer.playFullFile(temps[7]);
        }
      else if (a == 40 or a == 41 or a == 42 or a == 43 or a == 44){
        musicPlayer.playFullFile(temps[8]);  
      }
      else if (a == 45 or a == 46 or a == 47 or a == 48 or a == 49){
        musicPlayer.playFullFile(temps[9]);
      }
      else if (a == 50 or a == 51 or a == 52 or a == 53 or a == 54){
        musicPlayer.playFullFile(temps[10]);
      }
      else if (a == 55 or a == 56 or a == 57 or a == 58 or a == 59){
        musicPlayer.playFullFile(temps[11]);
      }
      else if (a == 60 or a == 61 or a == 62 or a == 63 or a == 64){
        musicPlayer.playFullFile(temps[12]);
      }
      else if (a == 65 or a == 66 or a == 67 or a == 68 or a == 69){
        musicPlayer.playFullFile(temps[13]);
      }
      else if (a == 70 or a == 71 or a == 72 or a == 73 or a == 74){
        musicPlayer.playFullFile(temps[14]);
      }
      else if (a == 75 or a == 76 or a == 77 or a == 78 or a == 79){
        musicPlayer.playFullFile(temps[15]);
      }
      else if (a == 80 or a == 81 or a == 82 or a == 83 or a == 84){
        musicPlayer.playFullFile(temps[16]);
      }
      else if (a == 85 or a == 86 or a == 87 or a == 88 or a == 89){
        musicPlayer.playFullFile(temps[17]);
      }
      else if (a == 90 or a == 91 or a == 92 or a == 93 or a == 94){
        musicPlayer.playFullFile(temps[18]);
      }
      else if (a == 95 or a == 96 or a == 97 or a == 98 or a == 99 or a == 100){
        musicPlayer.playFullFile(temps[19]);
      }
      int b = Skies; //b is the sky condition number
      if(b == 61 or b == 63 or b == 65 or b == 66 or b == 67 or b == 80 or b == 81 or b == 82 or b == 51 or b == 53 or b == 55 or b == 56 or b == 57){
          for(int i=0; i<NUMPIXELS; i++){ //blue
                     pixels.setPixelColor(i, pixels.Color(0, 191, 255));
                      pixels.show();   
                      }
                  musicPlayer.playFullFile("/track021.mp3"); //rainy
                  delay(4000);
                  pixels.clear();
                  for(int i=0; i<NUMPIXELS; i++){ //NeoPixel reset
                     pixels.setPixelColor(i, pixels.Color(0, 0, 0));
                      pixels.show(); 
                       }
        }
        else if(b == 0 or b == 1){
          for(int i=0; i<NUMPIXELS; i++){ //currently pink for clear, but can be coded to red for sunny
                         pixels.setPixelColor(i,pixels.Color(255,102,255));
                          pixels.show();   
                      }
                      musicPlayer.playFullFile("/track026.mp3"); //sunny/clear
                      delay(4000);
                      pixels.clear();
                     for(int i=0; i<NUMPIXELS; i++) { //NeoPixel reset
                           pixels.setPixelColor(i, pixels.Color(0, 0, 0));
                           pixels.show();   
                        }
              }
        
        else if(b == 2 or b == 3 or b == 45 or b == 48){
          for(int i=0; i<NUMPIXELS; i++){ //gray
                         pixels.setPixelColor(i, pixels.Color(32, 32, 32));
                          pixels.show();   // Send the updated pixel colors to the hardware.
                      }
                      musicPlayer.playFullFile("/track023.mp3"); //cloudy
                      delay(4000);
                      pixels.clear();
                     for(int i=0; i<NUMPIXELS; i++){ //NeoPixel reset
                           pixels.setPixelColor(i, pixels.Color(0, 0, 0));
                           pixels.show();   
                        }
              }
        
        else if(b == 71 or b == 73 or b == 75 or b == 77 or b == 85 or b == 86){
          for(int i=0; i<NUMPIXELS; i++){ //white
                         pixels.setPixelColor(i, pixels.Color(255, 255, 255));
                          pixels.show();   
                      }
                      musicPlayer.playFullFile("/track024.mp3"); //snowy
                      delay(4000);
                      pixels.clear();
                     for(int i=0; i<NUMPIXELS; i++){ //NeoPixel reset
                           pixels.setPixelColor(i, pixels.Color(0, 0, 0));
                           pixels.show(); 
                        }
              }
        
        else if(b == 95 or b == 96 or b == 99){
          for(int i=0; i<NUMPIXELS; i++){ //yellow
                         pixels.setPixelColor(i, pixels.Color(255, 100, 0));
                          pixels.show();   
                      }
                      musicPlayer.playFullFile("/track025.mp3"); //stormy
                      delay(4000);
                      pixels.clear();
                     for(int i=0; i<NUMPIXELS; i++){ //NeoPixel reset
                           pixels.setPixelColor(i, pixels.Color(0, 0, 0));
                           pixels.show();   
                        }
              }
        }
  }
}

Particle Argon

/*
Rain!
Gabriel Prado

Code sends temperature and sky condition data from OpenMeteo API to Arduino Uno via Serial

This code is from Daragh Byrne's work with OpenMeteo (https://diotlabs.daraghbyrne.me/docs/working-with-data/webhooks/openmeteo_weather)

*/
    

void setup() {
  // Subscribe to the integration response event
  Serial.begin(9600);
  Serial1.begin(9600);
  Particle.subscribe("hook-response/get-forecast", handleForecastReceived );

}

void loop() {\
  getData();
  delay(10000);
}   
      
void getData()
{
     // Publish an event to trigger the webhook
  Particle.publish( "get-forecast" );
}

 
String temperature = "";
int weatherCode = 0;

// This function will handle data received back from the webhook
void handleForecastReceived(const char *event, const char *data) {
  // Handle the integration response

  String receivedStr =  String( data );
  int loc1 = 0;
  int loc2 = 0;

  loc1 = receivedStr.indexOf("~");

  temperature = receivedStr.substring(0,loc1); //Temperature in F

  
  loc2 = receivedStr.indexOf("~",loc1+1);
  weatherCode = (double) String(receivedStr.substring(loc1+1,loc2)).toFloat(); //Sky condition
  
  Serial1.print(temperature); //Temperature sent to Arduino
  Serial1.print(",");
  Serial1.println(weatherCode); //Sky condition sent to Arduino
 
}

Insults

Rain (0) --> 21. And don't bother getting your umbrella, you'll need a shower anyways
Sunny (1) --> 22. Looks like we're gonna have sun today. Here's a fun tip: stare at it 
Cloudy (2) --> 23. The sky is gray,not the brightest. I'm sure you can relate 
Snow (3) --> 24. The snow is so pure and wonderful, and you're a disgusting blemish
Stormy (4) --> 25. It's getting rough out there, have fun!
Clear (1) --> 26. The sky is clear, but I'll be sincere: I hate you

0-20 degree range
     1. I just wanna see you freeze to death
     2.Ready to freeze, scum?
     3. The weather outside looks frightful, but you look even more frightful. Seriously, just look at yourself.  
     
20-30 degree range
     4. See if I liked you, I would tell you to stay inside. But, I don't so, get out there!
     5. You should wear your jacket, but seriously it makes you look like a balloon
     6. The freezing point of human blood is 31 degrees, so let's keep our fingers crossed shall we?
     
30 - 40 degree range
     7. It's too cold to for a walk and too hot to go sledding, so go screw yourself
     8. Looks like you'll be looking for warmth again, we all know how that will go

40 - 50 degree range
     9. Whatever drink you get to keep you warm, I hope you spill it all over yourself
     10. The temperature right now is the number of reasons why you're a loser
50 - 60 degree range
     11. Slightly cool, slightly warm. I don't know anymore, so screw you
     12. The temperature is as meh as your looks
     
60 - 70 degree range
     13.It's getting kind of hot in here, I hope your body oder doesn't show
     14. You should go outside and enjoy the weather. Oh wait, you're a loser my bad 

70 - 80 degree range
     15. It's so warm, unlike your personality
     16. The temperature right now is pretty great to be honest. The only thing in my way is you


80 - 90 degree range
     17. It' really hot, unlike you
     18. Global warming is coming for you!
     

90 - 100 degree range
     19. Time to starting wearing less, but no one wants to see that 
     20. Some people wanna watch the world burn, like me

Sources

Snarky Female Voice –> Jolie Ma

Robotic Male Voice –> https://voicemaker.in/

Insults –> Katarina Garcia, Soomin Kong, Jolie Ma, Gabriel Prado

OpenMeteo API Code –> https://diotlabs.daraghbyrne.me/docs/working-with-data/webhooks/openmeteo_weather (by Daragh Byrne)

Subject in Commercial –> Jolie Ma

Tear-drop Shape –>

 

]]>
Documentation Flux+ https://courses.ideate.cmu.edu/62-362/f2022/pflux/ Fri, 16 Dec 2022 22:36:07 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12490

Description / Narration:

Above viewers see a painting easel that allows them to co-create a visual representation of your interactions with it. The flow of colored ink through tubes mounted on the easel mixes and creates a painting on a paper roll. When viewer is standing nearby, or simply just passing-by, their horizontal position relative to the installation will be sent to the paint sets. This setup transduce the distance between viewer and the installation into a visual representation through the flow of colors, which can vary depending on the flow rates of the ink and the order in which the viewers enter the painting area. Tubes closest to you will have the quickest colors flow, and color sometimes mixes. There are three basic colors: red, blue, yellow, then are four color combinations available: red and blue, red and yellow, yellow and blue, and red and blue. Within a timeframe, such as one night, the viewers’ activity will be documented on the paper through this color flows. The painting can be taken away by the viewers once the paper roll is pulled down and cut.

 

 

Process Photo:

Process Reflection

In the process of building Flux, I struggled to integrate design + mechanical + computational, three elements effectively. I found it easy to come up with a concept, but integrating the mechanical components with fabrication, plus the computational aspect was much more challenging. In the project 2, there are several defects that I need to iterate on, which gives another layer of complexity to this final show.

One of the hardest parts of the project was rebuilding the tube settings and calibrate the pumps and sensors. Last presentation, the tubes were not adjusted in a fixed location, so colors sprayed everywhere, and cleaning became a hard problem. This time, I undo, and reconnected all the tubings on the easel, with a better planned mounting steps. I always told myself to stay alert when dealing with the mechanics and fabrication, with the idea that fixing can take much longer than being careful. After the three hours preparation, the tubings finally sit correctly.

The other part was the pumps and sensors, in which are more challenging. As I wanted to control the color flow without letting it went crazy, I re-tested its pwm prior to the show, and re-mounted them with lots of glues. However, this was just the first step. Calibrating the sensors so that they sent appropriate signals to the pump was another thing I tried hard. From rewritting the color arranging code, to testing the performance of the code with varying physical distance, I was managed to use eight sensors and guaranteed at least six would be working. Though this was a algorithmic aspect of the project, I believe this effort did contributed a lot to the performance of this artwork. Looking back to my project 2, the aforementioned instances where I thought I had everything working correctly, only to realize there was an error somewhere that was causing the project to malfunction. Though last time was frustrating, this time I knew the importance of thorough testing and debugging. It became easier to integrate all the different elements and to troubleshoot any issues that arose.

The show was amazing. People were attracted by the interesting flows of colors, as well as the creative paints generated through this interactive sets. In specific, during later part of the show, when the colors were richer on the paper, the painting looked magical. As some of them noticed the sensors, most of them were surprised by the concept of this piece. Though the preparation took a bit longer time than expected, I felt proud to my final work and grateful to everyone who made this happen. Thanks to the lighting, the other art pieces, and everyone, who made the night a poetic co-creation.

Lastly, dealing with the leftover paints after the show taught me valuable skills in organization and patience. I had to disassemble most of the components I had built from scratch and carefully clean them one by one in the sink. It was a time-consuming and tiring process, but I felt a sense of accomplishment and responsibility for not only my own artwork, but for the entire show. Despite being the last student to leave the WQED studio, I left feeling satisfied and proud of the work I had put in. The experience reinforced the importance of being organized and taking care of my surroundings.

Overall, this project was a great learning experience. It pushed me to learn new skills and taught me the importance of careful planning and thorough testing. I’m excited to apply what I learned to future projects and to continue growing as a creative and technical thinker.

 

Video Demonstration:

 

Code Submission:

//FLUX code
//Sunniva Liu
#include <NewPing.h>
int myArray1[20];
int myArray2[20];
int myArray3[20];
int myArray4[20];
int myArray5[20];
int myArray6[20];
int myArray7[20];
int myArray8[20];
int sensorValue[8] = {0,0,0,0,0,0,0,0};

int counter1 = 0;
int counter2 = 0;
int counter3 = 0;
int counter4 = 0;
int counter5 = 0;
int counter6 = 0;
int counter7 = 0;
int counter8 = 0;

int rawValue1;
int rawValue2;
int rawValue3;
int rawValue4;
int rawValue5;
int rawValue6;
int rawValue7;
int rawValue8;

int pump1 = 6;
int pump2 = 7;
int pump3 = 8;
int pump4 = 9;
int pump5 = 10;
int pump6 = 11;
int pump7 = 12;
int pump8 = 13;
//1,3,5,8 - on; 2,4,6,7 off
int pumpValue1 = 80; //200
int pumpValue2 = 100; //150
int pumpValue3 = 80;
int pumpValue4 = 100;
int pumpValue5 = 100;
int pumpValue6 = 80;
int pumpValue7 = 100;
int pumpValue8 = 80;

int distance_two[2] = {0,0};
int distance_pin[2] = {0,0};

#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

#define TRIGGER_PIN1  22  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN1     23  // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN2  24  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN2     25 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN3  26  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN3   27 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN4  28  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN4     29 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN5  30  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN5     31 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN6  32  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN6     33 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN7  34  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN7     35 // Arduino pin tied to echo pin on the ultrasonic sensor.

#define TRIGGER_PIN8  36  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN8     37 // Arduino pin tied to echo pin on the ultrasonic sensor.

NewPing sonar1(TRIGGER_PIN1, ECHO_PIN1, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar2(TRIGGER_PIN2, ECHO_PIN2, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar3(TRIGGER_PIN3, ECHO_PIN3, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar4(TRIGGER_PIN4, ECHO_PIN4, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar5(TRIGGER_PIN5, ECHO_PIN5, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar6(TRIGGER_PIN6, ECHO_PIN6, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar7(TRIGGER_PIN7, ECHO_PIN7, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
NewPing sonar8(TRIGGER_PIN8, ECHO_PIN8, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  pinMode(pump1, OUTPUT);
  pinMode(pump2, OUTPUT);
  pinMode(pump3, OUTPUT);
  pinMode(pump4, OUTPUT);
  pinMode(pump5, OUTPUT);
  pinMode(pump6, OUTPUT);
  pinMode(pump7, OUTPUT);
  pinMode(pump8, OUTPUT);
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() {
  delay(500);                  

//-----get raw data-----
  
  rawValue1 = sonar1.ping_cm();
//  Serial.println(rawValue1);
  if (rawValue1 >0){
  myArray1 [counter1] = rawValue1;
  }
  counter1 += 1;
  if (counter1 >= 10) {
    counter1 = 0;
  }
  int allData1 = 0;
  for (int i = 0; i <= 10; i++) {
    allData1 = allData1 + myArray1[i];
  }
  int average1 = allData1 / 10;
//  Serial.println(average1);
  sensorValue[0] = average1;


  rawValue2 = sonar2.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue2 >0){
  myArray2 [counter2] = rawValue2;
  }
  counter2 += 1;
  if (counter2 >= 10) {
    counter2 = 0;
  }
  int allData2 = 0;
  for (int i = 0; i <= 10; i++) {
    allData2 = allData2 + myArray2[i];
  }
  int average2 = allData2 / 10;
//  Serial.println(average2); 
  sensorValue[1] = average2;


  rawValue3 = sonar3.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue3 >0){
  myArray3 [counter3] = rawValue3;
  }
  counter3 += 1;
  if (counter3 >= 10) {
    counter3 = 0;
  }
  int allData3 = 0;
  for (int i = 0; i <= 10; i++) {
    allData3 = allData3 + myArray3[i];
  }
  int average3 = allData3 / 10;
//  Serial.println(average3); 
  sensorValue[2] = average3;


  rawValue4 = sonar5.ping_cm(); //sonar4 is broken
//  Serial.println(rawValue2);
  if (rawValue4 >0){
  myArray4 [counter4] = rawValue4;
  }
  counter4 += 1;
  if (counter4 >= 10) {
    counter4 = 0;
  }
  int allData4 = 0;
  for (int i = 0; i <= 10; i++) {
    allData4 = allData4 + myArray4[i];
  }
  int average4 = allData4 / 10;
//  Serial.println(average4); 
  sensorValue[3] = average4;


 
  rawValue5 = sonar5.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue5 >0){
  myArray5 [counter5] = rawValue5;
  }
  counter5 += 1;
  if (counter5 >= 10) {
    counter5 = 0;
  }
  int allData5 = 0;
  for (int i = 0; i <= 10; i++) {
    allData5 = allData5 + myArray5[i];
  }
  int average5 = allData5 / 10;
//  Serial.println(average5); 
  sensorValue[4] = average5;


 
  rawValue6 = sonar6.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue6 >0){
  myArray6 [counter6] = rawValue6;
  }
  counter6 += 1;
  if (counter6 >= 10) {
    counter6 = 0;
  }
  int allData6 = 0;
  for (int i = 0; i <= 10; i++) {
    allData6 = allData6 + myArray6[i];
  }
  int average6 = allData6 / 10;
//  Serial.println(average6); 
  sensorValue[5] = average6;



  rawValue7 = sonar7.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue7 >0){
  myArray7 [counter7] = rawValue7;
  }
  counter7 += 1;
  if (counter7 >= 10) {
    counter7 = 0;
  }
  int allData7 = 0;
  for (int i = 0; i <= 10; i++) {
    allData7 = allData7 + myArray7[i];
  }
  int average7 = allData7 / 10;
//  Serial.println(average7); 
  sensorValue[6] = average7;


  rawValue8 = sonar8.ping_cm();
//  Serial.println(rawValue2);
  if (rawValue8 >0){
  myArray8 [counter8] = rawValue8;
  }
  counter8 += 1;
  if (counter8 >= 10) {
    counter8 = 0;
  }
  int allData8 = 0;
  for (int i = 0; i <= 10; i++) {
    allData8 = allData8 + myArray8[i];
  }
  int average8 = allData8 / 10;
//  Serial.println(average8); 
  sensorValue[7] = average8;

//Serial.print(sensorValue)
Serial.println(average1); Serial.println(average2); Serial.println(average3); Serial.println(average4); Serial.println(average5);Serial.println(average6);Serial.println(average7);Serial.println(average8); 



//-----set pump pin-----

// if distance > x, off pump is increased 

//find smallest two vertical distance

  int small_value1 = 100; //sensor value
  int small_value2 = 100;
  int small_pin1 = 0; //find sensor location
  int small_pin2 = 0;
  
  for (int i = 1; i < 4; i++){
//    Serial.println(sensorValue[i],i);
    if (sensorValue[i] < small_value1 && sensorValue[i] != 0){
      small_value1 = sensorValue[i];
      small_pin1 = i+5;
      }
    }
  for (int i = 5; i < 8; i++){
    if (sensorValue[i] <  small_value2 && i != small_pin1 && sensorValue[i] != 0){
      small_value2 = sensorValue[i];
      small_pin2 = i+5;
      }
    }
  //Increase_Pump value
  int pump_updated = 80;
  //update the 2+5,4+5,6+5,7+5
  if (small_pin1 <= 7){
     small_pin1 = 7;
  }
  if (small_pin1 > 7){
     small_pin1 = 9;
  }
  if (small_pin2 <= 11){
     small_pin1 = 11;
  }
  if (small_pin2 > 11){
     small_pin1 = 12;
  }

  //send signals
  analogWrite(small_pin1, pump_updated);
  analogWrite(small_pin2, pump_updated);
  int pumpArray1[4] = {7,9,11,12};
  int pumpArray2[4] = {6,8,10,13};
  for (int n = 0; n<4; n++) {
    if (pumpArray1[n] != small_pin1 | pumpArray1[n] != small_pin2){
    analogWrite(n, 0);
    Serial.println(pumpArray1[n]);
    }
    }

  for (int n = 0; n<4; n++) {
    analogWrite(pumpArray2[n], 70);
    }



}


 

]]>
Final Show documentation https://courses.ideate.cmu.edu/62-362/f2022/final-show-documentation/ Sat, 10 Dec 2022 18:52:42 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12477 Improving GATES Project: We are all Horrible People

Description:

This desktop philosophical experience is intended to be placed discretely somewhere in CMU with high foot traffic.

After sitting down, you answer each question as it appears on the screen. The ‘y’ key means yes and the ‘n key means no. All of the questions are modeled after decisions that a CMU student might make on a normal day, some a bit more dramatic than others. After you answer all of the questions, you will get a receipt printed with some of the positive and negative consequences of the choices you made.

Process:

It was really useful to be able to go back and improve on my earlier project and get it to a place that I was happy with it. My main improvements were with the receipt printer and questions. I changed out the 3rd 4th and 5th questions to better align with the message that I was trying to portray in my project. I felt these original three questions didn’t have as much of a moral questioning as the three I replaced them with. The questions were:

3. You have a midterm in an hour do you study?

4. You haven’t talked to your mom in over a week. Do you call her?

5. You decide on Thai for dinner. Do you order delivery?

And I replaced them with:

3. Your bank account is empty, but you need to eat lunch. Do you steal a sandwich?

4. You got into a fight with your mom yesterday and feel guilty. Do you call and apologize?

5. One of your coworkers asks you on a date. Do you go?

 

I also took some time to make the receipt printer seem more purposeful by installing it into one of the drawers of my desk. Originally it just sat on the table, but putting it into the drawer made it seem less like an afterthought. The only issue with putting it in the drawer is that some people missed the receipt and moved away from the piece before it finished printing. I tried to solve this my including an arrow on top of the desk pointing to the printer which seemed to help. The good part is that people noticed the printer from the user before them and it was only missed at the beginning of the show. People were also a bit impatient with the printer because it took a minute to print.

It was interesting to see the difference in how people interacted based on if I was standing next to the exhibit or not. I overheard a discussion among some friends and they were talking about Nihilism so I was happy to hear that some people picked up on the message. Someone else after I was talking to them about the piece told me that they were going to put the receipt into their wallet which was oddly touching.

//AMOR FATI
//by Cassie Rausch
//this code is designed to recieve input from a user as a key press of either 'y' or 'n'
//in response to a displayed question and then compile correlating responses 
//to this input and print a receipt with the responses generated


int qcounter = 0; //counter that tracks the question you are on

String []  receipt = {" ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; //string that holds all of the responses to be printed

char results[] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; //string that holds all of the users input

String [] question = {
  "Your alarm goes off, but you're so tired. Do you snooze? Y/N", 
  "You're still so groggy. Do you get coffee? Y/N", 
  "Your bank account is empty, but you need to eat lunch. Do you steal a sandwich? Y/N", 
  "You got into a fight with your mom yesterday and feel guilty. Do you call and apologize? Y/N", 
  "One of your coworkers asks you on a date. Do you go? Y/N", 
  "As you walk home you pass someone homeless, begging for money. Do you help them? Y/N", 
  "A startup has reached out to you with a dream job offer, but they insist that you drop out of CMU first. Do you do it? Y/N", 
  "You are up late working on a project for a class, but all you want to do is sleep. Do you stay awake to finish it? Y/N", 
  "You catch your partner cheating, but they swear they'll change. Do you give them a second chance? Y/N", 
  "Would you make the same decisions again? Y/N", 
};

String [] nanswers = {
  "You wake up and make it to class on time,\nbut fall back asleep during lecture.\n\n", 
  "\nYou're so tired you don't take any\nnotes in class and fail the next quiz.\n\n", 
  "\nYou're hangry the rest of the day,\nbut stood by your morals.\n\n", 
  "\nYou hold your ground in the fight,\nbut your mom is secretly hurt.\n\n", 
  "\nYour coworker is hurt,\nbut you avoid an awkward date\n\n", 
  "\nThe homeless person struggles\nto find food and becomes ill. You stay\nsafe and keep your money.\n\n", 
  "\nYou graduate CMU and work at Meta.\nIt's fine.\n\n", 
  "\nYou get a lovely night of sleep, but\ncome to class with an unfinished project.\n\n", 
  "\nYou watch the person you were in love with\nleave you for someone else.\nYou are alone, but happy.\n\n\n\n\n\n", 
  "\n\nAMOR FATI  \n\n\n\n\n\n\n\n"
};

String [] yanswers = {
  "You wake up late feeling less tired,\nbut you slept through your class.\r\n", 
  "\n\nYou contribute to the mass\ndeforestation for coffee farming.\r\n", 
  "\n\nYou enjoy your sandwich\nbut have a lingering guilt.\r\n", 
  "\n\nYou feel better after apologizing,\nbut part of you is still mad\r\n", 
  "\n\nYour coworker is happy,\nbut the date is awkward.\r\n", 
  "\n\nYou give the homeless person money,\nbut they quickly spend it.\r\n", 
  "\n\nYou love working your dream job\nuntil the startup fails.\r\n", 
  "\n\nYou stay up all night,\nbut feel awful all day\r\n", 
  "\n\nYour partner continues to cheat,\nbut for a bit you're happy again.\r\n\n\n", 
  "\n\nAMOR FATI   \n\n\n\n\n\n\n\n"
};

import processing.serial.*;

Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port


void setup() {

  size(1300, 1000);
  println(Serial.list());
  String portName = Serial.list()[1];
  myPort = new Serial(this, portName, 9600);
}

void draw() { // drawing background and text
  background (150, 50, 300);
  textSize(25);
  rectMode (CENTER);
  textAlign(CENTER, CENTER);
  String printresults = new String(results);
  if (qcounter == 10) {
    delay (1000);
    receiptbuilder ();
    delay (5000);
    qcounter = 0;
  }
  // text(printresults, 10, 10);
  // text(qcounter, 10, 20);
  if (qcounter < 10) text(question[qcounter], width/2, height/2, 500, 300);
}

void keyPressed () { 
  if (qcounter < 10) {
    if (key == 'y') {
      results[qcounter] = 'y';
      qcounter++;
    }
    if (key == 'n') {
      results[qcounter] = 'n';
      qcounter++;
    }
  }
}

void  receiptbuilder () {  // function to build all of the responses to be printed based on user input
  for (int counter = 0; counter < 10; counter++) {
    if (results[counter] == 'y') {
      receipt[counter] = yanswers[counter];
    } else if (results[counter] == 'n') {
      receipt[counter] = nanswers[counter];
    }
  } 
  myPort.write(receipt[0]);
  delay (2000);
  myPort.write(receipt[1]);
  delay (2000);
  myPort.write(receipt[2]);
  delay (2000);
  myPort.write(receipt[3]);
  delay (2000);
  myPort.write(receipt[4]);
  delay (2000);
  myPort.write(receipt[5]);
  delay (2000);
  myPort.write(receipt[6]);
  delay (2000);
  myPort.write(receipt[7]);
  delay (2000);
  myPort.write(receipt[8]);
  delay (2000);
  myPort.write(receipt[9]);
}

void serialEvent (Serial p) {
  String inString = p.readString();
  // println (inString);
}

 

]]>
Preparation for Final Event: Flux https://courses.ideate.cmu.edu/62-362/f2022/preparation-for-final-event-flux/ Tue, 06 Dec 2022 13:46:59 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12471
  • Project Title: Flux (iterate on project 2)
  • Installation sketch:
    • Use of Space
      • What type of space do you need?
        • The space that I need is about 45 feet x 60 feet. My easel is 40 feet wide, and the sensors have a working range, so having that amount of space will allow the viewers to interact with the painting better.
      • For example, do you need electricity?
        • I need electricity, mostly power supply, in order for my pump to work
      • Do you need a table / surface? Do you need wall space?
        • Yes I need a wall space, and it would be the best to have a table for the easel to lean on. I will carry two sand bags from Media Lab to prevent the easel from sliding towards the ground.
      • A list of additional equipment / tools you’ll need from IDeATe and/or beyond.
        • Tube connectors (They’re running out.) Type 1: From large tube to small tube connector; Type 2: Small tube three-leg connector;
    ]]>
    Flow Project: Ideation for Show https://courses.ideate.cmu.edu/62-362/f2022/flow-project-ideation-for-show/ Fri, 02 Dec 2022 13:59:43 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12463

    This concept would require no extra coding or programming. Simply an expansion of the project into a more installation-oriented piece.

    ]]>
    Rausch P3 https://courses.ideate.cmu.edu/62-362/f2022/rausch-p3/ Wed, 30 Nov 2022 18:43:36 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12457 We are all Horrible People

    I will need about a 5×5 square foot of floor space for the desk/space for a person to sit in front of it. I will also need electricity for the computer to plug into.

    I will need a monitor/keyboard/mouse from A10 as well as an HDMI cord and I already have the desk and chair.

    ]]>
    FLOW Rausch Documentation https://courses.ideate.cmu.edu/62-362/f2022/flow-rausch-documentation/ Wed, 30 Nov 2022 16:41:31 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12438

    Social Robots

    This was the model of Hades that I created, but ran out of time to implement electronics into.

     

    This odd soft egg shape made of foam slowly rotates around its center axis, making a grinding, rolling sound. As you go closer to it, it starts to rotate faster.

    Process

    My first idea was to analyze the most commonly used personality dimensions (Extroversion, agreeableness, contentiousness, neuroticism, openness) and assign each robot a random combination of these traits.

    Once I started to define the robots based on their dimensions, I realized that I am limited in how much personality I can show with these forms. For example, it is difficult to show the level of openness that something that is not creative.

    I still broke down the dimensions of each social robot that I planned to make, but the factors that seemed to influence them the most was their levels of extroversion and agreeableness.

    I originally planned to make three distinct robots with different personalities, but due to time and how surprisingly challenging it was to make Hermes, I did not make Hades or Oizys. Hades was intended to be a hard rigid form that would have a temper and be antisocial. Oizys was designed to be anxious and nervous.

    The interactions that I mapped out for each social robot helped me to define them in my head and get a sense of how they should react when approached to socialize.

    This was my original plan for Hermes which I more or less followed when constructing it. The main idea was to have a servo with a weight on the end of it continuously moving and shifting Herme’s center of gravity.

     

    Process Reflection

    The process for designing and constructing Hermes was fun but rough. I enjoyed making its shell out of foam, it’s rare that I can make something so organic and intentionally imperfect as Hermes. Most of my struggles came after that when I was trying to implement the electronics into this form. I had the idea to try and put the Arduino, servo, battery pack and breadboard into a tin can and then core out the shell and put the self contained can in. I was on the right track with this method and it’s something I’m going to implement into my work in the future, but did not fan out how I planned in this case. The main issue was that the servo needed to be able to rotate a full 360 degrees to get the action that I wanted, but this required the servo to have wide clearance in a small space. The shell of Hermes should have been slightly bigger to allow me more space to work with, but in the end I was able to make everything fit.

    The biggest other issue I ran into was Hermes not animating in the way that I was expecting. I chose a tin can to house the electronics because this would also allow me to make a bow in the bottom for Hermes to rotate on. I make this bow by hammering the bottom of the can, but because of this, the bottom was not a symmetrical hemisphere for Hermes to rotate on. Looking back, I should have 3D printed the electronics housing to ensure that I had space for the servo and the bottom was symmetrical. I also did not have enough weight on the end of the servo for it to make Hermes sway the amount that I had intended. However, the end result of a little wiggle that Hermes does is surprisingly still communicative of the happy/social personality that I wanted Hermes to have.

    I also ran into some issues with the distance sensor. Initially I planned on using a laser ranger distance sensor, but after a failed attempt to make that sensor work, I reported to the ultrasonic range finder. This sensor is functional, but will randomly report incorrect numbers with will confuse the servo and so the motion of Hermes is not always connected to distance.

     

    //Social robots
    //Casandra Rausch
    //A project to physically animate and give personality to unique forms.
    //This code detects the distance and changes the speed of a continuously rotating servo in response.
    
    #include <NewPing.h>
    #include <Servo.h>
    
    #define TRIGGER_PIN 9
    #define ECHO_PIN 8
    #define MAX_DISTANCE 200
    const int GAUGEMOTORPIN = 3;
    
    Servo gaugeMotor;
    
    // NewPing setup of pins and maximum distance
    NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
    
    void setup() {
      Serial.begin(9600);
      gaugeMotor.attach(GAUGEMOTORPIN);
    }
    
    void loop() {
      delay(50);
      unsigned int distance = sonar.ping_cm();
      Serial.print(distance);
      Serial.println("cm");
    
      int Dist = analogRead(distance);
      int Level = 0;
      Level = map(Dist, 0, 200, 1, 9);
    
      if (Level = 1) {
        gaugeMotor.write(90);
        delay(5000);
      }
        if (Level = 2) {
        gaugeMotor.write(80);
        delay(4500);
      }
          if (Level = 3) {
        gaugeMotor.write(70);
        delay(4000);
      }
        if (Level = 4) {
        gaugeMotor.write(60);
        delay(3500);
      }
          if (Level = 5) {
        gaugeMotor.write(50);
        delay(3000);
      }
          if (Level = 6) {
        gaugeMotor.write(40);
        delay(2500);
      }
          if (Level = 7) {
        gaugeMotor.write(30);
        delay(2000);
      }
          if (Level = 8) {
        gaugeMotor.write(20);
        delay(1500);
      }
          if (Level = 9) {
        gaugeMotor.write(10);
        delay(1000);
      }
    }  
    

     

    ]]>
    Project 3: Rain (continuation of Project 2) https://courses.ideate.cmu.edu/62-362/f2022/project-3-rain-continuation-of-project-2/ Wed, 30 Nov 2022 15:28:03 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12439 Rain

    Space needed: ~ 9 sq ft

    • Small table
    • Access to electricity for Rain and laptop

    Additional Equipment

    • Tablecloth (black) (long enough to conceal sides of table)
    • Small monitor

     

     

    ]]>
    Project 2: Rain https://courses.ideate.cmu.edu/62-362/f2022/project-2-rain/ Tue, 29 Nov 2022 08:26:32 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12399 Rain 

    Photos

    Video

    Narrative Description

    A frosty white device composed of acrylic panels and a tear-drop shaped facade sits on a table. The tear-drop contains a speaker centered on its face as well as an IR-proximity sensor just below the speaker. The user sets their hand directly in front of the sensor for about a second. The device then begins playing a message. Narrated by a male robotic voice, the message describes the weather for the week at the user’s location using highly detailed meteorological terminology. The tear-drop plays two short messages, with a rectangular light accompanying the second message. These two messages, which berate the user, are narrated by a real yet snarky female voice. The first message corresponds to a certain temperature range while the second message, along with the light, corresponds to a sky condition. Once the second message is played, the rectangular light shuts off after about 4 seconds. 

    Progression to Final Project

    Maquette –> Simple circuit –> Hardware –> Electronics Integration –> Final Project

    Maquette

    Maquette made out of cotton balls and pipe cleaners. Circuit contains 4 blue LEDs, powered by a button press

    Simple Circuit

    Simple circuit with Adafruit MusicMaker shield playing MP3 file in parallel with NeoPixels lighting up, all activated by gentle press on IR proximity sensor

    Hardware

    Gluing a side and bottom panel together with acrylic glue

    Electronics Integration

    Placement of speaker, NeoPixels, Arduino, and IR proximity sensor into back compartment of device

    Final Project

    Rain lighting up yellow to indicate stormy weather

    Process Reflection

    This project involved many compromises and experimentation regarding its hardware and software, but many lessons were learned. I wanted to take this project into the gimmick product realm. I wanted a device that informs the user about the weather and berates them while doing so. Throughout the project build, I adhered to the latter quality quite well. However, the type of weather information I wanted the device to convey proved to be a rather complicated decision. Due to limitations of the Arduino Uno board and a lack of time to implement a wifi-compatible board, I found it difficult to implement live and useful weather data such as temperature or precipitation percentage. These values change very often, which seems to necessitate a live stream of data. Ultimately, I decided on using the “area forecast discussion” from the National Weather Service as my weather data. This is essentially commentary on the weekly weather of a specified location, designed for meteorologists. It includes vocabulary that is very unlikely to be comprehended by the average user and does not contain numerical values that people tend to care about. Including this kind of data increases the absurdity of the product experience; this is further elaborated in my artist’s statement. 

    I ran into lots of issues on the software side of this project. To play audio files, I used an Adafruit MusicMaker MP3 Shield, which has its own code library. It took me some trial and error to get some understanding of what the MusicMaker code was doing, so that I could then manipulate it for the project. Unfortunately, I did not pay close enough attention to the code at first, and I missed important information on which pins of the Arduino were being used by the shield. As a result, trying to play an audio file along while lighting NeoPixels took a very long time to figure out as I kept placing the NeoPixels into pins that were already used. Thankfully, Zach spotted this issue very quickly, and I was then able to successfully play audio files along with lighting the NeoPixels. Another challenge emerged when finalizing the code. Despite the lack of a live data stream, I wanted to emulate such a data stream as closely as possible for the final critique. I decided on importing Pittsburgh weather data for one day into the code and basing all the product’s actions on that. Specifically, I wanted it such that, anytime a user gently pressed the IR sensor, the device would play a message and light up correspondingly to the weather of a randomly chosen time that day. For instance, after a gentle press, the random time chosen is 6pm, and the device would play audio and light up according to the weather at 6pm of the imported day. This required a lot of if/else if statements, which unfortunately I could not get to work properly. So, I ended up having to manually alter the code after every use to display all weather combinations. 

    The hardware assembly involved some improvisation. The tear-drop facade as well as the back panels are all laser-cut acrylic pieces. Initially, I wanted the device to have a soft, fluffy exterior to make it more approachable. This necessitated 3d-printing, but, due to time constraints, I ended up designing the device to be laser cuttable. I created a CAD model of the full assembly and created DXF files from that model. I used acrylic glue to fixture the tear-drop to the two side panels. These side panels were then glued to a bottom panel. The top and rear panel were not featured at all as I wanted easy access to electronics for debugging. In between the back panels lies the Arduino, all of the wires, and a clear acrylic wall where two NeoPixels are hot glued onto. The speaker is fastened to the tear-drop facade with nylon screws, and the IR sensor is placed on the facade through a small rectangular hole. In order to experiment with lighting, I did not glue the NeoPixel wall as I wanted to move it freely. Gluing would also make any debugging more difficult. Because of this, the wall would not stay perpendicular to the ground, which made the lighting on the tear-drop uneven. As a result of the panel enclosure, the lighting on the tear-drop was rectangular. I had wanted the light to cover the entire face in any external lighting condition, but of course this was limited by the rectangle.

    Overall, I did not fully realize my ideas for this project, but I made compromises to get as close to them as I could. Managing my time better would definitely have improved this situation; I think I spent some unnecessary time on hardware design. As with my previous project, I overestimated the wiring difficulty, but not as bad as before. The main issue with the wiring this time was accessibility. I could barely fit a few fingers into the back compartment of the device, so ensuring all the wires were firmly connected proved to be challenging. I think wiring consideration in design will come with experience as it is difficult to predict and implement wiring in CAD. Despite these difficulties I have outlined, going through them has given me valuable insight into how I want to expand this project. Similar to my first project, I want to implement a dystopian plot to the product. Specifically, the device would contain a weatherman that is trapped inside of it and is forced to be snarky and provide weather data to the user; this is hinted in my project video. To fully realize such a plot, I think the biggest design changes I need to make are to implement live weather data and include another medium, likely a video, to better contextualize the device with the plot. 

    Artist’s Statement

    This project is a physical device that informs users of the weather at their location and mocks them while doing so. The weather information is highly detailed in meteorological language that is very likely foreign to the average person. Once the weather information is presented, the teardrop-shaped face lights up to a color corresponding to the current weather. While doing so, the user is mocked. I was inspired by the song Rain by The Beatles. Its writer, John Lennon, grew tired of what he perceived to be people constantly complaining about the weather, and he dedicated this song to making fun of them. It’s one of my favorite songs from the band, and I only recently discovered its original meaning, which makes it not only musically but thematically clever. So, I decided to create a physical manifestation of the song. 

    The project provides interaction through physical, auditory, and visual means. It is a white acrylic teardrop with lights and a speaker attached from the back in a white acrylic case. When a user brings their hand in front of a sensor on the teardrop face, a message is played. Narrated by a robotic male voice, the message describes in meteorological detail the weather for the week. Afterward, the teardrop lights up, depending on how the weather is, and then a real female voice mocks the user with a few lines. 

    One of the most common small-talk discussion topics is the weather. It’s very easy to discuss because it’s always with us and everyone experiences it. I sometimes get a bit annoyed when I catch myself mentioning the weather in small-talk; it seems like a waste of conversation given how obvious the weather is like. Rain takes this phenomenon and completely exaggerates such a scenario. By presenting weather information that is nearly incomprehensible without decent meteorological knowledge and by berating the user, conversation about weather is seen as undesirable. It questions the presence of weather in kind, simple small-talk. 

    Code 

    //Rain 
    //Gabriel Prado
    //Code plays MP3 files through speaker and lights NeoPixels, all activated by IR sensor
    //Code used from Adafruit MusicMaker MP3 Shield library and NeoPixels library
    
    
    //Lines 10-41 --> setup for Adafruit MusicMaker MP3 Shield
    //Lines 43-60 --> setup for NeoPixels
    
    #include <SPI.h>
    #include <Adafruit_VS1053.h>
    #include <SD.h>
    
    // define the pins used
    //#define CLK 13       // SPI Clock, shared with SD card
    //#define MISO 12      // Input data, from VS1053/SD card
    //#define MOSI 11      // Output data, to VS1053/SD card
    // Connect CLK, MISO and MOSI to hardware SPI pins. 
    // See http://arduino.cc/en/Reference/SPI "Connections"
    
    // These are the pins used for the breakout example
    #define BREAKOUT_RESET  9      // VS1053 reset pin (output)
    #define BREAKOUT_CS     10     // VS1053 chip select pin (output)
    #define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
    // These are the pins used for the music maker shield
    #define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
    #define SHIELD_CS     7      // VS1053 chip select pin (output)
    #define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
    
    // These are common pins between breakout and shield
    #define CARDCS 4     // Card chip select pin
    // DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
    #define DREQ 3       // VS1053 Data request, ideally an Interrupt pin
    
    
    
    Adafruit_VS1053_FilePlayer musicPlayer = 
      // create breakout-example object!
      //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
      // create shield-example object!
      Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
      
    #include <Adafruit_NeoPixel.h>
    #ifdef __AVR__
     #include <avr/power.h> // Required for 16 MHz Adafruit Trinket
    #endif
    
    // Which pin on the Arduino is connected to the NeoPixels?
    #define PIN        6 // On Trinket or Gemma, suggest changing this to 1
    
    // How many NeoPixels are attached to the Arduino?
    #define NUMPIXELS 32 // Popular NeoPixel ring size
    
    // When setting up the NeoPixel library, we tell it how many pixels,
    // and which pin to use to send signals. Note that for older NeoPixel
    // strips you might need to change the third parameter -- see the
    // strandtest example for more information on possible values.
    Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
    
    #define DELAYVAL 500 // Time (in milliseconds) to pause between pixels
    
    // table below includes all MP3 files for insults 
    int temps[] = {"/track001.mp3" , "/track002.mp3", "/track003.mp3" , "/track004.mp3" , "/track005.mp3", "/track006.mp3",
    "/track007.mp3" , "/track008.mp3", "/track009.mp3" , "/track010.mp3" , "/track011.mp3" , "/track012.mp3" , "/track013.mp3" ,
    "/track014.mp3" , "/track015.mp3" , "/track016.mp3" , "/track017.mp3" , "/track018.mp3" , "/track019.mp3" , "/track020.mp3", 
    "/track021.mp3" , "/track022.mp3" , "/track023.mp3" , "/track024.mp3" ,"/track025.mp3" , "/track026.mp3"};
    
    
    
    void printDirectory(File dir, int numTabs) { //part of MP3 Shield setup
       while(true) {
         
         File entry =  dir.openNextFile();
         if (! entry) {
           // no more files
           //Serial.println("**nomorefiles**");
           break;
         }
         for (uint8_t i=0; i<numTabs; i++) {
           Serial.print('\t');
         }
         Serial.print(entry.name());
         if (entry.isDirectory()) {
           Serial.println("/");
           printDirectory(entry, numTabs+1);
         } else {
           // files have sizes, directories do not
           Serial.print("\t\t");
           Serial.println(entry.size(), DEC);
         }
         entry.close();
       }
    }
    
    
    void setup() {
      pinMode(A0,INPUT); //Pin for IR proximity sensor
      Serial.begin(9600);
      
      musicPlayer.begin();
      SD.begin(CARDCS);
      //SD.open("/track001.mp3");
      
      
     // printDirectory(SD.open("/"), 0);
      
      musicPlayer.setVolume(20,20);
      
      #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
      clock_prescale_set(clock_div_1);
    #endif
      // END of Trinket-specific code.
    
      pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
      
    }
    
    void loop() {
        pixels.clear();
        delay(1000);
        if(analogRead(A0) >= 200){
            musicPlayer.playFullFile("/track099.mp3"); //MP3 for area forecast discussion
            int up = 3; // current sky condition (0,1,2,3, or 4)
            int f = random(0,3);
            int g = random(3,6);
            int h = random(6,8);
            int i = random(8,10);
            int j = random(10,12);  //each letter corresponds to insults for certain temp range
            int k = random(12,14);
            int l = random(14,16);
            int m = random(16,18);
            int n = random(18,20);
            musicPlayer.playFullFile(temps[2]); //MP3 for insult corresponding to temp
            if(up == 0){
                      for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                         pixels.setPixelColor(i, pixels.Color(0, 191, 255)); //blue emitted
                          pixels.show();   // Send the updated pixel colors to the hardware.
                          }
                      musicPlayer.playFullFile(temps[up+20]); //MP3 for insult corresponding to sky condition
                      delay(4000);
                      pixels.clear();
                      for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                         pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //no color emitted
                          pixels.show();   // Send the updated pixel colors to the hardware.
                           }
                  }
                  else if (up == 1){
                      for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                             pixels.setPixelColor(i, pixels.Color(255, 20, 0));   //red-orange emitted
                             pixels.show();   // Send the updated pixel colors to the hardware.
                          }
                          musicPlayer.playFullFile(temps[up+20]);
                          delay(4000);
                          pixels.clear();
                         for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                               pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //no color emitted
                               pixels.show();   // Send the updated pixel colors to the hardware.
                            }
                  }
                  else if (up == 2){
                     for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                             pixels.setPixelColor(i, pixels.Color(32, 32, 32)); //gray emitted
                              pixels.show();   // Send the updated pixel colors to the hardware.
                          }
                          musicPlayer.playFullFile(temps[up+20]);
                          delay(4000);
                          pixels.clear();
                         for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                               pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //no color emitted
                               pixels.show();   // Send the updated pixel colors to the hardware.
                            }
                  }
                  else if (up == 3){
                      for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                             pixels.setPixelColor(i, pixels.Color(255, 255, 255)); //white emitted
                              //pixels.setPixelColor(1,pixels.Color(0, 150, 0));
                              pixels.show();   // Send the updated pixel colors to the hardware
                          }
                          musicPlayer.playFullFile(temps[up+20]);
                          delay(4000);
                          pixels.clear();
                         for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                               pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //no color emitted
                               pixels.show();   // Send the updated pixel colors to the hardware.
                            }
                  }
                  else if (up == 4){
                    for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                             pixels.setPixelColor(i, pixels.Color(255, 100, 0)); //yellow emitted
                              pixels.show();   // Send the updated pixel colors to the hardware.
                          }
                          musicPlayer.playFullFile(temps[up+20]);
                          delay(4000);
                          pixels.clear();
                         for(int i=0; i<NUMPIXELS; i++){ // For each pixel...
                               pixels.setPixelColor(i, pixels.Color(0, 0, 0)); //no color emitted
                               pixels.show();   // Send the updated pixel colors to the hardware.
                            }
                  }
                   
        }     
            
      
    }

    Insults

    Rain (0) --> 21. And don't bother getting your umbrella, you'll need a shower anyways
    Sunny (1) --> 22. Looks like we're gonna have sun today. Here's a fun tip: stare at it 
    Cloudy (2) --> 23. The sky is gray, not the brightest. I'm sure you can relate 
    Snow (3) --> 24. The snow is so pure and wonderful, and you're a disgusting blemish
    Stormy (4) --> 25. It's getting rough out there, have fun!
    
    0-20 degree range
         1. I just wanna see you freeze to death
         2. Ready to freeze, scum?
         3. The weather outside looks frightful, but you look even more frightful. Seriously, just look at yourself.  
         
    20-30 degree range
         4. See if I liked you, I would tell you to stay inside. But, I don't so, get out there!
         5. You should wear your jacket, but seriously it makes you look like a balloon
         6. The freezing point of human blood is 31 degrees, so let's keep our fingers crossed shall we?
         
    30 - 40 degree range
         7. It's too cold to for a walk and too hot to go sledding, so go screw yourself
         8. Looks like you'll be looking for warmth again, we all know how that will go
    
    40 - 50 degree range
         9. Whatever drink you get to keep you warm, I hope you spill it all over yourself
         10. The temperature right now is the number of reasons why you're a loser
    50 - 60 degree range
         11. Slightly cool, slightly warm. I don't know anymore, so screw you
         12. The temperature is as meh as your looks
         
    60 - 70 degree range
         13.It's getting kind of hot in here, I hope your body odor doesn't show
         14. You should go outside and enjoy the weather. Oh wait, you're a loser my bad 
    
    70 - 80 degree range
         15. It's so warm, unlike your personality
         16. The temperature right now is pretty great to be honest. The only thing in my way is you
    
    
    80 - 90 degree range
         17. It' really hot, unlike you
         18. Global warming is coming for you!
         
    
    90 - 100 degree range
         19. Time to starting wearing less, but no one wants to see that 
         20. Some people wanna watch the world burn, like me
    

    Sources

    Snarky Female Voice –> Jolie Ma

    Robotic Male Voice –> https://voicemaker.in/

    Insults –> Katarina Garcia, Soomin Kong, Jolie Ma, Gabriel Prado

    Area Forecast Discussion –>

    https://forecast.weather.gov/product.php?site=PBZ&issuedby=PBZ&product=AFD&format=CI&version=1&glossary=1&highlight=off

    Tear-drop Shape –>

    ]]>
    Flux – Project 2 Documentation https://courses.ideate.cmu.edu/62-362/f2022/flux-project-2-documentation/ Mon, 28 Nov 2022 18:32:09 +0000 https://courses.ideate.cmu.edu/62-362/f2022/?p=12373 Documentation

    PROGRESS REFLECTION

    The entire idea is from my ambition to expand the interaction to two person. I started the project from aiming to create a fun & spatial experience between people and environment. To fulfill this goal, certain design considerations come to mind that guide me throughout the whole process.

    1. The time-based painting needs to be large enough to be seen.
    By fulfilling this idea, me and Zach made a large easel from scratch. Marking, cutting, and mounting all the woods took us hours. However, this is a great learning process in that I knew how to use machines in the woodshops.
    To create an experience of time, the paper roll was then mounted onto the easel and by manually pulling down when needed, it dropped onto a certain height, and being clamped to the easel.

    2. The influx of colors are controllable.
    I proceeded to test out the paint texture. The water-ish color flows too fast, which is harder to control, but the acrylic paint has higher viscosity that is more difficult to pump. After testing, I found that acrylic paint has heavier texture, which can be easier to control if we have a robust pump. Also, mixing a little water into the color will make the acrylic paint more fluidic.
    When finding the pump that fits, I was trying to find excellent pumps from Amazon, but later I found out that IDEATE has lots of 12V pumps for lending that are also robust enough.

    3. Color Mixture looks like a painting that has certain aesthetic.
    I was experimenting on multiple color mixture ideas. The initial idea was just doing red and blue mixture — which turns purple only. Then, I found that more color variation could lead to more vibrance and dynamic effect. In the setup, there are three colors mixing together (red, blue, yellow), and there are six kinds of color possibilities each with multiple levels of mixture (red, blue, yellow, green, purple, orange).

    4. The control of pumps on the painting are dependent on their distance between each other.
    To capture the distance of two people, I used 8 ultrasonic sensors, with each sending signal to one pump. Mounting all the hardwares and manage the wiring + tubing is a super time-consuming process.
    Though not managed to calibrate to a “working” state, I got all the required setups (code+hardware).

    Things that was hard:
    Setting Mechanics up: This took me an entire weekend. First I drew out the schematics, and try to produce a small demo before mounting. Then, the tedius part comes: I individually glued the pumps, sensors, breadboards, and Arduino to the Easel. Then, the wiring process requires a crystal clear mind to avoid making mistakes. Also, there are risks that things are burned. I nearly damaged all the hardwares because one time I was testing, the power supply immediately goes to 21V when turned on. I could even see smokes. All the lession learnt is to Stay Alert.
    Cleaning: Thanks to the help from Zach and Erin, I was able to clean up the space after the presentation. The thing that I need to keep in mind in the future is to prepare for the mess beforehand (such as papers, napkins etc.), so that I will not spend lots of time wiping the floor and the table.

    Things that I learned:
    The installation process requires a huge amount of time and energy, and might result in lots of errors, so plan ahead and leave space for fixing / calibrating would be super important.
    The presentation was — a physical MESS. Although my audience’s feedback was that seeing the pumps creating an unexpected effect was fun, I personally was not satisfied because the idea is to “control” my hardware to not go crazy. Before the next presentation (final show), one thing I should do is to make sure all the pumps work correctly, and the color will not be disrupting. But this could be a thing learnt as well: you never know how the final things turn out to be and how the intended effect and the actual one could be.

    Finally, this is still a work-in-progess project that I can’t wait to iterate on!

     

    Video

    (This are just detailed shots of the set-up and not Working Demos!!! – Please wait for the final show :))

    Code:

    //FLUX
    //This is the Arduino Code for operating the interactive painting setups. Pin assignment is listed below.
     
    #include <NewPing.h>
    int myArray1[20];
    int myArray2[20];
    int myArray3[20];
    int myArray4[20];
    int myArray5[20];
    int myArray6[20];
    int myArray7[20];
    int myArray8[20];
    int sensorValue[8] = {0,0,0,0,0,0,0,0};
    
    int counter1 = 0;
    int counter2 = 0;
    int counter3 = 0;
    int counter4 = 0;
    int counter5 = 0;
    int counter6 = 0;
    int counter7 = 0;
    int counter8 = 0;
    
    int rawValue1;
    int rawValue2;
    int rawValue3;
    int rawValue4;
    int rawValue5;
    int rawValue6;
    int rawValue7;
    int rawValue8;
    
    //Pin Mapping
    int pump1 = 6;
    int pump2 = 7;
    int pump3 = 8;
    int pump4 = 9;
    int pump5 = 10;
    int pump6 = 11;
    int pump7 = 12;
    int pump8 = 13;
    
    int pumpValue1 = 100; //red
    int pumpValue2 = 100; //blue
    int pumpValue3 = 100; //red
    int pumpValue4 = 100; //yellow
    int pumpValue5 = 100; //yellow
    int pumpValue6 = 100; //blue
    int pumpValue7 = 100; //red
    int pumpValue8 = 100; //blue
    
    int distance_two[2] = {0,0};
    int distance_pin[2] = {0,0};
    
    #define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
    
    #define TRIGGER_PIN1  22  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN1     23  // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN2  24  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN2     25 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN3  26  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN3   27 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN4  28  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN4     29 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN5  30  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN5     31 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN6  32  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN6     33 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN7  34  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN7     35 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    #define TRIGGER_PIN8  36  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN8     37 // Arduino pin tied to echo pin on the ultrasonic sensor.
    
    NewPing sonar1(TRIGGER_PIN1, ECHO_PIN1, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar2(TRIGGER_PIN2, ECHO_PIN2, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar3(TRIGGER_PIN3, ECHO_PIN3, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar4(TRIGGER_PIN4, ECHO_PIN4, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar5(TRIGGER_PIN5, ECHO_PIN5, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar6(TRIGGER_PIN6, ECHO_PIN6, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar7(TRIGGER_PIN7, ECHO_PIN7, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    NewPing sonar8(TRIGGER_PIN8, ECHO_PIN8, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    
    void setup() {
      pinMode(pump1, OUTPUT);
      pinMode(pump2, OUTPUT);
      pinMode(pump3, OUTPUT);
      pinMode(pump4, OUTPUT);
      pinMode(pump5, OUTPUT);
      pinMode(pump6, OUTPUT);
      pinMode(pump7, OUTPUT);
      pinMode(pump8, OUTPUT);
      Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
    }
    
    void loop() {
      delay(500);                  
    
    //-----get raw data-----
      
      rawValue1 = sonar1.ping_cm();
    //  Serial.println(rawValue1);
      if (rawValue1 >0){
      myArray1 [counter1] = rawValue1;
      }
      counter1 += 1;
      if (counter1 >= 20) {
        counter1 = 0;
      }
      int allData1 = 0;
      for (int i = 0; i <= 20; i++) {
        allData1 = allData1 + myArray1[i];
      }
      int average1 = allData1 / 20;
    //  Serial.println(average1);
      sensorValue[0] = average1;
    
    
      rawValue2 = sonar2.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue2 >0){
      myArray2 [counter2] = rawValue2;
      }
      counter2 += 1;
      if (counter2 >= 20) {
        counter2 = 0;
      }
      int allData2 = 0;
      for (int i = 0; i <= 20; i++) {
        allData2 = allData2 + myArray2[i];
      }
      int average2 = allData2 / 20;
    //  Serial.println(average2); 
      sensorValue[1] = average2;
    
    
      rawValue3 = sonar3.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue3 >0){
      myArray3 [counter3] = rawValue3;
      }
      counter3 += 1;
      if (counter3 >= 20) {
        counter3 = 0;
      }
      int allData3 = 0;
      for (int i = 0; i <= 20; i++) {
        allData3 = allData3 + myArray3[i];
      }
      int average3 = allData3 / 20;
    //  Serial.println(average3); 
      sensorValue[2] = average3;
    
    
      rawValue4 = sonar5.ping_cm(); //sonar4 is broken
    //  Serial.println(rawValue2);
      if (rawValue4 >0){
      myArray4 [counter4] = rawValue4;
      }
      counter4 += 1;
      if (counter4 >= 20) {
        counter4 = 0;
      }
      int allData4 = 0;
      for (int i = 0; i <= 20; i++) {
        allData4 = allData4 + myArray4[i];
      }
      int average4 = allData4 / 20;
    //  Serial.println(average4); 
      sensorValue[3] = average4;
    
    
     
      rawValue5 = sonar5.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue5 >0){
      myArray5 [counter5] = rawValue5;
      }
      counter5 += 1;
      if (counter5 >= 20) {
        counter5 = 0;
      }
      int allData5 = 0;
      for (int i = 0; i <= 20; i++) {
        allData5 = allData5 + myArray5[i];
      }
      int average5 = allData5 / 20;
    //  Serial.println(average5); 
      sensorValue[4] = average5;
    
    
     
      rawValue6 = sonar6.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue6 >0){
      myArray6 [counter6] = rawValue6;
      }
      counter6 += 1;
      if (counter6 >= 20) {
        counter6 = 0;
      }
      int allData6 = 0;
      for (int i = 0; i <= 20; i++) {
        allData6 = allData6 + myArray6[i];
      }
      int average6 = allData6 / 20;
    //  Serial.println(average6); 
      sensorValue[5] = average6;
    
    
    
      rawValue7 = sonar7.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue7 >0){
      myArray7 [counter7] = rawValue7;
      }
      counter7 += 1;
      if (counter7 >= 20) {
        counter7 = 0;
      }
      int allData7 = 0;
      for (int i = 0; i <= 20; i++) {
        allData7 = allData7 + myArray7[i];
      }
      int average7 = allData7 / 20;
    //  Serial.println(average7); 
      sensorValue[6] = average7;
    
    
      rawValue8 = sonar8.ping_cm();
    //  Serial.println(rawValue2);
      if (rawValue8 >0){
      myArray8 [counter8] = rawValue8;
      }
      counter8 += 1;
      if (counter8 >= 20) {
        counter8 = 0;
      }
      int allData8 = 0;
      for (int i = 0; i <= 20; i++) {
        allData8 = allData8 + myArray8[i];
      }
      int average8 = allData8 / 20;
    //  Serial.println(average8); 
      sensorValue[7] = average8;
    
    //Serial.print(sensorValue)
    //Serial.println(average1); Serial.println(average2); Serial.println(average3); Serial.println(average4); Serial.println(average5);Serial.println(average6);Serial.println(average7);Serial.println(average8); 
    
    //-----set pump pin-----
    //pump is from 100 to 255 
    // if distance > x, red or blue pump is increased 
    
    //find smallest two vertical distance
      int small_value1; 
      int small_value2;
      int small_pin1; //find sensor location
      int small_pin2;
      for (int i = 1; i < 4; i++){
        if (sensorValue[i] < sensorValue[i-1]){
          small_value1 = sensorValue[i];
          small_pin1 = i+5;
          }
        }
      for (int i = 5; i < 8; i++){
        if (sensorValue[i] < sensorValue[i-1] && i != small_pin1){
          small_value2 = sensorValue[i];
          small_pin2 = i+5;
          }
        }
      //Increase_Pump value
      int pump_updated = 200;
      
      Serial.println(small_pin2,small_pin1);
      //color spreading out
      analogWrite(small_pin1, pump_updated);
      analogWrite(small_pin2, pump_updated);
    
      //-----send signal to pump-----
      //Mixing: more left - more red element, more right - more blue element
      int pump_red = pumpValue1;
      int pump_blue = pumpValue1;
      int pumpArray[8] = {6,8,10,12};
      for (int i = 0; i < 8; i++){
        if (i+6 != small_pin1 | i+6 != small_pin2){
          analogWrite(i+6, pump_red);
        }
        pump_red = pump_red + 30;
        }
      int pumpArray[8] = {7,9,11,13};
      for (int i = 0; i < 8; i++){
        if (i+6 != small_pin1 | i+6 != small_pin2){
          analogWrite(i+6, pump_blue);
        }
        pump_blue = pump_blue - 30;
        }
    
    //Serial.println(small_pin1,small_pin2);Serial.println(small_value1,small_value2);
     //analogWrite(pump1, pumpValue1);
    //analogWrite(pump2, pumpValue2);
    //analogWrite(pump3, pumpValue3);
    //analogWrite(pump4, pumpValue4);
    //analogWrite(pump5, pumpValue5);
    //analogWrite(pump6, pumpValue6);
    //analogWrite(pump7, pumpValue7);
    //analogWrite(pump8, pumpValue8);
    
    }
    
    
    

     

    ]]>