Close

Vaše projekty: Projekt „Bombona“

Arduino Letadlo

V rámci soutěže ke 4000 fanouškům na naší FB stránce se sešlo spoustu zajímavých projektů. To nás namotivovalo k tomu zde vytvořit rubriku Vaše projekty. Víme totiž, že je super mít možnost nechat se inspirovat od ostatních. Jako první Vám přinášíme článek o projektu, který nám poslal Jan Hons Šuškleb. S ním také vyhrál první cenu.


Vše začalo asi před rokem. Začal jsem na zelené louce a prošlapával si cestu neznámým terénem. Vlastně, abych si ověřil využitelnost internetu jako čistě vzdělávacího média a co vše a jakým způsobem je využitelné. Proto jsem projekt paojal širším způsobem. Vyzkoušel 3D tisk, naučil se základy programování a rozšířil si obzory.

Pokud by měl někdo obdobný zájem si vše vyzkoušet, pokusím se celý proces sumarizovat v tomtlo článku.

Procesy, které je možné zvládnout pomocí návodů na youtube a obdobných serverech:

  • výroba, kompletace, rozchození a naučení se létání s RC modelem, 🙂
  • RC simulátor Phoenix,
  • Google Sketchup – pro 3D tisk,
  • Netfabb – finish 3D tisku (vystřelovací mechanismus bomby),
  • Visual Studio s pluginem Micro (programování Arduina),
  • Arduino language,
  • pájení a práce s SMD technologií,
  • návrh obvodu a simulace obvodu,
  • Eagle (pro návrh PCB tištěného spoje),
  • domácí výroba PCB,
  • zdokonalení se v anglickém jazyce
  • a nějaké další dovednosti jako soustružení, sváření, řízení auta, odhánění dětí od nedodělané práce atd.

Každý z těchto procesů je pro začátečníka poměrně náročný a cesta k úspěchu, byť jen částečnému, je plná mnohdy zoufalých pokusů a omylů a vyžaduje nesmírnou trpělivost. Odměnou je ale báječný pocit, že je to alespoň částečně možné ve zcela amatérských podmínkách, bez předchozích znalostí či dovedností, a každá takto nově nabitá zkušenost pootvírá dveře do krásných zákoutí technologické říše divů.

V následujícím představení projektu upozadím procesy přímo nesouvisející s Arduinem a pouze bych k tomu podotknul, že naučit se létat pro mne bylo nejtěžší dovedností, kterou je třeba navíc zcela v mozku zautomatizovat. Proto bych doporučil, z úplného kraje, pár dnů potrénovat se simulátorem a až potom se pustit do rozsekávaní modelů na louce. Každý podle svého gusta. Já jsem samozřejmě začal na louce a až s hromádkou kuliček z EPP jsem pořídil simulátor.

Pájení, výroba PCB, 3D tisk už jsou přeci jen méně adrenalinové záležitosti a dají se zmáknout v klidu, po nocích, z křesla u počítače. Nejprve jsem vyzkoušel Arduino IDE, ale po pár nocích hraní si s template projekty mne přestalo bavit bílé prostředí a u složitějšího kódu nemožnost skrývání stromů kódu a nějak jsem intuitivně tušil, že to jde určitě i jinak a třeba třídění proměnných a automatické doplňování kódu by taky bodlo. Proto jsem sjel tutoriály od Microsoftu: Jak na Visual Studio, a naučil se tak základy.

Bylo třeba doinstalovat Plugin Micro. Vše v předcházejícím návodu.

Obsah článku:

Armstrong

Prvním projektem se stal Armstrong: blikač-pípač- generátor kostky-přehazovač blikacích sekvencí a tak podobně. Doplněno o MP3 přehrávač se tak ze staré krabice na špendlíky stal na několik dnů raketoplán. Děti si s tím chvilku vyhrály, hlavně si to pomohly sestrojit a několikrát letěly za gaučem na Mars i na měsíc.

Armstrong - Arduino Ovladač Raketoplánu
Armstrong – Arduino Ovladač Raketoplánu

Poté jsem sestrojil pípač s rf modulem a nakrmil ho upraveným kódem – odsud: https://www.arduino.cc/en/tutorial/melody.

int speakerPin = 17;
int length = 25; // the number of notes
char notes[] = "CaaggeecCaaggeecoeeee"; // a space represents a rest
int beats[] = { 4, 2, 2, 2, 2, 1, 3, 4, 4, 2, 2, 2, 2, 1, 3, 4, 2, 1, 1, 1, 1, 2, };
int tempo = 150;
void playTone(int tone, int duration) {
    for (long i = 0; i < duration * 1000L; i += tone * 2) {
        digitalWrite(speakerPin, HIGH);
        digitalWrite(13, HIGH);
        delayMicroseconds(tone);
        digitalWrite(speakerPin, LOW);
        digitalWrite(13, LOW);
        delayMicroseconds(tone);
    }
}

