Last active
August 29, 2015 14:12
-
-
Save gwygonik/dee80233dffe22bc5227 to your computer and use it in GitHub Desktop.
A demo of using the accelerometer in the L3D Cube to keep a "ground plane" level while rotating side to side. Two color modes - ground and water. You'll need to add the Adafruit Neopixel library to your code in Spark.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This #include statement was automatically added by the Spark IDE. | |
#include "neopixel/neopixel.h" | |
#include <math.h> | |
//set up the pin that controls the LEDs, the type of LEDs (WS2812B) and the number of LEDs in the cube (8*8*8=512) | |
#define PIXEL_PIN D0 | |
#define PIXEL_COUNT 512 | |
#define PIXEL_TYPE WS2812B | |
#define SIDE 8 | |
//accelerometer pinout | |
#define X 13 | |
#define Y 14 | |
#define Z 15 | |
SYSTEM_MODE(SEMI_AUTOMATIC); //don't connect to the internet on boot | |
#define BUTTON D2 //press this button to connect to the internet | |
#define MODE D3 | |
bool onlinePressed=false; | |
bool lastOnline=true; | |
int accelerometer[3]; | |
int MIDVAL_X = 0; // to store the initial resting accelerometer value to compare against | |
Adafruit_NeoPixel strip=Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); | |
bool colorAsGround = true; // set to false to use "water tank" colors | |
// standard non-blocking millisecond update vars | |
long prevM = 0; | |
int interval = 25; // fast update, but allowing time for LED refresh | |
void setup() { | |
pinMode(7,OUTPUT); | |
digitalWrite(7, HIGH); | |
initCloudButton(); | |
strip.setBrightness(64); // dim all the LEDs. Set to 255, or comment out, for normal brightness | |
clearStrip(); | |
strip.show(); | |
// we're going to let the accelerometer settle | |
delay(500); | |
// grab 10 readings from the accelerometer | |
for (int i=0;i<10;i++) { | |
updateAccelerometer(); | |
MIDVAL_X += accelerometer[1]; | |
delay(50); // delay slightly | |
} | |
// get the average to use as a base for rotation later | |
MIDVAL_X /= 10; | |
// pause for effect | |
delay(500); | |
} | |
void loop() { | |
checkCloudButton(); | |
updateAccelerometer(); | |
// check if we're needing to do an update | |
unsigned long curM = millis(); | |
if (curM - prevM > interval) { | |
prevM = curM; | |
clearStrip(); // clear all colors from cube | |
// subtract base rotation value from current value to get a negative to positive rotation value | |
// then divide by 100 to get a small number (the accelerometer values are in the thousands range) | |
int val = floor((accelerometer[1] - MIDVAL_X) / 100); | |
// clamp the rotation to -3 to +3. Change to -4 to +4 for more extreme rotation | |
if (val < -3) val = -3; | |
if (val > 3) val = 3; | |
// update all the LEDs in the cube | |
for (int x=0;x<8;x++) { | |
for (int z=0;z<8;z++) { | |
int lval = intlerp(-val,val,x/8.0f); // lerp between negative of value to positive of value to keep level across | |
for (int y=0;y<4+lval;y++) { | |
if (colorAsGround) { | |
// brownish base, green grass | |
strip.setPixelColor(y + (x * 8) + (z*64),y < 3+lval ? strip.Color(24, 7, 0) : strip.Color(0, 70, 0)); | |
} else { | |
// dark blue base, light blue top level | |
strip.setPixelColor(y + (x * 8) + (z*64),y < 3+lval ? strip.Color(0, 0, (y+1)*3) : strip.Color(0, (y+1)*5, (y+1)*10)); | |
} | |
} | |
// draw the background plane | |
if (z == 0) { | |
for (int y=4+lval;y<8;y++) { | |
if (colorAsGround) { | |
// light blue sky background | |
strip.setPixelColor(y + (x * 8) + (z*64), strip.Color(0,100,105)); | |
} | |
// water tank doesn't have a background | |
} | |
} | |
} | |
} | |
strip.show(); | |
} | |
} | |
// function to return an integer between start and end values | |
int intlerp(int start, int end, float perc) { | |
return floor(start + perc*(end - start)); | |
} | |
// set all LEDs to black | |
void clearStrip() { | |
for (int p=0;p<PIXEL_COUNT;p++) { | |
strip.setPixelColor(p,0); | |
} | |
} | |
void updateAccelerometer() | |
{ | |
for(int i=0;i<3;i++) | |
accelerometer[i]=analogRead(X+i); | |
} | |
//sets up the online/offline switch | |
void initCloudButton() | |
{ | |
//set the input mode for the 'connect to cloud' button | |
pinMode(BUTTON, INPUT_PULLUP); | |
pinMode(MODE, INPUT_PULLUP); | |
if(!digitalRead(MODE)) | |
WiFi.listen(); | |
//a.k.a. onlinePressed is HIGH when the switch is set to 'online' and LOW when the switch is set to 'offline' | |
onlinePressed=digitalRead(BUTTON); | |
if(onlinePressed) | |
Spark.connect(); | |
} | |
//checks to see if the 'online/offline' switch is switched | |
void checkCloudButton() | |
{ | |
//if the 'connect to cloud' button is pressed, try to connect to wifi. | |
//otherwise, run the program | |
//note -- how does this behave when there are no wifi credentials loaded on the spark? | |
//onlinePressed is HIGH when the switch is _not_ connected and LOW when the switch is connected | |
//a.k.a. onlinePressed is HIGH when the switch is set to 'online' and LOW when the switch is set to 'offline' | |
onlinePressed=digitalRead(BUTTON); | |
if((!onlinePressed)&&(lastOnline)) //marked as 'online' | |
{ | |
lastOnline=onlinePressed; | |
Spark.connect(); | |
} | |
else if((onlinePressed)&&(!lastOnline)) //marked as 'offline' | |
{ | |
lastOnline=onlinePressed; | |
Spark.disconnect(); | |
} | |
lastOnline=onlinePressed; | |
if(!digitalRead(MODE)) | |
WiFi.listen(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment