This may take the cake for the most frustrating lab yet. I thought I knew how to code in JavaScript, but no, p5.js was out to prove me wrong. I could get approximately nothing to do what I wanted. So, I suppose let’s start at the start, and go forward from there.
The first part of the lab asked us to make sure that the arduino was able to take information from two analog inputs and send it (via serial) to p5.js. This whole process is a little non-intuitive for me because you have to actually use serial.print within the arduino to send it to p5.js, but you can’t open the serial monitor. (Serial can only be used by one application at a time, so either the p5.serial.control app or the arduino serial monitor.) Then, you have to use console.log within p5.js to make sure that you are receiving correctly. The proper format is to separate the values from the two potentiometers by a comma, then have a line break at the end of each reading (450, 220 /n). P5 can read this in (as a string), then stores it in an array. Below is the schematic for my circuit and a video of my p5 console printing out the values the arduino sent via serial.

The next step was getting p5 to talk back to the arduino, which is pretty simple. From the p5 side, it is as easy as serial.write(); In arduino, I included an if statement to make sure that there was actually data coming in from the serial communication. If there is and it is greater than 0, the light on pin 9 flashes. Here is a video of the light flashing when I push the key “R”. The write is included in my keypressed function, which only looks for the key R, so the light only flashes when R is pressed.
Finally, I needed to use p5 to make a game. I thought of several ideas and made some sketches before finally settling on the idea of a maze game. I wanted the user to navigate a ball through a maze to the finish. Easy, right?
No. Not easy at all. Turns out that adding physics in p5 was going to take a LOT of lines of code. So basically, making the ball (controlled by the potentiometers) bounce off the walls of the maze was way too much. So, I changed my mind and decided to make a drawing game, where the user drew a path using the ball to a final destination. After several hours of work, I got to the point where I could get p5 to eternally draw a rectangle that followed the ball around. Not at all the point. The issue here is that the draw loop is on eternal repeat, so it updates the position of the rectangle every time you move the sensors. I couldn’t figure out a place to put a boolean statement that made it so that the rectangle was only drawn when the key was pressed and STAYED in that location. Very frustrating. Then, I decided I would make a game where all of the rectangles would change into different colors when you clicked on them, and the point of the game would be to make all the rectangles the same color. (P.S. by clicked, I mean hovered over them and hit the “R” key.) Well, the fill command changes the colors of all the rectangles, not just one, so they all change color simultaneously, making the game really easy. I figured out how to make each rectangle a different color using an array of colors and a for loop, but then the nightmare that was trying to figure out which color it is so you could change it on keypress defeated me. Then, I finally landed on the current game (which sucks, but you know what, I’ll take what I get). The point of the game is to find the rectangle that makes all the other rectangles disappear. They all change color together, but they all turn different colors. Here is a video of my rather lame game:
And here is the code that makes it run from p5:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| This P5 sketch is a template for getting started with Serial Communication. | |
| The SerialEvent callback is where incoming data is received | |
| By Arielle Hein, adapted from ITP Phys Comp Serial Labs | |
| Edited March 12 2019 | |
| */ | |
| var serial; //variable to hold an instance of the serial port library | |
| var portName = '/dev/cu.usbmodemFA131'; //fill in with YOUR port | |
| var sensor1; | |
| var sensor2; | |
| var pot1; | |
| var pot2; | |
| var placeR = 0; | |
| var placeR2 = 0; | |
| var counter = 1; | |
| var circlesize = 50; | |
| var drawRect = false; | |
| function setup() { | |
| createCanvas(600, 600); | |
| serial = new p5.SerialPort(); //a new instance of serial port library | |
| //set up events for serial communication | |
| serial.on('connected', serverConnected); | |
| serial.on('open', portOpen); | |
| serial.on('data', serialEvent); | |
| serial.on('error', serialError); | |
| serial.on('close', portClose); | |
| //open our serial port | |
| serial.open(portName); | |
| //let's figure out what port we're on – useful for determining your port | |
| // serial.on('list', printList); //set a callback function for the serialport list event | |
| // serial.list(); //list the serial ports | |
| } | |
| function draw() { | |
| background('purple'); | |
| var circlesize = 50; | |
| //make circle follow potentiometers | |
| pot1 = map(sensor2, 0, 255, 0+circlesize/2, width-circlesize/2); | |
| pot2 = map(sensor1, 0, 255, height-circlesize/2, 0+circlesize/2); | |
| ellipse(pot1, pot2, circlesize); | |
| //make many rectangles that all change color | |
| rect(0, 0, 50, 50); | |
| rect(100, 100, 50, 50); | |
| rect(200, 200, 50, 50); | |
| rect(300, 300, 50, 50); | |
| rect(135, 450, 50, 50); | |
| rect(200, 300, 50, 50); | |
| rect(300, 400, 50, 50); | |
| rect(500, 200, 50, 50); | |
| if(placeR < 170 && placeR > 130 && placeR2<480 && placeR2 >440){ | |
| fill("black"); | |
| } | |
| if(placeR < 230 && placeR > 180 && placeR2<330 && placeR2 >280){ | |
| fill("green"); | |
| } | |
| if(placeR<330 && placeR >280 && placeR2<430 && placeR2 >380){ | |
| fill("blue"); | |
| } | |
| if(placeR<530 && placeR >480 && placeR2<230 && placeR2 >180){ | |
| noStroke(); | |
| fill("purple"); | |
| } | |
| if(placeR < 140 && placeR > 80 && placeR2<140 && placeR2 >80){ | |
| fill("orange"); | |
| } | |
| if(placeR < 230 && placeR > 180 && placeR2<230 && placeR2 >180){ | |
| fill("white"); | |
| } | |
| if(placeR < 330 && placeR > 280 && placeR2<330 && placeR2 >280){ | |
| fill("pink"); | |
| } | |
| if(placeR < 80 && placeR > 0 && placeR2<80 && placeR2 >0){ | |
| fill("grey"); | |
| } | |
| } | |
| function getLocation(){ | |
| placeR = pot1; | |
| placeR2 = pot2; | |
| } | |
| //This is a function that sends the key stroke to the Arduino | |
| function keyPressed(){ | |
| drawRect = false; | |
| if(key=='R'){ | |
| serial.write(key); | |
| console.log(key); | |
| fill("red"); | |
| placeR = pot1; | |
| placeR2 = pot2; | |
| drawRect = true; | |
| counter++; | |
| console.log(pot1); | |
| console.log(pot2); | |
| } | |
| } | |
| //all my callback functions are down here: | |
| //these are useful for giving feedback | |
| function serverConnected(){ | |
| console.log('connected to the server'); | |
| } | |
| function portOpen(){ | |
| console.log('the serial port opened!'); | |
| } | |
| //THIS IS WHERE WE RECEIVE DATA!!!!!! | |
| //make sure you're reading data based on how you're sending from arduino | |
| function serialEvent(){ | |
| //receive serial data here | |
| var inString = serial.readLine(); | |
| //print(inString); | |
| if(inString != ""){ | |
| var stringArray = split(inString, ","); | |
| sensor1 = Number(stringArray[0]); | |
| sensor2 = Number(stringArray[1]); | |
| } | |
| } | |
| function serialError(err){ | |
| console.log('something went wrong with the port. ' + err); | |
| } | |
| function portClose(){ | |
| console.log('the port was closed'); | |
| } | |
| // get the list of ports: | |
| function printList(portList) { | |
| // portList is an array of serial port names | |
| for (var i = 0; i < portList.length; i++) { | |
| // Display the list the console: | |
| print(i + " " + portList[i]); | |
| } | |
| } |
And from arduino:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| int pot = 0; //potentiometer variable | |
| int pot2 = 0; | |
| int incoming = 0; | |
| void setup() { | |
| // put your setup code here, to run once: | |
| Serial.begin(9600); // initialize serial | |
| } | |
| void loop() { | |
| // put your main code here, to run repeatedly: | |
| pot = analogRead(A0); | |
| pot2 = analogRead(A1); | |
| int lightVals = map(pot, 0, 1023, 0, 255); | |
| int light2Vals = map(pot2, 0, 1023, 0, 255); | |
| Serial.print(lightVals); | |
| Serial.print(","); | |
| Serial.println(light2Vals); | |
| delay(1); | |
| analogWrite(9, lightVals); | |
| analogWrite(10, light2Vals); | |
| if(Serial.available()>0){ | |
| incoming = Serial.read(); | |
| if(incoming>0){ | |
| analogWrite(9,255); | |
| } | |
| } | |
| } |
I think p5 isn’t my very favorite coding language. Between the epic lagginess of my computer and the eternally looping draw function, this was a struggle. Very fun premise, but I think given more time and a different library, I could probably do better.