void playNote(char note, int duration) {
    char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'o' };
    int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956, 0 };
    // play the tone corresponding to the note name
    for (int i = 0; i < 8; i++) {
        if (names[i] == note) {
            playTone(tones[i], duration);
        }
    }
}

void setup() {
    pinMode(speakerPin, OUTPUT);
    pinMode(13, OUTPUT);
}

void loop() {
    for (int i = 0; i < length; i++) {
        if (notes[i] == ' ') {
            delay(beats[i] * tempo); // rest
        } else {
            playNote(notes[i], beats[i] * tempo);
        }
        // pause between notes
        delay(tempo / 2);
    }
    for (int i = 0; i < 5; i++) {
        digitalWrite(13, HIGH);
        delay(50);
        digitalWrite(13, LOW);
        delay(100);
    }
    delay(250);
}

Konstrukce je obdobná jako RF vysílač odsud. Má pin ATAD a ten se spojí s Arduino vstupovýstupem a napájení s malou LiPol baterkou. To je celé. Více viz zde.

Následovaly mé chabé pokusy s testováním senzorů, ale posléze jsem přišel na to, že existují již hotová kompletní řešení pro všechny senzory, co jsem si půjčil, a že mne to vlastně nebaví. Chtěl jsem dětem sestrojit robota, ale pak jsem jej našel na Aliexpresu hotového, a tak jsem Arduino odložil do šuplíku na neurčito, přemýšlel o koupi hotových řešení a přišlo první zoufalství. Vše již stejně bylo, je a bude uděláno v Číně, proč objevovat Ameriku, když to stačí objednat.

Takže, kdo se s tím vším nechce otravovat a projekt se mu líbí, může si to koupit vše hotové. A Amos Komenský ať se jde zahrabat a dá si oběd v čínském bistru pod bustou pana prezidenta. Vše letělo do kouta, zaprášený ovladač od televize dostal nové baterky a po příchodu z práce jsem se opět resetoval u televize.

Jenže jednoho večera mě tak děsně namíchli s neustálým vymýváním mozku, že ovladač letěl z okna, kutil ve mně se vzepřel a já opět vytáhl Arduino ze šuplíku. Chtěl jsem udělat něco zvláštnějšího a pustit se trošku víc do bastlení, a tak jsem si pořídil řiditelné ledky WS2812B (1, 2).

Jenže NeoPixel kód, teď už vím, že se tomu říká „knihovna“, se mi nelíbil, a tak jsem se naučil používat knihovny a github: https://visualstudio.github.com/. A začal experimentovat s geniální knihovnou FASTLED (G+ komunita).

A zase mě to chytlo. A světlo světa spatřil tento light box:

Video Lightbox

Co umí: spoustu sekvencí, zpomalování, zrychlování a přibral jsem další skill a sice řízení z PC přes serial port. A naučil se psát si primitivní aplikace.


Poznámka pro ty, co s tím třeba ještě nezačali… Byly stavy, kdy jsem mlátil hlavou o klávesnici a naprosto zoufale nechápal, proč to nejede, kde zas chybí nebo přebývá středník a proč programátoři nejsou lidi. A tak jsem objevil komunitu a zjistil, že lidé kolem Arduina jsou poměrně sdílní nadšenci ochotní pomoct a tu a tam se podělit o radu.

A pak už to šlo samo.

Kecám.

Ne nešlo.

Neo se ze mě přes noc nestal, ale osvojil jsem si cyklus neustálého hledání informací v referenčním manuálu, v knihách, fórech a tutoriálech, tedy návodech. Po nějaké době se mi začal jevit kód z internetu jasnější a srozumitelnější a pochopil jsem, že jsou tak asi dva druhy kodérů. Geniální čuňata a shovívaví průvodci neméně tak geniální. A pak taky tak něco mezi a jak kdy.

Čuňáckým kódem nemá vůbec smysl se zabývat a prase, aby se v tom vyznalo. Shovívavý průvodce má kód popsaný, někdy i krásně upravený, a občas je radost se v tom hrabat a člověk se ledacos naučí. A když se k tomu po měsíci vrátí, tak do toho zas nemusí čučet od začátku. To jen tak na okraj, pokud někdo dočetl až sem, čemuž se upřímně divím a v tom případě mi to dělá radost.

if here == ažsem
    potom radost = nějaká hodnota

Pomohlo mi psát si kód takto a až pak jej začít strkat do závorek, středníků a dalších celků. Následovala miniaturizace a s tím spojený přechod na pro mé účely zcela vyhovující „platformu“ Attiny a začal jsem experimentovat s čipy Attiny45 a Attiny85 dle tohoto návodu. Tím jsem potunil bedničku Armstrong, a uvolnil si tak Arduino UNO na další pokusy.

Na jakékoli druhy blikání a na časování nenáročné operace je to podle mě úplně skvělé. Zde je krásně vidět, kolik pinů má který čip k dispozici, a kódování jsem nijak upravovat nemusel.

Historie experimentování - Od 555 po Android
Historie experimentování – Od 555 po Android

A na řadu přišel první FSM. A potřeba multitaskingu a Interrupts a další krásné záhady Arduina. A knihovnička s čudlíkem a knihovnička na servo a první robot na světě. Bohužel nemám dokumentaci, jednalo se o pár pokusů se servama a motorkem. A na řadu přišla potřeba výroby prvního tišťáku. A naprosto frustrující a zničující učení se programu EAGL na kreslení tišťáků.

Pokud někdo začíná, nedělejte stejnou tvrdohlavou chybu jako já a nezačínejte s EAGLEM. Je to mocný nástroj, ale vůbec žádný sluha. Intuitivnost naprosto nulová a to co jsem se před pár měsíci naučil ve sketchupu kvůli 3D tisku, tak v Eaglu jde naprosto proti tomu. Vývojáři toho programu patrně nejsou lidi, ale nějaký druh umělé inteligence. Zlomit ten program mi dalo opravdu děsnou práci. Na druhou stranu v ničem jiném bych už teď nechtěl dělat, protože toho svede opravdu hodně a skvěle. Ale pro začátečníka je to děs. Jistě existují i lehčí programy, na druhou stranu tento je v základu pro domácí kutění zdarma a dá se v něm udělat úplně naprosto vše kolem návrhů elektroniky.

Googloval jsem pojem leptání fotocestou. A postupoval podle návodu z těchto stránek mlab.cz. S tím, že PCB jsem koupil už s fotovrstvou.

První "úspěšně" vyleptaný pokus
První „úspěšně“ vyleptaný pokus

Bombona

Nakonec tedy spíš konečně přišel čas, kdy jsem pocítil potřebu si kód nějak graficky nakreslit, protože jsem se ztrácel v logice, co ze kterého stavu se má pokračovat kam. Můj požadavek na 2CH dvoukanálové ovládání je následující.

  • 1CH (GEARS) z recievru letadla ovládá serva podvozku a s tím rozsvěcuje i přistávací světla (přistávací sekvenci)
  • 2CH (FLAPS) při 1/3 signálu mění sekvence blikání a bomb drop, při plném signálu vysouvá klapky přes zpomalovač.

sekvence blikání:

  • OFF ( Arduino ve sleep modu spotřeba teoretických 6uA, praktických úplně jinde a to teď ladím)
  • ALARM (vše bliká při vybité baterce) – under construction
  • STANDARD
  • TAXI (při pojíždění po runway)
  • BLUE (upozornění před vypuštěním bomby nebo možnost skoku do STD režimu)
  • BOMB DROP

Z toho vyplývá, že jsem začal tvořit jakési stavy nějakého vnitřního stroje a nemohl jsem se v tom vyznat, co má po čem následovat. A tak jsem objevil krásný online nástroj GLIFFY, ve kterém se dají jednotlivé stavy krásně rozkreslit, nebo třeba i jen myšlenková mapa. A kód se pak dá navrhovat snadněji.

A pak už jsem se pustil do finálního programování vlastního blikače a odhazovače. Požadované funkce:

  • Blikání s digitálními ledkami WS2812B
  • Blikání s normálními ledkami
  • Ovládání serva
  • Ovládání dvěma RC kanály – jeden na vysouvání podvozku, ten rozsvítí přistávací sekvenci, druhý na odhazování bomby, vysouvání klapek a přepínání sekvence blikání.
  • Přepínání dotykovým spínačem (když je ero na zemi a pro testování)
  • Přepínání do režimu nízké spotřeby a vypnutí komplet.
  • Monitorování napětí baterky.
  • A příprava na spolupráci s Ardupilotem. (to jsem zatím neimplementoval)

Přikládám i ukázkový kód, ale opatrně s tím, protože jsem tam pomazal hlavičky odkud jsem to polepil, a tak by se autoři oněch řádků mohli čepýřit. Nějak jsem jaksi vůbec nepočítal, že bych to někdy někam dával, ale kamarádovi se to líbilo a přesvědčil mne, tak se s vámi o to dělím!

Zatím jsem nestudoval ty licence a ochrany autorství a takové věci, ale budu se do toho muset brzo pustit. Zde tedy ukázka amatérského kódu. Varuji ale profíky a hnidopichy – „z tohodle vás asi trefí šlak!“ Ale co?! Já mám radost, že to funguje!!! A o to podle mě jde především.

Můj amatérský kód:

/*
 Name:      Navlights_2016_susu_Duben_v9.ino
 Created:   3/29/2016 7:57:36 PM
 Author:    Já + půl internetu  
 docela by mně bodlo, kdyby mně nějaký dobrák vysvětlil jak se to tady s tou hlavičkou dělá.
*/

#include "FastLED.h"
#include "Button.h"

#include "PinChangeInt.h"
#include "Servo.h"

#define NUM_LEDS 2
#define LED_DT 5
#define LED_TYPE WS2812B 
#define COLOR_ORDER GRB 

#define FRAMES_PER_SECOND   100

