Reaali Robootika.COM

NXT robotimaailm ja programmeerimine C-keeles

Presidendi Lossis

Jõudsime Robomiku finaalis 3. kohale ning esikohtadele oli organiseeritud vastuvõtt Presidendi juures.

President Toomas-Hendrik Ilves ja robootika

See oli äärmiselt mõnus ja meeldejääv sündmus. Alguses tehti meile ringkäik Lossis ja tutvustati sealseid ruume ning elukorraldust. Ajaloost, K.Päts on olnud 9 korda President, sellist resümeed on vähestel ette näidata. Lossi seinakate on mitmes ruumis kaunis elegantne ja peen kangas (mitte värv ega tapeet). Kogu majesteetlik mööbel on eesti käsitööliste tehtud ja hästi säilinud või renoveeritud.

Ainult üks mõistatus jäi kogu sellest käigust – et miks Venemaa relvakambrist pole võimalik kätte saada Eesti Vabariigi esimese presidendi Konstantin Pätsi ametiketti? Ja keegi ei teadvat miks ja kui kauaks see seal asub?

Aitäh President, et leidsid oma väga tihedas graafikus aega meie vastuvõtuks ning innustamaks noori insenere jätkama sellega millega nad tegelevad.

Robomiku võistluse roboti programm

Robomiku võistlusel saavutasime 3. koha.

Koos reavahede ja kommentaaridega tuli kokku ligi 200 rida koodi.

Kuna palusin poistel kommentaarid juurde panna siis peaks olema arusaajale inimesele täitsa loetav kood. Kuna kasutasime mitte kõige uuemat versiooni NXC-st siis seetõttu on LineLeader anduriga suhtlev library siia eraldi included. Uuemasse softi (15. märts 2011) on juba kõik need uute andurite driverid sisse kirjutatud.

/*
autor: Ramses Sepp 20/03/11
robomiku 2011 kevad karupäästmise programm
selles programmis:
* sõidab robot mööda joont LineLeader anduri abil
* leiab rohelisi ja hõbedasi teibiribasid mis on kannatanud ja annab nendest märku
* tuvastab IR abil karu ja annab temast märku
* robotil on haarad mille abil ta kannab karu majast välja
*/

#include "LL-Lib.nxc"
#define IR_TOUCH S1
#define I2C_SENSOR S2
#define COLOR S3
#define LIGHT S4
#define LL_ADDR 0x04

long endTime;
bool haaradLahti = FALSE;
bool mulOnKaru = FALSE;
task DriveOnTheLine();
task KeeraRobotit180();
task KeeraRobotit();

//funktsioon ArvutaKiirus tagastab väärtuse, mis jääb -100 ... 100 vahele
int ArvutaKiirus(int x, int min, int max)
{
if (x < min)
   return min;
else if (x > max)
   return max;
else
   return x;
}

//alamprogramm HaaradLahti avab haarad ning seejärel robot sõidab edasi
task HaaradLahti()
{
RotateMotorEx(OUT_A, -100, 6840, 0, FALSE, TRUE);
haaradLahti = TRUE;
//endTime muutujat kasutatakse selleks 
//et robot sõidaks peale haarade lahti tegemist 2 sekundit edasi
endTime = CurrentTick() + 1000;
ExitTo(DriveOnTheLine);
}

//alamprogramm HaaradKinni sulgeb haarad ning siis käivitub roboti pööramine
task HaaradKinni()
{
RotateMotorEx(OUT_A, 100, 6840, 0, FALSE, TRUE);
mulOnKaru = TRUE;
haaradLahti = FALSE;
ExitTo(KeeraRobotit180);
}

//alamprogramm KeeraRobotit180 keerab robotit 180 kraadi 
//kuni ta on joone keskel
task KeeraRobotit180()
{
int onJoonel;
//hakkame mootoreid keerama, et robot liiguks joonelt ära
RotateMotor(OUT_BC, 40, 360);
OnFwdReg(OUT_B, 40, OUT_REGMODE_SPEED);
OnFwdReg(OUT_C, -40, OUT_REGMODE_SPEED);
Wait(1000);
while (TRUE)
   {
   OnFwdReg(OUT_B, 40, OUT_REGMODE_SPEED);
   OnFwdReg(OUT_C, -40, OUT_REGMODE_SPEED);
   //loeme LL andurist kas robot on joone keskel
   onJoonel = LL_Read (I2C_SENSOR, LL_ADDR, LL_READ_AVERAGE);
   //kui robot on joone keskel siis käivitub uuesti põhiprogramm
   if (onJoonel < 50 && onJoonel > 40)
      {
      Off(OUT_BC);
      ExitTo(DriveOnTheLine);
      }
   }
}

