Week 11 – Serial Communication

Group Members: Shamsa Alremeithi and Maliha

Exercise 1

For this exercise, we had connected a potentiometer to the Arduino by connecting the middle pin to analog pin A1, and the other two pins to 5V and GND. we had written a simple Arduino code to read the analog value from the potentiometer and map it to a range of 0 to 400, which was then sent to the computer through the serial port. With p5.js and the p5.webserial library, a circle moves left to right across the screen based on the potentiometer’s position. we also included “Connect” and “Disconnect” buttons to control the serial connection from the browser with ease.

 

Arduino Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
void setup() {
Serial.begin(9600);
}
void loop() {
// Read the analog value from pin A1 (0 to 1023)
int potentiometer = analogRead(A1);
// Map the raw potentiometer value to a new range (0 to 400) for use in p5.js
int mappedPotValue = map(potentiometer, 0, 1023, 0, 400);
Serial.println(mappedPotValue);
delay(100);
}
void setup() { Serial.begin(9600); } void loop() { // Read the analog value from pin A1 (0 to 1023) int potentiometer = analogRead(A1); // Map the raw potentiometer value to a new range (0 to 400) for use in p5.js int mappedPotValue = map(potentiometer, 0, 1023, 0, 400); Serial.println(mappedPotValue); delay(100); }
void setup() {
  Serial.begin(9600); 
}

void loop() {
  // Read the analog value from pin A1 (0 to 1023)
  int potentiometer = analogRead(A1);                  

  // Map the raw potentiometer value to a new range (0 to 400) for use in p5.js
  int mappedPotValue = map(potentiometer, 0, 1023, 0, 400); 

  Serial.println(mappedPotValue);

  delay(100);                                            
}

 

p5.js Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let port;
let connectBtn;
let disconnectBtn;
let baudrate = 9600;
let isConnected = false;
function setup() {
createCanvas(400, 400);
background(220);
// Create a new Web Serial port instance using p5.webserial
port = createSerial();
// If a port was previously used, auto-connect to it
let usedPorts = usedSerialPorts();
if (usedPorts.length > 0) {
port.open(usedPorts[0], baudrate);
isConnected = true;
}
// Create the Connect button and open the port when clicked
connectBtn = createButton("Connect to Serial");
connectBtn.position(10, 10);
connectBtn.mousePressed(() => {
port.open(baudrate); // Opens a serial connection using the chosen baud rate
isConnected = true;
});
// Create the Disconnect button to close the serial port
disconnectBtn = createButton("Disconnect");
disconnectBtn.position(150, 10);
disconnectBtn.mousePressed(() => {
port.close(); // closes the serial connection
isConnected = false;
// Clear screen and show "Disconnected" message
background(255);
textAlign(CENTER, CENTER);
textSize(18);
fill(100);
text("Disconnected.", width / 2, height / 2);
});
}
function draw() {
if (isConnected) {
//"\n", signaling the end of one complete piece of data after sending each number.
let str = port.readUntil("\n");
if (str.length > 0) {
background("white");
// Convert the received string to an integer (e.g., mapped potentiometer value)
let x = int(str);
// Make sure x stays within the canvas width (safety measure)
x = constrain(x, 0, width);
ellipse(x, 200, 40, 40);
}
}
}
let port; let connectBtn; let disconnectBtn; let baudrate = 9600; let isConnected = false; function setup() { createCanvas(400, 400); background(220); // Create a new Web Serial port instance using p5.webserial port = createSerial(); // If a port was previously used, auto-connect to it let usedPorts = usedSerialPorts(); if (usedPorts.length > 0) { port.open(usedPorts[0], baudrate); isConnected = true; } // Create the Connect button and open the port when clicked connectBtn = createButton("Connect to Serial"); connectBtn.position(10, 10); connectBtn.mousePressed(() => { port.open(baudrate); // Opens a serial connection using the chosen baud rate isConnected = true; }); // Create the Disconnect button to close the serial port disconnectBtn = createButton("Disconnect"); disconnectBtn.position(150, 10); disconnectBtn.mousePressed(() => { port.close(); // closes the serial connection isConnected = false; // Clear screen and show "Disconnected" message background(255); textAlign(CENTER, CENTER); textSize(18); fill(100); text("Disconnected.", width / 2, height / 2); }); } function draw() { if (isConnected) { //"\n", signaling the end of one complete piece of data after sending each number. let str = port.readUntil("\n"); if (str.length > 0) { background("white"); // Convert the received string to an integer (e.g., mapped potentiometer value) let x = int(str); // Make sure x stays within the canvas width (safety measure) x = constrain(x, 0, width); ellipse(x, 200, 40, 40); } } }
let port;
let connectBtn;
let disconnectBtn;
let baudrate = 9600;
let isConnected = false;

function setup() {
  createCanvas(400, 400);
  background(220);

  // Create a new Web Serial port instance using p5.webserial
  port = createSerial();

  // If a port was previously used, auto-connect to it
  let usedPorts = usedSerialPorts();
  if (usedPorts.length > 0) {
    port.open(usedPorts[0], baudrate);
    isConnected = true;
  }

  // Create the Connect button and open the port when clicked
  connectBtn = createButton("Connect to Serial");
  connectBtn.position(10, 10);
  connectBtn.mousePressed(() => {
    port.open(baudrate);  // Opens a serial connection using the chosen baud rate
    isConnected = true;
  });

  // Create the Disconnect button to close the serial port
  disconnectBtn = createButton("Disconnect");
  disconnectBtn.position(150, 10);
  disconnectBtn.mousePressed(() => {
    port.close();  // closes the serial connection
    isConnected = false;

    // Clear screen and show "Disconnected" message
    background(255);
    textAlign(CENTER, CENTER);
    textSize(18);
    fill(100);
    text("Disconnected.", width / 2, height / 2);
  });
}

function draw() {
  if (isConnected) {
//"\n", signaling the end of one complete piece of data after sending each number.

    let str = port.readUntil("\n");

    if (str.length > 0) {
      background("white");

      // Convert the received string to an integer (e.g., mapped potentiometer value)
      let x = int(str);

      // Make sure x stays within the canvas width (safety measure)
      x = constrain(x, 0, width);

      ellipse(x, 200, 40, 40);
    }
  }
}

Exercise 2

make something that controls the LED brightness from p5

p5.js interface:

Arduino Code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int ledPin = 9; // PWM-capable pin to control LED brightness
void setup() {
Serial.begin(9600); // Start serial communication at 9600 baud rate
pinMode(ledPin, OUTPUT); // Set the LED pin as an output
}
void loop() {
if (Serial.available()) { // Check if data is available to read from serial
int brightness = Serial.parseInt(); // Read the integer value (brightness)
brightness = constrain(brightness, 0, 255); // Limit the value to the 0-255 range
analogWrite(ledPin, brightness); // Write the brightness value to the LED pin
}
}
int ledPin = 9; // PWM-capable pin to control LED brightness void setup() { Serial.begin(9600); // Start serial communication at 9600 baud rate pinMode(ledPin, OUTPUT); // Set the LED pin as an output } void loop() { if (Serial.available()) { // Check if data is available to read from serial int brightness = Serial.parseInt(); // Read the integer value (brightness) brightness = constrain(brightness, 0, 255); // Limit the value to the 0-255 range analogWrite(ledPin, brightness); // Write the brightness value to the LED pin } }
int ledPin = 9; // PWM-capable pin to control LED brightness

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

void loop() {
  if (Serial.available()) {    // Check if data is available to read from serial
    int brightness = Serial.parseInt();  // Read the integer value (brightness)
    brightness = constrain(brightness, 0, 255); // Limit the value to the 0-255 range
    analogWrite(ledPin, brightness);   // Write the brightness value to the LED pin
  }
}

This project creates a real-time visual and physical interface to control an LED’s brightness using a slider in a p5.js sketch. The brightness value is sent from the browser to an Arduino board via serial communication. As the user moves the slider, the LED’s intensity changes accordingly, both in the physical circuit and on-screen through a glowing animation and gauge ring. The interface also includes a connect/disconnect button for flexible hardware control.

Exercise 3

In this exercise, we took the gravity and wind example and instead connected it to the Arduino. We replaced the digital wind control with a potentiometer, allowing us to control the wind force by hand. Additionally, we used an LED to light up every time the ball hit the ground and is at rest.

Arduino Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const int ledPin = 5;
const int potPin = A0;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}
void loop() {
int sensorValue = analogRead(potPin);
Serial.println(sensorValue);
if (Serial.available() > 0) {
char msg = Serial.read();
if (msg == '1') {
digitalWrite(ledPin, HIGH);
}
else if (msg == '0') {
digitalWrite(ledPin, LOW);
}
while (Serial.available() > 0) Serial.read();
}
delay(50);
}
const int ledPin = 5; const int potPin = A0; void setup() { Serial.begin(9600); pinMode(ledPin, OUTPUT); } void loop() { int sensorValue = analogRead(potPin); Serial.println(sensorValue); if (Serial.available() > 0) { char msg = Serial.read(); if (msg == '1') { digitalWrite(ledPin, HIGH); } else if (msg == '0') { digitalWrite(ledPin, LOW); } while (Serial.available() > 0) Serial.read(); } delay(50); }
const int ledPin = 5;
const int potPin = A0;

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

void loop() {
  int sensorValue = analogRead(potPin);
  Serial.println(sensorValue);

  if (Serial.available() > 0) {
    char msg = Serial.read();
    
    if (msg == '1') {
      digitalWrite(ledPin, HIGH);
    } 
    else if (msg == '0') {
      digitalWrite(ledPin, LOW);
    }
    
    while (Serial.available() > 0) Serial.read();
  }

  delay(50);
}

 

p5.js Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let port;
let baudrate = 9600;
let position, velocity, acceleration, gravity, wind;
let drag = 0.99;
let mass = 50;
let val = 0;
let str = "";
let hitGround = false;
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);
port = createSerial();
let connectButton = createButton("Connect");
connectButton.position(10, 10);
connectButton.mousePressed(() => {
if (!port.opened()) port.open(baudrate);
});
let disconnectButton = createButton("Disconnect");
disconnectButton.position(100, 10);
disconnectButton.mousePressed(() => {
if (port.opened()) port.close();
});
let dropButton = createButton("Drop Ball");
dropButton.position(220, 10);
dropButton.mousePressed(dropBall);
}
function draw() {
background(255);
applyForce(gravity);
applyForce(wind);
velocity.add(acceleration);
velocity.mult(drag);
position.add(velocity);
acceleration.mult(0);
ellipse(position.x, position.y, mass, mass);
if (position.y > height - mass / 2) {
velocity.y *= -0.9;
position.y = height - mass / 2;
if (!hitGround) {
hitGround = true;
if (port.opened()) {
port.write("1\n"); // turn LED on
}
}
} else {
hitGround = false;
if (port.opened()) {
port.write("0\n"); // turn LED off
}
}
str = port.readUntil("\n");
val = int(str.trim());
if (!isNaN(val)) {
updateWind(val);
}
}
function applyForce(force) {
let f = p5.Vector.div(force, mass);
acceleration.add(f);
}
function updateWind(val) {
wind.x = map(val, 0, 1023, -1, 1);
}
function dropBall() {
// Reset ball to the top
position.y = 0;
velocity.set(0, 0);
acceleration.set(0, 0);
hitGround = false;
// Force LED off
if (port.opened()) {
port.write("0\n");
}
}
let port; let baudrate = 9600; let position, velocity, acceleration, gravity, wind; let drag = 0.99; let mass = 50; let val = 0; let str = ""; let hitGround = false; 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); port = createSerial(); let connectButton = createButton("Connect"); connectButton.position(10, 10); connectButton.mousePressed(() => { if (!port.opened()) port.open(baudrate); }); let disconnectButton = createButton("Disconnect"); disconnectButton.position(100, 10); disconnectButton.mousePressed(() => { if (port.opened()) port.close(); }); let dropButton = createButton("Drop Ball"); dropButton.position(220, 10); dropButton.mousePressed(dropBall); } function draw() { background(255); applyForce(gravity); applyForce(wind); velocity.add(acceleration); velocity.mult(drag); position.add(velocity); acceleration.mult(0); ellipse(position.x, position.y, mass, mass); if (position.y > height - mass / 2) { velocity.y *= -0.9; position.y = height - mass / 2; if (!hitGround) { hitGround = true; if (port.opened()) { port.write("1\n"); // turn LED on } } } else { hitGround = false; if (port.opened()) { port.write("0\n"); // turn LED off } } str = port.readUntil("\n"); val = int(str.trim()); if (!isNaN(val)) { updateWind(val); } } function applyForce(force) { let f = p5.Vector.div(force, mass); acceleration.add(f); } function updateWind(val) { wind.x = map(val, 0, 1023, -1, 1); } function dropBall() { // Reset ball to the top position.y = 0; velocity.set(0, 0); acceleration.set(0, 0); hitGround = false; // Force LED off if (port.opened()) { port.write("0\n"); } }
let port;
let baudrate = 9600;
let position, velocity, acceleration, gravity, wind;
let drag = 0.99;
let mass = 50;
let val = 0;
let str = "";
let hitGround = false;

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);

  port = createSerial();

  let connectButton = createButton("Connect");
  connectButton.position(10, 10);
  connectButton.mousePressed(() => {
    if (!port.opened()) port.open(baudrate);
  });

  let disconnectButton = createButton("Disconnect");
  disconnectButton.position(100, 10);
  disconnectButton.mousePressed(() => {
    if (port.opened()) port.close();
  });

  let dropButton = createButton("Drop Ball");
  dropButton.position(220, 10);
  dropButton.mousePressed(dropBall);
}

function draw() {
  background(255);

  applyForce(gravity);
  applyForce(wind);

  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);

  ellipse(position.x, position.y, mass, mass);

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

    if (!hitGround) {
      hitGround = true;
      if (port.opened()) {
        port.write("1\n"); // turn LED on
      }
    }
  } else {
    hitGround = false;
    if (port.opened()) {
      port.write("0\n"); // turn LED off
    }
  }

  str = port.readUntil("\n");
  val = int(str.trim());

  if (!isNaN(val)) {
    updateWind(val);
  }
}

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

