KURZ: Cykly

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ů:

  1. cyklus s podmínkou na začátku,
  2. cyklus s podmínkou na konci,
  3. 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 c010 loop large Loop, který nalezneme v paletě Paleta Complete Complete > FlowControl Flow, do okna programu dojde ke vložení výchozího programového cyklu.

NXT-G Cyklus LOOP

Jeho typ je nutno zvolit v parametrech bloku.

Parametry bloku

NXT-G Panel cyklu LOOP

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 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: 

  1. 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.
  2. 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ží).
  3. 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. 

1 1 1 1 1 1 1 1 1 1 Hodnocení 5.00 (1 hodnocení)

Nemáte oprávnění přidat komentář.
Komentáře mohou přidávat pouze registrovaní uživatelé, kteří neporušují pravidla diskuze.