The purpose of this workshop was the apply learnings from physical computing and combine that with Introduction to Computation Media to create physical interactions on the breadboard and have the result be reflected on the screen in the p5.js editor. The first activity was to use a potentiometer to move an ellipse across the screen as you turned the dial from 0 to 1023 and the second activity was to use a button to have an ellipse disappear on a screen when pushed.
The tricky part was ensuring that the breadboard and Arduino properly spoke to the p5.js library through serial communications.
Here were the exact instructions for the above activities (I want to share them here because there are a lot of variables and I want to be sure not to miss anything):
- Download the P5 Serial Control application. This application serves as a bridge between your arduino and your p5 sketch. For it to run you'll on a mac you either need to have "allow apps downloaded from anywhere" enabled or cntrl-click to open. More info on apple's help pages.
- Open the following example, connect your arduino, and get it running. (You can "duplicate" it in the p5 editor to save it into your account.) Make sure the editor is using http and not https.
- p5.js code for reading analog value. Works with AnalogReadSerial Arduino sketch, found in the Arduino IDE, File menu, Examples-> Basics —> AnalogReadSerial. Turn a potentiometer from 0 - 1023, the ball moves from 0-255 on the screen.
- p5.js code for reading digital value. Works with DigitalReadSerial Arduino sketch, found in the Arduino IDE, File menu, Examples -> Basics —> DigitalReadSerial. Push a button, ball appears or disappears.
The examples use the p5.serialport library. You can read documentation and find more examples.
You might notice the above examples use a new concept called a "callback." This is a concept we will examine in detail next week in ICM while looking at "DOM manipulation." A quick explanation for how this relates to serial communication is as follows:
There is an "event" each time your p5 sketch receives data from the serial port. You get to decide what function is executed for that event. In the case of the examples, that function is serialEvent().
// When there is data, run serialEvent
serial.on('data', serialEvent);
The above line of code then requires you write a function called serialEvent() to handle the data.
function serialEvent() {
// Your code for reading the data goes here.
}
The only issue that we ran into was with the potentiometer activity -- when the ellipse moved across the screen it was very jittery. Apparently there is a smoothing function that can help with this issue
Application
Finally, we were asked to create out own "physical variable sketch" in p5.js. We were given the option to create a new sketch and add a physical component or incorporate a a physical interaction through serial on a previously created sketch.
My partner, Dominic, and I decided that we would implement a button interaction to a previous sketch that I created for ICM: Horus.
Because this was a previously generated sketch we had to upload p5.serialport.js file and link the this to the index.html file by including this line of code:
<script src="p5.serialport.js"></script>
Here is the code in the p5.js Horus sketch that allowed the serial communications to work in the browser:
var clicked = false;
var lastPeriodic = 1;
var serial; // variable to hold an instance of the serialport library
var sensorValue = 0; // ellipse position
function periodic(freq) {
if (clicked == false) {
return lastPeriodic;
}
// sin of frequency * two pi * time
lastPeriodic = sin(freq * TWO_PI * millis());
return lastPeriodic;
}
function randColor() {
if (clicked == true) {
fill(random(255), random(255), random(255));
}
}
// When mouse is clicked, switched Boolean value of clicked
function mouseClicked() {
clicked = !clicked;
}
function setup() {
createCanvas(400, 400);
serial = new p5.SerialPort(); // make a new instance of serialport library
serial.on('list', printList); // callback function for serialport list event
serial.on('data', serialEvent);// callback for new data coming in
serial.list(); // list the serial ports
serial.open("/dev/cu.usbmodem1411"); // open a port
}
function draw() {
background(220);
randColor();
// Stroke growing based on time
strokeWeight((millis() / 75) % 400);
// Draw ellipse using periodic function for width and height
ellipse(width / 2, height / 2, 300 * periodic(22), 300 * periodic(22));
if (sensorValue !== 0) {
clicked = true;
}
else {
clicked = false;
}
}
function printList(portList) {
for (var i = 0; i < portList.length; i++) {
// Display the list the console:
println(i + " " + portList[i]);
}
}
function serialEvent() {
var inString = serial.readLine();
if (inString.length > 0) {
inString = inString.trim();
sensorValue = Number(inString/4);
}
}
Here is a video that demonstrates how the button behavior affected the Horus sketch
I would be interested to also include the potentiometer in this sketch so that the Horus eye moved from right to left with the values on the potentiometer. Combining two serial inputs is something that we will be working on in class this week, so I hope to implement after.