PCOMP Week 6

For my first serial communication project, I reviewed all the P5 sketches I have made so far. Any work could have been connected to Arduino; I thought the assignment, Flying bird, was above all, the best one to be controlled by physical inputs.

The bird in the canvas flies following the mouse on the x-axis. I wanted to control the bird with a joystick for this opportunity. But it was Saturday night when I first came up with this idea, and I didn’t have any joystick at that time. It was too late to order one from online, and the offline shop where I can buy one also would close until Sunday. The earliest day I can get it was Monday, so I decided to do editing the source code to be more suitable for the joystick version as well as refactoring during the weekend.

The colour of the bird in the original version was blue, and it made it look calm. I needed a bird that looks more furious, so I, first of all, changed its colour to somewhat red.

Also, I thought the varying background was unnecessary for the new version. This time, I wanted to focus on the bird’s movement. Therefore, I removed all the functions related to making the bubbles fade in and out and changing the background colour, and instead, made the bubbles move in the opposite of the bird’s flying direction. Moreover, I gave the fire-breathing technique to the bird as a joystick also generate a digital input besides the two analogue outputs, VRx and VRy.

Later, I also had the bird’s speed adjustable by a potentiometer. The value affects the flow speeds of the bubbles as well.

After all the modification, I developed a virtual joystick and a potentiometer to test the sketch. I used the four arrow keys for the joystick, ‘<‘ and ‘>’ keys for the potentiometer and the space bar for the joystick’s switch. The source code for these is like below:

[Joystick – analogue input]

function virtualJoystick() {
if(keyCode == UP_ARROW) yValue++;
if(keyCode == DOWN_ARROW) yValue--;
if(keyCode == LEFT_ARROW) xValue--;
if(keyCode == RIGHT_ARROW) xValue++;
xValue = constrain(xValue, 0, 1023);
yValue = constrain(yValue, 0, 1023);
}

[Joystick – digital input]

function keyPressed() {
if(key == ' ') {
switchOn = 0;
}
}

[Potentiometer] – Actually, I could have tested a real potentiometer at this point, but I couldn’t be bothered and just decided to develop a virtual version.

function virtualPotentiometer() {
if(keyCode == 190) potValue++;
else if(keyCode == 188) potValue--;
potValue = constrain(potValue, 0, 1023);
}

Although it was super slow as the browser or Javascript couldn’t recognise a continuous key pressing, it worked anyway! I expected that it would be much faster with actual electronic parts. The following is the virtual version of the angry bird. It is still controllable by the way I described above.

