Programování robotů 1
Transkript
OBCHODNÍ AKADEMIE ORLOVÁ, PŘÍSPĚVKOVÁ ORGANIZACE ÚVOD DO PROGRAMOVÁNÍ ROBOTŮ 1 MGR. MIROSLAV SULÍR ORLOVÁ 2012 Tento projekt je spolufinancován Evropským sociálním fondem a státním rozpočtem České republiky PROJEKT: ŠKOLA DNES A ZÍTRA INOVATIVNÍ PŘÍSTUP K VÝUCE TECHNICKÝCH A PŘÍRODOVĚDNÝCH OBORŮ Řešitel projektu: Obchodní akademie, Orlová, příspěvková organizace Učební pomůcka pro podporu výuky přírodních věd a technických oborů Název: Úvod do programování robotů 1 Autor: Mgr. Miroslav Sulír Vydání: Počet stran: 99 Náklad: Tisk: Ediční středisko první, 2012 20 © Mgr. Miroslav Sulír © Obchodní akademie, Orlová, příspěvková organizace Jazyková korektura nebyla provedena, za jazykovou správnost odpovídá autor. ISBN 978‐80‐87477‐04‐5Orlová Tento projekt je spolufinancován Evropským sociálním fondem a státním rozpočtem České republiky 0bsah Kapitola 0. Úvod ................................................................................................................................ 4 Pro koho je kniha určena ..................................................................................................................... 4 Programovací jazyk C# ......................................................................................................................... 4 Lego Mindstorms a Robotc ................................................................................................................. 4 Jak se učit ............................................................................................................................................ 5 Dodatky ke sbírce ................................................................................................................................ 5 Metodika ............................................................................................................................................. 6 Hodně štěstí při práci .......................................................................................................................... 6 Kapitola 1. Program Robotc a stavebnice Lego Mindstorms ............................................................ 7 Instalace vývojových prostředí ............................................................................................................ 7 Chyby při aktualizaci firmware ............................................................................................................ 8 Okno programu Robotc ....................................................................................................................... 9 Sestavení robota ................................................................................................................................ 10 Kapitola 2. Algoritmus a jeho vlastnosti .......................................................................................... 14 Pojem algoritmu ................................................................................................................................ 14 Vlastnosti algoritmu .......................................................................................................................... 14 Zápis algoritmů .................................................................................................................................. 15 Základní algoritmické struktury ......................................................................................................... 16 Kapitola 3. První příklad v prostředí Robotc .................................................................................... 18 Programování motorů ....................................................................................................................... 18 Struktura programu ........................................................................................................................... 18 Kompilace programu ......................................................................................................................... 19 Chyby programů ................................................................................................................................ 20 Nahrání programu do NXT terminálu a jeho testování ..................................................................... 22 Příkazy: motor, wait1Msec ................................................................................................................ 23 Komentáře programu ........................................................................................................................ 24 Kapitola 4. Příklady na jízdu ............................................................................................................. 26 Otáčíme robotem .............................................................................................................................. 26 Kapitola 5. Zvuky .............................................................................................................................. 30 Příkaz PlaySound ............................................................................................................................... 30 Problémy doprovázející příkazy přehráváním zvuku ......................................................................... 32 Přehrání zvuku ze souboru ................................................................................................................ 33 Kapitola 6. Proměnné a datové typy ............................................................................................... 37 Pojem proměnné a datového typu ................................................................................................... 37 Přiřazení hodnoty do proměnné ....................................................................................................... 40 Počáteční inicializace proměnné ....................................................................................................... 40 Konstanta .......................................................................................................................................... 41 Kapitola 7. Psaní na displej NXT terminálu ...................................................................................... 42 Psaní textů ......................................................................................................................................... 42 Velikost písma ................................................................................................................................... 44 Zobrazování hodnot číselných proměnných ..................................................................................... 46 Výpis více proměnných v jednom řetězci .......................................................................................... 48 Zobrazení obsahu textových proměnných v řetězci .......................................................................... 48 Další způsoby výpisu textových informací na displej ........................................................................ 49 Vymazání obsahu displeje ................................................................................................................. 49 Kapitola 8. Početní operace s proměnnými a konstantami číselných datových typů ..................... 51 Zjednodušené psaní operací.............................................................................................................. 53 Kapitola 9. Podmínka ....................................................................................................................... 55 Kapitola 10. Dotykový senzor ............................................................................................................ 58 Dotaz na stisk dotykového senzoru ................................................................................................... 59 Nekonečný cyklus .............................................................................................................................. 60 Časová prodleva pro opětovné testování ......................................................................................... 62 Vícenásobná podmínka ..................................................................................................................... 68 Disjunktní podmínky .......................................................................................................................... 69 Kapitola 11. Hrajeme si ...................................................................................................................... 74 Generátor náhodných čísel ............................................................................................................... 74 Hra pozornosti ................................................................................................................................... 75 Seznam cvičení a souhrnných cvičení v kapitolách Kapitola 0. Úvod ................................................................................................................................ 4 Kapitola 1. Program Robotc a stavebnice Lego Mindstorms ............................................................ 7 Kapitola 2. Algoritmus a jeho vlastnosti .......................................................................................... 14 Kapitola 3. První příklad v prostředí Robotc .................................................................................... 18 Testování příkazů motor a wait1Msec .............................................................................................. 23 Kapitola 4. Příklady na jízdu ............................................................................................................. 26 Otočka o 360 stupňů ......................................................................................................................... 26 Tam a zpět ......................................................................................................................................... 27 Jízda městem ..................................................................................................................................... 28 Kapitola 5. Zvuky .............................................................................................................................. 30 Pojezd a zvuk ..................................................................................................................................... 32 Kolečko se zvuky ................................................................................................................................ 35 Kapitola 6. Proměnné a datové typy ............................................................................................... 37 Kapitola 7. Psaní na displej NXT terminálu ...................................................................................... 42 Popis jízdy .......................................................................................................................................... 44 Odpočet ............................................................................................................................................. 45 10 stupňů celsia ................................................................................................................................. 47 Pi ........................................................................................................................................................ 48 Výkon motorů .................................................................................................................................... 48 Fotbal ................................................................................................................................................. 49 Kapitola 8. Početní operace s proměnnými a konstantami číselných datových typů ..................... 51 Pořadí matematických operací .......................................................................................................... 53 Porovnání zápisu pro zvětšení proměnné ......................................................................................... 54 Odpočet s proměnnou ...................................................................................................................... 54 Kapitola 9. Podmínka ....................................................................................................................... 55 Kapitola 10. Dotykový senzor ............................................................................................................ 58 Zapnutí a vypnutí pojezdu dvěma ovladači ....................................................................................... 62 Zvyšování a snižování rychlosti .......................................................................................................... 65 Zahýbání ............................................................................................................................................ 66 Jízda s nastavením rychlosti předem ................................................................................................. 67 Zahýbání a jízda vpřed 1 .................................................................................................................... 68 Zahýbání a jízda vpřed 2 .................................................................................................................... 69 Zastavení po uplynutí určité doby nebo nárazem do zdi .................................................................. 72 Kapitola 11. Hrajeme si ...................................................................................................................... 74 Generování čísel ze zadaných intervalů ............................................................................................ 74 Hra pozornosti pro dva hráče ............................................................................................................ 78 Pojezdová hra .................................................................................................................................... 79 Kapitola 0. Úvod Pro koho je kniha určena Programování bývá pro začátečníky často učivem velmi obtížným. Každý začátek je ale těžký, a proto je dobré nenechat se odradit. Abych Vám pomohl překonat první krůčky do světa programů „za zdí“, kde slovo program znamená tisíce znaků sdružených do příkazů programovacího jazyka, připravil jsem pro Vás sbírku příkladů Úvod do programování robotů k mechanické programovatelné stavebnici Lego Mindstorms NXT 2.0. Právě držíte její první díl. Tato publikace je určena všem, kteří se chtějí seznámit s programováním, nejen v moderním programovacím jazyce C#. Na své si ovšem přijdou i Ti, kteří už v programování něco zvládají, a chtějí se v něm zdokonalovat zábavnou formou. V obou případech je nutné vlastnit, anebo mít k dispozici (třeba ve škole) programovatelnou stavebnici Lego Mindstorms a program Robotc. Programovací jazyk C# Hlavním cílem knihy je, průběžně Vás seznámit se základy programování v programovacím jazyku C#. Jedná se o objektově orientovaný programovací jazyk, který vyvinula firma Microsoft tak, aby splňoval požadavky platformy .NET. Jazyk C# je pokračovatelem programovacích jazyků C a C++, a vychází tedy z jejich syntaxí (mají stejné nebo podobné příkazy). V jazyce C# dnes můžete programovat prakticky cokoliv, co Vás napadne. Od formulářových aplikací pro Windows, přes software do mobilních zařízení, databáze, až po internetové stránky. Než se však dostanete k programování náročných aplikací, budete muset ujít ještě dlouhou cestu. Stojíte nyní na jejím začátku, což je bezesporu její nejnáročnější část. Na začátku se musíte seznámit se základními algoritmizačními strukturami a příkazy. V tomto dílu učebnice se bude jednat o sekvenci a podmínku. Dozvíte se také, jak pracovat s tzv. proměnnými a konstantami. Pomocí příkladů si budete upevňovat základní programovací návyky. Jazyk C# je dnes velmi moderním a rozšířeným jazykem. Jeho základy, nabyté v této knize, můžete v budoucnu využít k programování formulářových, mobilních, internetových i jiných aplikací. Lego Mindstorms a Robotc Lego Mindstorms je pro začínající programátory velmi zajímavý projekt. Snoubí v sobě totiž jak hračku (přiznejte se, kdo z Vás si rád nehraje ), tak programovací nástroj. Právě skutečnost, že se jedná o hračku, dělá programování zábavnějším. Společnost Lego přibaluje ke stavebnici software nazvaný Lego Mindstorms, ve kterém jsou návody pro sestavení čtyř základních strojů. Taktéž je dodáváno grafické prostředí pro vývoj programů. Tím se ale budeme zabývat velmi okrajově a rovnou se vrhneme na programování pomocí textového zápisu algoritmu. K tomu využijeme program Robotc společností Robomatter LLC / DRJ Software LLC. Protože budete vytvářet programy pro lego robota, jsou nezbytnou součástí učebnice postupy, jak přistupovat k jeho součástkám. Dozvíte se například, jak rozhýbat motor, aby robot popojel, nebo jak detekovat stisk senzoru, aby robot uměl zareagovat na povel zvenčí. Konkrétně se budeme zabývat motory a jejich pojezdem ve stanoveném čase, dotykovým (touch) senzorem, programováním displeje a reproduktoru NXT terminálu. Tento terminál, obsahující procesor, paměť, vstupní a výstupní porty, displej, reproduktor a napájecí systém je hlavním jednotkou každého robota. Jak se učit Při psaní této knihy jsem dbal na to, aby byl každý nový poznatek vysvětlen nejen teoretickým popisem, ale hlavně praktickým příkladem použití. Sbírka obsahuje jak příklady přímo řešené, jejichž rozborem, úpravou a spuštěním se naučíte nové poznatky, tak cvičné, na nichž si osvojené znalosti otestujete. Souhrnná cvičení nakonec otestují Vaše dovednosti na složitějších příkladech. Vyřešené kódy veškerých cvičení s vysvětlením jsou uvedeny v zadní části učebnice. Velmi však na Vás apeluji, abyste těchto klíčů využívali minimálním způsobem. Osvojení programátorských zásad a metod nepatří k nejlehčím, ale vězte, že opisováním kódů se ještě nikdo programovat nenaučil. Pokud tedy budete mít při programování problém, zkuste se ještě jednou vrátit k dotyčné látce v učebnici, nebo se poradit se svými kamarády, či učiteli o možnostech řešení. Nakouknutí do vyřešených kódů berte vždy až jako poslední východisko. Je ještě jeden důvod, proč se unáhleně neuchylovat k hotovým řešením. Programování je tvůrčí činnost, jejímž cílem je vytvořit program splňující zadání (dané učitelem, zaměstnavatelem, sebou samými, …). Pokud byste tento úkol, zadali několika lidem, všichni by začali pracovat na prázdném listu. Výsledné programy by se nakonec více, či méně, lišily. Mohou existovat desítky programových kódů, které nejsou stejné, ale dělají to samé. V zadní části knihy je ale jen jeden z nich. Proto hrozí nebezpečí, že podíváte-li se na hotová řešení této učebnice, můžete spatřit velké rozdíly oproti řešení Vašemu a ztratit tak motivaci, protože budete své řešení automaticky pokládat za od základu špatné. To ale nemusí být pravda a drobnou úpravou Vašeho odlišného přístupu můžete dojít ke zdárnému řešení. Proto si raději programy sami vytvářejte a konzultujte, ne opisujte. Dodatky ke sbírce Knihu doplňuje doprovodné CD, které obsahuje jak veškeré ukázkové programy sbírky, tak řešení cvičných úkolů. Dále je obsažena časově omezená verze programu Robotc v.3.04 a ovladače robota Lego Mindstorms pro Windows, které jsou také volně stažitelné z internetu. CD obsahuje i zvukové soubory použitelné v programech. Na tuto sbírku navazuje její druhý díl Úvod do programování robotů 2, který v příkladech rozvíjí učivo sbírky první a doplňuje ji o další navazující témata. V části programovacích jazyků se jedná hlavně o algebraickou strukturu cyklus. Znalosti stavebnice Lego Mindstorms si rozšíříte o další možnosti ovládání pojezdu motorů, práci s barevným senzorem a ultra-sonic senzorem, což je prakticky sonar pro detekci předmětů v určité vzdálenosti. Metodika Aby byl člověk schopen dobře programovat, určitě se neobejde bez základní teorie. Krom obecné teorie programování se jedná především o znalost základních algebraických struktur a příkazů. S algebraickými strukturami je potřeba se postupně sžívat, a to od jednoduché sekvence, přes složitější podmínku, až k cyklům. Abych dal čtenáři možnost vstřebávat tyto struktury pozvolna, beru je popořádku a ke každé uvádím značné množství ukázkových příkladů i cvičení. Z cyklů se v této sbírce dostane jen na netradiční nekonečný cyklus, který pomůže především při práci s dotykovými senzory. Nad běžícím učivem algebraických struktur nechávám čtenáře objevovat základní příkazy. Jejich naučení podporují ukázkové příklady, které slouží k analýze. Poslední fází naučení je procvičování. Cvičných příkladů je zde dohromady 25. 19 z nich je průběžných a jsou různých typů. Jedná se např. o procvičování jednoduchých příkazů pomocí experimentu, vytváření jednoduchých příkazů, či úpravu kódů vložených na doprovodném CD tak, aby se upravila činnost robota dle zadání. Programování je ale především tvůrčí proces, ve kterém je potřeba naučit se samostatnému tvůrčímu myšlení. To jsem měl při psaní této sbírky na paměti, a proto zde nezanedbatelnou roli hrají příklady, které si musí programátor vymyslet od začátku do konce. K některým příkladům jsem přiřadil poznámky, a to buď dopředu sbírky, abych programátory upozornil na některé problémy a cesty, kudy se vydat. Další poznámky jsou umístěny vzadu v klíči, aby podpořily naučení u problémovějších úloh. 6 souhrnných cvičení ve sbírce má podobu pracovního listu, na kterém je krom zadání její podrobnější rozbor a seznam znalostí a pomůcek, které bude programátor potřebovat. Hodně štěstí při práci Z vlastní zkušenosti vím, že v jakékoli práci je nejdůležitější najít motivaci. Pokud se k ní připojí radost, ať už z objevování nového, či práce samotné, budete na nejlepší cestě být dobří v tom, co děláte. Doufám, že Vám v tom tato sbírka bude aspoň trochu nápomocna. Kapitola 1. Program Robotc a stavebnice Lego Mindstorms Co se naučíte: Stojíte na samém počátku učebnice programování. Proto nebude na škodu seznámit se s programem, ve kterém budete pracovat. Dále si podrobně povíme o stavebnici Lego Mindstorms a jejích možnostech. Klíčové pojmy kapitoly: Robotc, Lego Mindstorms Instalace vývojových prostředí Než nainstalujeme software Robotc do počítače, je nejprve zapotřební nainstalovat do Windows ovladače robota Lego Mindstorms. Ovladače si můžete stáhnout ze stránky http://www.robotc.net/download/nxt/, anebo je naleznete na přiloženém CD. Je potřeba zvolit 32-bitovou nebo 64-bitovou verzi ovladačů, podle verze operačního systému. Zapněte terminál robota oranžovým tlačítkem, připojte jej k počítači USB kabelem a spusťte instalaci. Během ní potvrďte licenční podmínky tlačítkem Agree. Obr. 1 ‐ Průběh instalace ovladače Lego Mindstorms Následně nainstalujte program RobotcForMindstorms. Instalační soubor lze stáhnout ze stejného umístění, ze kterého jste stahovali ovladač robota. Program je dostupný i na přiloženém CD, konkrétně se jedná o verzi 3.0. Při instalaci je opět potřeba potvrdit licenční ujednání. Obr. 2 ‐ Průběh instalace programu Robotc Na CD se nachází pouze 30-ti denní trial verze. Vlastníte-li licenci, můžete si produkt aktivovat v okně ROBOTC License Management. Dostanete se k němu z menu Help, kliknutím na položku Manage Licences. Obr. 3 – Okno pro aktivaci produktu Robotc Při prvním spuštění programu Robotc a prvním připojení robota je potřeba aktualizovat jeho firmware. Zapněte terminál robota oranžovým tlačítkem a připojte k počítači USB kabelem. V nabídce Robot programu Robotc vyberte možnost Download Firmware, a následně položku Standard File (za nápisem Standard File může být označení aktuální verze firmware). Otevře se Vám okno NXT Brick Download, ve kterém stiskněte tlačítko F/W Download. Tím se nainstaluje Firmare ze souboru uloženého ve složce Firmware programu Robotc. Až se v části Message Log okna objeví nápis „Firmware download completed“, je firmware v pořádku nainstalován a můžete se pustit do práce. Chyby při aktualizaci firmware Pokud by došlo k chybě, která by se projevila dlouhodobým zablokováním NXT terminálu za současného „tikajícího“ zvukového signálu, stiskněte v okně NXT Brick Download tlačítko Refresh Lists. Poté se opakujte nahrání tlačítkem F/W Download. Na některých počítačích jsem se při pokusu o aktualizaci firmware setkal s chybovou hláškou odkazující na nemožnost komunikace skrze USB port. V takovém případě stačí program Robotc vypnou a nainstalovat software Lego Mindstorms dodávaný se stavebnicí. To by mělo problém vyřešit. Obr. 4 ‐ Aktualizace firmware robota Lego Mindstorms v okně NXT Brick Download Okno programu Robotc Nyní si popíšeme okno programu Robotc, které můžete vidět na Obr. 5. V horní části programu se nachází, jak jsme zvyklí od většiny programů, hlavní menu a panely nástrojů. Hlavní nabídka obsahuje položky File pro práci se soubory, Edit pro práci se schránkou a funkcemi pro vyhledávání v kódu a View pro úpravu prostřední programu (zobrazování panelů, úpravy fontů, …). Nabídka Robot slouží pro nastavení platformy, správu senzorů a jiných vstup/výstupních zařízení, kompilaci a nahrání programu do paměti NXT terminálu robota. Zbývají nabídky Window pro nastavení samotného menu a Help pro zobrazení přehledně provedené nápovědy, či aktualizace produktu. Pokud budete mít problém s programem, anebo programovacím jazykem, vřele doporučuji nápovědu v menu Help využívat. Nejednou mi dobře posloužila. Panely nástrojů pod hlavní nabídkou umožňují rychlejší přístup k nejčastěji používaným funkcím programu. Největší část okna tvoří editor kódu. Zde budete psát své programy, o jejichž struktuře se něco dozvíte později. Projektů, jak se říká rozpracovaným programům, si můžete otevřít několik najednou a přepínat mezi nimi pomocí záložek nad editorem kódu. Nalevo se nachází panel Function Library, ve které můžete vyhledávat téměř všechny funkční a deklarační předpisy, které lze v programu využít. Výhodné je to především tehdy, nepamatujete-li si příkaz, který potřebujete, nebo hledáte-li příkaz, který by Vám v práci pomohl. Po nalezení jej stačí myší systémem „táhni a pusť“ přesunout na místo kódu, kde jej chcete vložit a doplnit o konkrétní proměnné, či výrazy. Doporučuji však naučit se zápis základních struktur a funkcí programu zpaměti. Ušetříte si tak spoustu času. Dvojitým klikem na položku Function Library spustíte nápovědu. Před každým spuštěním programu se provádí kontrola, zda je veškerý kód napsán formálně správně. Na nesprávně napsaný kód Vás upozorní panel Errors, který se nachází ve spodní části okna programu. A nejen že na něj upozorní, ale navíc označí řádek, kterého se chyba týká a napoví, jak ji opravit. Více o chybách v programu se dočtete v další kapitole. Obr. 5 ‐ Okno programu Robotc Sestavení robota Než začnete vytvářet programy, musíte si ze stavebnice postavit model, pro který je budete vytvářet. Nejsnadnější cesta je spustit si nainstalovaný program Lego Mindstorms, dodávaný se stavebnicí, a vybrat si jeden ze 4 typů robotů vyobrazených v panelu Robo Center programu. Ke každému modelu je připraveno několik obrazových průvodců pro sestavení. Obr. 6 ‐ Panel Robo Center s návody pro sestavení robotů v pravé části okna Pro práci s touto sbírkou příkladů postačí, když si sestavíte vozidlo (Vehicles) v základní variantě (Driving Base). V některých příkladech si k tomuto sestavení (Obr. 7) připojíme senzory. Až budete v programování zběhlejší, můžete si samozřejmě vyzkoušet psát programy i pro roboty v jiných sestaveních. A pokud by Vás ty standardní omrzely, na internetu si jistě najdete návody na další varianty. Obr. 7 ‐ Robot Lego Mindstorms v základní verzi vozidla, se kterou budeme pracovat Krom jednoduchých plastových součástek se ve stavebnici nachází hlavní jednotka nazvaná NXT (název vychází ze slova NEXT) s procesorem a pamětí. Paměť obsahuje obslužný program jednotky, programy, které si do ní skrze USB kabel nahrajete a zdroje, které programy využívají (např. zvuky). Jednotka také obsahuje porty RJ11 pro kabelové připojení motorů a senzorů. Stavebnice disponuje v základní verzi třemi motory (ve většině případů jsou dva hlavní pro pojezd, či pochod, robota a jeden s doplňkovou funkcí), sonar (ultrasonic sensor), který zjišťuje vzdálenost objektů před ním, barevný (color) senzor pro rozeznávání barev a dva dotykové (touch) senzory pro reakci na stisk. Dotykové senzory mohou reagovat na stisk buď jiné součástky robota, nebo na tlak okolního prostředí (např. vražení senzoru na zeď, stisknutí senzoru palcem, …). Je možné dokoupit si další senzory. Senzory jsou hlavní součástky pro komunikaci mezi programem a jeho okolím. Jako vstupní zařízení poskytují programu data z okolí, na základě kterých se pak program rozhoduje, co dál dělat. Jako výstupní zařízení, která demonstrují činnost programu navenek, můžeme označit všechny tři motory a obrazovku NXT terminálu, na které lze vyobrazovat jak textové, tak grafické informace. Mezi výstupní zařízení počítáme i reproduktor terminálu. Při sestavování robota se prosím držte základních připojení motorů a senzorů k NXT terminálu, která dodržuji i ve všech programech sbírky. Vyhnete se tak zbytečným hledání chyb v programu, které by vycházejících pouze ze špatného zapojení: Vstupní, výstupní zařízení Obrázek senzoru Název portu NXT terminálu pojezdové motory B, C doplňkový motor A dotykové senzory dle nastavení programátora v okně Motors and Sensors Setup (touch sensor) barevný senzor (colour sensor) sonar (ultrasonic sensor) dle nastavení programátora v okně Motors and Sensors Setup dle nastavení programátora v okně Motors and Sensors Setup Tab. 1 – Vstupní a výstupní zařízení základní sady stavebnice Lego Minstorms NXT 2.0 Obr. 8 ‐ Základní připojení vstupních a výstupních zařízení k portům NXT terminálu Shrnutí kapitoly: Na úvod jsme si ukázali, co všechno si máme pro naši práci připravit. Nyní se Vám začnou pootevírat dvířka do světa programování. Protože se ale žádná pořádná práce neobejde bez základních teoretických znalostí, bude právě následující kapitola teoretického rázu. Potom už ale rovnýma nohama do programování. Kapitola 2. Algoritmus a jeho vlastnosti Co se naučíte: V následující kapitole se dozvíte, co je to algoritmus, jaké musí splňovat vlastnosti, aby se dal skutečně za algoritmus považovat. Dále si řekneme něco o tom, jaké existují způsoby zápisu algoritmu a z jakých částí (struktur) se obvykle skládají. Klíčové pojmy kapitoly: Algoritmus, konečnost, hromadnost, determinovanost, rezultativnost, vývojový diagram, sekvence, podmínka, cyklus Pojem algoritmu Pod pojmem algoritmu rozumíme posloupnost příkazů (jakýsi postup), která vede k nějakému výsledku. Ač je dnes pojem algoritmu automaticky spojován s programováním, nemusí se k němu nutně vázat. Příkladem může být recept, kdy procházíte od začátku do konce sérií úkonů, na jejichž konci se nachází výsledek v podobě nějaké dobroty. I návod, pomocí kterého skládáte nábytek, nebo třeba vašeho robota, se dá nazvat algoritmem. Vlastnosti algoritmu Nyní, když máte aspoň malou představu o tom, co to algoritmus je, upřesníme si jeho definici výpisem charakteristických vlastností algoritmů: Konečnost Každý algoritmus končí po konečném počtu kroků. Kdybych chtěl např. zjistit, pomocí kolika 2dl skleničkami naplním 1l nádobu vodou, naplnil bych skleničku a vylil do velké nádoby, a to tolikrát, dokud by se nádoba nenaplnila. Důležité přitom je, že by došlo k naplnění nádoby, a tudíž ukončení práce. Pokud bych volil početní řešení, převedl bych nejprve 2dl na 0,2l, a následně vypočítal 1l / 0,2l. Tak bych zjistil, že výsledek je 5 a postup by byl také ukončen. Existují i nekonečné výpočetní metody. Říká se jím reaktivní procesy. To proto, že reagují na podněty z okolí, např. na stisk tlačítka. Nyní Vám prozradím, že i některé programy psané pro našeho robota, budou reaktivní procesy obsahovat. Tím, že nesplňují vlastnost konečnosti, se ale nemusíte trápit. Reaktivní procesy se dají za jistý specifický druh algoritmu pokládat, navíc existují krajní způsoby, jak tento proces ukončit. Hromadnost Každý algoritmus se musí správně vykonat pro jakákoli data splňující vstupní podmínku. Napsat algoritmus pro dělení dvou čísel by asi neměl moc využití, kdyby uměl dělit např. jen čísla 6 a 3. Musí fungovat pro jakákoli čísla, která mu uživatel zadá. Co když ale uživatel zadá jako dělitel číslo 0, kterým dělit nelze? Právě proto je v definici použit onen dodatek: „…data splňující vstupní podmínku.“. Nula zjevně nesplňuje vstupní podmínku pro dělitele. I tak by se měl programátor postarat o to, aby se algoritmus po zadání podobné hodnoty vhodně zachoval, např. upozornil uživatele na chybné zadání. Determinovanost Algoritmus musí být definovaný přesně a jednoznačně. V každém kroku musí algoritmus jednoznačně vědět, kterou cestou se vydat. Představte si, že byste si sedli k televizi a dálkový ovladač Vás najednou přestal poslouchat. Např. by po zvolení kanálu č. 1 ne vždy naskočilo správné vysílání. Nebo byste na kávovaru zvolili konkrétní přípravu kávy a on by ji začal přelévat studenou vodou. Takové „nehody“ by byly asi pořádnou zkouškou pro vaše nervy. Zmíněná zařízení jsou naštěstí naprogramována tak, že vždy přesně vědí, jaká je posloupnost jejich pracovních úkonů a při stejném zadání vždy poskytnou stejný výsledek. A takový by měl být každý algoritmus. Rezultativnost Algoritmus vždy poskytne řešení (neboli výstup), tedy výsledek své činnosti. Když vaříte a procházíte algoritmem – receptem, děláte to za účelem výstupu, tedy oběda. A když se oběd spálí? Inu to také můžeme považovat za výstup. Znovu připomínám příklad s dělením dvou čísel, kde může být řešením jak výsledek dělení, tak informace o chybně zadaných vstupních údajích. Zápis algoritmů Algoritmus je postup sloužící k dosažení nějakého výsledku, a proto je potřeba umět jej správně popsat. Mezi nejjednodušší způsoby zápisu algoritmů patří slovní a písemné. Jde o situace, kdy nám druhá osoba řekne, nebo napíše, co máme udělat. Nejlepší jsou samozřejmě formální popisy, o kterých se již nedají vést velké spory. Často však rozumíme i prostému vysvětlení. Tento způsob prezentace algoritmů je však naprosto nevhodný pro účely programování. Za prvé neexistuje přesný způsob zápisu (dva lidé nás mohou požádat o totéž různým způsobem), ale hlavně, nejsme zvyklí v něm nemluvit tak „doslovně“, jak to přesné algoritmy vyžadují. Pokud např. sedím za stolem a někdo mi dá příkaz: „Rozsviť světlo!“, už mi neříká, že se musím odsunout od stolu, vstát, otočit o x stupňů, popojít o y kroků, natáhnout ruku pod úhlem z stupňů zatlačit na vypínač. Automaticky vím, co musím vykonat pro splnění úkolu a člověk, který mi to přikázal, s tím také počítá. Ale od programu jaksi nic předpokládat nejde. Ten ví pouze to, co mu napíšeme. Pro účely programování musely logicky vzniknout jiné způsoby zápisu – programovací jazyky. Ty jsou přesně definované množinou příkazů a pravidel, jak příkazy používat. My se budeme v této učebnici orientovat na programovací jazyk C#. Ten patří mezi tzv. vyšší programovací jazyky (stejně jako např. další verze jazyku C, Pascal a další). Hardware počítače ale příkazy těchto jazyků nezná. Ten potřebuje univerzálnější, a hlavně strojově akceptovatelnější nižší programovací jazyk, což je jazyk, který dokáže pracovat se strojovým kódem. Programy vyšších programovacích jazyků se proto musí do nižších jazyků překládat, aby je byl hardware schopen zpracovat. K tomu slouží tzv. kompilátory a interpretery. Aby se mezi sebou programátoři pracující s různými programovacími jazyky domluvili, byl vytvořen univerzální způsob zápisu algoritmů, kterému se říká vývojový diagram. Zapisuje se pomocí grafických značek (kroužky, obdélníky, kosočtverce, kosodélníky) na papír nebo do speciálních programů. Grafické značky reprezentují základní příkazy, uvnitř nichž je napsán jejich přesný význam. Jsou propojeny šipkami, které naznačují průchod diagramem. Příklad takového vývojového diagramu můžete vidět na Obr. 9. Začátek čti: číslo číslo < 0 číslo = ‐ číslo vypiš: číslo Konec Obr. 9 ‐ Příklad vývojového diagramu pro výpočet absolutní hodnoty čísla Základní algoritmické struktury Algoritmická struktura je způsob zápisu algoritmu. V programování se setkáváme se třemi základními algoritmickými strukturami: sekvencí, podmínkou a cyklem. Protože je mým cílem, abyste se v rámci učebnice seznamovali s programováním skrze praktické příklady, řekneme si zatím o daných strukturách jen velmi obecně. Nebojte, podrobnějšího výkladu se dočkáte, až budete postupovat učebnicí. Sekvence Sekvence se vyskytují v každém algoritmu, avšak algoritmy, které jsou čistě sekvenční (bez ostatních struktur) potkáváme pro svou jednoduchost velmi zřídka. Jedná se o zápis několika po sobě jdoucích kroků. Ty se vykonávají v přesně daném pořadí a žádný z nich není vynechán. Za sekvenci můžeme považovat už tolikrát zmiňovaný recept (znovu si přečtěte předchozí větu a pochopíte). Podmínka Podmínka je místo v algoritmu, kde je na základě podmínky jednoznačně rozhodnuto, kterou cestou se bude algoritmus dále ubírat. Příkladem ze života může být hod mincí. Pokud si např. házíte, zda půjdete do kina, nebo do divadla, přisoudíte nejprve jednoznačně ke každé možnosti stranu mince. Algoritmus začíná hodem, při kterém padne jedna ze dvou možností. Nastává vyhodnocení na základě podmínky, která jednoznačně říká, co se má dělat v případě, že padne orel, či panna. Dále už se algoritmus zabývá jen buď cestou do kina, nebo cestou do divadla. Cyklus Cyklem nazýváme algebraickou strukturu, která má na starost opakování posloupnosti příkaz. V některých případech je počet opakování přesně daný, jiné cykly opakují své příkazy, dokud není splněna nějaká podmínka. Velmi specifickým druhem cyklu je nekonečný cyklus, který slouží pro testování, zda byla splněna podmínka. Příkladem budiž klávesnice, ve které se stále dokola (pomocí cyklu) testuje, zda došlo ke stisku klávesy. V případě detekce je zjištěno, která klávesa byla stisknuta a příslušný znak se vypíše na obrazovku. Pak se v testování pokračuje. O tomto speciálním cyklu se rozepisuji, protože v této sbírce s ním budete pracovat. V našich programech bude nekonečný cyklus detekovat stisknutí dotykových senzorů robota. Shrnutí kapitoly: Abychom mohli předpis nazvat algoritmem, musí splňovat vlastnost konečnosti, hromadnosti, rezultativnosti a determinovanosti. Výjimečný případ nastává u tzv. reaktivního procesu, který, ač nesplňuje podmínku konečnosti, můžeme za algoritmus považovat. Algoritmy můžeme zapsat různými způsoby. Z odborného hlediska by však měl být tento zápis formalizován. Tyto zápisy mohou být buď obecného (vývojové diagramy) nebo konkrétního charakteru (programovací jazyk). Nejjednodušším algoritmům, které vykonávají jednoduché za sebou jdoucí příkazy, říkáme sekvence. Pokud se musí program rozhodovat, kterak dál postupovat, využije podmínky. Cyklus poslouží pro případ, že potřebujeme jistou část kódu několikrát zopakovat. Kapitola 3. První příklad v prostředí Robotc Co se naučíte: Ukážeme si první sekvenční algoritmus – pojezd robota. Na příkladu si vysvětlíme zapojení a ovládání motorů robota, řekneme si, jaká jsou pravidla při psaní programu, co je to kompilace a jak program nahrát do NXT terminálu. Dále se dozvíte, jak se program chová, má-li v sobě chybu a jak Vám může Robotc pomoci ji napravit. Klíčové pojmy kapitoly: kompilace, syntax, sémantika Nové příkazy: task main( ) hlavička hlavního programu motor( ); nastavení výkonu motoru wait1Msec( ); časová prodleva programu Programování motorů Ke stavebnici jsou přiloženy celkem 3 motory. V sestavení vozidla byste měli mít dva pojezdové motory připojeny k portům B a C NXT terminálu. V programu se na ně budete odkazovat podle písmena portu, ke kterému jsou připojeny. Motor připojený k portu B se bude v programu jmenovat motorB, obdobně to platí i pro ostatní motory. Nyní budeme chtít naprogramovat jízdu robota v délce 3 vteřin. Otevřete si program Robotc, vytvořte nový projekt a napište do editoru kódu následující příkazy: task main() { motor(motorB)=50; motor(motorC)=50; wait1Msec(3000); } Struktura programu Na základě našeho malého příkladu si nyní řekneme něco o struktuře programu. Každý program, který napíšete, bude začínat stejným řádkem, a to: task main() Jedná se o hlavičku hlavního programu. Následovat vždy budou v páru zapsané složené závorky, které ohraničují tělo hlavního programu. Mezi nimi bude napsána posloupnost příkazů. Všimněte si polohy závorek vůči ostatním příkazům. Vím, že budete mít od začátku co dělat s příkazy a logikou programů, avšak důrazně doporučuji naučit se správně program zapisovat. Bude-li nějaká ze závorek trochu víc vlevo nebo vpravo, nebo nebudou-li příkazy pod sebou, ale za sebou, nebude to mít vliv na funkčnost programu, rapidně to však sníží jeho přehlednost a čitelnost. To poznáte, až budou Vaše programy složitější a složitější. Složené závorky ohraničují skupinu příkazů a vyskytují se bezprostředně za určitými typy příkazů. V tomto příkladu se jedná o příkaz task main(), později to bude např. příkaz if. První složená závorka se vždy píše přesně pod první znak příkazu, ke kterému patří. Po stisku Enter můžete sledovat, že se kurzor na novém řádku odsadí o dva znaky doprava oproti závorce. Tam přesně jej chceme chtít. Tam pište své příkazy. Každý napsaný příkaz ukončete středníkem. Až budete na posledním řádku psát ukončující složenou závorku daného bloku, uvidíte, že sama přeskočí na své místo, tedy pod závorku, která daný blok začíná. Teď si můžete říct, že stačí pouze mačkat Enter a Robotc si odsazení řádků projektu obhospodaří sám. A měli byste pravdu. Praxe však vypadá tak, že se stále někde něco dopisuje, přeskupuje a mění, takže na pochvíli si budete muset odsazení příkazů stejně hlídat sami. Program uložte pod názvem „Program 1 – Pojezd“. Vytvoříte tak soubor s příponou „.c“. Příkazy si podrobně vysvětlíme později. Kompilace programu V horní části menu Robot programu Robotc se nacházejí dvě položky: Compile and Download Program a Compile Program. Obr. 10 ‐ Kompilace programu Slovíčko Compile se do češtiny překládá jako kompilace. Kompilace je funkce, kterou provádí překladač (neboli kompilátor). Jedná se o převod programu vytvořeného ve vyšším programovacím jazyce do strojového kódu. Za vyšší programovací jazyky můžeme považovat C, C++, C#, Java, Pascal (a další). Tyto jazyky procesory neznají. Proto je potřeba překladu do strojového kódu, aby si program s hardwarem rozuměl. Kompilátor vždy přeloží program celý od začátku do konce (na rozdíl od programů s obdobnou funkcí – interpreterů). Zatímco položka menu „Compile“ program pouze zkontroluje a přeloží, položka Compile and Download Program jej navíc nahraje do NXT terminálu. Ten musí být během nahrávání zapnutý a připojený k počítači. Aby se program v pořádku přeložil, musí být napsán bez syntaktických chyb. Chyby programů Nikdo není neomylný a každý programátor děla chyby. Svých chyb jsou si vědomy i velké softwarové společnosti, které vydávají zkušební beta verze, aby testováním skryté nedostatky odhalily. A co se neodhalí v beta verzi, to vyspraví opravné balíčky. Vy se budete s chybami potýkat také. I když to samozřejmě nebude v tak masivním měřítku, bude to chtít hodně zkušeností, než se naučíte na chyby pružně reagovat. Nenechte se tím ale odradit. To je úděl každého programátora. Programové chyby dělíme na dva základní typy: Syntaktické chyby jsou prohřešky proti gramatice jazyka. Pokud např. místo příkazu „motor(motorB);“ napíšete příkaz „moter(motorB);“, jedná se o syntaktickou chybu. Pokud byste zapomněli za příkaz napsat středník, nebo vložili do závorky výraz, se kterým příkaz nebude umět pracovat, bude se také jednat o chybu v syntaxi. Stejně tak můžete za syntaktickou chybu považovat neuzavřenou závorku. Syntaktická chyba se nepozorností nebo překlepem vyrobí velmi snadno. Naštěstí pro nás, je také velmi snadno opravitelná. Při kompilaci na něj program upozorní. V dolní části okna Robotc se pod sebe vypíše, na jakých řádcích jsou chyby a jakého typu. Kritické chyby bránící spuštění programu jsou označeny červeným křížkem. Jednodušší chyby, které si kompilátor umí opravit sám, jsou označeny křížkem žlutým, i ty je však dobré opravit ručně. Vyzkoušejte si výše napsaný program zkompilovat přes položku Compile program. Kompilátor by neměl hlásit žádnou chybu (viz. Obr. 11). Obr. 11 ‐ Kompilace syntakticky správně napsaného programu Nyní přepište první příkaz motor na příkaz moter. Opětovná kompilace upozorní na neznámou proceduru na třetím řádku. Tuto chybu označí za kritickou, tedy červeným křížkem. Na tuto chybu se mohou „nabalit“ i další, které však automaticky zmizí s opravou chyby hlavní. Situaci ukazuje Obr. 12. Obr. 12 ‐ Ukázkový příklad syntaktické chyby Opravte chybu, kterou jste schválně vyrobili před chvílí a vyrobte jinou. Smažte středník za prvním příkazem motor a sledujte, jak kompilátor chybu ohlásí. Kritická chyba se dá přeložit jako chybějící (očekávaný) středník. Kompilátor však ukazuje ne na řádek s chybějícím středníkem, nýbrž na řádek pod ním (Obr. 13). To je specifické pro chybu tohoto typu. Překladač totiž hledá středník tak daleko, kam až sahá následující příkaz. Proto chybu najde až těsně před ním. Obr. 13 ‐ Specifický ohlas syntaktické chyby ‐ chybějícího středníku Vyzkoušíme si vyrobit poslední chybu. Tentokrát ale středník vymažeme za posledním příkazem. Na Obr. 14 vidíte, že kompilátor tuto chybu za kritickou nepovažuje. Jak je to možné? Poslední příkaz před koncem bloku (před každou pravou složenou závorkou) totiž nemusí být zakončen středníkem. Reakce kompilátoru je, jak je z obrázku patrné, taková, že chybějící středník sám nahradí. Obr. 14 ‐ Jednoduché syntaktické chyby, které si kompilátor sám opraví, jsou označeny žlutým křížkem Sémantické chyby jsou bohužel horší v tom, že nás na ně kompilátor neupozorní. Jedná se o chyby ve významu. Tyto chyby se projeví až při testování programu, ať už neočekávanou chybou a havárií programu, nebo nekorektními výsledky funkcí (např. 3 + 7 = 15). Nalézt je, a opravit, už je složitější, protože to vyžaduje ponořit se do logiky programu. Nahrání programu do NXT terminálu a jeho testování Zapněte NXT terminál oranžovým tlačítkem a připojte jej USB kabelem k počítači. Program 1 – Pojezd zkompilujte a nahrajte do terminálu pomocí položky Compile and Download Program, která se nachází v nabídce Robot (nebo klávesou F5). Umístěte robota tak, aby měl kolem sebe volné místo na jízdu, stiskněte tlačítko Start v okně ukazující Obr. 15 a sledujte jeho činnost. Obr. 15 ‐ Okno Program Debug Předtím, než si kód rozebereme, vyzkoušejte si, jak bude robot reagovat na následující změny. Po provedení každé změny musíte program uložit, klávesou F5 nahrát do NXT terminálu a spustit jeho provádění tlačítkem Start. Sledujte, jak změny ovlivňují chování robota. Správnost svého pozorování si můžete porovnat s klíčem v zadní části učebnice. Testování příkazů motor a wait1Msec Otevřete si „Program 1 – Pojezd“ a vyzkoušejte si, jak se změní chování robota po těchto programových úpravách: Cvičení 1 1. V původním příkladu změňte čísla 50 na čísla 100. 2. Změňte pouze jednu hodnotu 50 na 100, u druhého příkazu ponechte hodnotu 50. 3. V původním příkladu změňte hodnotu u posledního příkazu z 3000 na 6000. 4. Vymažte celý příkaz wait1Msec(3000); Příkazy: motor, wait1Msec První dva příkazy programu „Program 1 – Pojezd.c“ slouží k nastavení výkonu motorů. Obecný zápis tohoto příkazu je: Příkaz pro nastavení výkonu motoru motor(motorX)=výkon; Rozbor příkazu Písmeno X se nahrazuje písmenem A, B, nebo C (podle toho, k jakému portu terminálu je motor připojen). Za výkon se dosazuje číslo, které označuje procentuální výkon motoru. Nejvyšší číslo, které lze dosadit, je 100 - motor tehdy pracuje na 100% výkon. Nejnižší možný výkon je naopak -100, což znamená 100% výkon v opačném směru otáčení. Vozidlo tedy jede pozpátku. Chcete-li motory zastavit, dosadíte za výkon číslo 0. Pokud má vozidlo 2 motory, je potřeba oba motory nastavit na stejnou hodnotu, chceme-li, aby jelo rovně dopředu nebo dozadu. Při nastavení odlišných hodno se robot otáčí. Nastavíte-li např. levému motoru vyšší výkon, otáčí se rychleji, než motor pravý a robot se tím pádem otáčí na pravou stranu. Poslední příkaz programu je určen pro časovou prodlevu programu a obecně vypadá takto: Časová prodleva Wait1Msec(čas); Rozbor příkazu Časová prodleva se udává do závorky v jednotkách milisekund. Pokud chcete např. časovou prodlevu 1 sekundu, do závorky napíšete číslo 1000. Časová prodleva se nejčastěji využívá proto, aby vymezila čas, po který se projevuje skupina předchozích příkazů, v našem případě, jak dlouho jsou motory aktivní. Kdyby náš program neobsahoval příkaz wait1Msec, po aktivaci motorů by okamžitě následoval konec programu. Při rychlosti, jakou se příkazy provádějí, by totiž program skončil dřív, než by se motory stačily roztočit. To jste si ostatně mohli vyzkoušet u cvičení k tomuto příkladu. Nenabuďte ale mylného dojmu, že časová prodleva vyměřuje čas pro práci motorů. Motory nepřestaly po 3 sekundách prodlevy pracovat, protože by je zastavil příkaz wait1Msec. Tento příkaz slouží pouze jako přestávka programu před vykonáváním dalších příkazů. Motory se v našem příkladu zastavily proto, že za příkazem wait1Msec už nenásledovaly příkazy další a program došel na svůj konec. Pokud by za časovou prodlevou následovaly další příkazy, vykonávaly by se s třísekundovým zpožděním, ale motory by přitom pořád běžely. Nechcete-li, aby se při vykonávání dalších příkazů motory stale točily, musíte je po uplynutí prodlevy zastavit: task main() { motor(motorB)=50; //rozběhnutí motorů motor(motorC)=50; wait1Msec(3000); //3sekundová prodleva motor(motorB)=0; //zastavení motorů motor(motorC)=0; //zde by následovaly další příkazy } Komentáře programu Jistě jste se zamýšleli nad tím, co znamenají ona dvě lomítka na několika částech výše napsaného kódu. Jedná se o komentáře. Pomocí nich si můžete program jednoduše popsat přímo v kódu, abyste věděli (buď okamžitě, nebo za nějaký čas), co jaká část program dělá. Komentář se v programu píše vždy za dvě lomítka. Toto předznačení je informací pro kompilátor, že následující text není příkazem. Bez předznačení by se kompilátor snažil Váš komentář neúspěšně přeložit a ohlásil by chybu programu. Dvě lomítka lze použít pouze bezprostředně před jednořádkovým komentářem. Pokud byste potřebovali napsat komentář na více řádků, musíte jej na začátku i na konci uzavřít pomocí znaku lomítka a hvězdičky: /* Jsem komentář, který přesahuje přes dva nebo více řádky. Musíte mě označit na začátku i na konci, aby kompilátor věděl, kde končím a kde začínají další příkazy. */ Shrnutí kapitoly: Každý program pro Robotc začíná hlavičkou hlavního programu „task main( )“. Za tímto příkazem následuje blok dat ohraničený složenými závorkami. Pro přehlednost programového kódu je vhodné dodržovat zavedenou formu zápisu, u které každý nový programový blok způsobí odsazení jeho vnitřních příkazů doprava oproti předchozímu textu. Je také vhodné si kód okomentovat komentáři. Před nahráním programu do NXT terminálu dochází k jeho přeložení do strojového kódu – tzv. kompilaci. Krom překladu nám kompilace vyhledá syntaktické (gramatické) chyby. Sémantické (logické) chyby se však projeví až při testování programu a programátor musí jejich zdroj hledat sám. Kapitola 4. Příklady na jízdu Co se naučíte: Základní informace pro psaní programu a hledání chyb jste získali v předchozí kapitole. V této kapitole si je osvojíte na několika cvičeních. Detailněji si rozebereme příkaz pro nastavení výkonu motorů. Otáčíme robotem Na základě předchozího příkladu už víte, jak naprogramovat zabočení robota. Oběma motorům dáte kladné otáčky, přičemž jednomu z nich nastavíte vyšší výkon, než druhému. Motoru, který je na straně zabočení, nastavíte zpravidla výkon 0, druhému motoru jakýkoli kladný výkon. Jak ale zajistit otočení na místě? Otevřete si z CD soubor „Program 2 - Otočení na místě“ a vyzkoušejte si jej. Kód programu vypadá následovně: task main() { motor(motorB)=50; motor(motorC)=‐50; wait1Msec(1000); } Možná byste na to přišli sami. Stačí nastavit jednomu motoru kladné otáčky o určitém výkonu, druhému pak záporné otáčky o stejném výkonu. Takovéto protichůdné otáčení způsobuje otáčení robota na místě. O kolik stupňů se ale robot otočí? Na to bohužel neexistuje snadná odpověď. Úhel otočení závisí na výkonu motorů, na době, po kterou se má robot otáčet a na tření působící na pojezdové pásy, tudíž na povrchu podložky, na které je robot umístěn. Testováním jsem zjistil, že při 50% výkonu motorů trvá robotovi s pojezdovými pásy, který je umístěn na papírové podložce, 1 sekundu (1000 ms), než se pootočí o 90 stupňů. Z toho byste mohli mylně usuzovat, že při 100% výkonu bude doba otočení 500 ms. Bohužel, mezi výkonem motorů a časem potřebným k pootočení neexistuje nepřímá úměra. Ostatně si to můžete sami ověřit úpravou výchozího programu. Proto není od věci zapsat si výsledky podobných cvičení, jako je následující. Když později budete vytvářet programy s pojezdy o konkrétní vzdálenosti, či otočkami o konkrétní úhel, z poznámek si budete moci čas pojezdu pro danou činnost a výkon motorů odvodit. Otočka o 360 stupňů Pomocí pokusů určete, jak dlouho trvá robotovi s pojezdovými pásy pootočení o 360 stupňů, stojí-li na dřevěné podložce, pro tyto výkony motorů: Cvičení 2 1. Jeden motor 30% a druhý motor -30%. 2. Jeden motor 50% a druhý motor -50%. 3. Jeden motor 100% a druhý motor -100%. Tam a zpět Vytvořte a otestujte příklad, ve kterém jede robot 4 vteřiny směrem dopředu, otočí se o 180 stupňů a vrátí se na místo, odkud vyjel. To vše při 100% výkonu motorů. Cvičení 3 Pozn. Pokuste se nejprve napsat příklad sami. Pokud si nebudete vědět rady, využijte nápovědy níže. Pokud se Vám ani přesto nepodaří cvičení po delší době vyřešit, využijte klíče v zadní části učebnice. Do klíče se podívejte i přesto, že se Vám příklad vyřešit podaří. Možná zjistíte, že k jeho napsání potřebujete méně příkazů, než jste si mysleli. Nápověda: Program se bude skládat ze tří částí. První a poslední část se shodují (jízda směrem dopředu pomocí nastavení výkonu motorů a nastavení časové prodlevy). Prostřední (otáčecí) sekvence je analogická předchozímu příkladu. Jízda městem Souhrnné cvičení 1 Teoretická východiska Pomůcky Zadání Nakreslete si na papír jednoduché město a vytvořte program, který provede robovozidlo skrz něj ze startovního do koncového bodu – garáže. Do garáže ať vozidlo zacouvá. znalost základní struktury programu příkaz pro spuštění motorů stavebnice s požadovaným výkonem příkaz pro časovou prodlevu robot Lego Mindstorms v sestavení vozidlo (stačí základní, ale může být jakékoli jiné) papír o rozměru cca 0,5 x 1m fixy různě velké krabice (nepovinné) 1. Fixy si namalujte na papír schéma „bludiště“, podobné, jako na obrázku. Krom startovacího a cílového bloku (garáž) jsou na nákresu obdélníky s překříženými čarami. Ty představují domy, které bude muset robot objet. Tip 1: Pokud chcete, můžete nakreslit na prázdná místa ulici a domy vyrobit z krabic. Vše bude vypadat zajímavěji a „město“ určitě najde uplatnění i v jiných příkladech. Tip 2: Pojezdovou plochu si můžete vytvořit i jinou, dbejte však na to, aby robot během své cesty aspoň 3x zatáčel. 2. Vytvořte nový program s názvem „Souhrnné cvičení 1 – Průjezd městem“ a naprogramujte průjezd ulicí města od startu až do garáže. Těsně před garáží, ať se vozidlo na místě otočí o 180° a do garáže zacouvá. Rychlost jízdy nastavte na 30% výkonu. GARÁŽ START Shrnutí kapitoly: Tato kapitola byla spíše praktického rázu. Především jsme si podrobně rozebrali příkaz pro nastavení výkonu motorů robota. Pokud jste předchozí příklady zvládli, můžete si pogratulovat. Pro začínajícího programátora totiž není nic důležitějšího, než pevný a jistý programátorský základ, na kterém se dá dále stavět. Kapitola 5. Zvuky Co se naučíte: Tato kapitola pojednává o přehrávání zvuků přes reproduktor NXT terminálu. Naučíte se pár základních příkazů, a také způsoby, jak nové zvuky do terminálu nahrát. Nové příkazy: PlaySound( název_zvuku) přehrání předdefinovaného zvuku PlaySoundFile(„název_zvuku“); přehrání nahraného zvukového souboru Příkaz PlaySound Zvuk se přehrává dvěma různými způsoby. První z příkazů vypadá následovně: Přehrání předdefinovaného zvuku PlaySound(název_zvuku); Rozbor příkazu Používá se tehdy, chcete-li přehrát jeden z předdefinovaných zvuků. Bohužel, NXT terminál jich obsahuje jen devět. Vytvořte si program Play_sound a vložte příkaz PlaySound( ). Obecně máte při vkládání jakéhokoli příkazu dvě možnosti, jak to udělat. Buď jej přímo napíšete, anebo si jej najdete v panelu Function Library (viz. Obr. 16). Obr. 16 – Příkaz můžete najít v panelu Function Library a přetáhnout do editoru kódu Obr. 16 ‐ Vložení příkazu PlaySound() z Function Library Pokud jste příkaz vložili druhým způsobem, vymažte slovo sound a vepište název vybraného předdefinovaného zvuku. Pokud neznáte jejich názvy, můžete si zvuk vybrat ze seznamu. Stiskněte levým tlačítkem mimo příkaz, a potom umístěte kurzor zpět, mezi prázdné závorky příkazu PlaySound( ). Měl by se Vám ukázat seznam zvuků, ze kterého si stačí vybrat dvojklikem myši, jak to ukazuje Obr. 17. Obr. 17 ‐ Výběr zvuků do příkazu PlaySound() Vyberte zvuk „soundBeepBeep“ a program uložte pod názvem „Program 3 Přehrávání PlaySound“. Program zkompilujte a nahrajte do terminálu. Spuštěním si ověřte, že… nefunguje Z reproduktoru se nic neozývá, protože program zase pádí dopředu rychleji, než bychom potřebovali. Příkaz PlaySound(soundBeepBeep) se sice provede, ale dřív, než se stačí zvuk přehrát, program se vypne. Je to, jako byste si v CD přehrávači našli skladbu, kterou chcete poslouchat, zmáčkli jste Play, ale vzápětí vypnuli přehrávač hlavním tlačítkem. Co ale udělat proto, aby se skladba přehrála? Správně, dáme jí čas. První možností je umístit za příklad dostatečně dlouhou časovou prodlevu. To od nás vyžaduje vědět, jak je zvuk dlouhý. Mnohem lepší je ale vložit za příkaz PlaySound následující cyklus: while(bSoundActive) {} Ačkoli se budete s cykly podrobně seznamovat až ve druhé části sbírky, bude pro Vás užitečné, když se tento specifický naučíte nazpaměť. Aby se Vám lépe pamatoval, zkusíme si jej přeložit do češtiny: While (zatímco) bSoundActive (je aktivní přehrávání zvuku)… a následuje prázdný programový blok, který tedy říká: „Nedělej nic“. Tedy vytvoř časovou prodlevu na nezbytně dlouhou dobu, dokud nedohraje právě přehrávaný zvuk. Zvykněte si tento příkaz dávat za každý příkaz pro přehrání zvuku, který nemá být rušen žádnou následující akcí (např. pojezdem). Pokud program přehráním zvuku končí, je nutné příkaz while(bSoundActive) použít také. Nyní už by se měl program chovat korektně a vypnout se až po dohrání zvuku. Kdybyste chtěli, aby se robot po zaznění zvuku rozjel na 4 sekundy o výkonu 50%, doplnili byste jej takovým způsobem. Doplňte program, uložte jej a ověřte, zda se chová správně. task main() { //přehrání zvuku PlaySound(soundBeepBeep); while(bSoundActive); {} //jízda motor(motorB)=50; motor(motorC)=50; wait1Msec(4000); } Pojezd a zvuk Vytvořte program, ve kterém nejprve robo-vozidlo pojede 5 sekund dopředu 20% Cvičení 4 výkonem motorů a po zastavení přehraje zvuk „soundDownwardTones“. Problémy doprovázející příkazy přehráváním zvuku Pokud se Vám podařilo předchozí cvičení správně naprogramovat, tak Vás chválím. Rád bych Vás ale upozornil na jednu záludnost, kterou provází přehrávání zvuků. Zkuste v programu „Cvičení 4 – Pojezd a zvuk“, který jste buď naprogramovali, nebo jej máte k dispozici na přiloženém CD, změnit výkon pojezdu z 20% na 100%. Po spuštění zjistíte, že zvuk, který se má po dojezdu přehrát, neslyšíte, nebo jej slyšíte v pozadí, když vozidlo stále jede. Tato chyba se projeví pokaždé, použijete-li příkaz přehrávající zvuk za příkazy, které zastavují motory po pojezdu s vysokým výkonem. Jedná se pravděpodobně o synchronizační chybu NXT terminálu. Pro Vás je především důležitá informace, že tuto chybu nemáte jako programátoři možnost ovlivnit. Můžete ji však obejít, a to tím, že za příkazy zastavení motoru vložíte cca 1,5-sekundovou časovou prodlevu, během níž budou ještě motory dokončovat svůj pojezd. Program (na CD uložen pod názvem Program 4 - Pojezd s velkým výkonem a zvukem) tedy bude vypadat následovně. task main() { motor(motorB)=100; //jízda motor(motorC)=100; wait1Msec(5000); motor(motorB)=0; //pokud nevypnete motory, zvuk nepůjde slyšet motor(motorC)=0; wait1Msec(1500); /*NUTNÁ ČASOVÁ PRODLEVA MEZI PŘÍKAZY ZASTAVUJÍCÍ MOTORY PO POJEZDU S VYSOKÝM VÝKONEM A PŘÍKAZEM PŘEHRÁVAJÍCÍ ZVUK*/ PlaySound(soundDownwardTones); //prehrani zvuku while(bSoundActive); {} } Tuto chybu jsem uvedl záměrně, protože pro toho, kdo o ní neví, je velmi těžko odhalitelná. Proto, pokud by se Vám někdy nechtěl přehrát zvukový soubor, zkuste si vzpomenout na tuto část kapitoly. Možná Vám ušetří spoustu času. Přehrání zvuku ze souboru Robot dokáže přehrát zvuk i ze souboru: Tento soubor musí mít příponu .rso. Příkaz má následující syntaxi: Přehrání zvuku ze souboru PlaySoundFile(„název_zvuku“); Rozbor příkazu Zvukový soubor musí mít příponu „rso“. Název zvuku musí být vypsán včetně přípony a v uvozovkách. Zvukový soubor musí být nahrán do NXT terminálu. Způsob tohoto nahrání je obsažen dále v této kapitole. Máte několik možností, jak se dostat ke zvukům v .rso formátu: 1. Můžete je nalézt ve složce Sounds nainstalovaného software Lego Mindstorms dodávaného se stavebnicí. Standardní cesta ke zvukovým souborům je: C:\Program Files\LEGO Software\LEGO MINDSTORMS NXT\engine\Sounds 2. Několik zvukových soborů si můžete stáhnout ze stránek http://mindstorms.lego.com Je potřeba kliknout na odkaz Funzone, na další stránce na Downloads, a nakonec na Sounds. Přímý odkaz na stránku se stahováním je (přístupnost ověřena 1.8.2010) http://mindstorms.lego.com/en-us/funzone/downloads/default.aspx#Sounds 3. Pomocí konvertovacích nástrojů převést zvukový soubor v jiném formátu (např. mp3) na formát .rso. Bohužel, převod se vždy musí provést přes formát .vaw (pokud chcete např. přehrát mp3 soubor, je třeba jej nejprve převézt do .vaw formátu, a následně do .rso formátu). Další omezení vyplývá z velmi malé paměti NXT terminálu, která nepojme velké zvukové soubory, nebo jen v omezeném množství. Zvukové soubory z bodu 1 a 2 máte k dispozici na CD k této sbírce. Aby bylo možné přidané soubory v programech využívat, musí být zvuk nahrán v NXT terminálu. To se děje dvěma způsoby: 1. Nahrát do soubor do složky NXT Systém Files programu RobotC. Zde je standardní cesta k adresáři: C:\Program Files\Robotics Academy\ROBOTC for MINDSTORMS\NXT System Files Mějme vytvořený, uložený a zkompilovaný program s využitím externího zvukového souboru. Při nahrání si software zkontroluje, zda se daný soubor nachází v NXT terminálu. Není-li tomu tak, stáhne si jej sám z výše uvedené složky. Pokud se nenachází ani v této složce, nahlásí chybu. 2. Přes program Robotc. V menu Robot, NXT Brick, File Management (Obr. 18) Obr. 18 ‐ Cesta k File Managementu pro nahrání souborů do NXT terminálu V okně File Managementu (Obr. 19) stiskněte tlačítko Download. Najděte soubor, který chcete nahrát, ve složkách počítače a otevřete. Nakonec stiskněte tlačítko Refresh Files. Tímto způsobem jste nahráli soubor rovnou do NXT terminálu a je připraven k použití v programu. Ve správci souborů si můžete zvuky i přehrávat, mazat je, anebo uvést paměť NXT terminálu do původního stavu, v jakém byl zakoupen. Obr. 19 ‐ Okno File Management pro správu souborů NXT terminálu Pro přehrání zvuku ze souboru je potřeba dodržet stejná opatření, jako tomu je u příkazu PlaySound. Tedy použít příkaz while(bSoundActive) za příkazem, nemá-li být zvuk přerušen. Taktéž před příkaz nezapomeňte umístit 1,5-sekundovou časovou prodlevu, následuje-li za příkazy zastavující motory po pojezdu s vysokým výkonem. Tím předejdete tomu, že byste zvuk neslyšeli z důvodu dojezdu motorů. Další příkazy spojené s přehráváním zvuku si můžete prostudovat v nápovědě programu Robotc. Kolečko se zvuky Ať robot řekne na začátku programu „Start“, objede jedno kolečko o poloměru cca Cvičení 5 10 cm. Po dojezdu ať zavolá „Good Job“ (to abychom se pochválili, jak nám to programování dobře jde) a program se ukončí. Pozn. Pro začátek bude potřeba připravit soubory Start.rso a Good Job.rso pro nahrání do NXT terminálu. Jedná s o zvuky nainstalované se softwarem Lego Mindstorms dodávaného se stavebnicí. Jak je dohledat a jak připravit pro nahrání do terminálu bylo popsáno v této kapitole. Shrnutí kapitoly: V této kapitole jste se naučili, jakým způsobem naučit robota pípat, hrát, nebo třeba i mluvit. Buď se jednoduše využije jeden z mála předdefinovaných zvuků, nebo nahrajete zvuk z externího souboru. Druhá varianta je sice malinko zdlouhavější, může však učinit Vaše programy mnohem originálnější. Vedle pohybových a zvukových projevů robota můžeme postavit i další jeho možnou činnost - zobrazování textu na displeji NXT terminálu. Před jeho vysvětlením si ale musíme připravit půdu v podobě ´teoretičtější kapitoly a proměnných. Kapitola 6. Proměnné a datové typy Co se naučíte: Tato kapitola je čistě teoretického rázu a pojednává o proměnných. Proměnné si můžete představit jako pojmenovaná místa v paměti, do kterých můžete ukládat a uchovávat různé hodnoty. Naučíte se, jak vytvořit proměnné takového typu, aby se jim daly přiřadit informace, jaké potřebujete. A o přiřazení samotném si také povíme. Klíčové pojmy kapitoly: proměnná, case-sensitive, datový typ, inicializace, konstanta Nové příkazy: datový_typ název_proměnné ; deklarace proměnné název_proměnné = hodnota; přiřazení hodnoty datový_typ název_proměnné = hodnota_proměnné; deklarace s inicializací const datový_typ název_konstanty = hodnota_konstanty; deklarace konstanty Pojem proměnné a datového typu Proměnnou v programování nazýváme symbolické označení libovolného prvku z určité množiny prvků. Prvky patří do dané množiny tehdy, splňují-li nějaké přesně dané vlastnosti, jsou-li, jinak řečeno, nějakého typu. Proto se těmto množinám říká datové typy. Abych opět uvedl příklad z reálného života. Představte si, že máte několik kuliček různých velikostí. Určili jste si datový typ „Malé kuličky“, což je množina takových kuliček, jejichž průměr je do 1 cm. Krabici ve tvaru krychle o straně 1 cm si nazveme K a řekneme, že je to proměnná datového typu Malé kuličky. Do krabice K (proměnné) je přípustné vložit pouze jednu kuličku z dané množiny (datového typu). Pokud bychom chtěli vložit jinou kuličku z množiny, předchozí umístěná kulička se automaticky z krabice vysype. Kdybychom potřebovali manipulovat s dvěma kuličkami najednou, potřebovali bychom dvě krabice (proměnné) označené např. K a L. Mezi základní datové typy programovacího jazyka C# patří několik typů číselných, znak, řetězce znaků a logická hodnota. Chcete li v programu využívat nějakou proměnnou, musíte ji v programu nejprve vytvořit. A to buď na místě, kde proměnnou potřebujete poprvé, nebo kdekoli v kódu před jejím prvním použitím. Vytvoření nové proměnné v programu se říká deklarace. Kód deklarace má následující syntaxi. Deklarace proměnné datový_typ název_proměnné; Rozbor příkazu Název proměnné by se měl odvíjet od jejího účelu. Datový typ by se měl odvíjet od množiny prvků, které do ní chcete uložit a operací, které s nimi chcete provádět. Název proměnné by se měl odvíjet od jejího účelu. Pokud byste např. vytvářeli program pro základní početní operace mezi dvěma čísly, bylo by vhodné vytvořit tři proměnné s názvy, jako cislo1, cislo2 a vysledek. Možná byste mi mohli oponovat, že i kdybyste proměnné nazvali x, y a z, byli byste se v programu vyznali. Představte si ale, že budete v programu potřebovat proměnných třeba deset. Pojmenovat je každé jedním písmenem, to byste se orientovali o mnoho hůře, a co teprve někdo, kdo by se na Váš kód přišel podívat? Vyznat se v něm by trvalo mnohem delší čas. Za měsíc už byste se v něm nevyznali ani Vy. Krom udělování správného jména si také zvykněte na jeho specifický zápis. Pojmenujete-li proměnnou jedním slovem, začněte malým písmenem. Jestliže bude název víceslovný, skládejte slova za sebe a každé krom prvního začněte velkým písmenem (např. cenaZaKus, konecnyVysledek, apod.). Dodržovat tento styl zápisu není bezpodmínečně nutné pro chod programu, ale ulehčí Vám spoustu chybových hlášek kompilátoru. Jazyk C# je totiž tzv. case-sensitive, to znamená, že od sebe odlišuje velká a malá písmena. Pokud byste např. deklarovali proměnnou s názvem „vysledek“ a pak byste při práci s ní psali její název jako „Vysledek“, považoval by ji kompilátor za novou, doposud nedeklarovanou proměnnou a nahlásil chybu. A ještě jedna připomínka. Budete-li chtít zahrnout do názvu proměnné číslice, nesmí jimi název proměnné začínat. Zde je přehled základních datových typů. V deklaraci se využívá informace z prvního sloupce tabulky. Datový typ sbyte byte short ushort int uint long ulong float double bool char string Název 8-bitová celá čísla se znaménkem 8-bitová celá čísla bez znaménka 16-bitová celá čísla se znaménkem 16-bitová celá čísla bez znaménka 32-bitová celá čísla se znaménkem 32-bitová celá čísla bez znaménka 64-bitová celá čísla se znaménkem 64-bitová celá čísla bez znaménka reálná čísla Velikost 1B = 8b Rozsah -128 .. 127 1B = 8b 0 .. 255 2B = 16b -32 768 .. 32 767 2B = 16b 0 .. 65 535 4B = 32b -2 147 438 648 .. 2 147 438 647 4B = 32b 0 .. 4 294 967 295 8B = 64b -9 223 372 036 854 775 808 .. .. 9 223 372 036 854 775 807 8B = 64b 0 .. 18 446 744 073 709 551 615 4B = 32b reálná čísla s větší přesností logická proměnná znak řetězec (znaků) 8B = 64b 1.5*10 -45 .. 3.4*10 38 (7-8 platných cifer) 5.0*10 -324 .. 1.7*10 308 (15-16 platných cifer) 1B = 8b 2B = 16b 2B * počet znaků true nebo false 1 znak z ASCII tabulky n znaků Tab. 2 ‐ Tabulka základních datových typů C# Výběr správného datového typu je velmi důležitý. A nejedná se jen o to, zda se bude jednat o proměnnou číselného, či alfanumerického charakteru. Musíme dbát i na rozsah dané proměnné a operace, které s nimi budete chtít provádět. Představte si, že potřebujete proměnnou, do které se bude ukládat číslo kalendářního měsíce. Povolené položky jsou tedy celá čísla v rozsahu 1 až 12. Podíváte-li se na rozsah všech číselných datových typů uvedených v tabulce, zjistíte, že můžete použít prakticky jakýkoli. My však vyloučíme použití reálných čísel (měsíc 1,4 neexistuje) a čísla o zbytečně velkých rozsazích. Nakonec vybíráme mezi datovými sbyte a byte. Zvolíme raději byte, protože záporná čísla využívat nechceme. Proč jsme ale takovouto vylučovací metodou vybírali vhodný datový typ, když jsme si řekli, že čísla v požadovaném rozsahu můžeme uložit do jakékoli číselné proměnné? Podívejte se do třetího sloupce tabulky. Ta udává, kolik paměti bude daná proměnná zabírat. Někdo by mohl namítat, že máme dnes v počítačích operační paměti o takových kapacitách, že rozdíl mezi 1B a 4B nic neznamená. Tento přístup ale není hoden dobrého programátora, který by měl krom správného fungování programu zajistit i jeho co možná nejmenší paměťovou náročnost. Přiřazení hodnoty do proměnné Máme-li někde v programu vytvořenou proměnnou, třeba následovně: int cislo; můžeme kdekoli dále v programu přiřadit této proměnné konkrétní hodnotu z rozsahu daného datovým typem. Syntaxe je následující: Přiřazení hodnoty do proměnné název_proměnné = hodnota; Rozbor příkazu V případě, že bych chtěl do naší proměnné cislo vložit hodnotu 50, udělal bych to příkazem: cislo = 50; Pokud bych kdekoli dále v programu přiřadil proměnné cislo jinou hodnotu, automaticky nahradila starou hodnotu 50. Počáteční inicializace proměnné Někdy je potřeba vložit hodnotu do proměnné okamžitě po jejím vytvoření. Takovémuto druhu přiřazení se říká inicializace. Pokud byste měli v úmyslu vytvořit např. proměnnou mesic datového typu byte a okamžitě mu přiřadit hodnotu 1, máte dvě možnosti, jak to udělat. První již napsat umíte: byte mesic; mesic = 1; Druhým způsobem zápisu, který doporučuji používat, má obecný tvar: Deklarace proměnné a její inicializace datový_typ název_proměnné = hodnota_proměnné; Rozbor příkazu Příklad: byte mesic = 1; Inicializace je důležitá z toho hlediska, že při vytvoření proměnné prakticky nevíme, co je v ní uloženo. Někdo by si mohl myslet, že tam je nula a s tímto chybným předpokladem počítat při programování. Inicializace proměnné má ovšem větší význam, než jen ušetření jednoho řádku kódu. Předpokládám, že jste si ještě kvůli čerstvosti informací o datových typech nepoložili otázku: „Co se nachází v proměnné bezprostředně po její deklaraci?“ Je odpověď 0? Či nějaké jiné číslo? Nebo dokonce písmeno? Proměnné se vytvářejí v buňkách operační paměti. Tyto buňky, předtím, než jsme si je zablokovali naším programem, využíval jiný proces a zanechal v nich hodnoty. Pokud vytvoříme proměnnou s odkazem na danou datovou buňku, přebírá si proměnná hodnotu oné paměťové buňky. Proto je v některých případech přímo nezbytné, ihned po deklaraci vložit do proměnné počáteční hodnotu, a nenechat ji „náhodě“. Typickým příkladem budiž funkce čítače. Pokud byste chtěli počítat, kolikrát bylo za určitou dobu stisknuto tlačítko, vytvořili byste si nejprve proměnnou, pojmenovanou řekněme citac. V programu byste vytvořili příkaz, který na každý stisk tlačítka zvedne hodnotu proměnné citac o jedničku. Zde je naprosto jasné, že pokud bychom proměnnou citac na začátku neinicializovali na hodnotu 0, mohly by se stisky připočítávat k úplně jiné hodnotě a výsledkem by bylo špatné číslo. Navíc, při testování se tato chyba vůbec nemusí projevit, protože v mnoha případech může být hodnota paměťové buňky, na které vytvářím novou proměnnou, nulová. Konstanta Speciálním případem proměnné, která se inicializuje hned při její deklaraci, a poté se již její hodnota nemění, je konstanta. Deklarace konstanty vypadá následovně: Deklarace konstanty const datový_typ název_konstanty = hodnota_konstanty; Rozbor příkazu Příklad: const int vyhra = 1000000; S konstantou se v příkladu pracuje stejným způsobem, jako s proměnnou, akorát jí nelze přiřadit žádná nová hodnota. Shrnutí kapitoly: Naučili jste se vytvářet proměnné a naplňovat je hodnotami. Řekli jsme si, co je inicializace proměnné, a že je často nezbytné nastavení na počáteční hodnotu provést. Nakonec jste se mohli dočíst o konstantách a jejich deklaraci. Tato kapitola byla sice více teoretická, ale o to víc si zaprogramujeme v kapitolách příštích. Než začneme vytvářet komplexnější programy, ve kterých se budou vyskytovat proměnné, anebo konstanty, budeme se ještě muset naučit, jak je zobrazit na displeji NXT terminálu. Kapitola 7. Psaní na displej NXT terminálu Co se naučíte: Práci s proměnnými lze nejlépe ukázat s pomocí displeje NXT terminálu. Na tomto displeji lze psát texty (bohužel jen bez diakritiky, už program Robotc diakritiku při psaní kódu nepovoluje) nebo nebo vypisovat hodnoty proměnných. Na displeji lze mimo jiné vykreslovat základní geometrické objekty. V rámci základní sbírky se však tomuto tématu vyhneme. Nové příkazy: nxtDisplayTextLine(číslo_řádku, "text"); vypsání textu nxtDisplayTextLine(číslo_řádku, název_proměnné); výpis textové proměnné nxtDisplayBigTextLine(číslo_řádku, „text“); výpis větším písmem nxtDisplayCenteredTextLine(číslo_řádku, „text“); nxtDisplayCenteredBigTextLine(číslo_řádku, „text“); výpisy na střed řádku nxtDisplayTextLine(číslo_řádku,“řetězec_s_formátem_čísla“,název_proměnné); výpis proměnné v řetězci eraseDisplay(); vymazání obsahu displeje Psaní textů Text se na displej terminálu vypisuje po řádcích. Řádků má terminál celkem 8, avšak jsou číslovány od nuly. První řádek má tedy číslo 0, druhý řádek číslo 1, atd. Poslední řádek je osmý a má označení 7. Na to si možná budete chvíli zvykat, ale věřím, že to zvládnete. Na každý řádek se vejde jen omezený počet znaků. Jestliže dáte vložit text delší, než se na daný řádek vejde, nedojde k jeho zalomení (podobně jako když píšete v textovém editoru), ale nevypíše se celý. Proto se displej nepoužívá k zobrazení nějakých souvislých textů, ale jednoduchých informací, jako výsledek matematické operace, aktuální stav programu, výkon motorů, apod. Vypsání textové informace nxtDisplayTextLine(číslo_řádku, "text"); Rozbor příkazu V příkazu píšete na první pozici závorky číslo řádku, na který se má psát, a za čárku pak vepisovaný text V UVOZOVKÁCH. Pokud budete chtít např. na první řádek displeje vypsat „Ahoj!“, příkaz bude vypadat následovně: nxtDisplayTextLine(0,“Ahoj!“); Příkaz si zkuste napsat jako program. Uložte jej pod názvem „Program 5 – Ahoj“ a otestujte, zda funguje. Že nefunguje? Ale funguje. Akorát dřív, než stačíte zaznamenat změnu na displeji, tak se program ukončí a vrátí do menu terminálu. Proto musíme v tomto jednoduchém programu umístit za příkaz nxtDisplayTextLine příkaz wait1Msec a nastavit časovou prodlevu v milisekundách před skončením programu. Vyzkoušejte, zda to pomohlo: task main() { nxtDisplayTextLine(0,“Ahoj!“); wait1Msec(10000); //nápis „Ahoj!“ bude na displeji 10 sekund } Protože už známe pojem proměnné a její deklarace, zkusíme si program přepsat tak, aby se nevypisoval přímo text „Ahoj!“, ale informace uložená v námi deklarované proměnné napis. Program si uložte pod názvem „Program 6 - Ahoj jako hodnota proměnné“ a otestujte, zda funguje dle očekávání: task main() { string napis; napis = „Ahoj!“; nxtDisplayTextLine(0,napis); wait1Msec(10000); } //deklarace textové proměnné /*nápisy přiřazené proměnným typu string nebo char musí být ohraničeny uvozovkami*/ //zobrazení hodnoty proměnné napis //na displeji uvidíme Ahoj! //„Ahoj!“ bude na displeji 10 sekund Všimněte si, že u předposledního příkazu není slovo napis v uvozovkách. To proto, že nezobrazujeme přímo text, ale hodnotu textové proměnné. Uvozovky jsme u řetězce použili už tehdy, když jsme jej vkládali do proměnné napis. Pokud bychom slovo napis vložili uvnitř zobrazovacího příkazu do uvozovek, zobrazilo by se na displeji slovo „napis“. Jen si to zkuste. Vypsání obsahu textové proměnné nxtDisplayTextLine(číslo_řádku, název_proměnné); Rozbor příkazu V příkazu píšete na první pozici závorky číslo řádku, na který se má psát, a za čárku pak název textové proměnné BEZ UVOZOVEK. Deklarace a vložení textu by se dalo nahradit jediným řádkem (inicializace na počáteční hodnotu): string napis = „Ahoj!“; Velikost písma Standardní velikost písma při použití příkazu nxtDisplayTextLine je 8 pixelů. Příkaz pro vložení písma dvounásobné velikosti vypadá podobně: Vypsání textu dvojnásobné velikosti nxtDisplayBigTextLine(číslo_řádku, „text“); Rozbor příkazu Příkaz je analogický předchozímu, jen v názvu příkazu je zakomponováno slovo „Big“. Uvědomte si, že zvětšením písma snížíte počet znaků, které se vejdou na daný řádek displeje. Obdobné příkazy můžete využít, chcete-li text vypsat na střed zvoleného řádku: Vypisování textu na střed řádku nxtDisplayCenteredTextLine(číslo_řádku, „text“); nxtDisplayCenteredBigTextLine(číslo_řádku, „text“); Rozbor příkazů Příkazy jsou analogické předchozím, jen v názvech příkazů je zakomponováno slovo „Centered“. Do všech příkazů pro výpis textu na displej se zadává číslo řádku. Pokud v kódu dojde podruhé k vložení textu na stejný řádek, dosavadní text na řádku se kompletně přepíše novým. Popis jízdy Otevřete si program „Cvičení 3 – Tam a zpět“ a přeuložte jej pod názvem „Cvičení Cvičení 6 6 – Popis jízdy“. Doplňte kód tak, aby se sekundu před samotnou jízdou zobrazil vlevo na prvním řádku displeje (řádku označeném 0!) malý text „Prubeh jizdy:“. Nápis ponechte vypsaný až do konce programu. Při pojezdu ať je na středu čtvrtého řádku displeje velkým písmem popsán průběh jízdy, a to následovně: při odjezdu nápisem „Odjezd“ při otočce ať nápis „Odjezd“ zmizí (displej tedy zůstane bez popisu průběhu jízdy) při návratu nápisem „Prijezd“ Odpočet Souhrnné Vytvořte program pro startovací odpočet se zobrazením na displeji, po jehož uplynutí robo-vozidlo vystartuje vpřed. cvičení 2 příkaz pro spuštění motorů stavebnice s požadovaným výkonem znalost příkazů pro vypsání textových řetězců znalost práce se zvuky Pomůcky zvukový soubor Start.rso, který naleznete na CD ke sbírce Zadání 1. Připravte zvukový soubor Start.rso pro použití v programu. Teoretická východiska 2. Zobrazte na středu čtvrtého řádku displeje malým písmem odpočet 3, 2, 1. Každé z čísel ať je na displeji 1 sekundu. 3. Za odpočtem zobrazte na středu čtvrtého řádku displeje velkým písmem slovo START a přehrajte zvukový soubor Start.rso. 4. Po doznění zvukového souboru ať robot vyrazí dopředu o 100% výkonu a zastaví se po 5 sekundách jízdy. Zobrazování hodnot číselných proměnných Prozatím jsme se zabývali pouze zobrazováním textových informací na displeji terminálu. Co když ale budeme chtít zobrazit hodnotu číselné proměnné? Příkaz pro výpis čísla se liší od výpisu textu počtem parametrů (informací v závorce). Vypsání proměnné v řetězci nxtDisplayTextLine(číslo_řádku,“řetězec_s_formátem_čísla“,název_proměnné); Rozbor příkazu Příkaz pro výpis čísla se liší od výpisu textu počtem parametrů (informací v závorce). Za formát čísla můžete vkládat následující znaky: Označení formátu čísla Popis formátu čísla %d zobrazujete-li proměnnou typu celé číslo (decimal) %f zobrazujete-li proměnnou typů reálné číslo (float) %e zobrazujete-li proměnnou typu reálné číslo v tzv. E formě (např. 423.78 se zobrazí jako 4.2378e+2) %x.yf Tato syntaxe se používá pro zobrazení proměnné typu reálné číslo, přičemž se vypisuje pouze určitý počet celých a desetinných míst. Za x se dosazuje počet celých míst, za y počet desetinných míst, f se ponechává. (např. při zápisu „%2.4f“ se číslo 12.4551923 zobrazí jako 12.4551) Tab. 3 ‐ Označení formátu čísla v příkazech vypisujících hodnoty číselných proměnných Takto by vypadal příklad zobrazení čísla 10 vlevo nahoře displeje. Zkuste si jej napsat a uložit pod názvem „Program 7 - Zobrazení číselné proměnné“. task main() { byte cislo = 10; //deklarace celočíselné proměnné s počáteční inicializací číslem 10 nxtDisplayTextLine(0,“%d“,cislo); //zobrazení hodnoty proměnné cislo ‐ na displeji uvidíme číslo 10 wait1Msec(5000); //číslo bude na displeji 5 sekund } Ve výše uvedeném příkladu jsme vypisovali pouze hodnotu dané proměnné. Protože ale každé číslo v reálném světě chápeme v určitém kontextu, často je potřeba vypsat kombinaci čísla a textu, který by jej okomentoval. Zde je pár jednoduchých příkladů, abyste věděli, o čem mluvím. V zápisu příkazu se napíše celý požadovaný výraz v uvozovkách, přičemž na místo, kde je potřeba dosadit hodnotu proměnné, se napíše označení formátu čísla příslušného datového typu (viz. Tab. 3). Samotný název proměnné je posledním argumentem v závorce: Hodnota proměnné reálného datového typu Kontext Možnost použití základního příkazu 10 stupňů Celsia stupňů úhlu alfa procent výkonu motoru nxtDisplayTextLine(0,“Venku je %f°C.“, proměnná); 90 100 nxtDisplayTextLine(0,“úhel alfa: %f°“, proměnná); nxtDisplayTextLine(0,“ %fprocentní výkon“, proměnná); Tab. 4 ‐ Zobrazování hodnot číselných proměnných v příslušném kontextu 10 stupňů celsia Vytvořte proměnnou teplota 8-bitového celočíselného typu byte a inicializujte ji Cvičení 7 číslem 10. Na prvním řádku NXT terminálu pak na 10 sekund zobrazte nápis „10 stupnu Celsia“, kde 10 je hodnota proměnné teplota. Při práci s reálnými čísly se v C# používá desetinná TEČKA místo desetinné čárky, na kterou jsme zvyklí. Tzn. že např. místo 3,14 se musíte naučit psát 3.14. V opačném případě kompilátor nahlásí chybu. Pro úplnost uvádím příklad, ve kterém se na displej vypisuje výsledek testu. Vytvořte si jej pod názvem „Program 8 - Skóre testu“ a otestujte funkčnost. task main() { float skore = 6.8; //deklarace reálné proměnné s počáteční inicializací nxtDisplayTextLine(0,"Prumerne skore"); nxtDisplayTextLine(1,"je %1.1f bodu",skore); nxtDisplayTextLine(2,"z 10."); //na obrazovku se vypíše „Prumerne skore je 6.8 bodu z 10.“ wait1Msec(10000); } A abyste si nějaký program zase zkusili vymyslet sami, naprogramujte následující cvičení. Pi Nadeklarujte reálnou proměnnou cisloPi a inicializujte hodnotou Cvičení 8 3,14159265358979323846. Vypište na první řádek displeje výraz „pi = 3,14“. Věřím, že si s tím, jak dlouhé číslo proměnné cisloPi vypsat ve zkrácené formě, rychle poradíte. A kdybyste přece jen měli nějaké problémy, snad pomůže Tab. 3. Výkon motorů Vytvořte program, ve kterém jede robo-vozidlo 5 sekund dozadu výkonem 20%, na 3 sekundy se zastaví, a stejným výkonem dojede dopředu na místo, odkud vyrazilo. Cvičení 9 Po celou dobu běhu programu musí být v horní části displeje nápis „VYKON MOTORU“ a zhruba uprostřed displeje informace o aktuálním výkonu motorů. Výpis více proměnných v jednom řetězci Pokud byste někdy potřebovali vložit text obsahující více vložených proměnných, bude příkaz o něco složitější. Ale nebojte se. Stále budeme vycházet z toho, co už znáte. Celý problém si vysvětlíme na příkladu. Můžete si jej napsat a uložit pod názvem Program 9 – Fotbal. Úkolem programu je výpis fotbalového skóre. Počet vstřelených gólů je uchován ve dvou proměnných (pro každý tým jedna). task main() { byte skoreTymu1 = 2; byte skoreTymu2 = 0; //deklarace dvou celočíselných proměnných s počáteční inicializací nxtDisplayTextLine(0,“%d : %d“,skoreTymu1,skoreTymu2); //na obrazovku se vypíše „2 : 0“ wait1Msec(10000); } Z příkladu je patrné, že v příkazu nxtDisplayTextLine přibylo parametrů. Vypisujemeli pouze jedinou proměnnou, má příkaz právě 3 parametry. S každou další proměnnou jeden parametr přibývá. Prvním parametrem je, jako vždy, číslo řádku, na který se řetězec vypisuje. Druhým parametrem je text řetězce, který obsahuje tolik označení formátů (%d, %f, apod.), kolik je proměnných. Následují čárkami oddělené názvy proměnných, a to v tom pořadí, ve kterém mají být vkládány do řetězce. Zobrazení obsahu textových proměnných v řetězci Pokud má být v řetězci umístěna proměnná typu string, vkládá se do řetězce na její místo zástupné symboly „%s“ (string). Pokud byste např. chtěli ve větě „Úhel gama pravý.“ slovo „gama“ přečíst z proměnné pravyUhel, vypadal by kód následovně: string pravyUhel = „gama“; nxtDisplayTextLine(0,“Uhel %s je pravy.“,pravyUhel); Fotbal Otevřete si Program 9 – Fotbal, přeuložte pod názvem Cvičení 10 – Fotbal a upravte jej dle instrukcí: Cvičení 10 Na druhé řádku vycentrujte velký nápis „SKORE UTKANI“. Informaci o stavu utkání vycentrujte na pátém řádku displeje. Vytvořte dvě vhodně pojmenované proměnné pro zadání názvů fotbalových klubů a vložte do nich názvy: „Real“ a „Barcelona“. Zobrazte je nad skóre tak, jak to ukazuje náhled: SKORE Real:Barcelona Podobně, pokud bychom do řetězce vkládali hodnotu proměnné typu char (znak), použili bychom zástupné symboly „%c“. Další způsoby výpisu textových informací na displej Pro „konzolový“ výpis na displej terminálu existuje ještě jedna sada příkazů. Syntaxe se krom jiného názvu příkazu liší počtem a významem parametrů. První parametr, který jsme používali pro číslo řádku, na který se má vepisovat, je nahrazen dvěma parametry, které zastupují x-ovou a y-ovou souřadnici (v jednotkách pixelů), kde má text začínat: nxtDisplayStringAt(x‐ová_souřadnice,y‐ová_souřadnice, „textový_řetězec“); Tento příkaz existuje i v dalších modifikacích, jako např. pro psaní velkým písmem, či s vypisováním řetězců obsahujících proměnné. Tento způsob vypisování uvádím pouze pro úplnost a nebudu se jím v dalších příkladech dále zabývat. Vymazání obsahu displeje Na závěr kapitoly si jen řekneme o příkazu, který se Vám může někdy hodit, když potřebujete vyčistit displej pro zobrazení dalších informací: Vymazání obsahu displeje eraseDisplay(); Rozbor příkazů Příkaz jednoduše vyčistí obrazovku NXT terminálu ode všech informací, které jsou na ní aktuálně zobrazeny. Shrnutí kapitoly: Jednou z charakteristických vlastností algoritmů je to, že podávají informaci o výsledku své práce. To se většinou děje vypsáním těchto informací na obrazovku. Právě proto je konzolový způsob výpisu informací na displej, popsaný v této kapitole, nepostradatelnou dovedností pro psaní jakýchkoli dalších programů pro Lego Mindstorms. Při vypisování hodnot je také nezbytné uvést, čeho se týkají. Např. samotné číslo o ničem nevypovídá a získává na významu až v uvedeném kontextu. Proto se musí programátor vcítit do pozice uživatele programu, který potřebuje danou informaci nejen přečíst, ale i pochopit. V této kapitole jsme často vypisovali hodnoty číselných proměnných. Proto by bylo dobré se naučit, jak s těmito proměnnými matematicky pracovat. Pokud Vás zajímá, jak se to dělá, nezavírejte sbírku a čtěte dál Kapitola 8. Početní operace s proměnnými a konstantami číselných datových typů Co se naučíte: Protože se programování váže k výpočetní technice, není vůbec nic divného na tom, že výpočty jsou jednou z nejčastějších funkcí programování. Uvidíte ale sami, že to není nic těžkého. Stačí se naučit příkazy pro základní operátory a umět matematiku Klíčové pojmy kapitoly: inkrementace, dekrementace Nové příkazy: výsledek_operace = číslo1 znaménko_operace číslo2; algebraické operace číslo1 početní_operace = číslo2; mat. změna proměnné cislo ++; inkrementace cislo --; dekrementace S čísly, potažmo číselnými proměnnými, v jazyce C# můžeme provádět různé aritmetické operace. Příkaz je jednoduchým přepisem matematického vztahu mezi čísly: Příkazy základních aritmetických operací výsledek_operace = číslo1 znaménko_operace číslo2; Rozbor příkazu Na levé straně se vždy musí nacházet proměnná vhodného datového typu, kterého nabude výsledek operace. Následuje přiřazovací znaménko rovnosti a dvě čísla oddělená znaménkem. Znaménka základních aritmetických operací jsou následující: Znaménko operace Název operace Příklad + sčítání 11 + 5 = 16 - odčítání 11 – 5 = 6 * násobení 11 * 5 = 60 / dělení (jsou-li veškeré proměnné vystupující ve výrazu datového typu reálné číslo) 11 / 5 = 2.2 / celočíselné dělení (jeli aspoň jedna proměnná ve výrazu celočíselného datového typu) 11 / 5 = 2 % zbytek po celočíselném dělení (modulo) 11 % 5 = 1 (11 : 5 se dá napsat jako 2 celé, zbytek 1) Tab. 5 ‐ Tabulka základních aritmetických operací Čísla mohou být vyjádřena přímo zapsanými čísly, jako např. v tomto příkladě sčítání: soucet = 5 + 3; Mnohem častější je však matematická operace mezi dvěma proměnnými: soucet = scitanec1 + scitanec2; Kombinace konkrétního čísla a číselné proměnné je také možná: soucet = scitanec + 1; Na pravé straně výrazu se může vyskytovat i více operací najednou. Pořadí operací při výpočtu je stejné, jako v matematice. Můžete si to vyzkoušet na následujícím cvičení. Pořadí matematických operací Napište program, který vypočítá, jaké výsledky dávají následující příkazy. Cvičení 11 Výsledek vypište na displej. vysledek1 = 3 + 6 * 2; vysledek2 = (3 + 6) * 2; Zjednodušené psaní operací Velmi často se v programování stává, že je potřeba upravit hodnotu číselné proměnné. Např. k ní něco přičíst, odečíst, něčím ji vynásobit, apod. Pokud byste vycházeli ze znalostí, které máte, dospěli byste nejspíš k tomuto zápisu: číslo1 = číslo1 početní_operace číslo2; Pokud byste chtěli např. zvednout proměnnou hodnota o 5, vypadal by příkaz: hodnota = hodnota + 5; Tedy do proměnné hodnota vlož číslo, kterého již nabývá, zvětšené o 5. Podobný případ by nastal při zvedání proměnné hodnota o proměnnou x: hodnota = hodnota + x; V jazyku C# existuje analogický zkrácený zápis těchto příkazů. Jsou shrnuty v následující tabulce. Protože jsou velmi oblíbené, často se v programech vyskytují. I vy byste se je měli naučit: Zkrácené formy příkazů přepočítávajících hodnotu proměnné číslo1 početní_operace = číslo2; Rozbor příkazu Konkrétní příkazy pro různé operace vypadají následovně: Název operace Klasický zápis Zkrácený zápis přičtení čísla x k proměnné cislo cislo = cislo + x; cislo +=x; odečtení čísla x od proměnné cislo cislo = cislo – x; cislo ‐=x; vynásobení proměnné cislo číslem x cislo = cislo * x; cislo *=x; vydělení proměnné cislo číslem x cislo = cislo / x; cislo /=x; Tab. 6 ‐ Zkrácený zápis některých aritmetických operací Porovnání zápisu pro zvětšení proměnné Vytvořte program, ve kterém porovnáte, zda dávají klasický a zkrácený zápis Cvičení 12 navýšení čísla stejné výsledky. Do proměnné cislo vložte číslo 10, v proměnné x vložte číslo 2. Proměnnou cislo navyšte o proměnnou x dvě různými příkazy. Výsledky obou příkazů zobrazte pod sebou na displeji. Zdržme se ještě chvíli u problematiky navyšování či snižování hodnoty proměnné. V programování se velmi často vyskytují případy, kdy se hodnota zvyšuje, anebo snižuje o jedničku. Zvyšování hodnoty se říká inkrementace, jejímu snižování pak dekrementace. Pokud bychom chtěli dejme tomu zvýšit hodnotu proměnné cislo o 1 (inkrementovat proměnnou cislo), mohli bychom místo příkazu: cislo = cislo + 1; či cislo += 1; napsat jednoduše: cislo ++; Obdobný příkaz existuje i pro snížení hodnoty proměnné o 1 (dekrementace proměnné cislo): cislo ‐‐; Inkrementace a dekrementace cislo ++; cislo ‐‐; Rozbor příkazů Inkrementací rozumíme zvýšení čísla o jedničku, dekrementace znamená snížení o jedničku. Odpočet s proměnnou Otevřete si program „Chyba! Nenalezen zdroj odkazů.“ (buď jste si jej vytvořili ami, anebo je dostupný na přiloženém CD) a přeuložte jej pod názvem „Cvičení 13 Cvičení 13 – Odpočet s proměnnou“. Chyba! Chybný odkaz na záložku.Přepište jej tak, aby se čísla 3, 2 a 1, vypisovaná na displej, vkládala z celočíselné proměnné. Tu během programu zmenšujte o jedničku. Shrnutí kapitoly: Znalostí programování matematických operací jsme si značně zvětšili okruh problémů, které můžeme jako programátoři řešit. Je dobré naučit se nejen základní příkazy, ale i zkrácené. Nejenže nám ušetří nějaký ten čas, ale budeme vědět, co znamenají, až je uvidíme v cizím kódu. Kapitola 9. Podmínka Co se naučíte: Sekvence je sice krásná věc, ale žádnému, ani tomu nejvíce podprůměrnému, programátorovi nestačí k tomu, aby tvořil zajímavé programy. Na to je sekvence příliš prostá. V této krátké kapitole si řekneme základní informace k algebraické struktuře podmínka, které naše dosavadní znalosti povznesou na novou úroveň. Nové příkazy: if (podmínka) { sekvence příkazů 1; } else { sekvence příkazů 2; } Podmínka Podmínka se využívá v programech všude tam, kde je potřeba, aby program zvolil jednu ze dvou cest vykonávání programu. Rozhoduje se na základě podmínky, což je proměnná, výraz nebo vlastnost, která musí být logického datového typu, tedy typu bool. Na podmínku vždy existuje odpověď ANO nebo NE (PRAVDA nebo NEPRAVDA, TRUE nebo FALSE). Podmínky se v C# zapisují následujícím způsobem: Podmínka if (podmínka) { sekvence příkazů 1; } else { sekvence příkazů 2; } Rozbor příkazu Pro úplné pochopení uvádím několik příkladů podmínek: Symbolický zápis podmínky Slovní zápis podmínky if (rychlost < 50) Je rychlost (číselná proměnná) menší než 50? if (stopStav == true) Je stopStav (logická proměnná) nastaven na true? if (pocet != 10) Je pocet (čiselná proměnná) jiný než 10? Tab. 7 ‐ Příklady podmínek Z příkladů je patrné, že jakýkoli symbolický zápis podmínky se dá slovně interpretovat jako otázka, na niž existuje jednoznačná odpověď: ANO nebo NE. Pokud je odpověď na otázku ANO, provede se sekvence příkazů 1. Pokud je odpověď NE, provede se sekvence příkazů 2. Jestliže místo sekvence příkazů 1 nebo sekvence příkazů 2 chcete vložit pouze jediný příkaz, nemusíte jej ohraničovat nahoře a dole závorkami. Vnitřní příkazy podmínky je však vhodné vždy odsadit od ostatních příkazů kvůli přehlednosti programu. Ve středu podmínky se nachází operátor (znaménko), na jehož obou stranách se mohou nacházet proměnné, nebo konkrétní hodnoty. Úplný výčet a význam operátorů je v tabulce níže. Je potřeba se jej naučit: Operátor == != < <= > >= Význam je rovno není rovno (je různé od) je menší je menší nebo rovno je větší je větší nebo rovno Tab. 8 ‐ Operátory podmínek Pokud chcete vykonat určité příkazy jen v případě, že podmínka platí a v případě její neplatnosti pouze pokračovat ve vykonávání programu, můžete vypustit „else“ část. Podmínka by v tomto případě vypadala: if (podmínka) { sekvence příkazů 1; } Pojďme se podívat alespoň na malý příklad zápisu konkrétní podmínky. Bude se jednat o příklad, který vypíše, zda je v celočíselné proměnné cislo sudé, nebo liché číslo: if (cislo % 2 == 0) nxtDisplayTextLine(0,“Cislo %d je sude.“,cislo) else nxtDisplayTextLine(0,“Cislo %d je liche.“,cislo) Pozn. Je-li číslo dělitelné dvojkou (tedy je-li zbytek po dělení dvěma roven 0), jedná se o číslo sudé. V opačném případě je číslo liché. Shrnutí kapitoly: Podmínka je velmi důležitou algebraickou strukturou. Její uplatnění však najdeme pouze tam, kde se rozhodujeme na základě vlastnosti, či hodnoty, kterou předem jako programátoři neznáme. Protože ale zatím veškeré hodnoty zadáváme zevnitř programu, neuvedl jsem v této kapitole žádný příklad. Použití podmínky by bylo neprůkazné. V dalších kapitolách se proto budete seznamovat s jinými možnostmi zadání hodnot (ať už pomocí dotykových senzorů, či generátoru náhodných čísel), kde již bude použití podmínky nezbytné. Naučíte se také, jak zapsat vícenásobnou podmínku. Kapitola 10.Dotykový senzor Co se naučíte: Abyste úplně docenili možnost psaní podmínek, je potřeba se naučit možnosti, jak do robota dostat informace zvenčí (od uživatele). K tomu si vezmeme na pomoc dotykové senzory. Ty se standardně zapojují do konektorů 1 a 2 NXT terminálu a mohou plnit nejrůznější funkce. Dají se připevnit do čela robota, aby se tak stiskem detekoval náraz do čelní stěny, anebo si je můžete vzít do ruky a používat je pro ruční zadávání signálů. V příkladech pro detekci, zda došlo ke stisku dotykového senzoru, budete potřebovat nekonečný cyklus, který bude stále dokola testovat, zda nedošlo ke stisku. V poslední části této na nové informace i cvičení bohaté kapitoly se naučíte, k čemu a jak používat vícenásobné a disjunktní podmínky. Klíčové pojmy kapitoly: Touch sensor, nekonečný cyklus, vícenásobná podmínka, disjunktní podmínky Nové příkazy: SensorValue(jménoSenzoru) zjištění stavu dotykového senzoru for(;;) nekonečný cyklus break; vyskočení z právě probíhajícího cyklu Ať už budete používat jakýkoli senzor, musíte tuto skutečnost zanést do programu pomocí jednoho specifického příkazu. V něm zároveň určíte, pod jakým jménem bude senzor v programu vystupovat. Obrovskou výhodou je, že si tento příkaz nemusíte pamatovat, ale že jej za Vás napíše program Robotc. Stačí jen vědět, jak na to: V menu Robot vyberte položku Motors and Sensors Setup (Obr. 20). V nově otevřeném okně (Obr. 21) přejděte na záložku Sensors. Nacházejí se na ní 4 řádky začínající zkratkami S1 až S4. Ty symbolizují vstupy 1 až 4 NXT terminálu. Pokud budete chtít využívat jeden dotykový sensor zapojený do vstupu 1, napíšete do editačního pole vedle S1 název zařízení, např. ovladac a v seznamu vedle jména vyberete „touch“. Pozn. Pokud byste chtěl používat ultra-sonic senzor, najdete jej v seznamu pod jako SONAR. Barevný senzor pak reprezentuje položka LEGO Color. Podobným způsobem můžete přidat do řádku S2 druhý dotykový senzor, případně další senzory do řádků S3 a S4. Zadávání ukončíte tlačítkem OK. Pokud jste přidali pouze jeden dotykový senzor výše popsaným způsobem, doplní se automaticky do Vašeho programu následující řádek kódu: #pragma config(Sensor, S1, ovladac, sensorTouch) Počet řádků závisí na počtu Vámi přidaných senzorů. Tento automaticky vložený kód neslouží pouze programu, aby věděl, pod jakými označeními a v jakých portech hledat příslušné senzory. Je to také informace pro člověka s daným programem pracujícího, aby jasně věděl, jak správně zapojit senzory do terminálu, aby robot správně vykonával naprogramovanou činnost. Obr. 20 ‐ Cesta k nastavení senzorů Obr. 21 ‐ Okno Motors and Sensors Setup Dotaz na stisk dotykového senzoru Zásadní vlastností dotykového senzoru je, zda je stisknut nebo ne. Tato hodnota je logického datového typu a lze ji přečíst pomocí funkce SensorValue. Protože se dá na otázku o stisku odpovědět jen ano nebo ne, prakticky vždy se programuje pomocí podmínky. Dotaz na stisk dotykového senzoru if(SensorValue(jménoSenzoru) == 1) { sekvence příkazů 1; } else { sekvence příkazů 2; } Rozbor příkazu Ve výše uvedené podmínce se ptáme, zda je senzor o daném jménu stisknut. V případě, že ano, provede se sekvence příkazů 1. V opačném případě je provedena druhá sekvence příkazů. Nekonečný cyklus Ač se o cyklech podrobně dozvíte až ve druhé sbírce, naučíme se jeden velmi jednoduchý cyklus už nyní. Je to z toho důvodu, že při práci s dotykovým senzorem je nutné stále dokola testovat, zda nedošlo k jeho stisknutí. A dělat něco stále dokola znamená pracovat v cyklu. Jednoduchý cyklus, o kterém si teď řekneme, je pro algoritmizaci velmi specifický. Nekonečné cykly bývají většinou známkou špatného naprogramování, v našem specifickém použití budou ale nezbytné. Nekonečný cyklus for(;;) { příkazy cyklu; } Rozbor příkazu Největším nebezpečím nekonečných cyklů je to, že zacyklený program neskončí. Problém je částečně vyřešen tím, že se NXT terminál po určité delší době, během níž s ní uživatel nepracuje, sám vypne, a program se tak přeruší. Samozřejmě nám také nic nebrání v případě potřeby běžící program vypnout ručně (pomocí šedého tlačítka terminálu). Ukončení cyklu není problém ani jednoduše naprogramovat. Cyklus se většinou opouští po splnění nějaké podmínky. Stačí tuto podmínku dovnitř cyklu napsat, a v případě jejího splnění použít příkaz vyskočení z cyklu: Vyskočení z cyklu break; Rozbor příkazu Po vyskočení z cyklu bude program pokračovat příkazy za cyklem. Jestliže za ním již žádné příkazy nejsou, program se ukončí. V praxi použití nekonečného cyklu vypadá tak, že část programu, anebo celý program (který má v reálném čase reagovat na změny vstupních senzorů), je umístěn uvnitř něj. Před ním se většinou nachází základní deklarace, či inicializace proměnných, nebo např. nápisy na displej, které na něm mají zůstat po celou délku běhu programu. Za složenou závorku nekonečného cyklu má smysl vkládat další příkazy jen tehdy, je-li jeden z příkazů cyklu vyskočení z cyklu. Nekonečný cyklus totiž znamená, že až se dostane program ve zpracování na jeho konec, vždy se přesune na jeho začátek, a to stále dokola. Pokud by tedy uvnitř něj nebyl příkaz break, jakýkoli příkaz za tímto cyklem by se nikdy neprovedl. Vytvořte „Program 10 – Pojezd se stisknutým ovladačem“, který bude využívat jednoho dotykového senzoru připojeného do portu S1 terminálu. Dotykový senzor bude uživatel držet ve své ruce. Při stisknutém senzoru bude vozidlo v pohybu směrem vpřed o výkonu 50%. Při nestisknutém senzoru bude vozidlo stát. #pragma config(Sensor, S1, pojezd, sensorTouch) /*Kód vygenerovaný programem Robotc pomocí konfiguračního průvodce přidání senzorů. V tomto případě jsme přidali dotykový senzor do portu S1. V programu je na něj odkazováno slovem „pojezd“.*/ task main() //začátek programu { for(;;) //začátek nekonečného cyklu { if(SensorValue(pojezd)==1) //Je dotykový senzor pojezd aktivní? { motor(motorB)=50; //pokud ano, nastav výkon motorů na 50 motor(motorC)=50; } else { motor(motorB)=0; //pokud ne, nastav výkon motorů na 0 motor(motorC)=0; } } //konec cyklu vrací program na jeho začátek. } //K tomuto řádku (ukončení programu) program nikdy nedospěje. Nekonečným cyklem for(;;) se stále dokola testuje, zda je dotykový senzor stisknutý. Pokud je, nastaví se výkon motorů na 50% a robot se rozjede. Při zjištění nestisknutého senzoru jsou motory vynulovány a zastaví se. Délka času, po který motory jedou, tedy už není dána příkazem wait1Msec, ale je vytvářena reálným časem, po který se zpracovávají příkazy nekonečného cyklu během držení stisknutého senzoru. Zapnutí a vypnutí pojezdu dvěma ovladači Vytvořte program pro ovládání pojezdu robota pomocí dotykových senzorů. Stiskem prvního senzoru se robot rozjede dopředu výkonem uvedeným v konstantě Cvičení 14 rychlost. Stiskem tlačítka druhého senzoru se vozidlo zastaví. Pozn. Pro případ, že byste si s programem nevěděli rady, je v zadní části sbírky podrobně okomentovaný kód. Bylo by ale škoda to nejprve nezkusit sami. Má velmi malé množství řádků. Tak směle do toho Časová prodleva pro opětovné testování V některých programech bude užitečné, ba přímo žádoucí, abychom po nějaké sérii příkazů nastavili časovou prodlevu pomocí příkazu wait1Msec, byť jsou příkazy součástí nekonečného cyklu. Budeme to muset udělat v případech, kdy program nebude reagovat na to, zda je dotykový senzor držený, ale zda došlo ke stisku (tedy stisknutí a okamžitému puštění). Na tento úkon je totiž člověk mnohem více navyklý. Když se chcete dívat na televizi, taky jen jednou zmáčknete tlačítko a nedržíte ho po celou dobu, co se díváte. Problém si zkusíme ukázat na příkladu. Naším cílem je zvedat hodnotu proměnné stiskem senzoru o jedničku. Až se dostaneme k číslu 10, začne se počítat znovu od nuly. Jak zajistit, aby se při dosažení čísla 10 začínalo znova od nuly? Stačí se při každé změně proměnné podmínkou zeptat, zda již nepřekročila hodnotu 10. V případě kladné odpovědi proměnnou nebudeme neinkrementovat, ale přímo jí přiřadíme hodnotu 0, která už se bude opět zvyšovat o jedničku. Vše je vidět v následujícím kódu. Ten si opište a uložte pod názvem „Program 12 - Inkrementace čísla“. #pragma config(Sensor, S1, inkrementace, sensorTouch) task main(); { sbyte cislo = ‐1; nxtDisplayCenteredBigTextLine(3,"%d",cislo); for(;;) { if(SensorValue(inkrementace)==1) { if(cislo = 10) cislo = 0; else cislo++; nxtDisplayCenteredBigTextLine(3,"%d",cislo); } } } Než si otestujeme funkci programu, chtěl bych Vás upozornit na vnořenou funkci if. Splnění první podmínky (detekce stisknutého senzoru) je podmínkou pro to, aby se program zabýval podmínkou druhou (dotazem, zda je hodnota proměnné cislo rovna 10). Else část, jak jistě vidíte z ohraničení příkazů složenými závorkami, patří vnitřní (neboli vnořené) podmínce. Pokud není splněná podmínka první, logicky se program nedostane k podmínce druhé. A takovýchto vnořených podmínek může být, kolik potřebujete. Tento způsob programování je v některých příkladech prakticky nezbytný (i když v našem případě by existovala i jiná možnost). Podmínka if má totiž pouze dvě cesty, kudy se vydat (možnost ANO, možnost NE). Tím, že do jedné z cest vložíme další podmínku, ze které vedou opět dvě cesty, rozšíříme počet možných řešení vstupní podmínky o jednu. Takto můžeme vkládat vnitřní podmínky dál a dál. Některé situace, které mohou nastat různým skládáním vnějších a vnitřních podmínek, ukazuje ve formě tzv. vývojových diagramů Chyba! Nenalezen zdroj odkazů., Obr. 23 a Obr. 24. Předchozí příkazy programu + + podm.2 podm.1 ‐ ‐ Příkazy při splněné 1. a 2. podmínce Příkazy při splněné 1. podmínce a nesplněné 2. podmínce Příkazy při nesplněné 1. podmínce Následující příkazy programu Obr. 22 ‐ Vnořená podmínka v kladné větvi vnější podmínky Až 3 různé varianty Předchozí příkazy programu + + + podm.1 ‐ podm.2 ‐ podm.3 ‐ Příkazy při splněné 1., 2. a 3. podmínce Příkazy při splněné 1. a 2. podmínce, ale nesplněné 3. podmínce Příkazy při splněné 1. podmínce, ale nesplněné 2. podmínce Příkazy při nesplněné 1. podmínce Až 4 různé varianty Následující příkazy programu Obr. 23 ‐ Vnější podmínka má po jedné vnitřní podmínce v kladné i záporné větvi Předchozí příkazy programu + + podm.2 Příkazy při splněné 1. a 2. podmínce podm.1 ‐ + ‐ Příkazy při splněné 1. podmínce a nesplněné 2. podmínce Příkazy při nesplněné 1. a splněné 3. podmínce podm.3 ‐ Příkazy při nesplněné 1. a 3. podmínce Až 4 různé varianty Následující příkazy programu Obr. 24 ‐ Dvakrát vnořená podmínka A jdeme testovat. Při testování jste určitě zjistili problém, který spočívá v tom, že ač zvedáme proměnnou jen o jedničku, ve skutečnosti se mění velmi záhadným způsobem. Je to proto, že příkazy programu se provádějí velmi rychle. Dokonce tak rychle, že jen při letmém stisku dotykového senzoru se stačí cyklus mnohokrát zopakovat. Důsledkem je to, že pokud se cyklus stačí během mého krátkého stisku zopakovat třeba 80x, dojde celkem 80x k detekci stisku, a program se tak chová, jako bych senzor stisknul 80krát. Je to něco podobného, jako když píšete na klávesnici a necháte prst na klávese příliš dlouho. Taky se pak program chová, jako by byla klávesa stisknuta vícekrát, ačkoli byla stisknuta pouze jednou. Zde je vše akorát mnohem rychlejší. Východisko z tohoto problému je jednoduché. Stačí za každou detekcí stisku (resp. změnou proměnné) vložit krátkou časovou prodlevu, abyste měli čas na uvolnění tlačítka a nedošlo tak k další nechtěné detekci. Jak dlouhá by ale měla časová prodleva být? Při testování programu jsem došel k závěru, že vhodný časový interval pro testování aktivity senzoru je cca 0,2 sekundy. Pokud bychom nastavili interval kratší, pravděpodobně bychom během něj při klasickém stisku nestačili palec sundat dřív, než by došlo k další (nechtěné) detekci stisku. Pokud byste naopak nastavili prodlevu příliš velkou, např. 1 sekundu, mohlo by se stát, že uživatel provede stisk, zatímco běží příkaz wait1Msec(1000). Tím pádem se stisk nedetekuje (detekci má na starost podmínka if(SensorValue(inkrementace)==1)). Doplňte příklad tak, že za příkaz vypsání na displej vložte časovou prodlevu 0,2s: wait1Msec(200); Nastavení časové prodlevy před detekcí dalšího stisku záleží z velké části na individuálním rozhodnutí. Prodlevu si můžete testováním programu upravit dle svých požadavků. Složitější situace nastávají, má-li se během časové prodlevy prováděla nějaká činnost, např. běh motorů. Můžete si to ověřit v následujícím cvičení a nastavit délku časové prodlevy podle potřeby. Zvyšování a snižování rychlosti Vytvořte program pro ovládání pohybu vozidla. Při každém stisku senzoru Cvičení 15 „zvyseni_vykonu“ se zvýší výkon pojezdu o 10%. Při stisku senzoru „snizeni_vykonu“ se výkon o 10% sníží. Při snižování výkonu se může vozidlo dostat do záporných hodnot výkonu, a jet tak pozpátku. Aktuální výkon motoru ať je vyobrazen na displeji terminálu. Pozn.1 Pokud budete stiskem zrychlování tolikrát zvyšovat proměnnou rychlost, až se dostanete k číslu 150, budete moci pozorovat, že od čísla 100 se již rychlost nezvyšuje. Motory mohou jet max. na 100% a tak ač jim přidělujeme sebevětší hodnoty, stroj již na ně nereaguje. V tom by ještě takový problém nebyl. Horší je to, že při stisku ovladače pro zpomalování také nedojde ke změně. Proměnná rychlost se snižuje ze 150 poprvé na 140, podruhé na 130, potřetí na 120, ale to jsou hodnoty, při kterých motory jedou stále na 100% výkonu. Můžeme tedy snižovat rychlost, jak chceme, ale pokud se nedostaneme k hodnotě 100, pojede robot stále nejvyšší možnou rychlostí. Podobná situace nastává kolem rychlosti -100. Je třeba proto zabránit tomu, aby se do proměnné vykon zapsala hodnota větší než 100 a menší než -100. K tomu nám pomohou vnořené podmínky. Pozn.2 V tomto příkladě opět musíme přidat časovou prodlevu. I kdybyste dotykový senzor stiskli seberychleji, stihne se nekonečný cyklus, jež má na starost detekci stisku, zopakovat více, než jednou. To by znamenalo zvýšení výkonu o mnoho více, než 10%. Vyzkoušejte více různých časových rezerv, abyste našli tu ideální. Zahýbání Souhrnné cvičení 3 Teoretická východiska Pomůcky Zadání Vytvořte program, ve kterém jede robo-vozidlo stále dopředu. Držením levého nebo pravého dotykového senzoru zahýbá doleva, resp. doprava a vyhýbá se tak překážkám. znalost práce s dotykovým senzorem znalost práce s podmínkou znalost práce s nekonečným cyklem znalost práce s přehráváním zvukových souborů robot Lego Mindstorms v sestavení vozidlo s dotykovými senzory připojenými k terminálovým portům 1 a 2 různé překážky (krabice, plechovky, …), může posloužit i mapa města z prvního souhrnného cvičení 1. Vytvořte program, který reaguje na držení dotykových senzorů: a. Není-li stisknut žádný dotykový senzor, ať jede robot dopředu konstantním výkonem 50%. b. Při držení senzoru v portu 1, ať zahýbá doprava. c. Při držení senzoru v portu 2, ať zahýbá doleva. 2. Ať se po celou dobu zahýbání přehrává zvuk "MS_sfx_burp.rso", který najdete na přiloženém CD ve složce NXT zvuky Internet. Jízda s nastavením rychlosti předem Souhrnné cvičení 4 Vytvořte program pro robota ve složení vozidlo tak, aby byl ovladatelný dvěma dotykovými senzory. První senzor ať slouží k nastavení rychlosti, druhý ať aktivuje jízdu vpřed. znalost práce s dotykovým senzorem znalost práce s podmínkou znalost práce s nekonečným cyklem znalost práce se zobrazováním textu na displeji Pomůcky robot Lego Mindstorms v sestavení vozidlo (stačí základní, ale může být jakékoli jiné) Zadání 1. Vytvořte program pro ovládání pojezdu robo-vozidla vpřed pomocí dvou dotykových senzorů. Teoretická východiska 2. Prvním senzor – nastaveniRychlosti - slouží k nastavení rychlosti, jakou robot pojede. Každým stiskem senzoru se výkon motorů zvýší o 10. Až dosáhne rychlost čísla 100 (a nebude ji tudíž možné dále zvyšovat), změní se stiskem senzoru na nulu. První senzor však slouží pouze k nastavení rychlosti, ne jízdě samotné. 3. Senzorem nastaveniRychlosti ať je aktuálně nastavená rychlost přehledně zobrazena na displeji. 4. Stisk druhého senzoru - Start - způsobí rozjezd robota výkonem nastaveným pomocí senzoru nastaveniRychlosti. 5. Robota ať zastaví nové zadávání rychlosti, tedy stisk senzoru nastaveniRychlosti. Vícenásobná podmínka Pokud je v programu podmíněno vykonání nějakého příkazu, nebo série příkazů, splněním více dílčích podmínek, máme 2 možnosti, jak k této situaci přistoupit. První možnost, kterou již známe, je vnořená podmínka. Pokud budeme např. vyžadovat splnění dvou dílčích podmínek, jednu dáme do vnější podmínky a druhou do vnitřní. Samotný příkaz pak vložíme do vnitřní podmínky. V případě, že má být dílčích podmínek víc, vnoříme o to víc příkazů if do sebe. if(podmínka1) if(podmínka2) { sekvence příkazů; } Zahýbání a jízda vpřed 1 Vytvořte program na ovládání robo‐vozidla dvěma dotykovými senzory. Při stisku jednoho senzoru ať se robot otáčí na místě doleva, resp. doprava, podle toho, zda byl stisknut levý Cvičení 16 nebo pravý senzor. Při stisku obou senzorů ať robot jede vpřed. V programu použijte několika vnořených příkazů if s jednou podmínkou. Druhým, a příjemnějším, řešením je spojení dílčích podmínek v jednom příkazu if: Vícenásobná podmínka if(podmínka1 && podmínka2 && … && podmínkaN) { sekvence příkazů; } Rozbor příkazu Propojení dílčích podmínek, které mají platit zároveň, se provádí pomocí spojky &&, která se vkládá mezi každé dvě dílčí podmínky. Dílčích podmínek v jednom příkazu if může být samozřejmě více. Vícenásobnou podmínku si teď zkusíme naprogramovat. Vytvoříme program, ve kterém se bude zapínat a vypínat pojezd robota jediným dotykovým senzorem. Můžete si jej zkusit napsat a uložit pod názvem „Program 13 - Zapnutí a vypnutí pojezdu jedním ovladačem.c“. Pod kódem naleznete rozbor příkladu, který si určitě si jej prostudujte. #pragma config(Sensor, S1, stopStart, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { bool jizda = false; for(;;) { if(SensorValue(stopStart)==1 && jizda==false) { motor(motorB)=50; motor(motorC)=50; jizda=true; } else if(SensorValue(stopStart)==1 && jizda==true) { motor(motorB)=0; motor(motorC)=0; jizda=false; } wait1Msec(200); } } Abych umožnil 2 možné reakce programu (rozjetí a zastavení) na jedinou reakci zvenčí (stisk dotykového senzoru), vytvořil jsem si logickou proměnnou jizda, podle které budu při stisku tlačítka rozhodovat o dalším osudu robota. Této proměnné přiřazuji hodnoty true (robot je v pohybu) nebo false (robot stojí). Pokud je stisknut senzor a zároveň robot stojí, jeho reakcí je rozjetí a nastavení proměnné jizda na true. Pokud je proměnná jizda nastavena na true (příznak toho, že robot je v pohybu), je se stiskem senzoru robot zastaven a proměnná jizda nastavena na false. Zahýbání a jízda vpřed 2 Naprogramujte stejný problém, jako u cvičení 16, jen s tím rozdílem, že použijete vícenásobné podmínky v jednom příkazu if. Cvičení 17 Disjunktní podmínky Nyní si představte situaci, kdy příkaz if obsahuje více dílčích podmínek, ale k tomu, aby byla podmínka vyhodnocena jako true postačuje, aby byla splněna aspoň jedna z nich. Na to v programování také jistě mnohokrát narazíte. Programuje se podobným způsobem, jako vícenásobná podmínka, jen se změní znaménko mezi dílčími podmínkami na ||: Disjunktní podmínky if(podmínka1 || podmínka2 || … || podmínkaN) { sekvence příkazů; } Rozbor příkazu Propojení dílčích disjunktních podmínek se provádí pomocí spojky ||, která se vkládá mezi každé dvě dílčí podmínky. Dílčích podmínek v jednom příkazu if může být samozřejmě více. Programátor někdy musí šáhnout po proměnné, která bude obsahovat aktuální stav programu. Pokuste se výhody takových proměnných pochopit na následujícím příkladu: Dotykový senzor, který je připojený k portu 1, připevněte na přední část robo-vozidla tak, aby se stisknul případným nárazem do překážky. Budeme mu říkat stop senzor. Druhý dotykový senzor, připojený k portu 2, budete držet v ruce. Tento senzor pojmenujeme stopStart. Vytvořte program, který rozjede vozidlo vpřed stiskem ručního senzoru, a zastaví jej stiskem jednoho ze dvou senzorů. Tzn., že se robot zastaví stiskem stejného ovladače, jakým se rozjíždí, anebo nárazem do zdi. Před samotným programováním je potřeba uvážit, za jakých okolností se robot začne pohybovat, a kdy se naopak zastaví. Rozjezd je možný na stisk stopStart senzoru za předpokladu, že auto stojí na místě a má uvolněný stop senzor. Je-li robot v pohybu, zastaví se při stisku jak stopStart, tak stop senzoru. Jak ale zjistím, zda je robot v pohybu, či nikoliv? Odpověď najdete v následujícím kódu. Obsahuje, mimo jiné, logickou proměnnou jizda, která je buď false, pokud robot stojí, nebo true, pokud jede. Tato proměnná je využívána při dotazech podmínky if. Nesmíme ji ovšem zapomenout přenastavit při změně stavu robota. Kód si uložte pod názvem „Program 14 – Start a stop“. #pragma config(Sensor, S1, stopStart, sensorTouch) #pragma config(Sensor, S2, stop, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { bool jizda = false; //na zacatku robot stoji, promennou jizda //tedy nastavim na false for(;;) { if(SensorValue(stopStart)==1 && SensorValue(stop)==0 && jizda==false) { motor(motorB)=50; motor(motorC)=50; jizda=true; wait1Msec(500); } if(SensorValue(stopStart)==1 || SensorValue(stop)==1) if(jizda==true) { motor(motorB)=0; motor(motorC)=0; jizda=false; wait1Msec(500); } } } Zastavení po uplynutí určité doby nebo nárazem do zdi Souhrnné cvičení 5 Teoretická východiska Pomůcky Zadání Vytvořte program pro robota ve složení vozidlo s dotykovým senzorem připevněným vepředu. Ať se robot rozjede na stisk senzoru a zastaví se buď po 5 sekundách, nebo dříve nárazem do zdi. znalost práce s dotykovým senzorem znalost práce s disjunktní podmínkou znalost práce s nekonečným cyklem robot Lego Mindstorms v sestavení vozidlo s dotykovým senzorem připevněným ve přední části tak, aby došlo k jeho stisku při kolmém najetí na zeď 1. Robot bude v klidovém stavu čekat, až dojde ke stisku dotykového senzoru rukou uživatele. Po stisku se robot rozjede dopředu výkonem 50%. 2. Doba jízdy ať je 5 vteřin. Po uplynutí tohoto časového intervalu se robot zastaví a přehraje zvuk „soundUpwardTones“. 3. Pokud dojde před ukončením časového limitu 5 vteřin ke stisknutí senzoru nárazem do zdi, předčasně se vypnou motory a přehraje se stejný zvuk, jako v bodu 2. Shrnutí kapitoly: Chceme-li v našich programech využívat reakci na stisk dotykového senzoru, musíme vědět, jak tento stisk detekovat. Testování stisku musí probíhat přiměřeně často, aby se detekoval i při kratičkém stisku, ale aby se při delším podržení nedetekoval vícekrát, než jednou. Detekce stisku probíhá formou nekonečného cyklu, který obsahuje časovou prodlevu odpovídající intervalu testování následovanou samotným testování pomocí podmínky. Mezi jinými příkazy může být v cyklech přítomen i příkaz break, který způsobí vyskočení z právě probíhajícího cyklu, což způsobí pokračování příkazy za ním. Programátoři se často dostanou do situace, kdy potřebují provést část kódu za předpokladu splnění 2 a více podmínek najednou. Máte na výběr za dvou základních možností, jak tento problém řešit. Buď za pomoci vnořené podmínky (do kladné větve podmínky if vložíte další podmínku), anebo vložením více podmínek do jedné funkce if, přičemž mezi tyto podmínky vložíte zdvojenou spojku &&. Podobně lze naprogramovat i disjunktní podmínku, která se považuje za splněnou za předpokladu, že je splněna aspoň jedna z podmínek. V příkazu if se mezi takovéto podmínky vkládá zdvojená spojka ||. Kapitola 11.Hrajeme si Co se naučíte: Jednou z nejpřitažlivějších programátorských činností je jistě, alespoň pro začínající vývojáře, programování her. Přitažlivé však ještě neznamená jednoduché. Já ale věřím, že se s touto kapitolou poperete a přijdete jí na kloub. Před samotným vytvářením her se seznámíme příkazem, který slouží ke generování náhodných čísel. Ten bude využit v první hře, kterou budete mít za úkol pochopit a upravit. Druhá hra už bude čistě na Vás. Nové příkazy: název_proměnné = random(max); generování náhodného čísla Generátor náhodných čísel Čas od času potřebujeme, aby se nám v programu vygenerovalo náhodné číslo a uložilo do proměnné pro její další využití. Náhodná čísla někdy potřebujeme vytvořit pro funkčnost programu, jindy pro její testování. Existuje několik způsobů, jak se taková čísla generují. Nám bude stačit tento jednoduchý: Generátor náhodných čísel název_proměnné = random(max); Rozbor příkazu Příkaz vygeneruje číslo v intervalu 0 až max a uloží jej do proměnné. Pokud např. chcete vygenerovat náhodné číslo od 0 do 10 a uložit jej do proměnné nahoda, bude kód vypadat takto: nahoda = random(10); Pokud chcete generovat čísla v jiném rozsahu, např. od 1 do 20, musíte zaimprovizovat: nahoda = random(19)+1; Příkazem random(19) se generují čísla od 0 do 19. Přidáním +1 za příkaz random se každé vygenerované číslo zvedne o 1. Tedy z 0 se stane 1, z 1 se stane 2, …, z 19 se stane 20. Do proměnné nahoda se tedy nakonec uloží čísla v intervalu 1 až 20. Generování čísel ze zadaných intervalů Jakými příkazy se vygenerují do proměnné x typu integer čísla z následujících Cvičení 18 intervalů? a) čísla od 0 do 100 b) čísla od 10 do 100 c) čísla od -100 do 100 Hra pozornosti Vytvořte hru pozornosti, která se bude hrát na NXT terminálu s připojeným jedním dotykovým senzorem. Na začátku hry se objeví na displeji nápis „START“. Po třech sekundách začne hra. Ta spočívá v tom, že se na displeji každé 0,8 sekundy objeví trojice náhodně vygenerovaných čísel od 1 do 5. Hráč musí stisknout dotykový senzor ve chvíli, kdy jsou na displeji 2 nebo 3 stejná čísla: 1. Pokud jsou při stisku senzoru na displeji 2 stejná čísla, dostává hráč 3 body. 2. Trefí-li se hráč stiskem do tří stejných čísel, dostane bodů 10. 3. Pokud se hráč splete a stiskne senzor při třech různých číslech, 3 body se mu odečtou. Hra končí ve chvíli, kdy hráč dosáhne 50 nebo více bodů. Na displeji se objeví na 5 vteřin nápis „VÍTĚZ“. Během hry musí být hráč stále informován o výši jeho bodového konta a o tom, kolik bodů se mu daném kole přičítá, či odečítá. Zásadním problémem, na který byste při programování této hry mohli narazit, je kontinuální běh dvou časových smyček. Jedna časová smyčka je 0,8 sekundy a je potřeba pro generování trojice čísel. Druhá časová smyčka slouží k detekci stisku dotykového senzoru. Zde by se nám možná hodily znalosti paralelního programování dvou současně probíhajících procesů. Protože již na to není v této sbírce prostor, zkusím Vám jednoduchým schématem ozřejmit, jak můžete postupovat s tím, co znáte: Nekonečný cyklus Vygeneruj trojici náhodných čísel. Vykonej 80krát 10ms časovou prodlevu pro získání celkové prodlevy 0,8s. Za každou 10ms prodlevou testuj, zda nedošlo ke stisku dotykového senzoru. Průběžně také hlídej, zda hráč nedosáhl požadovaného počtu bodů. V takovém případě hru ukonči. Obr. 25 ‐ Grafické znázornění algoritmu Analyzujte si a prakticky otestujte kód programu „Program 15 – Hra pozornosti“. K jeho pochopení by vám měly posloužit komentáře. Pozn. Následující program funguje pouze v programu Robotc verze 3 a vyšší. Nižší verze nedokáže na displej zobrazit tři proměnné v rámci jednoho příkazu. Máte-li nižší verzi, vytvořte alternativní řešení, kdy jsou tři proměnné zobrazeny ne vedle sebe, ale pod sebou. #pragma config(Sensor, S1, hrac1, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { byte cislo1; byte cislo2; byte cislo3; byte citac = 80; /*promenna citac slouzi k odmereni osmdesáti 10 miliseknudovych časových prodlev, mezi kterymi se testuje stisk dotykoveho senzoru na jednu sadu znaku. Na zacatku se inicializuje cislem 80 proto, ze pred prvnim generovanim nahodnych cisel nechceme odmerovat zadny cas.*/ int skoreHrace1 = 0; bool blokaceHrace1 = false; /*promenna blokaceHrace1 slouzi k zablokovani vicenasobne reakce na stisk dotykoveho senzoru na jedu sadu znaku.*/ nxtDisplayCenteredBigTextLine(3,"START"); wait1Msec(2000); for(;;) { /*Pokud uplynulo 0,8 sekund od zobazeni posledni sady znaku, vygeneruje se nova sada, vypise se a citac se vynuluje pro odmereni dalsich 0,8s. Pokud hrac reagoval na stisk behem predchozi sady znaku, a byl tedy po svem pokusu zablokovat, je nyni odblokovan pro pokracovani ve hre. Pred kazdou sadou znaku je take vypsano skore hrace.*/ if(citac == 80) { cislo1 = random(4)+1; cislo2 = random(4)+1; cislo3 = random(4)+1; nxtDisplayCenteredBigTextLine(3,"%d %d %d",cislo1,cislo2,cislo3); citac = 0; blokaceHrace1 = false; nxtDisplayTextLine(6,"Hrac 1: %d",skoreHrace1); } else /*Pokud jeste neuplynulo 0,8 sekund od zobazeni posledni sady znaku, zda byl poprve (blokace je nastavena na false) behem aktualni sady stisknut senzor.*/ { if(SensorValue(hrac1) == 1 && blokaceHrace1 == false) { /*Byl‐li stisknut seznor, nastavi se blokace na true, aby nemohl byt stisknut vicekrat behem jedne sady znaku. Testuje se, zda jsou vygenerovana cisla stejna.*/ blokaceHrace1 = true; if(cislo1 == cislo2 && cislo2 == cislo3 && cislo1 == cislo3) { /*V pripade shodnosti vsech znaku se pricte 10 bodu a informace se zobrazi na displeji.*/ skoreHrace1 = skoreHrace1 + 10; nxtDisplayTextLine(6,"Hrac 1: %d +10",skoreHrace1); } else /*Pokud by nebyla vsechna 3 cisla stejna, testuje se, zda byla stejna aspon nektera dvojice cisel.*/ if(cislo1 == cislo2 || cislo2 == cislo3 || cislo1 == cislo3) { /*Pokud byla nalezena dvojice shodnych cisel, prictou se ke skore hrace 3 body a informace se zobrazi na displeji.*/ skoreHrace1 = skoreHrace1 + 3; nxtDisplayTextLine(6,"Hrac 1: %d +3",skoreHrace1); } else { /*Pokud se pri stisku nebojevila ani dvojice stejnych cisel, jsou ze skore odecteny 3 body a informace se zobrazi na displeji.*/ skoreHrace1 = skoreHrace1 ‐ 3; nxtDisplayTextLine(6,"Hrac 1: %d ‐3",skoreHrace1); } } } /*Casova prodleva je vyuzita k tomu, aby se kazdych 10 milisekund zvednul obsah citace. To slouzi k mezitestovani senzoru pri odmerovani 0,8 sekundy pro vygenerovani nove sady znaku.*/ citac++; wait1Msec(10); /*Testovani, zda hrac nedosahl nebo nepreskocil skore 50 a nezvitezil. Pokud zvitezil, objevi se infomace na obrazove a prikazem break se vyskoci z nekonecneho cyklu na konec programu.*/ if(skoreHrace1 >= 50) { nxtDisplayCenteredBigTextLine(3,"VITEZ"); wait1Msec(5000); break; } } } Hra pozornosti pro dva hráče Hrát hru sám se sebou je nuda, a proto upravte „Program 15 – Hra pozornosti“ tak, Cvičení 19 aby hru hráli dva hráči proti sobě. K NXT terminálu připojte další dotykový senzor, aby měl každý hráč svůj. Oba hráči si během hry zvedají své bodové konto najednou, takže na její plynulosti se nic nemění. Pro větší zábavnost však můžete doprogramovat, že při „trefě“ jednoho hráče (která povede k připsání 3 nebo 10 bodů) se zablokuje pokus druhého hráče v daném kole. Body za postřeh při mačkání senzoru tedy může v každém kole získat jen jeden z hráčů. Bodová konta obou hráčů budou na obrazovce zobrazena najednou, aby o sobě měli navzájem přehled. Hráč, který dosáhne 50 bodů dříve, než druhý, vyhrává. Pojezdová hra Souhrnné cvičení 6 Vytvořte pojezdovou hru, která se hraje tak, že si dva hráči předávají dotykový senzor, na jehož stisk se vozidlo rozjede. To je na začátku hry postavené v libovolné vzdálenosti kolmo od zdi. Před každým stiskem se na displeji rozpohybuje ukazatel tak, že se neustále zvětšuje a zmenšuje. Čím je ukazatel při stisku dotykového senzoru větší, tím ať je jízda delší. Vítězí ten hráč, jehož pojezdem dojde k dotyku vozidla se zdí. Hra tedy spočívá v tom, že si aktivní hráč musí promyslet, kolik času potřebuje do kontaktu senzoru se zdí a zda dokáže sepnout ruční senzor v tom správném momentě aktuální polohy časového ukazatele. Jestliže si např. hráč řekne, že ani by ani při nejvyšším čase nedošlo ke kontaktu robota se zdí, měl by s délkou pojezdu taktizovat tak, aby kontakt neumožnil soupeři, který hraje po něm. Teoretická východiska Pomůcky Zadání znalost práce s dotykovým senzorem znalost importování zvuků do NXT terminálu a jejich přehrávání znalost práce s nekonečným cyklem a podmínkou znalost příkazů pro programování displeje znalost příkazu pro generování náhodného čísla robot Lego Mindstorms v sestavení vozidlo s dotykovým senzorem připevněným ve přední části tak, aby došlo k jeho stisku při kolmém najetí na zeď druhý připojený dotykový senzor bude držet hráč v ruce 1. Ať se na displeji objeví nápis „Hráč 1“ a zůstane tam 1,5 s. 2. Poté ať se na displeji objeví postupně na prvním až posledním řádku libovolný znak (nebo série znaků): Nejprve se znak vypíše na prvním řádku, potom přibude na druhém řádku, atd. až bude znak na každém řádku. Poté ať znaky zase postupně mizí (od posledního nakresleného). Po zmizení všech znaků ať se celý cyklus stále dokola opakuje, a to dokud hráč nestiskne dotykový senzor, který má v ruce. Časový rozdíl mezi přidáváním a odebíráním znaků je 70 ms. 3. Po stisku senzoru ať vozidlo jede výkonem 30% po uvedenou dobu: Doba jízdy = počet znaků na displeji * 200 ms 4. Po dojezdu se na displeji objeví nápis „Hráč 2“ po dobu 1,5 s, pro kterého se bude celá procedura výběru času jízdy pomocí ukazatele na displeji opakovat. 5. Program ať stále střídá Hráče 1 a 2, dokud nedojde ke kontaktu předního dotykového senzoru se zdí. Vyhrává ten hráč, kterému se podařilo tohoto kontaktu dosáhnout. Na konci hry oznamte na displeji informaci, který hráč vyhrál a přehrajte importovaný zvuk „Hooray.rso“. Shrnutí kapitoly: V této kapitole jste si vyzkoušeli prakticky veškeré dovednosti, které jste nabyli v předchozím textu sbírky. Navíc jste se naučili příkaz pro generování náhodného čísla. Poslední souhrnné cvičení bylo docela náročné, protože popis již neobsahuje veškeré detaily, na které si musíte při programování dávat pozor. Pokud jste jej zvládli, gratuluji Vám. Závěrem A tímto jste se dostali na konec této sbírky, což je ten nejlepší předpoklad k tomu, abyste se nejprve pochválili, a pak co nejdříve pokračovali v neutuchajícím boji o vzdělávání druhým dílem. Z programátorského hlediska je nejdůležitější prakticky zvládnout základní algebraické struktury. Nyní již znáte sekvenci a podmínku. Ve druhé části učebnice se dočtete o cyklech, které Vám obrovským způsobem rozšíří Vaše možnosti v programování. Z této učebnice již znáte nekonečný cyklus, přerušený podmínkou obsahující příkaz vyskočení z cyklu. Čistě teoreticky by Vám tato znalost mohla stačit, protože veškeré klasické cykly lze nahradit právě nekonečným cyklem s podmínkou. Skutečnost je ale jiná a jistě byste záhy zjistili, že znalost typičtějších druhů cyklů, jejich zápisů a použití patří mezi znalosti základní, bez kterých se neobejdete jak při analýze kódů, tak jejich přehlednějšímu psaní. Ve druhé části sbírky se dále naučíte, jak v prostředí Robotc programovat sonar a barevný senzor stavebnice Lego Mindstorms. Navíc využijete i funkci doplňkového motoru, především pomocí tzv. krokování. Doufám, že se Vám programování dařilo. Také doufám, že Vás bavilo, snad i díky práci s netypickým prostředkem programovatelného robota. Protože pro další vzdělávání a zdokonalování v jakékoli oblasti lidského vědění a konání není příznivější podmínky, než že Vás práce baví. Klíče ke cvičením Cvičení 1: 1. 2. 3. 4. Robot jede dopředu poloviční rychlostí. Robot při jízdě zahýbá. Délka jízdy robota se zdvojnásobí Program skončí, aniž by se robot pohnul. Cvičení 2: 1. 2. 3. Testování příkazů motor a wait1Msec Otočka o 360 stupňů cca 6500 ms cca 3800 ms cca 2700 ms Cvičení 3: Tam a zpět task main() { //jízda dopředu se 100% výkonem a délkou 4 vteřiny motor(motorB)=100; motor(motorC)=100; wait1Msec(4000); //otočení o 180 stupňů na místě motor(motorB)=‐100; motor(motorC)=100; wait1Msec(1400); //* Délka otáčení 1,4 vteřiny se může lišit podle povrchu, na kterém robot jede. *// //jízda dopředu se 100% výkonem a délkou 4 vteřiny motor(motorB)=100; motor(motorC)=100; wait1Msec(4000); } Když se podíváte pozorně, uvidíte, že v kódu je příkaz „motor(motorC)=100;“ napsán třikrát. Tolikrát tam ovšem není potřeba. Nastavíme-li jednou motoru C nějakou hodnotu, zůstává mu stále přiřazena, dokud mu nenastavím jinou, či neskončí program. Proto můžeme kód tzv. optimalizovat tak, že příkaz pro nastavení motoru C ponecháme jen v prvním výskytu: task main() { motor(motorB)=100; motor(motorC)=100; wait1Msec(4000); motor(motorB)=‐100; wait1Msec(1400); motor(motorB)=100; wait1Msec(4000); } Cvičení 4: Pojezd a zvuk task main() { motor(motorB)=20; //jizda motor(motorC)=20; wait1Msec(5000); motor(motorB)=0; //pokud nevypnete motory, zvuk nepujde slyset motor(motorC)=0; PlaySound(soundDownwardTones); //prehrani zvuku while(bSoundActive); {} } Cvičení 5: Kolečko se zvuky task main() { //program přímo začíná zvukem, není proto potřeba časové prodlevy předem PlaySoundFile(„Start.rso“); /*přehrání zvuku Start.rso, který musí být nahrán v terminálu, nebo musí být přítomen ve složce NXT System Files programu Robotc*/ while(bSoundActive) {} //čekání na dohrání zvuku motor(motorB)=30; //výkon jednoho motoru je vyšší, než druhého motor(motorC)=100; wait1Msec(15000); //pojezd motor(motorB)=0; //vypnutí motoru B po dojezdu motor(motorC)=0; //vypnutí motoru C po dojezdu wait1Msec(1500); //časová prodleva pro přípravu zařízení PlaySoundFile(„Good Job.rso“); /*přehrání zvuku Good Job.rso, který musí být nahrán v terminálu, nebo musí být přítomen ve složce NXT System Files programu Robotc*/ while(bSoundActive) {} //čekání na dohrání zvuku } K programu lze dodat, že poloměr, který má vozidlo opsat, závisí na rozdílu výkonů motorů B a C. Čím větší bude mezi nimi výkonový rozdíl (čím rychlejší bude jeden motor oproti druhému), tím menší je průměr kružnice, kterou vozidlo svým pohybem vykreslí. V závislosti na výkonu a podložce, po které se robot pohybuje, je potřeba správně zvolit dobu pojezdu. Cvičení 6: Popis jízdy task main() { nxtDisplayTextLine(0,"Prubeh jizdy:"); wait1Msec(1000); nxtDisplayCenteredBigTextLine(3,"Odjezd"); motor(motorB)=100; motor(motorC)=100; wait1Msec(4000); nxtDisplayCenteredBigTextLine(3,""); /*Uvozovkami napsanými u sebe vkládáme prázdný řetězec. Tím prakticky jen smažeme předchozí text.*/ motor(motorB)=‐100; wait1Msec(1400); nxtDisplayCenteredBigTextLine(3,"Prijezd"); motor(motorB)=100; wait1Msec(4000); } Cvičení 7: 10 stupňů Celsia task main() { byte stupne = 10; //deklarace celočíselné proměnné s počáteční inicializací číslem 10 nxtDisplayTextLine(0,“%d stupnu Celsia“,stupne); //na obrazovku se vypíše „10 stupnu celsia“ wait1Msec(10000); } Cvičení 8: Pi task main() { float cisloPi= 3.14159265358979323846; //deklarace reálné proměnné s počáteční inicializací. //nezapomněli jste napsat místo desetinné čárky tečku? nxtDisplayTextLine(0,“pi = %1.2f“,cisloPi); //na obrazovku se vypíše „pi = 3.14“ wait1Msec(10000); } Cvičení 9: Výkon motorů task main() { nxtDisplayCenteredTextLine(1,“VYKON MOTORU“); //protože se nikde v následujícím kódu nepracuje s řádkem č. 1, //zůstane text „VYKON MOTORU“ na displeji po celou dobu běhu programu int vykon = ‐20; //vytvoříme proměnnou vykon, která bude uchovávat aktuální výkon motorů //proměnnou vykon budeme také vypisovat na displej motor(motorB)=vykon; motor(motorC)=vykon; //oběma motorům je přiřazen výkon z proměnné vykon nxtDisplayCenteredBigTextLine(4,“%d“,vykon); //vypsání hodnoty proměnné vykon na displeji wait1Msec(5000); //a jedeme vykon = 0; //proměnnou vykon již nyní nevytváříme, jen jí přiřazujeme novou hodnotu motor(motorB)=vykon; motor(motorC)=vykon; nxtDisplayCenteredBigTextLine(4,“%d“,vykon); //přepsání hodnoty proměnné vykon na displeji wait1Msec(3000); vykon = 20; motor(motorB)=vykon; motor(motorC)=vykon; nxtDisplayCenteredBigTextLine(4,“%d“,vykon); //přepsání hodnoty proměnné vykon na displeji wait1Msec(5000); } Cvičení 10: Fotbal task main() { string nazevTymu1 = „Real Madrid“; string nazevTymu2 = „Barcelona“; byte skoreTymu1 = 2; byte skoreTymu2 = 0; nxtDisplayCenteredBigTextLine(1, „SKORE“); nxtDisplayCenteredTextLine(3,“%s : %s“,nazevTymu1,nazevTymu2); nxtDisplayCenteredTextLine(4,“%d : %d“,skoreTymu1,skoreTymu2); wait1Msec(10000); } Cvičení 11: Pořadí matematických operací task main() { int vysledek1; int vysledek2; vysledek1 = 3 + 6 * 2; nxtDisplayTextLine(0,"3 + 6 * 2 = %d",vysledek1); vysledek2 = (3 + 6) * 2; nxtDisplayTextLine(1,"(3 + 6) * 2 = %d",vysledek2); wait1Msec(15000); } Cvičení 12: Porovnání zápisů pro zvětšení proměnné task main() { int cislo = 10; int x = 2; cislo = cislo + x; nxtDisplayTextLine(0,"Zapis1: cislo=%d",cislo); /*Abychom otestovali, zda jsou zapisy analogicke, musime znovu nastavit promenne, se kterymi se pocita, na pocatecni hodnoty.*/ cislo = 10; x = 2; cislo += x; nxtDisplayTextLine(1,"Zapis2: cislo=%d",cislo); wait1Msec(10000); } Cvičení 13: Odpočet s proměnnou task main() { byte odpocet = 3; nxtDisplayCenteredTextLine(3,“%d“,odpocet); wait1Msec(1000); odpocet‐‐; nxtDisplayCenteredTextLine(3,“%d“,odpocet); wait1Msec(1000); odpocet‐‐; nxtDisplayCenteredTextLine(3,“%d“,odpocet); wait1Msec(1000); nxtDisplayCenteredBigTextLine(3,“START“); PlaySoundFile(„Start.rso“); while(bSoundActive) {} motor(motorB)=100; //výkon jednoho motoru je vyšší, než druhého motor(motorC)=100; wait1Msec(5000); } Cvičení 14: Zapnutí a vypnutí pojezdu dvěma ovladači Nejprve si necháme vygenerovat kód nastavením potřebných dotykových senzorů: #pragma config(Sensor, S1, start, sensorTouch) #pragma config(Sensor, S2, stop, sensorTouch) Poté by mohl následovat tento kód. Na začátku je nastavená konstanta rychlost. Zbylé příkazy jsou uzavřeny nekonečným cyklem for(;;), aby se na detekci stisknutých dotykových senzorů stále opakovaly. task main() { const int rychlost = 50; for(;;) { if(sensorValue(start)==1) { motor(motorB)=rychlost; motor(motorC)=rychlost; } if(sensorValue(stop)==1) { motor(motorB)=0; motor(motorC)=0; } } } Rozbor příkladu: Pokud není stisknut žádný senzor, program prochází vnitřní příkazy cyklu stále dokola, ale nic se neděje. Uvnitř se totiž nacházejí pouze dvě podmínky, které nejsou splněny. Pokud by byl stisknut „stop-senzor“ a robot přitom stál na místě, opět by se nic nedělo. Výkon motorů by se nastavil na nulu, ale tuto hodnotu stejně aktuálně mají. Při x-tém průchodu cyklu uživatel stiskne „start-senzor“. Výkon obou motorů se nastaví na hodnotu uvedenou v konstantě rychlost a robot se rozjede. Opět připomínám, proč za nastavením motorů nemusí být časová prodleva. Po jejím uplynutí by se totiž nic nezměnilo. V dalším cyklu by následoval dotaz na aktivitu „stop-senzoru“, který by byl negativní a program by opět přešel na začátek nekonečného cyklu. Motory přitom pořád jedou, protože je žádný příkaz nedeaktivoval. To nastane, až se někdy v y-tém opakování nekonečného cyklu detekuje zmáčknutý „stop-senzor“. Časovou prodlevu tedy tak zastupuje nekonečná smyčka cyklu, ohraničená stiskem startovního a stop senzoru. Cvičení 15: Zvyšování a snižování rychlosti #pragma config(Sensor, S1, zvyseni_vykonu, sensorTouch) #pragma config(Sensor, S2, snizeni_vykonu, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { int vykon = 0; //deklarace proměnné výkon //inicializace počáteční hodnoty na 0 je zde nutná for(;;) { if(SensorValue(zvyseni_vykonu)==1) if(vykon < 100) //horní hodnota výkonu nesmí přesáhnout 100 vykon = vykon + 10; else vykon = 100; if(SensorValue(snizeni_vykonu)==1) if(vykon > ‐100) //dolní hodnota výkonu nesmí přesáhnout ‐100 vykon = vykon – 10; else vykon = ‐100; motor(motorB) = vykon; motor(motorC) = vykon; nxtDisplayTextLine(0,"Vykon: %d",vykon); //zobrazení rychlosti wait1Msec(100); } } Cvičení 16: Zahýbání a jízda vpřed #pragma config(Sensor, S1, otoceniVpravo, sensorTouch) #pragma config(Sensor, S2, otoceniVlevo, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { for(;;) { if(SensorValue(otoceniVpravo)==1) if(SensorValue(otoceniVlevo)==1) { motor(motorB)=50; motor(motorC)=50; } else { motor(motorB)=‐50; motor(motorC)=50; } else if(SensorValue(otoceniVlevo)==1) { motor(motorB)=50; motor(motorC)=‐50; } else { motor(motorB)=0; motor(motorC)=0; } } } Cvičení 17: Zahýbání a jízda vpřed 2 #pragma config(Sensor, S1, otoceniVpravo, sensorTouch) #pragma config(Sensor, S2, otoceniVlevo, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { for(;;) { if(SensorValue(otoceniVpravo)==1 && SensorValue(otoceniVlevo)==1) { motor(motorB)=50; motor(motorC)=50; } if(SensorValue(otoceniVpravo)==0 && SensorValue(otoceniVlevo)==1) { motor(motorB)=50; motor(motorC)=‐50; } if(SensorValue(otoceniVpravo)==1 && SensorValue(otoceniVlevo)==0) { motor(motorB)=‐50; motor(motorC)=50; } if(SensorValue(otoceniVpravo)==0 && SensorValue(otoceniVlevo)==0) { motor(motorB)=0; motor(motorC)=0; } } } Cvičení 18: a) b) c) Generování čísel ze zadaných intervalů x=random(100); x=random(90)+10; x=random(200)‐100; Cvičení 19: Hra pozornosti pro dva hráče #pragma config(Sensor, S1, hrac1, sensorTouch) #pragma config(Sensor, S2, hrac2, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { byte cislo1; byte cislo2; byte cislo3; byte citac = 80; int skoreHrace1 = 0; int skoreHrace2 = 0; bool blokaceHrace1 = false; bool blokaceHrace2 = false; nxtDisplayCenteredBigTextLine(3,"START"); wait1Msec(2000); for(;;) { if(citac == 80) { cislo1 = random(4)+1; cislo2 = random(4)+1; cislo3 = random(4)+1; nxtDisplayCenteredBigTextLine(3,"%d %d %d",cislo1,cislo2,cislo3); citac = 0; blokaceHrace1 = false; blokaceHrace2 = false; nxtDisplayTextLine(6,"Hrac 1: %d",skoreHrace1); nxtDisplayTextLine(7,"Hrac 2: %d",skoreHrace2); } else { if(SensorValue(hrac1) == 1 && blokaceHrace1 == false) { blokaceHrace1 = true; if(cislo1 == cislo2 && cislo2 == cislo3 && cislo1 == cislo3) { skoreHrace1 = skoreHrace1 + 10; nxtDisplayTextLine(6,"Hrac 1: %d +10",skoreHrace1); blokaceHrace2 = true; } else if(cislo1 == cislo2 || cislo2 == cislo3 || cislo1 == cislo3) { skoreHrace1 = skoreHrace1 + 3; nxtDisplayTextLine(6,"Hrac 1: %d +3",skoreHrace1); blokaceHrace2 = true; } else { skoreHrace1 = skoreHrace1 ‐ 3; nxtDisplayTextLine(6,"Hrac 1: %d ‐3",skoreHrace1); } }; if(SensorValue(hrac2) == 1 && blokaceHrace2 == false) { blokaceHrace2 = true; if(cislo1 == cislo2 && cislo2 == cislo3 && cislo1 == cislo3) { skoreHrace2 = skoreHrace2 + 10; nxtDisplayTextLine(7,"Hrac 2: %d +10",skoreHrace2); blokaceHrace1 = true; } else if(cislo1 == cislo2 || cislo2 == cislo3 || cislo1 == cislo3) { skoreHrace2 = skoreHrace2 + 3; nxtDisplayTextLine(7,"Hrac 2: %d +3",skoreHrace2); blokaceHrace1 = true; } else { skoreHrace2 = skoreHrace2 ‐ 3; nxtDisplayTextLine(7,"Hrac 2: %d ‐3",skoreHrace2); } } } citac++; wait1Msec(10); if(skoreHrace1 >= 50 || skoreHrace2 >= 50) { nxtDisplayTextLine(6,"Hrac 1: %d",skoreHrace1); nxtDisplayTextLine(7,"Hrac 2: %d",skoreHrace2); if(skoreHrace1 > skoreHrace2) { nxtDisplayCenteredBigTextLine(1,"HRAC 1"); nxtDisplayCenteredBigTextLine(3,"WINS!!!"); } else if(skoreHrace1 < skoreHrace2) { nxtDisplayCenteredBigTextLine(1,"HRAC 2"); nxtDisplayCenteredBigTextLine(3,"WINS!!!"); } else nxtDisplayCenteredBigTextLine(3,"REMIZA"); wait1Msec(5000); break; } } } Klíče k souhrnným cvičením Souhrnné cvičení 1: Jízda městem Program vychází ze zapojení pravého motoru (při pohledu zezadu) do portu B a levého motoru do portu C. Dále se předpokládá, že jste dodrželi obdobný tvar města, jako je v zadání souhrnného cvičení. Váš program se v tom případě může lišit jen délkami časových prodlev, které závisí na povrchu, po kterém robot jezdí, a na proporcích „budov“, které objíždí. task main() { //jizda dopredu motor(motorB)=30; motor(motorC)=30; wait1Msec(4000); //otoceni o 90 stupnu doprava motor(motorB)=0; wait1Msec(3200); //jizda dopredu motor(motorB)=30; wait1Msec(4600); //otoceni o 90 stupnu doleva motor(motorB)=30; motor(motorC)=0; wait1Msec(3200); //jizda dopredu motor(motorC)=30; wait1Msec(4000); //otoceni o 90 stupnu doleva motor(motorB)=30; motor(motorC)=0; wait1Msec(3200); //jizda dopredu motor(motorC)=30; wait1Msec(2300); //otoceni o 180 stupnu na miste motor(motorB)=30; motor(motorC)=‐30; wait1Msec(3300); //zacouvani do garaze motor(motorB)=‐30; wait1Msec(2300); } Souhrnné cvičení 2: Odpočet task main() { nxtDisplayCenteredTextLine(3,“3“); //řádky displeje jsou označeny od nuly, proto čtvrtý řádek má označení 3 wait1Msec(1000); //nápis „3“ bude na displeji 1 sekundu nxtDisplayCenteredTextLine(3,“2“); wait1Msec(1000); nxtDisplayCenteredTextLine(3,“1“); wait1Msec(1000); nxtDisplayCenteredBigTextLine(3,“START“); //nápis „START“ vypíšeme 2x větším písmem, než je odpočet PlaySoundFile(„Start.rso“); /*přehrání zvuku Start.rso, který musí být nahrán v terminálu, nebo musí být přítomen ve složce NXT System Files programu Robotc*/ while(bSoundActive) {} //čekání na dohrání zvuku //nastavení pojezdu motor(motorB)=100; motor(motorC)=100; wait1Msec(5000); } Souhrnné cvičení 3: Zahýbání #pragma config(Sensor, S1, doprava, sensorTouch) #pragma config(Sensor, S2, doleva, sensorTouch) task main() { motor(motorB)=40; motor(motorC)=40; for(;;) { if(SensorValue(doleva)==1) { motor(motorB)=40; motor(motorC)=0; PlaySoundFile("MS_sfx_burp.rso"); while(bSoundActive); {} } else if(SensorValue(doprava)==1) { motor(motorB)=0; motor(motorC)=40; PlaySoundFile("MS_sfx_burp.rso"); while(bSoundActive); {} } else { motor(motorB)=40; motor(motorC)=40; } } } Souhrnné cvičení 4: Jízda s nastavením rychlosti předem #pragma config(Sensor, S1, nastaveniRychlosti, sensorTouch) #pragma config(Sensor, S2, start, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard!!*// task main() { int rychlost = 0; nxtDisplayCenteredTextLine(1,"Nastaveni"); nxtDisplayCenteredTextLine(3,"Rychlost: %d",rychlost); for(;;) { if(SensorValue(nastaveniRychlosti)==1) { motor(motorB)=0; motor(motorC)=0; wait1Msec(200); rychlost = rychlost + 10; if(rychlost > 100) rychlost = 0; nxtDisplayCenteredTextLine(3,"Rychlost: %d",rychlost); } if(SensorValue(start)==1) { motor(motorB)=rychlost; motor(motorC)=rychlost; wait1Msec(100); } } } Souhrnné cvičení 5: Zastavení po uplynutí určité doby nebo nárazem do zdi #pragma config(Sensor, S1, startStop, sensorTouch) #pragma config(Sensor, S2, start, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { for(;;) //cyklus ceka na stisk senzoru //stiskem senzoru se rozjedou motory a jde se odpocitavat //za for nasleduje jen jeden prikaz if, proto netreba {} if (SensorValue(startStop)==1) { motor(motorB)=50; motor(motorC)=50; break; } byte cyklus = 0; for(;;) { cyklus++; wait1Msec(200); //stisk senzoru se testuje co 200ms if(cyklus==25 || SensorValue(startStop)==1) //vozidlo se zastavi po 25 x 200ms = 5s //nebo setekovanym stiskem senzoru { motor(motorB)=0; motor(motorC)=0; wait1Msec(500); PlaySound(soundUpwardTones); while(bSoundActive) {} break; } } } Souhrnné cvičení 6: Pojezdová hra #pragma config(Sensor, S1, ovladac, sensorTouch) #pragma config(Sensor, S2, konec, sensorTouch) //*!!Code automatically generated by 'ROBOTC' configuration wizard !!*// task main() { byte intenzitaJizdy = 0; int casJizdy; bool zvysovaniCasu = true; byte cisloHrace = 1; nxtDisplayCenteredBigTextLine(3,"HRAC %d",cisloHrace); wait1Msec(1500); nxtDisplayCenteredBigTextLine(3,""); for(;;) { if(zvysovaniCasu == true) { nxtDisplayTextLine(intenzitaJizdy,"___________________"); intenzitaJizdy++; if(intenzitaJizdy==8) zvysovaniCasu=false; } else { intenzitaJizdy‐‐; nxtDisplayTextLine(intenzitaJizdy,""); if(intenzitaJizdy==0) zvysovaniCasu=true; } wait1Msec(70); if(SensorValue(ovladac)==1) { motor(motorB)=30; motor(motorC)=30; casJizdy = intenzitaJizdy*200; wait1Msec(casJizdy); motor(motorB)=0; motor(motorC)=0; if(SensorValue(konec)==0) { if(cisloHrace==1) cisloHrace = 2; else cisloHrace = 1; eraseDisplay(); nxtDisplayCenteredBigTextLine(3,"HRAC %d",cisloHrace); wait1Msec(1500); nxtDisplayCenteredBigTextLine(3,""); } else { eraseDisplay(); nxtDisplayCenteredBigTextLine(2,"HRAC %d",cisloHrace); nxtDisplayCenteredBigTextLine(5,"WINS!!!"); PlaySoundFile("Hooray.rso"); wait1Msec(5000); } } } } Tento algoritmus má jeden malý nedostatek, jehož přítomnost Vám musím, jakožto autor sbírky, vysvětlit. Jedná se o to, že k vyhodnocení, zda došlo ke střetu vozidla s protější stěnou, dochází až po uplynutí celého pojezdu za daný časový úsek zvolený dotykovým senzorem. V praxi to vypadá tak, že zbývá-li do střetu se stěnou půl sekundy, ale hráč zvolí pojezd jednosekundový, bude se střet robota se zdí ověřovat právě až po jedné sekundě. Jestliže se ale robot během druhé půl sekundy po střetu stočí tak, že se uvolní dotykový senzor pro testování konce hry, program hru nevyhodnotí jako ukončenou. Daný problém by se dal vyřešit tak, že by se netestovalo až po uplynutí časového intervalu, ale několikrát během něj. To by však kód velmi znepřehlednilo. I když si myslím, že i přesto můžete k tomuto správnému řešení dojít, odložil bych „lepší“ řešení až na dobu, kdy budete umět zapisovat klasické cykly. Až jejich zápis by dokázal přinést kódu kýženou přehlednost.
Podobné dokumenty
Monitorování provozu operačních systémů a jejich diagnostika
neustále zvyšuje, počet potenciálních chyb v počítači může růst násobky. A to nehovořím o
chybách hardwaru. Nelze se tedy divit, že neexistuje žádný expertní program, jenž by po analýze
operačního ...
Řízení robota MINDSTORMS NXT pomocí PC PC Controlling of
sestavení prvního robota a originální software pro programování. Roboti jsou schopni plnit
jednoduché i více složitější úlohy, vždy záleží na konstrukci a schopnosti naprogramovat
odpovídající algo...
Ovládání laboratorního modelu robota Mindstorms
středního věku, kteří jsou většinou rádi, kdyţ si umí pouţívat alespoň základní funkce jako
je volaní a psaní SMS.
V roce 1949 vznikly první kostičky, které umoţňovaly pevné, ale rozebíratelné stav...
Programování Lego robotů pomocí NQC
využívá. Samotný jazyk NQC však může být využíván i na jiných systémech
(Sun, Apple, UNIX a další). Můžete jej stáhnout z www adresy
http://www.enteract.com/~dbaum/lego/nqc/
Většina z tohoto tutori...
LEGO Roboti a jejich programování (teoretická a praktická část)
jednoduchost vývojového prostředí včetně procesu programování tak, aby s
robotem mohli pracovat už i žáci základních škol, kteří mají s programováním
minimální zkušenosti.
Ovládání laboratorního modelu Mindstorms NXT (spike) pomocí PC
rychlostí 12,1 Mb/s), přes niž lze z nadřazeného počítače do paměti mikropočítače
zaznamenat řídící program nebo další systémové soubory. Na spodní straně se nalézají čtyři
výstupní porty (označené...
Sborník - Olympiáda techniky Plzeň
PhDr. Milan Klement, Ph.D., Univerzita Palackého v Olomouci, ČR
Ing. Jaroslav Novák, Ph.D., Univerzita Karlova v Praze, ČR
Doc. PaedDr. Viera Tomková. Ph.D., Univerzita Konštantína Filozofa Nitra, ...