Final Project Documentation

Catch the horse: In Action

Schematic:

Circuit Design

The circuit design includes:

  • Inputs:
    • Buttons for Jump, Rock, Bird, and Choice.
    • Ultrasonic sensor for crouching detection.
  • Outputs:
    • Servo motor for mechanical horse movement.

Circuit Setup:

Concept: 

“Catch the Horse” is an interactive, physically engaging game that combines a physical mechanical horse with a virtual environment. The game revolves around a man running after a horse, dodging obstacles, and strategising to catch the runaway animal. Using Arduino for hardware control and p5.js for the game logic, the project merges physical and digital interactivity in a seamless experience.

The game is designed for a single player or multiplayer to interact with both the physical and digital world, utilising buttons, sensors, and a motor to create a truly immersive gameplay environment.

Implementation Overview

The implementation is divided into two main components:

  1. Hardware (Arduino): Controls the physical setup, including buttons for gameplay interactions, an ultrasonic sensor for crouching detection, and a motor for the mechanical horse.
  2. Software (p5.js): Manages the game logic, animations, audio feedback, and communication with the Arduino.

Interaction Design

The player interacts with the game through a combination of physical actions and button presses:

  • Jump Button: Press to make the man jump over obstacles like rocks.
  • Rock Button: Press to launch rocks as obstacles for the man.
  • Bird Button: Press to release birds, which the man must dodge.
  • Lasso Button (Choice Button): Triggers a Choice Screen where the player selects between Skill and Luck to catch the horse.
  • Crouching: The ultrasonic sensor detects when the player crouches to avoid fences.

The game starts with a running man chasing a horse. Players must navigate these challenges to achieve victory. Victory conditions include successfully throwing the lasso and either rolling a winning dice number (Luck) or capturing the horse via a precise throw (Skill).

Arduino Code

The Arduino code serves as the bridge between the physical components and the digital game. Key features include:

  • Button Mapping: Jump, Rock, Bird, and Choice buttons are connected to Arduino pins, triggering serial communication to p5.js.
  • Ultrasonic Sensor Integration: Detects crouching and sends the signal to the game.
  • Motor Control: Starts and stops the physical horse motor based on game states.

The final Arduino sketch was robust and efficient, thanks to iterative improvements. One notable challenge was integrating the button connected to pin 5 (Choice Button) to handle multiple game states effectively. Solving this required careful adjustments to both Arduino and p5.js logic.

p5.js Code

The p5.js script handles the game logic, animations, and audio. Key highlights include:

  • Game States: Playing, Choice Screen, Game Over, and Game Won states dynamically adjust gameplay.
  • Animations: The running man and birds are controlled via sprite animations, providing a polished visual experience.
  • Audio Integration: Background music tracks play during specific game states (ninja.mp3 during Playing and horse.mp3 during Game Won), enhancing immersion.
  • Obstacle Logic: Rocks and birds have cooldowns to maintain game balance.

The most challenging part was ensuring smooth communication between the Arduino and p5.js. For example, handling simultaneous button presses and sensor inputs required careful synchronisation to avoid bugs.

You can try the game here:

 

Final Project – Blue Lovable Utilitarian Reading Buddy (BLURB)

Inspiration

For all my assignments so far, I’ve tried to do something that’s personal and meaningful to me in some way, and this project is no different. My favorite hobby, without a doubt, is reading—it’s something I’ve loved for as long as I can remember. So, when I started brainstorming for this project, I decided I wanted to create something that revolves around the joy of books and the experience of reading as a whole.

Now, of course I’ve always thought there was something magical about getting lost in a story and exploring new worlds through words. But as much as I love reading, it can sometimes feel like a solitary experience, especially when I come across a thought or idea I want to share but no one’s around to talk to. That’s what inspired me to create a book buddy robot—something that could bring a sense of companionship to reading, making it feel a little less lonely while still keeping the focus on the stories I love so much.

Concept

