LightSaber (si fa per dire...)

Un prototipo di “spada laser”: una barra led RGB pilotata da un Arduino YUN/NUY (e corredata di un accelerometro) per giocare a fare il Jedi ;)

O anche per fare un po' di esperimenti ad esempio col wifi, si puo' mappare la qualita' del segnale wifi con i colori e il numero di led accesi sulla barra… tipo cio' che fa questa app per Android.


Versione darkside:

prototipo

video prova con accelerometro


Sketch LightSaber.ino

/*
 * LightSaber
 * (code derived from Arduino IDE examples, additions/integrations/modifications by Andrea Trentini)
 */
 
//#include "pitches.h"
 
// accelerometro
#include <AcceleroMMA7361.h>
 
// LEDstrip
#include "SPI.h"
#include "Adafruit_WS2801.h"
 
//bridge
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>
 
#define COORDINATES 3
// quanti led visibili
//#define RIDUZIONE (500/30)
#define QUALECOORD 1
AcceleroMMA7361 accelero;
int raw[COORDINATES];
//int accel[COORDINATES];
int max=0,min=1000;
//int middle;
 
// Listen to the default port 5555, the Yún webserver
// will forward there all the HTTP requests you send
YunServer server;
 
//TODO: invocazioni di Color si possono fare una volta sola
 
///////////////////////////////////////////////////
//// LED strip
// Choose which 2 pins you will use for output.
// Can be any valid output pins.
// The colors of the wires may be totally different so
// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!
 
uint8_t dataPin  = 2;    // Yellow wire on Adafruit Pixels
uint8_t clockPin = 3;    // Green wire on Adafruit Pixels
//
unsigned long defaultColor=Color(255,0,0);
 
int state=0;
 
// Don't forget to connect the ground wire to Arduino ground,
// and the +5V wire to a +5V supply
 
//#define MIN 5
//#define MAX 15
//#define INCR 1
//#define DELAY 500
 
#define VERSIONE "v7+accel "
 
#define BUTTON 8
#define ELSA 8
 
#define ACCENSIONE 500
 
///////////////////////////////////////
#define LINES 3  // 0,1,2
#define LED_LINE 31 // 0,...,30
///////////////////////////////////////
 
#define LEDS LINES*LED_LINE
 
// Set the first variable to the NUMBER of pixels. 25 = 25 pixels in a row
Adafruit_WS2801 strip = Adafruit_WS2801(LEDS, dataPin, clockPin);
// Optional: leave off pin numbers to use hardware SPI
// (pinout is then specific to each board and can't be changed)
//Adafruit_WS2801 strip = Adafruit_WS2801(25);
//
// For 36mm LED pixels: these pixels internally represent color in a
// different format.  Either of the above constructors can accept an
// optional extra parameter: WS2801_RGB is 'conventional' RGB order
// WS2801_GRB is the GRB order required by the 36mm pixels.  Other
// than this parameter, your code does not need to do anything different;
// the library will handle the format change.  Examples:
//Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin, WS2801_GRB);
//Adafruit_WS2801 strip = Adafruit_WS2801(25, WS2801_GRB);
 
///////////////////////////////////////////////////
 
void setup() {
    //int sleepPin, int selfTestPin, int zeroGPin, int gSelectPin, int xPin, int yPin, int zPin
    accelero.begin(7, 4, 6, 5, A2, A1, A0);
 
    accelero.setARefVoltage(5);
    accelero.setSensitivity(HIGH);
    accelero.calibrate();
 
    // Bridge startup
    pinMode(13, OUTPUT);
    digitalWrite(13, LOW);
    Bridge.begin();
    digitalWrite(13, HIGH);
 
    // Listen for incoming connection only from localhost
    // (no one from the external network could connect)
    server.listenOnLocalhost();
    server.begin();
 
    // initialize the serial communications:
    //Serial.begin(115200);
 
    // init strip
    strip.begin();
    // Update LED contents, to start they are all 'off'
    colorWipe(Color(0, 0, 0));
    strip.show();
    //strip.setPixelColor(1, Color(0,0,255));
    //strip.show();   // write all the pixels out
 
    pinMode(BUTTON,INPUT_PULLUP);
    impulseRing(defaultColor);
}
 
void readAccel() {
    raw[0] = accelero.getXRaw();
    raw[1] = accelero.getYRaw();
    raw[2] = accelero.getZRaw();
 
    if(raw[QUALECOORD]>max) max=raw[QUALECOORD];
    if(raw[QUALECOORD]<min) min=raw[QUALECOORD];
    //middle=(max-min)/2;
}
 
void loop() {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(20);
    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
    //delay(20);
 
    readAccel();
 
    if(digitalRead(BUTTON)==LOW) {
        stato();
        delay(50);
    }
 
    // Get clients coming from server
    YunClient client = server.accept();
    // There is a new client?
    if (client) {
        // Process request
        process(client);
        // Close connection and free resources.
        client.stop();
    }
 
    delay(20);
}
 
void ring(int nr) {
    //ring(nr,Wheel(color));
    ring(nr,defaultColor);
}
 
void ringBlack(int nr) {
    ring(nr,0);
}
 
void ring(int nr,uint32_t c) {
    for(int line=0; line<LINES; line++) {
        //Serial.print(line);
        //Serial.print(" ");
        strip.setPixelColor(LEDindex(nr,line), c);
    }
    strip.show();
 
    //Serial.println("ring");
    //delay(50);
}
 
/** (atrent) from the LED nr (0,1,2,3,...) and the line (0,1,2,3,...) computes the actual index, provided that the circuit is:
 *            0   1   2   3   4   5   6
 * LINE0 ----->|-->|-->|-->|-->|-->|-->|--/
 * LINE1   \-|<--|<--|<--|<--|<--|<--|<--/
 * LINE2   \->|-->|-->|-->|-->|-->|-->|-------
 *
 * REMARK: odd lines are REVERTED!!!
 */
int LEDindex(int nr, int line) {
    /*
    Serial.println("nr:");
    Serial.println(nr);
    Serial.println("line:");
    Serial.println(line);
    */
    // nr of LINES
    // LED_LINE is the number of LEDs per line
    // LEDS total
    if(line>=0 && line<LINES && nr>=0 && nr<LED_LINE) {
        if(line%2 == 0) {
            return nr+(line*LED_LINE); // simple shift
        } else {
            return (LED_LINE-nr-1)+(line*LED_LINE); // shift + revert
        }
    }
    return -1; // error
}
 
 
/*
void ruotaSingolo() {
    strip.setPixelColor(0, Color(0,0,1));
    strip.show();   // write all the pixels out
    delay(DELAY);
    strip.setPixelColor(0, Color(0,1,0));
    strip.show();   // write all the pixels out
    delay(DELAY);
    strip.setPixelColor(0, Color(1,0,0));
    strip.show();   // write all the pixels out
    delay(DELAY);
}
*/
 
/*
void ciclaUnLed() {
    for (int r=MIN; r < MAX; r+=INCR) {
        for (int g=MIN; g < MAX; g+=INCR) {
            for (int b=MIN; b < MAX; b+=INCR) {
                strip.setPixelColor(0, Color(r,g,b));
                strip.show();   // write all the pixels out
                //delay(10);
            }
        }
    }
}
*/
 
/* lightsaber testing
void helix() {
    int nr=0;
    for(; nr<LED_LINE; nr++) {
        ringBlack(nr-1);
        for(int line=0; line<LINES; line++) {
            strip.setPixelColor(LEDindex(nr,line), Color(255,0,0));
            strip.show();
            delay(30);
        }
    }
    //Serial.print("impulse ring, last: ");
    //Serial.println(nr);
    delay(10);
    ringBlack(nr-1);
}
*/
 
 
void rainbow(YunClient client) {
    // Send feedback to client
    client.print(F(VERSIONE));
    client.print(F(" rainbow... "));
    int col=client.parseInt();;
    for(int nr=0; nr<LED_LINE; nr++) {
        ring(nr,Wheel(col));
        col+=20;
        delay(2000/LED_LINE);
    }
    delay(2000);
    colorWipe(0);
}
 