//*********************_POWERSLEEEP___************************************
#include "LowPower.h"
const int wakeUpPin = 2;
///*********END___INTEGERS POWER SLEEP____********************************************

//uint8_t max_bright = 255;
struct CRGB leds[NUM_LEDS];

int ledMode;                                             // Starting mode is typically 0. Use 99 if no controls available. ###### CHANGE ME #########
int maxMode;
int lastMode;
int multiswitch;

// Pushbutton pin definition
const int buttonled = 11;                                     //LED in power button   já si to prostě občas popisuju anglicky protože mně pak kolegové nečeši rozumí při pomoci                             
int buttonState = 0;
int lastButtonState = 0;
#define BUTTON_PIN 2    // Digital pin used for debounced pushbutton
#define PULLUP true
#define INVERT true  
#define DEBOUNCE_MS 10
#define BLINK_INTERVAL 100
#define LONG_PRESS 3000

Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS);                     // Declare the button
enum { ONOFF, TO_BLINK, BLINK, TO_ONOFF };
uint8_t buttonSTATE;                   //The current state machine state
boolean buttonledState;                //The current LED status
unsigned long ms;                //The current time from millis()
unsigned long msLast;

// Generic variables
uint8_t thisdelay = 0;                                        // Standard delay
uint8_t thishue = 0;                                          // Standard hue
uint8_t thissat = 255;                                        // Standard saturation
int thisbright = 0;                                           // Standard brightness
uint8_t thisfade = 224;                                         // Standard fade rate
bool thisdir = 0;                                             // Standard direction

//___INTEGERS RECIEVER BUS____********************************************
int Gear;
int Flaps;
int alarmmode = 0;

boolean Offmode; //RC swicth ints
boolean Smode;
boolean Tmode;
boolean LLmode;
boolean Amode;
byte Amodecount;

//___INTEGERS SERVO BUS____********************************************
#define GEAR_IN_PIN 4
#define FLAPS_IN_PIN 3
// #define GEAR_OUT_PIN 12
#define FLAPS_OUT_PIN 10 //Bomb
Servo servoGEAR;
Servo servoFLAPS;
#define GEAR_FLAG 2       // These bit flags are set in bUpdateFlagsShared to indicate which
#define FLAPS_FLAG 4        // channels have new signals
volatile uint8_t bUpdateFlagsShared;
volatile uint16_t unGEARInShared;
volatile uint16_t unFLAPSInShared;
uint32_t ulGEARStart;
uint32_t ulFLAPSStart;

//___INTEGERS TAIL STROBO FLASHERU____********************************************
const int ledx = 7;
int stateONOFF = LOW;
int ledx_ONOFF = 1500; //pause time
unsigned long currentMillis = 0;
unsigned long previousONOFF_Millis = 0;
boolean blink = false;

unsigned long currentstrobo = 0;
unsigned long previousstrobo = 0;
long OnTime = 70;     //on step      
long OffTime = 140;  //off step
int ledState = LOW;

int nmbrcount = 4;
int pocitani = 0;

//____WING__INTEGERS_______*******************************************************
//const int ledwing = 8;
int stateONOFF_wing = LOW;
int ledx_ONOFF_wing = 1500; //pause time
unsigned long currentMillis_wing = 0;
unsigned long previousONOFF_Millis_wing = 0;
boolean blink_wing = false;

unsigned long currentstrobo_wing = 0;
unsigned long previousstrobo_wing = 0;
long OnTime_wing = 60;     //on step      
long OffTime_wing = 180;  //off step
int ledState_wing = LOW;

int nmbrcount_wing = 4;
int pocitani_wing = 0;

//______Beacon____***************************************************
int beacon1 = 6;           // the PWM pin the LED is attached to
boolean beac01 = false;
uint8_t xbeacon = 0;
byte xbeaconval = 0;

//______Landning____***************************************************
const int LLled = 13;
boolean ONOFFland = false;
int LLledState;

void setup() {
    //Serial.begin(9600);

    delay(500);

    digitalWrite(buttonled, HIGH);
    servoFLAPS.writeMicroseconds(1800);

    //pinMode(wakeUpPin, INPUT); //sleep wakeup

    pinMode(buttonled, OUTPUT); //Button Led

    pinMode(ledx, OUTPUT); // Tail led. v ocase
    pinMode(beacon1, OUTPUT); // Analog1 - Beacon led. MAJAK A0
    pinMode(LLled, OUTPUT); // Landing led. v křídlech


    LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);     //ws2812 v křídlech 
    //FastLED.setBrightness(max_bright);

    // set_max_power_in_volts_and_milliamps(5, 1000);  // UNDER CONSTRUCTION

    change_mode(ledMode, 0);    // Initialize the first sequence    

                                //********************____RC_READ___**************
//  servoGEAR.attach(GEAR_OUT_PIN);
    servoFLAPS.attach(FLAPS_OUT_PIN);
    PCintPort::attachInterrupt(GEAR_IN_PIN, calcGEAR, CHANGE);
    PCintPort::attachInterrupt(FLAPS_IN_PIN, calcFLAPS, CHANGE);
    
    xbeaconval = 0; //majak initializace 0
}

