Week 14: Final Project Documentation (Fitzgerald)

Partner: Robert

Our final iteration of our project took a slight turn from our original whack a mole idea. At first, we wanted to have a series of five targets that the user would then throw a ball at to trigger a vibration sensor. However, this idea was perfect in concept but when it came time to put it into action some aspects began to falter. Therefore, we shifted to a revised version of whack-a-mole that was more reminiscent of a target shooting game. Our final iteration had two targets, where one would randomly pop up and then the user would have to hit the target with the ball. We felt this game was engaging and interactive, making it both a fun and technically challenging final.

Since we have had a basic concept down, which include work with buttons, LED lights and Twitter API, we have decided to continue to work on parts of our project which we have originally planned. However, we came across some problems. The Small Arduino Servo Motors that came with the original Arduino Kit were not powerful enough to support the bull’s eye, which we have attached to each motor. In the process of doing so, two of the motors (out of 5 broke), because they were very fragile to start with. We could not borrow the motors from the check-out room because they did no longer not have any, thus we asked some of our peers to lend us, but they did not have it either. Since the small servo motors were so prone to be broken and could not support the bull’s eye, we decided to go with the Bigger-Size Servo Motors. However, they only had two of them, so our initial idea of using 5 servo motors (one for each bull’s eye), came down to using two. Here is the picture of how it looked after we have switched our motors:

IMG_6900

While we were still working with big servo-motors, we have only taped them with scotch tape (middle bottom part of the above picture), instead of hot-glue gun gluing it, in case if we had to change the position of the servos (left side-right side). Thus, all of the bull’s eyes were laying on their right side, and they were going to pull-up by rotating anti-clockwise. The wires in the pictures have not yet been taped together because of we were in the stage of testing how each servo worked as well as the servo schematic. From this situation, we have learned that better planning strategy regarding our hardware parts should be implemented at early stages of our project, in order to later avoid downscaling the project, instead of shooting for more and pushing our limits. This is how it looked like:

IMG_6899

After we have tested our servos and made sure that they were wired properly, as well as that they were functioning correctly we have decided to glue it to the wooden framework using the hot-glue gun. However, just as we did that the middle servo-motor (out of total 3 servo-motors that we had) suddenly stopped working and we could not figure out why, so we have eventually ended up only using 2 big servo motors. However, after that, we have come across the issue of vibration sensor not working as intended. In our initial plan, we have decided to use the vibration sensor which would be placed being the bull’s eye, so each time that it would be hit, it would detect vibration, and send that information to an Arduino. However, the sensor only worked if we have pressed it very hard with our finger, and only then would it display the significant change in the vibration levels in the Arduino Serial Monitor. We have thought to test the sensor by putting it in the middle of bull’s eye, and hitting the exact middle with something extremely hard, however, that did not prove to be effective either.

However, we have finally managed to come up with another fairly successful solution – using the motion sensor. Although this is something that we haven’t planned from the start, we have decided to attach two motion sensors, one on top of each bull’s eye, which would track specific movement that comes within its range in case if the player hits the specific area of the bull’s eye (approx. strip line in the middle). The medium-sized balls that we made were created out of approx. 5 meters of scotch tape each. After careful consideration of the shooting range, and the height of the platform to which we have mounted the sensors onto. We have set values for the motion sensors in the Arduino: If the user threw a ball and a motion sensor would detect that the ball has successfully hit the bull’s eye, the Arduino would update the result for the specific player who was playing that part of the game. This is the video of the project working.

Although most of our hurdles were on the hardware side of things, our project was not without its software difficulties. Since we were working with the MKR1000 to have a wireless connection, we had to depend on the school IMA wifi. However, the network topography of our school’s wifi makes the MKR1000’s connection unreliable. Additionally, we both decided to use a simple, in place, sorting algorithm-which ordered a subset of a 2d array. This aspect, although simple to say proved to be hard in programming since we are used to programming in java-where data structures function very differently. Lastly, the area we spent a lot of time on was having an accurate timing system, where the US range sensor would read at the exact moment the motor swept to the top and would stop reading once it began to sweep down.  As a side note, working with Temboo proved to be unreliable and a finicky situation. In the end, our success rate (on temboo’s end) was hovering around 50%, which for a final project is not ideal.

If we were to do this again, we would plan our hardware components more carefully – everything from the servo-motors to the types of sensors that we are using. We would also go check-out particular part of hardware which is fairly popular several weeks before the project was due, in order to ensure that this part of hardware will be available. If we have access to any type of sensors at the moment, we would most likely use a different type of vibration sensors and increase the number of servo motors that we have decided to include. We could also potentially add the 4th player, so the number of all players for a single game is even, rather than odd, thus people can play it in pairs!