//alamprogramm KeeraRobotit keerab robotit 180 kraadi
task KeeraRobotit()
{
RotateMotor(OUT_BC, 50, 360);
RotateMotorEx(OUT_BC, 50, 1100, 100, TRUE, TRUE);
Off(OUT_BC);
ExitTo(DriveOnTheLine);
}

//alamprogramm DriveOnTheLine on joone jälgimise, kannatanute tuvastamise
//ja karu kandmise programm
task DriveOnTheLine()
{
int steering;
int b_speed;
int c_speed;
int rohelisedMehed;
int hobedasedMehed;
bool naebKaru;
int karuKaugus;
bool onSoitnud2Sek = FALSE;
int baasKiirus;

//lõpmatu tsükkel mille sees toimub enamus programmist
while (TRUE)
   {
   rohelisedMehed = Sensor(COLOR);
   hobedasedMehed = Sensor(LIGHT);
   naebKaru = !Sensor(IR_TOUCH);
   karuKaugus = SensorUS(I2C_SENSOR);
   
   //kui värviandur näeb rohelist või hõbedast meest põrandal
   //annab heliga märku
   if (rohelisedMehed == 3 || hobedasedMehed > 70)
      {
      PlaySound(SOUND_DOUBLE_BEEP);
      }
      
   //kui IR_sensor näeb karu, haarad on kinni ja mul ei ole karu 
   //siis annab sellest heliga märku:P
   if (naebKaru && !haaradLahti && !mulOnKaru)
      {
      Off(OUT_BC);
      PlaySound(SOUND_UP);
      ExitTo(HaaradLahti);
      }
   
   //kui haarad on lahti, ei näe karu ja on sõitnud 2 sekundit 
   //siis paneb haarad kinni
   if (haaradLahti && !naebKaru && onSoitnud2Sek)
      {
      Off(OUT_BC);
      ExitTo(HaaradKinni);
      }
   
   //kui robot on haarad lahti teinud siis ta sõidab 2 sekundit joonel edasi
   //enne kui hakkab kontrollima kas on tarvis haarasid kinni panna
   if (haaradLahti)
      {
      if (endTime < CurrentTick())
         {
         onSoitnud2Sek = TRUE;
         }
      }
   
   //steering muutujasse kirjutatakse LineLeaderist steering väärtus
   //mida kasutatakse mootorite juhtimisel
   steering = LL_ReadSteering(I2C_SENSOR, LL_ADDR);
   
   //see If lause on vajalik, et steering oleks vahemikus -127 ... 127
   if(steering > 127)
      {
      steering = steering - 256;
      }

   // kui robot sõidab üles siis on baasKiirus 40, allaminekul 30
   if (mulOnKaru)
      {
      baasKiirus = 30;
      steering = steering / 3;
      }
   else
      {
      baasKiirus = 40;
      }
   /*
   mootoritele õige kiiruse andmine
   igal juhul ei saa olla mootori kiirus suurem kui 100
   igal juhul ei saa olla mootori kiirus väiksem kui -100
   */
   b_speed = ArvutaKiirus(baasKiirus + steering, -100, 100);
   c_speed = ArvutaKiirus(baasKiirus - steering, -100, 100);
   
   //kuna mootorid on tagurpidi siis peame muutma väärtused vastasmärgiliseks
   b_speed = 0 - b_speed;
   c_speed = 0 - c_speed;
   
   OnFwdReg(OUT_B, b_speed, OUT_REGMODE_SPEED);
   OnFwdReg(OUT_C, c_speed, OUT_REGMODE_SPEED);
   }
}

task main()
{
SetSensorLight(LIGHT);
SetSensorColorFull(COLOR);
SetSensorLowspeed(I2C_SENSOR);
SetSensorTouch(IR_TOUCH);
Wait(SEC_5);

LL_Write_KP(I2C_SENSOR, LL_ADDR, 40, 32); //katsetada 0...100 //alla:40
LL_Write_KI(I2C_SENSOR, LL_ADDR, 0, 32);  //jääb nulliks
LL_Write_KD(I2C_SENSOR, LL_ADDR, 5, 32);  //katsetada 0..20 //alla:5

StartTask(DriveOnTheLine);
}

Robomiku finaal 3. koht

