How to connect p5js to an arduino to sense or control the real world
How to control or measure something in the real world with p5js and a Arduino (or esp32 etc.)
For the Artificial Intelligence workshop at Humtek spring 2025
Until recently, it was difficult to control hardware from javascript/p5js in a browser. Now however it is reasonably easy, as hte browser Chrome supports javascript talking to a hardware serial port. (other browsers may or may not work)
In this example, connect a servo to pin 3, 5V and GND
Pinout/colours (http://www.pitch-play.nl/tips-and-tricks/servo-wires/)
To control or sense something in the real world from p5js, you need four things:
1) p5js sketch (below)
2) Arduino sketch (below)
3) Arduino compatible board (e.g. esp32, esp8266 also work fine)
4) Actuators or sensors to connect to the arduino board. (in this example a servo.
This solution is as simple as possible and does not use higher level abstraction layers like firmata, json etc.
p5js code:
(modified from https://learn.hobye.dk/kits/iot-tutorial ESP32/Arduino SERIAL to p5 (Directly))
Here:
https://editor.p5js.org/nicolasp/sketches/qQt7MMBt1
Or here:
// p5js code to send data to Arduino let serialAvaliable = false; let serialInput = ""; function setup() { createCanvas(400, 400); print("click on sketch canvas and press c to select serial port and connect") } function keyPressed() { if (key == "c") { serialConnect(); } } var timer = 0; var variable1 = 20; var variable2 = 0; function draw() { background(220); // prints the serial input buffer when the serialAvaliable flag is true if (serialAvaliable) { serialAvaliable = false; print(serialInput); serialInput = ""; } //Send data to the arduino every 2 seconds //- if data from Arduino shows up in the console it means that the arduino recieved it and returned some sensor values if (millis() - timer > 2000) { timer = millis(); variable1 = variable1 + 5; serialWrite(variable1); serialWrite(","); serialWrite(variable2); serialWrite("\n"); } } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // SERIAL COMMUNICATION FUNCTIONS BELOW // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX let port; let reader; let inputDone; let outputDone; let inputStream; let outputStream; let portIsOpen = false; async function serialListen() { if (portIsOpen) { while (true) { const { value, done } = await reader.read(); if (value) { serialAvaliable = true; serialInput = serialInput + value; } if (done) { console.log("[readLoop] DONE", done); reader.releaseLock(); break; } } } } async function serialConnect() { if (navigator.serial) { port = await navigator.serial.requestPort(); await port.open({ baudRate: 9600 }); const decoder = new TextDecoderStream(); inputStream = decoder.readable; inputDone = port.readable.pipeTo(decoder.writable); reader = inputStream.getReader(); const encoder = new TextEncoderStream(); outputDone = encoder.readable.pipeTo(port.writable); outputStream = encoder.writable; portIsOpen = true; print("Port is open"); serialListen(); } else { print("Serial not compatible with the browser you are using :/"); } } function serialWrite(line) { if (portIsOpen) { // CODELAB: Write to output stream const writer = outputStream.getWriter(); writer.write(line); writer.releaseLock(); } }
Arduino sketch code:
// p5js sketch should send data like 40,1\n (=newline) // this should move servo to 40 degrees and make LED on pin 2 (if exists) light up // Arduino sends data like 130,400\n (=newline), these are the values of the analog in pins // so this sketch supports 4 things, you probably only need one of them // but the data still needs to be in this format: 20,0\n // if you send any other data, you may need to reboot the arduino, as it does not handle other data formats #include <Servo.h> Servo myservo; // create servo object to control a servo. Twelve servo objects can be created on most boards int pos = 0; // variable to store the servo position. May be 0 to 180 int extraLedPin = 2; void setup() { // Start serial communication so we can send data over the USB connection from our p5js sketch Serial.begin(9600); myservo.attach(3); // attaches the servo on pin 3 to the servo object pinMode(LED_BUILTIN, OUTPUT); pinMode(extraLedPin, OUTPUT); } void loop() { // wait for data from p5 before doing something while (Serial.available()) { digitalWrite(LED_BUILTIN, HIGH); // led on while receiving data int variable1 = Serial.parseInt(); int variable2 = Serial.parseInt(); if (Serial.read() == '\n') { if(variable1 >= 0 && variable1 <= 180){ myservo.write(variable1); // tell servo to go to position in variable1 } digitalWrite(extraLedPin, variable2); // This is how we send sensor data back to the p5 sketch int sensor = analogRead(A0); delay(5); int sensor2 = analogRead(A1); delay(5); Serial.print(sensor); Serial.print(','); Serial.println(sensor2); } } digitalWrite(LED_BUILTIN, LOW); }