#include <Servo.h>

//LEADERBOARD
String leaderboard[4];
String finalMessage;
int runs = 0;

//Vibration and Motor VALUES
int pingPin = 9;
int pingPin2 = 10;


//MOTOR
Servo motor1;
Servo motor2;

//Game Variables
int score = 0;
int gameLength = 8;

//Libraries and Wifi
#include <SPI.h>
#include <WiFi101.h>
#include <Temboo.h>
WiFiClient client;
int status = WL_IDLE_STATUS;
#define WIFI_SSID "NYUSHIMA"
#define WPA_PASSWORD "Vlc5k$zf"

//Twitter Info
int calls = 1;   // Execution count, so this doesn't run forever
int maxCalls = 10;   // Maximum number of times the Choreo should be executed
String twitterName;

//Temboo Info
#define TEMBOO_ACCOUNT "robertp"  // Your Temboo account name 
#define TEMBOO_APP_KEY_NAME "myFirstApp"  // Your Temboo app key name
#define TEMBOO_APP_KEY "aLoLsqjPQQ5fFlgks7s8pXN11dBVegIv"  // Your Temboo app key

void setup()
{
  //Beginging Serial and Connecting to Wifi
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to WiFi network:
  
    while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(WIFI_SSID);
    //Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(WIFI_SSID, WPA_PASSWORD);

    // wait 10 seconds for connection:
    delay(10000);
    }
  
  Serial.println("Connected to wifi");

  //BUTTON SETUP
  Serial.begin(9600);
  getName();
  motor1.attach(6);
  motor2.attach(8);
}

void loop() {
  if (runs > 0) {
    {
      Serial.println();
      Serial.println("Get ready to play");
      Serial.println("3");
      delay(1000);
      Serial.println("2");
      delay(1000);
      Serial.println("1");
      Serial.println("START!");

      //THIS IS WHERE I RUN THE GAME
      int x = 0;
      while (x < gameLength) {
        motor1.write(0);
        motor2.write(0);
        int randNumber = random(2);
        if (randNumber == 0) {
          Serial.println("MOTOR 1");
          motor1.write(0);
          delay(2000);
          long duration, inches, cm;
          motor1.write(240);
          delay(500);
          long starttime = millis();
          long endtime = 0;
          while ((endtime - starttime) <= 3000) // do this loop for up to 1000mS
          {
            long duration, inches, cm;
            
            pinMode(pingPin, OUTPUT);
            digitalWrite(pingPin, LOW);
            delayMicroseconds(2);
            digitalWrite(pingPin, HIGH);
            delayMicroseconds(5);
            digitalWrite(pingPin, LOW);

            // The same pin is used to read the signal from the PING))): a HIGH
            // pulse whose duration is the time (in microseconds) from the sending
            // of the ping to the reception of its echo off of an object.
            pinMode(pingPin, INPUT);
            duration = pulseIn(pingPin, HIGH);
            cm = duration / 29 / 2;
            if (cm < 20 and cm > 3) {
              Serial.println("YOU HIT THE DANG BALL");
              score++;
              break;
            }
            endtime = millis();
            delay(100);
          }
        }
        if (randNumber == 1) {
          Serial.println("MOTOR 2");
          motor2.write(0);
          delay(2000);
          long duration, inches, cm;
          motor2.write(240);
          delay(500);
          long starttime = millis();
          long endtime = 0;
          while ((endtime - starttime) <= 3000) // do this loop for up to 1000mS
          {
            long duration, inches, cm;
            
            pinMode(pingPin2, OUTPUT);
            digitalWrite(pingPin2, LOW);
            delayMicroseconds(2);
            digitalWrite(pingPin2, HIGH);
            delayMicroseconds(5);
            digitalWrite(pingPin2, LOW);

            // The same pin is used to read the signal from the PING))): a HIGH
            // pulse whose duration is the time (in microseconds) from the sending
            // of the ping to the reception of its echo off of an object.
            pinMode(pingPin2, INPUT);
            duration = pulseIn(pingPin2, HIGH);
            cm = duration / 29 / 2;
            if (cm < 20 and cm > 3) {
              Serial.println("YOU HIT THE DANG BALL");
              score++;
              break;
            }
            endtime = millis();
            delay(100);
          }
        }
        x++;
      }
      checkLeaderboard();
      if (runs >= 3) {
        sendTweet();
      }
      score = 0;
      getName();
    }
  }
  runs++;
}

