Final Project Documentation

Concept
My final project is an interactive robot game where players try to guide a small “student robot” toward its destination inside Monster Academy. The robot has to navigate through an obstacle course with different paths and challenges, and the players must control it carefully to avoid stepping on the lose sensor. If they reach the final pressure pad, the second sensor detects it and triggers a win. The idea was to merge a physical robot with a digital game interface so the whole experience feels like playing a simple video game, but happening in real life.

Process Overview

Hardware
For the hardware stage, I used the SparkFun Inventor’s Kit and followed the tutorial for building a basic remote-controlled robot. The guide helped me wire the motor driver, connect both motors, and set up the power system. After getting the robot moving reliably, I added two FSR sensors: one placed under an obstacle point to detect a “lose” event, and another placed at the end of the track to detect “win.” Both sensors were connected as voltage dividers so that the Arduino could measure changes in pressure using analog inputs.

I also built a large obstacle course from scratch. It was 100 by 80 centimeters, made using three big wooden boards and different colored papers to mark areas for obstacles, safe paths, and start/finish points. This part took a lot of testing, measuring, and redesigning because the robot moves differently depending on surface friction and layout.

Software
The software had two separate components: Arduino code and p5.js code. Arduino handles all the physical behavior of the robot, such as driving the motors forward, backward, left, and right through an H-bridge motor driver. It also reads the two sensors and sends signals back to the computer when the robot wins or loses.

The p5.js side handles the player interface. I created multiple screens: Start, Instructions, Control/Connect, Win, and Lose screens. Each screen appears at the right moment depending on the game flow. When the player presses a button or arrow key, p5.js sends a single-character command over the Web Serial API to the Arduino. The interface also includes a timer and localStorage functionality that saves the best time under the key robotRunner_bestTime.

Interaction Design
During user testing, something interesting happened. Even though I placed on-screen buttons, almost everyone naturally pressed the arrow keys on the laptop. Because of that, I decided to add full arrow-key support for moving the robot. This made the whole experience more intuitive and closer to traditional games. I also made the interface responsive so it adjusts when players press F to go full screen. The Start page transitions into the Instructions, and then the Control page appears, which is where the real-time serial communication and gameplay happens.

Circuit Schematic

Arduino Code and How It Works
In the Arduino sketch, I set up motor control using digital pins for direction and PWM pins for speed. Each movement command, such as forward or left, runs the motors for a short pulse of time and then stops them. This makes movement more precise and prevents the robot from overshooting.

The two FSR sensors are read using analogRead on A0 and A1. Each one has a threshold value. When the reading passes that threshold, the Arduino prints either “BUMP” or “WIN” to the serial port. The p5.js program waits for these exact messages. Getting this communication stable was challenging at first because the sensor values changed based on pressure and surface, so I had to adjust thresholds multiple times.

I also improved motor speed values so the robot had a more controlled movement. I had issues where the motors were too weak when powered only through USB, so switching to the battery pack was necessary.

// REMOTE ROBOT — p5.js CONTROL

// Right motor pins
const int AIN1 = 13;
const int AIN2 = 12;
const int PWMA = 11;

// Left motor pins
const int BIN1 = 8;
const int BIN2 = 9;
const int PWMB = 10;

// FSR sensors
const int fsr1Pin = A0;        // obstacle sensor
const int fsr2Pin = A1;        // win sensor 
const int fsrThreshold = 200;  // adjust after testing

// movement durations
const int driveTime = 300;
const int turnTime = 250;

void setup() {
  pinMode(AIN1, OUTPUT);
  pinMode(AIN2, OUTPUT);
  pinMode(PWMA, OUTPUT);
  pinMode(BIN1, OUTPUT);
  pinMode(BIN2, OUTPUT);
  pinMode(PWMB, OUTPUT);
  
  Serial.begin(9600);
}