function updateWind(val) {
  wind.x = map(val, 0, 1023, -1, 1);
}

function dropBall() {
  // Reset ball to the top
  position.y = 0;
  velocity.set(0, 0);
  acceleration.set(0, 0);
  hitGround = false;

  // Force LED off
  if (port.opened()) {
    port.write("0\n");
  }
}

SchematiC

Video

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

Week 11 – Final Project Preliminary Concept

Final Project Preliminary Concept : Drawing With Motion

For my final project, I will design an interactive hand-controlled drawing device that allows users to sketch on a digital canvas by waving their hand in the air. I will use a distance sensor to track the distance of a hand from the sensor. The distance information will be sent to p5.js, which will use iit to manage various features of a virtual brush, like how it draws and how thick the lines will be. Thus, the graphics in p5.js will change instantly according to the user’s hand movements. For instance, as the hand moves closer to the sensor, the brush could create bolder, thicker lines. However, bringing the hand farther away might result in thinner lines. The system allows individuals to “paint” on the screen without using a mouse or stylus at all.

The p5.js sketch on the screen will show a white canvas featuring a circular brush that moves in sync with the user’s hand motions. When the user holds their hand over the sensor, the brush will emerge and begin drawing as they move their hand side to side. To clarify when to begin, the canvas will show a “Place your hand to start” message. As soon as a hand is identified near the sensor, the message will vanish and drawing will start automatically. In addition, it might be possible to add a color wheel for the user to click the desired color when “painting” on p5.

Once the user finishes their drawing, they can easily press a button next to the distance sensor. After pressing, the canvas will pause and show a cheerful message: “Awesome! “Thanks for your artwork!” In a few seconds, the sketch will return to the starting screen, prepared for the next attempt to draw.

Week 10 – Reading responses

A Brief Rant on the Future of Interaction Design

The article, “A Brief Rant on the Future of Interaction Design” Criticizes the “Pictures Under Glass” approach in interaction design, where the author emphasizes the importance of tactile and hands-on engagement, which is frequently disregarded in preference to visual interfaces. The author asserts that touch is essential to our interactions with the world, highlighting the extensive tactile sensations we experience from common items such as books or glasses of water, and underlining the variety of hand motions required for activities like opening a jar. He analyzes the drawbacks of touchscreens, which primarily provide a flat, sliding motion that fails to reflect the depth of physical interaction we typically experience. Although he recognizes the visual energy of digital interfaces, Victor proposes that present technologies, such as the iPad, might not have lasting potential unless they develop to utilize more of our physical abilities. This made me think about how often we overlook tactile feedback in our daily activities and how digital interfaces, although visually engaging, frequently fail to deliver that deep physical interaction.

Week 10: Music Instrument

Concept

For this assignment, me and Maliha made an interactive light-sensitive sound device using an Arduino Uno, a photoresistor (LDR), a pushbutton, an LED, and a piezo speaker. When the button is pressed, the Arduino reads the surrounding light level using the LDR and maps that value to a specific sound frequency. The speaker then emits a tone depending on the brightness or darkness—darker settings yield higher-pitched tones, and brighter settings yield lower-pitched tones. Meanwhile, the LED lights up to signal that the system is reading and responding actively. This project taught us how sensors, inputs, and outputs are combined to build responsive circuits.

 