// accensione spada laser
/*
void lightsaber() {
    int nr=0;
    for(; nr<LED_LINE; nr++) {
        ring(nr,defaultColor);
        delay(LED_LINE/2000);
    }
    delay(500);
    //ringBlack(nr-1);
}
*/
 
void impulseRing(unsigned long col) {
    int nr=0;
    for(; nr<LED_LINE; nr++) {
        ring(nr,col);
        //delay(10);
        ringBlack(nr-1);
    }
    ringBlack(nr-1);
}
 
/*
void impulse() {
    for (int i=0; i < strip.numPixels(); i++) {
        if(i!=0) strip.setPixelColor(i-1, Color(0,0,0));
 
        //for (int c=0; c < 1000; c+=20) {
        //strip.setPixelColor(i, Color(255-(i*2),0,2*i));
        strip.setPixelColor(i, Wheel(random(1000)));
        strip.show();   // write all the pixels out
        //delay(15);
        //}
        //delay(5);
    }
 
    colorWipe(Color(0, 0, 0), 0);
    delay(20);
}
*/
 
/*
void old_rainbow(uint8_t wait) {
    int i, j;
 
    for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
        for (i=0; i < strip.numPixels(); i++) {
            strip.setPixelColor(i, Wheel( (i + j) % 255));
        }
 
        strip.show();   // write all the pixels out
        delay(wait);
    }
}
*/
 
// Slightly different, this one makes the rainbow wheel equally distributed
// along the chain
/*
void rainbowCycle(uint8_t wait) {
    int i, j;
 
    for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
        for (i=0; i < strip.numPixels(); i++) {
            // tricky math! we use each pixel as a fraction of the full 96-color wheel
            // (thats the i / strip.numPixels() part)
            // Then add in j which makes the colors go around per pixel
            // the % 96 is to make the wheel cycle around
            strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
        }
 
        strip.show();   // write all the pixels out
        delay(wait);
    }
}
*/
 
 
 
// fill the dots one after the other with said color
// good for testing purposes
void colorWipe(uint32_t c) {
    int i;
 
    for (i=0; i < strip.numPixels(); i++) {
        strip.setPixelColor(i, c);
        //delay(wait);
    }
    strip.show();
}
 
/* Helper functions */
 
// Create a 24 bit color value from B,G,R //ATTENZIONE CHE SONO GIRATI!
uint32_t Color(byte r, byte g, byte b) {
    uint32_t c;
    c = r;
    c <<= 8;
    c |= g;
    c <<= 8;
    c |= b;
    return c;
}
 
//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos) {
    if (WheelPos < 85) {
        return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    } else if (WheelPos < 170) {
        WheelPos -= 85;
        return Color(255 - WheelPos * 3, 0, WheelPos * 3);
    } else {
        WheelPos -= 170;
        return Color(0, WheelPos * 3, 255 - WheelPos * 3);
    }
}
 
 
 
 
//////////////////////////////////////////
/* per accelerometro
void _audioTest() {
    int x=analogRead(xpin);
    int diffx=abs(x-prevx);
    Serial.print(diffx);
    // print a tab between values:
    Serial.print("\t");
    int y=analogRead(ypin);
    int diffy=abs(y-prevy);
    Serial.print(diffy);
    // print a tab between values:
    Serial.print("\t");
    int z=analogRead(zpin);
    int diffz=abs(z-prevz);
    Serial.print(diffz);
    Serial.println();
    // delay before next reading:
    //delay(DELAY);
    int tono=(1+diffx+diffy+diffz)*30;
    tone(8, tono, DELAY);
    delay(DELAY);
    prevx=x;
    prevy=y;
    prevz=z;
}
*/
 
 
 
 
 
 
 
 
/*
  Arduino Yún Bridge example
 
 This example for the Arduino Yún shows how to use the
 Bridge library to access the digital and analog pins
 on the board through REST calls. It demonstrates how
 you can create your own API when using REST style
 calls through the browser.
 
 Possible commands created in this shetch:
 
 * "/arduino/digital/13"     -> digitalRead(13)
 * "/arduino/digital/13/1"   -> digitalWrite(13, HIGH)
 * "/arduino/analog/2/123"   -> analogWrite(2, 123)
 * "/arduino/analog/2"       -> analogRead(2)
 * "/arduino/mode/13/input"  -> pinMode(13, INPUT)
 * "/arduino/mode/13/output" -> pinMode(13, OUTPUT)
 
 This example code is part of the public domain
 
 http://www.arduino.cc/en/Tutorial/Bridge
 
 */
 
 
 
 
 
