Week 14 – Final Project Blog

Concept and Implementation

The game begins with a start page where the user gets enough time to read through the instructions.

Upon clicking start the game begins with a sequence of one color; say blue. The color is highlighted with a black stroke. The user is supposed to press the same color. If they get it right they proceed to the next round which appends one more color to the sequence say green and now the player sees two colors blue and green. If they had gotten it wrong on the first try the sequence repeats at the expense of one out of the three lives that the player has. This is to say that the player has got only two passes to get it wrong. The game continues until all the colors have been highlighted and well matched by the players. At the side there is a score tracking progress bar that fills depending on the number of colors that the player gets right. When the player successfully fills the bar by getting all the colors right, the game ends and the player wins. If the player gets it wrong three times the game ends and they have the option to restart.

VIDEO/ IMAGES

 

ARDUINO

The arduino code is less complicated compared to the p5js code. The connections involved 

  • 4 led push buttons
  • Buzzer
  • Jumper wires

SCHEMATIC

For my scematic I used normal push buttons as I could not find the led-push buttons for representation.

ARDUINO CODE

// Pin Definitions
const int redPin = 6;
const int greenPin = 7;
const int bluePin = 8;
const int yellowPin = 9;
const int buzzerPin = 11;

const int buttonPins[] = {2, 3, 4, 5};  // Red, Green, Blue, Yellow
const char* colorNames[] = {"red", "green", "blue", "yellow"};

// Frequencies for different colors (in Hz)
const int tones[] = {262, 330, 390, 494}; // A4, C5, D5, E5

int lastButtonState[4] = {HIGH, HIGH, HIGH, HIGH};  // For edge detection
String colorSequence = "";  // Collects pressed color names

void setup() {
  // LED outputs
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);

  // Button inputs
  for (int i = 0; i < 4; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }

  Serial.begin(9600);
}

void loop() {
  for (int i = 0; i < 4; i++) {
    int currentState = digitalRead(buttonPins[i]);

    // Detect new button press (from HIGH to LOW)
    if (lastButtonState[i] == HIGH && currentState == LOW) {
      // Turn on the LED
      if (i == 0) digitalWrite(redPin, HIGH);
      if (i == 1) digitalWrite(greenPin, HIGH);
      if (i == 2) digitalWrite(bluePin, HIGH);
      if (i == 3) digitalWrite(yellowPin, HIGH);

      // Play tone on buzzer
      tone(buzzerPin, tones[i], 150);  // Play for 150 ms

      // Append to sequence and send it
      if (colorSequence.length() > 0) {
        colorSequence += ",";
      }
      colorSequence += colorNames[i];

      Serial.println(colorSequence);  // Send entire sequence
    }

    // Turn off LED if button is released
    if (currentState == HIGH) {
      if (i == 0) digitalWrite(redPin, LOW);
      if (i == 1) digitalWrite(greenPin, LOW);
      if (i == 2) digitalWrite(bluePin, LOW);
      if (i == 3) digitalWrite(yellowPin, LOW);
    }

    lastButtonState[i] = currentState;
  }

  delay(50);  // Short delay for debouncing
}
P5JS 

For my p5js I mainly used functions to help with handling of data and processing from the arduino and to display. In the sketch I had html, a webserial library, music(background, correct and incorrect sounds), and the actual p5js sketch code. Some of the notable portions of the p5js code include music handling, serial communication, game start page, button handling and game over page.

Below are the different code portions.

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
    
    <!-- Load the web-serial library -->
    <script src="p5.web-serial.js"></script>
    
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />

  </head>
  <body>
    <main>
    </main>
    <script src="sketch.js"></script>
  </body>
</html>

WEBSERIAL LIBRARY

let port, reader, writer;
let serialActive = false;

async function getPort(baud = 9600) {
  let port = await navigator.serial.requestPort();

  // Wait for the serial port to open.
  await port.open({ baudRate: baud });

  // create read & write streams
  textDecoder = new TextDecoderStream();
  textEncoder = new TextEncoderStream();
  readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
  writableStreamClosed = textEncoder.readable.pipeTo(port.writable);

  reader = textDecoder.readable
    .pipeThrough(new TransformStream(new LineBreakTransformer()))
    .getReader();
  writer = textEncoder.writable.getWriter();

  return { port, reader, writer };
}

class LineBreakTransformer {
  constructor() {
    // A container for holding stream data until a new line.
    this.chunks = "";
  }

  transform(chunk, controller) {
    // Append new chunks to existing chunks.
    this.chunks += chunk;
    // For each line breaks in chunks, send the parsed lines out.
    const lines = this.chunks.split("\r\n");
    this.chunks = lines.pop();
    lines.forEach((line) => controller.enqueue(line));
  }

  flush(controller) {
    // When the stream is closed, flush any remaining chunks out.
    controller.enqueue(this.chunks);
  }
}

async function setUpSerial() {
  noLoop();
  ({ port, reader, writer } = await getPort());
  serialActive = true;
  runSerial();
  loop();
}

async function runSerial() {
  try {
    while (true) {
      if (typeof readSerial === "undefined") {
        console.log("No readSerial() function found.");
        serialActive = false;
        break;
      } else {
        const { value, done } = await reader.read();
        if (done) {
          // Allow the serial port to be closed later.
          reader.releaseLock();
          break;
        }
        readSerial(value);
      }
    }
  } catch (e) {
    console.error(e);
  }
}

async function writeSerial(msg) {
  await writer.write(msg);
}

p5js SKETCH

gridSize = 5;
squareSize = 100;
colors = ['red', 'green', 'blue', 'yellow'];
grid = [];
sequence = [];
playerInput = [];
showingSequence = false;
showIndex = 0;
showTimer = 0;
inputEnabled = false;
currentRound = 1;
gameOver = false;
gameStarted = false;

serialMessage = '';
messageColor = 'black';
confetti = [];
startButton = null;
restartButton = null;

statusTimer = 0;
statusDuration = 2000;

roundStartTime = 0;
timeLimit = 10000;
timeLeft = timeLimit;

let bgMusic, correctSound, incorrectSound;

lives = 3;

function preload() { //loading the music
  soundFormats('mp3', 'wav');
  bgMusic = loadSound('music/background.mp3');
  correctSound = loadSound('music/correct.mp3');
  incorrectSound = loadSound('music/incorrect.mp3');
}

function setup() {
  createCanvas(gridSize * squareSize + 80, gridSize * squareSize + 60);
  noStroke();

  startButton = createButton('▶ Start Game');//start button
  styleButton(startButton, width / 2 - 60, height / 2 + 10, '#4CAF50');
  startButton.mousePressed(async () => {
    await setUpSerial();//using the start button to initiate serial comm
    startGame();
  });

  bgMusic.setLoop(true);
  bgMusic.play();// playing the background music throughout
}

function styleButton(btn, x, y, color) {// styling code function for all the buttons
  btn.position(x, y);
  btn.style('font-size', '20px');
  btn.style('padding', '10px 20px');
  btn.style('background-color', color);
  btn.style('color', 'white');
  btn.style('border', 'none');
  btn.style('border-radius', '8px');
}

function startGame() { //initializing the game
  gameStarted = true;
  startButton.remove();// moving from the start page to the grid
  initGrid();
  nextRound();
}


//game loop
function draw() {
  background(220);

  if (!gameStarted) {
    drawStartScreen(); 
    return;
  }

  if (gameOver) {
    drawEndScreen();
    return;
  }

  drawGrid();
  drawProgressBar();
  drawTimeBar();
  drawSidebar();

  if (showingSequence && millis() - showTimer > 800) {
    showTimer = millis();
    showIndex++;
    if (showIndex >= sequence.length) {
      showingSequence = false;
      inputEnabled = true;
      showIndex = 0;
      roundStartTime = millis();
    }
  }

  if (inputEnabled) {
    timeLeft = timeLimit - (millis() - roundStartTime);
    if (timeLeft <= 0) {
      handleIncorrect('Time Up!');
    }
  }

  clearSerialMessageIfDue();
}

function drawStartScreen() {
  drawBackgroundGradient();
  fill(30);
  textAlign(CENTER, CENTER);
  textFont('Helvetica');
  textSize(36);
  text(' Color Memory Game', width / 2, height / 2 - 80);
  textSize(20);
  text('Repeat the color sequence using the physical buttons!', width / 2, height / 2 - 40);
}


