Week 13: Final Project Documentation & User Testing

Concept

Fruitfall Frenzy is an entertaining and straightforward catching game where players aim to accumulate points by catching fruits while avoiding junk food to prevent point deductions. To achieve victory, players must collect fruits and reach a score of 15 or more. However, failing to do so and catching 10 junk foods with a score of 0 results in a loss for the player.

link to the game: https://editor.p5js.org/Javeria/sketches/e-4vC95i_

Implementation

In terms of interaction, I’ve incorporated two buttons on the breadboard to facilitate the control of the basket’s left and right movements. The Arduino integration is seamlessly implemented, with the readSerial() function acting as the communication bridge between p5.js and Arduino. The Arduino code is designed to read the status of two switches and relay these values to p5.js. On the other hand, p5.js takes charge of displaying the game graphics, playing sounds, and managing the overall game logic.

p5js Code:

let basket;
let fruits = [];
let junkFoods = [];
let score = 0;
let gameOver = false;
let startPage;
let front;
let instructions;
let gifImage;
let win;
let lose;
let junkFoodsCaught = 0;
let gameStarted = false;
let instructionMode = false;
let customFont;
let gameWon = false;
let switch1State, switch2State;
let startmusic;
let winmusic;
let lossmusic;
let gamemusic;
let fruitmusic;
let junkfoodmusic;
let currentMusic;

let basketImg, backgroundImage;
let fruitImages = [];
let junkFoodImages = [];

function preload() {
  customFont = loadFont('Sunday Happy.ttf');
  startPage = loadImage('1.png');
  instructions = loadImage('2.png');
  basketImg = loadImage('basket.png');
  backgroundImage = loadImage('background.png');
  win = loadImage('win.png'); // Add this line
  lose = loadImage('lose.gif'); // Add this line
  startmusic = loadSound ('start.mp3');
  winmusic  = loadSound ('win.mp3');
  lossmusic  = loadSound ('loss.mp3');
  gamemusic  = loadSound ('game.mp3');
  fruitmusic  = loadSound ('fruit.mp3');
  junkfoodmusic  = loadSound ('junkfood.mp3');

  // Load different fruit images
  for (let i = 1; i <= 5; i++) {
    fruitImages.push(loadImage('fruit' + i + '.png'));
  }

  // Load different junk food images
  for (let i = 1; i <= 2; i++) {
    junkFoodImages.push(loadImage('junkfood' + i + '.png'));
  }
}

function setup() {
  createCanvas(620, 650);
  setupGame();
  currentMusic = startmusic;
  currentMusic.play();
}

function setupGame() {
  basket = new Basket(basketImg);

  // Limit the initial number of falling elements
  const initialFruitsCount = 2; // Adjust this value as needed
  const initialJunkFoodsCount = 2; // Adjust this value as needed

  for (let i = 0; i < initialFruitsCount; i++) {
    fruits.push(createRandomFruit());
  }

  for (let i = 0; i < initialJunkFoodsCount; i++) {
    junkFoods.push(createRandomJunkFood());
  }
}

function drawGame() {
  // Draw background image
  image(backgroundImage, 0, 0, width, height);

  basket.display();
  basket.move();

  // Add new fruits and junk foods based on certain conditions
  if (frameCount % 60 === 0 && fruits.length + junkFoods.length < 5) {
    // Check if there's enough space for a new fruit
    if (fruits.length < 2) {
      fruits.push(createRandomFruit());
    }

    // Check if there's enough space for a new junk food
    if (junkFoods.length < 2) {
      junkFoods.push(createRandomJunkFood());
    }
  } }
 //<-- Add this closing bracket

function draw() {
  background(250);

  if (gameWon) {
    // Player wins
    currentMusic.stop(); // Stop the current music
    winmusic.play();    // Play the win music
    currentMusic = winmusic;
    drawWinPage();
     currentMusic.stop(); // Stop the current music
    winmusic.play();    // Play the win music
    currentMusic = winmusic; // Update currentMusic
  } else if (gameOver) {
    // Player loses
    drawLosePage();
    currentMusic.stop(); // Stop the current music
    lossmusic.play();   // Play the lose music
    currentMusic = lossmusic; // Update currentMusic
  } else {
    if (instructionMode) {
      // Display instructions
      image(instructions, 0, 0, width, height);
      fill(255, 204, 0, 180);
      noStroke();
      rect(535, 524, 70, 35);
      fill(0);
      textSize(30);
      textFont(customFont);
      text("Back", 542, 549);
       if (currentMusic !== startmusic) {
        currentMusic.stop(); // Stop the current music if it's not start music
        startmusic.play();  // Play the start music
        currentMusic = startmusic; // Update currentMusic
      }

      
    } else {
      // Display the start page
      image(startPage, 0, 0, width, height);
      fill(255, 204, 0, 180);
      noStroke();
      rect(228, 335, 150, 35);
      fill(0);
      textSize(30);
      textFont(customFont);
      text("Start Game", 237, 359);
      fill(255, 204, 10, 180);
      noStroke();
      rect(227, 391, 150, 35);
      fill(0);
      textSize(30);
      textFont(customFont);
      text("Instructions", 235, 417);
      

      // Draw game elements if the game has started
      if (gameStarted) {
        drawGame();
         if (currentMusic !== gamemusic) {
          currentMusic.stop(); // Stop the current music if it's not game music
          gamemusic.play();   // Play the game music
          currentMusic = gamemusic; // Update currentMusic
      }
    }
  }
}
}