The concept behind my book buddy robot, BLURB, is to create a small, interactive companion that enhances your reading experience. Made using p5.js and Arduino, BLURB is designed to be there with you as you dive into a good book, offering a few fun features along the way.

  • Flip Pages (Arduino): Using Arduino, BLURB has the ability to automatically flip the pages of your book. Whether you’re reading a physical book or using a digital device, BLURB page-flipping function helps keep the flow going without having to pause and turn the page yourself. It gives the feeling of having a personal assistant to handle the mundane task, allowing you to stay immersed in your story.
  • Play Ambient Music (p5.js): BLURB uses p5.js to play soft, ambient music tailored to enhance your reading experience. Whether it’s a gentle instrumental tune or nature sounds, the music helps set the atmosphere, making it easier to focus and get lost in your book. You can choose different genres or moods depending on the type of book you’re reading, helping you stay engaged and relaxed.
  • Track Reading Time (p5.js): With p5.js, BLURB can track how much time you’ve spent reading, giving you a sense of accomplishment as you progress through your book. It can display a timer on the screen, helping you set reading goals or simply monitor how long you’ve been immersed in the story. It’s a subtle way to keep track of time without taking away from the reading experience.
  • Give Break Suggestions (p5.js): Sometimes, reading for too long can leave you feeling drained. When you take a break, BLURB suggests helpful activities that could refresh your mind. These suggestions might include stretching, taking a short walk, drinking water, or even reading a motivational quote. It’s a fun way to make sure you’re taking care of yourself while you dive into your books.
  • Display Messages (Arduino): BLURB features an LCD screen powered by Arduino that displays small, personalized messages. These messages could tell you when BLURB says “Hello” and also display whether you’re currently reading or on break. The idea is to add a little more interaction to the reading process, keeping you engaged and providing a sense of companionship while reading.
  • Move Head (Arduino): BLURB’s head movement is controlled by Arduino, reacting to your actions. When you take a break, BLURB will slowly move its head side to side, to acknowledge your interaction.. When you start reading again, its head will return to a forward position, creating another cute and dynamic interaction. It’s a fun way to make BLURB feel more like a real companion that’s in tune with your reading habits.
  • Light Up Reading Lamp (Arduino): BLURB has a small reading lamp that can be activated by tapping its foot. This feature, powered by Arduino, adds a practical element to your reading experience. When the lights are dim or you need a little extra light, a simple tap on BLURB’s foot will turn on the lamp, giving you the perfect amount of illumination to read comfortably. It’s a cute, functional addition that makes BLURB more than just a robot—it’s a true reading companion.

Final Project; Pengu Pounce

Pengu Pounce — IT’S OVER!

I am ECSTATIC to say that I am finally done with this project! It has certainly been a dynamic experience.

As I had proposed, I thought of incorporating one of my favorite things ever into my final project –  my love for penguins. Therefore, I decided to create a fun little game where a Penguin called Pengu, has to jump over platforms — inspired by the Doodle Jump game. 

A lot has changed since my previous User Proposal, as my idea now is fully fleshed out/ In terms of the game itself, the primary objective is for Pengu to hop on different platforms till the timer ends — the person is supposed to last sixty seconds in the game. If the penguin falls off – then they lose.

In terms of the physical implementation, this game has four buttons: Restart, Left, Right, and Jump. 

There are several challenges I faced, most of them mainly to do with the game itself rather than the arduino.

For example, I was struggling with generating the actual platforms for the penguin to jump on. After I added the special ‘disappear’ platforms, it felt like the screen was being overcrowded. In addition, sometimes, the penguin would start on a disappear platform and therefore lose the game immediately,  so I decided on a set of three  normal platforms for the penguin to jump on at the start of the game. 

I also had struggled with making the platforms disappear once the penguin moved up, and ,make new ones appear. However, my friend had taught me about a handy concat built in function and filter, and as well as the spread operator, which I actually ended up finding useful and using it here now.

<iframe src=”https://editor.p5js.org/zv2029/full/otoQ9nLsh”></iframe>

Here is a link my complete p5.js sketch: https://editor.p5js.org/zv2029/sketches/otoQ9nLsh

Here is my code for the Arduino IDE that I used: 

 

const int jumpButtonPin = 10; // Button for jump
const int leftButtonPin = 13; // Button for move left
const int rightButtonPin = 4; // Button for move right
const int restartButtonPin = 2; // Button for restart

