Concept:
For my final project, I pursued my initial idea and created a game that utilizes the ultrasonic sensor. The ultrasonic sensor will measure the distance from my hand and project that distance onto a ball’s horizontal position in p5. The ball can move left and right according to our hand movement. Multiple red rectangles are falling from above, and our job is to dodge them using our hands. There are also blue rectangles that spawn less frequently compared to the red ones. There is also a scoring system in which the score decreases by one after every frame, and hitting the red rectangles decreases the score by 2. Grabbing the blue rectangles that spawn less frequently is the only way to get a higher score. So the game becomes a fight against time and obstacles. As the score changes, the speaker that is connected to the breadboard also produces a different tone. Each score has its own unique tone produced by the speaker to make the game more engaging and fun. Therefore, this is a 2-way communication game, from p5 to Arduino and Arduino to p5.
Arduino:
Arduino will basically send the distance measured using the ultrasonic sensor to p5.Js. The Arduino side of the code will receive a score value from the p5. Arduino will input the echo pin(from ultrasonic sensor reading) and outputs both the trig pin(from ultrasonic) and speaker pin(value received from p5).
Here is my code for it so far:
const int trigPin = 11; const int echoPin = 12; const int speakerPin = 9; void setup() { // Start serial communication so we can send data // over the USB connection to our p5js sketch Serial.begin(9600); pinMode(LED_BUILTIN, OUTPUT); // Outputs on these pins pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(speakerPin, OUTPUT); //start the handshake while (Serial.available() <= 0) { digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data Serial.println("0,0"); // send a starting message delay(300); // wait 1/3 second digitalWrite(LED_BUILTIN, LOW); delay(50); } } void loop() { // sends a short pulse of ultrasonic sensor and waits a bit then receives it digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Time it takes for the pulse to travel back from the object long int duration = pulseIn(echoPin, HIGH); // Universal conversion of time into distance in cm int distance = duration * 0.034 / 2; //SENDS TO P5 Serial.println(distance); delay(50); //GETS FROM P5 int score = Serial.parseInt(); // Map the score to a frequency for the speaker int frequency = map(score, 0, 100, 100, 4000); // Play the tone tone(speakerPin, frequency); }
The Arduino board:
p5:
For the p5 side of the code, the p5 will receive the distance value measured from Arduino and map it onto the canvas. The p5 will also send a live score value to Arduino. There are multiple classes to my p5 code: ball class, Obstacle class, TimeRectangle class, a class for the port connection, and finally the main sketch.
This is my attached main sketch class:
//Initialize all variables let knobValue = 0; let targetKnobValue = 0; let easing = 0.08; // Adjust this value for the desired level of smoothing let score = 0; let lastFrameCount; //initialize the class objets let obstacles = []; let timeRectangles = []; let ball; function setup() { createCanvas(400, 300); //call the ball object ball = new Ball(width / 2, height - 30, 20); //line of code to set lastframe to the new one lastFrameCount = frameCount; } function draw() { //set background background(220); //if function to connect port if (!serialActive) { fill(0); textSize(18); text("Press Space Bar to select Serial Port", 20, 30); } //else function if the port is connected else { // lerp function linear interpolates(smoothes the value we get from arduino using distance sensor) knobValue = lerp(knobValue, targetKnobValue, easing); //updates ball position according to distance sens ball.update(knobValue); // Draw ball ball.show(); // Draw and move obstacles for (let i = obstacles.length - 1; i >= 0; i--) { obstacles[i].update(); obstacles[i].show(); // Remove obstacles that are off-screen if (obstacles[i].offscreen()) { obstacles.splice(i, 1); } else { // Check for collision with the ball if (obstacles[i].collision(ball)) { // Handle collision (e.g., decrease score) score= score-2; obstacles.splice(i, 1); // Remove the obstacle } } } // Draw and move timeRectangles(blue ones) for (let i = timeRectangles.length - 1; i >= 0; i--) { timeRectangles[i].update(); timeRectangles[i].show(); // Remove timeRectangles that are off-screen if (timeRectangles[i].offscreen()) { timeRectangles.splice(i, 1); } else { // Check for collision with the ball if (timeRectangles[i].collision(ball)) { // Handle collision (e.g., increase score) score += 5; timeRectangles.splice(i, 1); // Remove the timeRectangle } } } // Print the current knobValue fill(0); textSize(18); text('Knob Value: ' + str(knobValue), 20, 30); // Display score text("Score: " + score, 20, 60); // Spawn new obstacles and timeRectangles randomly if (random() < 0.01) { obstacles.push(new Obstacle()); } if (random() < 0.005) { timeRectangles.push(new TimeRectangle()); } // Update the score every second by subtracting current frame with last frame recorded in setup if (frameCount - lastFrameCount >= 60) { score = max(0, score - 1); lastFrameCount = frameCount; } } } function keyPressed() { if (key == " ") { // important to have in order to start the serial connection!! setUpSerial(); } } function readSerial(data) { //////////////////////////////////// // READ FROM ARDUINO HERE //////////////////////////////////// if (data != null) { // Parse the data received from Arduino let fromArduino = split(trim(data), ","); targetKnobValue = int(fromArduino[0]); print(targetKnobValue); } ////////////////////////////////// // SEND TO ARDUINO HERE ////////////////////////////////// let sendToArduino= score + "\n"; writeSerial(sendToArduino); }
The P5 interface:
Future improvements:
As of now, I just put down the main codes and functions for both platforms. I will have to work more on the visuals, designs, and aethstics side as a whole of the p5 game.