Alan Wang
Published © CC BY-NC-SA

So I Fixed a Broken Hasbro Lightsaber

Refit a 2004 Hasbro lightsaber toy with Arduino Nano, NeoPixel, ADXL335 and a DFPlayer Mini.

IntermediateShowcase (no instructions)6,817
So I Fixed a Broken Hasbro Lightsaber

Things used in this project

Story

Read more

Code

Refitted Hasbro lightsaber

C/C++
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h" // https://github.com/DFRobot/DFRobotDFPlayerMini
#include <Adafruit_NeoPixel.h> // https://github.com/adafruit/Adafruit_NeoPixel
#include "ADXL335.h" // https://github.com/Seeed-Studio/Accelerometer_ADXL335

#define BUTTON_PIN 2
#define NEOPIXEL_PIN 3
#define MP3_BUSY_PIN 4
#define MP3_RX_PIN 5
#define MP3_TX_PIN 6

#define ACCEL_TRIGGER_RATIO 0.06

#define NEOPIXEL_NUM 9
#define BUTTON_LONGPRESS_1 750
#define BUTTON_LONGPRESS_2 1500

#define SABER_ON 1
#define SABER_HUM 2
#define SABER_MOVE 3
#define SABER_OFF 4
#define SABER_QUOTE 5
#define SABER_MUSIC 6

#define SABER_ON_START 1
#define SABER_ON_END 15
#define SABER_HUM_START 16
#define SABER_HUM_END 25
#define SABER_MOVE_START 26
#define SABER_MOVE_END 50
#define SABER_OFF_START 51
#define SABER_OFF_END 58
#define SABER_QUOTE_START 59
#define SABER_QUOTE_END 72
#define SABER_MUSIC_START 73
#define SABER_MUSIC_END 81

#define SABER_ON_VOLUME 25
#define SABER_HUM_VOLUME 20
#define SABER_MOVE_VOLUME 22
#define SABER_OFF_VOLUME 25
#define SABER_QUOTE_VOLUME 20
#define SABER_MUSIC_VOLUME 22

SoftwareSerial softSerial(MP3_RX_PIN, MP3_TX_PIN);
DFRobotDFPlayerMini mp3;

ADXL335 accel;
int x, y, z, button_start, button_end, hum_index;
float last_accel_data, current_accel_data, accel_diff;
bool r, g, b, musicMode;

Adafruit_NeoPixel leds(NEOPIXEL_NUM, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

void setup() {

  Serial.begin(9600);
  softSerial.begin(9600);

  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(MP3_BUSY_PIN, INPUT_PULLUP);

  leds.begin();
  accel.begin();

  mp3.begin(softSerial);
  delay(50);
  mp3.EQ(DFPLAYER_EQ_ROCK);
  musicMode = false;
  delay(200);

  clearLEDs();

}

void loop() {

  randomSeed(analogRead(A5) + analogRead(A6) + analogRead(A7));

  while (!buttonPressed());
  clearLEDs();
  chooseRGB();
  playMp3(SABER_ON);
  delay(50);
  for (int i = 0; i < 255; i++) {
    setLEDs(r * i, g * i, b * i);
    delay(1);
  }
  while (mp3IsBusy());
  while (buttonPressed());
  delay(200);
  chooseHum();
  getAccel();

  while (true) {

    last_accel_data = current_accel_data;
    getAccel();
    accel_diff = (current_accel_data - last_accel_data) / last_accel_data;

    if (!mp3IsBusy()) {
      musicMode = false;
      loopHum();
    }

    if (!musicMode && accel_diff >= ACCEL_TRIGGER_RATIO) {
      playMp3(SABER_MOVE);
      while (!mp3IsBusy());
      while (mp3IsBusy());
      delay(200);
    }

    if (buttonPressed()) {
      button_start = millis();
      while (buttonPressed());
      button_end = millis();
      if (button_end - button_start >= BUTTON_LONGPRESS_2) {
        musicMode = true;
        playMp3(SABER_MUSIC);
      } else if (button_end - button_start >= BUTTON_LONGPRESS_1) {
        musicMode = true;
        playMp3(SABER_QUOTE);
      } else {
        if (musicMode) {
          musicMode = false;
          mp3.pause();
          delay(200);
        } else {
          break;
        }
      }
    }
    delay(50);
  }

  delay(50);
  playMp3(SABER_OFF);
  delay(150);
  for (int i = 255; i >= 0; i--) {
    setLEDs(r * i, g * i, b * i);
    delay(2);
  }
  while (mp3IsBusy());
  while (!buttonPressed());
  delay(200);

}

bool buttonPressed() {
  return !digitalRead(BUTTON_PIN);
}

bool mp3IsBusy() {
  return !digitalRead(MP3_BUSY_PIN);
}

void playMp3(int soundType) {
  int startIndex, endIndex, selectedVolume;
  switch (soundType) {
    case SABER_ON:
      startIndex = SABER_ON_START;
      endIndex = SABER_ON_END;
      selectedVolume = SABER_ON_VOLUME;
      break;
    case SABER_HUM:
      startIndex = SABER_HUM_START;
      endIndex = SABER_HUM_END;
      selectedVolume = SABER_HUM_VOLUME;
      break;
    case SABER_MOVE:
      startIndex = SABER_MOVE_START;
      endIndex = SABER_MOVE_END;
      selectedVolume = SABER_MOVE_VOLUME;
      break;
    case SABER_OFF:
      startIndex = SABER_OFF_START;
      endIndex = SABER_OFF_END;
      selectedVolume = SABER_OFF_VOLUME;
      break;
    case SABER_QUOTE:
      startIndex = SABER_QUOTE_START;
      endIndex = SABER_QUOTE_END;
      selectedVolume = SABER_QUOTE_VOLUME;
      break;
    case SABER_MUSIC:
      startIndex = SABER_MUSIC_START;
      endIndex = SABER_MUSIC_END;
      selectedVolume = SABER_MUSIC_VOLUME;
      break;
    default:
      startIndex = 0;
      endIndex = 0;
      selectedVolume = SABER_HUM_VOLUME;
  }
  mp3.volume(selectedVolume);
  delay(50);
  mp3.play(random(startIndex, endIndex + 1));
  delay(200);
}

void chooseHum() {
  hum_index = random(SABER_HUM_START, SABER_HUM_END + 1);
}

void loopHum() {
  mp3.volume(SABER_HUM_VOLUME);
  delay(50);
  mp3.play(hum_index);
  delay(200);
}

void chooseRGB() {
  r = random(0, 2);
  g = random(0, 2);
  b = (r || g) ? random(0, 2) : true;
}

void clearLEDs() {
  leds.clear();
  leds.show();
}

void setLEDs(int rc, int gc, int bc) {
  for (int i = 0; i < NEOPIXEL_NUM; i++) {
    leds.setPixelColor(i, leds.Color(rc, gc, bc));
  }
  leds.show();
}

void getAccel() {
  accel.getXYZ(&x, &y, &z);
  current_accel_data = x + y + z;
}

Credits

Alan Wang

Alan Wang

32 projects • 102 followers
Please do not ask me for free help for school or company projects. My time is not open sourced and you cannot buy it with free compliments.

Comments