Assignment 8: Handshake Exercises

Partner: Hyein Kim

EXERCISE 01: ARDUINO TO P5 COMMUNICATION: 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.

To complete this exercise, we built a simple circuit as illustrated below. We used the photocell to control the horizontal movement of the ball in p5.

Exercise 1 Illustration

As it is shown in the code for Arduino, most of it is similar to that of the one provided to the class. The things we changed are mostly done inside the void loop(). Since the Arduino is sending information to p5, we readjusted the code so that data is sent unidirectionally to p5: the value collected in A0 from the photocell is sent to p5.

Arduino code:

int leftLedPin = 2;
int rightLedPin = 5;


void setup() {
 // Start serial communication so we can send data
 // over the USB connection to our p5js sketch
 Serial.begin(9600);


 // We'll use the builtin LED as a status output.
 // We can't use the serial monitor since the serial connection is
 // used to communicate to p5js and only one application on the computer
 // can use a serial port at once.
 pinMode(LED_BUILTIN, OUTPUT);


 // Outputs on these pins
 pinMode(leftLedPin, OUTPUT);
 pinMode(rightLedPin, OUTPUT);


 // Blink them so we can check the wiring
 digitalWrite(leftLedPin, HIGH);
 digitalWrite(rightLedPin, HIGH);
 delay(200);
 digitalWrite(leftLedPin, LOW);
 digitalWrite(rightLedPin, LOW);


 // start the handshake
 while (Serial.available() <= 0) {
   digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
   Serial.println("0,0"); // send a starting message
   delay(300);            // wait 1/3 second
   digitalWrite(LED_BUILTIN, LOW);
   delay(50);
 }
}


void loop() {
 // wait for data from p5 before doing something
     int sensor = analogRead(A0);
     delay(5);
     Serial.println(sensor);
 }

On p5, we drew an ellipse and initialized a variable ‘xposition’ that is used to move the horizontal position of the ball. Then under ‘if (data != null) {}’, we set the xposition = data where data refers to the value that is collected and sent from Arduino. This data is used to change the xposition of the ball in p5. 

p5 code:

let rVal = 0;
let alpha = 255;
let xposition = 100;


function setup() {
  createCanvas(640, 480);
  textSize(18);
}


function draw() {
  // one value from Arduino controls the background's red color
  background(map(rVal, 0, 1023, 0, 255), 255, 200);


  ellipse(xposition, height/2, 50, 50);
  
  // the other value controls the text's transparency value
  fill(255, 0, 255, map(alpha, 0, 1023, 0, 255));


  if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    text("Connected", 20, 30);
    // Print the current values
    text('rVal = ' + str(rVal), 20, 50);
    text('alpha = ' + str(alpha), 20, 70);
  }


function keyPressed() {
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}


// This function will be called by the web-serial library
// with each new *line* of data. The serial library reads
// the data until the newline and then gives it to us through
// this callback function
function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////


  if (data != null) {
    // make sure there is actually a message
    // split the message
    xposition = data;
    }


    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    let sendToArduino = left + "," + right + "\n";
    writeSerial(sendToArduino);
  }

EXERCISE 02: P5 TO ARDUINO COMMUNICATION: Make something that controls the LED brightness from p5.

For this exercise, we utilized the position of mouseX from p5 to control the brightness of the LED on Arduino. The circuit we made looks like this: 

circuit 2

Exercise 2 Illustration

Here, Arduino receives information from p5 and changes the brightness of the LED. Under void loop(), we used the map function to convert the values to PWM range and used analogWrite to set the LED brightness according to the value received from p5. 

Arduino Code:

int LEDpin = 3;  // Ensure this pin supports PWM
void setup() {
 Serial.begin(9600);
 pinMode(LED_BUILTIN, OUTPUT);
 pinMode(LEDpin, OUTPUT);


 // Initial blink to confirm working setup
 digitalWrite(LEDpin, HIGH);
 delay(200);
 digitalWrite(LEDpin, LOW);


 // Wait for initial data before proceeding
 while (Serial.available() <= 0) {
   digitalWrite(LED_BUILTIN, HIGH);  // Blink LED to indicate waiting for connection
   Serial.println("0,0");  // Send a starting message
   delay(300);
   digitalWrite(LED_BUILTIN, LOW);
   delay(50);
 }
}


void loop() {
 if (Serial.available() > 0) {
   digitalWrite(LED_BUILTIN, HIGH);  // LED on while receiving data
   int bright = Serial.parseInt();
   bright = map(bright, 0, 640, 0, 255);  // Adjust received value to PWM range


   if (Serial.read() == '\n') {
     analogWrite(LEDpin, bright);  // Set LED brightness
   }
   digitalWrite(LED_BUILTIN, LOW);  // Turn off status LED after handling data
   Serial.println(0);
 }
}

In p5, we used mouseX and its position on the canvas to control the brightness of the LED on Arduino. We initialized a variable LEDbright to 0 but then let it change according to the if statement. If mouseX <= width && mouseX >= 0 && mouseY <= height && mouseY >= 0 , then the variable LEDbright is mouseX and this data is then sent to Arduino which controls the brightness of the LED. However, if the condition is not satisfied, then the variable LEDbright remains 0. Simply put, the LED lights up brighter when the mouse is on the right side of the screen and dimmer when it is on the left side of the screen. 

p5 code:

let LEDbright = 0;

function setup() {
  createCanvas(640, 480);
  textSize(18);
}

function draw() {
  
  background(205);

  // the other value controls the text's transparency value
  fill(0)

  if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    text("Connected", 20, 30);

  }

  // when clicked, digital LED will turn on,
  // other analog write LED will have brightness corresponding to the height of the mouse when it is press. can be pressed and dragged for controlling brightness
  if (mouseX <= width && mouseX >= 0 && mouseY <= height && mouseY >= 0) {
      LEDbright = mouseX;
  } else {
    LEDbright = 0;
  }
}

function keyPressed() {
  if (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}

function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////

    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    
    //send the posiiton of mouseY when clicked to control brightness
    let sendToArduino = LEDbright + "\n";
    writeSerial(sendToArduino);

}

EXERCISE 03: BI-DIRECTIONAL COMMUNICATION: 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.

To complete this assignment, we used a potentiometer as an input to control wind and an LED as an output controlled by the bouncing ball in p5.js.

Exercise 3 Illustration

p5 code:

let velocity;
let gravity;
let position;
let acceleration;
let wind;
let drag = 0.99;
let mass = 50;
let light = 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);
}

function draw() {
  background(255);
  applyForce(wind);
  applyForce(gravity);
  velocity.add(acceleration);
  velocity.mult(drag);
  position.add(velocity);
  acceleration.mult(0);
  fill('black')
  
   if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    ellipse(position.x,position.y,mass,mass);
  if (position.y > height-mass/2) {
      velocity.y *= -0.9;  // A little dampening when hitting the bottom
      position.y = height-mass/2;
    light=1
    
    }
    else{
      light=0
    }
  }
}

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 (key == " ") {
    // important to have in order to start the serial connection!!
    setUpSerial();
  }
}


function readSerial(data) {
  ////////////////////////////////////
  //READ FROM ARDUINO HERE
  ////////////////////////////////////

  if (data != null) {
    // make sure there is actually a message
    // split the message
    let fromArduino = split(trim(data), ",");
    // if the right length, then proceed
    if (fromArduino.length == 1) {
      // only store values here
      // do everything with those values in the main draw loop
      
      // We take the string we get from Arduino and explicitly
      // convert it to a number by using int()
      // e.g. "103" becomes 103
      
      let sensorValue = int(fromArduino[0]);
      wind.x = map(sensorValue, 0, 1023, -1, 1);
    }
    }
    

    //////////////////////////////////
    //SEND TO ARDUINO HERE (handshake)
    //////////////////////////////////
    let sendToArduino = light + "\n";
    writeSerial(sendToArduino);
  }

Arduino code:

int LEDpin = 2;
int wind = A0;

void setup() {
  // Start serial communication so we can send data
  // over the USB connection to our p5js sketch
  Serial.begin(9600);

  // We'll use the builtin LED as a status output.
  // We can't use the serial monitor since the serial connection is
  // used to communicate to p5js and only one application on the computer
  // can use a serial port at once.
  pinMode(LED_BUILTIN, OUTPUT);

  // Outputs on these pins
  pinMode(LEDpin, OUTPUT);
  pinMode(wind, INPUT);


  // start the handshake
  while (Serial.available() <= 0) {
    digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data
    Serial.println("0,0"); // send a starting message
  }
}

void loop() {
  // wait for data from p5 before doing something
  while (Serial.available()) {
    digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data

    int light = Serial.parseInt();
    if (Serial.read() == '\n') {
      digitalWrite(LEDpin, light);
      int sensor = analogRead(A0);
      delay(5);
      Serial.println(sensor);
    }
  }
  digitalWrite(LED_BUILTIN, LOW);
}

To briefly explain this code, every time the ball hits the ground, the variable ‘light’ is set to 1. If this is not the case, ‘light’ is set to 0.

if (!serialActive) {
    text("Press Space Bar to select Serial Port", 20, 30);
  } else {
    ellipse(position.x,position.y,mass,mass);
  if (position.y > height-mass/2) {
      velocity.y *= -0.9;  // A little dampening when hitting the bottom
      position.y = height-mass/2;
    light=1
    
    }
    else{
      light=0
    }
  }
}

Then, p5.js sends the value of ‘light’ to the Arduino.

let sendToArduino = light + "\n";
    writeSerial(sendToArduino);

When the Arduino receives the light value from p5.js, it turns on if the value is 1 and turns off if the value equals 0.

int light = Serial.parseInt();
    if (Serial.read() == '\n') {
      digitalWrite(LEDpin, light);

To control the wind value, if the length of the data sensed by the Arduino is equal to 1, p5.js receives the data value of the potentiometer. We then use the map function to convert the analog input value from 0 to 1023 to a range of -1 to 1.

if (data != null) {
   // make sure there is actually a message
   // split the message
   let fromArduino = split(trim(data), ",");
   // if the right length, then proceed
   if (fromArduino.length == 1) {
     // only store values here
     // do everything with those values in the main draw loop
     
     // We take the string we get from Arduino and explicitly
     // convert it to a number by using int()
     // e.g. "103" becomes 103
     
     let sensorValue = int(fromArduino[0]);
     wind.x = map(sensorValue, 0, 1023, -1, 1);
   }
   }

 

 

Leave a Reply