Questo sketch pilota una striscia RGB in base agli alettoni: bianco con roll neutro, verde da un lato e blu dall’altro. Per enfatizzare la transizione tra neutro -> rollio si verifica un lampeggio di mezzo secondo nella transizione.

Il throttle e’ associato a un ciclo IF che pilota un LED in PWM sul motore e due lampeggiatori laterali: al throttle e’ a zero corrisponde uno PWM in dissolvenza verso il bassso per il motore e per i lampeggiatori, con throttle normali la luminosita’ del motore e’ proporzionale a questo, i LED laterali lampeggiano a una frequenza proporzionale al throttle. A throttle al massimo c’e’ una serie di lampeggi casuali per simulare un effetto afterburner.

INPUT:

OUTPUT:

FSM per alettoni = 3 stati + 2 transizioni:

Tramite la lettura del valore del throttle vengono indicati 3 stati:

/* Ailerons state machine
            Serial.print(mid_point);

Pilotare un LED RGB in base al canale degli alettoni:
Questo sketch usa 2 interrupts per thr e alettoni.

INPUT:
PIN 2   : throttle
PIN 3   : alettoni

OUTPUT:
ailerons	RGB Alettoni 
motore		Motore PWM
left, right 2 Lampeggiatori PWM laterali + PWM

FSM per alettoni
= 3 stati + 2 transizioni:
- piatto
- roll a sx
- roll a dx
- piatto -> sx
- piatto -> dx


Ciclo if per gestione di 3 stati del motore:
- idle
- middle 
- max


TODO:
* Da testare! Mai provato.

*/

#include <common.h>
#define DEBUG

// Variabili per interrupt 0 si PIN 2
volatile unsigned int thr = 1500; // Valore computato
volatile unsigned int chStart2 = 1500; // Inizio rilevamento

// Variabili per interrupt 1 su PIN 3
volatile unsigned int ail = 1500; // Valore computato
volatile unsigned int chStart3 = 1500; // Inizio rilevamento

// Variabili per autocalibrazione 0
const byte chPin2 = 3; // PIN per la calibrazione
int mid_point2 = 1500;

// LEDs:
Pwm motore = 11;

// LED RGB alettoni
RGBLed ailerons(5,6,9,255); // Common Cat
// Transizione: Pwm
Lampeggiatore sxLamp(6); // Lampeggiatore
Lampeggiatore dxLamp(9); // Lampeggiatore


// Variabili per lettura canale servo
byte ailPin = 3; // Calibrazione

// Vars Alettoni
int mid_point = 1560 ; // centro del segnale, trimmato nel setup
const int deviation = 50 ; // deviazione dal punto medio
        //per entrare nello stato successivo dal centro

// Led motore e altri:
Lampeggiatore left = 10;
Lampeggiatore right = 12;
Pwm sotto = 9;

// Quando il Throttle e' in IDE facciamo un PWM anche sui laterali
Pwm lpwm = 10 ;
Pwm rpwm = 12;

// Variabili:
unsigned long currentMillis; // timestamp reference per millis per tutto il loop
byte caso; // Random var
byte thrBit ; // Valore a 8bit per il throttle




// FSM gestione alettoni
enum  { // Stati della FMS
    middle,   // centrale
    sxin,     // transizione a sx
    sx,       // sx
    dxin,     // transizione a dx
    dx        // dx
} ailstate  = middle;

// Vars FSM
unsigned long FSM_lastMillis = 0 ; // Timestamp per la FSM degli alettoni
unsigned long pausa = 500;  // Pausa per la transizione durante gli stati 2, 4 della FSM

///////////////////////////////////////////////////////////
void setup() {


#ifdef DEBUG
   Serial.begin(9600);
#endif

    attachInterrupt(0, chRise2, RISING); // PIN 2 su 328p / 168
    attachInterrupt(1, chRise3, RISING); // PIN 3 su 328p / 168


// Funzione relativa a calibrazione:
mid_point =  calibraTrim(ailPin) + 10 ; // + LED di servizio per monitor calibrazione
//Serial.print(mid_point);
//while(1) {
//}
}

void loop() {
    currentMillis = millis(); // Timestamp per tutto il loop

    switch (ailstate) {
    case middle:
        ailerons.White();
        // Alettoni piatti
        if (ail > mid_point + deviation + deviation /3) {
            // extra margine per avere un po' di gioco
            ailstate = sxin;
            FSM_lastMillis = currentMillis;
        }
        else if (ail < mid_point - deviation - deviation / 3) {
            ailstate = dxin;
            FSM_lastMillis = currentMillis ;
        } ;
        break;

    case sxin:
        // Transizione a sx
        sxLamp.Blink(200);
        if (currentMillis - pausa > FSM_lastMillis ) {
            ailstate = sx;
        }
        break;

    case sx:
        ailerons.Green();
        if (ail < mid_point + deviation) {
            ailstate = middle;
        }
        else if (ail < mid_point - deviation) {
            FSM_lastMillis = currentMillis;
            ailstate = dxin;
        } ;
        break;

    case dxin:
        // Transizione a dx
        dxLamp.Blink(200);
        if (currentMillis - pausa > FSM_lastMillis ) {
            ailstate = dx;
        }
        break;

    case dx:
        ailerons.Blue();
        if (ail > mid_point - deviation) {
            ailstate = middle;
        }
        else if (ail > mid_point + deviation) {
            FSM_lastMillis = currentMillis;
            ailstate = dxin;
        } ;
        break;
    }

// Gestione throttle
    if (thr < 1050) {
        // IDLE
        rpwm.UD(2000);
        lpwm.UD(2000);
        motore.lDown(1500);
    }
    else if (thr > 1900) {
        // Throttle al massimo: LED laterali lampeggiano a caso,
        // Sotto luminosita' a caso
        caso = random(30, 250) ;
        right.Swap();
        left.Swap();
        motore.lSet(caso);
        delay(caso); // Blocking!
    }
    else {
        // Throttle medio
        thrBit = map(thr,1050, 1900, 0, 255);
        right.Blink(1220 - 4 * thrBit );
        left.Blink(1220 - 4 * thrBit );
        motore.lSet(thrBit);   // Luminosita' proporzionale al throttle
    }

        
#ifdef DEBUG
Serial.print((thr - 980) / 4);
    Serial.print("\tail: ");
    Serial.print(ail);
    Serial.print("\t ailstate:");
    Serial.println(ailstate);
#endif
}


// Functions
void chRise2() {
    attachInterrupt(0, chFall2, FALLING);
    chStart2 = micros();
}

void chFall2() {
    attachInterrupt(0, chRise2, RISING);
    thr = micros() - chStart2;
}
// Seconod iterrupt
void chRise3() {
    attachInterrupt(1, chFall3, FALLING);
    chStart3 = micros();
}

void chFall3() {
    attachInterrupt(1, chRise3, RISING);
    ail = micros() - chStart3;
}