Üle Eesti tuli kokku 22 võistkonda erinevatest koolidest, kes kõik katsusid jõudu ühe Karupäästmise ülesandega. www.robomiku.ee

Nimelt robot pidi liikuma mööda musta joont läbi keerulise kolmekorruselise maja, tuvastama majas olevaid kannatanuid ning ülemiselt korruselt karumõmmi majast välja tooma.

Ütlen kohe ette ära, et karu jäigi majja, kuid meie tiim sai karu sellegipoolest kõige kaugemale. Esimene ja teine koht läksid aga Narva kuna nemad jõudsid oma robotiga põlevast majast ka välja – kuigi ilma karuta.

Vaata 3. koha ehk siis meie roboti videot:

Robomikufinaal–Robojalg 3. koht

8. tund: mäng NXT ekraanile 1. osa

Esimene pool tunnist kulus Robomiku kevadise võistluse tutvustamiseks mis toimub Tartus 22. märtsil.

Selgus, et nii Ramsesel kui ka Jaanil oli juba ette valmistatud oma nägemus Robomiku võistlusrobotist.

Teine pool tunnist aga kulutasime selle peale, et alustada ühe mängu programmeerimisega NXT ekraanile. Ma viibisin nädal aega Redmondis ning seal oli aega NXT-le üks mäng ajaviiteks välja mõelda.

Mäng

Ekraanil põrkab pall üles-alla ja paremale-vasakule ning NXT ekraani alumises servas on väravavaht mida saab nooltega paremale-vasakule liigutada.

Väravavaht peab alati palli põrke all olema, et pall üles tagasi põrkaks. Kui pall kukub ekraani alt välja on mäng läbi. Lisaks saab valida 3-e erineva raskusastme vahel ning need mõjutavad palli liikumise kiirust ja punktiarvestust. Raskema mängu korral saab rohkem punkte.


Jagasime ülesande etappideks ning selle tunni aeg kulus õppimisele, kuidas liigutada väravat nooleklahvide abil paremale vasakule.

/*
Leivo Sepp, 23.02.2011
See on mäng, kus tuleb nooltega liigutada väravat paremale/vasakule nii,
et ekraanil põrkav pall ei kukuks mängualast välja vaid põrkaks vastu väravat.
*/

//värava muutuja koos palli esialgse asukohaga
int Joon = 50;

//joone liigutamise alamprogramm liigutab parema-vasaku klahvi abil 
//väravat ekraani allservas edasi-tagasi
task JooneLiigutamine()
{
while (TRUE)
   {
   if (ButtonPressed(BTNRIGHT, TRUE))
      {
      Joon += 4;
      }
   else if (ButtonPressed(BTNLEFT, TRUE))
      {
      Joon -= 4;
      }
   ClearLine(LCD_LINE8);
   TextOut(Joon, LCD_LINE8, "=");
   
   //wait on vajalik, et värav liiga kiiresti ei liiguks
   Wait(150);
   }
}

task main()
{
//siit kutsutakse välja ja käivitatakse alamprogramm JooneLiigutamine
Precedes(JooneLiigutamine);
}

7. tund: NXT kiiruse testimine

Tunni sisu on testida NXT aju protsessori kiirust kahe erineva programmeerimiskeele NXC ja NXT-G ja erinevate NXT Firmwarede korral.

Õppematerjal: Juhend- Do–While ja For tsüklid

Antud ülesande lahendame C-keeles FOR tsükliga.

Ülesanne. NXT kiiruse testimine.

Programm peab välja nägema järgmine.

Programmi käivitudes alustab tööd tsükkel, mis teeb 10 000/100 000 tavalist tsüklit. Lisaks on vaja kirjutada juurde stopper, mis mõõdab nende tsüklite läbimiseks kulunud aega ning kuvab selle ekraanil peale tsükli lõpetamist.

Kirjeldatud programm tuleb luua nii NXT-G kui ka NXC-s. Mõõta ja panna kirja tulemused.

Lisaks tuleb katsetada seda erineva NXT Firmware-ga. 

  • NXC: 1.28
  • Mindsensor: 1.29
  • Lego: 1.29
  • Lego: 1.31

Mõõta ja katsetada kas on erinevate Firmwarede ja programmeerimiskeeltega kiirustes erinevusi. Alljärgnevas tabelis on erinevate mõõtmiste kokkuvõte, tulemused on sekundites.

  Firmware 1.28