Code Highlights

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const int ldrPin = A0; // LDR connected to analog pin A0
const int buttonPin = 2; // Button connected to digital pin 2
const int speakerPin = 9; // Speaker connected to digital pin 9
const int ledPin = 13; // LED connected to pin 13
// Dramatically different frequencies (non-musical)
int notes[] = {100, 300, 600, 900, 1200, 2000, 3000};
void setup() {
pinMode(buttonPin, INPUT); // Button logic: HIGH when pressed
pinMode(speakerPin, OUTPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
int buttonState = digitalRead(buttonPin); // Read the button
if (buttonState == HIGH) {
int lightLevel = analogRead(ldrPin); // Read LDR
int noteIndex = map(lightLevel, 0, 1023, 6, 0); // Bright = low note
noteIndex = constrain(noteIndex, 0, 6); // Keep within range
int frequency = notes[noteIndex]; // Pick frequency
tone(speakerPin, frequency); // Play note
digitalWrite(ledPin, HIGH); // LED on
Serial.print("Light: ");
Serial.print(lightLevel);
Serial.print(" | Frequency: ");
Serial.println(frequency);
} else {
noTone(speakerPin); // No sound
digitalWrite(ledPin, LOW); // LED off
}
delay(100);
}
const int ldrPin = A0; // LDR connected to analog pin A0 const int buttonPin = 2; // Button connected to digital pin 2 const int speakerPin = 9; // Speaker connected to digital pin 9 const int ledPin = 13; // LED connected to pin 13 // Dramatically different frequencies (non-musical) int notes[] = {100, 300, 600, 900, 1200, 2000, 3000}; void setup() { pinMode(buttonPin, INPUT); // Button logic: HIGH when pressed pinMode(speakerPin, OUTPUT); pinMode(ledPin, OUTPUT); Serial.begin(9600); } void loop() { int buttonState = digitalRead(buttonPin); // Read the button if (buttonState == HIGH) { int lightLevel = analogRead(ldrPin); // Read LDR int noteIndex = map(lightLevel, 0, 1023, 6, 0); // Bright = low note noteIndex = constrain(noteIndex, 0, 6); // Keep within range int frequency = notes[noteIndex]; // Pick frequency tone(speakerPin, frequency); // Play note digitalWrite(ledPin, HIGH); // LED on Serial.print("Light: "); Serial.print(lightLevel); Serial.print(" | Frequency: "); Serial.println(frequency); } else { noTone(speakerPin); // No sound digitalWrite(ledPin, LOW); // LED off } delay(100); }
const int ldrPin = A0;         // LDR connected to analog pin A0
const int buttonPin = 2;       // Button connected to digital pin 2
const int speakerPin = 9;      // Speaker connected to digital pin 9
const int ledPin = 13;         // LED connected to pin 13

// Dramatically different frequencies (non-musical)
int notes[] = {100, 300, 600, 900, 1200, 2000, 3000};

void setup() {
  pinMode(buttonPin, INPUT);         // Button logic: HIGH when pressed
  pinMode(speakerPin, OUTPUT);     
  pinMode(ledPin, OUTPUT);         
  Serial.begin(9600);              
}

void loop() {
  int buttonState = digitalRead(buttonPin); // Read the button

  if (buttonState == HIGH) {
    int lightLevel = analogRead(ldrPin);         // Read LDR
    int noteIndex = map(lightLevel, 0, 1023, 6, 0); // Bright = low note
    noteIndex = constrain(noteIndex, 0, 6);      // Keep within range
    int frequency = notes[noteIndex];            // Pick frequency

    tone(speakerPin, frequency);                 // Play note
    digitalWrite(ledPin, HIGH);                  // LED on

    Serial.print("Light: ");
    Serial.print(lightLevel);
    Serial.print(" | Frequency: ");
    Serial.println(frequency);
  } else {
    noTone(speakerPin);            // No sound
    digitalWrite(ledPin, LOW);     // LED off
  }

  delay(100);
}

 

Video Demonstration

Challenges

One of the problems we faced was getting accurate light readings from the photoresistor since small changes in lighting at times caused big frequency jumps. We also had trouble keeping the wiring on the breadboard tidy and making sure each device was correctly connected to power and ground. Debugging the circuit and double-checking the connections fixed the issues and taught us about how analog inputs and digital outputs work together.

Week 9 – Analogue and Digital

Concept

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

For this assignment, I made a circuit that mimics the performance of solar-powered garden lights. The LED automatically turns on when the environment is dark and off when the environment is bright. I used a photoresistor  to sense the light around the environment and included a button for manual control, controlling the LED when the environment is dark. The LED automatically turns on when the light is low. If the button is pressed during darkness, the LED turns off but with a brief delay before turning on again. When there is enough ambient light, the LED turns off automatically.

Code Highlight (Arduino Code)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const int LED_PIN = 9; // LED that turns on in dark, or with button
const int LIGHT_SENSOR_PIN = A2; // Light sensor (photoresistor)
const int BUTTON_PIN = A3; // Button input (wired to GND)
const int LIGHT_THRESHOLD = 600; // Adjust based on your light conditions
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor
Serial.begin(9600); // Optional: monitor values for debugging
}
void loop() {
int light_value = analogRead(LIGHT_SENSOR_PIN);
int button_state = digitalRead(BUTTON_PIN);
Serial.print("Light: ");
Serial.print(light_value);
Serial.print(" | Button: ");
Serial.println(button_state);
if (light_value < LIGHT_THRESHOLD) {
// DARK: turn LED ON automatically
digitalWrite(LED_PIN, HIGH);
} else {
// BRIGHT: turn LED ON only if button is PRESSED (LOW)
if (button_state == LOW) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
}
delay(100); // Short delay to reduce flicker and serial flooding
}
const int LED_PIN = 9; // LED that turns on in dark, or with button const int LIGHT_SENSOR_PIN = A2; // Light sensor (photoresistor) const int BUTTON_PIN = A3; // Button input (wired to GND) const int LIGHT_THRESHOLD = 600; // Adjust based on your light conditions void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor Serial.begin(9600); // Optional: monitor values for debugging } void loop() { int light_value = analogRead(LIGHT_SENSOR_PIN); int button_state = digitalRead(BUTTON_PIN); Serial.print("Light: "); Serial.print(light_value); Serial.print(" | Button: "); Serial.println(button_state); if (light_value < LIGHT_THRESHOLD) { // DARK: turn LED ON automatically digitalWrite(LED_PIN, HIGH); } else { // BRIGHT: turn LED ON only if button is PRESSED (LOW) if (button_state == LOW) { digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); } } delay(100); // Short delay to reduce flicker and serial flooding }
const int LED_PIN = 9;             // LED that turns on in dark, or with button
const int LIGHT_SENSOR_PIN = A2;   // Light sensor (photoresistor)
const int BUTTON_PIN = A3;         // Button input (wired to GND)


