ARDUINO ↔ P5.JS
Week 08 - 10/26/2022
Serial IMU Output to p5.js | p5.webserial
p5.webserial is more direct and easier to use, however it only works in Chrome or Edge. One of the advantages is that it does not need a third-party application (such as p5.serialcontrol from Week07’s lab) to communicate with Arduino.
In the first part of the lab, I focused on reading the Internal Motion Unit (IMU), which is a nano 33 Iot built-in sensor and translating to p5.js in order to determine its heading, pitch, and roll.
const int buttonPin = 2; // digital input
void setup() {
// configure the serial connection:
Serial.begin(9600);
// configure the digital input:
pinMode(buttonPin, INPUT);
}
void loop() {
// read the first analog sensor:
int sensorValue = analogRead(A0);
// print the results:
Serial.print(sensorValue);
Serial.print(",");
// read the second analog sensor:
sensorValue = analogRead(A1);
// print the results:
Serial.print(sensorValue);
Serial.print(",");
// read the button:
sensorValue = digitalRead(buttonPin);
// print the results:
Serial.println(sensorValue);
}
Arduino:
// variable to hold an instance of the p5.webserial library:
const serial = new p5.WebSerial();
// HTML button object:
let portButton;
let inData; // for incoming serial data
let outData; // for outgoing data
// variables for the circle to be drawn:
let locH, locV;
let circleColor = 255;
function setup() {
createCanvas(400, 300); // make the canvas
// check to see if serial is available:
if (!navigator.serial) {
alert("WebSerial is not supported in this browser. Try Chrome or MS Edge.");
}
// if serial is available, add connect/disconnect listeners:
navigator.serial.addEventListener("connect", portConnect);
navigator.serial.addEventListener("disconnect", portDisconnect);
// check for any ports that are available:
serial.getPorts();
// if there's no port chosen, choose one:
serial.on("noport", makePortButton);
// open whatever port is available:
serial.on("portavailable", openPort);
// handle serial errors:
serial.on("requesterror", portError);
// handle any incoming serial data:
serial.on("data", serialEvent);
serial.on("close", makePortButton);
}
function draw() {
background(0); // black background
fill(circleColor); // fill depends on the button
ellipse(locH, locV, 50, 50); // draw the circle
}
// if there's no port selected,
// make a port select button appear:
function makePortButton() {
// create and position a port chooser button:
portButton = createButton("choose port");
portButton.position(10, 10);
// give the port button a mousepressed handler:
portButton.mousePressed(choosePort);
}
// make the port selector window appear:
function choosePort() {
serial.requestPort();
}
// open the selected port, and make the port
// button invisible:
function openPort() {
// wait for the serial.open promise to return,
// then call the initiateSerial function
serial.open().then(initiateSerial);
// once the port opens, let the user know:
function initiateSerial() {
console.log("port open");
}
// hide the port button once a port is chosen:
if (portButton) portButton.hide();
}
// read any incoming data as a byte:
function serialEvent() {
// read a string from the serial port
// until you get carriage return and newline:
var inString = serial.readStringUntil("\r\n");
//check to see that there's actually a string there:
if (inString) {
// split the string on the commas:
var sensors = split(inString, ",");
if (sensors.length > 2) {
// if there are three elements
// element 0 is the locH:
locH = map(sensors[0], 0, 1023, 0, width);
// element 1 is the locV:
locV = map(sensors[1], 0, 1023, 0, height);
// element 2 is the button:
circleColor = 255 - sensors[2] * 255;
}
}
}
// pop up an alert if there's a port error:
function portError(err) {
alert("Serial port error: " + err);
}
// try to connect if a new serial port
// gets added (i.e. plugged in via USB):
function portConnect() {
console.log("port connected");
serial.getPorts();
}
// if a port is disconnected:
function portDisconnect() {
serial.close();
console.log("port disconnected");
}
p5.js:
The result went well. I think the most difficult part is to fully understand how Serial Handshaking works. I am looking forward to applying it to some real-time motion projects in the future.
Two-Way Serial Communication
This part did not go well. Initially I tried to connect the breadboard and at least write part of the code in Arduino, since I think I understand the principle and the steps. However, I failed — it did not work at all. I did need to consult the lab page.
For some reason, after my failure, when I used the exact code from the lab page, the result was not correct either. The code worked, but the outcome was not as the same as it should be. I did not even reach the Handshaking part — I am still trying to debug it.
When the board is put flat on the table, the circle would not show at all. When I tip it over even for a little bit, the circle shows in the corner. According to the code, it should not work like that. It might be a connection problem.
When the problem is solved, I would like to integrate it in one of my p5.js sketches, in which each potentiometer will be able to control either x or y axis on the canvas. The sketch then will be more interactive than being controlled by a mouse.
UPDATE: PROBLEM SOLVED. It was the map.
video 1
video 2
figure 1