The Luxe Capacitor

DESCRIPTION:
I started out aiming to recreate the Flux Capacitor from Back to the Future, as part of my Marty McFly costume. I wanted to recreate a prop as I’m interested in prop design, and design for entertainment. However, I wanted to put my own spin on it, and decided that I would make a Luxe Capacitor, and I would wear it be wearable.
I came away with quite a few learnings from this process. Overall, I struggled to figure out the order in which to complete steps. For example, I spray painted individual components and then realized that it prevented adhesion when I started to glue everything together. Upon completion, I think I have a better (not perfect) sense in how I would order my to do list if repeating this process. I created my own dielines for the box (which I then laser cut), and I made the mistake of not leaving extra room for the insert to fit into the box. Lastly, I didn’t test my circuit while soldering. It worked out, but if I encountered errors then I wouldn’t have had any idea which connection was causing the issue.


PROGRESS:







MATERIALS:
Hardware
– 3 RGBW NeoPixels (8 LEDs per strip)
– Adafruit Gemma M0
– Tactile Switch Button
– Power Bank
Other Supplies
– Chipboard
– Solder
– Stranded Wire
– Gold Spray paint
– Transparent polyester film (from Artist & Craftsman Supply)
– Clear PVC tubing (from Canal Rubber)
– Thin silicon tubing (from Canal Rubber, leftover from 3DPD1)
– Hose (from Canal Rubber)
– Large flat washers (from Canal Lighting & Parts)
– Chain (from Canal Lighting & Parts)
– Gold lable tape
– Silicon Spark plug Boot
– Paint for spark plug (orange, yellow)
Tools
– Soldering Iron
– Wire Snips
– Wire Strippers
– Hot Glue Gun/
– Box Cutter/X-Acto
– Label Maker (Thank you Tristan!)
– Drill
CIRCUIT DIAGRAM:

ARDUINO CODE:
// Simple demonstration on using an input device to trigger changes on your
// NeoPixels. Wire a momentary push button to connect from ground to a
// digital IO pin. When the button is pressed it will change to a new pixel
// animation. Initial state has all pixels off -- press the button once to
// start the first animation. As written, the button does not interrupt an
// animation in-progress, it works only when idle.
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Digital IO pin connected to the button. This will be driven with a
// pull-up resistor so the switch pulls the pin to ground momentarily.
// On a high -> low transition the button press logic will execute.
#define BUTTON_PIN 0 // Gemma M0 D0 for button input
#define PIXEL_PIN 1 // Digital IO pin connected to the NeoPixels (Gemma M0 default)
#define PIXEL_COUNT 8 // Number of NeoPixels
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRBW + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
boolean oldState = HIGH;
int mode = 0; // Currently-active animation mode, 0-9
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
// Get current button state.
boolean newState = digitalRead(BUTTON_PIN);
// Check if state changed from high to low (button press).
if ((newState == LOW) && (oldState == HIGH)) {
// Short delay to debounce button.
delay(20);
// Check if button is still low after debounce.
newState = digitalRead(BUTTON_PIN);
if (newState == LOW) { // Yes, still low
if (++mode > 3) mode = 0; // Advance to next mode, wrap around after #3
switch (mode) { // Start the new animation...
case 0:
fluxChase(0, 0, 0, 0, 0); // off
break;
case 1:
fluxChase(255, 180, 0, 20, 100); // light chase, 100ms delay per frame
break;
case 2:
fadeEffect(255, 180, 0, 20, 5); // slow fade
break;
case 3:
fadeEffect(255, 180, 0, 20, 2); // fast fade
break;
}
}
}
// Set the last-read button state to the old state.
oldState = newState;
}
// Animated chasing glow
void fluxChase(uint8_t r, uint8_t g, uint8_t b, uint8_t w, int delayTime) {
for (int loop = 0; loop < 6; loop++) { // looping - renamed from 'i' to avoid shadowing
for (int step = 0; step < PIXEL_COUNT * 1; step++) {
strip.clear();
for (int i = 0; i < PIXEL_COUNT; i++) {
int offset = (step + i) % PIXEL_COUNT;
float fade = 1.0 - (float)i / PIXEL_COUNT; // trailing dimmer effect
strip.setPixelColor(offset, strip.Color(r * fade, g * fade, b * fade, w * fade));
}
strip.show();
delay(delayTime);
}
}
}
// Smooth fade in/out
void fadeEffect(uint8_t r, uint8_t g, uint8_t b, uint8_t w, int speed) {
for (int loop = 0; loop < 4; loop++) { // looping - renamed from 'i' for clarity
// Fade in
for (int brightness = 0; brightness <= 255; brightness++) {
setAllBrightness(r, g, b, w, brightness);
delay(speed);
}
// Fade out
for (int brightness = 255; brightness >= 0; brightness--) {
setAllBrightness(r, g, b, w, brightness);
delay(speed);
}
}
}
// Helper for setting all pixels to same brightness
void setAllBrightness(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t brightness) {
for (int i = 0; i < PIXEL_COUNT; i++) {
strip.setPixelColor(i, strip.Color(
(r * brightness) / 255,
(g * brightness) / 255,
(b * brightness) / 255,
(w * brightness) / 255
));
}
strip.show();
}