Eamon Magd
Published

Creating a Arduino Powered Wizard Staff!

A motion-activated prop that combines LED visuals, sound effects, and an LCD to deliver random fortunes when moved.

IntermediateShowcase (no instructions)74

Things used in this project

Story

Read more

Code

Code for staff on C

C/C++
// Include the library code
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <FastLED.h>

// Initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27, 16, 2);  // Set the LCD address to 0x27 for a 16x2 LCD display

#define NUM_LEDS 60
#define DATA_PIN 6
#define BUTTON_PIN 5  // Button pin
#define BUZZER_PIN 4  // Passive buzzer pin

CRGB leds[NUM_LEDS];
uint8_t maxBrightness = 50;  // Reduced brightness (0-255)

void setup() {
  // Initialize the LCD
  lcd.init();  // Initialize the LCD
  lcd.backlight();  // Turn on the backlight 

  // Initialize the LED strip
  FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);

  // Set up the button pin
  pinMode(BUTTON_PIN, INPUT_PULLUP);  // Use internal pull-up resistor

  // Set up the buzzer pin
  pinMode(BUZZER_PIN, OUTPUT);

  // Reset the lights at the start
  resetLights();
}

void loop() {
  // Check if the button is pressed
  if (digitalRead(BUTTON_PIN) == LOW) {
    // Reset the lights at the start of the sequence
    resetLights();
  lcd.init();  // Initialize the LCD
  lcd.backlight(); 
    // Display "Thinking..." on the LCD
    lcd.clear();
    lcd.print("Thinking...");
 

    // Run the sine wave effect for 3 seconds
    runSineWaveEffect();

    // Define the magical messages
    const char* positiveMessages[] = {
      "The path is clear.     ",
      "Fortune favors the brave.   ",
      "Winds whisper of change.     ",
      "The stars align in your favor.   ",
      "Magic flows through you.   ",
      "Your staff glows with power.   ",
      "Wizards recognize your strength.   ",
      "Ancient spells protect you.   ",
      "You wield the magic of the ancients.   ",
      "The light of magic guides you.   "
    };

    const char* negativeMessages[] = {
      "Shadows cannot hide the truth.   ",
      "Darkness holds no power here.   ",
      "Mystery lingers in the air.     ",
      "A great journey awaits.     ",
      "Beware the lure of false magic.   ",
      "Illusions may cloud your path.   ",
      "Power can corrupt even the wisest.   ",
      "The staff may lead you astray.   ",
      "Magic can twist intentions.   ",
      "Dark forces lurk nearby.   "
    };

    const char* neutralMessages[] = {
      "Courage lights the way forward.   ",
      "Seek the unknown with wisdom.   ",
      "Ask again later.   ",
      "Uncertain times ahead.     ",
      "The winds carry whispers of change.   ",
      "The magic is not yet revealed.   ",
      "Your staff holds untapped potential.   ",
      "A new journey begins soon.   ",
      "Mysteries await your discovery.   ",
      "Balance the magic within.   "
    };

    int randomCategory = random(0, 3);  // Choose a random category (0 for Positive, 1 for Negative, 2 for Neutral)
    const char* randomMessage;

    // Choose a random phrase from the selected category
    if (randomCategory == 0) {
      randomMessage = positiveMessages[random(0, 10)];  // Pick one of the positive options
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CRGB::Green;  // Set all LEDs to green for "Positive"
      }
      playPositiveSound();  // Play a positive sound for positive messages
    } else if (randomCategory == 1) {
      randomMessage = negativeMessages[random(0, 10)];   // Pick one of the negative options
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CRGB::DarkRed;    // Set all LEDs to dark red for "Negative"
      }
      playWrongSound();  // Play a wrong sound for negative messages
    } else {
      randomMessage = neutralMessages[random(0, 10)]; // Pick one of the neutral options
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CRGB::Blue;   // Set all LEDs to blue for "Neutral"
      }
      playRandomSound();  // Play a random sound for neutral messages
    }

    FastLED.show();  // Update the LED strip to show the final color

    // Wait a moment for the sound and lights before displaying the message
    delay(1000); // Delay to allow sound to play and LED color to set

    // Scroll the message on the LCD twice
    for (int i = 0; i < 2; i++) { // Display the message twice
      scrollMessage(randomMessage);
    }

    // Wait for 8 seconds before starting the passive light show
    for (int i = 0; i < 8; i++) {
      delay(1000); // Delay for 1 second
    }

    // Reset lights and LCD after 8 seconds
    resetLights();
    lcd.clear();
    lcd.noBacklight();

    // Start the passive light show
    while (true) {
      smoothColorAnimation(); // Start the smooth color animation
      if (digitalRead(BUTTON_PIN) == LOW) {
        resetLights(); // Reset lights if the button is pressed again
        break; // Break the loop to allow the button to work again
      }
    }
  } else {
    // If no input, run a smooth color animation in passive mode
    smoothColorAnimation();
  }
}