const int LIGHT_THRESHOLD = 600;   // Adjust based on your light conditions


void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP); // Use internal pull-up resistor
  Serial.begin(9600); // Optional: monitor values for debugging
}


void loop() {
  int light_value = analogRead(LIGHT_SENSOR_PIN);
  int button_state = digitalRead(BUTTON_PIN);


  Serial.print("Light: ");
  Serial.print(light_value);
  Serial.print(" | Button: ");
  Serial.println(button_state);


  if (light_value < LIGHT_THRESHOLD) {
    // DARK: turn LED ON automatically
    digitalWrite(LED_PIN, HIGH);
  } else {
    // BRIGHT: turn LED ON only if button is PRESSED (LOW)
    if (button_state == LOW) {
      digitalWrite(LED_PIN, HIGH);
    } else {
      digitalWrite(LED_PIN, LOW);
    }
  }


  delay(100); // Short delay to reduce flicker and serial flooding
}

The code reads the amount of light from a sensor and controls an LED based on that. When it’s dark, the LED turns on automatically. When it’s bright, the LED turns off, but if the button is pressed, the LED will turn on even in the light. The button works like a manual override. There’s a small delay in the code to avoid flickering, and the system checks the light level regularly to adjust the LED accordingly.

 

Challenges

I faced several issues while working on this project. First, it was confusing to make the photoresistor function properly, especially to understand how to make the LED respond to light and darkness. I also struggled to set the correct light threshold so that the LED would turn on at the right time. Plugging in the photoresistor correctly was challenging, and I had to figure out how to use a voltage divider. When I added the button, it didn’t work at first because I didn’t know how to connect it through the internal pull-up resistor. I also had trouble coding to make the LED turn on automatically when it’s dark and just the button when light. It was a lot of trial and error to make everything work the way I desired.

 