void loop() {
  // SENSOR 1 - OBSTACLE -  YOU LOSE
  int fsr1Value = analogRead(fsr1Pin);
  if (fsr1Value > fsrThreshold) {
    stopMotors();
    Serial.println("BUMP DETECTED");     
    delay(300);
    return;
  }

  // SENSOR 2 - GOAL - YOU WIN
  int fsr2Value = analogRead(fsr2Pin);
  if (fsr2Value > fsrThreshold) {
    stopMotors();
    Serial.println("WIN SENSOR HIT");   
    delay(300);
    return;
  }

  // SERIAL COMMANDS 
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    
    if (cmd == 'f') {
      rightMotor(-255);
      leftMotor(255);
      delay(driveTime);
      stopMotors();
    }
    if (cmd == 'b') {
      rightMotor(255);
      leftMotor(-255);
      delay(driveTime);
      stopMotors();
    }
    if (cmd == 'l') {
      rightMotor(255);
      leftMotor(255);
      delay(turnTime);
      stopMotors();
    }
    if (cmd == 'r') {
      rightMotor(-255);
      leftMotor(-255);
      delay(turnTime);
      stopMotors();
    }
  }
}

// MOTOR FUNCTIONS
void stopMotors() {
  rightMotor(0);
  leftMotor(0);
}

void rightMotor(int speed) {
  if (speed > 0) {
    digitalWrite(AIN1, HIGH);
    digitalWrite(AIN2, LOW);
  } else if (speed < 0) {
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, HIGH);
  } else {
    digitalWrite(AIN1, LOW);
    digitalWrite(AIN2, LOW);
  }
  analogWrite(PWMA, abs(speed));
}

void leftMotor(int speed) {
  if (speed > 0) {
    digitalWrite(BIN1, HIGH);
    digitalWrite(BIN2, LOW);
  } else if (speed < 0) {
    digitalWrite(BIN1, LOW);
    digitalWrite(BIN2, HIGH);
  } else {
    digitalWrite(BIN1, LOW);
    digitalWrite(BIN2, LOW);
  }
  analogWrite(PWMB, abs(speed));
}

p5.js Code Description
The p5.js script manages the entire visual and interactive flow of the game. I created states for each screen, and the draw function displays the correct one based on the current state. The Start and Instructions pages have simple navigation buttons. The Control page includes the connection button, movement controls, timer, and status labels.

Once the player connects through Web Serial, the browser can send characters directly to the Arduino. I set up an async text reader so p5.js continuously checks for any messages the Arduino sends back. When a “WIN” or “BUMP” message is detected, p5.js switches to the corresponding screen and stops the timer.

The timer is implemented using millis(), and I store the best time in localStorage so the score stays saved even after refreshing the page. This gives the game a small replayability element.


Communication Between Arduino and p5.js
The communication is simple but effective. p5.js sends commands like “f”, “b”, “l”, and “r”. The Arduino receives them through Serial.read() and triggers the motors. Arduino sends back plain text messages that indicate win or lose events. p5.js reads these messages through a continuous loop using Web Serial’s readable stream. This setup ensures the robot’s physical behavior is always linked to the digital interface.

How This Was Made
The robot’s basic structure comes from the SparkFun guide, which helped me understand the wiring, motor driver logic, and motor control functions. After building the foundation from that tutorial, I added new features: dual-sensor win/lose detection, the full p5.js interface, the multi-screen system, arrow-key controls, the timer, and the localStorage system.

I wrote most of the Arduino and p5.js code myself, but I used generative AI mainly for debugging when errors happened, organizing long sections of code, and helping solve serial communication issues. All visuals, photos, and the physical design are made by me.

Project Media
initial stages of setting the robot up

This was the initial design of the robot which was made from carton and covered with paper. However, it stopped working completely and I didn’t know the reason, so I had to reassemble it. Turns out 5V jumper wire got loose and it was causing an issue.

 

 

 

I learned my lesson and taped all the wires to the Arduino board so that these “accidents” don’t happen anymore. The end result turned out to be much better and pretties than before.

 

 

video demonstration

video demostration 2

What I’m Proud Of
I’m most proud of the amount of design work that went into this project. I spent a lot of time experimenting with layouts, choosing the right materials for the course, and making sure the robot could navigate smoothly. The obstacle course was a huge build and took multiple redesigns to get right. I also used a lot of hot glue during the building phase, to the point where I started recognizing the smell too well.