void process(YunClient client) {
    // read the command
    String command = client.readStringUntil('/');
 
    if (command == "anello") {
        anello(client);
    }
 
    if (command == "anello_colorato") {
        anelloColorato(client);
    }
 
    if (command == "azzera") {
        azzera(client);
    }
 
    if (command == "impulso") {
        impulso(client);
    }
 
    if (command == "rainbow") {
        rainbow(client);
    }
 
    /* is "analog" command?
    if (command == "analog") {
        analogCommand(client);
    }
    */
 
    /* is "mode" command?
    if (command == "mode") {
        modeCommand(client);
    }
    */
}
 
void anello(YunClient client) {
    int nr_anello = client.parseInt();
    ring(nr_anello,defaultColor);
 
    // Send feedback to client
    client.print(F(VERSIONE));
    client.print(F(" anello: "));
    client.println(nr_anello);
}
 
void anelloColorato(YunClient client) {
    int nr_anello = client.parseInt();
    int coloreAnello = client.parseInt();
    ring(nr_anello,coloreAnello);
 
    // Send feedback to client
    client.print(F(VERSIONE));
    client.print(F(" anello colorato: "));
    client.println(nr_anello);
}
 
 
void azzera(YunClient client) {
    int nr_anello = client.parseInt();
    ringBlack(nr_anello);
 
    // Send feedback to client
    client.print(F(VERSIONE));
    client.print(", accel:");
    client.print(accel());
    client.print(", min:");
    client.print(min);
    client.print(", max:");
    client.print(max);
    client.print(F(", black: "));
    client.println(nr_anello);
}
 
int accel() {
	readAccel();
    // tra min=>ELSA e max=>LED_LINE
    return ELSA+(1.0*raw[QUALECOORD]*(LED_LINE-ELSA))/(max-min);
    // old version
    //return raw[QUALECOORD]/RIDUZIONE;
}
 
 
void impulso(YunClient client) {
    int color = client.parseInt();
    impulseRing(color);
    /*
    color+=25;
    if(color>100) {
        color=0;
        lightsaber();
    }
    */
    // Send feedback to client
    client.print(F(VERSIONE));
    client.println(F(" impulso..."));
    //client.println(color);
}
 
void stato() {
    //Serial.println(state);
    switch(state) {
    // spegne
    case 0:
        colorWipe(0);
        state=40;
        break;
    // accende (default)
    /*
    case 10:
        accensione();
        state=20;
        break;
    */
 
    // accende (bianco)
    case 20:
        defaultColor=Color(100,100,100);
        accensione();
        state=30;
        break;
    // accende (darkside)
    case 30:
        defaultColor=Color(0,0,100);
        accensione();
        defaultColor=Color(100,0,0);
        state=60;
        break;
 
    //singolo impulso
    case 40:
        colorWipe(0);
        impulseRing(defaultColor);
        state=50;
        break;
    // tre impulsi colori diversi
    case 50:
        colorWipe(0);
        impulseRing(Color(0,255,0));
        impulseRing(Color(0,0,255));
        impulseRing(Color(255,255,255));
        state=20;
        break;
 
    // bilancia
    case 60:
        bilancia();
        state=0;
        break;
    }
}
 
void bilancia() {
    //accelero.calibrate();
    impulseRing(Color(0,255,0));
    for(int timeout=300; timeout>0; timeout--) {
        ring(accel());
        delay(100);
        colorWipe(0);
    }
    impulseRing(Color(0,255,255));
}
 
void accensione() {
    for(int nr=ELSA; nr<LED_LINE; nr++) {
        ring(nr,defaultColor);
        delay(ACCENSIONE/LED_LINE);
    }
}

Script vari

FIXME incollare qui script di generazione effetti