function drawWinPage() {
  // Draw the win background image
  image(win, 0, 0, width, height);
  fill(255, 204, 0, 180);
      noStroke();
      rect(247, 266, 140, 35);
      fill(0);
      textSize(30);
      textFont(customFont);
      text("Restart", 272, 290);
  
  
  if (mouseIsPressed && mouseX > 247 && mouseX < 387 && mouseY > 266 && mouseY < 301){
    
  
    restartGame();
   }
  
}

function drawLosePage() {
  // Draw the lose background image
  image(lose, 0, 0, width, height);
  fill(255, 204, 0, 180);
      noStroke();
      rect(247, 592, 150, 35);
      fill(0);
      textSize(30);
      textFont(customFont);
      text("Restart", 280, 616);
  
  
   if (mouseIsPressed && mouseX > 247 && mouseX < 397 && mouseY > 592 && mouseY < 627) {
    restartGame();
   }
  

  
  
}
function restartGame() {
  gameOver = false;
  gameStarted = false;
  score = 0;
  junkFoodsCaught = 0;
  gameWon = false;
  setupGame();
}

function mousePressed() {
  if (!gameStarted) {
    if (instructionMode) {
      // Handle mouse click to return to the main menu
      if (mouseX > 535 && mouseX < 605 && mouseY > 524 && mouseY < 559) {
        instructionMode = false;
      }
    } else {
      if (mouseX > 228 && mouseX < 378) {
        if (mouseY > 335 && mouseY < 370) {
          // Start the game
          gameStarted = true;
          setupGame(); // Call setupGame when the game starts
        } else if (mouseY > 391 && mouseY < 426) {
          // Show instructions
          instructionMode = true;
        }
      }
    }
  }
}


class Basket {
  constructor(img) {
    this.width = 200;
    this.height = 150;
    this.x = width / 2 - this.width / 2;
    this.y = height - this.height - 10;
    this.img = img;
  }

  display() {
    image(this.img, this.x, this.y, this.width, this.height);
  }

  move() {
    if (keyIsDown(LEFT_ARROW) && this.x > 0) {
      this.x -= 5;
    }
    if (keyIsDown(RIGHT_ARROW) && this.x < width - this.width) {
      this.x += 5;
    }
  }

  moveLeft() {
    if (this.x > 0) {
      this.x -= 5;
    }
  }

  moveRight() {
    if (this.x < width - this.width) {
      this.x += 5;
    }
  }
}


class Fruit {
  constructor(img) {
    this.x = random(width);
    this.y = 0;
    this.diameter = 120;
    this.img = img;
  }

  display() {
    image(this.img, this.x - this.diameter / 2, this.y - this.diameter / 2, this.diameter, this.diameter);
  }

  fall() {
    this.y += 5;
  }

  intersects(basket) {
    let halfBasket = basket.width / 2;
    return (
      this.x > basket.x - halfBasket &&
      this.x < basket.x + basket.width + halfBasket &&
      this.y > basket.y &&
      this.y < basket.y + basket.height
    );
  }

  intersectsBasket(basket) {
    let halfBasket = basket.width / 2;
    return (
      this.x > basket.x - halfBasket &&
      this.x < basket.x + basket.width + halfBasket &&
      this.y + this.diameter / 2 > basket.y &&
      this.y - this.diameter / 2 < basket.y + basket.height
    );
  }
}


class JunkFood extends Fruit {
  constructor(img) {
    super(img);
    this.diameter = 60;
   
  }

  // Override the intersectsBasket method
  intersectsBasket(basket) {
    let halfBasket = basket.width / 2;
    return (
      this.x > basket.x - halfBasket &&
      this.x < basket.x + basket.width + halfBasket &&
      this.y + this.diameter / 2 > basket.y &&
      this.y - this.diameter / 2 < basket.y + basket.height
    );
  }
}