//---------------END SCREEN-------------------------------
function drawEndScreen() {
  drawBackgroundGradient();
  drawConfetti();
  drawGameOverArt();
  textAlign(CENTER, CENTER);
  fill('#2E8B57');
  textFont('Georgia');
  textSize(36);
  text('Game Over!', width / 2, height / 2 - 80);
  fill(50);
  textSize(16);
  text('Press the button to restart', width / 2, height / 2 - 40);
  if (!restartButton) {
    restartButton = createButton(' Restart');
    restartButton.id('restartBtn');
    styleButton(restartButton, width / 2 - 60, height / 2 + 20, '#f44336');
    restartButton.mousePressed(() => {
      restartButton.remove();
      restartButton = null;
      resetGame();
    });
  }
}

//--------------------BOTTOM BAR--------------------------
//Displaying the message
function updateSerialMessage(msg, color) {
  serialMessage = msg;
  messageColor = color;
  statusTimer = millis();
}
//Clearing the message
function clearSerialMessageIfDue() {
  if (millis() - statusTimer > statusDuration && serialMessage !== '') {
    serialMessage = '';
  }
}

//---------------------SIDE BAR---------------------------------
function drawSidebar() {
  let barWidth = 60;
  let barX = width - barWidth;
  fill(240);
  rect(barX, 0, barWidth, height);

  let progress = sequence.length / grid.length;//filling with the progress bar
  fill('#2196F3');
  rect(barX + 10, 20, 40, height * progress);

  textAlign(CENTER, CENTER);
  textSize(20);
  for (let i = 0; i < 3; i++) {
    let y = height - 40 - i * 30;
    fill(i < lives ? 'red' : 'lightgray');
    text(i < lives ? '❤️' : '', barX + barWidth / 2, y);// representing lives with red heart emojis
  }
}

// -------------------TIME BAR---------------------------------------
function drawTimeBar() {
  let barHeight = 10;
  let barY = height - 60;
  let progress = constrain(timeLeft / timeLimit, 0, 1); 

  fill(200);
  rect(0, barY, width - 80, barHeight);

  fill(progress < 0.3 ? '#F44336' : progress < 0.6 ? '#FFC107' : '#4CAF50');
  rect(0, barY, (width - 80) * progress, barHeight);///changing color depending in the time left
}


//-------------------PROGRESS BAR-----------------------------
function drawProgressBar() {
  let barHeight = 30;
  let barY = height - barHeight;
  let progress = sequence.length > 0 ? playerInput.length / sequence.length : 0;

  fill(200);
  rect(0, barY, width - 80, barHeight); // filling the bar proporionally to the progress

  fill(messageColor === 'green' ? '#4CAF50' : messageColor === 'red' ? '#F44336' : '#2196F3');
  rect(0, barY, (width - 80) * progress, barHeight);

  fill(255);
  textAlign(CENTER, CENTER);
  textSize(16);
  text(serialMessage, (width - 80) / 2, barY + barHeight / 2);
}

//-------------------GRID SET UP-------------------------------------
function drawGrid() {
  for (let i = 0; i < grid.length; i++) {
    let sq = grid[i];
    let x = sq.x;
    let y = sq.y;
// highlighting square by a black stroke and appending them to the sequence.
    if (showingSequence && i === sequence[showIndex]) {
      let sw = 6;
      strokeWeight(sw);
      stroke(0);
      let inset = sw / 2;
      fill(sq.color);
      rect(x + inset, y + inset, squareSize - sw, squareSize - sw);//fitting the stroke within the square
    } else {
      noStroke();
      fill(sq.color);
      rect(x, y, squareSize, squareSize);
    }
  }
  noStroke();
}

function initGrid() {
  grid = [];
  for (let row = 0; row < gridSize; row++) {
    for (let col = 0; col < gridSize; col++) {
      let availableColors = colors.slice();
      if (row > 0) { //avoiding the same colors being next to each other in a row
        let aboveColor = grid[(row - 1) * gridSize + col].color;
        availableColors = availableColors.filter(c => c !== aboveColor);
      }
      if (col > 0) {//avoiding the same colors being next to each other in a col
        let leftColor = grid[row * gridSize + (col - 1)].color;
        availableColors = availableColors.filter(c => c !== leftColor);
      }
      grid.push({ x: col * squareSize, y: row * squareSize, color: random(availableColors) });
    }
  }
}

//---------SERIAL COMMUNICATION MANAGEMENT----------------------------
function readSerial(data) {
  if (!inputEnabled || gameOver) return;
  let colorClicked = data.trim().split(',').pop().trim();//reading the serial port for the color pressed and printed out by arduino
  let expectedIndex = sequence[playerInput.length];
  let expectedColor = grid[expectedIndex].color;// checking if the colors match
  if (colorClicked === expectedColor) {
    playerInput.push(expectedIndex);
    correctSound.play();
    updateSerialMessage('Correct', 'green');//updating the message.
    if (playerInput.length === sequence.length) {
      inputEnabled = false;
      setTimeout(nextRound, 1000);
    }
  } else {
    handleIncorrect('Incorrect');
  }
}


// checking if the pattern by the player is incorrect
function handleIncorrect(message) {
  incorrectSound.play();
  updateSerialMessage(message, 'red');
  lives--;
  playerInput = [];
  inputEnabled = false;
  if (lives <= 0) { // they have no more lives end game
    gameOver = true;
    spawnConfetti();
  } else {
    setTimeout(replayRound, 1500);
  }
}


//playing the next round when the player gets it right
function nextRound() {
  currentRound++;
  playerInput = [];
  if (sequence.length >= grid.length) { //checking if all the squares have been matched
    gameOver = true;// end game if true
    spawnConfetti();
    return;
  }
  sequence.push(floor(random(grid.length)));// append one more random square if the game is not over
  showingSequence = true;
  showIndex = 0;
  showTimer = millis();
}
// Repeating the round when the player gets it wrong
function replayRound() {
  playerInput = [];
  showingSequence = true;
  showIndex = 0;
  showTimer = millis();
}

function drawBackgroundGradient() {
  for (let y = 0; y < height; y++) {
    let c = lerpColor(color(255), color(200, 220, 255), map(y, 0, height, 0, 1));
    stroke(c);
    line(0, y, width, y);
  }
}


//-----------------CONFETTI FOR GAME OVER------------------------------------
function spawnConfetti() {
  confetti = [];
  for (let i = 0; i < 100; i++) {
    confetti.push({
      x: random(width),
      y: random(-200, 0),
      speed: random(2, 5),
      size: random(5, 10),
      color: random(colors)
    });
  }
}


function drawConfetti() {
  for (let c of confetti) {
    fill(c.color);
    noStroke();
    ellipse(c.x, c.y, c.size);
    c.y += c.speed;
    if (c.y > height) {
      c.y = random(-100, 0);
      c.x = random(width);
    }
  }
}

function drawGameOverArt() {
  for (let i = 0; i < sequence.length; i++) {
    fill(grid[sequence[i]].color);
    ellipse(50 + (i % 10) * 25, 50 + floor(i / 10) * 25, 20);
  }
}

//-------------- RESETTING THE GAME------------------------------------------
function resetGame() {
  lives = 3;
  sequence = [];
  playerInput = [];
  showingSequence = false;
  showIndex = 0;
  inputEnabled = false;
  currentRound = 1;
  gameOver = false;
  timeLeft = timeLimit;
  serialMessage = '';
  messageColor = 'black';
  initGrid();
  nextRound();
}
Areas I am proud of and areas for future improvement

I am really proud about how the game graphics turned out. That is; buttons, score recording and representation, start page, game over page, restart logic, “lives” handling and the game progression loop. On the hardware arduino side, I was proud of the carpentry and design of the wooden platform that held the push-buttons.  However, I think there’s still more that could have been done on the aspect of aesthetics to make my projects more appealing and attractive. I also need to work on communicating instructions more effectively and intuitively. Also it was in my very initial idea to 3D print so that I can automate a robot following the progress of the game. I was limited however because of the high demand of the 3D printers. I hope to one day finish what I have started.

Week 13 – User Testing

People Experience

I had people try out my game without prior instruction. At first people did not understand how to play the game but eventually after two tries people got the hang of it. It was particularly challenging at first because of the push buttons that took really long to read data(must have been faulty). 

Upon getting the hang of it, I could see the excitement as the game is really challenging for the users and therefore very exciting.