NXC
Firmware 1.29
Lego
Firmware 1.31
Lego
Firmware 1.29
Mindsensor
tsükleid NXT-G NXC NXT-G NXC NXT-G NXC NXT-G NXC
10 000 2,197 s 0,806 s 2,179 s 0,774 s 2,176 s 0,773 s 2,059 s 0,736 s
100 000 21,903 s 8,061 s 21,715 s 7,742 s 21,687 s 7,731 s 20,516 s 7,359 s
                 

Erakordselt suur vahe on programmeerimiskeele valikul. NXC on peaaegu 3 korda kiirem kui NXT-G.

Teine, kuid võrdlemisi tagasihoidlik vahe on Firmware’s.

Kuna me kirjutame programme C-keeles, on meil peamiselt laetud NXC firmware 1.28. Olen avastanud sellel firmware’l ühe puuduse, nimelt Mindsensori I2C Digital Port Splitter taga olevad andurid ei tööta selle firmware korral.

Kui laadida aga Mindsensori firmware (et töötaks I2C Digital Port Splitter), ei tööta jällegi mõned NXC spetsiifilised funktsioonid, nagu näiteks HiTechnic Prototype Boardi juhtimine.


Lahendus: NXC programm

/*
autor:Ramses Sepp 16.02.2011   19:28
See programm mõõdab aega mis kulub NXT-l ühe miljoni tsükli läbimiseks
Muudetud: Leivo Sepp 18.02.2011
*/

long LIIDA = 0;
long START;

long Stopper(long tsykkel)
{
	START = CurrentTick();
	//siin defineerin muutuja "i" mis võrdub nulliga 
	//ning paneb iga kord ühe i-le juurde
	//seni kaua kuni on üks miljon täis
	for(long i = 0; i < tsykkel; i++){
		//et NXT-l oleks ka mingi lihtne tehe arvutada
		LIIDA += 4;	
		}
	//funktsioon Stopper tagastab stopperi lõpuaja
	return CurrentTick()-START;
}

task main(){

long k = 10000;
string msg, stpr;

for (long j = 1; j < 3; j ++ ){
	//Kuvame ekraanil, et programm on alles käimas
	TextOut(3, LCD_LINE1, "Running ... ");
	//moodustame stringi ekraanile, mis kuvab tsükli arvu ja kestuse
	msg = StrCat(NumToStr(k), ":              ");
	stpr = NumToStr(Stopper(k));
	msg = StrReplace(msg, 8, stpr);
	TextOut(5, LCD_LINE2-j*8, msg);
	//korrutame tsükliarvu 10-ga
	k *= 10;
	}
ClearLine(LCD_LINE1);
TextOut(3, LCD_LINE1, "Valmis");
//programm jääb nupulevajutust ootama
until(ButtonPressed(BTNCENTER, FALSE));
}

Lahendus 2: NXT-G programm

NXT-G programm on selles mõttes lihtsam tehtud, et iga mõõtmise korral tuleb eraldi loop-le counter määrata: 10 000/100 000. NCX programmis toimus see automaatselt.

image

Juhend: HiTechnic prototüüpimislaud

HiTechnic NXT andurite tootjana on teinud ka ühe väga laheda asja – nimelt prototüüpimislaud.

http://www.hitechnic.com/cgi-bin/commerce.cgi?preadd=action&key=NPK1056 

Sellel on 5 analoogsisendit (1024 astet pingega 0..3,3 V) ning 6 digitaalset sisendit/väljundit, mille abil saab kõikvõimalikke keerukaid asju teha. Alljärgnevalt kaks lihtsat näidisprogrammi: a) jooksvad tuled ja b) KITT tuled.

Jooksvad tuled ja KITT tuled HiTechnic Prototype Board abil

Jooksvad tuled

Käesoleva juhendi käigus vaatame ainult prototüüpimislaua digitaalsete väljunditesse kirjutamise osa.

Prototüüpimislaual on 6 digitaalset väljundit B0…B5. Neid saab kasutada nii sisendi kui ka väljundi režiimis. Register “Digital Control” määrab ära millised pordid on sisendid ja millised väljundid. Näiteks “Digital Control” registris number 63 (kahendsüsteemis 111111) muudab kõik väljunditeks.

Digital Out registrisse antud number määrab ära milline väljundportidest on aktiveeritud 1-ga. 1 tähendab siis 3,3V ja 12mA. Näiteks Digital Out numbriga 63 (ehk 0x3F) tähendab, et kõik valgusdioodid põlevad.

Alljärgnev programm suunab DigitalOut registrisse järjest numbrid 1,2, 4, 8, 16, 32 (0x01, 0x02, 0x04, 0x08, 0x10, 0x20).