function drawGame() {
  // Draw background image
  image(backgroundImage, 0, 0, width, height);

  basket.display();
  basket.move();

  if (frameCount % 60 === 0) {
    fruits.push(createRandomFruit());
    junkFoods.push(createRandomJunkFood());
  }

  for (let i = fruits.length - 1; i >= 0; i--) {
    fruits[i].display();
    fruits[i].fall();

    if (fruits[i].intersects(basket)) {
      score += 1;
      fruits.splice(i, 1);
    } else if (fruits[i].y > height) {
      fruits.splice(i, 1);
    }
  }

  for (let i = junkFoods.length - 1; i >= 0; i--) {
    junkFoods[i].display();
    junkFoods[i].fall();

    if (junkFoods[i].intersects(basket)) {
      score -= 1; // Deduct score if junk food touches the basket
      junkFoods.splice(i, 1);
    } else if (junkFoods[i].y > height) {
      junkFoods.splice(i, 1);
    }
  }

  textSize(20);
  fill(0);
  text("Score: " + score, 20, 30);

  // Check win condition
  if (score >= 10) {
    gameWon = true;
    drawWinPage();
  }

  // Check lose condition
  if (score < 0 || junkFoodsCaught >= 10) {
    gameOver = true;
    drawLosePage();
  }
}

function createRandomFruit() {
  let randomFruitImg = random(fruitImages);
  let fruit = new Fruit(randomFruitImg);

  for (let existingFruit of fruits) {
    while (fruit.intersects(existingFruit) || fruit.intersectsBasket(basket)) {
      fruit = new Fruit(randomFruitImg);
    }
  }

  return fruit;
}

function createRandomJunkFood() {
  let randomJunkFoodImg = random(junkFoodImages);
  let junkFood = new JunkFood(randomJunkFoodImg);

  for (let existingFruit of fruits) {
    while (junkFood.intersects(existingFruit) || junkFood.intersectsBasket(basket)) {
      junkFood = new JunkFood(randomJunkFoodImg);
    }
  }
  for (let existingJunkFood of junkFoods) {
    while (junkFood.intersects(existingJunkFood) || junkFood.intersectsBasket(basket)) {
      junkFood = new JunkFood(randomJunkFoodImg);
    }
  }

  return junkFood;
}
function keyPressed() {
  // Handle key presses (this function only detects if a key is pressed at the moment)
}
function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////

  if (data != null) {
    // make sure there is actually a message
    // split the message
    let fromArduino = split(trim(data), ",");
    console.log(fromArduino);
    // if the right length, then proceed
    if (fromArduino.length == 2) {
      // only store values here
      // do everything with those values in the main draw loop
      
      // We take the string we get from Arduino and explicitly
      // convert it to a number by using int()
      // e.g. "103" becomes 103
      switch1State = int(fromArduino[0]);
      switch2State = int(fromArduino[1]);
      
      if (switch1State) {
        basket.moveLeft();
      } 
      
      if (switch2State) {
        basket.moveRight();
      }
    }

    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    let sendToArduino = "\n";
    writeSerial(sendToArduino);
  }
}


function keyPressed(){
  setUpSerial();
}

Arduino Code:

const int switch1Pin = 4;  
const int switch2Pin = 8;  

void setup() {
  Serial.begin(9600);
  pinMode(switch1Pin, INPUT_PULLUP);
  pinMode(switch2Pin, INPUT_PULLUP);
  

  while (Serial.available() <= 0 ){
    Serial.println("0,0");
    delay(300);
  }
}

void loop() {


  while(Serial.available()) {
    if (Serial.read() == '\n') {
      int switch1State = digitalRead(switch1Pin);
      delay(5);
      int switch2State = digitalRead(switch2Pin);
      
      Serial.print(switch1State);
      Serial.print(',');
      Serial.println(switch2State);
    }
  }


  
}

 

Future improvements

To enhance both the engagement and challenge levels of the game, I’m considering  incorporating additional features. These may include the gradual escalation of difficulty as the game progresses and the introduction of power-ups to provide players with unique advantages.

User Testing 

In the testing phase, I asked Nafiha to give my game a try. Impressively, she seamlessly utilized the buttons to navigate the basket without any hesitation. Her feedback highlighted that the controls were straightforward, requiring no additional instructions. Taking her suggestion into account, I modified the game dynamics by initially decreasing the number of falling objects and contemplating a gradual increase over time, resulting in a more balanced and enjoyable gameplay experience.

https://drive.google.com/file/d/1_36pcfyrhlTWxp_WqHmETfE6l8cfDicl/view?usp=sharing

 

Week 11: In class exercises

For the first exercise, Nafiha and I decided to use a light sensor as the analog input value for the movement of the ellipse on the p5js screen.

P5js Code

//exercise 1 p5js

let redValue = 0;
let transparency = 255;

function setup() {
  createCanvas(640, 480);
  textSize(18);
}

function draw() {
  if (key == " ") {
    initiateSerialConnection();
  }

  background(map(redValue, 0, 1023, 0, 255), 255, 255);
  fill(255, 0, 255, map(transparency, 0, 1023, 0, 255));

  if (!isSerialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    ellipse(redValue / 2, 240, 100, 100);
  }
}