I’m also proud of how the interface looks and how the robot, sensors, and game flow all connect together. It feels like a small arcade experience.

Future Improvements
In the future, I would like to add a separate physical controller so players don’t have to look at the laptop while playing. I would also include a scoring system with bonus points, a leaderboard that keeps track of previous scores, and maybe multiple levels or different obstacle layouts. These additions would make the game more competitive and engaging.

User Testing

IMG_0901

Today I had a few people try my project without giving them any instructions, just to see how intuitive it actually is. Since the website isn’t fully finished yet, some parts were definitely confusing at first. People weren’t totally sure what the experience was supposed to be, and the lack of intro screens made it feel like something was missing.

But honestly, the four buttons in the p5 interface made a huge difference. Even without explanations, most people understood pretty quickly that each button does something to the robot. They started clicking around, testing what each one does, and exploring on their own. The mapping between the controls and the robot’s movement felt clear to them, which is a good sign.

Still, because the rest of the experience isn’t complete yet, they didn’t really understand why the robot was moving or what the larger goal of the project was supposed to be. This is where most of the confusion happened. I found myself needing to explain the story/context and what the robot is meant to represent , which means that once the website is finished, I need to make sure the narrative is communicated immediately and visually, without me talking.

Overall, the parts that are working really well right now are:

  • the p5 buttons

  • the immediate direct feedback

  • the fact that people naturally experimented

The parts that need improvement:

  • clearer intro

  • clearer purpose

  • smoother connection between the physical robot and the digital scenes

Once the full website and story screens are built, I think the experience will make a lot more sense for first-time users. For now, at least the controls are intuitive so that’s a good foundation to build on.

Week 12 – Documentation on Final Project

Finalized Concept: “The Snail’s Journey to School”

Project Summary
The Snail’s Journey to School is an interactive physical–digital storytelling installation.
The player controls a small snail robot navigating a handmade obstacle course, helping it reach “school.” As the player moves the snail using physical buttons, a connected p5.js sketch narrates the adventure, updates animations, and reacts to the snail’s progress in real time through serial communication with Arduino.

1. Finalized Detailed Concept

Physical World (Arduino + Snail Robot)

The snail robot sits on a small motorized base (the base will be the robot that can be built from Arduino Uno kit). The user controls the snail with three buttons:

  • FORWARD
  • LEFT
  • RIGHT

A “finish line” sensor (photoresistor or IR distance sensor) detects when the snail reaches the school.

The obstacle course includes:

  • A puddle (painted blue)
  • Small pebbles
  • A small cardboard ramp
  • A school gate with the sensor hidden inside

Digital World (p5.js Storytelling Screen)

The p5 screen visually tells the story through 4 scenes:

  1. Intro Scene
    “The snail is late for school! Guide it through the obstacle course.”
  2. Instructions Scene
    Shows button directions + images.
  3. Live Story Mode
    Reacts to every button press and displays animations such as:
  • “Snail moves forward!”
  • “Turning left…”
  • Little movement animations or sound effects.
  1. Ending Scene
    When the sensor triggers finish, p5 displays:
    “You made it! The snail is in class now!” with a cute animation.
  2. If the player doesn’t make it on time, which is 2.5 minutes, or fails to cross more than 1 obstacle the screen shows “oh no, you’re late to school!”

Project Interaction Loop (Final Version)

  1. Player presses physical button
  2. Arduino moves snail robot + sends message to p5
  3. p5 receives message and updates story animation
  4. Snail reaches sensor
  5. Arduino sends “finish” to p5 ->  p5 plays ending

Arduino Program Design

Week 11 – Final Project Prompt

My final project is an interactive installation titled “The Snail’s Journey to School.” The idea is inspired by the opening scenes of Monsters University, where a small character makes their way toward school. In my version, the user helps a robot snail travel through a physical obstacle course until it reaches its destination.

Arduino will control the physical movement of the robot snail using motors and buttons for directional input. It may also include an optional sensor, such as a photoresistor or distance sensor, to detect obstacles or the finish line. The snail robot and the obstacle course will be fabricated by me, either through 3D printing or hand-built materials.

p5.js will act as the narrative and feedback layer. It will display an introduction, instructions, and story elements that respond to the user’s physical interactions. As the user presses buttons to move the snail, Arduino will send messages to p5.js, which will update the visuals, play small animations or sounds, and react to progress in real time. When the snail reaches the “school” area, p5 will display the final scene.

The interaction loop centers on listening (reading the user’s button presses), thinking (moving the snail and sending corresponding data), and speaking (p5.js reacting immediately with feedback).

Week 11 – Reading Response

In Design Meets Disability, Graham Pullin challenges the way society frames disability by questioning why assistive devices are often treated as purely functional rather than expressive. He argues that design for disability should not be limited to medical necessity, it should also include aesthetics, identity, and personal preference. What stood out to me is how Pullin highlights the quiet power imbalance in design: mainstream objects like glasses or smartphones have endless variations and styles, while many assistive tools remain clinical and uniform. This difference reveals how disability is still seen as something to “fix” instead of a natural part of human diversity.

Pullin pushes the reader to consider that assistive devices could be opportunities for creativity rather than reminders of limitation. For example, he discusses the possibility of hearing aids becoming fashionable accessories instead of devices people feel pressured to hide. His argument reframes disability not as a deficit but as a design space full of potential innovation.

Overall, the reading invites designers to rethink their assumptions. Instead of designing for disabled people, Pullin encourages designing with them, treating disability as a source of insight and richness. The book ultimately suggests that inclusive design is not just ethical, it also expands the possibilities of design itself.

Week 11 – Production

Task 1: 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.

Asma built a simple circuit using an Arduino and a 10kΩ potentiometer to control an on-screen ellipse in p5.js. She connected the potentiometer’s outer legs to 5V and GND and the middle leg to the analog pin A0, allowing it to act as a variable voltage divider. After uploading the Arduino code and checking the serial monitor, she could see how turning the knob changed the analog readings from 0 to 1023. This helped her understand how analog sensors translate physical movement into numerical data that can be visualized digitally.

Arduino code:

const int potPin = A0;

void setup() {
  Serial.begin(9600);  
}

void loop() {
  int val = analogRead(potPin);   // 0..1023
  Serial.println(val);            
  delay(10);                     
}

P5.js codę:

// === Arduino + p5.js WebSerial (directional movement, fixed) ===
// Pot controls direction/speed by how its value changes. p5 does NOT control Arduino.

let port;
let reader;
let connectButton;
let isConnected = false;

let latestData = null; // last parsed int from serial (0..1023)
let prevData   = null; // previous sample to compute delta
let lineBuffer = '';   // accumulate serial chunks until '\n'

let posX = 0;          // ellipse position
let speed = 0;         // horizontal velocity

function setup() {
  createCanvas(windowWidth, windowHeight);
  background(240);
  textFont('monospace');

  connectButton = createButton('Connect to Arduino');
  connectButton.position(20, 20);
  connectButton.mousePressed(connectToSerial);

  // start centered; we'll keep it centered until first data arrives
  posX = width / 2;
}

async function connectToSerial() {
  try {
    // Request and open port
    port = await navigator.serial.requestPort();
    await port.open({ baudRate: 9600 });
    isConnected = true;
    console.log(' Port opened');

    // Create a text decoder stream and reader for clean line-by-line reads
    const textDecoder = new TextDecoderStream();
    const readableClosed = port.readable.pipeTo(textDecoder.writable);
    reader = textDecoder.readable.getReader();

    // Kick off read loop
    readSerialLines();
  } catch (err) {
    console.error(' Connection failed:', err);
    isConnected = false;
  }
}

async function readSerialLines() {
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) break; // reader released
      if (!value) continue;

      // Accumulate and split by newline
      lineBuffer += value;
      let lines = lineBuffer.split(/\r?\n/);
      lineBuffer = lines.pop(); // save incomplete tail

      for (let line of lines) {
        line = line.trim();
        if (!line) continue;
        const v = parseInt(line, 10);
        if (!Number.isNaN(v)) {
          // Clamp to expected 10-bit range
          latestData = Math.min(Math.max(v, 0), 1023);
          // Initialize prevData on first valid sample
          if (prevData === null) prevData = latestData;
        }
      }
    }
  } catch (err) {
    console.error(' Read error:', err);
  } finally {
    try { reader && reader.releaseLock(); } catch {}
  }
}

function draw() {
  background(240);

  if (!isConnected) {
    fill(200, 0, 0);
    noStroke();
    textAlign(CENTER, CENTER);
    textSize(20);
    text("Click 'Connect to Arduino' to begin", width / 2, height / 2);
    return;
  }

  // If we haven't received any valid data yet, show waiting status
  if (latestData === null || prevData === null) {
    fill(0);
    textSize(16);
    textAlign(LEFT, TOP);
    text('Waiting for data...', 20, 60);
    // Keep ellipse centered until first data arrives
  } else {
    // Change in pot reading determines direction and speed bump
    const delta = latestData - prevData;

    // Deadband to ignore small noise
    const deadband = 4;
    if (delta > deadband) {
      speed = constrain(speed + 0.6, -12, 12); // turn right -> move right
    } else if (delta < -deadband) {
      speed = constrain(speed - 0.6, -12, 12); // turn left -> move left
    } else {
      // friction when knob still
      speed *= 0.90;
    }

    // Integrate position and clamp
    posX += speed;
    posX = constrain(posX, 0, width);

    // Update prev for next frame
    prevData = latestData;
  }

  // Draw ellipse at vertical center
  noStroke();
  fill(50, 100, 255);
  ellipse(posX, height / 2, 80, 80);

  // HUD
  fill(0);
  textSize(14);
  textAlign(LEFT, TOP);
  const shown = latestData === null ? '—' : latestData;
  text(⁠ Sensor: ${shown} ⁠, 20, 60);
  text(⁠ Speed:  ${nf(speed, 1, 2)} ⁠, 20, 80);
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  // Keep position on-screen if you resize smaller
  posX = constrain(posX, 0, width);
}

Schematic:

 

Task 2: make something that controls the LED brightness from p5

Hajar created a simple schematic and circuit using one LED and one resistor connected to the Arduino. Since the main goal was to control the LED’s brightness through serial communication with p5.js, she kept the hardware minimal and focused more on the coding. She first tested the LED with a basic Arduino sketch to make sure everything worked, then created the schematic. Although the circuit was simple and familiar, it still showed her how even a basic setup can become interactive when combined with p5.js.

Arduino code:

const int ledPin = 10;  // LED connected to pin 10

void setup() {
  Serial.begin(9600);   // must match p5.js baud rate
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    int brightness = Serial.read();      // read 0–255
    brightness = constrain(brightness, 0, 255);
    analogWrite(ledPin, brightness);     // control LED brightness
  }
}

P5.js codę:

Sketch:

Task 3: take the gravity wind example 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

For this project, I combined both physical computing and digital simulation by connecting an Arduino circuit to a p5.js sketch. My setup included a potentiometer to control the wind force in the animation and an LED that lit up every time the falling ball hit the ground. I built a simple circuit using one LED, a resistor, and a 10kΩ potentiometer, and then connected it to my computer through serial communication. Even though the hardware was straightforward, the real challenge came from getting the Arduino and p5.js to communicate properly. I spent a lot of time testing the potentiometer readings, debugging the serial connection, and making sure the LED responded at the right moment in the animation.

P5.js code:

let velocity;
let gravity;
let position;
let acceleration;
let drag = 0.99;
let mass = 50;

let brightnessValue = 0; // Potentiometer value from Arduino (0–5)
let ballDropped = false;
let ledOn = false;

function setup() {
  createCanvas(640, 360);
  noFill();
  textSize(18);

  position = createVector(width / 2, 0);
  velocity = createVector(0, 0);
  acceleration = createVector(0, 0);
  gravity = createVector(0, 0.5 * mass);
}

function draw() {
  background(255);

  fill(0);
  if (!ballDropped) {
    text("Press D to drop the ball", 20, 30);
    text("Press Space Bar to select Serial Port", 20, 50);
    return;
  }

  if (serialActive) {
    text("Connected", 20, 30);
    text(`Potentiometer: ${brightnessValue}`, 20, 50);
  } else {
    text("Serial Port Not Connected", 20, 30);
  }

  // Gravity only (no wind)
  applyForce(gravity);

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

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

  // Bounce
  if (position.y >= height - mass / 2) {
    velocity.y *= -0.9;
    position.y = height - mass / 2;

    // Tell Arduino: turn LED on briefly
    if (serialActive && !ledOn) {
      writeSerial("1,0\n");
      ledOn = true;
    }
  } else if (ledOn) {
    // Tell Arduino: turn LED off
    writeSerial("0,0\n");
    ledOn = false;
  }
}

function applyForce(force) {
  let f = p5.Vector.div(force, mass);
  acceleration.add(f);
}

// Serial setup and drop ball
function keyPressed() {
  if (key == " ") setUpSerial();
  if (key == "D" || key == "d") dropBall();
}

function dropBall() {
  position.set(width / 2, 0);
  velocity.set(0, 0);
  mass = 50;
  gravity = createVector(0, 0.5 * mass);
  ballDropped = true;
}

// Read data from Arduino
function readSerial(data) {
  if (data != null) {
    let fromArduino = split(trim(data), ",");
    if (fromArduino.length === 1) {
      brightnessValue = int(fromArduino[0]); // Potentiometer value
    }
  }
}

Arduino code:

int potPin = A5;   
int ledPin = 3;    

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);

  analogWrite(ledPin, 255);
  delay(200);
  analogWrite(ledPin, 0);
}

void loop() {
  int raw = analogRead(potPin);

  int brightness = map(raw, 0, 1023, 0, 255);

  Serial.println(brightness);

  // Check for serial commands from p5
  if (Serial.available()) {
    String data = Serial.readStringUntil('\n');

    if (data == "1,0") {
      analogWrite(ledPin, brightness);  // flash with pot brightness
      delay(100);
      analogWrite(ledPin, 0);           // turn off after flash
    }
  }

  delay(30); 
}

Sketch:

Video:

IMG_9469

Week 10 – Reading Reflection

This piece, A Brief Rant on the Future of Interaction Design, really made me stop and think about how disconnected we’ve become from the physical world, even as our technology gets “smarter.” The author argues that our so-called “futuristic” devices are actually quite limited, everything has become a flat piece of glass we tap on, instead of something we truly interact with. He calls out this obsession with “pictures under glass” as lazy design — a downgrade from the richness of real, tactile experience.

What really stuck with me was his reminder of how incredible our hands are. They can sense texture, pressure, temperature, yet we now use them mainly to poke at screens. His comparison to trying to tie your shoes with numb fingers really drives it home. It’s not just that we’ve lost physical feedback, we’ve lost creativity and subtlety in how we use our bodies to understand the world.

But as much as I agree with him, I think his critique could use a bit more realism. There’s a reason touchscreens took over: they’re convenient, cheap, and universal. Designing physical, tactile, or responsive interfaces on a large scale would be expensive and hard to standardize. For example, the Apple Vision Pro tries to reintroduce gesture-based control, but even that feels awkward and unnatural for many people. It’s like we’ve already trained ourselves to think in 2D, to expect smooth glass, not texture or resistance.

Still, I think his rant is important because it challenges the direction of design thinking. It made me think about situations like education or online learning. imagine how much richer it would be if students could physically interact with virtual models or data instead of just scrolling and clicking. Or think of creative fields like art or architecture, where so much of the learning used to come from the feel of materials. Now, everything happens behind a screen.

So, while his rant might sound idealistic, it’s also a necessary wake-up call. It reminds us that innovation shouldn’t just mean “simpler” or “sleeker”, it should mean more human. The goal shouldn’t be to erase physicality for convenience, but to design technology that reconnects us to the world instead of flattening it.

Week 9 – Shadow and Light

Concept