void getName() {
  Serial.println("Please enter your twitter name with the @ sign");
  Serial.println("If you do not have a twitter account, enter normal name");
  Serial.println();
  while (Serial.available() == 0) {}
  char rx_byte = 0;
  String rx_str = "";
  while (Serial.available() > 0) {    // is a character available?
    rx_byte = Serial.read();       // get the character

    if (rx_byte != 'n') {
      // a character of the string was received
      rx_str += rx_byte;
    }
  }
  rx_str.trim();
  twitterName = rx_str;
  Serial.println("Welcome " + twitterName + " to the game!");
}

void checkLeaderboard() {
  if (runs == 1) {
    leaderboard[0] = String(score) + twitterName;
  }
  else if (runs == 2) {
    if (leaderboard[0][0] < score) {

      leaderboard[0] = String(score) + twitterName;
    }
    else {
      leaderboard[1] = String(score) + twitterName;
    }
  }
  else {
    if (runs == 3) {
      leaderboard[2] = String(score) + twitterName;
    }
    else {
      leaderboard[3] = String(score) + twitterName;
    }
    String copy[4];
    for (int i = 0; i < 4; i++) {
      copy[i] = (leaderboard[i]);
    }
    for (int i = 0; i < (4); i++) {
      for (int o = 0; o < (4 - (i + 1)); o++) {
        if (copy[o][0] >= copy[o + 1][0]) {
          String t = copy[o];
          copy[o] = copy[o + 1];
          copy[o + 1] = t;
        }
      }
    }
    Serial.println();
    Serial.println("HERE IS THE CURRENT LEADERBOARD!!!!");
    String name1 = String(copy[3]);
    String score1 = String(copy[3][0]);
    name1.remove(0, 1);
    String name2 = String(copy[2]);
    String score2 = String(copy[2][0]);
    name2.remove(0, 1);
    String name3 = String(copy[1]);
    String score3 = String(copy[1][0]);
    name3.remove(0, 1);

    finalMessage = " " + name1 + " " + score1 + " " + name2 + " " + score2 + " " + name3 + " " + score3;
    Serial.println(finalMessage);
    Serial.println();
    leaderboard[0] = copy[3];
    leaderboard[1] = copy[2];
    leaderboard[2] = copy[1];
    leaderboard[3] = "";
  }
}

void sendTweet() {
  Serial.println("WIFI STATUS");
  Serial.println(status);

  TembooChoreo StatusesUpdateChoreo(client);

  // Invoke the Temboo client
  StatusesUpdateChoreo.begin();

  // Set Temboo account credentials
  StatusesUpdateChoreo.setAccountName(TEMBOO_ACCOUNT);
  StatusesUpdateChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
  StatusesUpdateChoreo.setAppKey(TEMBOO_APP_KEY);


  // Set Choreo inputs
  Serial.println(finalMessage);
  String StatusUpdateValue = "LEADERBOARD " + String(finalMessage);
  StatusesUpdateChoreo.addInput("StatusUpdate", StatusUpdateValue);
  String ConsumerKeyValue = "GCgsedFeeDPjGcXX6w7omleM4";
  StatusesUpdateChoreo.addInput("ConsumerKey", ConsumerKeyValue);
  String AccessTokenValue = "861505638966243330-NnNA8w7IiMYkKzlGhJv1vxpK2F3CAcj";
  StatusesUpdateChoreo.addInput("AccessToken", AccessTokenValue);
  String ConsumerSecretValue = "8ZkAB0IDCwPCg0w6gADnCzCRYufI4n7hSJkufS3UBCRa45vdPI";
  StatusesUpdateChoreo.addInput("ConsumerSecret", ConsumerSecretValue);
  String AccessTokenSecretValue = "sTCuHtTozozZvYVX3oFRIuF4tfLUOEXRpe1waaKU2R3AJ";
  StatusesUpdateChoreo.addInput("AccessTokenSecret", AccessTokenSecretValue);

  // Identify the Choreo to run
  StatusesUpdateChoreo.setChoreo("/Library/Twitter/Tweets/StatusesUpdate");

  // Run the Choreo; when results are available, print them to serial
  StatusesUpdateChoreo.run();

  while (StatusesUpdateChoreo.available()) {
    char c = StatusesUpdateChoreo.read();
    Serial.print(c);
  }
  twitterName = "";
  StatusesUpdateChoreo.close();
  Serial.println("nWaiting...n");
  delay(10000);
}

Leave a Reply