PCOMP: MIDTERM PART II

continued from first blogpost

The plan this week was to ensure everything works in sequence and to stitch all the parts of the project together. For this we worked on the following:

-> Serially communicate spinning wheel result to p5

 

-> Test solenoid valve using Arduino.

The basic circuit:

IMG_3754.JPG

-> Ensure water drops only after the artist is selected on the wheel.

 

-> Run animation and sound on p5 after water drops on the screen.

After the first round of testing with fellow students Isa, Simon and Terrick, we realised that the users get lost after spinning the wheel, but understand the concept once we tell them.

IMG_8628.JPG

We then decided to narrate the story before the user starts interacting with the piece. We had a voice over that would start once the headphones are lifted off the stand. We first used a proximity sensor to detect the headphones. We then switched to light sensor because the results were more accurate. This was the end of constructing the whole piece. And time to get feedback from users. We got students Hadar, Amythab, Daniel and Akmyrat to test this second protoype. Inputs from user testing:

  1. Users did not comprehend why there was a water drop. This means that they don’t pay much attention to the narration.

  2. They love playing with the spinning wheel and would keep spinning it.

  3. Few of them would actually put up their hand for the drop and some wouldn’t. This again meant that the instructions weren’t clear.

  4. Users DO NOT like to be instructed.

  5. Lighting affected their mood and hence the message that was intended.

  6. Users reported that they enjoyed mixing the music with the wheel, the "haunted" versions we produced especially for our installation piece made some of them feel uneasy and even scared. Others felt positively influenced by the music.

  7. They liked watching the water drop and even playing with it on the glass, but some did not fully understand the connection to the rest of the installation - although the voice narration explained it to them. 

  8. Some were overwhelmed by the sensory inputs and stimulations - they wished less was happening and they could focus more on music, playing with the wheel and watching the water as they felt strongest for these parts.

Keeping all of these in mind, we realized that displaying the title of the piece with a little description of the story of the drop and a hint at its spiritual roots in India can have a larger impact than the narration just at the beginning. Users do not have to hold the drop in their hand. We also realized that drop on the screen actually works out because it looks like the drop is carrying the artist from heaven(spinning wheel) to earth(screen). 

We then modified our final midterm piece based on these inputs and thoughts. 

Interaction:

  • wheel first touch -> water drop, plays one track, displays visuals
  • wheel further touches -> layering more tracks and water drops on screen
  • visual communication: p5 sketch
  • audio: p5 sketch

The user is acting and reacting to audiovisual stimuli, can create his own listening and viewing experience, the water drop serves as a unique, non-interactive physical stimulation.

IMG_2040.JPG

Our Arduino code:

/*     Arduino Rotary Encoder Tutorial
 *      
 *  by Dejan Nedelkovski, www.HowToMechatronics.com
 *  
 */
 
 #define outputA 2
 #define outputB 3
 #define reset_button 5

 
 int counterLast = 1;
 int wait_loops = 0;
 int counter = 0;
 int star = 0;
 int aState;
 int aLastState; 
 int ValveOpen = 700;
 int ValvePause = 1000;
 int milk = 0;
 int lifted = 0;
 int audio_start = 0;
 
 const int SolenoidPin = 4;  // Set valve to pin 2 connects to a transistor and a 9V battery

 int sensorPin = A5;
 int sensorValue = 0;


 
 void setup() { 
   
   pinMode (outputA,INPUT);
   pinMode (outputB,INPUT);
   pinMode (reset_button, INPUT);
   pinMode(SolenoidPin, OUTPUT);  // Set pin 2 as an output

   
   Serial.begin (115200);
   // Reads the initial state of the outputA
   aLastState = digitalRead(outputA);   
 } 
 void loop() {
  sensorValue = analogRead (sensorPin);
  //delay(10);
  //Serial.write(sensorValue);
  
   if (sensorValue > 800){
      lifted = 0;
      audio_start = 0;
      //Serial.write(sensorValue);
      delay (100);
    }
    
   if (sensorValue < 800){
   lifted = 1;
   }
   if (lifted == 1){
     if(audio_start == 0){
     star = 6;
     Serial.write(star);
     audio_start = 1;
     delay (100);
     }
   }
   aState = digitalRead(outputA); // Reads the "current" state of the outputA
   // If the previous and the current state of the outputA are different, that means a Pulse has occured
   if (aState != aLastState){ 
    wait_loops = 0;    
     // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
     if (digitalRead(outputB) != aState) { 
       counter ++;
     } else {
       counter --;
     }
     if (counter == 40 || counter == - 40){
      counter = 0;
     }
     if (counter > -6 && counter <= 4){
      star = 1;
      //Serial.println("Minnie");
     }
     if (counter > 4 && counter <= 14){
      star = 4;
      //Serial.println("John");
     }
     if (counter > 14 && counter <= 24){
      star = 3;
      //Serial.println("Amy");
     }
     if (counter > 24 && counter <=34){
      star = 2;
      //Serial.println("David");
     }
          if (counter < -6 && counter >= - 16){
      star = 2;
      //Serial.println("David");
     }
     if (counter < - 16 && counter >= - 26){
      star = 3;
      //Serial.println("Amy");
     }
     if (counter < - 26 && counter >= - 36){
      star = 4;
      //Serial.println("John");
     }
     if (counter > 34 && counter < 40){
      star = 1;
      //Serial.println("Minnie");
     }
     if (counter < - 36 && counter > -40){
      star = 1;
      //Serial.println("Minnie");
     }
     
     //Serial.print("Position: ");
     //Serial.println(counter);
     Serial.write(star);
     milk = 1;
     delay(1);
   }
   aLastState = aState; // Updates the previous state of the outputA with the current state
//   if (digitalRead(reset_button) == HIGH){
//   }
//   else {
//   }
   wait_loops = wait_loops + 1;
   if ( milk == 1){
    if (wait_loops > 100000){
      Serial.write(5);
       digitalWrite(SolenoidPin, HIGH); // makes the valve open    
       delay(ValveOpen); 
       digitalWrite(SolenoidPin, LOW);
       delay(ValvePause);
       wait_loops = 0;     
       milk = milk + 1;
    }
    }
   }
 

Our p5 code:

var portName = '/dev/cu.usbmodem1411';  // fill in your serial port name here
var options = { baudrate: 115200}; // change the data rate to whatever you wish

var serial;          // variable to hold an instance of the serialport library
var inData;                             // for incoming serial data

var star = 8;

let star_select;

var sample;

var inData_last;

var wait;

var frame_count = 0;

var plays = 0;

let john;
let amy;
let david;
let minnie;

function preload(){
  soundFormats('mp3', 'ogg');
  sample0 = loadSound('barack_vocal.mp3');
  sample1 = loadSound('sounds/minnie_vocal.mp3');
  sample2 = loadSound('sounds/john_vocal.mp3');
  sample3 = loadSound('sounds/amy_vocal.mp3');
  sample4 = loadSound('sounds/bowie_vocal.mp3');
  sample5 = loadSound('barack_vocal2.mp3');
}

function setup() {
  imageMode(CENTER);
  john = loadImage('pics/johncoltrane.png');
  amy = loadImage('pics/amyw.png');
  david = loadImage('pics/davidbowie.png');
  minnie = loadImage('pics/minnier.png');
  title = loadImage('pics/title.png');
  
  
  createCanvas(windowWidth, windowHeight);
  serial = new p5.SerialPort();       // make a new instance of the serialport library
  serial.on('list', print);  // set a callback function for the serialport list event
  serial.on('connected', serverConnected); // callback for connecting to the server
  serial.on('open', portOpen);        // callback for the port opening
  serial.on('data', serialEvent);     // callback for when new data arrives
  serial.on('error', serialError);    // callback for errors
  serial.on('close', portClose);      // callback for the port closing
 
  serial.list();                      // list the serial ports
  serial.open(portName, options);
}

function serverConnected() {
  print('connected to server.');
}
 
function portOpen() {
  print('the serial port opened.')
}
 
function serialEvent() {
 inData = Number(serial.read());
}
 
function serialError(err) {
  print('Something went wrong with the serial port. ' + err);
}
 
function portClose() {
  print('The serial port closed.');
}

function draw() {
  frame_count ++;
  background(0);
  fill(255);
  //textSize(60);
  if (star == 8){
  push();
  translate(windowWidth / 2, windowHeight / 2);
  scale(0.23);
  image(title, 0, 0)
  pop();
  }
  //text("sensor value: " + inData, 30, 30);
  inData_last = inData;
  
  if (inData == 1){
      //text("Star: Minnie", 30, 100);
    star = 1;
    star_select = "minnie";
    frame_count = 0;
  }
  if (inData == 2){
      //text("Star: John", 30, 100);
    star = 2;
    star_select = "john";
    frame_count = 0;
  }
  if  (inData == 3){
      //text("Star: Amy", 30, 100);
    star = 3;
    star_select = "amy";
    frame_count = 0;
  }
  if (inData == 4){
      //text("Star: David", 30, 100);
    star = 4;
    star_select = "david";
    frame_count = 0;
  }
  if (inData == 5){
  //text("drop", 30, 100);
  //frame_count = 0;
  }
  if (inData == 6){
    star = inData;
    //frame_count = 0;
    inData = "none"
    if (star == 6){
      sample0.play(6);
      star = "none";
      plays = 1;
    }
  }
 
  if (inData_last == inData){
      if (frame_count > 20){
      if (star == 1){
              sample1.play();
        //sample5.play(sample1.duration() + 2);
        print("wait");
            star = "none";
          }
      if (star == 2){
              sample2.play();
                //sample5.play(sample2.duration() + 2);
        print("wait");
            star = "none";
          }
      if (star == 3){
              sample3.play();
                //sample5.play(sample3.duration() + 2);
        print("wait");
            star = "none";
          }
      if (star == 4){
        sample4.play();
                //sample5.play(sample4.duration() + 2);
        print("wait");
            star = "none";
          }
        if (star_select == "minnie" && sample1.isPlaying()){
        //push();
        translate(windowWidth / 2, windowHeight / 2);
        //scale(1.0)
        scale(0.4);
        rotate(radians(frameCount));
        image(minnie, 0, 0);
        //pop();
      }
      if (star_select == "john" && sample2.isPlaying()){
        //push();
        translate(windowWidth / 2, windowHeight / 2);
        scale(0.4);
        rotate(radians(frameCount));
        image(john, 0, 0);
        //pop();
      }
      if (star_select == "amy" && sample3.isPlaying()){
        //push();
        translate(windowWidth / 2, windowHeight / 2);
        scale(0.4);
        rotate(radians(frameCount));
        image(amy, 0, 0);
        //pop();
      }
      if (star_select == "david" && sample4.isPlaying()){
        //push();
        translate(windowWidth / 2, windowHeight / 2);
        scale(0.4);
        rotate(radians(frameCount));
        image(david, 0, 0);
        //pop();
      }
            if (sample1.isPlaying() != true && sample2.isPlaying() != true){
        if (sample3.isPlaying() != true && sample4.isPlaying() != true){
        push();
                translate(windowWidth / 2, windowHeight / 2);
        scale(0.23);
        image(title, 0, 0);
        pop();
        }
      }
  }
  }
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}