// Function to reset the lights (turn them off)
void resetLights() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black;  // Turn off all LEDs
  }
  FastLED.show();  // Update the LED strip
}

// Function to run the sine wave effect for 3 seconds
void runSineWaveEffect() {
  unsigned long startTime = millis(); // Get the current time
  while (millis() - startTime < 3000) {  // Run the loop for 3 seconds (3000 ms)
    for (int i = 0; i < NUM_LEDS; i++) {
      // Calculate the sine value based on the position of the LED and time
      float sineValue = sin((i + millis() / 100.0) * 0.2);  // Adjust 0.2 to control the wave frequency

      // Map the sine value to brightness (0 to 255)
      uint8_t colorBrightness = (sineValue + 1) * (maxBrightness / 2);  // Scales sine value (-1 to 1) to brightness

      // Set the LED color to white with the calculated brightness
      leds[i] = CRGB(colorBrightness, colorBrightness, colorBrightness);  // White based on sine wave
    }

    FastLED.show();  // Update the LED strip
    delay(20);       // Small delay for smoother animation
  }
}

// Function to run a smooth color animation in passive mode
void smoothColorAnimation() {
  static uint8_t hue = 0;  // Initialize hue for color cycling
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CHSV(hue + (i * 255 / NUM_LEDS), 255, maxBrightness);  // Cycle through colors
  }
  FastLED.show();  // Update the LED strip
  hue++;  // Increment hue for the next frame
  delay(30);  // Adjust delay for the speed of the color cycling
}

// Function to scroll a message on the LCD
void scrollMessage(const char* message) {
  int messageLength = strlen(message);  // Get the length of the message
  int displayLength = 16;  // Length of the display (number of characters)

  // Loop through the message
  for (int position = 0; position < messageLength - displayLength + 1; position++) {
    lcd.setCursor(0, 0);  // Reset cursor to the start
    lcd.print(message + position);  // Print a substring starting from current position
    delay(300);  // Delay to control scrolling speed
  }

  // If the message is longer than the display length, scroll it back to the beginning
  for (int position = messageLength - displayLength; position >= 0; position--) {
    lcd.setCursor(0, 0);  // Reset cursor to the start
    lcd.print(message + position);  // Print a substring starting from current position
    delay(300);  // Delay to control scrolling speed
  }
}

// Function to play a wrong sound for "Negative"
void playWrongSound() {
  tone(BUZZER_PIN, 500, 300);  // Play tone at 500 Hz for 300 ms
  delay(300);
  tone(BUZZER_PIN, 400, 300);  // Play tone at 400 Hz for 300 ms
  delay(300);
  noTone(BUZZER_PIN);
}

// Function to play a positive sound for "Positive"
void playPositiveSound() {
  tone(BUZZER_PIN, 1000, 300);  // Play tone at 1000 Hz for 300 ms
  delay(300);
  tone(BUZZER_PIN, 1200, 300);  // Play tone at 1200 Hz for 300 ms
  delay(300);
}

// Function to play a random sound
void playRandomSound() {
  tone(BUZZER_PIN, random(500, 1500), 300);  // Play random tone for 300 ms
  delay(300);
}

Credits

Eamon Magd
4 projects • 2 followers
Hi, I’m Eamon! An inventor, Computer Scientist and gamer, with an endless list of ideas. I have a yellow cockatiel.
Contact

Comments

Please log in or sign up to comment.