Motoring on through!

At the beginning of the run, the ball sits at the bottom of the run awaiting the elevator to turn on and carry it to the top. This was the simplest solution for having a single run setup. In order to start and stop the elevator component, the motor needed to be modified so that it could be controlled by the arduino.

There were two ways to do this. As the motor consisted of a power source and a switch we could have done one of the following:

  • Disassemble or replace the switch, allowing the arduino to control the power flow
  • Attach new wires to the power source input and use the arduino to power the elevator leaving the switch always on.

In the end, I decided to go for the latter mainly because I would be able to use the whole elevator/motor system as it was manufactured in the future should I wish whereas with the first method I would have always needed an arduino.

The process of doing this was simply soldering on additional wires, drilling a small hole in the housing to allow them to come out and then connecting these to the arduino. The option did have the added difficulty that we had to use a PWM pin in order to provide the correct amount of power and a transistor to make it into direct current. The results were what we envisaged and this part of the project worked faultlessly from the start.

Break a beam!

Well, not quite don’t break a leg but it’s close!

 

An integral part of the project was detecting where the ball was and whether it had passed a certain point or not. In order to do this I used some phototransitors coupled with some IR emitters as an improvised beam trip. When the ball passes between the phototransistors and IR emitter the arduino is able to detect the slight drop in the readings which indicates the ball has travelled past. This meant that we could flip booleans in the logic to indicate where the ball was in the system.

We had a slight issue with the bouncing of the sensors because occasionally the light levels would fluctuate and due to the fact the phototransistors detect a much wider range of light than an IR detector, it would occasionally simulate tripping the beam. To ensure this really was a ball passing through I wrote a small segment of code to ensure that the beam break time was synonymous with a real break.

Once I had created a working prototype on the breadboard I then created several smaller beam break modules using small squares of stripboard. These were mounted onto the small clips that held the track together and then the Emitter and phototransistor were aligned for best results.

The Final Product

I thought we probably should have shared with you all the results so here we are!

20140326_131837

We detected where the ball was using a ‘break the beam’ style and recorded the events from the Arduino in Processing using Firmata. Here is the code for those interested:

import twitter4j.conf.*;
import twitter4j.*;
import twitter4j.auth.*;
import twitter4j.api.*;
import java.util.*;
import processing.video.*;
import processing.serial.*;
import cc.arduino.*;

Arduino arduino;

Twitter twitter; //twitter instance
String searchString = “#heyHoLetsGoBall”; //hashtag to search for
List<Status> tweets; //list of tweets

Capture cam; //camera

int currentTweet; //int to hold the current number of tweets
int runsDone = 0; //how many times has the run function completed
int runTime = 0;
int sensitivity = 10;

int elevatorPin = 3;
int sector1LED = 8;
int sector2LED = 7;
int sector1Gate = 0;
int sector2Gate = 1;

void setup()
{
size(640, 480);

arduino = new Arduino(this, Arduino.list()[0], 57600);
arduino.pinMode(elevatorPin, Arduino.OUTPUT);
arduino.pinMode(sector1LED, Arduino.OUTPUT);
arduino.pinMode(sector2LED, Arduino.OUTPUT);
arduino.pinMode(sector1Gate, Arduino.INPUT);
arduino.pinMode(sector2Gate, Arduino.INPUT);
arduino.digitalWrite(sector1LED, Arduino.HIGH);
arduino.digitalWrite(sector2LED, Arduino.HIGH);
//analog read 0 and 1 for gates

String[] cameras = Capture.list(); //list of available cameras

if (cameras.length == 0) {
println(“No cameras available”);
exit();
}
else {
println(“Cameras available:”);
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}

cam = new Capture(this, cameras[1]);
cam.start(); //start camera 
}

ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey(“TOwvucqrfEsfkOHKy7DhQ”);
cb.setOAuthConsumerSecret(“4MmWFfRLqVDqP3S8cXaXz3lalmqaSx9EFUkuXdKlCKI”);
cb.setOAuthAccessToken(“2332151977-viWko3JzJvo1VrSk7z3kqYVwVULvfpYJAizh3Gq”);
cb.setOAuthAccessTokenSecret(“17q8peS67ZWmd2cF8W2vzGkQZIjgvXM0Xxi8rUhuFh4uA”);
//add all the keys necessary for Twitter authentication

TwitterFactory tf = new TwitterFactory(cb.build()); //use authentication