Alljärgnevalt näidisprogramm kuidas teha prototüüpimislaua abil jooksvad tuled NXC programmeerimiskeeles.

/*
Leivo Sepp 12.02.2011
See programm kasutab HiTechnicu prototüübi plaati
Paneb plaadi taha ühendatud valgusdioodid järjekorras põlema
Ehk teisisõnu "jooksvad tuled"
*/


#define PROTO_PORT S1

int count;
int light = 0x01;
byte cmndbuf[];
byte respbuf[];                 

/* protoboard I/O map
   42,43 - A0 input
   44,45 - A1 input
   46,47 - A2 input
   48,49 - A3 input
   4A,4B - A4 input
   4C    - B inputs
   4D    - B outputs
   4E    - B controls
*/

//see alamprogramm teostab reaalse kirjutamise protolaua registrisse
//aktiveerides kindla pordi (B0..B5), mille taga peab süttima valgusdiood
void writedata(int outputdata)
  {
  //loo 3 väärtusega massiiv
  ArrayInit(cmndbuf, 0, 3);
  //protolaua aadress
  cmndbuf[0] = 0x02;
  //register kuhu kirjutatakse 4D on output
  cmndbuf[1] = 0x4D;
  //output registrisse kirjutatakse number mis aktiveerib kindla väljundi
  cmndbuf[2] = outputdata;
  count=0;
	//Käivitada eelnevate andmete põhjal protolauda kirjutamine
  I2CBytes(PROTO_PORT, cmndbuf, count, respbuf);  
  }

task main()
  {
  SetSensorLowspeed(PROTO_PORT); 
  Wait(100);

  //massiivi initsialiseerimine, 3 väärtust
  ArrayInit(cmndbuf, 0, 3);
  //esimene väärtus massiivis, prototüüpimislaua aadress
  cmndbuf[0] = 0x02;
  //teine väärtus massiivis, registri Control valimine (sisendid/väljundid)
  cmndbuf[1] = 0x4E;
  //kirjutada registrisse Control number 63 ehk 111111
  //st. et kõik B0..B5 on väljundid
  cmndbuf[2] = 0x3F;
  //mitu baiti peab I2C protolaud tagastama, meie puhul 0
  count=0;
  //Käivitada eelnevate andmete põhjal protolauda kirjutamine
  I2CBytes(PROTO_PORT, cmndbuf, count, respbuf);
  Wait(100);

  while (TRUE)
    {
    //kutsutakse välja alamprogramm, kuhu kirjutatakse number
    //numbrid on 1, 2, 4, 8, 16, 32
    writedata(light);
     light = light * 0x02;
     if (light == 0x40)
        light = 0x01;
    Wait(100);
    }
}

KITT tuled.

Ja teine programm, mis paneb tuled edasi-tagasi liikuma, ehk nagu KITT
/*
Leivo Sepp 12.02.2011
See programm kasutab HiTechnicu prototüübi plaati
Paneb plaadi taha ühendatud valgusdioodid edasi/tagasi põlema
Ehk teisisõnu "KITT tuled"
*/


#define PROTO_PORT S1

int count;
int light = 0x01;
byte cmndbuf[];
byte respbuf[]; 
bool kitt=TRUE;                

/* protoboard I/O map
   42,43 - A0 input
   44,45 - A1 input
   46,47 - A2 input
   48,49 - A3 input
   4A,4B - A4 input
   4C    - B inputs
   4D    - B outputs
   4E    - B controls
*/

//see alamprogramm teostab reaalse kirjutamise protolaua registrisse
//aktiveerides kindla pordi (B0..B5), mille taga peab süttima valgusdiood
void writedata(int outputdata)
  {
  //loo 3 väärtusega massiiv
  ArrayInit(cmndbuf, 0, 3);
  //protolaua aadress
  cmndbuf[0] = 0x02;
  //register kuhu kirjutatakse 4D on output
  cmndbuf[1] = 0x4D;
  //output registrisse kirjutatakse number mis aktiveerib kindla väljundi
  cmndbuf[2] = outputdata;
  count=0;
	//Käivitada eelnevate andmete põhjal protolauda kirjutamine
  I2CBytes(PROTO_PORT, cmndbuf, count, respbuf);  
  }

