The 10K Celebration Machine


Using engineering to create a completely over-engineered machine to pop balloons and make a huge mess- all in the name of celebration!

What better way to celebrate reaching a milestone in my social media career than to create this silly, over engineered machine with the sole purpose of popping balloons filled with confetti.

the balloon popping machine!

As many projects do, the scope of this project grew. What started with the question, how can I pop balloons in a fun way, ended up as 4 engineered sub systems complete with servo motors, an Arduino controller, a 3d printed print-in-place chain (download will be available soon) and a hobby knife on a gantry slider system. The celebratory hands were just the icing on the cake.  These were based off the Raise Da Roof sculpture, but scaled way up (3 times larger).

HUGE up and down celebratory hands machine

The balloons ride on a chain and sprocket conveyor belt. The chain is made up of a bunch of print in place chain segments connected together with a 3D Printed pin.  The sprockets are mounted onto a boom tripod stand, and driven by a servo modified to run continuously.  I then hot glued the balloons to the chain (I know, I could've come up with a more elegant and reliable solution here).

Attaching balloons to conveyor belt

As the machine starts spinning the balloons along the belt, the knife slowly makes it's way up the slider on its linear bearings towards the balloons.  This is made up of some parts from amazon and some 3D printed brackets designed to clamp onto the vertical post of the tripod.  Using another modified servo motor to drive it, and some time based dead reckoning, the knife slider worked like a charm!

Knife Gantry slider thingamajig

As soon as the knife is high enough, mayhem ensues. Balloons popping, confetti flying. True celebration! I want to give a huge thank you to all that support me at the intersection of Art and Engineering! 

If you would like to support me and the creation of future engineered art projects, please consider becoming a JBV Creative patreon member: https://www.patreon.com/Jbvcreative 

Here is the code I used to run the machine.  I had to make use of Arduino's millis() function to keep the hands moving up and down throughout the machine sequence, while triggering 'timeline events' (Is this the TVA?) for the chain starting, then the knife rising up, then the knife stopping.  There was a bug in my code for the knife stopping, which is why the last balloon didn't pop.  If you can catch the bug, shoot me an email to jbvcreative@gmail.com and let me know how I can fix my shit :)

There is some code in here for 'drop sequence'.  Originally, the plan was to have the 10K balloons drop using a servo actuated dropper.  This was installed, complete with a servo motor hot glued to the wall above the machine.  In theory, it worked great.  Theory means when only 1 servo was connected to the system.  In practice, one I had all 5 servos running, the drop servo seemed to have some issues with twitchiness (not the live streaming kind) and would randomly drop the balloons mid machine run.  To prevent that from happening, I went with a more low-tech solution of having my girlfriend toss the rope to pull the balloons down.  Less satisfying, I know, but it still looked great in the video.  Of course, the rope didn't quite work the first time, which is why you might notice a little camera trick if you look carefully enough (our little secret).

Ok, enough rambling- here is the code!

#include <Servo.h>

Servo knifeServo;
Servo chainServo;
Servo handsServo1;
Servo handsServo2;
Servo balloonServo;

const int handsPeriod = 1000;
const int upPosition1 = 45;
const int upPosition2 = 80;
const int downPosition1 = 145;
const int downPosition2 = 170;
bool handsAreUp = false;

bool knifeStarted = false;
const int raiseValue = 60;
const int stopValue = 90;
const int knifePeriod = 6000;
const int knifeDelay = 16000;

bool chainIsRunning = false;
const int chainStartTime = 3000;
const int runChainValue = 90;
const int stopChain = 105;

bool dropSequence = false;
bool dropHappen = false;
const long dropDelay = 1000;
const int dropAngle = 150;
const int holdAngle = 40;

unsigned long previousTime = 0;
unsigned long previousTimeChain = 0;
unsigned long previousTimeKnife = 0;
unsigned long previousTimeDrop = 0;

void setup() {
  Serial.begin(9600);
  balloonServo.write(holdAngle);
  knifeServo.write(stopValue);
  chainServo.write(stopChain);
  handsServo1.write(downPosition1);
  handsServo2.write(downPosition2);
  
  knifeServo.attach(5);
  chainServo.attach(9);
  handsServo1.attach(10);
  handsServo2.attach(11);
  balloonServo.attach(6);
  while(!Serial.available()){}
  while(Serial.available()){Serial.read();}
  Serial.println("Starting Program");
  delay(20);
  while(Serial.available()){Serial.read();}
  previousTimeChain = millis();
  previousTimeKnife = millis();
}
void loop() {
  
  unsigned long currentTime = millis();
  if(currentTime - previousTime >= handsPeriod)
  {
    moveHands();
    previousTime = currentTime;
    if (dropSequence == true){
      Serial.println("Setting drop time");
      previousTimeDrop = currentTime;
      dropSequence = false;
      dropHappen = true;
    }
  }
  if(currentTime - previousTimeChain >= chainStartTime)
  {
    if(chainIsRunning == false){
      Serial.println("starting chain");
      chainServo.write(runChainValue);
      chainIsRunning = true;
    }else{}
  }
  
  if(currentTime - previousTimeKnife >= knifePeriod)
  {
    if(knifeStarted == true){}
    else{
      Serial.println("starting knife");
      knifeServo.write(raiseValue);
      knifeStarted = true;
      previousTimeKnife = currentTime;
      
    }
  }
  if(currentTime - previousTimeKnife >= knifeDelay)
  {
    if(knifeStarted == false){}
    else{
      Serial.println("Stopping knife");
      knifeServo.write(stopValue);
      knifeStarted = false;
    }
  }
  if(Serial.available()>0){
    dropSequence = true;
    Serial.println("Stopping Chain");
    chainServo.write(stopChain);
    delay(20);
    while(Serial.available()){Serial.read();}
    
  }
  if(currentTime - previousTimeDrop >= dropDelay && dropHappen == true)
  {
    Serial.println("Dropping Balloons");
    balloonServo.write(dropAngle);
    dropHappen = false;
  }
}
void moveHands(){
  if(handsAreUp == true){
    Serial.println("Hands Down");
    handsServo1.write(downPosition1);
    handsServo2.write(downPosition2);
  }
  else
  {
    Serial.println("Hands Up");
    handsServo1.write(upPosition1);
    handsServo2.write(upPosition2);
  }
  handsAreUp = !handsAreUp;
  
}