Final Project: Final Report

Concept:

To summarize, my final project is a game I like to call Treasure Hunt! In this game there is a pile of random items all over the desk, among these random items is one piece of TREASURE. Your goal is to retrieve that treasure. However, there is a radar sensor moving back and forth constantly trying to detect you. The goal is to get this treasure before the radar detects you and before the time runs out! Hence, you got to hide or run away to avoid the radar’s range.

Implementation:

Arduino:

For the arduino aspect of my final project, I used several components:

  • A servo motor which would be the radar sensor moving back and forth consistently.
  • An ultrasonic sensor which would be mounted on the servo motor and this would be used to detect the distance of the user from the radar sensor.
  • A force sensor to detect whether the treasure has been picked up or not. If it was 0 for 1 second, that indicates that the treasure has been found and that you won the game!
  • Three arcade LED switches to change the difficulty of the game. Depending on which buttons were pressed, that would change the speed of the servo motor, hence the radar sensor would move much faster and would be harder to avoid the radar’s range in time.
  • I also added an LED which is used for debugging and also managing whether the treasure has been set on the force sensor before starting the game. This is because if we started the game and the treasure wasn’t on the force sensor properly, then the game would simply declare the user has won and it wouldn’t make sense.

p5js:

The main aspect of p5js was the map out a visual aid for the radar sensor and to also map out the different stages of the game to Arduino, whether than being the main menu, losing screen, winning screen or the main game screen.

For the main radar screen, it would have the entire mapping of the radar sensor moving back and forth. It also contains details such as whether the object is in range or out of range, the degree of rotation, the distance from the sensor so the user can see how the radar maps them out.

It spins and maps out a green line attempting to detect the user, if the user is detected, it would map out a red line to indicate this and if they are detected for 1 second, then they lose. Else if there were to pick up the treasure then they win!

They can also go back to the menu from this screen to change their difficulty if they wish

Arduino and p5js Interactivity:

I made a little map of how Arduino and p5js map together:

Aspects I’m Proud of:

I would say i’m very proud of how the mapping between the radar sensor through the Arduino and p5js turned out. Visually on the p5js it looks very cool, especially with a really cool blur effect I added on p5js. That way it makes it seem like an actual radar sensor. The mapping between all the different phases of the game are really well done especially through all the values from the Arduino to p5js.

I would say I’m also very proud of how the actual radar sensor box looks like, it looks very cool and the design is very awesome in my opinion. I would also say that the arcade buttons are a very nice touch to display the difficulty of the game. This is because when pressed it lights up indicating which difficulty it is, making it easy for the user to understand what difficulty they have.

Aspects I would Improve:

As per the improvement aspect of the entire project, there are several:

  • I would have loved to implement a physical computing aspect for the win/lose stage of the project. My initial ideas were that if you won, then it would activate a servo motor waving a white flag to signify that the radar sensor admits defeat. Also if they lost, then another servo motor would be activated which would unwind a scroll with a picture saying you lost or something. These ideas would’ve been really cool however, because of the time, I was not able to implement these ideas and was forced to simply put a “you lose” or “you win” screen through p5js. However, next time if possible, will definitely implement.
  • I would have loved to also improve the quality of the box, perhaps use wood or acrylic or something or stronger material so that the entire product looks much nicer to look at rather than cardboard.
  • There is this bug where suppose you lost or won a game, then you would have to wait for the Servo motor to map back to the beginning before you can do anything again. I couldn’t find a solution for this and I think this could also be improved.

Video – Testing on my Own:

Video – User Testing Video:

Video – User Testing #2:

Link to p5js Code:

https://editor.p5js.org/awesomeadi00/sketches/KGKN8f8wE

Arduino Code:

#include <Servo.h>. 

//PINS: 
const int Radar_ServoPin = 10;   

const int echoPin = 9;    
const int trigPin = 8;

const int w_switch = A3;
const int g_switch = A2;
const int y_switch = A1;

const int w_led = 4;
const int g_led = 5;
const int y_led = 6;    

const int pressurePin = A0;
const int pressureLED = 2;

//Global Variables: 
int w_switchVal;
int g_switchVal;
int y_switchVal;
int pressureVal;
unsigned long duration;
int distance;
int difficulty = 1;
int loseBool = 0;

//All game states below are exactly as shown in p5js
int gameState;
int menuState = 0;
int radarState = 1;
int winState = 2;
int loseState = 3;

//Servo object for controlling the servo motor
Servo RadarServo; 

//====================================================================================================================================
void setup() {
  //Begin the serial monitor to p5js at 9600 baud
  Serial.begin(9600);

  //Setting the pinmodes for the ultrasonic sensor
  pinMode(trigPin, OUTPUT);  
  pinMode(echoPin, INPUT);   
  
  //Seting the pinmodes for the arcade switch pins
  pinMode(w_switch, INPUT);
  pinMode(g_switch, INPUT);
  pinMode(y_switch, INPUT);
  
  //Setting the pinmodes for the LEDs in the arcade buttons
  pinMode(w_led, OUTPUT);
  pinMode(g_led, OUTPUT);
  pinMode(y_led, OUTPUT);

  //Output mode for the pressureLED, this will check whether the pressure sensor is active or not.
  pinMode(pressureLED, OUTPUT);

  //Attaching the servos to arduino 
  RadarServo.attach(Radar_ServoPin);  
  RadarServo.write(0);

  //Setup for the game, sets the easy difficulty on by default (difficulty = 1) and sets up the menu screen.
  digitalWrite(w_led, HIGH);
  gameState = 1;

  // Blinks the pressureLED in case the Serial Connection between p5js and Arduino has not been made (debugging)
  while (Serial.available() <= 0) {
    digitalWrite(pressureLED, HIGH);
    Serial.println("0,0"); 
    delay(300);     
    digitalWrite(pressureLED, LOW);
    delay(50);
  }
}