Some of the areas of confusion came when the users did not read the basic instructions on the game flow but when they did it became all so easy to understand what is happening between the controls and the experience on the screen 

Effective aspects and areas to improve.

I am particularly proud of the fact that the game did not crash or have an unexpected breakdown. I am also proud that the communication was well mapped at most times between the arduino and p5js. I was able to channel all the data from randomly pressed push-buttons to p5js to match the sequence which I found just amazing. Also the synchronization between the arduino push-buttons and the p5js sounds made when the user gets it right was really challenging but when I got it done it was really fulfilling.

There are still some areas of improvement however. I noticed that after playing for a long time the game began to lag. This was indication that I needed a better way to map the data from arduino to p5js since as the game progressed data being mapped became more and more. Additionally, I needed to make the time more proportional to the number of colors expected to be matched by the player. I thought it would be a great challenge for the players but the limited time made it even more difficult(doable though). I could consider making the timing more lenient so as to have more people try to finish.

Areas the need to explain

Most people started the game without understanding the instructions. Most people thought that they were supposed to press the push-buttons immediately when the colors were displayed on the screen but that was not the case. I therefore had to explain to most people to wait for the sequence to completely finish before they could begin pressing the push buttons. I think to solve this problem for first timers playing the game, the best thing was to make the instructions more clear on the screen rather than printed out as I had planned.

Week 12 – Final Proposal and Progress

Finalized concept for the project;

Even though I was unsettled at first I finally decided to go with the color matching game where the user observes random color patterns on p5js and tries to match them by pressing the same sequence of colors on a set of push buttons embedded on a wooden platform. 

Communication between p5js and arduino;

The communication between p5js and arduino begins with a handshake which is initialized by the library we used in class – p5-web-serial(). The p5js generates random colors in increasing sequence and waits for response from the arduino. Arduino sends feedback in terms of the color that has been pressed if it is green for instance,… the  p5 reads the serial which has the color pressed in arduino printed out. If the color read matches with the expected color then p5js reads it as correct  and proceeds to the next round. If not, the p5js reads it as wrong and repeats the same sequence. For multiple colors in a long sequence the arduino prints out the colors pressed in an array that is matched against that which has been displayed in p5js. And the same logic of checking for correctness is repeated.

 Images of progress

Week 11- Final Project Preliminary Concept

Concept

For the final project I’ll be building a color memory game where the user sees colors generated at random by p5js and tries to match the colors by pressing arcade push buttons in the same order. And it gets tough as the game progresses. Every time the user gets it right a two-tiered trolley moves forward. The goal is to make the trolley/toy move as far as possible and close to the finish line within a short period of time.

Arduino and p5js

There will be serial communication between arduino and p5js in relaying the information concerning the color pressed (in arduino) against what has been displayed (on p5js) randomly. If there is a correct match between the two communication is sent back to the arduino to move the trolley forward. If not the p5js repeats the same pattern of colors previously displayed. There will also be a timer on the p5js screen to show the amount of time spent by the player.

Week 11 – Reading Response

DESIGN MEETS DISABILITY

This week’s reading was an eye-opener to the interconnectedness of design and disability. It actually got me thinking of some of the very great designs that I encounter often that are solely meant to aid with disability e.g glasses. This affirms the writer’s point that design  depends largely on constraints and that in so many ways disability inspires design. The reading also pointed out some nuanced details concerning disability designs. One, it is noted that a design should aim to enable while attracting minimal or no attention at all. The whole point of design in disability is to close the gap that is between disability and mainstream and therefore when a design attracts too much attention it is very likely to cause stigmatization that undermines the whole goal of the design. Nonetheless, the discretion is at the danger of sending out the message that disability is something to be ashamed of. Therefore to help strike a balance between discretion and attention the writer speaks of how fashion and medical designs have just done so. For instance, just like glasses have evolved from being disability designs to fashion designs, other medical designs should aim at seeking the perspective of the fashion designers and not be too focused on discretion. More confident and less discrete designs will help in promoting a positive image for disability. Also design for disability should aim for social inclusivity and reduced mediocrity in order to remove barriers that cause stigmatization. Additionally, with reference to James Lecker who manufactures furniture for children with cerebral palsy. He states that a furniture design needs to be so complicated such that it intimidates children and their friends therefore beating the whole point of social integration.

Week 10 – Reading Response