Week 9 – Reading Responses

Physical Computing’s Greatest hits and misses

This article provides an intriguing perspective on consistent themes and what are some aspects needed to understand what is physical computing. The conversation about theremin-like devices as popular starter projects, highlighted by their ease of use with photocells or distance sensors, is logical, just as the description of glove-related initiatives like Megatap 3000, which are captivating because of their link to daily tasks. From the reading, I noticed that there exists a favorable bias toward initiatives that promote significant physical involvement and creativity, illustrated by the criticism of “hand-waving” interfaces compared to the commendation for more organized interactions such as drum gloves. The reading didn’t explicitly alter my beliefs, but it offered a more defined structure for examining prevalent patterns and design issues in interactive systems.

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

Tom Igoe’s discussion on interactive art show that creators ought to “prepare the environment, then remain silent and observe.” His case against pre-planned audience interpretation echoes student reflections, with some applying his concepts by eliminating directions from their projects or realizing that interactive art promotes open discussions instead of presenting a singular perspective. The comparison to guiding actors—where proposing intentions is acceptable but imposing emotions restricts authenticity—really suggests the notion that the audience should have room for their own true reaction. The text made me consider how interactive art can be practiced, similar to a performance, to enhance audience involvement without excessive guidance.

Week 8 – Reading Responses

Margaret Hamilton: Her Code on the Moon

Reading “Margaret Hamilton: Her Code on the Moon” deepened my understanding of her pioneering contributions to the Apollo program and the development of software engineering. What struck me is that the article highlights her leadership at MIT’s Instrumentation Laboratory and how it was vital for creating the software for the Apollo guidance computer. I was amazed by the vast scope of the Apollo project, involving more than 400 individuals working on the software by 1968, while Hamilton introduced important innovations such as priority displays and created the term “software engineering” to give credibility to the discipline. I’ve always thought software engineering could come from the Turing Test or other experiments involving web development but hearing it comes from the Apollo project surprised me. The article deepened my comprehension of a software’s essential function in space exploration and I wondered what programming techniques or coding languages were used back then.

Norman,“Emotion & Design: Attractive things work better”

This has taught me on how aesthetics impact not only perception but also functionality and problem-solving. The notion that appealing designs can enhance the perception of task simplicity by aiding cognitive processing is intriguing, yet I recognize how bad usability can occasionally negate that advantage—similar to Michael Graves’ “Nanna teapot,” which is aesthetically pleasing but often impractical. It made me reflect on how frequently I’ve assessed a product based on its look, only to find out later that appearance doesn’t necessarily indicate user-friendliness. The author’s story regarding early computer displays changing in perceived worth over time also caught my attention, demonstrating how aesthetics can influence our evaluations in ways we might not readily acknowledge. I think it’s intriguing to consider what occurs in the brain when appealing things lead individuals to feel more competent. This reading doesn’t exactly alter my opinions, but it enhanced my understanding of how emotion and design connect, particularly in fields such as human-computer interaction, where it is vital to balance aesthetics and functionality.

Week 8 – Unusual Switch

Concept

Link: https://drive.google.com/file/d/19TgW5BmcVSER1t9MUOYlwJh5GEUXzX6o/view?usp=sharing

For this assignment, I decided to create a simple light-controlled system using a homemade pressure switch (A foot pedal). This is because I was curious to learn how basic, mundane materials like paper could be used to create an operational input device without using typical components like push buttons. By including this on the Arduino Uno, I could turn an LED on and off with a physical press, demonstrating how simple materials around the house can be repurposed to create interactive electronics projects.

Arduino Code

