For this week’s assignment, Zeina and I worked on three different exercises that focused on serial communication.
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
ARDUINO CODE
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A1); // 0–1023
Serial.println(sensorValue); // send to p5.js
delay(50);
}
P5 CODE
let port;
let connectBtn;
let baudrate = 9600;
let lastMessage = "";
let sensorValue = 0;
function setup() {
createCanvas(400, 400);
background(220);
//Setting the global variable port to a new serial port instance inside setup:
port = createSerial();
// we can open ports we have used previously without user interaction
let usedPorts = usedSerialPorts(); //array of used ports
if (usedPorts.length > 0) {
port.open(usedPorts[0], baudrate); //if any used port is in the array, open that port with 9600 baudrate
}
// any other ports (new ones) can be opened via a dialog after user interaction (see connectBtnClick below)
connectBtn = createButton("Connect to Arduino");
connectBtn.position(width/2, 270);
connectBtn.mousePressed(connectBtnClick);
}
function draw() {
background("white");
// Read from the serial port. This is a non-blocking function. If a full line has come in (ending in \n), it returns that text. If the full line is not yet complete, it returns an empty string "" instead.
let str = port.readUntil("\n");
if (str.length > 0) { // if str -a string- has any characters
// print(str);
lastMessage = str;
sensorValue = int(lastMessage);
}
//draw ellipse mapped to horizontal axis
let x = map(sensorValue, 0, 1023, 0, width);
ellipse(x, height / 2, 40, 40);
// Display the most recent message
text("Last message: " + lastMessage, 10, height - 20);
// change button label based on connection status
if (!port.opened()) {
connectBtn.html("Connect to Arduino");
} else {
connectBtn.html("Disconnect");
}
}
function connectBtnClick() {
if (!port.opened()) {
port.open("Arduino", baudrate);
} else {
port.close();
}
}
2-Make something that controls the LED brightness from p5
DEMO
ARDUINO CODE
// Week 12 Example of bidirectional serial communication
int leftLedPin = 2;
int rightLedPin = 5;
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(leftLedPin, OUTPUT);
pinMode(rightLedPin, OUTPUT);
digitalWrite(leftLedPin, HIGH);
digitalWrite(rightLedPin, HIGH);
delay(200);
digitalWrite(leftLedPin, LOW);
digitalWrite(rightLedPin, LOW);
while (Serial.available() <= 0) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("0,0");
delay(300);
digitalWrite(LED_BUILTIN, LOW);
delay(50);
}
}
void loop() {
while (Serial.available()) {
digitalWrite(LED_BUILTIN, HIGH);
int left = Serial.parseInt();
int right = Serial.parseInt();
if (Serial.read() == '\n') {
// -----------------------
// ONLY CHANGE IS HERE:
// -----------------------
digitalWrite(leftLedPin, left); // left stays ON/OFF
analogWrite(rightLedPin, right); // right is now BRIGHTNESS (0–255)
// -----------------------
int sensor = analogRead(A0);
delay(5);
int sensor2 = analogRead(A1);
delay(5);
Serial.print(sensor);
Serial.print(',');
Serial.println(sensor2);
}
}
digitalWrite(LED_BUILTIN, LOW);
}
p5 CODE
let port; // making a var to hold the serial port
let baudrate = 9600; // speed for talking to arduino
let brightnessSlider; // slider to pick brightness
let smoothBrightness = 0; //transition into the brightness instead of jumping
function setup() {
createCanvas(400, 200); // just making a small canvas for ui
textSize(18); // bigger test
brightnessSlider = createSlider(0, 255, 0); // slider from 0 to full bright
brightnessSlider.position(20, 80); // where it shows up on screen
brightnessSlider.style('width', '200px'); // make it a bit wider
port = createSerial(); // create a serial object so we can connect to arduino
let used = usedSerialPorts(); // check if we already used a port before
if (used.length > 0) {
port.open(used[0], baudrate); // auto connect to the last used port
}
}
function setupSerial() {
if (!port.opened()) { // if no connection yet
port.open("Arduino", baudrate); // try to open one
} else {
port.close(); // if already open then close it (toggle)
}
}
function draw() {
background(240); // light grey
if (!port.opened()) {
text("Press SPACE to connect", 20, 30); // tell the user what to do
} else {
text("Connected!", 20, 30); // connection message
}
let target = brightnessSlider.value(); // get the slider value
// do transitional brightness
smoothBrightness = lerp(smoothBrightness, target, 0.07);
text("Brightness: " + int(smoothBrightness), 20, 70); // show the number
// actually send the brightness to the arduino
if (port.opened()) {
let sendString = "0," + int(smoothBrightness) + "\n"; // left=0 right=smooth
port.write(sendString); // send it over serial
}
}
function keyPressed() {
if (key === " ") {
setupSerial(); // hitting space toggles the port connection
}
}
3-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
void setup() {
pinMode(2, OUTPUT);
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A1);
Serial.println(sensorValue);
//check for bounce
if (Serial.available() > 0) {
//if 1, light up led
if (Serial.parseInt() == 1) {
digitalWrite(2, HIGH);
delay(100);
digitalWrite(2, LOW);
}
}
delay(10);
}
P5.JS CODE
let velocity;
let gravity;
let position;
let acceleration;
let wind;
let drag = 0.99;
let mass = 50;
let port;
let connectBtn;
let baudrate = 9600;
let lastMessage = "";
let sensorValue = 0;
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);
//Setting the global variable port to a new serial port instance inside setup:
port = createSerial();
// we can open ports we have used previously without user interaction
let usedPorts = usedSerialPorts(); //array of used ports
if (usedPorts.length > 0) {
port.open(usedPorts[0], baudrate); //if any used port is in the array, open that port with 9600 baudrate
}
// any other ports (new ones) can be opened via a dialog after user interaction (see connectBtnClick below)
connectBtn = createButton("Connect to Arduino");
connectBtn.position(width/2, 270);
connectBtn.mousePressed(connectBtnClick);
}
function draw() {
background(255);
// Read from the serial port. This is a non-blocking function. If a full line has come in (ending in \n), it returns that text. If the full line is not yet complete, it returns an empty string "" instead.
let str = port.readUntil("\n");
if (str.length > 0) { // if str -a string- has any characters
// print(str);
lastMessage = str.trim();
sensorValue = int(lastMessage);
}
//wind controlled by analog sensor
wind.x = map(sensorValue, 0, 1023, -1, 1);
console.log("Sensor value: " + sensorValue);
applyForce(wind);
applyForce(gravity);
velocity.add(acceleration);
velocity.mult(drag);
position.add(velocity);
acceleration.mult(0);
ellipse(position.x, position.y, mass, mass);
// Bounce detection
if (position.y > height - mass / 2) {
velocity.y *= -0.9; // Dampening
position.y = height - mass / 2;
//send bounce signal to Arduino
port.write("1\n");
}
// Display the most recent message
text("Last message: " + lastMessage, 10, height - 20);
// change button label based on connection status
if (!port.opened()) {
connectBtn.html("Connect to Arduino");
} else {
connectBtn.html("Disconnect");
}
}
function applyForce(force){
// Newton's 2nd law: F = M * A
// or A = F / M
let f = p5.Vector.div(force, mass);
acceleration.add(f);
}
function keyPressed(){
if (keyCode==LEFT_ARROW){
wind.x=-1;
}
if (keyCode==RIGHT_ARROW){
wind.x=1;
}
if (key==' '){
mass=random(15,80);
position.y=-mass;
velocity.mult(0);
}
}
function connectBtnClick() {
if (!port.opened()) {
port.openDialog(); // user selects port
} else {
port.close();
}
}