(Fullscreen: http://alpha.editor.p5js.org/full/S1LBungab)

The audio file for the fire-breathing sound was found here: http://freesound.org/people/cabled_mess/sounds/335034/

I finally got the part on Monday and before connecting my p5 sketch and Arduino sketch, I first tested the joystick and a potentiometer running a simple Arduino code. The following is the schematic:

However, the digital value of the joystick was very unstable. It didn’t immediately respond when I pressed the button. I tested it several times with different wires and other digital pins but didn’t once properly work. I couldn’t take back the new cool ability from the bird, so I eventually added a button to the circuit and the schematic and the picture below are those of the modified one:

Furthermore, I expected the change pattern of the joystick’s value according to its direction totally wrong. I thought the value would continuously decrease from the median value while the stick is pulled towards left or up and  increase while it is pulled towards right or down. In fact, the value immediately became 0 when I pulled it to the left and 1023 when pulled to right. So I had to modify the p5 code.

I also made the Arduino refine its values before handing them to the browser to lessen her burden. There were two tricks I tried for this. First was to simplify the Joystick’s analogue values and I initially used ‘map’ function for it. However, it didn’t work accurately as the median values of x and y weren’t always exactly in the middle between 0 and 1023. For this reason, I used ‘if’ statements as an alternative.
The second was to make Arduino filter other redundant HIGH values which are acquired when the button was pressed, but despite the effort, p5 got multiple continuous HIGH values from Arduino anyway because of the processing time difference and had to ignore them itself.

#define SWITCH 2
int pSw = 0;
void setup() {
Serial.begin(9600);
pinMode(SWITCH, INPUT);
}
void loop() {
int x = analogRead(A0);
int y = analogRead(A1);
int pot = analogRead(A2);
int sw = digitalRead(SWITCH);
int on;
if(sw == 1) {
if(pSw!=1) {
on = 1;
pSw = 1;
}
else on = 0;
}
else if(sw == 0) {
pSw = 0;
on = 0;
}
if(x<100) { Serial.print("-1"); } else if(x>1000) { Serial.print("1"); }
else { Serial.print("0"); }
Serial.print(',');
if(y<100) { Serial.print("-1"); } else if(y>1000) { Serial.print("1"); }
else { Serial.print(0); }
Serial.print(',');
Serial.print(pot);
Serial.print(',');
Serial.println(on);
delay(100);
}

Another problem was caused by the bird’s swinging behaviour. The bird was designed to bounce up and down in a consistent height, though it disturbed updating the bird’s Y position when the joystick is pulled or pushed in the y-axis. I fixed this issue by blocking the bouncing while it moves up or down.

The following is the final code of my p5 sketch:


var serial; // variable to hold an instance of the serialport library
var portName = '/dev/cu.usbmodem1451'; // fill in your serial port name here
//////////
let bird;
let bubbles = [];
/////////
let pPotValue = 0;
let potValue = 0;
let xd = 0;
let yd = 0;
let pOnFire = 0;
let onFire = 0;
/////////
let speed = 1;
let birdX;
let birdY;
let direction = -1;
let pDirection = -1;
/////////
let fireSound;
/////////
function preload() {
soundFormats('wav');
fireSound = loadSound('fire.wav');
}
function setup() {
createCanvas(1250, 800);
birdX = width/2;
birdY = height/2;
bird = new Bird(birdX, birdY, direction, speed);
/////////
let x, y, rad, r, g, b, a;
for(let i=0; i<50; i++) { x = random(-width*2, width*2); y = random(0, height); rad = random(20, 150); r = random(0, 255); g = random(0, 255); b = random(0, 255); a = random(30, 100); bubbles.push(new Bubble(x, y, rad, color(r,g,b,a), direction, speed)); } fireSound.setVolume(0.1); ///////// serial = new p5.SerialPort(); // make a new instance of the serialport library 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 draw() { push(); colorMode(HSB, 100); background(70, 80, 30); pop(); if(bubbles.length > 0) {
for(let i=0; i<bubbles.length; i++) {
bubbles[i].flow();
}
}
if(frameCount%round((width/2)/speed) == 0) {
let x, y, rad, r, g, b, a;
for(let i=0; i<50; i++) {
if(direction < 0) x = random(width, width*2); else x = random(-width, 0); y = random(0, height); rad = random(20, 150); r = random(0, 255); g = random(0, 255); b = random(0, 255); a = random(30, 100); bubbles.push(new Bubble(x, y, rad, color(r,g,b,a), direction, speed)); } } if(bubbles.length>200) bubbles.splice(0,50);
/////////
bird.fly();
/////////
// to use the values from the serial to make the bird fly and angry
if(xd!=0) {
bird.updateX(xd);
if(((xd<0) && (pDirection<0)) || ((xd>0) && (pDirection>0))) {
direction *= -1;
bird.updateDirection(direction);
for(let i=0; i<bubbles.length; i++) {
bubbles[i].updateDirection(direction);
}
pDirection = direction;
}
console.log("x: ", xd);
}
if(yd!=0) {
bird.updateY(yd);
bird.lockSwing();
console.log("y: ", yd);
}
if(yd==0) {
bird.unlockSwing();
}
if((potValue-pPotValue)!=0) {
speed = map(potValue, 0, 1023, 1, 5);
bird.updateSpeed(speed);
for(let i=0; i<bubbles.length; i++) { bubbles[i].updateSpeed(speed); } pPotValue = potValue; console.log("speed: ", speed); } if(onFire==1) { if(pOnFire!=1) { console.log("Fire!!!!"); bird.breathFire(); fireSound.play(); pOnFire = 1; } } else if(onFire==0) pOnFire = 0; } function keyPressed() { bird.bringBack(); } function serialEvent() { // it happens when something arrives let stringFromSerial = serial.readLine(); if(stringFromSerial.length > 0) {
let values = stringFromSerial.split(',');
xd = values[0];
yd = values[1];
potValue = values[2];
onFire = values[3];
}
// console.log("xd: ", xd, ", yd: ", yd, ", pot: ", potValue, ", Fire: ", onFire);
}
/********************************
Open and Close the Serial
*********************************/
function serverConnected() {
print('connected to server.');
}
function portOpen() {
print('the serial port opened.')
}
function serialError(err) {
print('Something went wrong with the serial port. ' + err);
}
function portClose() {
print('The serial port closed.');
}

I don’t’ write the code in other files such as bird.js or bubble.js in this posting, but they are all available here:
http://alpha.editor.p5js.org/yeony102/sketches/ryxYcg7pW

Here is a video that shows how it actually responds to the physical devices:

Now that I review this, it would have been better if I also had changed the bird’s wing fluttering rate according to its speed!

Anyway, I’m happy to get to know how to connect my physical sensors and board to software!

Leave a Reply

Your email address will not be published. Required fields are marked *