I changed the original Arduino “Blink” code to make the light not turn on and off by itself, but only turn on when I trigger it using my paper and copper tape switch:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int buttonPin = 2;
int ledPin = 13;
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // Enables internal pull-up resistor
pinMode(ledPin, OUTPUT);
}
void loop() {
if (digitalRead(buttonPin) == LOW) {
digitalWrite(ledPin, HIGH); // LED ON when pressed
} else {
digitalWrite(ledPin, LOW); // LED OFF when released
}
}
int buttonPin = 2; int ledPin = 13; void setup() { pinMode(buttonPin, INPUT_PULLUP); // Enables internal pull-up resistor pinMode(ledPin, OUTPUT); } void loop() { if (digitalRead(buttonPin) == LOW) { digitalWrite(ledPin, HIGH); // LED ON when pressed } else { digitalWrite(ledPin, LOW); // LED OFF when released } }
int buttonPin = 2;
int ledPin = 13;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Enables internal pull-up resistor
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (digitalRead(buttonPin) == LOW) {
    digitalWrite(ledPin, HIGH); // LED ON when pressed
  } else {
    digitalWrite(ledPin, LOW);  // LED OFF when released
  }
}

 

I connected the switch to one of the Arduino’s pins that has the ability to sense if something is being touched. I also used a built-in function that helps the Arduino become aware when the switch is not being pressed. In the code, I instructed the Arduino to switch the light on when the switch is triggered, and off when it’s not. This ensures that the light will switch on directly due to my homemade pressure switch (A foot pedal).

Challenges

One of the main challenges was creating a functioning switch without a supply of crocodile clips, actual push buttons, or normal conductive material. I used paper, copper tape, and jumper wires with some trial and error to develop consistent electrical connection. Getting the copper strips into perfect alignment and holding them together in use took some experimentation. Also, getting a grasp on how to utilize the internal pull-up resistor is necessary to prevent false firing and ensure that the switch is reliable.

Midterm Project

Concept

Link to Sketch: https://editor.p5js.org/sa8831/sketches/R-3aQof8X

Inspired by a small app I made during high school (Refer to the blog about Midterm progress),  I decided that for the upcoming midterm project, to create an interactive visual novel game. The game takes place in a school of “The Periodic Table” where chemical elements are personified as classmates and teachers. Throughout the game, the user plays as a personified version of Carbon meets other elements like Hydrogen and oxygen to discuss who they are. However, there are 2 endings to this game, where after interacting with either characters, each gets a different ending and a different activity.

How the game works:

How the Periodic Table Academy Game Works (Updated Version):

  • Starting the Game:
    • When the game starts, a title screen with a Play button appears. Upon clicking the Play button, the game transitions to the instruction screen.
    • Instructions are displayed, welcoming the player to the Periodic Table Academy and explaining that the player can click the Play button again to begin the game. The player is presented with two characters to interact with: Oxygen and Hydrogen. The characters are displayed on the screen, and the player can choose who to talk to by selecting an option like “Talk to Oxygen” or “Talk to Hydrogen”.
    • If the player chooses to talk to Oxygen, they enter the oxygen-talk state. Oxygen responds with different dialogue options like:
      • How are you?
      • Tell me about yourself
      • Bye
    • Based on the selected option, the game displays different responses from Oxygen, with the dialogue box updating each time.
    • If the player selects “Bye”, the game moves into a cutscene where Oxygen says goodbye, and then the game transitions to one of the endings after a short delay (CO2).Hydrogen’s Dialogue:
      • Similarly, if the player chooses to talk to Hydrogen, they enter the hydrogen-talk state. Hydrogen responds with dialogue options such as:
        • How are you?
        • Tell me about yourself
        • Bye
      • The game progresses similarly as with Oxygen, with the player receiving different responses from Hydrogen.
      • Selecting “Bye” leads to a cutscene where Hydrogen says goodbye, followed by a transition to another ending (C-H).

 

Endings:

        • There are two possible endings:
          • CO2 (Carbon Dioxide): If the player interacts with Oxygen, they receive the CO2 ending. The game then displays a message congratulating the player for making CO2.
          • C-H (Hydrocarbon): If the player interacts with Hydrogen, they receive the Hydrocarbon ending. The game congratulates the player for making Hydrocarbons.Interactive Ending:
            • During the ending state, the player can click around the screen to generate particles that represent either CO2 or Hydrocarbons depending on the ending.
            • Particles are displayed on the screen, and each particle shows a label (either “CO2” or “C-H”) as it moves upward. These particles are generated when the player clicks anywhere on the screen.

Game Design

I initially wanted to draw a personified Carbon and allow the user to move using keys A and D to include a walking animation, to go either direction to the characters. However, due to breaking the screen and difficulty to link my spritesheet with the character, I removed that idea but instead made it inspired by the game Undertale:

Undertale Part #12 - Dating Start!

(inspiration for the dialogue)

In addition to this, the endings involves particles that resembles a “bond” between 2 characters. I aim for the particles to represent the compounds for reacting Carbon with either Oxygen or Hydrogen to create molecules (like C-H or Hydrocarbons, and Carbon Dioxide or CO2).

 