//====================================================================================================================================
void loop() {
  // This checks while the serial connection is available from p5js, then it will parse the gamestate from p5js to arduino. 
  while(Serial.available()) {
    int p5js_gameState = Serial.parseInt();
    if(Serial.read() == '\n') {
      gameState = p5js_gameState;
    }
  }

  //Based on the gamestate from p5js, it will map out exactly what to do on Arduino.
  if(gameState == menuState) {setDifficulty();}
  else if(gameState == radarState) {radarActivate();}
  Serial.println();
}

//====================================================================================================================================
//This functions is only called during the Main Menu. It checks which buttons are pressed to map the speed of the radar, hence setting the difficulty.
void setDifficulty() {
  //If the pressure is greater than 50, then it will switch on the pressureLED to indicate that the user still needs to find it. Else it will switch off indicating they won.
  pressureVal = analogRead(pressurePin);
  if(pressureVal > 200) {digitalWrite(pressureLED, HIGH); }
  else {digitalWrite(pressureLED, LOW); }

  //Reads all the values for all three buttons
  int y_sstate = digitalRead(y_switch);
  int g_sstate = digitalRead(g_switch);
  int w_sstate = digitalRead(w_switch);

  //If the yellow button is pressed, it will switch that on and set hard difficulty to 3
  if(y_sstate == HIGH) {
    digitalWrite(y_led, HIGH);
    digitalWrite(g_led, LOW);
    digitalWrite(w_led, LOW);
    difficulty = 3;
  }

  //If the green button is pressed, it will switch that on and set medium difficulty to 2
  else if(g_sstate == HIGH) {
    digitalWrite(y_led, LOW);
    digitalWrite(g_led, HIGH);
    digitalWrite(w_led, LOW);
    difficulty = 2;           
  }

  //If the white button is pressed, it will switch that on and set easy difficulty to 1
  else if(w_sstate == HIGH) {
    digitalWrite(y_led, LOW);
    digitalWrite(g_led, LOW);
    digitalWrite(w_led, HIGH);
    difficulty = 1;
  }
  Serial.println(difficulty);
}

//====================================================================================================================================
//This function will only be called if the game has started and thus the radar will become active. 
void radarActivate() {
  //Rotates the servo motor from 0 to 180 degrees
  for(int i = 0; i <= 180; i+=difficulty){ 
    pressureVal = analogRead(pressurePin);    //Reads the pressure value to determine if the user has won or not.
    if(pressureVal > 200) {digitalWrite(pressureLED, HIGH); }
    else {digitalWrite(pressureLED, LOW); }
    
    if(gameState == winState || gameState == loseState) {
      RadarServo.write(0); 
      break; 
    }

    RadarServo.write(i);                      
    delay(30);
    distance = calculateDistance();           //Calculates the distance measured by the ultrasonic sensor for each degree. 

    //Sending p5js the degree of rotation of the servo, the distance and the pressure value from the Arduino.
    Serial.print(i+difficulty);              //Sends the current degree to p5js
    Serial.print(",");                  //Sends comma character for indexing in p5js
    Serial.print(distance);             //Sends the distance value to p5js
    Serial.print(",");                  //Sends comma character for indexing in p5js
    Serial.println(pressureVal);          //Sends the pressure value to p5js
  }

  // Repeats the previous lines from 180 to 0 degrees (moving it backwards)
  for(int i = 180; i > 0; i-=difficulty){ 
    pressureVal = analogRead(pressurePin); 
    if(pressureVal > 200) {digitalWrite(pressureLED, HIGH); }
    else {digitalWrite(pressureLED, LOW); }

    if(gameState == winState || gameState == loseState) {
      RadarServo.write(0); 
      break; 
    }

    RadarServo.write(i);
    delay(30);
    distance = calculateDistance();

    Serial.print(i-difficulty);
    Serial.print(",");
    Serial.print(distance);
    Serial.print(",");
    Serial.println(pressureVal);
  }
  Serial.println();
}

//====================================================================================================================================
//Function for calculating the distance measured by the Ultrasonic sensor
//Issue with the sensor is that for objects extremely far away, it takes virtually 69ms to come back and translate to distance
//This is way too long hence, for each increment on the Radar Servo, it would take 69ms.
//Perhaps wrap some board 90cm away from the sensor around in 180˚ so it maps that out and nothing else that's far.
int calculateDistance(){ 
  //Sets the trigPin on LOW for 2 microseceonds.
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  //Sends a signal from the triggering transducer for 10 microsends.
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  //Reads the echoPin and returns the sound wave travel time in microseconds. 
  duration = pulseIn(echoPin, HIGH); 

  //The distance will be calculated in cm, hence cm = (microseconds/2)/29
  distance = (duration/2)/29;
  return distance;
}

 

Leave a Reply