
Bonsai Breathing Backpack
Air pollution is rampant. biodiversity loss is at a critical level. My halloween costume is a discursive project that sparks conversation around humanity’s future quality of life. I built a personal oxygen device that creates a symbiotic relationship between a human and a single tree. The human and the tree exchange Carbon Dioxide for Oxygen to keep both organisms alive. The tree is held in a clear terrarium to enable photosynthesis, with a tube running from the encasement on the top to a gas mask on the human’s face. LED lights are placed under the lid of the encasement to create an organic, dynamic display that symbolizes life.
Arduino Techniques
I experimented with an Adafruit 12 RGBW neopixel display. Adafruit 24 RGB neopixel display and I experimented with different sketches including a Breathe. I settled on a continuous rainbow loop that runs around the top of the tree, forming a continuous halo.
Materials
- Nebulizer mask/tube
- Container Store canister
- Adafruit 24 RGB neopixel display
- Miady battery pack
- Wires
- Fake Tree
- Model bushes
- Hot glue
- Blue foam
- Soil
Steps
- create terrarium arrangement in canister
- solder wires to neopixel display
- select neopixel script to run
- hot glue neopixel display to interior of canister lid
- attach nebulizer tube to canister lid
Code
//Initialize
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Which pin on the Arduino is connected to the NeoPixels?
// On a Trinket or Gemma, change to 1:
#define LED_PIN 1
// How many NeoPixels are attached to the Arduino?
#define TOTAL_LEDs 25
// NeoPixel brightness, 0 (min) to 255 (max)
#define BRIGHTNESS 50 // Set BRIGHTNESS to about 1/5 (max = 255)
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(TOTAL_LEDs, LED_PIN, NEO_GRB + 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)
int MaximumBrightness = 255;
int SpeedFactor;
int StepDelay;
void setup() {
// These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
// Any other board, you can remove this part (but no harm leaving it):
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
clock_prescale_set(clock_div_1);
#endif
// END of Trinket-specific code.
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(BRIGHTNESS);
}
void loop()
{
//breathe(255, 0.008, 5);
rainbow(10);
}
void breathe(float MaximumBrightness, float SpeedFactor, float StepDelay)
{
// Make the lights breathe
for (int i = 0; i < 6000; i++) {
// Intensity will go from 10 - MaximumBrightness in a "breathing" manner
float intensity = MaximumBrightness /2.0 * (1.0 + sin(SpeedFactor * i));
strip.setBrightness(intensity);
// Now set every LED to that color
for (int ledNumber=0; ledNumber<TOTAL_LEDs; ledNumber++) {
strip.setPixelColor(ledNumber, 93, 153, 255);
}
strip.show();
//Wait a bit before continuing to breathe
delay(StepDelay);
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
// Hue of first pixel runs 5 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
// means we'll make 5*65536/256 = 1280 passes through this loop:
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
// strip.rainbow() can take a single argument (first pixel hue) or
// optionally a few extras: number of rainbow repetitions (default 1),
// saturation and value (brightness) (both 0-255, similar to the
// ColorHSV() function, default 255), and a true/false flag for whether
// to apply gamma correction to provide 'truer' colors (default true).
strip.rainbow(firstPixelHue);
// Above line is equivalent to:
// strip.rainbow(firstPixelHue, 1, 255, 255, true);
// Make the lights breathe
for (int i = 0; i < MaximumBrightness; i++) {
// Intensity will go from 10 - MaximumBrightness in a "breathing" manner
int intensity = i;
strip.setBrightness(intensity);
// // Now set every LED to that color
// for (int ledNumber=0; ledNumber<TOTAL_LEDs; ledNumber++) {
// strip.setPixelColor(ledNumber, 93, 153, 255);
// }
//strip.show();
//Wait a bit before continuing to breathe
//delay(StepDelay);
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
Circuit