Highlights/ Challenges:
The highlights of this would be this snippet:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Particle Class
class Particle {
constructor(x, y, text) {
this.x = x;
this.y = y;
this.size = random(20, 50);
this.text = text;
this.ySpeed = random(-2, -1);
}
move() {
this.y += this.ySpeed; // Move upward
}
display() {
fill('#ADD8E6');
noStroke();
ellipse(this.x, this.y, this.size);
fill(255);
textSize(this.size / 2);
text(this.text, this.x, this.y);
}
}
// Generate particles on click
function mousePressed() {
if (state === 'ending') {
let newParticle = new Particle(mouseX, mouseY, endingType);
particles.push(newParticle);
}
}
// Particle Class class Particle { constructor(x, y, text) { this.x = x; this.y = y; this.size = random(20, 50); this.text = text; this.ySpeed = random(-2, -1); } move() { this.y += this.ySpeed; // Move upward } display() { fill('#ADD8E6'); noStroke(); ellipse(this.x, this.y, this.size); fill(255); textSize(this.size / 2); text(this.text, this.x, this.y); } } // Generate particles on click function mousePressed() { if (state === 'ending') { let newParticle = new Particle(mouseX, mouseY, endingType); particles.push(newParticle); } }
// Particle Class
class Particle {
  constructor(x, y, text) {
    this.x = x;
    this.y = y;
    this.size = random(20, 50);
    this.text = text;
    this.ySpeed = random(-2, -1);
  }

  move() {
    this.y += this.ySpeed; // Move upward
  }

  display() {
    fill('#ADD8E6');
    noStroke();
    ellipse(this.x, this.y, this.size);
    fill(255);
    textSize(this.size / 2);
    text(this.text, this.x, this.y);
  }
}

// Generate particles on click
function mousePressed() {
  if (state === 'ending') {
    let newParticle = new Particle(mouseX, mouseY, endingType);
    particles.push(newParticle);
  }
}

Because of clicking around the ending screen to get the needed “molecule” for each ending.

However, the challenges involves the following:

  1. Ensuring smooth user interaction with the character dialogues was challenging, especially with different choices for interactions such as “How are you?”, “Tell me about yourself?”, and “Bye.”
    • I structured the dialogue system using buttons that allow for straightforward user input. This kept the interactions clean, with each character giving distinct options based on the user’s previous choices. This helped in providing a more guided yet flexible experience.
  2. Since I wanted to integrate Object-Oriented Programming, handling multiple characters (Oxygen and Hydrogen) with unique behaviors, interactions, and background transitions was tricky, especially with the game requiring seamless transitions from one scene to another.
    • I utilized OOP principles to create classes for characters, backgrounds, and game states. This allowed for easy management of multiple elements interacting with each other, while ensuring that transitions and character interactions felt fluid and natural. The background changed dynamically as Carbon moved, which helped convey the progression of the game.
  3. Another challenge was implementing multiple endings depending on which character the player interacts with first and ensuring the game could be easily restarted without refreshing the page.
    • I included an instruction screen and a restart button after each ending. To handle game state management, I kept track of the character interactions and ensured the game’s ending sequences could be triggered based on the order of choices. The restart button was designed to reset the game state while keeping the experience accessible without needing to reload the page.
  4. The game’s concept of displaying chemistry information such as oxygen bonding with carbon, and visual representations of molecules like CO2 and hydrocarbons, needed to be both educational and engaging.
    • I decided to keep the visual representations simple, using floating shapes and rain animations to visually communicate the chemical reactions. This allowed players to understand the results of their choices (CO2 and hydrocarbons) in a non-overwhelming way.

Improvements

  • Enhancing Character Interactions:

    • Add more diverse dialogue options that react to previous choices, making conversations more personalized and dynamic.
  • Expanding the Periodic Table Academy Environment:

    • Introduce additional elements from the periodic table with unique interactions, personalities, and visual effects.
    • Create puzzles or mini-games based on chemical properties to increase educational value.
  • Improved Visual Effects for Chemical Reactions:

    • Implement particle effects, such as glowing or color-changing molecules when bonding occurs, to enhance visual appeal and illustrate chemical reactions more vividly.

Week 5 – Reading Response

Computer vision also differs from human vision in that it doesn’t “see” like humans do—it reads images as raw pixel data without reference to context or meaning. Where humans intuitively see objects, emotions, and intent, computers need algorithms to define patterns, edges, and movement. We naturally adjust for differences in light, angle, or occlusions, but computer vision generally needs to be programmed further to compensate. Humans also employ depth perception and prior knowledge to make sense of 3D space, while computers typically work on 2D images and need additional techniques like stereo cameras or depth sensors to estimate depth.

So that computers can more easily track what we’re interested in, we use techniques like frame differencing ( movement by detecting differences between frames of video), background subtraction (new objects are highlighted against a static scene), and brightness thresholding (objects are highlighted based on light contrast). More advanced techniques include edge detection, feature tracking, and deep learning algorithms that can detect faces, gestures, or objects. For interactive art, computer vision is frequently utilized by artists to explore themes of control and visibility, as seen in works like Sorting Daemon and Suicide Box.