task main()
  {
  SetSensorLowspeed(PROTO_PORT); 
  Wait(100);

	//massiivi initsialiseerimine, 3 väärtust
  ArrayInit(cmndbuf, 0, 3);
  //esimene väärtus massiivis, prototüüpimislaua aadress
  cmndbuf[0] = 0x02;
  //teine väärtus massiivis, registri Control valimine (sisendid/väljundid)
  cmndbuf[1] = 0x4E;
  //kirjutada registrisse Control number 63 ehk 111111
  //st. et kõik B0..B5 on väljundid
  cmndbuf[2] = 0x3F;
  //mitu baiti peab I2C protolaud tagastama, meie puhul 0
  count=0;
  //Käivitada eelnevate andmete põhjal protolauda kirjutamine
  I2CBytes(PROTO_PORT, cmndbuf, count, respbuf);
  Wait(100);

    while (TRUE)
    {
    //kutsutakse välja alamprogramm, kuhu kirjutatakse number
    //numbrid on 1, 2, 4, 8, 16, 32
    writedata(light);
    if (kitt){
    	 //numbrid jooksevad väiksemast suuremaks
       light = light * 0x02;
       if (light == 0x20){
          kitt = FALSE;
          }
       }
    else {
    	  //numbrid jooksevad suuremast väiksemaks
        light = light / 0x02;
        if (light == 0x01)
           kitt = TRUE;
        }
    Wait(200);
    }
}

Kahe seina vahel roniv robot

Ma tegin ühe roboti mis ronib kahe seina vahel üles-alla. Seda ehitades mul polnud mitte mingit probleemi. Kuid kui ma jõudsin programmeerimise juurde siis tekkis mul küll mõningaid probleeme. Kuid enne räägin milline oli mu roboti programmeerimise järjekord. Kõigepealt kui robot oli valmis siis polnud mingit muret esimese kolmandikuga alustada. Esimeses kolmandikus ma panin ta lihtsalt üles sõitma seni kuni ta näeb lähedamal kui 10 cm lage. Sellega erilisi probleeme ei tekkinud kuna see oli üpriski lihtne programm. Teise kolmandiku programmist ma panin roboti sõitma küll pikema programmiga kuid mõne algaja jaoks ka kergem ning seekord sõitis robot lõpmatuseni üles-alla. Minu viimane kolmandik programmist sõitis robot ka muidugi lõpmatusein üles alla kuid nüüd on see lühem ja kergem kui eelmine kord.

Mu isa tegi sellest ka video:

Kahe seina vahel ronija robot

Programm näeb välja selline:

/*
Autor:Ramses Sepp 09.02.2011
See programm võimaldab robotil sõita kahe seina vahelt üles
*/

//See alamprogramm juhib roboti mootoreid üles-alla sõidul
void Liikumine(bool Yles, int KiirusSeinal){
	//Järgnev if lause peatab ühe või teise mootori kui robot on balansist väljas
	//Siin if-i lauses korrgeerib balanssi robot siis kui ta näeb oranþi
	if (Sensor(S2) > 50){
		//Need kaks järgmist rida suunavad kumb mootor peatub 
		//siis kui läheb üles-alla ja näeb oranþi
		if (Yles) Off(OUT_B);
		else Off(OUT_C);
		until(Sensor(S2) < 50);
		}
	//Siin else if-i lauses korrigeerib balanssi robot siis kui ta näeb musta
	else if(Sensor(S2) < 40){
		//Need kaks järgmist rida suunavad kumb mootor peatub 
		//siis kui läheb üles-alla ja näeb musta
		if (Yles) Off(OUT_C);
		else Off(OUT_B);
		until(Sensor(S2) > 40);
		}
	else{
		//Muidu sõidab robot lihtsalt kahe seina vahelt alla
		OnRevReg(OUT_BC, KiirusSeinal, OUT_REGMODE_SPEED);
		OnRev(OUT_A, 20);
		}
}
task main(){
SetSensorLowspeed(S4);
SetSensorLight(S2);
SetSensorLowspeed(S3);
bool TOP;
//Järgnev mootori programmi osa laiendab mõlemad mootorid seinte vastu
OnFwd(OUT_A, -75);
Wait(1000);
while (TRUE){
	//Siin vaatab kas lagi on lähedamal kui 10 cm
	if(SensorUS(S4) < 10){
		Off(OUT_BC);
		TOP = TRUE;
		}
	//Siin vaatab kas põrand on lähedamal kui 10 cm
	if(SensorUS(S3) < 10){
		Off(OUT_BC);
		TOP = FALSE;
		}
	//See pool paneb roboti alla sõitma
	if(TOP){
		Liikumine(FALSE, -15);
	}
	//See pool paneb roboti üles sõitma
	else{
		Liikumine(TRUE, 30);
	}
}
}