function keyPressed() {
  if (key == " ") {
    initiateSerialConnection();
  }
}

function readSerial(data) {
  if (data != null) {
    let fromArduino = split(trim(data), ",");
    if (fromArduino.length == 2) {
      redValue = int(fromArduino[0]);
      transparency = int(fromArduino[1]);
    }
  }
}

Arduino Code

//exercise 1 arduino

void setup() {
 Serial.begin(9600);
 pinMode(LED_BUILTIN, OUTPUT);
// start the handshake
 while (Serial.available() <= 0)
{
   Serial.println("0,0"); // send a starting message
   delay(300);            // wait 1/3 second
 }
}
void loop()
{
 // wait for data from p5 before doing something
   while (Serial.available())
{
   digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data
 // Read sensor value
 int sensorValue = analogRead(A0);
  Serial.print(sensorValue);
 // Map sensor value to screen width
 int screenValue = map(sensorValue, 0, 1023, 0, 800);
 // Send mapped value to p5.js
 Serial.println(screenValue);
 delay(50); //    for stability
}
digitalWrite(LED_BUILTIN, LOW);
}

For the second exercise the LED’s brightness is changed by mouseX and the other’s by mouse Y.

P5js Code

//exercise 2 p5js
let rVal = 0;
let alpha = 255;
let left = 0; // True (1) if mouse is being clicked on left side of screen
let right = 0; // True (1) if mouse is being clicked on right side of screen
function setup() {
 createCanvas(255, 255);
 textSize(18);
}
function draw() {
 // one value from Arduino controls the background's red color
 background(map(rVal, 0, 1023, 0, 255), 255, 255);
 // the other value controls the text's transparency value
 fill(255, 0, 255, map(alpha, 0, 1023, 0, 255));
 if (!serialActive) {
   text("Press Space Bar to select Serial Port", 20, 30);
 } else {
   text("Connected", 20, 30);
  
   // Print the current values
   text('rVal = ' + str(rVal), 20, 50);
   text('alpha = ' + str(alpha), 20, 70);
 }
 // click on one side of the screen, one LED will light up
 // click on the other side, the other LED will light up
 if (mouseIsPressed) {
   if (mouseX <= width / 2) {
     left = 1;
   } else {
     right = 1;
   }
 } else {
   left = right = 0;
 }
}
function keyPressed() {
 if (key == " ") {
   // important to have in order to start the serial connection!!
   setUpSerial();
 }
}
// This function will be called by the web-serial library
// with each new *line* of data. The serial library reads
// the data until the newline and then gives it to us through
// this callback function
function readSerial(data) {
 ////////////////////////////////////
 //READ FROM ARDUINO HERE
 ////////////////////////////////////
 if (data != null) {
   // make sure there is actually a message
   // split the message
   let fromArduino = split(trim(data), ",");
   // if the right length, then proceed
   if (fromArduino.length == 2) {
     // only store values here
     // do everything with those values in the main draw loop
    
     // We take the string we get from Arduino and explicitly
     // convert it to a number by using int()
     // e.g. "103" becomes 103
     rVal = int(fromArduino[0]);
     alpha = int(fromArduino[1]);
   }
   //////////////////////////////////
   //SEND TO ARDUINO HERE (handshake)
   //////////////////////////////////
  
   let sendToArduino = mouseX + "," + mouseY + "\n";
   writeSerial(sendToArduino);
 }
}

Arduino Code

//exercise 2 arduino
int leftLedPin = 3;
int rightLedPin = 6;
void setup() {
 // Start serial communication so we can send data
 // over the USB connection to our p5js sketch
 Serial.begin(9600);
 // We'll use the builtin LED as a status output.
 // We can't use the serial monitor since the serial connection is
 // used to communicate to p5js and only one application on the computer
 // can use a serial port at once.
 pinMode(LED_BUILTIN, OUTPUT);
 // Outputs on these pins
 pinMode(leftLedPin, OUTPUT);
 pinMode(rightLedPin, OUTPUT);
 // Blink them so we can check the wiring
 digitalWrite(leftLedPin, HIGH);
 digitalWrite(rightLedPin, HIGH);
 delay(200);
 digitalWrite(leftLedPin, LOW);
 digitalWrite(rightLedPin, LOW);
 // start the handshake
 while (Serial.available() <= 0) {
   digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
   Serial.println("0,0"); // send a starting message
   delay(300);            // wait 1/3 second
   digitalWrite(LED_BUILTIN, LOW);
   delay(50);
 }
}
void loop() {
 // wait for data from p5 before doing something
 while (Serial.available()) {
   digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data
   int xPos = Serial.parseInt();
   int yPos = Serial.parseInt();
   if (Serial.read() == '\n') {
     analogWrite(leftLedPin, xPos);
     analogWrite(rightLedPin, yPos);
     int sensor = analogRead(A0);
     delay(5);
     int sensor2 = analogRead(A1);
     delay(5);
     Serial.print(sensor);
     Serial.print(',');
     Serial.println(sensor2);
   }
 }
 digitalWrite(LED_BUILTIN, LOW);
}