void loop() {
    detachInterrupt(0);

    ms = millis();
    
    //show_at_max_brightness_for_power();

    RCread();
    RCswitch();
    readbutton();
    change_mode(ledMode, 0);                               // Strobe, don't set it.
}

void change_mode(int newMode, int mc) {                        // mc stands for 'Mode Change', where mc = 0 is strobe the routine, while mc = 1 is change the routine
    maxMode = 6;
    if (mc) Beacon(false);                                           // Set this OFF as default
    if (mc) Landing(false);
    if (mc) fill_solid(leds, NUM_LEDS, CRGB(0, 0, 0));              // Clean up the array for the first time through. Don't show display though, so you may have a smooth transition.

    switch (newMode) {                                          // First time through a new mode, so let's initialize the variables for a given display.
        case  0: if (mc) { thisdelay = 20; } Off(); break;              // All off, not animated.
        case  1: if (mc) { thisdelay = 20; } Beacon(true); TailONOFF(1700, 5);  Sinusovac2();  break;                                         //  Standart                           Strobo2(0xff, 0xff, 0xff, 2, 70, 75); 
        case  2: if (mc) { thisdelay = 20; } Landing(true); Beacon(true); TailONOFF(1000, 3); Sinusovac(); break;                                                     //Landing     {thisdelay=20;} SinusovacPIN();
        case  3: if (mc) { thisdelay = 20; } SinusovacLR(); TailONOFF(3500, 2); break;                                     //Standby TAXI Landing
        case  4: if (mc) { thisdelay = 20; } Beacon(true); TailONOFF(500, 4); Wingstrob(800, 3); break;                                            // Full Strobo - ALARM                       Strobo1(0xff, 0xff, 0xff, 5, 70, 75);
        case  5: if (mc) { thisdelay = 20; } Drop(); {fill_solid(leds, NUM_LEDS, CRGB(0, 0, 255)); LEDS.show(); } LEDS.show(); break;           // BLUE on, not animated.
        case  6: if (mc) { thisdelay = 20; } Beacon(true);  break;             //beacon
    } // switch newMode

    ledMode = newMode;
    lastMode = ledMode;
} // change_mode()

  //---------------------- WINGS - křídla - ws2812 ---------------------------------------------

void Standby() {
    /*
    leds[0] = CRGB::Red;
    leds[1] = CRGB::Green;
    LEDS.show();
    */
}

void Wingwhite() {
    leds[0] = CRGB::White;
    leds[1] = CRGB::White;
    LEDS.show();
}

void Wingblack() {
    leds[0] = CRGB::Black;
    leds[1] = CRGB::Black;
    LEDS.show();
}

void Wingstrob(int ledx_ONOFF_wing, int kolikrat_wing) {
    currentMillis_wing = millis();
    currentstrobo_wing = millis();

    if (currentMillis - previousONOFF_Millis_wing >= ledx_ONOFF_wing) {
        blink_wing = !blink_wing;
        previousONOFF_Millis_wing += ledx_ONOFF_wing;
    }
    if ((blink_wing == true) && (stateONOFF_wing == LOW)) {
        stateONOFF_wing = HIGH;

        Wingstrobo();
    }
    else
    {
        stateONOFF_wing = LOW;
    }
    nmbrcount_wing = kolikrat_wing;
    Pocitadlo_wing();
}

void Wingstrobo() {
    if ((ledState_wing == HIGH) && (currentstrobo_wing - previousstrobo_wing >= OnTime_wing))
    {
        ledState_wing = LOW;
        previousstrobo_wing = currentstrobo_wing;
        // digitalWrite(ledwing, ledState);
        Wingblack();
    }
    else if ((ledState_wing == LOW) && (stateONOFF_wing == HIGH) && (currentstrobo_wing - previousstrobo_wing >= OffTime_wing))
    {
        ledState_wing = HIGH;
        previousstrobo_wing = currentstrobo_wing;
        // digitalWrite(ledwing, ledState);
        Wingwhite();
        pocitani_wing = pocitani_wing + 1;
    }
}

void Pocitadlo_wing() {
    if ((pocitani_wing >= nmbrcount_wing) && (blink_wing == true)) {
        pocitani_wing = 0;
        blink_wing = false;
        // digitalWrite(ledwing, LOW);
        Wingblack();
    }
    stateONOFF_wing = LOW;
}

//----------------------Sinusovac WS2812B ---------------------------------------------
void Sinusovac() {
    uint8_t xsin = beatsin8(25, 0, 255); // beatsin16(BPM,min,max);
    leds[0] = CRGB(xsin, 0, 0);
    leds[1] = CRGB(0, xsin, 0);
    LEDS.show();

} // konec sinusovace

  //----------------------Sinusovac  LEFT/RIGHT WS2812B ---------------------------------------------
void SinusovacLR() {

    uint8_t xsinlr = beatsin8(22, 0, 255); // beatsin16(BPM,min,max);
    leds[0] = CRGB(xsinlr, 0, 0);
    byte z = 255 - xsinlr;
    leds[1] = CRGB(0, z, 0);
    LEDS.show();

} // konec sinusovace


  //----------------------Sinusovac2 WS2812B ---------------------------------------------
void Sinusovac2() {
    uint8_t xsin2 = beatsin8(29, 0, 255); // beatsin16(BPM,min,max);
    leds[0] = CRGB(xsin2, 0, 0);
    leds[1] = CRGB(0, xsin2, 0);
    LEDS.show();

    if (xsin2 <= 7) { Wingwhite(); }
    if (xsin2 <= 5) { Wingblack(); }
    if (xsin2 <= 3) { Wingwhite(); }
    if (xsin2 <= 1) { Wingblack(); }
}


// konec sinusovace

//**************************___TAIL STROBO FLASH___**********************************************************************//

///*
void TailONOFF(int ledx_ONOFF, int kolikrat) {
    currentMillis = millis();
    currentstrobo = millis();

    if (currentMillis - previousONOFF_Millis >= ledx_ONOFF) {
        blink = !blink;
        previousONOFF_Millis += ledx_ONOFF;
    }
    if ((blink == true) && (stateONOFF == LOW)) {
        stateONOFF = HIGH;

        Tailstrobo();
    }
    else
    {
        stateONOFF = LOW;
    }
    nmbrcount = kolikrat;
    Pocitadlo();
}

void Tailstrobo() {
    if ((ledState == HIGH) && (currentstrobo - previousstrobo >= OnTime))
    {
        ledState = LOW;
        previousstrobo = currentstrobo;
        digitalWrite(ledx, ledState);
    }
    else if ((ledState == LOW) && (stateONOFF == HIGH) && (currentstrobo - previousstrobo >= OffTime))
    {
        ledState = HIGH;
        previousstrobo = currentstrobo;
        digitalWrite(ledx, ledState);
        pocitani = pocitani + 1;
    }
}

void Pocitadlo() {
    if ((pocitani >= nmbrcount) && (blink == true)) {
        pocitani = 0;
        blink = false;
        digitalWrite(ledx, LOW);
    }
    stateONOFF = LOW;
}
//*/

/*
void TailONOFF(int casovac, int defpocitac) {
    uint8_t zapvyp;
    zapvyp = beat8(25, 0);
    if (zapvyp < 140)
    {
        uint8_t blik;
        blik = beat8(230, 0);
        if (blik >= 230)ledState = HIGH;
        else ledState = LOW;
    }
    else {
        ledState = LOW;
    }
    digitalWrite(ledx, ledState);
}
*/

//KONEC ****************************************************************************************************************
//----------------------Sinusovac pin BEACON---------------------------------------------

void Beacon(boolean beac01) {
    if (beac01 == true) {     
        uint8_t xbeaconval = beatsin8(9, 0, 255, 0, 0);
        //xbeacon = cubicwave8(xbeaconval);
        xbeacon = quadwave8(xbeaconval);
        analogWrite(beacon1, xbeacon);
    }
    else analogWrite(beacon1, 0);
} // konec sinusovace

  //----------------------Landning ---------------------------------------------

void Landing(boolean ONOFFland) {
    if (ONOFFland == true) {
        LLledState = HIGH;
    }
    else {
        LLledState = LOW;
    }
    digitalWrite(LLled, LLledState);
} // konec landing

  //----------------------All PINS OFF---------------------------------------------
void Off() {
    Offmode = true;
    digitalWrite(ledx, LOW);
    digitalWrite(LLled, LOW);
    analogWrite(beacon1, 0);
    fill_solid(leds, NUM_LEDS, CRGB(0, 0, 0));
    LEDS.show();
}

void Sleep() {
    Off();
    attachInterrupt(0, wakeUp, LOW);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
}
//---------------------- Utility Functions ---------------------------------------------


void wakeUp()
{
    // Just a handler for the pin interrupt.
    
}

int wrap(int step) {
    if (step < 0) return NUM_LEDS + step;
    if (step > NUM_LEDS - 1) return step - NUM_LEDS;
    return step;
} // wrap()

void fill_solid_HSV(uint8_t ahue, uint8_t asat, uint8_t abright) {  // Set all LED's to an HSV value.
    for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CHSV(ahue, asat, abright);
    }
}  // fill_solid_HSV()

void setPixel(int Pixel, byte red, byte green, byte blue) {
    leds[Pixel].r = red;
    leds[Pixel].g = green;
    leds[Pixel].b = blue;
}