THE FUTURE OF INTERACTION DESIGN

A very timely article especially with the current pace of technological advancement. I totally agree with Bret Victor that interaction finds its truest meaning when the capabilities of human beings are amplified through the tools/invention used to make work easier. These tools are meant to make work easier and not to do away with it altogether. I think with the growing technological development drawing a line between increasing efficiency and reducing tactility is becoming harder by the day. Interaction at least as I know it has to involve meaning back and forth engagement between the tool and the user. Therefore designers should refrain from “doing everything” for the user in the name of increasing efficiency but like Bret has committed to his readers they should start thinking about how to increase the interaction experience of the users and making them become more aware of their capabilities in an efficient way and not the opposite. As Bret puts it in his follow up article; we need to aim for “dynamic mediums that we can see, feel, and manipulate”

 

Week 9 – Reading Response

Physical Computing’s Greatest Hits (and misses)

I used to believe that something could only be considered unique if it was entirely new or never seen before. That made me overlook the value of familiarity. But now, I’ve come to understand that familiarity isn’t a limitation—it can actually deepen meaning and make an idea more impactful. From reading about the musical instrument examples and others too, I realized how something as common as an instrument can still be a powerful space for creativity and interaction. It showed me how familiar forms can be reimagined in playful, thoughtful ways. This has shifted how I think about uniqueness, and I’m now considering using the concept of a musical instrument as inspiration for my final project—not because it’s entirely new, but because it holds potential for creative reinterpretation.

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

This was such an eye-opening and exciting read—it completely shifted how I view and approach interactive art and media. Before engaging with the article, I believed it was essential not only to guide the audience on how to interact with my work but also to explain how they should feel while doing so. I struggled with finding the boundary between offering direction and allowing personal interpretation. Now, I understand that interactive art is less about delivering a fixed message and more about creating an open-ended environment—one that invites the audience to explore, interpret, and respond in their own unique way. It’s not about scripting every possible outcome but rather about designing the space, the elements, and the cues in a way that encourages genuine engagement and discovery. Going forward, I aim to embrace this approach in my future projects. I want to focus more on creating spaces that speak for themselves—spaces that offer intuitive cues, invite interaction, and allow viewers to craft their own interpretations. I’m excited to stop over-explaining and start listening more, letting the dialogue between artwork and audience unfold naturally.

 

Week 9 – Traffic(Lights) Sounds

Concept

For my project, I developed a traffic light system that uses sound to provide directions. This solution addresses the challenge pedestrians face in reading traffic lights during the day, particularly when sunlight makes the signals hard to see. The system uses an LDR (Light Dependent Resistor) to detect light levels above a certain threshold, activating a buzzer that beeps twice for “go” (green) and once for “stop” (red). This feature helps pedestrians who may struggle to see the traffic lights in bright sunlight. At night, when the lights are easily visible, the buzzer remains off, reducing unnecessary noise.

Implementation

The project uses the following components: 6 LEDs, an LDR, a buzzer, resistors, wires, and a switch. The switch is particularly useful for stopping and resetting the system. The buzzer is triggered when specific LEDs are on, and the LDR reading exceeds a set threshold. The LEDs are divided into two groups: one for pedestrian signals and the other for vehicle signals. The buzzer sound is dependent on the pedestrian signal’s color: it beeps twice when the light is green and once when it is red.

Images and sketch

Code Highlights

I’m particularly proud of how I managed the buzzer’s beeping pattern using functions, classes, and conditional statements. Below are some key snippets of the code. 

void beepOnce(int note, int duration) {
  tone(buzzer, note, duration);   // Play the note on the buzzer
  delay(duration + 50);           // Wait for the note to finish
  noTone(buzzer);                 // Stop the sound
}

