V minulém díle našeho seriálu zaměřeného na programování jsme se naučili robota rozhýbat a příkazem if podmínit jeho činnost. Tématem druhého dílu budou cykly, využití senzorů a vyluzování zvuků.
Cyklus s daným počtem opakování
Potřebujeme-li opakovat skupinu příkazů, použijeme cyklus. Opakovat lze daný počet n-krát nebo podmíněně.
Zápis vypadá následovně:
repeat(n)
{
příkaz1;
příkaz2;
…
}
Blok příkazů mezi složenými závorkami se bude vykonávat n-krát. Konkrétním příkladem může být pokus o jízdu robota do čtverce. Přesné hodnoty obou konstant musíte zjistit metodou pokus/omyl, protože jízda robota je ovlivněna spoustou přirozených faktorů (povrch, výkon motorů konkrétní stavebnice, stav baterií aj.).
#define pohyb_rovne 150
#define pohyb_zataceni 100
task main()
{
OnFwd(OUT_A+OUT_C);
repeat(4) /*robot čtyřikrát zatočí*/
{
Wait(pohyb_rovne);
OnRev(OUT_A);
Wait(pohyb_zataceni);
OnFwd(OUT_A);
}
Off(OUT_C+OUT_A);
}
Kód s cyklem je přehlednější, než zapsaný bez něj.
Cyklus s podmínkou na začátku
Syntax tohoto cyklu je následující:
while(podmínka)
{
příkaz1;
příkaz2;
}
Příkazy uvnitř složených závorek se vykonají pouze v případě, že platí podmínka v závorce. Často se používá konstrukce while(true) – v tomto případě se budou příkazy mezi závorkami vykonávat stále znovu a znovu, protože podmínka true je vždy platná. Tento zápis má praktický význam při práci se senzory.
Použijeme-li v cyklu příkaz break, cyklus se přeruší a začnou se vykonávat příkazy následující bezprostředně za ním. Poslední příkaz používaný uvnitř těla cyklů je continue. Tento příkaz ukončí právě prováděný průchod cyklem a vynutí přechod k dalšímu průchodu.
Senzory
Díky senzorům může robot reagovat na vnější podněty. Základními senzory jsou dotykový a světelný senzor.
Dotykový senzor
Při stisku mikrospínače vyšle dotykový senzor signál RCX kostce, která na něj může reagovat. V programu je nejprve potřeba nastavit jeden ze vstupů tak, aby byl připraven na data z dotykového senzoru. To se provede příkazem SetSensor(SENSOR_x,SENSOR_TOUCH), kde x je číslo vstupu, ke kterému je dotykový senzor připojen.
SENSOR_1 je proměnná, v níž se zaznamenává hodnota v závislosti na poloze senzoru. Pokud je senzor stlačen, přiřadí se do proměnné SENSOR_1 hodnota 1, v opačném případě obsahuje proměnná hodnotu 0.
Použití dotykového senzoru vypadá následovně:
task main()
{
SetSensor(SENSOR_1,SENSOR_TOUCH);
OnFwd(OUT_A+OUT_C); /*robot jede rovně,…*/
while(SENSOR_1!=1) /*…dokud nenarazí*/
{}
Off(OUT_C+OUT_A);
}
Světelný senzor
Další ze senzorů je světelný. Tento senzor vyšle infračervený paprsek a podle toho, jak se odrazí, dokáže přibližně rozeznat tři barvy. V programu je nejprve opět potřeba připravit vstup ze senzoru příkazem SetSensor(SENSOR_x,SENSOR_LIGHT), kde x je číslo vstupu, ke kterému je připojen světelný senzor.
#define SVETLO 40
task main()
{
SetSensor(SENSOR_1,SENSOR_LIGHT);
OnFwd(OUT_A+OUT_C);
while(SENSOR_1<SVETLO)
{}
Off(OUT_C+OUT_A);
}
Tento program zapne oba motory a robot pojede dopředu, dokud světelný senzor nezaznamená tmavší objekt. Kontrola, zda nebylo nalezeno tmavé místo, probíhá porovnáním hodnoty proměnné SENSOR_1 s konstantou prahové hodnoty černé barvy senzoru (obvykle to bývá 40). Senzor dokáže rozeznat podle intenzity osvětlení tři barvy: bílou, zelenou a černou. Každou z nich můžeme rozpoznat podle určitého rozmezí dat ze senzoru.
Rozmezí |
Barva |
>50 |
bílá |
43-47 |
zelená |
<40 |
černá |
Pokud budeme například kontrolovat, zda robot nepřejel přes zelenou čáru, napíšeme:
while(SENSOR_2>42 && SENSOR_2<48)
{}
Stejné hodnoty získané z optického senzoru nemusí odpovídat vždy stejné barvě – výsledky závisí na vzdálenosti optického senzoru od sledovaného objektu. Pokud se infračervený paprsek špatně odrazí, nemusí výsledek skutečnosti odpovídat vůbec. Proto je vhodné pro každou barvu používat určité rozmezí, které lze metodou pokus/omyl upřesnit. Takto je možné dokonce vymezit i další barvy.
Hudba
Kostka RCX může přehrávat tóny. Kromě vlastního zvukového efektu mohou při programování sloužit k lepší kontrole činnosti robota.
Tóny přehráváme příkazem PlayTone(x,t), kde x je frekvence tónu a t je doba tónu (stejně jako u příkazu Wait() je v setinách sekundy). Tedy příkaz PlayTone(440,100) zahraje tón a1 po dobu jedné sekundy. Za každým zvukovým příkazem by měl následovat příkaz Wait(), protože procesor RCX nečeká, až zvuk dozní, ale začne vykonávat další příkaz.
Přehled jednotlivých frekvencí je uveden v tabulce:
Oktáva |
Tón |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
G# |
52 |
104 |
208 |
415 |
831 |
1661 |
3322 |
|
G |
49 |
98 |
196 |
392 |
784 |
1568 |
3136 |
|
F# |
46 |
92 |
185 |
370 |
740 |
1480 |
2960 |
|
F |
44 |
87 |
175 |
349 |
698 |
1397 |
2794 |
|
E |
41 |
82 |
165 |
330 |
659 |
1319 |
2637 |
|
D# |
39 |
78 |
156 |
311 |
622 |
1245 |
2489 |
|
D |
37 |
73 |
147 |
294 |
587 |
1175 |
2349 |
|
C# |
35 |
69 |
139 |
277 |
554 |
1109 |
2217 |
|
C |
33 |
65 |
131 |
262 |
523 |
1047 |
2093 |
4186 |
B |
31 |
62 |
123 |
247 |
494 |
988 |
1976 |
3951 |
A# |
29 |
58 |
117 |
233 |
466 |
932 |
1865 |
3726 |
A |
28 |
55 |
110 |
220 |
440 |
880 |
1760 |
3520 |
Následující program přehraje jednoduchou melodii.
task main()
{
PlayTone(147,40); Wait(45);
PlayTone(165,40); Wait(45);
PlayTone(175,40); Wait(45);
PlayTone(165,40); Wait(45);
}
Na závěr uvedeme program se všemi dosud probranými prvky jazyka NQC. Robot pojede dopředu, a pokud narazí, změní směr. Jakmile narazí popáté, zastaví se.
task main()
{
SetSensor(SENSOR_1,SENSOR_TOUCH);
SetSensor(SENSOR_3,SENSOR_TOUCH);
int i;
i=0;
OnFwd(OUT_A+OUT_C);
while(true) /*nekonečný cyklus*/
{
while(SENSOR_1!=1) /*robot jede rovně, dokud nenarazí*/
{}
i=i+1; /*počet nárazů se zvětší o 1*/
if (i=5) /*pokud robot narazil pětkrát, cyklus končí*/
break;
OnRev(OUT_A+OUT_C); Wait(50); /*pojede půl sekundy dozadu*/
OnFwd(OUT_A); Wait(40); /*zatočí*/
OnFwd(OUT_C); /*a opět jede rovně*/
}
Off(OUT_A+OUT_C);
}
V příštím díle našeho seriálu ze světa programování dokončíme základy jazyka NQC.
autoři: Filip Děchtěrenko, Mirek Dočekal a Jakub Sedlák