void readbutton() {                                           // Read the button and increase the mode
    myBtn.read();

    if (myBtn.wasPressed()) {
        switchLED();
    }
    if (myBtn.wasReleased()) {
        switchLED();
        ledMode = ledMode >= maxMode ? 0 : ledMode + 1;              // Reset to 0 only during a mode change
        change_mode(ledMode, 1);
    }
    if (myBtn.pressedFor(3000)) {
        switchLED();
        digitalWrite(buttonled, LOW);
        ledMode = 255;
        change_mode(ledMode, 1);
        Sleep();
    }
} // readbutton()

  //*******************BUTTON signal LED****************************
void switchLED()
{
    msLast = ms;                 //record the last switch time
    buttonledState = !buttonledState;
    digitalWrite(buttonled, buttonledState);
}

//Switch the LED on and off every BLINK_INETERVAL milliseconds.
void fastBlink()
{
    if (ms - msLast >= BLINK_INTERVAL)
        switchLED();
}

//*******************RC Reciever functions****************************

void RCswitch() {
    if (Offmode == true) {
        Smode = true;   //OFF mode
        Tmode = true;
        LLmode = true;
        Smode = true;
        Offmode = !Offmode;
    }

    else {
        if (Gear == 0 & Flaps == 0) {
            if (Smode == false) {
                change_mode(1, 1); // 1 STANDART  
                Smode = true;
            }

            Tmode = false;
            Amode = false;
            LLmode = false;
            servoFLAPS.writeMicroseconds(1800);
            if (Amodecount > 2) {
                Amodecount = 0;
            }
        }

        if (Gear == 1 & Flaps == 0) {
            if (Tmode == false) {
                change_mode(3, 1); // 3 TAXI  
                Tmode = true;
            }

            Smode = false;
            LLmode = false;
            Amode = false;
        }

        if (Gear == 1 & Flaps == 1) {
            if (LLmode == false) {
                change_mode(2, 1);  // 2 LL 
                LLmode = true;
            }

            Tmode = false;
            Smode = false;
            Amode = false;
            servoFLAPS.writeMicroseconds(1800);
            if (Amodecount > 2) {
                Amodecount = 0;
            }

        }
        if (Gear == 0 & Flaps == 1) {

            if (Amode == false) {

                switch (Amodecount)
                {
                case  0: if (1) change_mode(4, 1);   break;  //ALARM
                case  1: if (2) change_mode(5, 1);   break;  // BombDROP BLUE LIGHT
                case  2: if (3) change_mode(6, 1);   break; // Beacon
                }

                Amodecount++;
                Amode = true;
                Serial.println(Amodecount);
            }

            Tmode = false;
            LLmode = false;
            Smode = false;
        }
    }

    //Serial.println(Smode);
}

//****************SERVO Functions*****************************
void Drop() {
    servoFLAPS.writeMicroseconds(800);
}

void RCread() {
    // create local variables to hold a local copies of the channel inputs
    // these are declared static so that thier values will be retained 
    // between calls to loop.

    static uint16_t unGEARIn;
    static uint16_t unFLAPSIn; // local copy of update flags
    static uint8_t bUpdateFlags; // check shared update flags to see if any channels have a new signal

    if (bUpdateFlagsShared)
    {
        noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables
                        // take a local copy of which channels were updated in case we need to use this in the rest of loop
        bUpdateFlags = bUpdateFlagsShared;

        // in the current code, the shared values are always populated
        // so we could copy them without testing the flags
        // however in the future this could change, so lets
        // only copy when the flags tell us we can.

        if (bUpdateFlags & GEAR_FLAG)
        {
            unGEARIn = unGEARInShared;
        }

        if (bUpdateFlags & FLAPS_FLAG)
        {
            unFLAPSIn = unFLAPSInShared;
        }

        // clear shared copy of updated flags as we have already taken the updates
        // we still have a local copy if we need to use it in bUpdateFlags
        bUpdateFlagsShared = 0;

        interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
                      // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
                      // service routines own these and could update them at any time. During the update, the 
                      // shared copies may contain junk. Luckily we have our local copies to work with 🙂
    }

    // do any processing from here onwards
    // only use the local values unFLAPSIn, unThrottleIn and unGEARIn, the shared
    // variables unFLAPSInShared, unThrottleInShared, unGEARInShared are always owned by 
    // the interrupt routines and should not be used in loop

    // the following code provides simple pass through 
    // this is a good initial test, the Arduino will pass through
    // receiver input as if the Arduino is not there.
    // This should be used to confirm the circuit and power
    // before attempting any custom processing in a project.

    // we are checking to see if the channel value has changed, this is indicated  
    // by the flags. For the simple pass through we don't really need this check,
    // but for a more complex project where a new signal requires significant processing
    // this allows us to only calculate new values when we have new inputs, rather than
    // on every cycle.

    if (bUpdateFlags & GEAR_FLAG)
    {
        if (servoGEAR.readMicroseconds() != unGEARIn)
        {
            servoGEAR.writeMicroseconds(unGEARIn);
        }
    }

    if (bUpdateFlags & FLAPS_FLAG)
    {
        if (servoFLAPS.readMicroseconds() != unFLAPSIn)
        {

        }
    }

    bUpdateFlags = 0;

    /*
    int printme;
    int printmenew = unFLAPSIn;
    if (printmenew != printme)
    Serial.print("\t");
    Serial.println (printmenew);  // display if it changed
    printme= printmenew;
    */

    if (unFLAPSIn > 1000 && unFLAPSIn < 1700) {
        Flaps = 1;

        //Serial.print("\t");
        //Serial.println("Flaps 1");
    }
    if (unFLAPSIn > 1800 && unFLAPSIn < 2100) {
        Flaps = 0;
        //Serial.print("\t");
        //Serial.println("Flaps 0");
    }
    if (unGEARIn > 1000 && unGEARIn < 1400) {
        Gear = 1;
        //Serial.print("\t");
        //Serial.print("\t");
        //Serial.println("Gear 0");
    }
    if (unGEARIn > 1500 && unGEARIn < 2100) {
        Gear = 0;
        //Serial.print("\t");
        //Serial.print("\t");
        //Serial.println("Gear 1");
    }
    /*
    if (unFLAPSIn < 100 && unGEARIn < 100) {
    ledMode = 5;
    change_mode(ledMode, 1);
    }
    */
}