void beepTwice(int note, int duration) {
  tone(buzzer, note, duration);   // Play the note on the buzzer
  delay(duration + 50);           // Wait for the note to finish
  noTone(buzzer);                 // Stop the sound
  delay(100);                     // Short delay before second beep
  tone(buzzer, note, duration);   // Play the note again
  delay(duration + 50);           // Wait for the note to finish
  noTone(buzzer);                 // Stop the sound
 
ldr_value = analogRead(ldrpin); // Read the LDR sensor value
  if (ldr_value > 600) {  // Only beep if LDR value is greater than 600
    beepTwice(NOTE_E4, 300);  // Beep twice when Side 1 is Green
  }
 
ldr_value = analogRead(ldrpin); // Read the LDR sensor value
  if (ldr_value > 600) {  // Only beep if LDR value is greater than 600
    beepOnce(NOTE_C4, 300);  // Beep once when Side 1 is Red and Side 2 is Yellow
  }

 

Additionally, I learned how to define musical notes in Arduino, and I believe this will be useful in future projects.

const int NOTE_C4 = 261;   
const int NOTE_E4 = 330;     

Challenges and Future Improvements

I faced challenges in synchronizing the color patterns of the traffic lights, but after some time and effort, I was able to get it right. Moving forward, I plan to deepen my understanding of buzzer functionalities and work on streamlining and optimizing my code.

Demonstration

video

Week 8 – Unusual Switch

When thinking of an unusual switch, I looked for something that is less used in the kit and unconventional. I chose to explore how I can use the temperature sensor creatively as a switch. When thinking of the same, I realized most air conditioning units require manual input which may be an inconvenience to people who have specific and fixed room temperature requirements. I therefore decided to create a program that can be preset so that the AC unit can adjust automatically as it has been configured. For the MVP I had one LED light to show the change in temperature such that it lit when the temperatures went above a certain threshold and went off when the temperatures reduced below a certain level. I later added two more LED lights so that together with the three led lights could show the signal when the temperature was within certain ranges. Why is this important? This program could be modified and connected to a thermostat so that instead of only turning the A/C on and off, one could set it to self-modify the temperatures when the room temperature is at a certain level without necessarily changing it manually.

CODE HIGHLIGHTS

The only part that was slightly challenging was converting the reading from the TMP36 to voltage and later on to degrees celsius. I realized that the TMP36 sensor has a linear output of 10mV per °C, with an offset of 500mV at 0°C. And therefore to convert to volts and degrees I used the following block of code;

void loop() {
  reading = analogRead(A0);  // read analog pin
  volts = reading * aref_voltage / 1023.0; // convert to voltage
  millivolts = 1000 * volts; // convert to millivolts
  degreesC = (millivolts - 500)/10;  // convert to deg C
  degreesF = (degreesC * 9/5) + 32;  // convert to deg F

 

IMAGES AND DEMO

REFLECTIONS AND FUTURE IMPROVEMENTS

Using the temperature sensors was fun but as the Professor noted in one of the classes it can be a boring tool in the sense that it takes long to actually test it’s efficacy owing to the rigidity of the independent variable – temperature. Going forward I’d love to make projects that are more user friendly and more interactive that is; makes more use of the physical things around us. Also, I definitely will be exploring the other items in the toolkit even more.

Demonstration Video

To analyze the thermal response of the circuit, I positioned it near the heat emission area of my laptop, then incrementally increased the distance to observe variations in temperature effect

Demonstration

 

Week 8 – Reading Response

Attractive things work better.

I loved the article as it speaks on something very relatable and significant in the Design world and that is the intersection of design and beauty. I never really gave it much thought but after reading the article I now see this evident in my life too and that of friends around me. I appreciate how Norman categorised how affect impacts design and behaviour. In terms of behaviour, he explains how affect regulates how well we can solve problems and perform tasks. For instance, I find myself more motivated to handwrite when I have an aesthetically pleasing pen or pencil and the opposite is also true. In terms of design, affect impacts how easy it is to learn how to use an item. My takeaway from the reading is that designers should strive to strike a balance between optimum usability and also the appealing nature of their designs. 

Her code got humans on the moon

Such an amazing piece of writing highlighting the outstanding contribution of Margaret Hamilton in the development of software Engineering. There are so many lessons to learn from this writing but what stood out to me is the passion and sheer determination of Hamilton to push beyond the ordinary and uncover the complex technological milestones with so many odds stacked against her. I found it inspiring how she paid keen attention to the possible crash of code and was ready to solve it despite the skepticism she received from NASA. Had she not been that assertive, who knows what would have happened to the space explorers. On a broader scale I appreciate how the Apollo space program revolutionized both computing history and space exploration.So many insights to take on in life from the reading —encouraging me to push boundaries, embrace innovation, and persevere through challenges in any field.