Project tutorial

Magic Staff Stick © GPL3+

A gesture-controlled Magic Staff Stick that lights up with different styles when you make certain gestures.

  • 168 views
  • 0 comments
  • 0 respects

Components and supplies

Anduino 5v addressable LED strip
make sure it is a 5v addressable led strip
×1
Ardgen 101
Arduino 101 & Genuino 101
×1
11026 02
Jumper wires (generic)
get a set of all the types
×1
battery case holder
I'm using a 3 slot AA battery case holder
×1
male barrel jack adapter
×1
female barrel jack adapter
×1
AA batteries
you need 3 AA batteries
×1

About this project

Part 1

This project is about the fun of creating your own gesture to light up an LED. I made this because I think it is a unique project, and it's also a fun project. This is a gesture-controlled LED stick that lights up in different styles when you make certain gestures.

Part 2

This is how mine looks:

This is a GIF of how it works. So basically you get your Arduino 101 board, plug it into your computer to install the code. You need to have Arduino IDE software installed. Copy and paste the code into Arduino IDE. Find your board under "Tools" and click "Board:" to select your board.

Part 3

Once you have selected your board, now select your port under option "Board:". Make sure you select the correct board and port. Now click the "Upload" logo on the top left to upload the code to your Arduino board.

Alright, now from the LED strip you'll see 3 wires: a +5V, Din and GND. Now connect the +5V to the 3.3V pin on your Arduino board with a jumper cable and connect GND to the GND pin on the Arduino board next to the 5V pin. And the Din goes to pin ~6 on your Arduino board.

Now power up your Arduino board using the batteries. Connect the male barrel jack adapter to your battery case and make sure positive goes to the positive and negative goes to the negative. For the female barrel jack adapter, connect the positive to the 5V pin on your Arduino board and the negative to any GND pin on your board, next to pin VIN or next to pin 13, which ever.

Now put in your AA batteries into the battery case holder and plug in your male barrel jack adapter to your female barrel jack adapter. Now you're done, have fun and don't forget to study for your exam!

Code

my codeArduino
#include "CurieIMU.h"
#include <Adafruit_NeoPixel.h>
#define PIN 6  // what pin are the NeoPixels connected to?
Adafruit_NeoPixel strip = Adafruit_NeoPixel(15 , PIN, NEO_GRB + NEO_KHZ800);  //  the strip is 60 pixels long.

int tr = 0;  //Some variables to hold color target and color current for smoothing...
int tg = 0;
int tb = 0;
int r = 0;
int g = 0;
int b = 0;

long int globaltimer = 0;  // timers to keep track of gestures vs time...for things like "if timer hasn't passed 0.5sec, AND there's two taps, then..."
long int gesturetimer = 0;
long int ledtimer = 0;

int fade = 10;  // how quickly lights fade.  Used for smoothing

int tap = 0;  //couter for vertical impulses

int lr = 0;   //couter for left/right impulses

int fb = 0;   //couter for forward/back impulses

int gesture = 0;  // 
int state = 0;  // for our switch case...  this will keep track of each movement in a series.





void setup() {
  // put your setup code here, to run once:
  //Serial.begin(9600);

  globaltimer = millis();  // start timekeepers at current time
  gesturetimer = millis();
  ledtimer = millis();

  /* Initialise the IMU */
  CurieIMU.begin();
  CurieIMU.attachInterrupt(eventCallback);

  /* Enable Shock Detection */
  CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, 1500); // 1.5g = 1500 mg
  CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 50);   // milliseconds of spike required to call interupt
  CurieIMU.interrupts(CURIE_IMU_SHOCK);

  strip.begin();  //  intialize neopixel strip
  strip.show();   // Initialize all pixels to 'off'
}

void loop() {
  // put your main code here, to run repeatedly:


  //basic filter- the IMU registers multiple shocks from rebound and counteraction.  This tries to capture the dominant shock in each gesture.

  if (millis() - globaltimer > 170) {  //  this tries to find the dominant axis of movement for each shock..  Compares the sum of tap, left-right, and front-back movements, and picks the largest.
    if ((tap > lr) && (tap > fb)) {
      Serial.println("tap");
      gesture = 1;
      tap = 0; lr = 0; fb = 0; //  reset values after a movement is classified.
    }
    else if ((lr > fb) && (lr > tap)) {
      Serial.println("lr");
      gesture = 2;
      tap = 0; lr = 0; fb = 0;
    }
    else if ((fb > lr) || (fb > tap)) {
      Serial.println("fb");
      gesture = 3;
      tap = 0;  lr = 0; fb = 0;
    }
  }


  if (millis() - globaltimer > 1000) {  //timeoutreset
    globaltimer = millis() - 170;
tr = 0; tg=0; tb = 0;
    state = 0;
    //gesture=0;
  }
  if (millis() - gesturetimer > 1000) {
    gesturetimer = millis() - 350;
tr = 0; tg = 0; tb = 0;
    state = 0;
     //gesture=0;
  }

  switch (state) {   // This tracks gestures

    case 0: {  // no gestures recorded yet...  listen for tap.  If there's one, go to case 1.
        if (millis() - gesturetimer > 350) {  
          if (gesture == 1) {
            state = 1;
            gesture = 0;
            gesturetimer = millis();
          }
        }

        break;
      }
    case 1: {  // one tap recorded.  If a second tap happens, play a quick flash then go to step 2.
        if (millis() - gesturetimer > 350) {  
          if (gesture == 1) {
            r=10;g=10;b=10;  //feedback flash
            state = 2;
            gesture = 0;
            gesturetimer = millis();
            
          }
        }

        break;
      }
    case 2: {  // Switch point -  two taps recorded.  The three spells diverge here based on the next gesture.  If it's a tap, go to case 3.  If it's L/R, go to case 4. If it's Front/Back, go to case 5.
        
        if (millis() - gesturetimer > 350) {
          if (gesture == 1) {
            state = 3;
            gesture = 0;
            gesturetimer = millis();
          }
          if (gesture == 2) {
            state = 4;
            gesture = 0;
            gesturetimer = millis();
          }
          if (gesture == 3) {
            state = 5;
            gesture = 0;
            gesturetimer = millis();
          }
        }

        break;
      }
    case 3: {  //  three taps recorded...  we're in the tap spell, turn the staff red and listen for the final "tap" to set off the spell.
      tr = 20; tg = 0; tb = 0;
      globaltimer = millis()-250;
      if (millis() - gesturetimer > 350) {
        if (gesture == 1) {
          state = 0;
          Serial.println("tapspell!");
          tapspell();
        }
      }
        break;
      }
    case 4: {  //  two taps and a L or R recorded...  we're in the leftspell, turn the staff blue and listen for the final "tap" to set off the spell.
      tr = 0; tg = 0; tb = 20;
      globaltimer = millis()-250;
      if (millis() - gesturetimer > 350) {;
        if (gesture == 1) {
          state = 0;
          Serial.println("leftspell!");
          leftspell();
        }
      }

        break;
      }
    case 5: {  //  two taps and a forward or back recorded...  we're in the forwardspell, turn the staff green and listen for the final "tap" to set off the spell.
      tr = 0; tg = 20; tb = 0;
      globaltimer = millis()-250;
      if (millis() - gesturetimer > 350) {
        if (gesture == 1) {
          state = 0;
          Serial.println("forwardspell!");
          forwardspell();
        }
      }

        break;
      }
defaut: {
        break;
      }
  }
  //Serial.println(tr);
  
if (millis()-ledtimer > fade){   // only do this next step periodically every (fade value) milliseconds.  Unlike the "delay()" function, this allows other things to happen in the program in between updates.

   // color smoothing.  Actual color moves toward target color...  If target is more than curent, move up, if less, move down.
  if (tr > r + 1) {
    r++;
  }
  if (tg > g + 1) {
    g++;
  }
  if (tb > b + 1) {
    b++;
  }
  if (tr < r) {
    r--;
  }
  if (tg < g) {
    g--;
  }
  if (tb < b) {
    b--;
  }
  // turn all the LEDS to the current r, g, b values.
  for (int i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, r, g, b);
  }
  strip.show();
  ledtimer=millis();
}

}

// When a shock is detected, the following code interrupts the loop.

static void eventCallback(void)
{
  if (CurieIMU.getInterruptStatus(CURIE_IMU_SHOCK)) {
    if (CurieIMU.shockDetected(X_AXIS, POSITIVE)) {
      tap++;
      globaltimer = millis();
    }

    if (CurieIMU.shockDetected(X_AXIS, NEGATIVE)) {   // for now, just classifying shocks based on their axis.  positive and negative shocks both are the same.
      tap++;
      globaltimer = millis();
    }

    if (CurieIMU.shockDetected(Y_AXIS, POSITIVE)) {
      lr++;
      globaltimer = millis();
    }

    if (CurieIMU.shockDetected(Y_AXIS, NEGATIVE)) {
      lr++;
      globaltimer = millis();
    }

    if (CurieIMU.shockDetected(Z_AXIS, POSITIVE)) {
      fb++;
      globaltimer = millis();
    }

    if (CurieIMU.shockDetected(Z_AXIS, NEGATIVE)) {

      fb++;
      globaltimer = millis();
    }
  }
}


void tapspell() {
  // red theatre lights
  theaterChase(strip.Color(127, 20, 0), 20);
  theaterChase(strip.Color(127, 20, 50), 55);
  strip.show();
}

void leftspell() {
  theaterChase(strip.Color(0, 0, 100), 20);
  theaterChase(strip.Color(0, 30, 120), 75);
  strip.show();
}

void forwardspell() {
  theaterChase(strip.Color(0, 127, 0), 30);
  theaterChase(strip.Color(0, 127, 90), 55);
  strip.show();
}


// Spell functions for lights 
// From the Adafruit Neopixel Strandtest Example
// Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

 

Comments

Created by

Lucas Ainsworth

Are you Lucas Ainsworth? Claim this project and add it to your profile.

This is mine

Posted by

20031575 10207285236529184 2744539682906061237 n
Zufar Dinie
  • 0 projects
  • 0 followers

Additional contributors

  • Effort by Only me, Zufardinie

Published on

October 1, 2017
See similar projects
you might like

Similar projects you might like

Development Board for AtTiny MCU

by Vincenzo G.

  • 100 views
  • 0 comments
  • 4 respects

The Magnetic Field and RGB Tester

Project tutorial by Kutluhan Aktar

  • 164 views
  • 0 comments
  • 2 respects

Version 2.0 Advanced Attendance System (Without Ethernet)

Project tutorial by GadgetProgrammers

  • 2,840 views
  • 5 comments
  • 44 respects

How To Use DS18B20 Water Proof Temperature Sensor

Project showcase by IoTBoys

  • 145 views
  • 0 comments
  • 3 respects

Ultrasonic Security System

Project tutorial by Krepak

  • 264 views
  • 0 comments
  • 4 respects
Add projectSign up / Login