void calcGEAR()
{
    if (digitalRead(GEAR_IN_PIN) == HIGH)
    {
        ulGEARStart = micros();
    }
    else
    {
        unGEARInShared = (uint16_t)(micros() - ulGEARStart);
        bUpdateFlagsShared |= GEAR_FLAG;
    }
}

void calcFLAPS()
{
    if (digitalRead(FLAPS_IN_PIN) == HIGH)
    {
        ulFLAPSStart = micros();
    }
    else
    {
        unFLAPSInShared = (uint16_t)(micros() - ulFLAPSStart);
        bUpdateFlagsShared |= FLAPS_FLAG;
    }
}

No a protože je dobré vědět kdy skončit, přikládám video toho mála, co mám zdokumentované, a přeji všem nadšeným bastlířům, i skutečným profesionálům, ať je nadšení neopustí a ta práce s Arduinem ať se stane nejen vaším osobním rozvojem, ale třeba i uměleckou tvorbou.

S pozdravem
J.H.Šuškleb


Janovi za projekt moc děkujeme a přejeme hodně úspěchů. Máte projekt, se kterým se chcete pochlubit? Napište na zbysek@bastlirna.hwkitchen.cz!

Zbyšek Voda

6 Comments on “Vaše projekty: Projekt „Bombona“

Kamilh
2.5.2016 at 23:28

Hm, abych pravdu rekl, jako modelar pouzivam klasicky volny kanal pro servo pumovnice a nadaval bych do era dalsi vahu ( shield, baterie a pod.) O to vic bonbonu se vejde. Trochu mi uchazi smysl projektu. Cilem bylo aby si deti odpovidacem odhodili bonbony kdy ony chteji? Cili trebas i kdyz nejni ero nad hlavou 🙂

Ardu2do
7.5.2016 at 13:55

Cílem je RF „hon na lišku“
A něco se naučit.
Někam to spadne a pomcí vysílačky se hledá kam.
Dle popisu volny kanal na odhoz bomby neni k dispozici.
5ch klapky
6ch podvozek
Takže kombinaci tech dvou se uvolni 7me servo pro padak.

LuBoss
2.5.2016 at 10:03

Paráda.
Ale přeci jenom jsem u videa až do konce čekal, zda uvidím to nejzajímavější – odhození pumy. To mi tak trošičku chybí 😉

Jiří Patera
1.5.2016 at 11:50

Hezký „životní příběh“! A líbí se mi řada zajímavých odkazů a dobrých tipů ve stylu „jak na to“.

Jiří
1.5.2016 at 11:25

Dobrá inspirace pro modeláře, ale ne všichni modeláři ovládají Arduino tak dokonale. Pokud by tento program měl sloužit jako návod postrádám:
1. seznam komponentů
2. zapojení pinů k Arduinu (ne každý je schopný z program toto vyčíst)
3.odkazy na použité knihovny (odkud se dají stáhnout)
4.připojení příjmače k Arduinu
Sám se už delší dobu o Arduino zajímám a tak vím jak jsou začátky těžké. Využívám volně šiřitelní programy a upravuji si je pro vlastní potřebu. Problémy dělá hledání použitých knihoven. Ne všichni autoři programů dávají na ně odkazy. Troufám si říct že hodě z nás co používáme Arduino jako inspiraci neovládá programování a využívá již hotové programy, případně je upravuje. Vymýšlet něco co už někdo vymyslel je ztráta času. Právě srozumitelné programy pomohou rozšířit řadu těch co se začnou o Arduino zajímat. Pro modeláře vyšla řada návodů v loňském ročníku RC revue. Autorovi tohoto článku přeji další úspěchy a pokud své další nápady bude zveřejňovat ať myslí na ty méně zručné v Arduinu.

Tomáš
25.4.2016 at 21:33

Napsat komentář