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.

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@arduino.cz!

Zbyšek Voda

Zbyšek Voda

Už nějaký čas se zajímám o věci kolem Internetu věcí a otevřeného hardware a software. Tak jsem se také v roce 2010 dostal k Arduinu, pro které dodnes programuji a taky píšu články o práci s ním. Baví mě vymýšlet, jak staré věci používat novým způsobem.
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ář