A RobotC programozási nyelv

Típusok, típuskonstrukciók

Általános

Mivel a RobotC nyelv a C-re alapul, így a legtöbb tulajdonságuk megegyezik.

Elemi típusok

1. Skalár típusok

Az alaptípusok láttán egyértelmű a rokonság a C nyelvvel. A következő táblázat tartalmazza a lényeges különbségeket.

Típus kulcsszava Leírás Megjegyzés
int Egész szám, -32768 és 32768 közötti értékek. C-vel szemben (ahol implementációfüggő) itt kötötten 16 bites ábrázolás
long Egész szám, -2147483648 és 2147483648 közötti értékek 32 bites ábrázolás
float Lebegőpontos valós szám Azok a proramozási nyelvek illetve környezetek melyek a RobotC célhardvereihez íródnak nem tartalmaznak lebegőpontos ábrázolású valós szám típust, így ezzel a RobotC egyedülálló.
Ennek oka egyébként, hogy ezen robotok vezérlőegysége nem tartalmazza beépítve a lebegőpontos műveleteket, mint a ma használatos számítógépek processzorai, így a nyelv feladata a valós számok használatának megvalósítása.
bool Logikai típus, értéke true vagy false. A C++-os bool típushoz hasonlóan használhatjuk ezt a típust. 1 bájton tárolódik, értéke true esetén 1, false esetén 0. Mivel megvalósítása int alapú, C-hez hasonlóan minden nem 0 érték true-nak felel meg.
char Karakter típus  
string Karakterlánc A C nem tartalmazza ezt a típust beépítve, de a RobotC igen.

Az unsigned típusok a char típus kivételével nem támogatottak. Az unsigned kulcsszó használata egyéb típusoknál warning-ot generál és jelentése figyelmen kívül hagyásával folytatódik a fordítás

2. Mutató és referencia típus(ok)

RobotC-ben nincsenek mutatótípusok és a referencia típus is csak korlátozottan jelenik meg, mivel a nyelvben nincs dinamikus memóriafoglalás, mert nincsen heap
Ennek okai:

Referenciatípus van, de a készítők csak azért tették bele a nyelvbe, hogy lehessen alprogramoknak cím szerint paramétert átadni. Bár a legtöbb nem primitív adatszerkezet illetve algoritmus megvalósításához szükséges mutatók jelenléte egy programozás nyelvben, robotikában rengeteg feladat megoldható nélkülük. Így bár első hallásra ijesztő a pointer típusok hiánya, a nyelv kis robotok programozására jól használható.

Típuskonstrukciók

Vektor

Vektor típuskonstrukciónak RobotC-ben (C-hez hasonlóan) a tömb típus felel meg. Használata a pointerek hiánya miatt azonban módosul oly módon, hogy a tömb méretét a tömb típusú változó deklarálásakor meg kell adni.