For the third exercise, we used a potentiometer as our analog sensor to control the breeze.

Video

link: https://youtube.com/shorts/Yh3D4YKBIeA?feature=share

P5js Code

//exercise 3 p5js
let velocity;
let gravity;
let position;
let acceleration;
let breeze;
let drag = 0.99;
let mass = 50;
let heightOfBall = 0;
function setup() {
  createCanvas(640, 360); 
 
  noFill();
  position = createVector(width/2, 0);
  velocity = createVector(0,0);
  acceleration = createVector(0,0);
  gravity = createVector(0, 0.5*mass);
  breeze = createVector(0,0); 
}
function draw() {
  background(215);
  fill(0);
  
  if (!serialActive) {
    text("Press the space bar to select the serial Port", 20, 30);
  }
  else 
  {
    text("Arduino is connected! Press b to jump.", 20, 30);
  
  applyForce(breeze);
  applyForce(gravity);
  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);
  ellipse(position.x,position.y,mass,mass);
    
  if (position.y > height-mass/2) {
      velocity.y *= -0.9;  // A little dampening when hitting the bottom
      position.y = height-mass/2;
    
    heightOfBall = 0;
    
    } 
    else {
      heightOfBall = 1;
    }
  }
}
function applyForce(force){
  // Newton's 2nd law: F = M * A
  // or A = F / M
  let f = p5.Vector.div(force, mass);
  acceleration.add(f);
}
function keyPressed() {
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }   
  else if (key=='b'){
    mass=random(15,80);
    position.y=-mass;
    velocity.mult(0);
  }
}
// this callback function
function readSerial(data) {
    ////////////////////////////////////
    //READ FROM ARDUINO HERE
    ////////////////////////////////////
  
     if (data != null) {
    // make sure there is actually a message
    
    let fromArduino = split(trim(data), ",");
    
       // if the right length, then proceed
    if (fromArduino.length == 1) {
//sensor value is the input from potentiometer
      let sensorVal = int(fromArduino[0]);
      
//potentiometer value ranges from 0 - 1023
//for values less than 400,wind blows to right
      if (sensorVal < 400){
        breeze.x=1
      }
//if value between 400 and 500, wind stops so ball stops
      else if(sensorVal >= 400 && sensorVal < 500){
        breeze.x = 0
      }
//if value greater than 500, wind blows to left
      else {
        breeze.x = -1
      }
          //////////////////////////////////
          //SEND TO ARDUINO HERE (handshake)
          //////////////////////////////////
    }
//height of ball sent to arduino to check if ball on floor or not
    let sendToArduino = heightOfBall  + "\n";
    writeSerial(sendToArduino);
  }
}

Arduino Code

const int poten_pin = A0;
const int ledPin = 2;
void setup() {
  Serial.begin(9600); // Start serial communication at 9600 bps
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(poten_pin, INPUT);
  // start the handshake
  while (Serial.available() <= 0) {
    digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
    Serial.println("0,0"); // send a starting message
    delay(300);            // wait 1/3 second
    digitalWrite(LED_BUILTIN, LOW); 
    delay(50);
  }
}
void loop() 
{
  // wait for data from p5 before doing something
    while (Serial.available()) 
    {
      digitalWrite(LED_BUILTIN, HIGH);
      digitalWrite(ledPin, LOW);
//read the position of ball from p5
      int position = Serial.parseInt();
    
      if (Serial.read() == '\n') {
        // Read potentiometer value
      int sensorValue = analogRead(poten_pin);
      //send value to p5
      Serial.println(sensorValue);
      }
//if ball is touching the ground i.e. height is zero, turn LED on
      if (position == 0)
      {
        digitalWrite(ledPin, HIGH);
      }
      else{
        digitalWrite(ledPin, LOW);
      }
    }
      digitalWrite(LED_BUILTIN, LOW); 
    }

 

 

 

Week 11: Final Project Idea

For my final project, I envision creating an immersive and interactive experience, a collaborative music jam that seamlessly combines Arduino gesture sensors with P5.js to transform hand movements into a dynamic and expressive musical journey. It will invite participants to engage in a unique music jam session where their gestures become the driving force behind the creation of a harmonious ensemble. Leveraging Arduino gesture sensors, the system will capture the nuances of users’ hand movements, translating them into musical notes or instrument selections in real-time through the P5.js environment.

Reading Reflection: Week 11

The reading offers a compelling intersection of disability, fashion and design. From my perspective, the narrative goes beyond mere functionality, delving into the core principles of inclusion and empowerment, particularly when viewed through the lenses of inclusivity and disability awareness.