void setup() {
  pinMode(jumpButtonPin, INPUT_PULLUP);
  pinMode(leftButtonPin, INPUT_PULLUP);
  pinMode(rightButtonPin, INPUT_PULLUP);
  pinMode(restartButtonPin, INPUT_PULLUP); 
  Serial.begin(9600);
}

void loop() {
  // Read button states
  int jumpState = digitalRead(jumpButtonPin);
  int leftState = digitalRead(leftButtonPin);
  int rightState = digitalRead(rightButtonPin);
  int restartState = digitalRead(restartButtonPin);


  if (jumpState == LOW) {
    Serial.println("JUMP");
  } else if (leftState == LOW) {
    Serial.println("LEFT");
  } else if (rightState == LOW) {
    Serial.println("RIGHT");
  } else if (restartState == LOW) {
    Serial.println("RESTART");
  } else {
    Serial.println("IDLE"); 
  }

}

Here is a video of the game being played:

 

Assignment 10: Testing Phase

Title: Testing Phase of “Catch the Horse” – Insights and Improvements

With the development of “Catch the Horse” completed, I conducted user testing to evaluate the intuitiveness, playability, and overall experience of the game. The goal of this phase was to observe how players interacted with the game, identify areas where they struggled, and determine how the gameplay mechanics could be made more intuitive and accessible.

User Testing Overview

During testing, participants were asked to engage with the game without receiving any prior instructions or guidance. The goal was to simulate the experience of a first-time player encountering the game. I recorded their interactions and noted points of confusion, questions they asked, and their overall feedback.

Observations and Findings

  1. What Users Figured Out on Their Own
    • Jump, Bird, and Rock Buttons:
      Players intuitively understood the jump mechanic and the functions of the bird and rock buttons. These actions had immediate visual feedback (e.g., the cowboy jumped, birds appeared, or rocks were thrown), which made the controls feel natural and responsive.
  2. What Needed Explanation
    • Lasso Button (Choice Button):
      Players struggled to understand how the lasso button worked. I had to explain that pressing the lasso button initiated the “Choice Screen” and that they could select between Skill or Luck to catch the horse.

      • Skill vs. Luck:
        The difference between the Skill and Luck options was unclear without explanation. Participants were unsure why they would choose one option over the other.
  • Interaction with Rocks and Birds:
    Although players understood how to use the rock and bird buttons, they were initially confused about how the cowboy was supposed to interact with these obstacles. For example, they weren’t sure if the rocks could be dodged or destroyed and if the birds required a specific action to avoid.

    What Worked Well

  • Physical Integration:
    The physical crouching mechanic, detected by the ultrasonic sensor, added an engaging and immersive element to the game. Users enjoyed the novelty of having to physically move to interact with the game.
  • Visual Feedback:
    Immediate visual feedback for the jump, bird, and rock mechanics allowed players to quickly understand these actions without explanation.
  • Game Flow and Balance:
    Cooldowns for the horse’s abilities (mud, fences, and booster) were well-received, as they maintained a fair and balanced gameplay experience.

    Lessons Learned

    • Mapping Between Controls and Gameplay:
      Intuitive mapping between controls and gameplay actions is critical. For example, the jump button and crouching were easy to grasp because the controls directly mirrored the in-game actions. However, abstract mechanics like the lasso required additional explanation due to their more complex interactions.
    • The Importance of Feedback:
      Immediate feedback helped players connect their actions to in-game effects. Enhancing feedback for less intuitive mechanics (like the lasso) will likely make the game easier to pick up.
    • Balancing Physical and Digital Gameplay:
      Players found the integration of physical actions (like crouching) and digital gameplay highly engaging. This balance between physical and virtual interaction should remain a cornerstone of the game’s design.

      Next Steps

      1. Add an Instructions Page or Tutorial:
        Include a brief tutorial or instructions page at the beginning of the game to explain the mechanics of the lasso button, Skill vs. Luck, and how to interact with obstacles like birds and rocks.
      2. Enhance In-Game Prompts:
        Add dynamic text prompts or animations during gameplay to guide players through challenging mechanics. For example:

        1. “Press J to Jump Over Rocks!”
        2. “Dodge Birds to Avoid Game Over!”

    Demonstration

Pingu Pounce — User Testing