task main() { int v[5]; //ez C-ben úgy nézne ki, hogy int* v = new int[5]; }

Többdimenziós vektorok

2 dimenziós vektorok támogatva vanak nyelvi eszközökkel, például

task main() { int v2d[3][3] = {{1,2,3},{4,5,6},{7,8,9}; }

2-nél több dimenziós tömbök rekord adatszerkezettel, vagy címfüggvények használatával képezhetők, de a nyelv nem ad más eszközt a kezünkbe.

Rekord

Megegyezik az ANSI C struct típuskonstrukciós eszközével.

Unió

A C-ben kevesebbek által használt unió típus határozottan jól alkalmazható, ha esetleg alacsonyabb szintű feladatok megvalósításához optimalizált kódot szeretnénk írni.

Típusok robotokhoz

Robotok programozásánál speciális input és output eszközökkel dolgozunk. Input eszközök a robotra szerelt különböző szenzorok, "output" eszközök a robot motorjai, melyekkel mozgatjuk (motorok felhasználása természetesen nem csak a robot mozgatásában merül ki). A roboton található mikrovezérlő alacsonyszintű hozzáférést biztosít ezekhez az eszközökhöz, de egy magasszintű robot-programozási nyelvtől azt várjuk el, hogy ezen egységek egyszerű kezelhetőségét biztosítsa.

Objektumelvű leírásban a Motorok és a Szenzorok is megfeleltethetők egy-egy osztálynak. A Motor osztály példányszintű művelete lehet például, hogy forogjon előre irányba, forogjon hátra irányba, a Szenzor osztálynak példányszintű függvénye lekérheti a szenzor által éppen mért értéket. Ebben a megközelítésben az aktuális robot felépítésnek megfelelően létrehozunk motor és Szenzor példányokat, melyek műveleteit használva érjük el a hardvereket.


A RobotC nem ilyen objektumelvű megközelítést használ egyszerűen azért mert a szűkös erőforrásoknál luxus lenne egy ilyen szintű ábárzolás. Például RobotC-ben nincsen szükség példányok létrehozására, mert kötött hardverek a céleszközök, például a LEGO NXT-nek 3 db motorja lehet (A,B,C) és 4 db szenzort köthetünk rá (S1, S2, S3, S4). Ezért RobotC-ben ezek a példányok statikusan minden programnál létrejönnek.

Motorok

A motorokhoz és beálíltásaikhoz különböző tömbökön keresztül férhetünk hozzá. Legfontosabb ilyen tömb a motor tömb. A motor tömb indexei a különböző motorok azonosítói, az egyes indexekhez tartozó érték a megfelelő motor aktuális sebességét jelenti.

task main () { motor[motorA] = 50; //Az A motor 50-es fokozatra kapcsol }
A tömb értékei -100 és 100 között lehetnek, az indexek előre definiált konstansokkal (pl.: motorA=0, motorB=1) kiválthatók.
Sőt a fejlesztőkörnyezetben beállíthatunk saját nevet is a motorjainknak. Pédául ha az A motorra kötjük a baloldali kereket és a B motorra a jobboldalit, akkor adhatjuk nekik a left és right neveket. Ha ezt a fejlesztőkörnyezetben beállítottuk, akkor programunkhoz automatikusan új sorok adódnak:
# pragma config (Motor , motorA , left , tmotorNormal , PIDControl ) # pragma config (Motor , motorB , right , tmotorNormal , PIDControl ) task main () { motor[left] = 100; motor[right] = 100; wait1Msec (3000); }
Az általálunk adott neveket használva a példaprogram mindkét motort elindítja 100-as fokozaton majd 3 másodpercig hagyja őket menni. (így előre halad a robotunk)
A motor tömb bármely értékenek megváltoztatásakor a futtató környezet felméri, hogy milyen utasításokat kell alacsonyszinten a motornak küldeni. Ez a programozó számára nagyon kényelmes, nem kell vizsgálni, hogy miylen állapotba van a motor amikor beállítunk egy új sebesség értéket.

Encoderek

RobotC-ben elérhető a motorok pozíciója, vagyis hogy mennyit fordult azóta, hogy legutóbb inicializálták. A fordulás fokban értendő, egész szám reprezentálja. Ezt a nMotorEncoder tömb megfelelő indexű elemei tartalmazzák. Az nMotorEncoderTarget tömbbel pedig megadhatjuk, hogyha elér a motor egy bizonyos fordulatot (a tömb megfelelő indexű elemének beállított érték) akkor a motor leáll. Ezzel a két tömbbel precíz mozgások programozhatók le.
Például a következő alprogrammal 2 fordulatot tesz meg mindkét motor, ami tekintve hogy tudjuk mekkora a kerék átmérője azt jelenti meg tudjuk mondani mennyit menjen előre pontosan:

# pragma config (Motor , motorA , left , tmotorNormal , PIDControl ) # pragma config (Motor , motorB , right , tmotorNormal , PIDControl ) task main () { //a bal motor encoderével mérjük mennyit fordul nMotorEncoder[left]=0; //ezért inicializáljuk nMotorEncoderTarget[left]=720; //beállítjuk, hogy 2 fordulat után álljon majd le motor[left] = 50; motor[right] = 50; //mindkét motort elindítjuk while ( nMotorRunState [left]!= runStateIdle ){} //amíg nem kerül át idle módba a bal motor, addig tevékenyen várakozunk } //amint átkerül véget ér a program és ezzel(!!!!!) leáll a jobb motor is

Szinkronizáció

RobotC-ben egy X motorhoz hozzáköthetjük Y motort, és így ha X-et elindítjuk Y automatikusan vele együtt mozog. Ilyen konstrukciók robotoknál sokszor hardveresen vannak megvalósítva mikrovezérlők segítségével. RobotC-ben ezt szoftveresen tehetjük meg, ami egy sokkal rugalmasabb megoldás, a programkód olvashatósága javul, valamint a hibalehetőségek száma csökken.

A szinkronizáció beállítása az nSyncedMotors változó értékenék megadásával történik.
A lehetséges értékek:


ahol synchXY a nyelv konstansa, és X motorhoz kötjük hozzá Y motort.

Még be kell állítanunk az nSyncedTurnRatio változó értékét is, mely 0 és 100 között lehet és azt állítja be, hogy hány százalékát fordulja az Y motor az X-nek.

Látható, hogy egyszerre csak két motort tudunk szinkronba kötni RobotC-ben, ami az esetek 99%-ban elég, mert a szinkronizált motorokat többnyire arra használjuk, hogy a bal és jobb motorokat összehangoljuk.

A következő példa ugyanazt csinálja mint az előző szekcióban: előremegy precízen 2 kerékfordulatnyit. Itt már szinkronizált motorokat használunk az egyenes mozgás programozására, ezért például a program végén biztosak lehetünk benne, hogy ha a bal motor leáll, akkor a jobb is.

# pragma config (Motor , motorA , left , tmotorNormal , PIDControl ) # pragma config (Motor , motorB , right , tmotorNormal , PIDControl ) task main () { nSyncedMotors = synchAB ; // bal motorhoz hozzákapcsoljuk a jobbat nSyncedTurnRatio = +100; // a jobb motor pont ugyanannyit forogjon, mint a bal nMotorEncoder[left]=0; // inicializáljuk a fordulatmérőt nMotorEncoderTarget[left] = 720; // két fordulatot megyünk motor[left] = 50; // elindítjuk a bal motort (jobb motor is elindul) while (nMotorRunState[left]!= runStateIdle ){} //ha a fordulatszámláló elérte a 2 fordulatot már kiléphetünk }

Szenzorok

A robothoz kötött szenzorokat hasonló módon, tömbön keresztül tudjuk elérni RobotC-vel. Szenzorokra az S1, S2, S3, S4 konstansokkal tudunk hivatkozni, de a motorokhoz hasonlóan a fejlesztői környezetben beállíthatunk nekik saját neveket. Ekkor a következő fodítói utasítás adódik a programnkhoz:

# pragma config ( Sensor , S1 , trigger , sensorTouch ) // az S1 porton lévő szenzort, ami egy nyomásérzékelő (touchsensor) a trigger névhez kötjük.

A szenzorokat a SensorValue tömbbel érjük el, a tömböt a port nevével vagy a beállított névvel kell indexelni.

A különböző típusű érzékelők és tulajdonságaik a következő táblázatban láthatóak:

Érzékelő típusa Leírás Értéke
sensorTouch Nyomásérzékelő 0 vagy 1
sensorLightActive fényérzékelő LED-del 0-tól 100-ig, százalék
sensorLightInactive fényérzékelő LED nélkül 0-tól 100-ig, százalék
sensorSoundDB hangérzékelő 0-tól 100-ig, százalék
sensorSONAR ultrahangos távolságmérő 0-tól 255-ig, centiméterben

Példaprogram: addig megyünk előre amíg nem ütközünk falba, ha ütköztünk visszatolatunk egy kicsit
task main() { while(SensorValue(touchSensor) == 0) //a nyomás érzékelő értékétől függ, hogy belépünk-e a ciklusba { motor[motorA] = 100; //A motort elindítjuk motor[motorB] = 100; //B motort elindítjuk } motor[motorA] = -75; //A motor tolatásra kapcsol motor[motorB] = -75; //B motor tolatásra kapcsol wait1Msec(1000); //a tolatást 1 mp-ig foyltatjuk, ezután véget ér a program és leáll a robot }

A futtató környezet állandóan puffereli az összes szenzorból bejövő adatokat, és amikor azokra szükség van, már csak a pufferből kell a mérési adatot visszaadni a futó programnak. Ez nagyságrenddel gyorsabb futást eredményez, mint más robotokra írt progamozás nyelv által generált program.