KURZ: Cykly
- Podrobnosti
- PhDr. Tomáš Jakeš, Ph.D.
- Aktualizováno: 30.01.2014
- Zobrazení: 11300
Asi by se nám příliš nelíbilo bezpečnostní zařízení, které by každou vteřinu vyžadovalo manuální spouštění kontroly prostoru. Bezpečnostní alarm by se měl spustit a pak až do svého vypnutí samočinně opakovaně monitorovat střežený prostor.
Právě k programovému provádění opakujících se činností nám slouží cykly. A nejde jen o alarm. V cyklu můžeme opakovaně měřit překročení hodnoty senzoru, testovat, zda uživatel nestiskl tlačítko, či zda není před našim právě jedoucím robotem nějaká překážka. A příkladů by se našla celá řada. Cykly jsou zkrátka základem každého programovacího jazyka a vytvořený program si bez nich lze jen těžko představit.
V programovacích jazycích obvykle rozeznáváme tři typy cyklů:
- cyklus s podmínkou na začátku,
- cyklus s podmínkou na konci,
- cyklus s pevným počtem průchodů.
Cyklus s podmínkou na začátku se výborně hodí na úlohy, ve kterých provádíme určitou činnost a ještě před jejím opakovaným vykonáním otestujeme, zda je splněna podmínka (přesněji podmínkový výraz) dovolující její běh.
Praktické využití: Typické využití pro tento cyklus může být testování volného prostoru před robotem při jeho pohybu. Asi bychom nechtěli, aby se náš domácí robotický vysavač rozjel a plnou silou narazil do nohy stolu a až poté testoval, zda před ním není překážka.
Cyklus s podmínkou na konci je obdobou předchozího cyklu. Činnost je však nejprve vykonána a poté až dochází k testování, zda danou činnost znovu provést.
Praktické použití: Velmi častým příkladem využitím je realizace hlavní programové smyčky, která končí splněním úkolu. Tím může být například zaparkování vozidla na parkovací místo mezi dvěma dalšími auty či pouhé stisknutí tlačítka uživatelem informující o žádosti o ukončení programu.
Cyklus s pevným počtem průchodů je využíván tam, kde známe přesný počet opakování činnosti potřebných ke zdárnému dokončení úkolu.
Praktické použití: Za příklad nám může posloužit stroj, který se potenciálně stará o balení tabletek léků (např. Paralenu) do blistrů. V každém blistru, překrytým hliníkovou fólii jsou dvě řady po pěti lécích. Stroj tedy ví, že má uchopit tabletku ze zásobníku, přesunout ji do připravené jamky v blistru a blistr následně posunout o předem jasně zadanou vzdálenost. Pokud toto zopakuje pětkrát, má tabletkami naplněnou celou řadu. Tento cyklus může být součástí dalšího cyklu, který nejprve připraví pozici pro první a následně pro druhou řadu. Pokud by se výrobce rozhodl využít nových typů maxibalení o dvaceti prášcích (4 řady po 5 prášcích), stačí pouze upravit počet průchodů druhého cyklu.
Použití cyklů v programovacím prostředí
NXT-G
Z pohledu využití cyklů je grafické prostředí NXT-G dosti specifické. Pro realizaci cyklů zde nalezneme pouze jeden jediný blok s názvem Loop. Ten dle nastavení umožňuje provést buďto cykly s podmínkou na konci, s pevným počtem průchodů či speciální časově omezený a nekonečný cyklus, který se dá ukončit pouze blokem Stop či stisknutím šedé tlačítka na kostce NXT.
Umístění bloku cykly (Loop)
Po přetažení bloku Loop, který nalezneme v paletě Complete > Flow, do okna programu dojde ke vložení výchozího programového cyklu.
Jeho typ je nutno zvolit v parametrech bloku.
Parametry bloku
Volba typu cyklus se provádí v sekci Control a to z těchto možností:
- Forever – nekonečný cyklus ukončitelný pouze koncem celého programu.
- Time – časově omezený cyklus s podmínkou na konci, který testuje uplynutí času zadaného v parametru Seconds: v sekci Until:. Pro cyklus trvající půl vteřiny zde nastavíme Seconds: 0.5.
- Logic – cyklus s podmínkou na konci, který o svém pokračování rozhoduje na základě logické hodnoty přivedené na rozhodovací vstup (obrázek ano/ne).
- Sensor – je kombinací předchozího cyklu s výstupem senzoru. Senzor pak poskytuje informaci, zda z něj získaná hodnota splňuje námi nastavenou podmínku. Díky tomuto cyklu pak nemusíme vkládat blok senzoru a následné propojení s cyklem Logic.
- Count – cyklus s pevným počtem průchodů. Počet průchodů se nastavuje v parametru Minimální počet průchodů je stanoven na 1.
U všech cyklů lze pomocí parametru Show: Counter aktivovat výstup počítadla průchodů. To můžeme použít i pro zpracování ve vnitřní části cyklu (např. pro třídičku vykonávající odlišné operace pro sudá a lichá čísla).
Ukázka použití cyklů
RobotC
Příkazy a metody
Na rozdíl od grafického prostředí NXT-G máme v jazyce RobotC k dispozici všechny tři základní typy cyklů. Pojďme si je přiblížit.
Rozcestník
- Cyklus s podmínkou na začátku
- Cyklus s podmínkou na konci
- Cyklus s pevným počtem průchodů
- Import z knihovny funkcí
Cyklus s podmínkou na začátku
Cyklus s podmínkou na začátku nejprve zkoumá, zda došlo ke splnění podmínky či podmínkového výrazu. Pokud je její výsledek pravda (true), vykoná vnořený kód (blok mezi složenými závorkami). Po jeho dokončení se cyklus vrací opět k podmínce a cyklus tak probíhá neustále dokola, dokud nedojde k nesplnění podmínky - nepravda (false).
Základní zápis cyklu
Cyklus se skládá z klíčového slova while za kterým následuje podmínka uzavřená do kulatých závorek (). Za nimi se nachází blok kódu vykonávaný při jejím splnění. Blok kódu je umístěn do složených závorek {}.
//CYKLUS S PODMINKOU NA ZACATKU while (true) //na misto true umistnete podminku ci podminkovy vyraz { //zde umistnete kod, ktery se ma opakovane vykonavat }
Z důvodu přehlednosti programu a odstraňování potencionálních chyb Vám doporučujeme se držet výše uvedeného formátování.
Příklad možné programové konstrukce
V následující ukázce kódu vidíte řešení přiblížení robota na vzdálenost cca. 20 cm od překážky. V případě, že se překážka nachází příliš blízko, motory se nerozjedou a robot zůstane stát.
//UKAZKA - PRIBLIZENI ROBOTA K PREKAZCE (ZDI) NA 20 CM //Robot otestuje, zda se pred nim nenachazi prekazka while (SensorValue[Ultrazvuk1]>20) { //pokud ma pred sebou volno, prekazka je dale nez 20 cm, rozjede se //motor B a C se nastavi na 75% vykon motor[motorB] = 75; motor[motorC] = 75; //protoze nehrozi kolize (prekazka je daleko) a neni tak potreba prilis //casteho testovani, nechame robota jet a dalsi test udelame za 100ms wait1Msec(100); } //Cyklus skoncil, jsme na miste, vypiname motory motor[motorB] = 0; motor[motorC] = 0; //Tento kod je mozno opakovat dle libosti a na rozdil od podminky na konci //nebude dochazet k neustalemu nepatrnemu priblizovani robota k prekazce
Cyklus s podmínkou na konci
Cyklus s podmínkou na konci nejprve provede příkazy umístěné v jeho těle a až následně zkoumá, zda má opětovně vykonat tento blok. Je-li podmínka či podmínkový výraz cyklu splněna (výsledná hodnota pravda (true)) bude cyklus vykonáván. Při hodnotě nepravda (false) se cyklus přeruší a pokračuje se v dalším běhu programu.
Základní zápis cyklu
Cyklus se skládá z klíčového slova do za kterým se nachází blok kódu, který je v případě splnění podmínky opakovaně vykonáván. Blok je uzavřený do složených závorek {}. Po nich následuje klíčové slovo while a podmínka či podmínkový výraz uzavřená do kulatých závorek (). Cyklus je zakončen středníkem ;.
//CYKLUS S PODMINKOU NA KONCI do { //zde umistnete kod, ktery se ma opakovane vykonavat } while (true); //na misto true umistnete podminku ci podminkovy vyraz
Příklad možné programové konstrukce
V následující ukázce kódu vidíte řešení měřiče vzdálenosti, který počítá ujetou vzdálenost podle otáček motoru jež koeficientem přepočítává na ujetou vzdálenost. Pro snazší měření je začátek i konec měření spuštěn stiskem tlačítka.
//UKAZKA MERIC VZDALENOSTI //Meric vzdalenosti pocita pocet stupnu otoceni motoru, //ktere pak prepocita na vzdalenost a zobrazi na displeji //Ke spusteni i zastaveni mereni bude vyuzito tlacitko. //MERENI ZACNE STISKEM TLACITKA do { //specialitou je, ze v teto sekci nebude zadny kod //opakovane se tedy bude vykonavat "nic" //jen se bude testovat, zda muzeme pokracovat } while (SensorValue(dotykovySenzor) == 0); //tlacitko nestisknuto //VYMAZEME POCITADLO MOTORU nMotorEncoder[MotorA] = 0; wait1Msec(1000); //nyni musi uzivatel do vteriny pustit tlacitko //A OPET TESTUJEME TLACITKO do { } while (SensorValue(dotykovySenzor) == 0); //tlacitko nestisknuto //VYPOCET VZDALENOSTI - obvod kola 12 cm float vzdalenost = nMotorEncoder[MotorA] / 360 * 12; nxtDisplayTextLine(4, "%f", vzdalenost); //zobrazeni vzdalenosti na displ. wait1Msec(5000); //cekam, jinak by se displej smazal
Poznámka: V rámci zjednodušení řešení úlohy se předpokládá, že uživatel vždy stisknuté tlačítko do jedné vteřiny pustí. Pro přesnější realizaci by bylo vhodné reagovat spíše na uvolnění tlačítka.
Cyklus s pevným počtem průchodů
Cyklus s pevným počtem průchodů funguje ve třech režimech. V prvním inicializačním režimu, který nastává pouze při novém vstupu do cyklu nastaví výchozí hodnotu proměnné. Tu pak bude využívat pro řízení cyklu. V druhé části dochází k porovnání zadané podmínky. Není-li podmínka splněna, cyklus svou činnost ukončuje. V opačném případě (splnění podmínky) dojde k vykonání příkazů umístěných v programovém bloku cyklu {}. Po dokončení jejich provádění dochází ke změně proměnné podle uživatelem zadaného vzorce (nejčastěji její zvýšení o 1). Poté se celý proces (vyjma úvodního nastavení) opakuje a dochází k opětovnému vyhondocení splnění podmínky.
Cyklus se skládá z klíčového slova for za kterým následují kulaté závorky () obsahující tři časti oddělené středníky:
- inicializace proměnné (příklad: int pruchod=0; nebo i=1;)
V této první části dochází k definici proměnné použité pro řízení programového cyklu a k nastavení její vychozí hodnoty. Proměnná musí být celočíselného datového typu Pokud je proměnná použita jen v rámci tohoto cyklu a nepožadujeme zachování její hodnoty pro zpracování mimo cyklus, je výhodné ji zadeklarovat jako místní proměnnou (int i=1;). Velmi častým názvem proměnné pro tento typ cyklů je i, jenž je zkratkou slova index. Při vnořování cyklů do sebe je pak též využívána proměnná j. Velmi vám proto doporučujeme, abyste proměnné tohoto jména používali výhradně pro cykly. - kontrola splnění podmínky (příklad: pruchod<5; nebo i<=128;)
Ve druhé sekci se definuje podmínka obsahující proměnnou deklarovanou v předchozí části. Při splnění podmínky dojde k vykonání programového kódu umístěného v bloku cyklu. V případě že podmínka není splněna, je cyklus ukončen a je vykonán další příkaz následující za cyklem. Protože podmínka je testována před samotným provedením bloku cyklu, může se stát, že cyklus neproběhne ani jednou (příklad: v zásobníku balícího stroje není dostatečný počet zboží (žvýkaček), takže nelze balení po deseti kusech zkompletovat - čeká se na doplnění zboží). - krok - provedení změny proměnné (příklad: pruchod++; nebo i=i*2;)
Po vykonání příkazů vnořených do cyklu je volán tento blok. Ten obsahuje vzorec pro změnu (zvýšení, snížení) obsahu proměnné. Přesto, že nejčastějším případem je zvýšení proměnné o jedna, je možné obsah proměnné změnit podle předem zadaného vzorce - např. výpočet mocnin čísla 2: i=i*2;.
Za touto sekcí se nachází blok kódu vykonávaný při jejím splnění. Blok kódu je umístěn do složených závorek {}. V tomto bloku je možno využít obsah proměnné určující průběh cyklu.
//CYKLUS S PEVNYM POCTEM PRUCHODU - DEKLARACE for (inicializace_promenne; kontrola_splneni_podminky; krok_provedeni_zmeny_promenne) { //opakovane vykonavany programovy kod }
Příklad možné programové konstrukce
V následující ukázce vidíte použití cyklu pro postupné vypsání čísel 0 až 5 na displeji jendotky.
//CYKLUS S PEVNYM POCTEM PRUCHODU - PRIKLAD for (int i = 0; i<5; i++) { //opakovane vykonavany programovy kod //vypisujici na displeji postupne cisla od 0 do nxtDisplayTextLine(4, "%d", i); wait1Msec(500); }
Vnoření cyklů
Na následujícím programu můžete vidět využití vnoření cyklů v praxi. Program slouží k plnění blistru na tabletky složeného ze dvou řad. Pro umístění tabletek je využíváno vnoření cyklů s pevným počtem průchodů. Detailní popis programu je obsažen v komentářích.
task main() { //VNORENI CYKLU - PROGRAM BALICKA //Program slouzi k plneni blistru na tabletky paralenu //Blistr vzdy obsahuje dve rady tabletek po 5 kusech //Jamky na tabletky jsou od sebe vzdy ve stejne vzdalenosti //ZACATEK - jsem ve vychozi pozici nad prvni tabletkou //potrebuji v kazde ze dvou rad 5x po sobe umistit tabletku //a posunout se na dalsi pozici //nejprve vlozim cyklus pro vyber rady //protoze je pocet rad znamy, zvolim cyklus s pevnym poctem pruchodu for (int rada=1; rada<=2; rada++) { //do kazde rady umistim 5 tabletek //i zvolim cyklus s pevnym poctem pruchodu for (int tabletka=1; tabletka<=5; tabletka++) { //na displeji si vypisu, jakou tabletku plnim nxtDisplayTextLine(4, "r: %d, t: %d", rada, tabletka); //umistim tabletku - ovladano motorem C motor[motorC] = 60; wait1Msec(200); motor[motorC] = -60; wait1Msec(200); //premistim se na dalsi pozici, ktera presne odpovida otoceni 126 stupnu nMotorEncoder[motorA] = 0; nMotorEncoderTarget[motorA] = 126; //rozjedu motor na 45% vykon motor[motorA] = 45; //a necham ho otacet do doby, nez dosahnu ciloveho natoceni //zvolil jsem cyklus while, ktery okamzite testoval, zda nejsem uz spravne while (nMotorRunState[motorA] != runStateIdle) { //motor stale neni na spravne pozici, tak cekam, nez tam dojede //krome neustaleho testovani nedelam nic } //vypnu motor motor[motorA] = 0; //jdu na dalsi tabletku } //zaplnil jsme celou radu tabletek, nyni se vratim na puvodni misto nMotorEncoder[motorA] = 5 * 126; nMotorEncoderTarget[motorA] = 0; motor[motorA] = -45; while (nMotorRunState[motorA] != runStateIdle) { } //vypnu motor posuvu plnicky motor[motorA] = 0; //a posunu platicko na druhou radu nMotorEncoder[motorB] = 0; nMotorEncoderTarget[motorB] = 253; motor[motorB] = 45; while (nMotorRunState[motorB] != runStateIdle) { } //vypnu motor posuvu platicka motor[motorB] = 0; //opakuji plneni rady ... } //nyni mam jiz naplnene platicko a vracim se do vychozi polohy nMotorEncoder[motorB] = 253; nMotorEncoderTarget[motorB] = 0; motor[motorB] = -45; while (nMotorRunState[motorB] != runStateIdle) { } //vypnu motor posuvu platicka motor[motorB] = 0; //cely tento kod mohu umistit do dalsiho cyklu, ktery bude provadet napr. baleni do krabicky }
Import z knihovny funkcí
Pokud si nepamatujeme názvy klíčových slov vykonávajících matematické funkce, můžeme je nalézt v knihovně funkcí (Function Library) sekci _C Constructs.
Po přetažení položek v sekcích Control Structures do programového okna dojde ke vložení námi zvoleného cyklu.