I have made significant progress with my work, and have come close to a finish. For my project, a game called Pingu Pounce, I’ve decided to add physical controls to make the overall experience much more enjoyable and interactive.

I have used 4 buttons — A restart, left, right, and jump button.

Here I have attached a video of a classmate playing with my game and I received some overall feedback. This is not the final version of my project as I have many improvements left to do – namely implementing my buttons in a much more accessible way.

Over the remaining days, I will work on how to make my game more intuitive without me having to explain the instructions too much — perhaps I will add labels to my buttons to do so. 

IMG_8879

Reading Reflection 8

Reuse and Recycle: A reflection on Design Meets Disability

In Design Meets Disability, the idea of trickle-down effects made a lot of sense to me. The tech market’s priorities often align with majority demand, leaving designs for the disabled marginalized in terms of research and funding. Sectors like fashion or mass-market tech get the lion’s share of attention, while solutions for disabilities often lack the investment they deserve.

However, the book highlights a crucial skill for designers: recognizing the applicability of existing technology to new problems. While creating something original is commendable, repurposing an established design can be equally impactful. Legal hurdles, like patents, may limit financial gains from such adaptations, but progress shouldn’t be confined by a competitive or profit-driven mindset. True innovation lies in recognizing the value of existing tools to accelerate development and as designers or artists, we have the benefit of the sky being the limit to our creativity. Thus, repurposing existing technology is never frowned over by our kind as artists have the ability to bring their own touch to any project.

Assignment 9: Final project Proposal

Title: Catch the Horse
Mechanical Horse.mp4 – Google Drive

Concept:

“Catch the Horse” is an interactive two-player game that blends physical and virtual gameplay to create an engaging experience. A physical mechanical horse and a digital cowboy chase are brought to life through Arduino and p5.js integration. The game revolves around strategy, reflexes, and decision-making, where one player controls a cowboy trying to catch a runaway horse, while the other player actively defends the horse using tools like mud, fences, and boosters. With immersive elements like crouching to dodge obstacles and precise timing challenges to throw a lasso, the game offers an interactive and entertaining experience.

Overview:

In “Catch the Horse,” a virtual horse escapes its stable and leaves the screen, triggering a motor that animates a physical mechanical horse placed beside the monitor. The cowboy avatar must chase after the horse, dodging obstacles and using a lasso to attempt capture. The horse player can make the chase challenging with mud, fences, and boosters, while the cowboy must rely on strategic decision-making and skill to win.

Gameplay Mechanics

The Cowboy’s Role (Player 1)

  • Chasing the Horse:
    • The cowboy avatar moves left and right using a joystick to dodge mud and other obstacles.
    • Physical crouching (detected by an ultrasonic sensor) is required to avoid fences thrown by the horse player.
    • At set intervals, the cowboy can attempt to throw a lasso to capture the horse or a bag of treats.
  • Lasso Mechanic:
    The cowboy has two options when throwing the lasso:

    1. Catch the Horse (Luck-Based):
      • A meter appears with an oscillating needle that moves slower, making it easier to time the throw.
      • If successful, the player rolls a virtual dice. A roll of 5 or 6 captures the horse; otherwise, the chase continues.
    2. Catch the Treats (Skill-Based):
      • The meter’s needle oscillates faster, requiring greater precision to time the throw.
      • Success guarantees the bag of treats, which stops the horse and ensures a win.
      • Failure results in no capture, and the chase continues. Speedometer meter with arrow for dashboard. - Vector. 30715312 Vector ...

The Horse’s Role (Player 2)

  • The horse player uses three buttons to evade capture:
    1. Mud Throw: Throws mud obstacles that the cowboy must dodge with the joystick.
    2. Fence Throw: Launches fences that the cowboy must crouch to avoid.
    3. Booster: Temporarily speeds up the horse, preventing the cowboy from throwing a lasso.
  • All buttons have cooldown periods to maintain fairness and balance. Robot Unicorn Attack 2 (Gameplay) Android / iOS - YouTube

Challenges and Solutions

  1. Mechanical Horse Durability:
    • The motor runs at a controlled speed to prevent stress on the fragile body.
  2. Button Cooldowns and Fairness:
    • Cooldown timers for the horse player’s buttons ensure balanced gameplay.
  3. Accurate Crouch Detection:
    • Calibrate the ultrasonic sensor to detect movement precisely while avoiding false triggers.

