Front view of party button with power at resting state of red loading lights.
This project is a party button meant to help celebrate the smaller wins in life, making them feel more momentous. The party button can be pressed to trigger a celebratory sequence, including a fun light show, music, and a small confetti popper.
Side view of the party button showing a detailed confetti launcher mechanism: a DC motor with a rotating pin that catches and pulls a string attached to the confetti popper, triggering its release.
Close-up of the speaker grille in a dimly lit setting, highlighting the glow of the light strip around the outside of the device.
Top view of the project showing the central button surrounded by a ring of illuminated LEDs. In the corner, the opening for the confetti launcher is also visible.
Party button in its resting state while plugged in, displaying a red loading light.
First run of the party button being pressed after full assembly.
This video shows the final run of the party button sequence when pressed, including the confetti launch and light effects. (Turn up the volume to hear the music.)
Modeling the space in the housing for the confetti popper. This shows the measured dimensions of the popper as a section that was then revolved.
Wiering setup before being housed.
DC motor being used in party button.
Servo motor and quick string pull mechanism prototype. (This was too weak to pull the string of the popper so ened up using the DC motor that used an external power source)
small scale test of the confetrtie popper withour being in full project housing.
light and music test 1
light and music test 2
Wiring setup with confetti popper attached the a servo motor.
testing the loading light movment to swirl and fade red lights around the neopixle ring.
When creating and designing this device, I chose to approach it by first figuring out all of the coding and electrical components. I tested the lights, then the sound, and finally the confetti mechanism. After confirming that each component worked individually, I integrated everything into the housing.
I was able to experiment extensively with the light colors and also decided to create a custom audio file for the music. For the confetti mechanism, I initially built a small-scale version to hold the popper and test its functionality. Once that was successful, I moved on to designing the full housing.
While designing the housing, I intentionally included space for the lighting system as well as diffusing covers to enhance the overall visual effect.
3. Discussion
(instructions are embedded below)
Address all of the prompts below. It is best to address all of these topics in a natural piece of prose. However, if you prefer, you may write four disjoint paragraphs, each of which is addressing a prompt. (The first way is better.) In total, this section should be ~300–500 words.
A reminder that as outlined in the course syllabus, you are strictly prohibited from using any generative AI service or writing assistant in your reflection/discussion.
Response to comments gathered during the in-class crit. Quote (verbatim) from *at least* two written critiques that you received (positive, negative, or otherwise) from the in-class crit, and respond to them. (You may agree or disagree—in either case, explain your position.) You can access the written critique feedback by going to the class's Shared Drive and opening "11/5/25 Project 2 Final Critique feedback".
Self critique pertaining to the project. Are you happy with how the project came out? Did it satisfy your own goals? This *should not* simply be a recital of your process, but rather a meaningful reflection.
What you learned about your own abilities and/or limitations through the process of working on this project. These could be technical in nature (i.e. "I found that coding this particular behavior was surprisingly difficult"), or not (i.e. "I enjoyed making cardboard forms very much, and I think it will be a useful prototyping medium for me in the future"). What would you do differently next time? What would your advice to your past self be? Did you get hung up at a particular point in progress, or fail to see an easy workaround to a problem? Did you find a creative spark you didn't anticipate? Etc.?
Next steps. Do you expect to build another iteration of this project? If so, describe what you're planning to do. If not, describe what you *would* do if you were to build another iteration, based on the experience you had with this first one.
4. Technical information
4a. Include **schematic and block diagrams**, drawn in https://draw.ioref.org, and exported from that software as .png images.
The block diagram should legibly show all inputs, computational steps, and outputs of your project. The schematic should be done so that a competent person, reading your drawing and with the appropriate parts, could recreate the electrical system of the project. For both schematics and block diagrams, follow all of the standards described on the course schematics guidance page.
/*
Party Button
The party button plays music, does a fun light show, and sets off a confetti
popper using a DC motor when a button is pressed, and triggers the sequence.
This device uses an Adafruit music shield, two speakers, a button, a DC motor,
a 24-light RGBW neopixel light ring, and an RGB LED strip.
pin mapping:
Arduino pin | role | details
------------------------------
2 input button
5 output DC motor
8 output NeoPixle ring
9 output LED strip
13 output music maker shield
12 output music maker shield
11 output music maker shield
7 output music maker shield
6 output music maker shield
4 output music maker shield
3 output music maker shield
Sophie Heap, sheap@andrew.cmu.edu
*/
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <Adafruit_NeoPixel.h>
#include <Servo.h>
// ---------------- VS1053 SETUP ----------------
#define SHIELD_RESET -1
#define SHIELD_CS 7 // VS1053 CS
#define SHIELD_DCS 6
#define DREQ 3
#define CARDCS 4
// ---------------- BUTTON ----------------
#define BUTTON_PIN 2
// ---------------- NEOPIXELS ----------------
#define RING_PIN 8
#define STRIP_PIN 9
#define NUMPIXELS_RING 24
#define NUMPIXELS_STRIP 40
// ---------------- DC MOTOR ----------------
#define MOTOR_PIN 5 // Arduino pin to control transistor/MOSFET
bool motorRunning = false;
unsigned long motorStartTime = 0;
// VS1053 player object
Adafruit_VS1053_FilePlayer musicPlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
// NeoPixel objects
Adafruit_NeoPixel ring(NUMPIXELS_RING, RING_PIN, NEO_GRBW + NEO_KHZ800);
Adafruit_NeoPixel strip(NUMPIXELS_STRIP, STRIP_PIN, NEO_GRB + NEO_KHZ800);
int position = 0;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(MOTOR_PIN, OUTPUT); // control pin for motor
digitalWrite(MOTOR_PIN, LOW); // motor off at start
// ----- VS1053 -----
if (!musicPlayer.begin()) {
Serial.println("Couldn't find VS1053!");
while(1);
}
Serial.println("VS1053 ready!");
if (!SD.begin(CARDCS)) {
Serial.println("SD card failed or not present");
while(1);
}
Serial.println("SD card ready!");
musicPlayer.setVolume(0, 0); // Loudest
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
// ----- NeoPixels -----
ring.begin(); ring.show();
strip.begin(); strip.show();
}
void loop() {
// Check if button pressed
if (digitalRead(BUTTON_PIN) == LOW) {
// Start music (non-blocking)
musicPlayer.startPlayingFile("/TRACK002.MP3");
// --- Start motor ---
digitalWrite(MOTOR_PIN, HIGH);
motorStartTime = millis();
motorRunning = true;
Serial.println("Button pressed! Playing music and lights...");
// Light show duration (match song length or set time)
unsigned long startTime = millis();
unsigned long showDuration = 17000; // 18 seconds light show
while (millis() - startTime < showDuration) {
// ---- Motor auto shutoff after 2 seconds ----
if (motorRunning && millis() - motorStartTime >= 500) {
digitalWrite(MOTOR_PIN, LOW);
motorRunning = false;
Serial.println("Motor OFF after 2 seconds");
}
rainbowFlash();
spiralRainbow(2, 10);
}
// Wait for music to finish if still playing
while(musicPlayer.playingMusic) {
// Could add idle lights here if desired
delay(50);
}
Serial.println("Playback and light show finished.");
// Wait for button release to prevent retrigger
while(digitalRead(BUTTON_PIN) == LOW) { delay(10); }
}
// Idle red fade trail
redFadeTrail();
}
// ---- Idle red fading trail ----
// ---- Smooth idle red fade trail (brightness 10-255) ----
void redFadeTrail() {
static float phase = 0; // continuous phase for smooth movement
float speed = 0.2; // adjust for faster/slower movement
int minBrightness = 10; // minimum brightness
int maxBrightness = 255; // maximum brightness
for(int i = 0; i < NUMPIXELS_RING; i++){
float angle = (i * 2 * PI / NUMPIXELS_RING) + phase;
int brightness = (sin(angle) * 0.5 + 0.5) * (maxBrightness - minBrightness) + minBrightness;
ring.setPixelColor(i, brightness, 0, 0, 0);
}
ring.show();
for(int i = 0; i < NUMPIXELS_STRIP; i++){
float angle = (i * 2 * PI / NUMPIXELS_STRIP) + phase;
int brightness = (sin(angle) * 0.5 + 0.5) * (maxBrightness - minBrightness) + minBrightness;
strip.setPixelColor(i, brightness, 0, 0);
}
strip.show();
phase += speed;
if(phase > 2 * PI) phase -= 2 * PI; // wrap phase continuously
delay(30); // smaller = smoother
}
// ---- Flash rainbow ----
void rainbowFlash() {
uint32_t ringColors[] = {
ring.Color(255, 0, 0, 0),
ring.Color(255, 255, 0, 0),
ring.Color(0, 255, 0, 0),
ring.Color(0, 0, 255, 0),
ring.Color(180, 0, 255, 0),
ring.Color(255, 0, 120, 0)
};
uint32_t stripColors[] = {
strip.Color(255, 0, 0),
strip.Color(255, 255, 0),
strip.Color(0, 255, 0),
strip.Color(0, 0, 255),
strip.Color(180, 0, 255),
strip.Color(255, 0, 120)
};
for(int i=0; i<6; i++){
ring.fill(ringColors[i]);
strip.fill(stripColors[i]);
ring.show();
strip.show();
delay(150);
ring.clear();
strip.clear();
ring.show();
strip.show();
delay(150);
}
}
// ---- Spiral rainbow ----
void spiralRainbow(int rotations, int shiftDelay){
for(int r=0; r<rotations; r++){
for(int i=0; i<NUMPIXELS_RING; i++){
for(int j=0; j<NUMPIXELS_RING; j++){
int colorIndex = (j + i) % NUMPIXELS_RING;
ring.setPixelColor(j, Wheel((colorIndex * 256 / NUMPIXELS_RING) & 255));
}
for(int j=0; j<NUMPIXELS_STRIP; j++){
int colorIndex = (j + i) % NUMPIXELS_STRIP;
strip.setPixelColor(j, WheelRGB((colorIndex * 256 / NUMPIXELS_STRIP) & 255));
}
ring.show();
strip.show();
delay(shiftDelay);
}
}
}
// ---- Color wheels ----
uint32_t Wheel(byte WheelPos){
WheelPos = 255 - WheelPos;
if(WheelPos < 85) return ring.Color(255 - WheelPos*3, 0, WheelPos*3, 0);
else if(WheelPos < 170){ WheelPos -= 85; return ring.Color(0, WheelPos*3, 255 - WheelPos*3, 0); }
else { WheelPos -= 170; return ring.Color(WheelPos*3, 255 - WheelPos*3, 0, 0); }
}
uint32_t WheelRGB(byte WheelPos){
WheelPos = 255 - WheelPos;
if(WheelPos < 85) return strip.Color(255 - WheelPos*3, 0, WheelPos*3);
else if(WheelPos < 170){ WheelPos -= 85; return strip.Color(0, WheelPos*3, 255 - WheelPos*3); }
else { WheelPos -= 170; return strip.Color(WheelPos*3, 255 - WheelPos*3, 0); }
}