Before You Start
If this is your first foray into the world of arduino-based microcontrollers, you'll need to install some software first. Head over to the Circuit Playground Lesson 0 guide for detailed installation and setup instructions.
FastLED Library
You will also need to install the FastLED library in Arduino (Sketch > Include Library > Manage Libraries...
)
One other note: if you're using FastLED with Circuit Playground, be sure to #include
the Circuit Playground library FIRST and theFastLED library second, or you may run into problems.
Upload Code
Once you've got everything installed and your computer can talk to the Circuit Playground, it's time to upload the code.
Plug your Circuit Playground into your computer and select the Circuit Plaground under Tools > Boards
. Then select the Circuit Playground as the Port.
Copy and paste this code (by Phil Burgess) into a new Arduino window and click "upload".
// "Amazon bracelets" sketch for Circuit Playground and NeoPixels. // Press the RIGHT button on Circuit Playground for AUTO mode -- LEDs // are then ON most of the time, best for photographing one's get-up. // Press the LEFT button for DEFLECT mode -- LEDs are off until a loud // sound or fast movement are detected. Pew pew! Deflect bullets! // Triumph not with fists or firepower, but with love! #include <Adafruit_CircuitPlayground.h> #include <FastLED.h> #define CP_PIN 17 // Circuit Playground's NeoPixels are on pin 17 #define CP_LEN 10 // Number of NeoPixels on Circuit Playground #define STRIP_PIN 6 // NeoPixel strip is connected to this pin #define STRIP_LEN 13 // Length of NeoPixel strip #define SINGLES_PIN 12 // Single NeoPixels are connected to this pin #define SINGLES_LEN 2 // Number of NeoPixel singles in chain #define COLOR_ORDER GRB #define FPS 80 // Animation frames-per-second #define TRIGGER_TIME 250000 // Debounce time after sound/motion trigger (microseconds) // SOUND REACTIVE SETUP -------------- // Higher number = less sensitive (louder sound required to trigger) #define SOUND_THRESHOLD 200 // Range 0 to 341 // MOTION REACTIVE SETUP -------------- // Higher number = less sensitive (faster acceleration required to trigger) #define G_THRESHOLD 3.0 // Range 1.0 to 8.0 G's int deflectionping = 1; // Bullet deflection "ping" sound. Change to 0 to turn this off // LED animation patterns cycle among several states. There are two main modes // (selected with the two buttons on Circuit Playground), each with some sub-states. // In the 'auto' mode, the animation happens on its own, not in response to sound // or motion. In this mode it alternates between two states -- an 'idle' state // with a solid color, and a periodic random flicker to add interest. Best for // photography, as it's all lit up most of the time. In the 'deflect' mode, // animation happens in response to sound and motion -- certain stimuli trigger a // series of states for a 'deflected bullet' animation. These goes from idle // (awaiting sound/motion), flicker (the initial animation upon a 'bullet hit'), // solid (brief state after hit) and back to idle (during which any lit LEDs will // slowly fade), unless another bullet is deflected. // An 'enumeration' is just the thing for this -- it's a C feature that creates a // list of sequential integer constants by name, and ensures any variables of this // type are not assigned outside the list. enum { AUTO_IDLE, // Auto mode (no sound/motion reaction) idle appearance AUTO_FLICKER, // Auto mode, periodic random flicker DEFLECT_IDLE, // Deflect mode (sound/motion reactive) idle appearance DEFLECT_FLICKER, // Deflect mode, short flicker upon deflecting a bullet DEFLECT_SOLID, // Deflect mode, short solid-color appearance } mode = DEFLECT_IDLE; // Start out in DEFLECT_IDLE mode // Color for solid() mode #define HUE 24 // Orangey fire-ish color #define SATURATION 255 #define BRIGHTNESS 255 CRGB cp[CP_LEN], // Separate arrays for Circuit Playground pixels, strip[STRIP_LEN], // strip and singles, so brightness can be singles[SINGLES_LEN]; // controlled separately if needed uint32_t lastFrameTime = 0L, // Used for frame-to-frame interval timing lastTriggerTime = 0L; // Used to 'debounce' sound & motion inputs uint16_t frameCounter; // Counter for animation timing void setup() { CircuitPlayground.begin(); FastLED.addLeds<WS2812B, CP_PIN , COLOR_ORDER>(cp , CP_LEN ).setCorrection(TypicalLEDStrip); FastLED.addLeds<WS2812B, STRIP_PIN , COLOR_ORDER>(strip , STRIP_LEN ).setCorrection(TypicalLEDStrip); FastLED.addLeds<WS2812B, SINGLES_PIN, COLOR_ORDER>(cp, SINGLES_LEN).setCorrection(TypicalLEDStrip); //singles are set up with the cp array so they act like the Circuit Playground onboard LEDs set_max_power_in_volts_and_milliamps(5, 500); // FastLED 2.1 Power management set at 5V, 500mA fill_solid(cp , CP_LEN , CRGB::Black); fill_solid(strip , STRIP_LEN , CRGB::Black); } void loop() { uint32_t currentTime; // Frame-to-frame timing is kept semi-consistent-ish by checking the current // time against the prior-frame time. Rather than burning off this time with // a delay() call, this is a perfect opportunity to test for any button, // sound or motion inputs...repeatedly, if need be, until the elapsed frame // interval is passed. A do/while loop is used so these tests are always // performed at least once per frame (else inputs might be ignored if there's // heavy animation going on). do { currentTime = micros(); // Check first for button presses... if(CircuitPlayground.leftButton()) { // Left button pressed? mode = DEFLECT_IDLE; // Yes, switch to motion/sound reactive mode lastTriggerTime = currentTime; // Note time of activation while(CircuitPlayground.leftButton()); // Wait for button release } else if(CircuitPlayground.rightButton()) { // Right button pressed? mode = AUTO_IDLE; // Yup, switch to 'auto' mode (not reactive) frameCounter = FPS; // AUTO_IDLE animation for 1 second lastTriggerTime = currentTime; // Note time of activation while(CircuitPlayground.rightButton()); // Wait for button release // Else no button presses. If we're in a 'deflect' mode, // and if sufficient time has passed since last trigger... } else if((mode >= DEFLECT_IDLE) && ((currentTime - lastTriggerTime) >= TRIGGER_TIME)) { // ..then check for sound and motion... int value = CircuitPlayground.soundSensor() - (1023 / 3); // Audio amplitude if(abs(value) >= SOUND_THRESHOLD) { // Loud noise? ping(); mode = DEFLECT_FLICKER; // Bullet deflected! Pew pew! frameCounter = FPS * 3 / 2; // Flicker for 1.5 sec lastTriggerTime = currentTime; // Turn off detection for a moment } else { // No sound, check accelerometer... sensors_event_t event; CircuitPlayground.lis.getEvent(&event); // Compare magnitude of accelerometer reading against G_THRESHOLD. // Costly sqrt() is avoided by ^2 the threshold value for comparison. if(((event.acceleration.x * event.acceleration.x) + (event.acceleration.y * event.acceleration.y) + (event.acceleration.z * event.acceleration.z)) >= ((9.8 * G_THRESHOLD) * (9.8 * G_THRESHOLD))) { ping(); mode = DEFLECT_FLICKER; // Bullet deflected! Pew pew! frameCounter = FPS * 3 / 2; // Flicker for 1.5 sec lastTriggerTime = currentTime; // Turn off detection for a moment } } } // Repeat until frame interval has elapsed: } while((currentTime - lastFrameTime) < (1000000L / FPS)); lastFrameTime = currentTime; // Save time for next frame // Done with button/sound/motion sensing. LEDs are updated immediately after // interval test, for more uniform timing. So this actually displays the colors // calculated on the *prior* loop() pass... FastLED.show(); frameCounter--; // Count down to zero (cycles modes) // Then we render one frame of animation for the *next* pass... switch(mode) { // The first two modes -- AUTO_IDLE and AUTO_FLICKER -- are used when // sound/motion reactivity has been turned off. The code will alternate // between these two states until reactivity is switched on (left button). case AUTO_IDLE: solid(); // Show solid color if(!frameCounter) { // for desired number of frames, then... mode = AUTO_FLICKER; // Switch to AUTO_FLICKER mode and frameCounter = FPS * 2; // set it to flicker for 2 seconds } break; case AUTO_FLICKER: flicker(); // Show occasional random flicker if(!frameCounter) { // for desired number of frames, then... mode = AUTO_IDLE; // Switch back to AUTO_IDLE mode frameCounter = random(3 * FPS, 10 * FPS); // for 3 to 10 sec. } break; // The remaining modes are used when 'deflecting bullets.' case DEFLECT_IDLE: // Awaiting action fade(); // Dim LEDs slightly break; case DEFLECT_FLICKER: // Initial reaction to bullet hit flicker(); // Random-ish LED flickering if(!frameCounter) { // FLICKER time elapsed? mode = DEFLECT_SOLID; // Switch to DEFLECT_SOLID mode frameCounter = FPS / 2; // for next 1/2 sec } break; case DEFLECT_SOLID: // Short 'solid' period follows flicker solid(); // Solid color if(!frameCounter) { // SOLID time elapsed? mode = DEFLECT_IDLE; // Switch back to IDLE mode } break; } } void fade() { fadeToBlackBy(cp , CP_LEN , 85); // Fade Circuit Playground LEDs by 1/3 fadeToBlackBy(strip , STRIP_LEN , 8); // Fade other LEDs slightly } void flicker() { fadeToBlackBy(cp, CP_LEN, 85); // Fade Circuit Playground LEDs by 1/3 if(!random(8)) { // Then, if random 1/8 chance... // Set one random pixel on Circuit Playground to white cp[random(0, CP_LEN)] = CRGB::White; } if(!random(8)) { // A separate 1/8 chance... // Set all other LEDs to a random brightness CRGB c = CHSV(HUE, SATURATION, random(32, BRIGHTNESS)); fill_solid(strip , STRIP_LEN , c); } else { // Fade others slightly fadeToBlackBy(strip , STRIP_LEN , 8); } } void solid() { fadeToBlackBy(cp, CP_LEN, 85); // Fade Circuit Playground LEDs by 1/3 CRGB c = CHSV(HUE, SATURATION, BRIGHTNESS); fill_solid(strip , STRIP_LEN , c); // Set other LEDs to solid color } void ping() { if (deflectionping==1) { CircuitPlayground.playTone(random(2000,2200), 30); } }
Press the RIGHT button on the Circuit Playground for AUTO mode -- lights are on all the time, great for photo shoots and peace talks. You'll see random flashes every few seconds on the Circuit Playground's onboard LEDs, with no effort on your part.
Press the LEFT button to enter DEFLECT mode. Make some noise and/or shake your Circuit Playground around a bit. The motion and sound will trigger a bullet-blocking animation. The Circuit Playground will make a "ping" sound and the lights will flash randomly, simulating the spark of a bullet strike.
Note: If this "ping" sound drives you crazy, it's easy to turn it off in the code. Look for this line:
int deflectionping = 1; // Bullet deflection "ping" sound. Change to 0 to turn this off
Change the 1 to a 0 to turn off the sound.
Page last edited April 12, 2017
Text editor powered by tinymce.