6. tund: Andurite info kuvamine NXT ekraanil

Selle tunni käigus õpitakse kuvama andurite infot ekraanil. See on vajalik et aru saada mis infot andurid parasjagu väljastavad.

Õppematerjal:

Ülesanne.

Kuva ühendatud anduri info ekraanil. Vaja läheb NXT-d ning erinevaid andureid.


Variant a)

UltraSonic kauguseandur

Lahendus: Iseenesest väga lihtne programm, vaid ühe while() tsükliga.

/*
See programm kuvab ekraanile sõna Ultrasensor 
ja selle alla kui kaugel on ees olev asi.
*/

task main () {

SetSensorLowspeed (S2);

while (TRUE) {
   ClearScreen();
   TextOut(1, LCD_LINE1, "Ultrasonic");
   NumOut(1, LCD_LINE2, SensorUS (S2));
   Wait(200);
   }
}

Variant b)

Light sensor andur

/*
See programm kuvab ekraanile sõna LightSensor 
ja selle alla kui hele on ees olev asi.
*/
task main () {

SetSensorLight (S2);

while (TRUE) {
   ClearScreen();
   TextOut(1, LCD_LINE1, "LightSensor");
   NumOut(1, LCD_LINE2, Sensor(S2));
   Wait(200);
   }
}

Variant c)

Color sensor

Lahendus. Selle anduri juures annab numbri kuvamine liiga vähe olulist informatsiooni, seega palusin lahendada ülesande sellisel moel, et vastavalt värvile kuvataks ekraanil värvi nimetus. Ja need värvid mille nimetus pole kirjutatud, nende korral kuvatakse number. NB! Edaspidi õpime massiive ning saab sama programmi uuesti teha massiivi abil. Ehk tunduvalt lühema ja lihtsama.

/*
See programm kuvab ekraanile sõna ColorSensor 
ja selle alla värvi nimetuse
*/
task main () {

SetSensorLowspeed (S2);

while (TRUE) {
   ClearScreen();
   TextOut(1, LCD_LINE1, "ColorSensor");
   switch(SensorHTColorNum(S2))
   {
     case 0:
            TextOut (1, LCD_LINE2, "Must");
            break;
     case 6:
            TextOut (1, LCD_LINE2, "Kollane");
            break;     
     case 8:
            TextOut (1, LCD_LINE2, "Punane");
            break;     
		 case 14:
            TextOut (1, LCD_LINE2, "Beez");
            break;
     case 17:
            TextOut (1, LCD_LINE2, "Valge");
            break;

     default:
            NumOut(1, LCD_LINE2, SensorHTColorNum(S2));
      }
      Wait (200);
   }
}

Bricx Command Center häälestamine

BricxCC on NXT programmeerimise vahend, mille abil meie oma põhilise osa koodist kirjutamine.

Tegemist on tasuta tarkvaraga, mille saab alla laadida siit: http://bricxcc.sourceforge.net/

Järgnevalt leidsin hulga asju mida annab selles keskkonnas vaikimisi häälestuse suhtes oluliselt kasutajasõbralikumaks muuta.

Alljärgnevate ekraanipiltide järgi häälestades saad enda BricxCC keskkonna mugavamaks.

Edit – Preferences – Editor vaheleht

Bricx Preferences Editor seaded

Paremal pool ülalt alla:

Automatically indent lines (ON) – kui kirjutad koodirida mis algas mitte rea algusest vaid eendiga, siis enteriga järgmisele reale minnes satud täpselt samale tasemele eelneva reaga. Väga kasutajasõbralik ning normaalne käitumine.

Alt sets column selection (OFF) – Selle sisselülitamisel saab Alt klahvi all vajutades teha hiirega selectioni üle mitme rea nii et veeru osa jääb paigale. Üsna segane ja mõttetu asi.

Move cursor on right click (ON) – kui teed koodis mõnes kohas hiirega paremklõpsu siis viiakse automaatselt ka hiirekursor sellesse kohta. Põhimõtteliselt on see normaalne asjade toimimise viis arvutis.

Scroll Past EOL (OFF) – sisselülitamisel liigub kursor lõputult paremale kui vajutad noole paremale. Täiesti mõttetu funktsionaalsus – lülitasin välja. Välja lülitaud asendis viib nool paremale kursori rea lõppu jõudes järgmise rea algusesse. See on normaalne ja ootuspärane käitumine.

