Skip to content

BubbleViz: Internet-enabled Bubble Gun

2009 April 26

BubbleViz is an internet-enabled toy bubble gun that uses an Arduino, XBee and ConnectPort to poll a PHP script and check an IMAP server for new messages, upon which the device showers you with a delightful cascade of bubbles.

View it in action:

More information, pictures and code follow!

It's not a bomb Bubble, bubble, toil and trouble Closeup of servo-controlled nozzle / bubble loop

As you can see, this project more than meets the “looks like a bomb” quota.

Here’s my relevant PHP code (using my modified Email to DB class):

include_once("class.emailtodb_tedb0t.php");
 
$edb = new EMAIL_TO_DB();
$edb->connect('imap.gmail.com:993', '/imap/ssl/novalidate-cert', 'username@gmail.com', 'password');
echo $edb->getNumNewMessages();
$edb->close();

Here’s the pertinent function from the classfile.  I’m certain there is a better, more logical way to do this.  We can’t use PHP Sessions because Rob’s ConnectPort server doesn’t implement them… maybe I will add that in ;)

function getNumNewMessages(){
	$myFile = "numMessages.txt";
	$fh = fopen($myFile, 'r');
	$lastNum = intval(trim(fgets($fh)));
	$currentNumMessages = $this->num_message();
	fclose($fh);
	$fh = fopen($myFile, 'w+');
	fwrite($fh, $currentNumMessages);
	fclose($fh);
 
	return $currentNumMessages - $lastNum;
}

And the Arduino code:

// BubbleViz
//   Bubble Gun Controller
//   by Ted Hayes <www.liminastudio.com>
 
#include 
 
#define PIN_SWITCH 4
#define PIN_MOTOR 12
#define DUR_MAX 3000
 
Servo myservo;
int lastRead = HIGH;
long i = 0;
int dur = 1000;
int durMult = 500;    // ms per new emails
int curByte;
int curVal;
int curDur;
 
void setup()
{
  Serial.begin(115200);
  pinMode(PIN_SWITCH, INPUT);
  pinMode(PIN_MOTOR, OUTPUT);
  digitalWrite(PIN_SWITCH, HIGH);  // set pullup on pin 2
  digitalWrite(PIN_MOTOR, LOW);    // motor off
 
  //// software serial
  pinMode(rx,INPUT);
  pinMode(tx,OUTPUT);
  digitalWrite(tx,HIGH);
 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  myservo.write(80);  // reset to "closed" position
}
 
void loop()
{
  int switchRead = digitalRead(PIN_SWITCH);
  if(switchRead == LOW && lastRead == HIGH){
    fire(dur);
  }
  lastRead = switchRead;
 
  if (Serial.available() > 0) {
    curByte = Serial.read();
    curVal = curByte - 48;    // "decodes" ASCII number to DEC number
 
    if(curVal > 0){
      curDur = durMult * curVal;    // ms * num of new emails
      if(curDur > DUR_MAX) curDur = DUR_MAX;
      fire(curDur);
    }
  }
 
  // poll web script every n iterations of loop (as opposed to using delay())
  if(i > 300000){
    Serial.print("http://verge.myftp.org:81/Listereen/emailtodb_v0/check_mail.php");
    i=0;
  }
  i++;
}
 
void fire(int duration){
  // trigger gun motor
  digitalWrite(PIN_MOTOR, HIGH);
  delay(300);               // wait for loop to wet
  myservo.write(105);          // pull loop out
  delay(duration);                 // wait for bubbles to blow
  // reset motor and servo
  digitalWrite(PIN_MOTOR, LOW);
  myservo.write(80);
}

Related Posts: