Conceptualization:
The central idea was to build a simple connection between physical and digital worlds.
Exercise 1: Single-Sensor and p5.js Movement
Using only one analog sensor (a potentiometer), the Arduino continuously reads values and streams them to p5.js over serial. p5.js interprets those readings and moves an ellipse along the horizontal axis, keeping it vertically centered.
// exercise 1
void setup() {
Serial.begin(9600);
// wait for p5 to connect
while (Serial.available() <= 0) {
Serial.println("0,0");
delay(300);
}
}
void loop() {
// wait for data from p5
while (Serial.available()) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.read(); // read incoming
int sensorValue = analogRead(A0); // read sensor
Serial.println(sensorValue); // send sensor value
}
digitalWrite(LED_BUILTIN, LOW);
}
P5js: https://editor.p5js.org/aka7951/sketches/alRawYdiF
Demo https://drive.google.com/file/d/1Morf2y7cxIAgYLHKVnitsadjr813cX4Z/view?usp=sharing
Exercise 2: LED Brightness Controlled by p5.js
Next, I reversed the flow. Instead of only reading from Arduino, I sent numerical values from p5.js back to the board so it could adjust LED brightness using PWM.
int ledPin = 9;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
// Wait for p5 connection
while (Serial.available() <= 0) {
digitalWrite(LED_BUILTIN, HIGH);
delay(300);
digitalWrite(LED_BUILTIN, LOW);
delay(300);
}
}
void loop() {
if (Serial.available() > 0) {
int brightness = Serial.parseInt(); // Read brightness value from p5
analogWrite(ledPin, brightness); // Set LED brightness
if (Serial.read() == '\n') {
digitalWrite(LED_BUILTIN, LOW);
}
}
}
P5js: https://editor.p5js.org/aka7951/sketches/tQoRTseMj
Demo: https://drive.google.com/file/d/1rdLpd3JG87jDa9bJEWZWtLMIvA9Ub0Vg/view?usp=sharing
Exercise 3: Gravity + Wind Integration
Finally, I modified the p5.js gravity wind sketch. Each time the ball hits the “ground,” p5 sends a signal to Arduino, turning an LED on briefly before switching back off. Meanwhile, an analog sensor feeds continuous data to p5.js to influence the wind force acting on the falling ball.
int ledPin = 5;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
// wait for p5 to connect
while (Serial.available() <= 0) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("0");
delay(300);
digitalWrite(LED_BUILTIN, LOW);
delay(50);
}
}
void loop() {
while (Serial.available()) { //check if there's data from p5
digitalWrite(LED_BUILTIN, HIGH);
int ledValue = Serial.parseInt(); //read LED value from p5 (0 or 1)
if (Serial.read() == '\n') { // check for newline character
digitalWrite(ledPin, ledValue);
int sensorValue = analogRead(A0); // read potentiometer value
Serial.println(sensorValue); // send sensor value back to p5
}
}
digitalWrite(LED_BUILTIN, LOW);
}
P5js: https://editor.p5js.org/aka7951/sketches/ze7W5LcOi
Demo: https://drive.google.com/file/d/1c0O6wrqE6aStFpg9cvYVOke0zxojdR4Z/view?usp=sharing
Reflection & Challenges:
This project helped me practice the bidirectional serial communication between Arduino and p5.js. One difficulty came from synchronizing input and output flows. In Exercises 2 and 3, sending and receiving serial data simultaneously often led to mixed or incomplete values being parsed. I learned to structure the serial communication carefully — ensuring each transmission ended with a newline and that both ends only read or wrote when data was available.