HalfPage Scroll (OFF) – Kui see on sisse lülitatud siis PgUp või PgDn nuppe vajutades liigub ekraan üles-alla ainult poole kaupa. Ebamugav funktsionaalsus, lülitasin välja, mulle meeldib et kogu leht liigub korraga üles-alla.

Drag and drop editing (ON) – see on ju elementaarne, et saan koodijupi hiirega kinni võtta ja teise kohta lohistada, muidugi lülita sisse.

Quick tab (OFF) – jälle üks mõttetu asi, lülita välja. Sisselülitamise korral liigub kursor TAB klahvi vajutades eelmise rea esimese tühikuni jne. Täiesti ebakasutajasõbralik funktsioon.

Keep trailing blanks (ON) – vajalik sisse lülitada, et TAB klahv korralikult töötaks.

Enhanced home key (ON) – sisselülitamise korral viiakse kursor Home nupule vajutuse korral esimese täheni antud real. Lülitasin välja, kuna ma olen harjunud et kursor viiakse konkreetselt rea algusesse kui vajutan „home“ nuppu.

With grouped undo (OFF) – ei saanudki aru mis undo’d see grupeerib. Lülitasin välja et ei hakkaks mingit segadust kogemata tekitama.

Use Tab to indent (ON) –See on väga oluline asi sisse lülitada. Selle abil saad tervet koodi blokki korraga paremale nihutada või siis Shift-Tab abil vasakule nihutada. Väga vajalik asi sisse lülitada.

Show special characters (OFF) – kuvad koodikirjutamise aknas ka reavahetuse, tühiku jms sümbolid. Pole kunagi vaja läinud.

Convert tabs to spaces (OFF) – pole vaja sisse lülitada. Las tabid jäävad tabideks ja mitte ei muutu tühikuks.

Highlight current line (ON/OFF) – mul on see sisse lülitatud, kuna poistele suurelt ekraanilt näidates on sedasi parem koodirea peal fookust hoida – sellisel juhul tuleb ka Color vahelehelt määrata mis on Highlight rea värvus, mina valisin kollase. Kui kirjutan lihtsalt koodi, siis selleks ajaks võtan välja.

Keep caret x position (ON) – sisselülitamisel hoiab kursor oma positsiooni kui üles alla liikuda. Hea mugav asi, kogu aeg vaja.

Autosize max left character (OFF) – mingi veidi mõttetu asi taas.

Edit – Preferences – General vaheleht

image

Multiformat clipboard copy (ON) – Kopeerib koodi vaikimisi RTF-vormingusse.

Maximize editor Windows (ON) – Käivitamisel ja uute loomisel on aknad kohe full screen.

Use MDI mode (OFF) – võta linnuke ära, siis on programmid TAB-dena

Edit – Preferences – Options vaheleht

image

Lülita sisse ridade nummerdamine. Line numbers.

Edit – Preferences – StartUp vaheleht

image

Määra, et vaikimisi Brick-type oleks NXT.

Juhend: Do–While ja For tsüklid

Alljärgnevalt veel kaks eriliste omadustega tsüklit, mille abil saab panna programmi täitma mingit protseduuri teatud arv kordi.

 

do { “body” } while ("tingimus")

do
 {
    x = x + 1;
    y = y * 2;
 } while (x < 10);

 

Erinevus tavalisest while-tsüklist seisneb selles, et tsükkel täidetakse alati vähemalt ühe korra ja alles seejärel kontrollitakse tingimuse vastavust. Kui on tõene, täidetakse tsükkel teist korda.

Seega, kõigepealt läheb tsükkel käima, täida enda sees olevad käsud ja siis jõuab viimase reani while (..), mille sees on tingimus. Kui see tingimus on tõene minnakse do-tsükli algusesse tagasi ja täidetakse uuesti kõik käsud. Kui aga while (..) tingimus on muutunud vahepeal FALSE-ks, väljutakse tsüklist ja minnakse ülejäänud programmiga edasi.


for("init", “condition”, “increment”) { “body” }

for (int i = 0; i < 8; i++)
 {
    NumOut(0, LCD_LINE1-i*8, i);
 }


Init-ga algväärtustatakse muutuja i, tsükkel täidetakse kuni tingimus on tõene ja iga tsükli alguses täidetakse increment, mis liidab muutujale i juurde ühe numbri.

Seega, For-tsükli eripära seisneb selles, et sellele on sisse ehitatud loendur, mida saab kohe for-tsükli parameetrites häälestada. Pole tarvis ise tsükli sisse kirjutada liitmistehet ja suurem/väiksem kontrolli.