Az NXC nyelv Lego NXT robot programozása NXC Nyelv segítségével Írta és fordította: prof.ing.kőrösi Gábor 2010, Zenta-Szerbia, Bolyai Tehetséggondozó Gimnázium Oldal1 www.bolyai-zenta.edu.rs
BEVEZETŐ 2 I. AZ ELSŐ PROGRAMUNK MEGÍRÁSA 3 A ROBOT ÉPÍTÉSE 3 ISMERKEDÉS A BRICX COMMAND KÖZPONTAL 4 A PROGRAM ÍRASA 5 A PROGRAM FUTTATÁSA 6 HIBÁK A PROGRAMUNKBAN 6 A SEBESSÉG VÁLTOZTATÁSA 7 ÖSSZEFOGLALÓ 8 II. ÉRDEKESEBB PROGRAM KÉSZÍTÉSE 9 FORDULÓ MOZGÁS KÉSZÍTÉSE 9 UTASÍTÁSOK ISMÉTLÉSE 10 KOMMENTÁROK HOZZÁADÁSA 11 ÖSSZEFOGLALÓ 12 III. VÁLTOZÓK HASZNÁLATA 13 MOZGÁS SPIRÁL ALAKZATBAN 13 VÉLETLEN SZÁMOK 14 ÖSSZEFOGLALÓ 15 IV. VEZÉRLŐ UTASÍTÁSOK 16 AZ IF FELTÉTELES UTASÍTÁS 16 A DO UTASÍTÁS 17 ÖSSZEFOGLALÓ 18 V. ÉRZÉKELŐK 19 VÁRAKOZÁS AZ ÉRZÉKELŐRE 19 LEHETŐSÉGEK AZ ÉRINTŐ ÉRZÉKELŐVEL 20 FÉNYÉRZÉKELŐ 20 HANG ÉRZÉKELŐ 21 ULTRAHANGOS ÉRZÉKELŐ 22 ÖSSZEFOGLALÓ 23 VI. FÜGGVÉNYEK ÉS ELJÁRÁSOK 24 ELJÁRÁSOK 24 FÜGGVÉNYEK 25 MAKRÓK DEFINIÁLÁSA 27 ÖSSZEFOGLALÓ 28 Oldal2
VII. HANG SUGÁRZÁSA 29 HANG FÁJL LEJÁTSZÁSA 29 HANG JÁTSZÁSA 30 ÖSSZEFOGLALÓ 31 VIII. A MOTOROK MÉLYEBB ISMERETE 32 LÁGY LEÁLLÍTÁS 32 ÖSSZETETT VEZÉRLÉS 32 PID VEZÉRLÉS 34 ÖSSZEFOGLALÓ 36 IX. AZ ÉRZÉKELŐK TOVÁBBI LEHETŐSÉGEI 37 ÉRZÉKELŐ MÓDOK ÉS TÍPUSOK 37 FORGÁS ÉRZÉKELŐ 38 TÖBB ÉRZÉKELŐ EGY BEMENETEN 39 ÖSSZEFOGLALÓ 40 X. PÁRHUZAMOS ELJÁRÁSOK 41 A ROSSZ PROGRAM 41 A KRITIKUS RÉSZEK ÉS A MUTEX VÁLTOZÓ 42 SZEMAFOROK HASZNÁLATA 43 ÖSSZEFOGLALÓ 44 XI. ROBOTOK KÖZÖTTI KOMUNIKÁCIÓ 45 A MASTER-SLAVE ÜZENETKÜLDÉS 45 SZÁMOK ÉRTELMEZETT KÜLDÉSE 47 DIREKT VEZÉRLÉS 48 ÖSSZEFOGLALÓ 49 XII. TÖBB UTASÍTÁS 50 IDŐZÍTŐK TIMERS 50 PONT MÁTRIXOS KIJELZŐ 51 FÁJL RENDSZEREK 52 ÖSSZEFOGLALÓ 56 XIII. ÁTTEKINTÉS 57 JOGOK ÉS FELHASZNÁLÁSI FELTÉTELEK 58 Oldal3
Bevezető Ez a könyv elsősorban azok számára íródott akik most kezdenek ismerkedni a Lego Mindstrom programozási lehetőségeivel. Amennyiben foglalkozni szeretnénk valamely új vagy régebbi típusú lego robot programozásával, legyen az a Mindstorms RIS, CyberMaster, vagy Spybotic illetve a legújabb Mindstroms NXT, ehhez elsősorban valamilyen programozói felületre lesz szükségünk. Elsőként értelem szerűen mindenki az ingyenesen kapható és jól dokumentált NXG nyelvhez folyamodik, melyben grafikus környezetben tudunk dolgozni. A jól kezelhető felületnek köszönhetően, könnyedén oldhatunk meg programozási problémákat, legyünk akár óvodások vagy egyetemet végzett szakemberek. Ezt a nyelvet a LabViev a Legoval közreműködve hozta létre mely, animált eszközökkel teszi lehetővé az egyszerű programozást még olyan emberek számára is akik az eddigi életükben soha, egy sort sem programoztak. Az NXG programkörnyezet nagyon egyszerű, viszont ennek következtében nem kellőképp rugalmas, és bizonyos esetekben csak felesleges program modulokkal tudjuk rákényszeríteni a gépünket a kívánt feladatra. Ezen problémák kikerülése miatt hozta létre John Hansen az NXC program nyelvet mely Lego és más robot rendszerek programozásban nyújt segítséget. Az NXC egy C nyelven alapuló program környezetet. Itt most sokan felkaphatják a fejüket, hogy hogyan fogjak hozzá, hiszen és még soha sem programoztam, azonban biztosíthatom az olvasót, hogy még az alapok hiánya mellett is megtanulhatja ezt a nyelvet, ha lépésről lépésre végigköveti a könyv egyes fejezeteit. Hogy a program írása még egyszerűbb legyen, használhatjuk a Bricx Command Center (BricxCC)-t. Ez az eszköz segít abban, hogy a megírt programokat egyszerűen fel illetve letöltjük a gépünkbe, futathatjuk azokat, adatokat keressünk a NXT flash memóriájában, stb. Ez a leírás a BricxCC 3.3.7.16 (vagy újabb) integrált fejlesztő környezetére épít. A program letölthető : http://bricxcc.sourceforge.net/ Oldal4
I. AZ ELSŐ PROGRAMUNK MEGÍRÁSA Ebben a fejezetben megtanuljuk, hogy hogyan kell egy egyszerű programot írni. A programban melyet megírunk a következőket fogjuk csinálni: a robot előrehalad 4 másodpercet, majd visszafelé megy 4 másodpercet, ezek után megáll. Ez nem tűnhet túl bonyolult feladatnak, viszont ezen a példán keresztül rálátásunk nyílik a programozás alap logikájára, valamint azt is megtekinthetjük, hogy valójában milyen egyszerű egy program elkészítése. Mielőtt azonban bármihez is hozzá foghatnánk, szükségünk lesz egy tesztelhető robotra. A ROBOT ÉPÍTÉSE A robot melyet építünk az egész leíráson keresztül használni fogjuk így célszerű, ha egy egyszerűbb robotot építünk. Így idő takarékossági okokból a következőkben az alap csomagban kapható TRIBOT-ot fogjuk megépíteni és használni. A megépítés után le kell ellenőrizni, hogy fel, lett-e telepíve a NXT fantom drivert, mely megtalálható az alap csomagban található. Oldal5
ISMERKEDÉS A BRICX COMMAND CENTERREL A elkövetkezőkben a programjainkat a BricxCC segítségével fogjuk elkészíteni. A program indításához kétszer rá kell kattintanunk a BricxCC ikonjára. (Ez csak abban az esetben lehetséges ha már előzőleg letöltöttük és feltelepítettük a gépünkre ezt az alkalmazást. Amennyiben ez még nem történt meg úgy pótoljuk ezt a hiányosságot). Miután elindítottuk az alkalmazást, megkérdezi tőlünk, hogy hol található a robotunk. Ekkor kacsoljuk be a robotunkat, majd kattintsunk az OK-ra, és ennek hatására a program automatikusan (legtöbbször) megtalálja az eszközt. Ezek után ismerkedjünk a felhasználói felülettel. (lásd lent a képen) Mint látható az alkalmazásunk úgy néz ki mint egy egyszerű szöveg szerkesztő, és a menüje is a szokványos elemekkel rendelkezik,mit például: gombok a mentéshez, megnyitáshoz, nyomtatáshoz, stb. Továbbá, találhatóak további speciális menük is melyekkel, a megírt programunkat tudjuk fordítani,a gépbe tölteni vagy információkat kérhetünk le a robotból. Ahhoz hogy megírhassuk az első programunkat legelőször szükségünk lesz egy új file nyitására, melyet a NEW FILE gomb megnyomásával tehetünk meg. Oldal6
A PROGRAM ÍRASA Gépeljük be a következő programsorokat Első ránézésre komplikáltnak tűnhet a dolog, ezért elemezzük át a fent látottakat. Amint észrevetettük az említett pár sor NXC nyelvi elemeket tartalmaz. A programunk csak egy eljárásból épül fel, melynek neve main. Minden egyes programoknál szükséges hogy az eljárásokat main-nek nevezzük el melyet a robot egyetlenként értelmezve végrehajt. (Erről bővebben is beszélünk majd a hatodik fejezetben) Az eljárásunk továbbá tartalmaz több parancsot, melyet utasításnak is szoktunk nevezni. Láthatjuk, hogy a programunk kezdetét és végét egy zárójel( { } ) fogja, közre mely egyértelműen behatárolja a programunk törzsét. Minden utasítást kötelezően pontos vesszővel (;) kell zárnunk. Most hogy letisztáztuk az alapokat, érthető,hogy hol kezdődik a program, hol kezdődnek egyes parancsok és hogy mire szolgálnak ez elválasztó karakterek, értelmezhetjük a programot. Az eljárásunk törzse a következő képen épül fel: Ennek alapján az előzőleg begépelt programunkban hat darab utasítást találhatunk. Tekintsük meg ezeket egyenként. OnFwd(OUT_A, 75); Ez az utasítás jelzi a robotnak, hogy indulnia kell, az A kimenetre (output A) csatlakoztatott eszköznek. Ez egy motor mely a parancs hatására elindul előre (forward). A további számok a sebesség beállítására szolgálnak mely ez esetben a maximális sebesség 75%-át jelenti. OnFwd(OUT_C, 75); Oldal7
Ez az utasítás megegyezik az előzővel, azzal az eltéréssel, hogy most a C motor indul meg. Ez az utasítás után már mindkét motorunk forog (előre -forward). Wait(4000); Most a várakoztatáshoz érkeztünk. Ez az utasítás 4 másodperces várakoztatást jelent. Ezt az adatot a következő számok arányából kapjuk, egy másodperc késleltetés 1/1000. Tehát nagyon precízen be tudjuk hangolni a programunkat a várakoztatáskor. A 4 másodperc alatt a programunk alvó állapotba kerül(ez idő alatt nem érzékel semmit a külső világból), és a robot folyamatosan halad előre. OnRev(OUT_AC, 75); Most már eleget haladt előre a robotunk, szóval jelezzük neki, hogy fordítsa meg a motorok forgás irányát hátrafelé. Mint láthatjuk nem kötelező, hogy ezt a parancsot egyenként adjuk ki, mivel módunk van rá, hogy akár két kimeneten megjelenő parancsot is kiosszunk az OUT_AC utasítással. Wait(4000); Ismételten 4 másodperc várakozás következik. Off(OUT_AC); És leállítjuk mind két motort. A programunk működése tehát: A motorok forognak 4mp előre és 4mp hátra majd megállnak. Bizonyára feltűnt, hogy a programozó környezetben a szövegek automatikusan elszíneződnek gépelés közben, így segítve a program íróját a munkában. (Ezeket a színeket tetszőlegesen módosíthatjuk a beállítások menüben.) A PROGRAM FUTTATÁSA Elsőként meg kellet írni a programot, majd le kell fordítani (ez a folyamat átalakítja a forrás kódot, hogy gép számára is érthető legyen) és átküldeni a robotba az USB kábel vagy a BLUETOOTH segítségével. Itt látható gombok segítségével tudjuk fordítani, átküldeni, futtatni, és megállítani a programot. A második gomb megnyomásával, le tudjuk ellenőrizni, hogy találhatóak e hibák a programban, és hogy sikerült e lefordítani és átküldeni az adatainkat. Ha ezzel megvagyunk, futathatjuk a programunkat.(hogy ezt megtehessük, menjünk a MyFiles OnBrick menübe >Software files ->run simple_1 program) Emlékezzünk rá,hogy a programunk az NXT modulban ugyan azt a nevet viseli, mint amit az NXC-ben adtunk neki. A programot két féle képen tudjuk futtatni. Automatikusan a CLRT+F5 gombkombináció vagy indíthatjuk a letöltés után zöld gomb megnyomásával is. A CTRl+F5(vagy a zöld gomb) hatására indulnia kell a robotnak.amennyiben ez nem sikerült, ellenőrizzük át a vezetékeket. HIBÁK A PROGRAMUNKBAN Amikor programot készítünk nagy eséllyel hibákat is vétünk. Ezeket a hibákat a fordító képes megtalálni és jelezni számunkra, az oldalunk alján, ahogy az alábbi képen látható. Oldal8
A hiba kereső automatikusan kiválasztja az első hibát.(pl. rosszul lett begépelve az OFF parancs) Amennyiben több hiba is található a, az üzenetre kattintva kijelölődik a hibás programrész. Gyakori, hogy a program elején vétünk valami nagy hibát, így hogy időt spóroljunk ajánlatos, először kijavítani ezt majd ismételten lefordítani. A hibák kiküszöbölésben további segítség lehet a színes betűk figyelembe vétele, gyakran ennek áttekintésével szinte azonnal kiszúrhatjuk a félregépelés helyét. Viszont akadnak olyan hibák is, amelyeket a program nem tud érzékelni, mint például amikor csak az A és a C kivezetésekre (portokra) kötünk motorokat és az OUT_B parancsot használjuk. A SEBESSÉG VÁLTOZTATÁSA Ahogy láthattuk az előző program futtatásakor a robotunk túl gyorsan mozgott. Hogyan orvosolhatjuk ezt a problémát? A sebesség változtatásához elegendő, hogy átírjuk a második paramétert a zárójelben. Ezeket a számokat 0 és 100 közötti értékekre állíthatjuk. A 0 álló helyzetet jelent a 100 pedig a 100% sebességet. A következőkben láthatjuk az előző programunkat módosítva, melyben a robotunk lassabban mozog. Oldal9
ÖSSZEFOGLALÓ Ebben a fejezetben megírtuk az első programunkat az NXC nyelv és a BricxCC használatával. Most már tudjuk, hogyan kell programot írni, lefordítani azt és beletölteni a robotunkba. A BricxCC rengeteg tulajdonsággal bír viszont ebben a könyvben csak az alap funkcióival ismerkedünk meg. Amennyiben mélyebben szeretnénk megismerkedni ezzel a programozó környezettel, úgy ajánlatos letölteni a programhoz kapható további leírásokat. Megtanultuk továbbá az NXC nyelv legfontosabb elemeit. Megismerhettük a main eljárás felépítését,és az alap motorvezérlő parancsokkal mint a :OnFwr(),OnRev(), és az OFF() valamint a Wait() várakoztató utasítást. Oldal10
II. ÉRDEKESEBB PROGRAM KÉSZÍTÉSE Az első programunk nem volt valami érdekfeszítő, ezért második lépésként létrehozunk valami bonyolultabb mozgást. Ezt a lépések számának növelésével, és az NXC nyelv lehetőségeinek használatával érjük el. FORDULÓ MOZGÁS KÉSZÍTÉSE A robotunkat forduló mozgásra késztethetjük az egyik motorunk lefékezésével vagy a fordulási irány változtatásával. Tehát nincs más feladatunk, mint, hogy begépeljük, betöltjük és futtatjuk a programot. A következő példa hatására 90 0 fordulást hozhatunk létre, úgy hogy először mind két, majd csak az egyik motort forgatjuk meg. Kipróbálhatunk több különböző számot, mint például 500-at a késleltetésben (Wait()) mellyel pl. 90 o fordulás hajthatunk végre. (Ez persze függet a felülettől is melyen a robotunk halad) Az értékek egyszerűbb változtatásához előnyösebb, ha neveket használva azok értékei módosítjuk. Ezt az NXC ben konstansok használatával valósíthatjuk meg, melyet a következő programban láthatunk. Az első két sor a konstansok definiálása, melyeket ezek után tetszőlegesen tudunk használni a programunkban. Konstansok definiálása előnyös mert: ez átláthatóbbá teszi a programunkat, könnyebben tudjuk kicserélni az értékeket. Oldal11
UTASÍTÁSOK ISMÉTLÉSE Most próbáljunk meg olyan programot írni melyben a robot négyszög alakban mozog. Ahhoz hogy ez létre jöjjön, a következő lépéseket kell elvégeznünk: előrehaladás, fordulás 90 o -ban, előrehaladás még egyszer, fordulás 90 o -ban, stb. Ezt a programrészt többször,(4x) egymás után írva, készíthetünk olyan programot, amely egy feladatot ismétel. Ettől azonban van egy egyszerűbb lehetőség, az utasítások ismételtetésére szánt repeat utasítással. A szám, amely a repeat parancs mellett található jelenti, hogy hányszor kell ismételni a feladatokat. A repeat ciklus csak azokat a parancsokat képes megismételni melyek az utasításhoz tartozó {} jelek közé vannak írva. Egy következő példaként, készítsünk egy programot, amely elvégzi az előző feladatot 10 szer. Oldal12
Ebben a programban a repeaten belül találhatunk még egy repeatet. Ezt egymásba épült ciklusoknak hívjuk. Lényegében a működési elve ugyan az mint az előzőé, először belép a program a belső ciklusba majd miután 4 szer végighajtotta a feladatok kilép, és újból indul amíg a külső ciklus 10 szer végig nem ér, Tehát valójában 10x4 alkalommal hajtódik végre. Ahogyan az előző esetnél itt is fontos figyelnünk a {} jelekre, különben könnyen végtelen ciklust hozhatunk létre. repeat { repeat { Utasítások.. } } KOMMENTÁROK HOZZÁADÁSA Ahhoz, hogy a programunk minél áttekinthetőbb legyen, szükséges hogy megfelelő kommentárokkal látjuk el. Ezeket a kommentárokat a // jelek közé kell tennünk. A két // jel közötti részt a fordító figyelmen kívül hagyja, így ha véletlenül oda írunk program részeket, azokat nem hajtja végre. Amennyiben hosszabb kommenteket kívánunk hozzáadni, azt a /* */ jelek közé tehetjük. A kommenteknek terméseztessen, más színük van a programtörzsön belül, így könnyen észrevehetjük azokat. Oldal13
ÖSSZEFOGLALÓ Ebben a fejezetben megismerkedhettünk az ismétlések használatára alkalmas REPEAT ciklussal, és azok egyszerű illetve egymásba épített használatával, melynek segítségével, rövid programmal is létrehozhatunk a robot számára hosszan tartó tevékenységet. Figyelem:Mielőtt tovább lépnénk ajánlatos pár gyakorló feladatok készíteni az eddig megismertek alapján. Oldal14
III. VÁLTOZÓK HASZNÁLATA A változók használata rendkívül fontos része a minden programozási nyelvnek. A változók valójában nem mások, mint memória címek melyeken az adott adatokat tároljuk. Ezek az értékek bár különböző helyeken találhatóak, tetszőleges változtathatóak. Lássunk tehát néhány konkrét példát a változók használatára. MOZGÁS SPIRÁL ALAKZATBAN Elsősorban a már előzőkben megírt programunkban kell gondolkodnunk. Hogyan kellene az idő intervallumokat és a motorok forgás irányát átszerkeszteni, hogy spirális mozgási útvonalat kapjunk? Ehhez módosítanunk kell a MOVE_TIME mozgási időt, de hogyan lehetséges ez? Eddig a MOVE_TIME egy konstansként szerepelt, tehát annak értékét nem változtathattuk, ezért most át kell alakítanunk, hogy a programban ezen túl változó ként szerepelhessen. Változókat, ahogyan a C nyelvbe az NXCben is egyszerűen definiálhatunk. Íme, a példa: E programban a számunkra legfontosabb sorokat kommenteztük. Az első ilyen a define a var.. melyben a változót definiáljuk az INT kulcsszó a változó típusát (int egészszám,float törtszám, char karakter,stb.), a move_time pedig a változó nevét jelenti, ez lehet bármi 1-32 karakterig (pl. a) a lényeg, ha kis(vagy nagy) betűvel írtuk akkor a továbbiakban csak úgy hivatkozhatunk rá a programban. Ugyanez fordítva is igaz. A név tartalmazhat számokat is, de csak betűvel kezdődhet. A következő kommentált sorban (set the..) kezdő értéket adunk az amúgy üres (0) változónknak. A harmadik sorban (use the value..) használjuk a változó értékét, tehát ugyan az történik mintha a várakozás értéke 200 lenne (wait(200)) mivel az előbbiekben beállítottuk a move_time változó alap értékét 200 ra. A negyedik sorban a move_time változó értékét növeljük meg a 200-al. Mivel ahogy a program elején észre lehetett venni a programunk ismétlő ciklusban(repeat) van ezért, ez a parancs mindig hozzáad 200 a változó értékéhez. Tehát először 200, másodszor 400, harmadszor már 600 a move_time értéke, stb. amíg 50 szer meg nem ismétlődik. Oldal15
A változónk értékét nem csak a + paranccsal módosíthatjuk, hanem szorzással (*=), kivonással (-=) és osztással (/=). (Ha maradékos osztás történne, akkor a program felkerekíti az értéket) Nem csak ilyen módon változtathatjuk a változóinkat, hiszen tetszőlegesen végezhetünk bármilyen matematika műveletet akár két vagy több változó között illetve készíthetünk akár összetett egyenleteket is. A következő példában nem fogunk tapasztalni semmilyen változást a roboton, kizárólag a NXT tulajdonságait, programozási lehetőségeit szemléltetjük. Az első két sorban láthatjuk, hogyan tudunk egy sorban egy vagy több változót is deklarálni, illetve mind három változót deklarálhattuk volna egy sorban is. A változó mely neve (values)mellett a [] szerepel, tömbök deklarálására szolgálnak, melynek segítségével egy változóban több értéket tárolhatunk (ennek megértéséhez ajánlatos a programozási alapok vagy legalább a matematikai mátrixok ismerte). A tömb egyes elemeit zárójelekbe írt számokkal tudjuk elérni. Az NXC-ben integer (egész szám) tömböt tehát a következőként hozhatunk létre: int név[]; A 12. sorban találhatunk egy parancsot melynek hatására a 10 elemű tömböt, 0-val tölti fel. ArrayInit (values,0,10); VÉLETLEN SZÁMOK Az eddigi programokban előre meghatároztuk, hogy a robotunk konkrétan mit tegyen. Viszont a robot mozgását érdekesebbé tehetjük azzal, ha úgy írjuk meg a programot, hogy ne tudjuk előre mi is fog lenni a következő lépése. Az NXC-ben módunk van véletlenszerű számokat generálni, melyet kiválóan használhatunk erre a célra. A következő programban a robotunk egy véletlenszerű úton fog haladni, úgy hogy az előrehaladás valamint az elfordulás ideje random módon lesz meghatározva. Oldal16
A programban definiáltunk két változót melyek értékét véletlenszerűen határozzuk meg. A random(600) azt jelneti, hogy a számok melyeket ez a parancs készít 0 és 600 közötti értéket vehetnek fel, és ezek minden egyes hívás után különbözőek. Az egyszerűsítés végett ezt a parancsot így is használhattuk volna wait(random(600)). Itt is észrevehettük, hogy a programunk magja ciklusba van helyezve (while-ciklus). Ami azt jelenti, hogy a programunk mind addig fut amíg az állításunk igaz(true). Erre most jó páran kérdezhetik milyen állítás? Mivel valójában semmilyen kivizsgálást nem végzünk ezért a true értékünk soha sem fog false-ra (hamisra) változni. Ezt a ciklust akkor használjuk, ha végtelen programot akarunk készíteni, és a programból csak a NXT agyon található gomb megnyomásának(sárga) segítségével tudunk kilépni. A while ciklus működés hasonló a repeatéhozz azzal, hogy az utóbbi egy bizonyos szám eléréséig ismétli a zárójelek közé fogott parancssorokat. Itt viszont mindaddig ismétlődik a ciklus, amíg a while parancs melletti zárójelben található feltételvizsgálat igaz. (feltétel vizsgálat a következő fejezetben) ÖSSZEFOGLALÓ Ebben a fejezetben tanulhattunk a változók használatáról és a tömbökről, melyeket tetszőlegesen felvehetünk a következő értékek szerint: int egész szám,(mely lehet short rövid illetve long hosszú), byte 0 vagy 1, bool igaz(true) vagy hamis (false) és string karakterlánc,szöveg. Továbbá megismerhettük a véletlenszerű számok készítésének módját, mellyel érdekesebbé tehetjük a robotunk mozgását, illetve megtudtuk, hogyan készíthetünk végtelenített ciklusokat. Oldal17
IV. VEZÉRLŐ UTASÍTÁSOK Az előző fejezetekben láthattuk hogyan lehet alkalmazni a repeat és a while ciklusokat. Viszont van úgy hogy ezekkel az utasításokkal nem lehet minden problémát megoldani ezért meg kell ismerkednünk a vezérlő utasításokkal. Ebben a fejezetben tehát a vezérlő utasításokkal ismerkedhetünk meg. AZ IF FELTÉTELES UTASÍTÁS Néha megesik, hogy program egyes elemeit csak valamilyen feltételtől függően kellene végrehajtani. Az ilyen problémák megoldására használjuk a feltételes (if) utasítást. Az egyszerűbb érthetőség miatt egyből egy példa segítségével szemléltetjük a működését. Ismét az előzőekben használt programot vesszük alapul, azonban teszünk bele egy csavart. A robot halad egyenes vonalban, majd elfordul jobbra vagy balra. Hogy ezt megtehessük, szükségünk van ismét a véletlen számokat generáló parancsra. Felveszünk egy random számot, amely lehet pozitív vagy negatív, amennyiben a szám kisebb, mint nulla a robot jobbra fordul, ellenkező esetben pedig balra fordul. Íme, a program: Az if feltételes utasítás első ránézésre hasonlít a while-ra. Amennyiben a if melletti zárójelben található feltétel igaz, akkor a zárójelek közötti parancsok utasítások végrehajtódnak, ellenkező estben a program tovább lép. Pontosabban csak lépne, ugyanis módunk van rá hogy az if(ha,amennyiben) utasítás után else (különben) parancsot tegyünk, ilyenkor amennyiben az else előtt található if(ek) nem teljesül(nek) akkor az else hajtódik végre. De vegyük át a konkrét példát, hogy még világososabbá váljon a dolog. A random() parancs értéka 0-val megegyező vagy eltérő lehet, így a random()>=0 kérdés vagy igaz, vagy hamis lehet, és ettől függően vagy belép az if-be vagy ugrik az else-re. A vizsgálódáshoz további összehasonlító parancsot használhatunk. Oldal18
== egyenlőség <kisebb <= kisebb vagy egyenlő >nagyobb >= nagyobb vagy egyenlő!= nem egyenlő valamint készíthetünk olyan feltételt is ahol több kivizsgálást végzünk, ilyenkor használhatjuk az && (jelentése és), (jelentése vagy) uatasításokat. Íme egy példa: mindig igaz mindig hamis igaz ha ttt nem egyenlő 3-al igaz ha ttt 5 nél nagyobb és 10-nél kisebb igaz ha aaa vagy bbb (vagy mindkettő)egyenlő 10-el A DO UTASÍTÁS A soron következő utasításunk a DO. Melynek a következő az alapszerkezete: Az utasításainkat a Do parancs után következő két zárójel közé kell beírnunk, melyek abban az esetben hajtódnak végre ha a feltételünk teljesül. A while után következő zárójelbe kell beillesztenünk a feltételünket melyeket ugyan úgy kell felállítanunk mint ahogy az IF feltételei esetén tettük. A következő példában a robot 20 másodpercig mozog véletlenszerűen, majd megáll. Oldal19
A programunk tehát úgy működik, hogy a véletlenszerűen felvett idő intervallumokat összeadja, és ha ezek összértéke eléri a 20000-et (20mp)a program kilép a ciklusból és a robot leáll. A while és a do-while ciklus között első ránézésre nem sok különbség látható, azzal, hogy még a while ciklus először tesztel, és csak ha a teszt true akkor hajtja végre, ezzel szemben a do-while ciklus egyszer mindenképp végrehajtódik, hiszen a tesztelés csak ezután történik meg. ÖSSZEFOGLALÓ E fejezetben megismerkedhettünk két új vezérlő utasítással,az if-el és a do-while-al. Az eddig megismert utasításokkal együtt használva komoly összetett, mégis ugyanakkor rövid és áttekinthető programok írására nyílik módunk. Figyelem: Ezeknek a parancsoknak a megértése létfontosságú a könyv folytatásához,így ajánlatos itt egy kis pihenőt tartani és minél több példaprogramot létrehozni. Amennyiben az utasítások megértése gondot okoz, úgy érdemes az interneten algoritmikus-grafikus leírást keresni, ahol ábrákban magyarázzák el ezek működését. Oldal20
V. ÉRZÉKELŐK Természetesen az NXT-re nem csak motorokat, hanem érzékelőket is tudunk kapcsolni, melyekkel az eszköz további alkalmazási területeit bővíthetjük. Mielőtt tovább léphetnénk, a könyv megkezdésekor említett gyári tribot-ra szereljük fel(amennyiben ezt eddig nem tettük meg), a gyári csomagolásban kapható három szenzort. VÁRAKOZÁS AZ ÉRZÉKELŐRE Kezdjük az egyik legegyszerűbb programmal, ahol a robot addig marad mozgásban, amíg valamit meg nem érint. Itt két fontos sorra kell odafigyelnünk. Az első sorban a robotnak elmondjuk (SetSenzor), hogy mely szenzort használja. IN_1 azt jelzi a rendszernek, hogy mely bemenetre kapcsoltuk az érzékelőnket. A további bemenetek IN_2,IN_3 és az IN_4. SENSOR_TOUCH azt jelenti, hogy érintő szenzort használunk. Ha például fényérzékelőt használnánk, akkor a LIGHT_SENSORT kellene beírnunk. Az érzékelő beállítása után a robotunk elindul amíg (until) az neki nem megy valaminek, ekkor az értéke 1 lesz (eddig 0 volt) és a motorok leállnak. Oldal21
LEHETŐSÉGEK AZ ÉRINTŐ ÉRZÉKELŐVEL Az érintő szenzor alaptulajdonságainak megismerése után, készítsünk, egy bonyolultabb programot. A következő példában a robot halad előre, amíg meg nem érint egy tárgyak. Ezek után kisé hátrál, majd elfordul és továbbhalad. Az előző példától eltérően a szenzort egy egyszerűbb paranccsal állítjuk be, majd a robot elindul,ekkor belépünk a WHILE ciklusba melyben az IF teszteli a szenzort, ha annak értéke 1 akkor a motor hátramegy (300ms) és jobbra fordul (300ms), majd továbbhalad. FÉNYÉRZÉKELŐ Az érintés érzékelő mellé feltehetünk más szenzorokat is az eszközünkre, mint például fényérzékelőt,hangérzékelőt, vagy ultrahangos érzékelőt. A fényérzékelő képes segéd fény kibocsájtására, illetve annak, szintjének továbbá a környezet fényének mérésére. A segédfény visszaverődésének mérését akkor tudjuk hasznát venni, ha például egy földre rajzolt vonalat kell követnünk. Ezt fogjuk tenni a következő példánkban. Ehhez a teljesen befejezett tribotra van szükségünk. (A képen látható formában) Oldal22
Továbbá szükségünk lesz, egy pályára ahol egy fekete vonalat tudunk követni, melyet szintén a légó szettben találhatunk meg. Az alapelv szerint a robotnak képesnek kell lennie követni a fekete vonalat, úgy hogy a fekete vonal határait figyeli. Amennyiben a vonal felső részét észleli (fehér felület nagy fényvisszaverő érték) úgy befelé fordul, ha viszont a vonal belső határát (fekete felület kis fényvisszaverő érték) érzékeli, úgy kifelé fordul. A kör középpontjától számítva. Íme, az egyszerű program, amely elvégzi a feladatot. A program először konfigurálja a harmadik bemenetet, mint LIGHT_SENSOR (fényérzékelő). Következőben beállítja a robot előre mozgását, és belép a ciklusba a program. Amint a fény értéke több mint 40 (használhatunk, konstansokat erre az értékre mellyel egyszerűen tudjuk cserélgetni ezt az értéket, ugyanis ez az érték nagyban függ a tér fényviszonyaitól) akkor az egyik motor forgásirány változtatásával ismét ráfordul a helyes útvonalra. Amint kipróbáltuk a kész programot,látható válik Oldal23
hogy a robot mozgása nem túl egyenletes. Próbáljuk meg hozzáadni a Wait(100) parancsot az until elé, így a robot jobban fog haladni. Itt azonban meg kell említenem, hogy a robot csak az óramutató járásával ellentétes irányban tud mozogni. Ahhoz hogy a program bármerre elindulhasson, ettől bonyolultabb programot kellene írni. Ha a környezet fényerejét szeretnénk megvizsgálni, ahhoz először ki kell kapcsolnunk a segédfényt, a következő parancsokkal. HANG ÉRZÉKELŐ A hangérzékelő használatával könnyedén alakíthatjuk át akár a tapsolásunkat, vezérlő utasítássá. Az elkövetkezőkben egy programot fogunk készíteni, mely egy hangos zajra várva indítja el a robotot mindaddig, amíg ismételt hangot nem hall. (ha még eddig nem tettük meg, csatlakoztassuk a hang szenzort a 2-es portra). Definiáltuk a THRESHOLD konstanst és egy alias-t (álnevet) a SENSOR_2-nek, a main(fő) programrészt úgy konfiguráltuk,hogy olvasson be adatot a PORT 2-ről a hangszenzor segítségével és lépjen be a végtelenített ciklusba. Az until parancsnál a program várja a hangerősség változását melynek értékét a THRESHOLD al hasonlítja össze.(azért hogy ne keljen mindig kiírni a SENSOR_2 nevet, mic nevű alias-ra hivatkozunk) Ha valami hangot hall a robot (mely nagyobb THRESHOLD-tól) megindul előre, amíg egy ismételt hang meg nem állítja. A wait várakozást be kellet iktatni, mert különben a program azonnal elindulna és leállna. (ez azért van, mert az NXT nagyon gyorsan dolgozik és nem vizsgál két until között). Ha megpróbáljuk kivenni Oldal24
az egyik vagy másik Wait-et, azonnal érthetővé válik a dolog. Alternatív megoldásként megpróbálhatunk olyan programot írni, melyben a wait-ket kicseréljük while-ra. Figyelem:Ne feledjük el hogy, az előző két eszköz értékei csak 0 és 100 közötti számokat vehetnek fel. ULTRAHANGOS ÉRZÉKELŐ Az ultrahangos érzékelő gyakorlatilag úgy dolgozik, mint egy szonár. Kiküld, egy magas frekvenciájú jelet,és érzékeli a tárgyakról visszaverődött részeit, és a két jel között eltelt időből kiszámítja a távolságot. Ez az előző szenzoroktól eltérően nem analóg, hanem digitális, ami annyit jelent, hogy az egység képes önmaga az adatok mérésére és feldolgozására. Így kész adatokat küld a rendszerünknek. Az ultrahangos érzékelő segítségével készíthetünk olyan programot, amelyben a robot képes megállni mielőtt neki ütközne valaminek, ellentétben azzal, ahogy az eddig az érintő szenzor esetében volt. A program beállítja a 4. portot a digitális US érzékelőnek (SetSensorLowspeed), majd belép a végtelen ciklusba, amely addig fut, amíg meg nem közelített valamit körülbelül 15 cm-re (While(SensorUs(IN_4)>NEAR)), ezek után hátrál egy kicsit és folytatja, előröl a ciklust. ÖSSZEFOGLALÓ Ebben a fejezetben láthattuk hogyan dolgoznak egyes szenzorok, hogy hogyan használhatjuk ezeket az eszközöket a until és a while utasítások kombinálásával. Figyelem: Ismételten ajánlatos most is egy kis kitérőt tartani és több lehetséges programot végigcsinálni, hogy jobban megérthessük és begyakorolhassuk a szenzorokról tanultakat. Oldal25
VI. FÜGGVÉNYEK ÉS ELJÁRÁSOK Az eddigi programjainkban mindössze egyetlen eljárást használtunk, ez volt a main vagy más néven a FŐ programrész. Viszont ahogy C nyelvben úgy az NXC-ben is módunk van többelemes összetett programokat készíteni, függvények és eljárások használatával. Ezek segítségével az ismétlődő programrészeket, továbbiakban nem kell számtalanszor megismételni, hanem elég csak a hozzájuk rendelt nevet meghívnunk. A függvények és eljárások segítségével egy bonyolultnak tűnő programot is egyszerűen el tudunk készíteni, mely így mindenki számára könnyen áttekinthető és gyorsan értelmezhető lesz. ELJÁRÁSOK Az NXC programnyelv 255 saját egyedi eljárást tartalmaz. A legfontosabb a main eljárás melyet mindig muszáj, megnyitnunk mivel ez képezi a programunk törzsét. A további eljárások a program betöltése után kerülnek használatba, melyeket csak a main törzsből lehet meghívni. Lássunk egy konkrét példát, hogy érthetőbb legyen az eljárások használata. Készítünk egy programot melyben a robot négyszög alakzatban halad, mint ahogy azt egy előző példánkban tette. Viszont ebben az esetben, ha ütés éri az érintés szenzort, akkor a robot erre reagál. Mind ezt nehéz lenne megoldani eljárások nélkül, mert a robotnak két dolgot kellene egy időben csinálnia (elfordulnia ás a szenzort vizsgálni). Tehát jobb megoldás, ha két eljárását használunk, egyet a mozgásra (négyszögben mozgás) és egyet a szenzor figyeléséhez. Íme, az így készült program. Oldal26
A fő (main) programrészben nem foglalkozunk, mással csak beállítjuk a szenzor típusát és elindítjuk mindkét eljárást (move_square,check_sensors), melyeknek átadja az irányítást, ezzel a main eljárás véget is ért. A move_square eljárás a robotunkat négyszög alakzatban mozgatja, egy végtelen ciklusban, még a check_senzor eljárásunk az érintő érzékelőt figyeli, és ha bármi hozzáér, a robotunkat elvezeti az akadálytól. Fontos megjegyezni, hogy amennyiben az eljárásokat egy időben indítjuk el, az nem várt eredményhez vezethet, mivel így mindkét eljárás egyszerre próbálná meg vezérelni a motorjainkat, hogy orvosoljuk ezt a problémát, deklarálunk egy változó típust, ez a MUTEX (mutal exclusion). Ezt a változót csak az ACQUIRE(elindít) és a RELEASE(megszakít) függvényekkel használhatjuk, melyeket a kritikus pontokra írva (a vezérlés kezdetére és végére illesztve)elérhetjük, hogy egy idő intervallumban,csak egy eljárás vezérelheti a motorokat. Ez a mutex típusú változót más néven szemafornak (útirányjelző lámpának) is szokták hívni, és ezt a programozási módszert is szintén ezzel a névvel illetik. FÜGGVÉNYEK Néha megesik, hogy egy bizonyos program részre többször is szükségünk van a program során. Erre az esetre nyújt segítséget függvények használata, melyre annak nevének megadásával hivatkozhatunk. Lássunk egy példát a függvények használatával. Ebben a programban egy olyan függvényt deklaráltunk melyben a robotunk elfordul. Ezt a függvényt a program fő részében háromszor is meghívjuk. Megfigyelhetjük, hogy a függvényneve mellett szám is szerepel a zárójelekben, melyekkel a motor erőségének értékét adjuk át. Amennyiben nem kívánunk, értéket átadni úgy a függvényben konkrét értékeket írunk be és elhagyjuk a zárójeleket. A a függvény használatának legnagyobb előnye nem a gyorsaság, vagy az egyszerűség, hanem az így készült program memória foglalásában rejlik. Hiszen az így a készült programunk kisebb helyet foglal. Ha azonban a függvényünk rövid, akkor célszerű inkább az INLINE függvényt használni az előző megoldásunk helyett. Ebben a megoldásban az adataink nem lesznek elkülönítve, tárolva, viszont Oldal27
egyszerű több helyen használni. Az INLINE függvény több helyet foglal a memóriában, de így nincs limitálva a függvényeink száma. A deklarációja a következően néz ki: Az inline függvény deklarálása, használata és hívása ugyan úgy működik, mint az egyszerű függvény. A következő példában megláthatjuk az inline függvény használatát. Módosíthatjuk úgy is az előző példát, a motor ereje és a késleltetés ideje csak a main programrészben legyen megadva. Oldal28
Megjegyezném, hogy a zárójelekben található értékeket csak a main függvényben használjuk, ezért az érték átadás szabályai szerint, ahány változót akarunk átadni (mindig ugyan annyit kell),annyi új változót kell felvenni a függvény neve után található zárójelben. A példánkban, mint integer változó deklaráltuk őket. Amennyiben több változóra lenne szükségünk, úgy vesszővel elválasztva tetszőleges számban tehetjük azt. Továbbá azt is fontos megjegyeznem, hogy függvényt mint void kell felvenni, ami annyit jelent, hogy a függvény nevének nincs visszatérési értéke. További lehetőségeket a függvényekről NCX guide leírásban találhatunk. MAKRÓK DEFINIÁLÁSA Az NXC-ben definiálhatunk makrókat is,(nem összekeverni a BricxCC makrókkal) melyet a #define kulcsszóval kezdünk majd nevet adunk neki, ezek után felírjuk a programrészt. Ismételten felírjuk még egyszer az előző programot, de most makrók segítségével. Oldal29
Miután felírtuk a #define kulcsszavat felírjuk a nevet, ezek után következik az utasítás, melynek egy sorban el kellene férnie, amennyiben nem fér bele a sorba úgy / jelet ütünk, és a következő sorba írjuk a parancsunkat. A define parancsszóval nem csak egy, hanem több makrót is készíthetünk. A következő példában ezt szemléltetjük melyben négy makrót is használunk, egyet-egyet az előre és hátra mozgáshoz, valamint egyet-egyet a jobbra és balra forduláshoz. A fenti példában szemet szúrhatott, hogy ahogyan a függvényeknél és az eljárásoknál, itt is módunk van rá, hogy a konkrét vezérlő értékeket a main program részben adjuk meg. ÖSSZEFOGLALÓ Ebben a fejezetben megismerkedhettünk az eljárásokkal, a függvényekkel, az inline függvénnyel és a makrókkal, melyek bár használata eltér egymástól, alkalmazásuknak célja azonban közös, hogy megkönnyítsék a program készítését, áttekinthetőbbé tegyék a forrás kódot, és hogy az amúgy véges befogadó képességű memóriából minél kevesebb helyet foglaljanak el. Az eljárások egyszerűen alkalmazhatóak, viszont némely helyzetben nem árt vigyázni, nehogy olyan parancsokat osszunk, ki melyeket nem lehet végrehajtani. A függvényeket olyan esetekben célszerű használni, amikor nagyobb kódrészeket többször is használnunk kell a programunk során, még az inline függvény esetében a kisebb kódok ismétlésének elkerülése a cél. Végül a makrókkal ismerkedhettünk meg, melyeket nagyon kis programrészek használatát könnyítik meg. Most hogy átvettük az előző fejezeteket, és jól átdolgoztuk őket, megszerezhettük a kellő tudást hogy építsünk, és vezéreljünk egy saját gyártású robotot. A következő fejezetekben az eddigi alapismeretekre építkezve mélyedünk bele az egyes elemek mélyebb ismeretébe, melyekkel tovább bővítjük a lehetőségeinket. Oldal30
VII. HANG SUGÁRZÁSA Az NXT modellünkben a sok okos alapeszköz mellet találhatóak beépített hangszórók is melyekkel különböző zene és hang fájlok lejátszására vagyunk képesek. Ez a tulajdonság akkor bizonyul hasznosnak amikor, szeretnénk, hogy a program futása közben valami féle visszajelzést kapjunk a gép működéséről. HANG FÁJL LEJÁTSZÁSA A BricxCC ben található egy beépített hang konverter mely a WAV fájlokat átalakítja RSO-ra. (Tools - >Sound conversion) Ezek után az átalakított fájlt el kell tárolnunk a NXT belső memóriájába (Tools -> NXT explorer) és lejátszatnunk a következő paranccsal: Az argumentumok helyére be kell írni a fájl nevét (filename), a hangerejét (0 és 4 között lehet), és az ismétlések számát(1 esetén ismétli a fájlt, 0 esetén csak egyszer játssza le). Ez a szép ki program egy olyan dalt játszik le amit bizonyára mindenki ismer, melyet a standard kattintás zenéjével készít el. (a szám: Shave and haircut). Itt is terméseztessen, makrókat használunk az egyszerűbb programozás végett. A kész programba próbáljuk meg módosítani a hang erejét és idejét. Oldal31
HANG JÁTSZÁSA A NXT-nk nem csak hang fájlok lejátszására képes, hanem hangokat is képes lejátszani, hogy ezt megtehessük a következő parancsot kell használnunk Melyben négy argumentumot fedezhetünk fel. Az első a hang frekvenciáját, a második a hosszát(ugyan úgy adhatjuk meg mint a wait esetében),a harmadik a hangerő és az utolsó az ismétlés. PlayTone (frekvencia, hossz) parancsot szintén használhatjuk, ebben az esetben a hangerő az NXT alapbeállításától fog függeni, és az ismétlés inaktív lesz. Íme a hangjegyek táblázata: Ahogyan a PlayFileEx parancsnál, az NXT itt sem fogja megvárni hogy befejeződjön a hang, tehát tudunk több hangot egyszerre is megszólaltatni illetve a különválasztáshoz várakoztatásokat kell használnunk. Íme, egy példa: Oldal32
Könnyedén tudunk így zene részleteket készíteni a Brick Piano segítségével. Ha zenét szeretnénk lejátszani a robot mozgása alatt, jobb, ha eljárásokként oldjuk meg ezt. Íme, egy program melyben a robot előre-hátra halad miközben zene szól. ÖSSZEFOGLALÓ Ebben a fejezetben megtudhattuk hogyan lehet zene fájlokat lejátszani illetve hangokat kibocsájtani, valamint megtekinthettük hogyan különíthetjük el a hangokat és a vezérlést eljárások segítségével. Oldal33
VIII. A MOTOROK MÉLYEBB ISMERETE Eddigiekben a motoroknak csak az alap lehetőségeit ismerhettük meg holott, számtalan megoldás és parancs létezik, melynek segítségével még precízebbé tehetjük a működésüket. Ebben a fejezetben megismerkedünk a következő parancsokkal: ResetTachoCount, Coast (Float), OnFwdReg, OnRevReg, OnFwdSync, OnRevSync,RotateMotor, RotateMotorEx, PID. LÁGY LEÁLLÍTÁS Eddigiekben a motorok leállításához az OFF parancsszavat használtuk mely azonnali hatállyal megállította azt, a fékek bekapcsolásával. Ettől a megoldástól azonban van egy lágyabb megoldás is, ahol a fékek használata nélkül áll le a motor. Erre a Float() vagy a Coast() utasításokat használhatjuk, melyek gyakorlatilag levágják az áramot. Íme, egy példa a használatára. Az először a robotot fékekkel majd fékek nélkül állítjuk meg. A különbség nem biztos, hogy nagyban érzékelhető, viszont nagyobb robotoknál és probléma megoldásoknál már számottevő lehet. ÖSSZETETT VEZÉRLÉS Az OnFwd() és a OnRev() a két legegyszerűbb rutin a motorok mozgásra bírásában, azonban a NXT szervo motorjai ennél jóval nehezebb és összetettebb feladat elvégzésére is képesek az intelligens belső felépítésüknek köszönhetően. Precíz PID vezérlésével lehetőségünk van a pozíció és a sebesség rendkívül pontos beállítására. Amennyiben azt szeretnénk elérni, hogy a robotunk szinte tökéltessen, egyenes vonalban haladjon, módunk van a motorokat szinkronizálni (syncronization), a COUPLE utasítással pedig képesek teljesen együtt mozogni, ha az egyik kerék lelassul a másik is követi, ha az egyik leáll, a másik is leáll vele együtt. OnFwrReg(kimenet,sebesség,regmode) parancs a motorunkat vezérli a kimenet, sebesség függvényében, még a vezérlés mórját(regmode) a következők lehetnek OUT_REGMODE_IDLE,OUT_REGMODE_SPEED,OUT_REGMODE_SYNC. Ha az IDLE lehetőséget választottuk, akkor nem lesz úgynevezett visszacsatolásos vezérlés,a SPEED módban a NXT mindig állandó sebességen próbálja tartani a motorokat, a SYNC módban pedig az előzőekben említett COUPLE tulajdonság szerint működik. OnRevReg() ez a parancs teljesen úgy működik, mint az előző csak ellentétes irányban. Oldal34
Ez a program bemutatja a különbségeket a vezérlések között. A futás közben próbáljuk a kezűnkkel megfogni a kereket, hogy lássuk, mi történik. Elsőként az IDLE mód működik, ahol nem történik semmi extra dolog, a második a SPEED mód, melyben lelassíthatjuk a kerekeket, ekkor az NXT az erő növelésével próbálja meg korrigálni a sebességcsökkenést, és utoljára maradt a SYNC mód melyben, ha lefogjuk az egyik kereket, a másik is követni fogja. OnFwdSyny(kimenet,sebesség,forgpont) parancs megegyezik az OnFwdReg() paranccsal,csak szinkron módban, viszont itt a forgpont paraméterben megadhatjuk a fordulat pontját is (-100 tól 100 ig) OnRevSync() ugyan az mint az előző parancs csak fordított irányban. A következő példában bemutatjuk ezeket a parancsokat. Oldal35
Végezetül bebírjuk állítani a motor forgását fokokban (0-360 o ). A következő utasításban hozzáférünk a sebesség és fokok változtatásához, amennyiben a sebesség és a fok azonos előjelű úgy a motor előreforog, ha viszont eltérő, akkor visszafelé forog. RotateMotor(kimenet,sebesség,fok) parancs forgatja a motort a kimenet, a fok és a sebesség erejének(1-100) a függvényében. RotateMotorEx(kimenet,sebesség,fok,forgpont,szinkron,stop) egy utasítás a precíz irányításra. Legyen például az A,C kimeneten két motor szinkronizálva, a fordulás pont alapján (-100 tól 100 ig), a szinkron boole értékekkel (igen-true, nem-false), majd használjon féket amennyiben tejesítette a kívánt fokot, a stop használatával(igen-true, nem-false). PID VEZÉRLÉS Az NXT következőbe épített lehetőség a PID(propotional integrative derivative - soros kompenzáción alapuló szabályozótípus) vezérlés, mellyel egyszerűen tudjuk irányítania motorunk sebességét és helyzetét. Ez a vezérlés típus az egyik legelterjedtebb és leg hatékonyabb visszacsatolásos irányítási eljárás az automatizációban. A PID szó angol szavak rövidítéséből ered, pontos fordítása helyett annak lényegét fogalmaznánk meg. A PID szabályozó egy lineáris rendszerek szabályozásánál gyakran alkalmazott, soros kompenzáción alapuló szabályozótípus. A PID rövidítés a szabályozó elvére utal, a szabályozó által kiadott végrehajtójel a hibajellel (P: proportional), a hibajel integráljával (I: integral), valamint a hibajel változási sebességével, deriváltjával (D: derivative) Oldal36
arányos tagokból adódik össze. Ezen tagok közül nem mindig valósítják meg mindet, ilyenkor beszélhetünk P, PI, PID szabályozókról. A programunk átadja a vezérlés pontot (R(t)) az eléréshez, elindítva a motor vezérlését (U(t)), mialatt méri annak pozícióját (Y(t)) a beépített kódoló segítségével, és kiszámítja a hibát E(t)=R(t)- Y(t). Ebből láthatjuk miért is nevezzük visszacsatolásos vezérlésnek, mivel a kimeneti pozíció Y(t) függvényében kiszámítja a hibát és ennek alapján kompenzálja a vezérlő U(t) jelet. U(t) = P(t) + I(t) + D(t), ahol P(t) = KP E(t), I(t) = KI ( I(t 1) + E(t) ) és D(t) = KD (E(t) E(t 1)) Ez most összeetetnek, tűnhet, ezért egy példa segítségével talán világosabbá válhat a dolog. Például ha nagyon le akarnánk egyszerűsíteni a dolgot, akkor, beszélhetünk a hajszárító vezérléséről. Képzeljünk el egy hajszárítót melynek 3 fokozata van. Hideg, meleg (15-25 0 ), és nagyon meleg (26-55 0 ). Amint bekapcsoljuk a hajszárítót (pl nagyon melegre) az maximális fordulaton és maximális fűtésen kezd dolgozni, de mivel a fűtés még nem melegedett át, a kifújt levegő hőmérséklete nem elég magas, így lejjebb veszi a fordulatot (visszacsatolt jel). Ezek után viszont értelemszerűen emelkedni kezd a hőmérséklet, így a kimenő hőmérséklet függvényében növelni kell a fordulatot egész a maximálisig, ha még így is nagy a hőmérséklet, akkor a fűtőtest áramellátását kell csökkenteni, teszi ezt mind a kívánt hőmérséklet és a kimenő levegő (visszacsatolt jel) hőmérsékletének függvényében. Bár ez a példa nem tükrözi teljes egészében a PID vezérlést, az alapelvet megérthettük belőle. A vezérlés valójában három értékből adódik össze,a p,i,d. A P(t) gyors vezérlést tesz lehetővé,de nem elhanyagolható hibával, az I(t) tag memóriát biztosít a vezérlésnek,mely az út alatt felhalmozódott hibákat megtartva garantálja a zéró hiba határos egyensúlyt. A D(t) tagunk jövőbe látásra képes (mint a matematikai deriválás), így gyors reagálásra képes. A PID vezérlés megértése kellő alapok nélkül majdnem lehetetlennek bizonyulhat, hiszen ez már egyetemi tananyag. A következő példa segítségével azonban elsajátíthatjuk a használatát. A RotateMotorPID (kimenet,sebesség,szög,ptag,itag,dtag) a motornak különböző mozgását eredményezi a PID függvényében. Próbáljuk ki a következő értékeket: (50,0,0): a motor nem fordul el pontosan 180 0 -ot, az ellensúlyozatlan hiba miatt Oldal37
(0,x,x): proportional tag nélkül a hiba nagyon nagy (40,40,0): ez egy túlhajtott eset, mely azt jelenti, hogy a motor be lett csapva az előre állított beállítás pontjával és visszafordításával. (40,40,90): pontos beállítás,és időnövelés (idő a beállítási pont eléréséhez) (40,40,200): oszcillálást eredményez a túl nagy deriváló tag miatt Több lehetséges érték kombinációt is érdemes kipróbálni, és megnézni, hogy arra hogyan reagál a robotunk. ÖSSZEFOGLALÓ Ebben a fejezetben megismerkedhettünk a motorok további tulajdonságaival, mint a FLOAT,COAST utasításokkal melyek lágyabb leállítást eredményezek, az OnXxxReg és az OnXxxSync parancsokkal a visszacsatolt sebesség és szinkronvezérléshez, valamint a RotateMotor és RotateMotorEx lehetőségeket a motor egyenletes és precíz mozgásához. Megismerkedhettünk a PID vezérléssel is amelynek lehetőségeiről érdemes az interneten leírást keresni. Oldal38
IX. AZ ÉRZÉKELŐK TOVÁBBI LEHETŐSÉGEI Az ötödik fejezetben megismerkedhettünk az érzékelők alap lehetőségeivel, viszont ezeknél a beállításoknál sokkal többet tudnak. Ebben a fejezetben a szenzorok beállítási módjaikkal és típusaival fogunk foglalkozni. ÉRZÉKELŐ MÓDOK ÉS TÍPUSOK A SetSensor paranccsal már találkozhattunk, mellyel beállíthatjuk az érzékelő típusát, valamint annak módját, amely a szenzor működését szabályozzuk. A módot és a típust-szenzorokét különböző féle képen kell beállítanunk, annak fajtájától és felhasználási területétől függően. A típus beállítását a SetSenzorType() paranccsal alkalmazhatjuk ki, a következő lehetőségek szerint: érintés szenzor esetén SENSOR_TYPE_TOUCH, fényérzékelő esetén (a fény be van kapcsolva) SENSOR_TYPE _LIGHT_ACTIVE, hangérzékelő SENSOR_TYPE_SOUND_DB, és az ultrahangos érzékelő SENSOR_TYPE_LOWSPEED_9V. A szenzorok típusának beállítása egy fontos lépés,melyben beállítjuk milyen elektromos ellátásra van szüksége az adott alkatrésznek(fényérzékelőnél led ki-be), illetve digitális eszköz esetén az I 2 C (soros) kommunikáció elindítására. Lehetőségünk van továbbá a régi RCX rendszerekből használni egy-két szenzort, mint a hőmérsékletmérő SENSOR_TYPE_TEMPERATURE, a régi típusú fény érzékelőt SENSOR_TYPE_LIGHT és s fordulat mérőt SENSOR_TYPE_ROTATION. Az érzékelők módjának beállításait a SetSensorMode() utasítással végezhetjük, melyek közül a legfontosabb a SENSOR_MODE_RAW,mely módban a visszakapott érték 0 és 1023 közötti értéket vehet fel. Ezt a durva-nyers (RAW) értéket a szenzor készíti. Ez konkrétan annyit jelent az érintés szenzor esetén, hogy amikor nem történik érintés ez az érték közel 1023,teljes benyomás esetén 50 körül mozog, részleges ütődés esetén 50 és 1000 a kapott szám, tehát RAW módban módunk van érzékelni nem csak az érintést, hanem annak fajtáját is. A fényérzékelő esetében az értéktől függően megállapíthatjuk a fény erejét is (300 nagyon világos,800 nagyon sötét). Mint látható az előző alapbeállításoktól eltérően ahol gyakorlatilag két érték közül választhattunk, itt már precíz értékeket tudunk használni. A következő mód a SENSOR_MODE_BOOL, melyben az értékünk két lehetséges elemet vehet fel ezek a 0 és az 1, a Raw módból átültetve ez azt jelenti, hogy 562 alatt az érték 0, felette pedig 1. Az érintés szenzor esetén ez az alapbeállítás, még a hőmérséklet érzékelőnél a SENSOR_MODE_CELSIUS és a SENSOR_MODE_FAHRENHEIT lehetségesek. A fényérzékelő alap beállítása viszont nem értékben, hanem százalékban (0-100)adja vissza az kapott értékeket SENSOR_MODE_PERCENT, a SENSOR_MODE_ROTATION viszont kizárólag a forgás érzékelőnél használhatjuk. További két érdekes beállítási lehetőség a SENSOR_MODE_EDGE és a SENSOR_MODE_PULSE, mely az átmeneteket hivatott számolni, az alsó állapotból a felsőbe vagy vissza. Például amikor az érintésszenzor alap módban van, akkor csak azt érzékeli, amikor megérintjük, ahhoz hogy ismét jelet generáljon, először el kell engednünk és ismét megérinteni, de mi van akkor, ha számunkra az elengedés pillanata is olyan fontos, mint a megérintésé. Itt ugyebár két jel is keletkezett a kikapcsoltból bekapcsoltba, majd vissza. Ennek érzékelését és feldolgozását segíti a SENSOR_MODE_EDGE amely a SENSOR_MODE_PULSE val ellentétben nem egy hanem két jelnek érzékel minden érintést. Terméseztessen akár egy (pulse) vagy akár kettő (edge) érintést kívánunk megszámolni, előtte nullába kell állítanunk a számlálónkat a ClearSensor()utasítással. Oldal39