Pullin skillfully demonstrates the evolution of assistive technology, including items like glasses and hearing aids, transcending their utilitarian roles to become symbols of fashion and personal identity. The transformation of these tools from mere aids to manifestations of individual style challenges the traditional notion that they are exclusively intended for individuals with particular disabilities.

He emphasizes the importance of designs that seamlessly blend functionality with aesthetic appeal. He underscores the significance of creating visually pleasing and accessible products for those with disabilities, shifting the narrative from mere utility to a combination of style and assistance. He stresses upon the value of maintaining functionality without compromising simplicity, asserting that such designs can benefit a broad spectrum of individuals, regardless of ability. 

The reading underscores the inclination to presume we understand what is optimal for individuals with disabilities, shaped by societal stigmas and preconceptions. Consequently, there is a critical need to concentrate on the nuanced aspects that not only improve our own lives but also profoundly influence the lives of those who stand as the primary recipients of these designs.

Week 10: Make a musical instrument

For our assignment, Nafiha and I drew inspiration from a synthesizer and a sampler to create our own musical instrument. Our instrument incorporates three buttons, a piezo buzzer, a potentiometer, and a bunch of wires and resistors. It is designed such that each button triggers a distinct melody, and by adjusting the potentiometer, the pitch is modified, consequently altering the played melodies.

Video:

link:https://drive.google.com/file/d/1zvd5qZeavfn0oTLdWGMqWOIxTLay6gbp/view?usp=sharing

Code:

const int switch1Pin = 12;
const int switch2Pin = 8;
const int switch3Pin = 7;
const int potentiometerPin = A0;
const int buzzerPin = 3;

int currentMelody[8];//array to store the current melody
int melodyIndex = 0;// keep track of the current note in the melody
int isPlaying = 0;//to indicate whether a melody is currently playing

//melodies for each button
int melody1[] = {262, 330, 392, 523, 392, 330, 262, 196};//melody for switch 1
int melody2[] = {330, 392, 523, 392, 330, 262, 196, 262};//melody for switch 2
int melody3[] = {392, 523, 659, 523, 392, 330, 262, 330};//melody for switch 3

