Assignment 11: Serial Communication

For this week’s assignment, we were asked to complete the three examples we had been tasked with during class. This week’s work was a learning curve on its own. It took a while to get the hang of connecting P5.js and Arduino together after using them both as seperate entities, but seeing them connected was really exciting.

Task 1 – make something that uses only one sensor on Arduino and makes the ellipse in p5 move on the horizontal axis

For this task, I used a potentiometer to get analogue values, then mapped them onto my P5 canvas to make the ellipse move

P5 code:

let serial; // variable for the serial object
let latestData = "waiting for data"; // variable to hold the data

function setup() {
  createCanvas(400, 400);
  // serial constructor
  serial = new p5.SerialPort();

  // serial port
  serial.open('COM6');

  // what to do when we get serial data
  serial.on('data', gotData);

}

// when data is received in the serial buffer

function gotData() {
  let currentString = serial.readLine(); // store the data in a variable
  trim(currentString); // get rid of whitespace
  if (!currentString) return; // if there's nothing in there, ignore it
  console.log(currentString); // print it out
  latestData = currentString; // save it to the global variable
}

function draw() {
  background(255, 255, 255);
  fill(0, 0, 0);
  text(latestData, 10, 10); // print the data to the sketch

  // using the recieved data to change the x value of the circle 
  let moveHorizontal = map(latestData, 0, 1023, 0 , width);
  ellipse(moveHorizontal, height/2, 100, 100);


}

Arduino code:

const int ledPin = 3;      // the pin that the LED is attached to

void setup() {
  // initialize the serial communication:
  Serial.begin(9600);
  // initialize the ledPin as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int brightness;

  // check if data has been sent from the computer:
  if (Serial.available() > 0) {
    // read the most recent byte (which will be from 0 to 255):
    brightness = Serial.read();
    // set the brightness of the LED:
    analogWrite(ledPin, brightness);
  }
}

Arduino schematic:

Task 2 – make something that controls the LED brightness from P5

For this task, I created a gradient background on P5, then used the mouseDragged() function to map it onto the LED connected on the Arduino

P5 code:

let serial; // variable for the serial object
let bright = 0; // variable to hold the data we're sending
let dark, light; // variables to hold the bgcolor

function setup() {
  createCanvas(512, 512);
  // colors for a blue gradient
  dim = color(0, 191, 255 );  // light blue
  bright = color(0, 0, 128);  // dark blue

  // serial constructor
  serial = new p5.SerialPort();

  // serial port
  serial.open('COM6');
}

function draw() {
  // Create a vertical blue gradient
  for (let y = 0; y < height; y++) {
    // Directly map the y position to the blue color
    let c = map(y, 0, height, dim.levels[2], bright.levels[2]);  // Map blue values from dark to light
    stroke(c, c, 255);  // Set color to blue, vary based on y position
    line(0, y, width, y);
  }

  stroke(255);
  strokeWeight(3);
  noFill();
  ellipse(mouseX, mouseY, 10, 10);
}

function mouseDragged() { // mapping the brightness level based on the position of the mouse
  brightLevel = floor(map(mouseY, 0, 512, 0, 255));
  // ensuring the brightness level does not exceed the level possible for the LED
  brightLevel = constrain(brightLevel, 0, 255);
  serial.write(brightLevel);
  console.log(brightLevel);
}

Arduino code:

const int ledPin = 13;  // Pin where the LED is connected
const int windSensorPin = A0;  // Pin for the analog wind sensor
int sensorValue = 0;

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

void loop() {
  // Check if there is incoming serial data
  if (Serial.available() > 0) {
    char incomingByte = Serial.read();  // Read incoming byte

    if (incomingByte == 'O') {
      digitalWrite(ledPin, HIGH);  // Turn LED ON
    } else if (incomingByte == 'F') {
      digitalWrite(ledPin, LOW);  // Turn LED OFF
    }
  }

  // Read the wind sensor value (adjust if needed)
  sensorValue = analogRead(windSensorPin);
  // Optionally, print the sensor value for debugging
  Serial.println(sensorValue);
  delay(100);
}

Arduino schematic:

Task 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

For this task, I used a potentiometer on the Arduino to send analogue values for the wind in the P5 example. I struggled with having the LED light up in time with the ball bounces, but I ended up using an IF statement within the draw() function which would then send a HIGH or LOW voltage value back to the Arduino

P5 code:

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

// new variables added
let windSensorValue = 0;
let serial; 
let latestData = "0"; 
let ledState = false; // true = on, false = off

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 up the serial port
  serial = new p5.SerialPort();
  serial.open('COM6'); 
  serial.on('data', serialEvent);
}
// Arduino data is stored inside the variable latestData
function serialEvent() {
  let incoming = serial.readLine();
  if (incoming.length > 0) {
    latestData = incoming; 
  }
}

function draw() {
  background(255);

  // reading the Potentiometer value
  // mapping the potentiometer value to wind (either left or right)
  let sensorValue = int(latestData);
  wind.x = map(sensorValue, 0, 1023, -5, 5);

  applyForce(wind);
  applyForce(gravity);
  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);

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

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

    // If touching ground and LED not already on
    if (!ledState) {
      serial.write('H');  // Turn LED on
      ledState = true;
    }
  } else {
    // If in air and LED is on, turn it off
    if (ledState) {
      serial.write('L');  // Turn LED off
      ledState = false;
    }
  }
}

function applyForce(force) {
  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);
  }
}

Arduino code:

const int ledPin = 13;  // LED on pin 13
const int sensorPin = A0; // analog sensor connected to A0

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

void loop() {
  // Read analog sensor
  int sensorValue = analogRead(sensorPin);
  Serial.println(sensorValue);
  delay(50); // small delay 

  // Check for incoming commands
  if (Serial.available() > 0) {
    char command = Serial.read();
    if (command == 'H') {
      digitalWrite(ledPin, HIGH);
    } else if (command == 'L') {
      digitalWrite(ledPin, LOW);
    }
  }
}

Arduino schematic:

Link to Video

Leave a Reply