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!