twitter = tf.getInstance(); //pass twitter factory to the instance of twitter

getNewTweets(); //check for all current tweets containing the search query

currentTweet = tweets.size(); //this stops the run starting from preexisting tweets
println(currentTweet);
thread(“refreshTweets”); //refresh tweets is run in a seperate thread, evert 30 seconds it calls getNewTweets
}

void draw()
{

if (cam.available() == true) {
cam.read();
}

set(0, 0, cam); //display the camera
}

void getNewTweets()
{
try //try catch because the internet is a risky place
{
Query query = new Query(searchString); //add the string to be matched to the query

QueryResult result = twitter.search(query); //query twitter

tweets = result.getTweets(); //store the results in an array list
}
catch (TwitterException te)
{
System.out.println(“Failed to search tweets: ” + te.getMessage());
System.exit(-1); //exit on fail
}
}

void refreshTweets()
{
while (true) //just keep running
{
getNewTweets(); //check for new tweets

println(“Updated Tweets”);
if (tweets.size() > currentTweet) { //there is a new tweet!
//start
println(“new tweet received”);
startRolling();
sendTweet(); //send a tweet in response
currentTweet = tweets.size(); //mark the new size of matching tweets
println(“Current matching tweets = ” + currentTweet);
}
delay(30000); // Mustn’t request information too often
}
}

void sendTweet() {
try {
runsDone++; //called again
String t = “Just completed run number ” + runsDone + “! (Runs count since I last booted up) in ” + runTime + ” seconds!”;//make up the string to tweet
StatusUpdate status = new StatusUpdate(t);
File file = new File(“/Users/fearnbrocks/Documents/Processing/tweetRoller2/data/image.jpg”);
status.setMedia(file); //add image
twitter.updateStatus(status); //update the status with the above string
println(“Successfully updated the status to [” + status + “].”);
file.delete(); //delete image
}
catch(TwitterException e) { //print error code if update fails
println(“Send tweet: ” + e + ” Status code: ” + e.getStatusCode());
}
}

void startRolling(){
int sector=1;
runTime=0;
int startTime = millis();
////////////
arduino.analogWrite(elevatorPin, 250);//I’m giving her all she’s got captain
delay(5500);
arduino.analogWrite(elevatorPin, 0);
while(sector == 1){
//Illuminate sector 1
boolean gate1Broken = false;
int gate1Previous = arduino.analogRead(sector1Gate);
int gate1Current = gate1Previous;
int breakCount = 0;
int firstBreak = 0;
while(!gate1Broken){
gate1Current = arduino.analogRead(sector1Gate);
if(gate1Current > 600){ // || gate1Current > gate1Previous+sensitivity){
if(millis() – startTime > 5){
breakCount++;
}
if(breakCount > 1 && millis() – firstBreak < 1){
gate1Broken = true;
delay(300);
saveFrame(“/Users/fearnbrocks/Documents/Processing/tweetRoller2/data/image.jpg”); //save still from camera
int newSector = sector+1;
print(“Gate 1 broken with value “);
print(gate1Current);
print(“. Sector “);
print(newSector);
println(” active!”);
sector++;
} else {
if(breakCount == 1){
firstBreak = millis();
}
if(breakCount > 2){
breakCount = 0;
firstBreak = 0;
}
}
} else {
gate1Previous = gate1Current;
}
}
}

while(sector == 2){
boolean gate2Broken = false;
int gate2Previous = arduino.analogRead(sector2Gate);
int gate2Current = gate2Previous;
int breakCount = 0;
int firstBreak = 0;
while(!gate2Broken){
gate2Current = arduino.analogRead(sector2Gate);
if(gate2Current > 600){ // || gate1Current > gate1Previous+sensitivity){
if(millis() – startTime > 5){
breakCount++;
}
if(breakCount > 1 && millis() – firstBreak < 1){
gate2Broken = true;
println(“Gate 2 broken. Run Complete!”);
//we’re at the end!
int finishTime = millis();
runTime = finishTime – startTime;
print(“Your run took: “);
int runSeconds = runTime /1000;
runTime = runSeconds;
print(runSeconds);
println(” seconds to complete!”);
sector = 0;
} else {
if(breakCount == 1){
firstBreak = millis();
}
if(breakCount > 2){
breakCount = 0;
firstBreak = 0;
}
}
} else {
gate2Previous = gate2Current;
}
}
}

}