For this project, I decided to make a small interactive game called Light & Shadow”. The concept is simple but fun: the yellow LED changes brightness depending on how much light the photoresistor (LDR) senses, and the blue LED only lights up when it’s dark and the button is pressed, basically “catching the shadow.” I liked that idea because it combines analog and digital inputs in a way that feels like a mini game.

The Process

The production process was mostly about setting up the circuit on the breadboard and figuring out how to connect everything correctly. Choosing the right resistors was harder than I expected,  sometimes the LEDs didn’t light up properly, and I had to try a few combinations before it worked. I also spent a lot of time drawing the schematic to make sense of the connections. I must have redrawn it several times to make it at least slightly understandable. Even now, I’m not 100% sure my plan is perfect, but it works!

Figure: the process of sketching the plan

The Finalized Sketch

The coding part was fun because it was simple enough to understand but still taught me a lot. I read the analog value from the photoresistor and mapped it to the brightness of the red LED, then used a simple if-statement to check the button and darkness to control the green LED. Seeing the LEDs react in real time to light and button presses made all the work feel rewarding.

int lightSensor = A0;
int buttonPin = 2;
int redLED = 9;
int greenLED = 8;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int lightValue = analogRead(lightSensor);    // 0–1023
  int brightness = map(lightValue, 0, 1023, 255, 0); // dark = bright
  analogWrite(redLED, brightness);

  int buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH && lightValue < 400) {
    digitalWrite(greenLED, HIGH);
  } else {
    digitalWrite(greenLED, LOW);
  }

  delay(100);
}

Reflection

Overall, this project was a great learning experience. I got hands-on practice with analog and digital inputs, using resistors correctly, and writing basic Arduino code. I also learned patience, both in wiring and drawing schematics. Even though some parts were frustrating or confusing, it felt really satisfying to see the LEDs respond the way I wanted. Next time, I’d probably try adding a buzzer or even a little LCD display to make it even more interactive.

The video demonstration

IMG_8850

Reading reflection

Reading Physical Computing’s Greatest Hits and Misses alongside Making Interactive Art: Set the Stage, Then Shut Up and Listen really made me rethink how we interact with technology in creative spaces. Both texts explore the tension between human intention and technological behavior, but they approach it from slightly different angles. The first one dives into successes and failures in physical computing projects, highlighting that even the best ideas can flop if the execution ignores user experience or the unpredictability of the real world. The second reading, on the other hand, emphasizes listening to the audience and letting interactions evolve naturally, rather than forcing a rigid narrative onto the art or installation.

The most interesting part for me was the recurring theme of “letting go.” In physical computing, there’s often a desire to control every aspect of a system, to make it work perfectly according to the designer’s vision. But as the readings show, interaction is messy. Sensors misfire, people behave unexpectedly, and sometimes the “mistakes” end up being the most engaging parts of the project. I appreciated the reminder that in interactive art, and in technology projects more broadly, failure isn’t always a failure, it’s data, feedback, and sometimes even the spark for something better.

One question that came to mind while reading was: How do we balance designing for reliability with designing for surprise and emergent behavior? Both readings suggest that embracing unpredictability can make projects more engaging, but too much unpredictability can frustrate users. My takeaway is that the key might be thoughtful scaffolding, providing enough structure so that the system is understandable and responsive, while leaving space for improvisation and interaction to shape the experience.

Overall, I found these readings both inspiring and a little humbling. They reminded me that creativity in physical computing isn’t just about technical skill, it’s about curiosity, flexibility, and, honestly, patience with both technology and people.

Week 8 – creative switch

For my project, I designed an Arduino switch using open-end wires that respond to the camera’s power state. I taped the wires to a digital camera so that when the camera is turned on, the wires disconnect and the LED light turns off, and when the camera is turned off, the wires reconnect and the light turns on. This created a simple but clever system where the camera itself acts as a physical trigger for the circuit. I really enjoyed experimenting with the setup, testing how small adjustments in the wire placement affected the light’s response. Since I’m passionate about photography, I wanted to combine my interest in cameras with my curiosity about electronics, and this project gave me a fun way to explore both creative and technical sides at the same time.

IMG_8468 (1) The video representation