Winning Conditions

  • The cowboy wins if they:
    • Successfully throw the lasso and roll a 5 or 6.
    • Successfully capture the bag of treats.
  • The horse wins if:
    • The cowboy fails all lasso attempts, or the timer runs out.

 

WEEK 11 – EXCERSISE(WORKED WITH AMNA)

EXCERCISE 1: ARDUINO TO P5.JS COMMUNICATION

RESULT:

TASK 1 VIDEO

P5 CODE:

let sensorValue = 0; // Variable to store sensor data
function setup() {
  createCanvas(640, 480);
  textSize(18);
  if (!serialActive) {
    setUpSerial(); // Start serial communication with Arduino
  }
}
function draw() {
  // Set the background to dark blue and purple hues based on the sensor value
  background(map(sensorValue, 0, 1023, 50, 75), 0, map(sensorValue, 0, 1023, 100, 150));
  // Map the sensor value to control the ellipse's horizontal position
  let ellipseX = map(sensorValue, 0, 1023, 0, width);
  // Draw the ellipse in the middle of the screen
  fill(255); // White ellipse for contrast
  ellipse(ellipseX, height / 2, 50, 50);
  // Display connection status
  fill(255); // White text for readability
  if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    text("Connected", 20, 30);
    // Display the current sensor value
    text("Sensor Value = " + str(sensorValue), 20, 50);
  }
}
function keyPressed() {
  if (key === " ") {
    setUpSerial(); // Start the serial connection when the spacebar is pressed
  }
}
// This function is called by the web-serial library with each new line of data
function readSerial(data) {
  if (data != null) {
    // Parse the sensor value from the Arduino
    sensorValue = int(trim(data));
  }
}

ARDUIN CODE:

int sensorPin = A0; // Sensor connected to A0

void setup() {
  Serial.begin(9600); // Start serial communication
}

void loop() {
  int sensorValue = analogRead(sensorPin); // Read sensor value
  Serial.println(sensorValue); // Send the value to p5.js
  delay(10); // Small delay to avoid overwhelming the serial buffer
}

EXCERCISE 2: P5 TO ARDUINO COMMUNICATION

RESULT:

TASK 2 VIDEO

P5 CODE:

let brightness = 0; // Brightness value to send to Arduino

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

  // Check if serial is active and set it up if not
  if (!serialActive) {
    setUpSerial(); // Initialize serial communication
  }
}

function draw() {
  background(30); // Dark background
  fill(255); // White text
  text("Use the UP and DOWN arrows to control LED brightness", 20, 30);

  // Display the current brightness value
  text("Brightness: " + brightness, 20, 60);
}

function keyPressed() {
  if (keyCode === UP_ARROW) {
    // Increase brightness
    brightness = min(brightness + 10, 255); // Max brightness is 255
    sendBrightness();
  } else if (keyCode === DOWN_ARROW) {
    // Decrease brightness
    brightness = max(brightness - 10, 0); // Min brightness is 0
    sendBrightness();
  } else if (key === " ") {
    // Start serial connection when spacebar is pressed
    setUpSerial();
  }
}

function sendBrightness() {
  if (writer) {
    // Send the brightness value to Arduino
    writer.write(brightness + "\n");
  } else {
    console.error("Writer is not available. Please connect to the serial port.");
  }
}

ARDUINO CODE:

int ledPin = 9; // LED connected to PWM pin 9
int brightness = 0; // Variable to store brightness value from p5.js

void setup() {
  Serial.begin(9600); // Start serial communication
  pinMode(ledPin, OUTPUT); // Set LED pin as an output
}

void loop() {
  // Check if data is available to read
  if (Serial.available() > 0) {
    // Read the brightness value sent from p5.js
    brightness = Serial.parseInt();

    // Constrain the brightness value to 0-255
    brightness = constrain(brightness, 0, 255);

    // Set the LED brightness
    analogWrite(ledPin, brightness);
  }
}

EXCERCISE 3: BI-DIRECTIONAL COMMUNICATION

RESULT:
TASK 3 VIDEO

P5 CODE:

let velocity;
let gravity;
let position;
let acceleration;
let wind;
let drag = 0.99;
let mass = 50;
let sensorValue = 0; // Variable to store wind value from Arduino
let windStrength = 0; // Wind force determined by the sensor

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);
  wind = createVector(0, 0);

  // Initialize serial communication
  if (!serialActive) {
    setUpSerial();
  }
}

function draw() {
  background(255);

  // Apply gravity
  applyForce(gravity);

  // Apply wind (continuously updated from sensor)
  wind.x = map(sensorValue, 0, 1023, -2, 2); // Map sensor value to a stronger wind range
  applyForce(wind);

  // Update position and velocity
  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);

  // Draw the ball
  ellipse(position.x, position.y, mass, mass);

  // Check for bounce
  if (position.y > height - mass / 2) {
    velocity.y *= -0.9; // A little dampening when hitting the bottom
    position.y = height - mass / 2;

    // Notify Arduino about the bounce
    sendBounce();
  }
}

function applyForce(force) {
  // Newton's 2nd law: F = M * A
  let f = p5.Vector.div(force, mass);
  acceleration.add(f);
}

// Notify Arduino when the ball bounces
function sendBounce() {
  if (writer) {
    writer.write('1\n'); // Send the bounce signal
  }
}

// Read wind control value from Arduino
function readSerial(data) {
  if (data != null) {
    // Parse the sensor value directly into a variable for wind force
    sensorValue = int(trim(data));
  }
}

// Handle serial setup (using the serial.js file)
function keyPressed() {
  if (key === " ") {
    setUpSerial();
  }
}

ARDUINO CODE:

const int ledPin = 9;      // LED connected to pin 9
const int sensorPin = A0;  // Analog sensor for wind control
int sensorValue = 0;       // Variable to store sensor value from analog pin

void setup() {
  Serial.begin(9600);  // Start serial communication
  pinMode(ledPin, OUTPUT);  // Set LED pin as output
}

void loop() {
  // Read the sensor value and send it to p5.js
  sensorValue = analogRead(sensorPin);
  Serial.println(sensorValue);

  // Check if a bounce signal is received
  if (Serial.available() > 0) {
    char command = Serial.read();
    if (command == '1') {
      // Turn on the LED
      digitalWrite(ledPin, HIGH);
      delay(100);  // Keep the LED on briefly
      digitalWrite(ledPin, LOW);  // Turn off the LED
    }
  }
}

 

WEEK 11 READING

In my opinion, this reading challenges the idea that design for disability should only focus on solving problems. The prosthetic designs by Aimee Mullins show that disability can spark bold and exciting ideas, not just practical solutions. I think this mindset is what’s missing in most assistive designs today. Why settle for blending in when design can help people stand out and feel empowered? Similarly, the trend of customizing prosthetic eyes with unique designs—like intricate patterns or bold colors—proves that assistive devices can be about self-expression. These designs don’t try to look like a “normal” eye; instead, they let people proudly showcase their personalities. This is exactly the kind of creativity the design world needs.

The reading also points out a major flaw in how we think about inclusivity in design. Universal design sounds great in theory, but trying to make one product fit everyone often dilutes its purpose. For example, overly adjustable furniture for kids with disabilities can end up alienating them instead of including them. Instead of trying to be “one size fits all,” designers should focus on creating multiple, simple solutions that truly meet the needs of different individuals. This isn’t about making disability invisible—it’s about making design human and the diversity that comes with it.

Assignment 8: In class Exercises (Serial Communication)

Exercise 1 – Moving Ellipse

Prompt: Make something that uses only one sensor on Arduino and makes the ellipse in p5 move on the horizontal axis, in the middle of the screen, and nothing on Arduino is controlled by p5.
Arduino Code
Demonstration:

Exercise 2 – LED Brightness

Prompt: Make something that controls the LED brightness from p5

Arduino Code

P5.js Sketch

Demonstration:

Exercise 3 – Bouncing Ball

Prompt: Take the gravity wind example (https://editor.p5js.org/aaronsherwood/sketches/I7iQrNCul) and make it so every time the ball bounces one led lights up and then turns off, and you can control the wind from one analog sensor

Arduino Code

P5.js Sketch

Demonstration: