#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