void setup() {
  pinMode(switch1Pin, INPUT_PULLUP);
  pinMode(switch2Pin, INPUT_PULLUP);
  pinMode(switch3Pin, INPUT_PULLUP);
  pinMode(potentiometerPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
}

void loop() {
  //potentiometer value for pitch control
  int pitch = analogRead(potentiometerPin);

  //if switch 1 is pressed
  if (digitalRead(switch1Pin) == HIGH && !isPlaying) {
    playMelody(melody1, pitch);
  }

  //if switch 2 is pressed
  if (digitalRead(switch2Pin) == HIGH && !isPlaying) {
    playMelody(melody2, pitch);
  }

  //if switch 3 is pressed
  if (digitalRead(switch3Pin) == HIGH && !isPlaying) {
    playMelody(melody3, pitch);
  }

  //check if any switch is pressed and a melody is currently playing
  if ((digitalRead(switch1Pin) == HIGH || digitalRead(switch2Pin) == HIGH || digitalRead(switch3Pin) == HIGH) && isPlaying) {
    noTone(buzzerPin);//stop playing the melody
    isPlaying = 0;//set the flag to indicate no melody is playing
  }
}

void playMelody(int melody[], int pitch) {
  //map the potentiometer reading to adjust the pitch
  int adjustedPitch = map(pitch, 0, 1023, 50, 255);

  //copy the melody to the currentMelody array
  memcpy(currentMelody, melody, sizeof(currentMelody));

  //play each note in the melody
  for (int i = 0; i < sizeof(currentMelody) / sizeof(currentMelody[0]); i++) {
    tone(buzzerPin, currentMelody[i], adjustedPitch);
    delay(250);
    noTone(buzzerPin);
  }

  //set the flag to indicate a melody is currently playing
  isPlaying = 1;
}

In terms of improving our instrument, one potential feature could be incorporating additional sound effects through the use of the potentiometer. However, overall, working on this assignment was really fun, and we’re pretty pleased with the outcome.

Reading Reflection: Week 10

After reading the author’s rant on today’s tech scene and the follow up article, I found myself nodding in agreement. It’s as if they put into words what many of us have been feeling – that our tech progress feels more like cautious steps instead of the significant leaps we had hoped for. The call for a more forward-thinking approach isn’t just criticism; it’s a plea for innovation that genuinely enhances how we engage with the world.

The author’s observation regarding our bodies adapting to technology, rather than the other way around, resonates with the changing nature of our interactions with modern devices. For example, in our engagements with smartphones and virtual reality, the absence of tactile richness becomes apparent. With smartphones, our interactions are primarily confined to tapping and swiping on flat screens, lacking the tangible feedback that our hands and fingers are accustomed to in the physical world. This shift towards touchscreens, while undoubtedly convenient, introduces a disconnect between our tactile senses and the digital interfaces we navigate daily. Similarly, in the realm of virtual reality, immersion often falls short due to a lack of genuine tactile experiences. While VR technology can visually transport us to breathtaking landscapes and scenarios, the tactile feedback remains limited, hindering the full potential of our hands in interacting with this virtual realm. The conceptualization of virtual environments replicating real-world actions and fully leveraging the capabilities of our hands and bodies presents an intriguing prospect. Imagine not just seeing but feeling the virtual world – a paradigm shift that challenges the conventional boundaries of human-computer interaction.

As I contemplated these notions, I couldn’t help but reflect on the potential future resembling the video and how to prevent technology from becoming devoid of feelings and feedback. This isn’t to say that we lack feedback from current technology, but it prompts us to question whether we are achieving the best possible feedback. In essence, this exploration not only echoes the author’s insightful observations but also introduces a layer of personal introspection regarding the implications and responsibilities tied to our technological trajectory. It serves as a call to action, urging us to actively contribute to shaping a future where technology seamlessly aligns with our human experiences.

Reading Reflection: Week 9

Physical Computing’s Greatest Hits (and misses)

Tigoe delves into a range of ‘physical computing’ projects in his article, “Physical Computing’s Greatest Hits (and misses).” I found this piece to be particularly beneficial, treating it as a brainstorming session for ideas on my final project. Exploring the diverse examples of projects was not only interesting but also provided inspiration for potential directions in my own work. One particularly noteworthy aspect of Tigoe’s perspective is his emphasis on the intrinsic beauty of recurring themes in physical computing. Rather than viewing the repetition of certain ideas as a deterrent, Tigoe encourages a nuanced perspective. He suggests that newcomers should recognize the vast potential for injecting individuality and creativity into these themes. What resonates with me is Tigoe’s assertion that repetition need not be perceived as a limiting factor. Instead, he reframes it as an open invitation to innovate — an opportunity to build upon existing concepts, introduce new elements and refine established ones. This perspective fosters a dynamic and progressive approach to physical computing projects, emphasizing the continuous evolution and enrichment of the field through creative contributions.

Making Interactive Art: Set the Stage, Then Shut Up and Listen

In “Making Interactive Art: Set the Stage, Then Shut Up and Listen” interactive art, is described as, is nothing short of orchestrating a living conversation. It’s not just a canvas where an artist dumps their thoughts; it’s a dynamic exchange where both creator and audience actively contribute. What struck me the most in this article is the call to resist the temptation to over explain. It’s an invitation for artists to step back after crafting the initial experience and allowing people the space to unravel its layers on their own. I used to think that you had to know how to interpret a piece of art to fully enjoy it. But over time, I’ve come to realize that not knowing is sometimes better than knowing. There’s no one right way to perceive an experience, and by trying to dictate it to the audience, you limit their perspective. This approach to interactive art feels really freeing. It’s all about breaking away from a fixed narrative and embracing the unpredictable beauty of individual interpretations. It’s not about telling people what the art means; it’s about co-creating an experience that’s as diverse and dynamic as the people engaging with it.

Week 9: Digital and Analog Input/Output

For this week’s assignment, I drew inspiration from traffic lights. I aimed to replicate their functionality using a potentiometer for analog input and a button for digital input. The potentiometer serves to control the transition of the LED lights, mimicking the sequence of a traffic light as it turns from red to yellow and then to green. Additionally, pressing the button initiates a special state where all three lights blink simultaneously. 

Video Demonstration

link to the video: https://drive.google.com/file/d/1gREpijAMYFY12Yk4Ann_fiJzZrkjL-z1/view?usp=sharing

 

Code

The code uses the concepts of analog reading, digital input, LED control, and mapping to create a dynamic and interactive traffic light simulation.

const int analogSensorPin = A0;
const int digitalSensorPin = 2;
const int redLEDPin = 6;
const int yellowLEDPin = 9;
const int greenLEDPin = 11;

//variables to store sensor readings
int analogSensorValue;
int digitalSensorState;
int trafficLightState = 0; // 0: red, 1: yellow, 2: green

void setup() {
  pinMode(analogSensorPin, INPUT);
  pinMode(digitalSensorPin, INPUT);
  pinMode(redLEDPin, OUTPUT);
  pinMode(yellowLEDPin, OUTPUT);
  pinMode(greenLEDPin, OUTPUT);
}

void loop() {
  analogSensorValue = analogRead(analogSensorPin);

  digitalSensorState = digitalRead(digitalSensorPin);

  //toggle traffic light state on button press
  if (digitalSensorState == HIGH) {
    // Blink all lights together
    digitalWrite(redLEDPin, HIGH);
    digitalWrite(yellowLEDPin, HIGH);
    digitalWrite(greenLEDPin, HIGH);
    delay(500); // Blink duration
    digitalWrite(redLEDPin, LOW);
    digitalWrite(yellowLEDPin, LOW);
    digitalWrite(greenLEDPin, LOW);
    delay(200); // Debouncing
  } else {
    //map potentiometer value to traffic light state
    trafficLightState = map(analogSensorValue, 0, 1023, 0, 2);

    //control traffic light LEDs based on state
    if (trafficLightState == 0) {
      //red light
      digitalWrite(redLEDPin, HIGH);
      digitalWrite(yellowLEDPin, LOW);
      digitalWrite(greenLEDPin, LOW);
    } else if (trafficLightState == 1) {
      //yellow light
      digitalWrite(redLEDPin, LOW);
      digitalWrite(yellowLEDPin, HIGH);
      digitalWrite(greenLEDPin, LOW);
    } else if (trafficLightState == 2) {
      // green light
      digitalWrite(redLEDPin, LOW);
      digitalWrite(yellowLEDPin, LOW);
      digitalWrite(greenLEDPin, HIGH);
    }
  }
  delay(50);
}

I enjoyed working on this assignment since there were numerous ways to modify the LEDs’ behavior. The only challenging aspect was recording the video, as the potentiometer is a bit tough to turn, and it ends up rotating the entire breadboard with it :/

 

Week 8: Create an Unusual Switch

Concept

Since the assignment was to create a switch that didn’t rely on using hands, I came up with the idea of using feet instead. The way this switch operates is that when your feet, covered in socks, make contact with each other, it triggers the LED to light up. I love collecting cute socks, so I thought it would be a fun and an entertaining feature to have the socks themselves light up when they come into contact with one another.

Demonstration

This is how the switch works:

https://drive.google.com/file/d/1wJUOS9xvNBDc9PbyCIyS2xbPuY8vBTjv/view?usp=share_link

This is the setup of the switch:

Process & Highlights 

The components used in constructing this switch include an LED, wires, an Arduino Uno, a breadboard, aluminum foil, tape, a resistor, and a pair of socks. The setup employs a basic series circuit configuration, featuring an LED and a resistor. To increase the contact area, I used aluminum foil to cover the wire ends attached to the socks. When these wire connections on the socks come into contact with each other, it activates the LED, causing it to illuminate.

Reflections

I thoroughly enjoyed working on this assignment, and there’s definitely ample space for additional creativity. One exciting idea is to attach wires at various points on the socks and incorporate multiple LED lights in different colors. This way, diverse foot movements would trigger various colored LEDs, adding another exciting layer to the experience.

 

Reading Reflection: Week 8

Emotion & Attractive

I thoroughly enjoyed this article as it underscores the significance of both user-friendliness and visual appeal. The author also acknowledges the importance of human interaction with products and a comprehensive design approach. In today’s context, the visual attractiveness of a product holds the potential to substantially enhance the overall user experience.

Don Norman doesn’t exhibit bias in this reading. He places value on usability and functionality while also recognizing the necessity of beauty and enjoyment in design. This well-rounded perspective is crucial as it demonstrates the complexity of human interaction with products and the need for a holistic design approach.

This reading has reinforced my belief in the importance of aesthetics within design. While functionality and usability remain pivotal, the aesthetic charm of a product can significantly elevate the user’s experience and satisfaction. This is especially relevant in today’s landscape, where numerous options are available, and a product’s visual appeal can truly set it apart. This reading also prompted me to question: How can designers strike the right balance between usability and aesthetics?

Her Code Got Humans on the Moon—And Invented Software Itself

The article offers a captivating glimpse into the formative years of software engineering and the substantial impact Margaret Hamilton had on the Apollo space program. It’s fascinating to observe how Hamilton’s efforts served as the foundation for the evolution of software engineering and how her groundbreaking ideas continue to influence the field to this day.

I found this article particularly appealing because it underscores Hamilton’s exceptional status as one of the few women working in the tech and engineering fields. This resonates with me as a computer science student because I’ve observed a distinct gender disparity in my classes and at internships, with a significantly higher number of male students compared to their female counterparts. The article also touches upon the challenges Hamilton faced as a working mother and a programmer in the space industry, as people questioned her ability to balance her career with motherhood. However, it was during one of the instances when her daughter inadvertently interacted with a keyboard and caused a simulator crash that proved to be of immense value. This incident played a crucial role in bringing the astronauts safely back to Earth after Jim Lovell selected P01 during a flight. By showcasing Hamilton’s achievements and contributions, the article challenges conventional gender roles and stereotypes. It highlights the significance of acknowledging and celebrating the accomplishments of women in the software development field.

Reading this article undeniably increased my understanding of the important roles played by early software engineers like Hamilton. In our current era of highly sophisticated software, it can be easy to forget the pioneers who established the groundwork for these remarkable advancements.