The DOM, sounds scary but really it’s just like everything else in coding, with a little practice it’s not too bad at all. I had very little issue with this section of the class, mostly because it builds on the previous sections. Prior to this I had been using createSlider to alter different values for given elements in a sketch like color or diameter. Including other types DOM’s is pretty straight forward remembering to create a var to hold the information the DOM is providing is the key to making everything play nicely. Once the basic structure is setup, passing the information in is painless.
function addItem() {
// Create an li element
var li = createElement('li', itemInput.value());
// set li's parent to an element with id "todolist"
li.parent("todolist");
li.style('color', 'cyan')
}
I first used createP which didn’t take advantage of the <ol id='orderedlist'></ol> so I switched to createElement and that did the trick.
Overall adding DOM’s top p5.js is pretty intuitive and i can see how there are many possible scenarios that the will be useful in the future.
So I’ve started using class() for defining objects, got it. And now let’s put those objects into an array, no problem got it. Now let’s make it so they all move independently of each other….don’t got it.
See here is the problem, the block of code is pretty straight forward, when used on one object no problem however, if that object is in an array the issue rears it’s evil little head. When any of the objects in the array meet the criteria for this.x or this.y the value is inverted because it is multiplied by -1. So instead of each object independently meeting the criteria and changing the value by (*-1), ALL objects in the array are assigned this value at the same time. How can the object only be effected by the condition logic in the aforementioned block of code only when that object meets the criteria?
Here is the code in it’s entirety
let speedx = 3;
let speedy = 5;
let speedx1 = 2;
let speedy1 = 1;
let squares = [];
let spots = [];
function setup() {
createCanvas(600, 600);
frameRate(10);
}
function mousePressed() {
if (random(1) < 0.5) {
let s = new Square(mouseX, mouseY, 50, 50, 5);
squares.push(s);
} else {
let s2 = new Spot(mouseX, mouseY, 50, 50);
spots.push(s2);
}
}
function draw() {
background(0);
for (let square of squares) {
// push();
square.show();
square.move();
// pop();
for (let i = 0; i < squares.length; i++) {
squares[i].move();
squares[i].show();
}
}
for (let spot of spots) {
// push();
spot.show();
spot.move();
// pop();
for (let i = 0; i < spots.length; i++) {
spots[i].move();
spots[i].show();
}
}
}
class Square {
constructor(tempX, tempY, tempH, tempW) {
this.x = tempX;
this.y = tempY;
this.h = tempH;
this.w = tempW;
}
move() {
if ((this.x > width) || (this.x < 0)) {
speedx = speedx * -1;
}
this.x = this.x + speedx;
if ((this.y > height) || (this.y < 0)) {
speedy = speedy * -1;
}
this.y = this.y + speedy;
}
show() {
push();
rectMode(CENTER);
stroke(255);
strokeWeight(1);
noFill();
rect(this.x, this.y, this.w, this.h);
pop();
// p;rint(this.x);
}
}
class Spot {
constructor(spotX, spotY, spotH, spotW) {
this.x = spotX;
this.y = spotY;
this.h = spotH;
this.w = spotW;
}
move() {
push();
if ((this.x > width) || (this.x < 0)) {
speedx1 = speedx1 * -1;
}
this.x = this.x + speedx1;
if ((this.y > height) || (this.y < 0)) {
speedy1 = speedy1 * -1;
}
this.y = this.y + speedy1;
pop();
}
show() {
// push();
ellipseMode(CENTER);
stroke(255, 0, 0);
strokeWeight(1);
noFill();
ellipse(this.x, this.y, this.h, this.w);
// pop();
// print(this.x);
}
}
I started with a sketch to enable communication from the Nano 33IoT to the computer, this communication enabled the computer to know which port the Nano was connected to. Using an intermediary program called P5.serialcontrol I was able to find the port that the Nano was connected to, in my case it was COM4. The code below is for the Nano.
void setup() {
Serial.begin(9600); // initialize serial communications
}
void loop() {
int potentiometer = analogRead(A0); // read the input pin
int mappedPot = map(potentiometer, 0, 1023, 0, 255); // remap the pot value to fit in 1 byte
Serial.write(mappedPot); // print it out the serial port
delay(1); // slight delay to stabilize the ADC
}
This next code is from p5.js.
let serial; // variable to hold an instance of the serialport library
function setup() {
serial = new p5.SerialPort(); // make a new instance of the serialport library
serial.on('list', printList); // set a callback function for the serialport list event
serial.list(); // list the serial ports
}
// 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:
console.log(i + portList[i]);
}
}
After the I knew the port, the next task was communication between the Nano and the p5.js web editor, this is no easy task luckily the aforementioned program , P5.serialcontrol comes to the rescue again. This is especially important for this communication to work since the p5.js environment and the Nano cannot natively communicate. The code is rather complex and includes a library file.
The library file is very long find it at the link below.
Here is the code to interface with the potentiometer connected to the Nano.
// let serial; // variable to hold an instance of the serialport library
// function setup() {
// serial = new p5.SerialPort(); // make a new instance of the serialport library
// serial.on('list', printList); // set a callback function for the serialport list event
// serial.list(); // list the serial ports
// }
// // 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:
// console.log(i + portList[i]);
// }
// }
let xPos = 0;
let serial; // variable to hold an instance of the serialport library
let portName = 'COM4'; // fill in your serial port name here
let inData; // for incoming se
function setup() {
createCanvas(1200, 500);
background(0x08, 0x16, 0x40);
serial = new p5.SerialPort(); // make a new instance of the serialport library
serial.list();
serial.open('COM4');
serial.on('list', printList); // set a callback function for the serialport list event
serial.on('connected', serverConnected); // callback for connecting to the server
serial.on('open', portOpen); // callback for the port opening
serial.on('data', serialEvent); // callback for when new data arrives
serial.on('error', serialError); // callback for errors
serial.on('close', portClose); // callback for the port closing
// serial.list(); // list the serial ports
// serial.open(portName); // open a serial port
}
function graphData(newData) {
// map the range of the input to the window height:
var yPos = map(newData, 0, 255, 0, height);
// draw the line in a pretty color:
stroke(0xA8, 0xD9, 0xA7);
line(xPos, height, xPos, height - yPos);
// at the edge of the screen, go back to the beginning:
if (xPos >= width) {
xPos = 0;
// clear the screen by resetting the background:
background(0x08, 0x16, 0x40);
} else {
// increment the horizontal position for the next reading:
xPos++;
}
}
// 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:
console.log(i + portList[i]);
}
}
function serverConnected() {
console.log('connected to server.');
}
function portOpen() {
console.log('the serial port opened.')
}
function serialEvent() {
inData = Number(serial.read());
}
function serialError(err) {
console.log('Something went wrong with the serial port. ' + err);
}
function portClose() {
console.log('The serial port closed.');
}
function draw(){
// background(0);
// fill(255);
// text("sensor value: " + inData, 2, 10);
graphData(inData);
}
Lab: Serial Output From p5.js
Here I some input happening in p5.js and need to have the Nano do something, in this case light a red LED.
Here is the code for the Nano.
const int ledPin = 5; // the pin that the LED is attached to
int incomingByte; // a variable to read incoming serial data into
void setup() {
Serial.begin(9600); // initialize serial communication
pinMode(ledPin, OUTPUT); // initialize the LED pin as an output
}
void loop() {
if (Serial.available() > 0) { // see if there's incoming serial data
incomingByte = Serial.read(); // read it
if (incomingByte == 'H') { // if it's a capital H (ASCII 72),
digitalWrite(ledPin, HIGH); // turn on the LED
// if you're using a speaker instead of an LED, uncomment line below and comment out the previous line:
// tone(5, 440); // play middle A on pin 5
}
if (incomingByte == 'L') { // if it's an L (ASCII 76)
digitalWrite(ledPin, LOW); // turn off the LED
// if you're using a speaker instead of an LED, uncomment line below and comment out the previous line:
// noTone(5);
}
}
}
Again we need to include the library file for P5.serialcontrol
The library file is very long find it at the link below.
var serial; // variable to hold an instance of the serialport library
var portName = 'COM3'; // fill in your serial port name here
var inData; // for incoming serial data
var outByte = 0; // for outgoing data
function setup() {
createCanvas(400, 300); // make the canvas
serial = new p5.SerialPort(); // make a new instance of the serialport library
serial.on('data', serialEvent); // callback for when new data arrives
serial.on('error', serialError); // callback for errors
serial.open(portName); // open a serial port
}
function serialEvent() {
// read a byte from the serial port:
var inByte = serial.read();
// store it in a global variable:
inData = inByte;
}
function serialError(err) {
println('Something went wrong with the serial port. ' + err);
}
function draw() {
// black background, white text:
background(0);
fill(255);
// display the incoming serial data as a string:
text("incoming value: " + inData, 30, 30);
}
function mouseDragged() {
// map the mouseY to a range from 0 to 255:
outByte = int(map(mouseY, 0, height, 0, 255));
// send it out the serial port:
serial.write(outByte);
}
function keyPressed() {
if (key >= 0 && key <= 9) { // if the user presses 0 through 9
outByte = byte(key * 25); // map the key to a range from 0 to 225
}
serial.write(outByte); // send it out the serial port
}
The previous five videos show various different interactions with the Nano using serial communication. Once I understood what was happening and how to alter the code inside p5.js to communicate the way I wanted it to this process wasn’t too bad, now if I had to write that library file…I’m not sure if I’d know where to start.
What can I say, the expected end of an outstanding seven weeks of class. But let’s get into the making of “Three Pigs Of the Apocalypse”. Stephanie Chen, Shaurya Seth, and I set out to tell our re-imagining of “The Three Little Pigs”. The Big Bad Wolf is represented by three current events: civil unrest, environmental chaos, and the advent of technology. Using a 3D modeled and rendered environment allowed us to take video clips of these current event s and set them into a world a little different than our own.
The challenge of this particular project was not of content or technical skills but that of geography as the groups was spread out between 3 different time zones. Never fear though, with the advent of technology,…pun intended, and with the help of Zoom and Google Drive it was like we were sitting in the same room. This whole process went pretty smoothly.
So what were the biggest issues you might ask, well for one Adobe Premier Pro has a nasty bug in it that causes persistent crashes. After loosing a day due to this and a few hours of research an answer to the cause of these crashes emerged, .avi. Premier Pro has an issues with it’s .avi compiler/converter. This would cause dropped frames and the software would try and recover from this in loop causing the playback window to freeze and eventually crash the program. Thankfully, having worked on files with many components before, my incessant need to save constantly was a life saver. After finding the issue I converted all the media to .mp4 and replaced the clips and voilà no crashing!! Adobe, I’m calling you out here, this issue has been logged for OVER a year now and there is no official response anywhere on the internet ( I know cause I viewed all the internet in search of a solution), Adobe you need to fix this problem.
It took 72 hours of rendering to complete the 3D modeled environment. We also had to troubleshoot an issue with embedding the video into the modeled environment. The solution finally came by using After Effects to extract each individual frame and use those frames as the source file for the embedded video.
As with any creative process your biggest friend is problem solving and perseverance. So without any further diatribe by yours truly, enjoy the show.
class descriptiveName() seems to be a very powerful aspect of p5.js however, there are parts about that I do not understand. I can create a sketch not using class descriptiveName() and make it do what I want like in the example that follows, rotate() a Line() around a location.
Just using function draw() I get this, which is the outcome I was looking for.
When I use a class descriptiveName() I get this:
let inner = [];
function setup() {
createCanvas(400, 400);
// inner1 = new Inner(0, 0, -200, -200 );
for (let i = 0; i < 50; i++) {
let vx = random(0, width);
let vy = random(0, height);
inner[i] = new Inner(0, 0, vx, vy)
}
}
function draw() {
background(0);
translate(width / 2, height / 2);
for (let i = 0; i < inner.length; i++) {
inner[i].show();
push();
let rep = 15;
angleMode(DEGREES);
rotate(rep);
pop();
rep = rep * 2;
}
}
class Inner {
constructor(x1, y1, x2, y2) {
this.x = x1;
this.y = y1;
this.a = x2;
this.b = y2;
}
show() {
// let rep = 15;
// angleMode(DEGREES);
// translate(width / 2, height / 2);
// push();
// rotate(rep);
stroke(255);
line(this.x, this.y, this.a, this.b);
// rep = rep*2;
// pop();
}
}
The above code shows my experimentation with trying to get the same result from class descriptiveName() and placing everything in draw().
After spending some time on this I decide to try another sketch to fulfill the week five excursive.
Sliders control the size of the rect() as well as the RGB fill() values.
I feel a bit lost down a deep deep hole, slowly climbing towards what seems the top longing for the daylight to strike me directly however each time a the top appears the hole seemingly grows, endlessly slowing the progress that just happened. I suppose that this feeling will continue for sometime, there are clear objectives in my head but producing these outcomes has proven more difficult than at first anticipated. Time. Time is the answer, but not just time, time spent with what is new and there in lies the root of the issue, it’s all new therefore, the time needed to fully grasp the ideas is exponential since each concept builds on the last.
10PRINT is in theory fairly easy to understand however, when applying more complex functions to this code things change rapidly. The following examples are all based on the same code with VERY slight adjustments, the outputs are VERY different.
So my question is this: Are these all considered iterations of 10PRINT?
Based on what we learned for the past four weeks, we want to create something that incorporates components from previous Labs. Our project scope was to create a small DJ station with:
One rotary potentiometer
One ribbon/flex sensor that can be used to change the tone/pitch of the audio
One (or multiple) LEDs to indicate that the audio is on/off
Other ideas/functions we wanted to try exploring:
To map the range of the circular ribbon sensor to the RGB LED, so that the colours would change according to the touch sensor
To map the sound of the speaker to the musical notes, so different areas of the sensor will trigger different musical notes
To have multiple ribbon sensors
Process:
Since we are familiar with the setup of sensor + speaker combo, and adding LED should be fairly straightforward (we were wrong), we just need to work on incorporating the circular ribbon sensor into the circuit & the code component that comes with it.
We started by setting up the circular ribbon sensor and mapped its values and ranges. The ribbon sensor produced minimal but noticeable changes when touched, but the overall sound was not audible. Both Phil and I had pretty small speaker output from Lab 3, so it’s crucial that we figured out how to amplify it. We followed the transistor’s tutorial, as demonstrated by Tom, tried connecting it to Arduino Uno and changed to 5.5V, also found several other examples online, etc. but none of them seemed to work.
We decided it’s best to work on small chunks of circuits at a time, to ensure they are working and functioning as intended, before integrating them it into one big circuit setup, so: 1. connect ribbon sensor & rotary potentiometer to the speaker 2. connect speaker & pot to transistor 3. connect LED to the pots & speaker 4. integrate/code all components together.
Documentation:
1. Speaker + Rotary Pot with working Ribbon Sensor but small sound ft. Saturday Applications class
2. Speaker with Transistor for some audibly LOUD SOUND. Breadboard was tight so have to press the Arduino down.
3. Speaker + Potentiometer + Ribbon Sensor. Sound is clear, but there was not much difference in sound when rotating the pot vs pressing on the sensor.
4. Played around with the delay(). Found the pitch and range that we want to keep. We wanted to make sure that there is a clear, audible differentiation between the rotary pot and the ribbon sensor.
5. Testing RGB LED with ribbon sensor and rotary pot, LED is flickering but is not entirely responsive to either pots.
6. Cue the RGB LED drama. Played with more delay() settings while trying to connect the LED to the pot. Still no relationship/correlation between pot and LED, the latter is flickering randomly.
We spent a good chunk of time trying to incorporate RGB LEDs and got into an interesting situation where everything seems to be working in reverse. We noticed that the LEDs display the opposite colour of what we input (i.e. red (255,0,0) would trigger blue/cyan, and cyan(0,255,255) would trigger red). We changed the digital input pin, flipped the LED, checked the datasheet, added and blocked out multiple code lines, but nothing seemed to work.
We decided to test again with a different RGB LED found on the floor, and it worked! That’s when we realised that we have been working with anode RGB LED all along, using a code written for a cathode RGB LEDs. We also noticed how the anode connects to negative/ground, while cathode connected to positive/red. Why are there two different kinds, and what are some of the occasions or purposes where having two different types of LEDs would be beneficial?
7. Final Output: We discovered the RGB LED mystery (described below), dropped it and decided to use two LEDs instead. Each pot controls one LED.
Schematic:
Arduino code:
const int blueLed = 8; const int redLed = 7; int analogValue1 = 0; int brightness1 = 0; int analogValue2 = 0; int brightness2 = 0;
void loop() { // get sensor reading int rotPot = analogRead(A0); int ribPot = analogRead(A1);
//map results of sensor range to pitch range float frequency = map(rotPot, 0, 1023, 50, 880); float pitch = map(ribPot, 0, 255, 440, 880); // float blueLed = map(brightness1, 0, 1023, 0, 255); // float redLed = map(brightness2, 0, 1023, 0, 255);
The output is different from what we planned, but still cool nonetheless! The DJ Station is on and will play the sound by default. We have two modes of controlling the audio, and both produce noticeable differences/alterations to the audio. We also have two corresponding coloured LEDs light that will flicker (when the user touch the ribbon sensor) or turn on and off (when the user turn the rotary potentiometer). Phil also made awesome renderings and prototype the enclosure of what it can look like!
Renderings and prototype of enclosure:
Takeaway:
We recreated the circuit setup many times to debug, and this was where working on multiple breadboards really helped. One of our ongoing challenges was to connect the pots/speaker setup to the LEDs. We transferred the LEDs setup through multiple breadboards to debug, and each time we always seemed to miss out on something (wrong digital or analog pin, wrong leg, wrong connection to power/ground, forgot to bridge across the breadboard, forgot to change digital pin number in the code, etc.) Overall, this project helped us to be proactive in troubleshooting and to try as many solutions or approaches as we can because at this stage, there are only so many things that can go wrong (…right?)
Color-coding is important, so are documentation and iterations, very important to keep a note so we have something to fall back on in case future experimentations failed.
Questions:
Difference between Cathode and anode LED, and why is there a need for both? What are some use cases for these two types of LEDs?
How to map the sensor to the music notes and/or LED? We tried this earl
How to map the output of the sensor to the LED while something else is being used/mapped?
How to use analog input to control two outputs?
We were playing around with digital inputs, with most of our current setups using digital pin 7 to 9. We switched to digital pin 5 & 6 once and that, when combined with our (semi) working code, shut down the board. Why did that happen?
We layered some delays() and they produced interesting audio effects?
First I made a bouncing ball, second I made the fill() change from (0, 255) based on the X position and Y position, then I made the background() change from (0, 255) based on the ball’s X, Y position, finally I added three sliders to change the RGB values independently.
I’m still having to refer back to the reference material to get the syntax correct but most of the terms and thinking through the actions of the code are making sense. I feel like there is a pretty steep learning curve associated with any coding. I find it interesting to be a beginner again, I haven’t had that opportunity in a long time, and it feels good to be challenged again. I see this skill as such an integral building block for many of the projects I have the desires to work on.
Let’s make some music….err rather some noise. There were a few distinct pitches produce by the melody sketch however, on every occasion I was only able to produce at best some clicks and at worst just some static.
There are a number of variables at play here so I tried some different configurations to try and work through the problems.
First I had only two Force Sensitive Resistors (FSR), they were labeled “19” and “20” figuring this was by design I tested both to find the range for each FSR.
Using the serial monitor I was able to see the following:
“19” had an approximate range of 0-29
“20” had an approximate range of 0-288
I wasn’t sure if this would have in affect on the success or functioning of a circuit. I used this information for both the analogTone circuit and the threeKeyInstrument circuit. I had better results with the threeKeyInstrumentthan the analogTone circuit, but that is getting ahead of ourselves here. Let’s look at the analogTone circuit first.
I mainly focused on map() changing the range of the sensor to get different results. I never had the ability to produce a clean sounding tone. I was able to alter the tone or completely stop the sound from playing. I change the FSRs for phototransistors but had much of the same results, and the same while using rotatory potentiometers.
Now lets turn to the threeKeyInstrument hers where the real fun begins. First it is got to note that the only sensor I had identical copies of were the photoresistors, in addition to those I had as follows (1) ribbon sensor, (2) rotary potentiometers, (2) flex sensors, (1) FSR labeled “19”, and (1) FSR labeled “20”. The ranges of all of the varied pretty wide not sure how that would change the output, I carried on. Something of note, as a newbie to the physical computing world trouble shooting can be very time consuming, frustrating , or fun this being said Tom Igoe said in class that the best way to troubleshoot is to go back to a point where you know what is happening, this is incredibly sound (pun intended) advice.
What follows are the combinations of sensors used while trying to accomplish the task of the threeKeyInstrument the order point is the physical location of the sensor moving down the breadboard away from the Nano:
FSR 19, FSR 20, flex sensor
FSR 19, FSR 20, rotary pot
Ribbon sensor, , FSR 19, rotary pot
Rotary pot , FSR 19, ribbon sensor
Ribbon sensor, FSR 20, rotary pot
Rotary pot, FSR 20, ribbon sensor
Moved analog wires down by one pin from AREF, A0, A1 to A), A1, A2
All combinations above yielded the same output: crinkled sound with static, there was no distinct note produced
Phototransistor, Phototransistor, Phototransistor (no sound at all)
Removed all sensors and used jumper wires in place
Changed threshold to 0, 5, 10… 45
Repeated all above with no 100Ω resistor, same results
At this point I’m not sure what caused this behavior, further trail and error will be needed to find the cause.
Throughout the whole speaker portion of the lab the volume was very very low.
Ser Vo,
This part of the lab went fairly well, I successfully controlled the movement of the servo with an analog input however, there was some noticeable hesitation and electromechanical wine emitting from the servo throughout the whole process. The servo used was a FS5106B which states it is a high torque 6V unit that can operate with either a 3.3V or 5V input voltage. I remember in one of the videos something about servos and using delay() or something equivalent to reduce the lag between input and output, but I was unsure of how to implement it. I will tackle this addition to the code at a later date.
I’m starting to see how the building blocks of p5.js will enable the creation of systems and thusly enable more complex programs to be written. There are however, a few concepts that still are a bit fuzzy. One of those is random(), I understand how this function works but I’m a bit lost as to why I can put it before the setup() so that it can have an affect on the code after it. I was able to find a work around unfortunately this creates a very long program to something I believe should be able to be done with far fewer lines of code.
You can see in the code below the video lines 22-41 and lines 52-70 are devoted to assigning a random color to the four circles. This seems like a lot of code to produce these changes. This is where I’m sure this is a better more compact way to do this.
The video is a screen recording of the behavior produced by this code. The circles which have an origin at the four corners has a random() assignment operation for location. The color of each circle is also is random() unless the (mouseButtonPressed) is used which changes each of the circles to red, green, blue, or black.