Evelyn Roque Final Project: Stage with Servos and LEDS

This project is inspired by the game Bang Dream Girls Band Party, where a band is on stage moving along with the music. I created a stage that features original characters. The stage has Bluetooth LD lights that sync with any device. It allows the lights to flash whenever music plays or flashes when people are talking. You are able to play with the settings in the app that is included with the connector of the LEDS. You can change the color of the LEDS without using the music feature of the app. I also included a separate LED strip to show case the characters colors that fade in and out with each other. The motors move every 3 seconds to the song. It creates an immersive atmosphere as if you were to witness a concert in real life.

Audience:

The target audience is someone who would have a box in between their bookcase that is next to a speaker or record player. It is also for those who enjoy music and the game that it is inspired by. It is also for those who wants to get to know characters they are unfamiliar with.

Materials:

*LED Strip

Adafruit_ Circuit Playground

Arduino

*Cardboard

BT SPI LED CONTROLLER

Power Adapter

Construction Paper

Phone/Tablet

Motor servos

Wires

Felt

Battery

Scissors

Soldering

Double sided tape (Optional: This isn’t needed since I borrowed the LEDS and BT SPI LED CONTROLLER from the professor, so I used the tape to not use the original sticky part of the led.

Features:

App: ZENGGE

Microphone

Step One:

Find a cardboard box and cut a hole on the left side of the box.

With the left-over cardboard create two smaller platforms to put at the back of the box.

Add tape along the back of the box and above the ceiling for LED strip.

Step Two:

Using the Adafruit Circuit Playground and implement this code:

#include <Servo.h>

#include <Adafruit_CircuitPlayground.h>

#include <FastLED.h>

//define CPX color strip

#define NUM_LEDS 30

#define LED_PIN A6

#define COLOR_ORDER GRB

#define brightness 80

#define LED_TYPE WS2812B

#define UPDATES_PER_SECOND 100

#define SECONDS_PER_PALETTE 3

//pattern

CRGBPalette16 gCurrentPalette;

//CRGBPalette16 gCurrentPalette;// sets the start palette to black (= lights off)

CRGBPalette16 gTargetPalette;

//void pattern_twinkles();

// Palette forwarding stuff

uint8_t paletteIndex = 5;  // which palette is active: 0–5

uint8_t colorIndex = 0;    // scrolling position inside the palette

CRGB leds[NUM_LEDS];  // declaring the current LED’s are color RGB

// —————- Servo pins —————-

// LED_PIN is already using A2, so this servo pin cannot also be A2

int LEFT_SERVO_PIN = A2;   // servo connected to CPX on one pin

int RIGHT_SERVO_PIN = A5;

int MIDDLE_SERVO_PIN = A3;  // servo connected to CPX on another pin

Servo left_Servo;

Servo right_Servo;

Servo middle_Servo;

// —————- Servo movement settings —————-

int centerAngle = 90;       // starts with the servos in this position (centered)

float amplitudeDeg = 80.0;  // how many degrees each servo can rotate away from center maximum

// 90 plus 10-30 degrees = smaller movement // 90 plus 40-80 degrees = larger movement

int leftMax = centerAngle + amplitudeDeg;   // = 150 max rotation (instead of 180) now

int rightMin = centerAngle – amplitudeDeg;  // = 30 max rotation (instead of 0) now

// How often the servos update (in milliseconds).

unsigned long updateEveryMs = 6;  // 5 – 10 = smooth, 15 – 25 = less smooth

unsigned long Servo_Timer;         // stores the last time the servos were updated

// Servo position

int leftAngle;   // the angle the left servo is turned to

int rightAngle;  // the angle the right servo is turned to

int middleAngle;

int stepSize = 1;            // how many degrees to move each update

int servoDirection = 1;      // 1 = moving outward, -1 = moving back to center

int middleServoDirection = 1;

bool sweepDone = false;      // tracks whether the full back-and-forth sweep is finished

bool servosAttached = false; // tracks whether the servos are currently attached

bool sweepActive = false;    // tracks whether the sweep is currently running

bool leftRightSweepDone = false;

bool middleSweepStarted = false;

bool middleSweepDone = false;

unsigned long servoSweepStartTime = 0;

const unsigned long middleServoStartDelay = 750;  // 750 milliseconds

CRGBPalette16 purplePalette = CRGBPalette16(

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::Magenta,

  CRGB::Magenta,

  CRGB::Linen,

  CRGB::Linen,

  CRGB::Magenta,

  CRGB::Magenta,

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::DarkViolet,

  CRGB::Linen,

  CRGB::Linen);

//drummer palette

DEFINE_GRADIENT_PALETTE(bhw2_31_gp) {

  0,   64,  64,  64,

  71,  255, 192, 192,

  128, 255, 255, 192,

  173, 255, 192, 192,

  255, 64,  64,  64

};

//keyboard palette add comma

DEFINE_GRADIENT_PALETTE(bhw2_36_gp) {

  0,   180, 130, 69,

  130, 255, 255, 192,

  255, 180, 130, 69

};

//bass gutiar add comma

DEFINE_GRADIENT_PALETTE(bhw1_02_gp) {

  0,   152, 10,  114,

  8,   152, 10,  114,

  128, 253, 215, 243,

  252, 84,  10,  64,

  255, 84,  10,  64

};

// lead gutiar

DEFINE_GRADIENT_PALETTE(bhw1_03_gp) {

  0,   0,   0,   0,

  138, 78,  176, 208,

  191, 126, 238, 179,

  255, 255, 255, 255

};

// vocalist palette

DEFINE_GRADIENT_PALETTE(bhw2_16_gp) {

  0,   153, 217, 179,

  92,  138, 64,  238,

  176, 187, 131, 181,

  255, 255, 192, 255

};

void setup() {

  Serial.begin(9600);

  CircuitPlayground.begin();

  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

  FastLED.setBrightness(80); // can go up to 255 in brightness

  gCurrentPalette = bhw2_16_gp;  // starting palette, matches paletteIndex = 5

  leftAngle = centerAngle;   // equals 90 degrees

  rightAngle = centerAngle;  // equals 90 degrees

  middleAngle = centerAngle;

  Servo_Timer = millis();  // establishes the starting time for the servo timer

  // delay(1000);

}

void loop() {

  fill_palette(leds, NUM_LEDS, colorIndex, 255 / NUM_LEDS, gCurrentPalette, 255, LINEARBLEND);

  EVERY_N_SECONDS(3) {

    nextPalette();  //advanceToNextPalette();

    startServoSweep();

  }

  EVERY_N_MILLISECONDS(10) {

    colorIndex++;

  }

  updateServoSweep();

  //EVERY_N_MILLISECONDS(50){

  //nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 15);

  //}

  FastLED.show();

}

void nextPalette() {

  paletteIndex++;

  if (paletteIndex > 5) {

    paletteIndex = 0;

  }

  switch (paletteIndex) {

    case 0: gCurrentPalette = purplePalette; break;

    case 1: gCurrentPalette = bhw2_31_gp; break;

    case 2: gCurrentPalette = bhw2_36_gp; break;

    case 3: gCurrentPalette = bhw1_02_gp; break;

    case 4: gCurrentPalette = bhw1_03_gp; break;

    case 5: gCurrentPalette = bhw2_16_gp; break;

  }

}

// ———————————————————

void startServoSweep() {

  // if the servos are not already moving then…

  if (sweepActive == false) {

    leftAngle = centerAngle;

    rightAngle = centerAngle;

    middleAngle = centerAngle;

    servoDirection = 1;

    middleServoDirection = 1;

    sweepDone = false;

    sweepActive = true;

    leftRightSweepDone = false;

    middleSweepStarted = false;

    middleSweepDone = false;

    servoSweepStartTime = millis();

    left_Servo.attach(LEFT_SERVO_PIN);

    right_Servo.attach(RIGHT_SERVO_PIN);

    middle_Servo.attach(MIDDLE_SERVO_PIN);

    left_Servo.write(leftAngle);

    right_Servo.write(rightAngle);

    middle_Servo.write(middleAngle);

    servosAttached = true;

  }

}

// ———————————————————

void updateServoSweep() {

  if (millis() – Servo_Timer >= updateEveryMs) {  // if enough time has passed since the last servo update

    Servo_Timer = millis();                       // update the saved timestamp

    if (sweepActive == true && sweepDone == false) {  // if the sweep movement is not finished yet then…

      if (leftRightSweepDone == false) {

        // Move the servos in opposite directions

        leftAngle = leftAngle + stepSize * servoDirection;

        rightAngle = rightAngle – stepSize * servoDirection;

        leftAngle = constrain(leftAngle, centerAngle, leftMax);     // set movement limits – caps at 150 rather than 180

        rightAngle = constrain(rightAngle, rightMin, centerAngle);  // set movement limits – starts at 30 rather than 0

        left_Servo.write(leftAngle);

        right_Servo.write(rightAngle);

        if (leftAngle >= leftMax && rightAngle <= rightMin) {  // if you’ve rotated all the way in one direction, then rotate all the way to the other

          servoDirection = -1;                                 // reverse direction and head back to center

        }

        if (leftAngle <= centerAngle && rightAngle >= centerAngle && servoDirection == -1) {  // if you’ve finished the full sweep then

          // return the servo to the center

          leftAngle = centerAngle;

          rightAngle = centerAngle;

          left_Servo.write(leftAngle);

          right_Servo.write(rightAngle);

          leftRightSweepDone = true;

        }

      }

      if (middleSweepStarted == false && millis() – servoSweepStartTime >= middleServoStartDelay) {

        middleSweepStarted = true;

      }

      if (middleSweepStarted == true && middleSweepDone == false) {

        middleAngle = middleAngle + stepSize * middleServoDirection;

        middleAngle = constrain(middleAngle, centerAngle, leftMax);

        middle_Servo.write(middleAngle);

        if (middleAngle >= leftMax) {

          middleServoDirection = -1;

        }

        if (middleAngle <= centerAngle && middleServoDirection == -1) {

          middleAngle = centerAngle;

          middle_Servo.write(middleAngle);

          middleSweepDone = true;

        }

      }

      if (leftRightSweepDone == true && middleSweepDone == true) {

        sweepDone = true;

        sweepActive = false;

        if (servosAttached == true) {  // detach the servos

          left_Servo.detach();

          right_Servo.detach();

          middle_Servo.detach();

          servosAttached = false;

        }

      }

    }

  }

}

Step Three:

Gather wires and solder them together. Since we have 3 servos, in total we should have 10 wires. It should look something like this

Image

Step Four:

Then you connect all the pins to the servos. Brown is ground, red is voltage, and yellow is where the pins will go in the Adafruit circuit playground. In this case, the left servo will go to A2, right servo to A5, and middle servo to A3. Finally, add the battery to the Adafruit so you don’t have to use the laptop.

Final Step:

Using the construction paper make an outline along the box. Afterward, use the felt to create curtains and put it inside the box.

Video:

Images:

Sketches of Project: