Reaali Robootika.COM

NXT robotimaailm ja programmeerimine C-keeles

Kuidas lahendada võrratusi Mathematics abil

Käesolev võrratuste lahendamise juhend õpetab võrratusi lahendama Microsoft Mathematics (tasuta Microsofti tarkvara) abil ja neid graafiliselt kujutama.

Kui kahe avaldise (arvu) vahel on võrratusmärk (<, >, <= või >= ), siis sellist seost nimetatakse võrratuseks.

Võrratuste ja nende ettekujutamine joonisel annab parema mõistmise võrratuste lahendamisele.

Võrratustel võib olla

a)      üks lahend

b)      mitu või lõpmatu arv lahendeid

c)      lahendid võivad puududa

Võrratuste lahendamine tähendab selle kõigi lahendite leidmist. Ülesanded võivad olla antud tekstiga „leia ühine positiivsus- või negatiivsuspiirkond“. Ka sellisel juhul on tegemist võrratuste lahendamise ülesannetega.

 

Ruut- ja lineaarne võrratus

On antud järgmised võrratused, mis tuleb lahendada.

ruutvõrratus

lineaarvõrratus

Võrratuse lahendamiseks tuleb see sisestada Mathematics töölehele (Worksheet) viisil, et nende võrratuste vahel on sõna and. See annab programmile teada, et tegemist on kahe võrratuse samaaegse lahendamisega.

 Microsoft Mathematics

Vajuta enter, tulemusena kuvatakse lahendus x > 3. See on mõlema võrratuse ühine piirkond.

Lisaks pannakse lahendatav võrrand sulgudesse, mis algab sõnaga solveIneq ja mille lõpus on „x“. SolveIneq tähendab et lahednatakse võrratust ja x tähistab, et seda lahendatakse muutuja x-suhtes. Mathematics leidis, et antud võrrandis on ainult üks muutuja ning eeldas, et kasutaja soovib leida just seda muutujat.

Microsoft Mathematics

Selleks, et paremini mõista, mida tähendab võrratuse lahendamine graafiliselt, kuva antud tulemus joonisel. Selleks vajuta lingil „plot this inequality“. Joonisel on näha viirutatud ala, mis asub x-teljel number 3-st paremal. See iseloomustabki lahendust x > 3.

Microsoft Mathematics 

Selleks, et aru saada kuidas need kaks võrratust kokku sellise tulemuse annavad, kirjutame need üles võrranditena ja kuvame joonisel.

Töölehele sisesta see võrrand järgmisel kujul: clip_image012[6] ja vajuta enter. Tulemusena kuvatakse võrrandi lahendid, kuid praegusel juhul huvitab meid rohkem graafik.

Microsoft Mathematics

Vajuta lingile „plot both sides of this expression in 2D“. Kõrvutades antud tulemus esialgse võrratuse graafikuga, on näha et mõlemad graafikud on positiivsed alates kolmest, ehk siit jooniselt on lihtne välja lugeda nende võrratuste lahend x > 3.

 Microsoft Mathematics

Leia ühine negatiivsuspiirkond

Olgu antud kaks võrrandit ning ülesanne on leida ühine negatiivsuspiirkond.

ruutvõrrand

lineaarvõrrand

Ülesande tekst nõuab, et need mõlemad võrrandid tuleb teisendada võrratusteks ja seejärel lahendada. Seega ülesande täitmiseks Mathematics abil on tarvis need võrratustena sisestada töölehele järgmisel kujul.

mathematics

Mõlema võrrandi puhul on = y ära vahetatud võrratusega < 0. Ehk siis leitakse mõlema võrratuse ühised lahendid, mis on väiksemad kui 0.

Sisesta see Mathematics töölehele ja vajuta enter. Mathematics annab lahenduseks 3 varianti: x < -1, x > 5/3 ja x < 3.

Microsoft Mathematics 

Kuvame selle tulemuse graafikul, vajutades lingil „plot this inequality“. Graafiline lahendus on viirutatud ala joonisel.

 Microsoft Mathematics

Vaata nüüd kuidas need graafikud joonisel välja näevad ja miks tekkis lahenduseks selline situatsioon.
Sisesta antud võrrandid töölehele ja vajuta enter.

võrrandisüsteem

Microsoft Mathematics

 

Kuva need graafikud joonisel vajutades linki „plot both sides of this expression in 2D“. Alljärgneval joonisel on näha graafiliselt tulemus mõlema graafiku negatiivsest piirkonnast. See on vasakul pool y-telge alates sellest punktist kus parabool on allpool x-telge. Y-teljest paremal pool on näha väike kolmnurkne piirkond, kus parabool on allpool x telge ning sirge pole veel jõudnud veel x-telge ületada.

Microsoft Mathematics

 

 

Kuidas lahendada võrrandeid Mathematics abil

Käesolev võrrandite lahendamise juhend õpetab võrrandeid lahendama Microsoft Mathematics (tasuta Microsofti tarkvara) abil ja neid graafiliselt kujutama.

Võrrandite ja nende kuvamine joonisel annab parema mõistmise võrrandite lahendamisele.

Võrranditel võib olla

a)      üks lahend

b)      mitu või lõpmatu arv lahendeid

c)      lahendid võivad puududa

 

Kaks ruutvõrrandit

Antud võrrandi mõlemal pool on ruutvõrrand seega on siin situatsioon, kus üks ruutvõrrand võrdub teise ruutvõrrandiga.

kaks ruutvõrrandit

1.      Kirjuta Mathematics töölehele (Worksheet) ülaltoodud võrrand ja vajuta enter.

Microsoft Mathematics

2.      Mathematics väljastab koheselt võrrandi tulemuse, x=-3.

Lisaks pannakse lahendatav võrrand sulgudesse, mis algab sõnaga solve ja mille lõpus on „x“. See tähendab et antud võrrand lahendatakse muutuja x-suhtes. Mathematics leidis, et antud võrrandis on ainult üks muutuja ning eeldas, et kasutaja soovib leida just seda muutujat.

 Microsoft Mathematics

3.      Kuna tegemist on numbrite ja x-dega mida on keeruline hoomata, tekib paratamatult küsimus et mis asi on õigupoolest see x mida otsitakse. Sellise võrrandi lahendust on kõige lihtsam mõista graafikul. Vajuta lingile „ploth both sides of this expression in 2D“, et näha antud lahendust joonisel.

Selle lingi vajutamise järel suunatakse kasutaja automaatselt joonise (Graphing) vahelelehele ja kuvatakse antud võrrand graafikul. Joonisel on näha kaks joont, kummagi võrrandi poole jaoks üks joon. Joonise kohal kuvatakse mõlemad võrrandid vastava värviga, millele need joonisel vastavad.

Toodud joonisel on näha, et x, mida otsitakse on mõlema võrrandi lõikekoht x-teljel, mis asubki täpselt -3 peal.

Microsoft Mathematics

 

Kaks lineaarvõrrandit ehk sirget

kaks lineaarvõrrandit ehk sirget

Sisesta võrrand Worksheet lehele, vajuta enter ja kuva lahendus joonisel. Näeme, et mõlemal võrrandi poolel asuvad lineaarvõrrandid ehk sirged ning neil on ühine lõikepunkt x-teljel, x=1/8=0,125.

 Microsoft Mathematics

Ruutvõrrand ja sirge

ruutvõrrand ja sirge

Käesoleva võrrandi esimene pool on absoluutväärtus ruutvõrrandist ning teine pool tavaline sirge ehk lineaarvõrrand. Sellel võrrandisüstemil on kolm lahendust, see tähendab et mõlema graafiku lõikuvad üksteisega kolmel korral: x=-3, x=2, x=0.

 Microsoft Mathematics

Vaatame jooniselt kuidas selline kolme x-ga lahendus on võimalik.

Joonisel on näha, et ruutvõrrandi kaar mis tavaliselt on allpool x-telge on nüüd ülespoole keeratud. Põhjus on selles, et antud ruutvõrrand on absoluutväärtuse märkide vahel, st see ei saa olla negatiivne. Selle tulemusena ongi võimalik saavutada kolm puutepunkti sirgega.

 Microsoft Mathematics

6. 9 klass 2 õppetundi: Roboti teekonna kaardistamine

Tiigrihype_logo

See materjal on loodud Tiigrihüppe Sihtasutuse programmi ProgeTiiger raames.

Ülesande eesmärk

Ehitada ja programmeerida robot, mis suudab ekraanile kuvada oma läbitud teekonna.

Käesoleva ülesande lahendamine kestab 2 robootika tundi, kusjuures ühe tunni pikkuseks on arvestatud 2x45 min.

 

Ülesande lahendamiseks vajalik

Õpilased peavad olema hästi kursis matemaatikaga ja oskama arvutada täisnurkse kolmnurga külgede pikkuseid nii koosinuse kui ka siinuse abil.

Õpilane peab arvesse võtma ülesande lahendamisel järgmisi asjaolusid:

1)      Ratta läbimõõt

2)      Rataste teljevahe

3)      Peab oskama tuletada roboti pöördenurga, kui ülejäänud muutujad on teada

roboti pöördenurk

4)      Peab oskama arvutada kolmnurga lähiskaateti pikkust tervanurga ning hüpotenuusi abil

lähiskaatet

5)      Peab oskama arvutada vastaskaateti pikkust teravnurga ning hüpotenuusi abil

vastaskaatet

6)      Peab oskama aru saada NXT koordinaatteljestikust, mis on mõõtudega 100x64 pikselit

 

Ülesande lahendamise käik

Lahenduse koodi pole mõttekas õpilastele ette anda, tegemist on nii lihtsa koodiga, et selle mahakirjutamine võtaks aega 10 min, kuid tarkus jääks tulemata.

Ülesanne on jaotatud neljaks etapiks mille käigus õpilased jõuavad järk-järgult lahenduseni.

Etapid ja õppetundide jaotus:

1.      Tund

a.      Roboti pöördenurga leidmine rataste pöördenurga abil

b.      Kolmnurga lahendamine, lähis- ja vastaskaatetite leidmine (siinus, koosiinus)

2.      Tund

a.      Roboti pöördenurk ning kolmnurga lahendamine kokku pandud (suunamõõdik ekraanil)

b.      Lõplik ülesande lahendus
 

Roboti pöördenurga leidmine

Selle etapi eesmärk on lasta õpilastel jõuda valemini, mille abil saab teisendada roboti rattakeeramise kraadid roboti enda pööramise kraadideks. See on vajalik, kuna ülesande lahendus baseerub omadusel, et meil on teada igal hetkel rataste omavahelise pöördenurga vahe.

Roboti pööramise illustreeriv näide

Kõige lihtsam on tuua näide seisva robotiga, kus meil on teada et üks ratas seisab ja teine ratas pöörab näiteks 360 kraadi, ehk teeb ühe tiiru. Sellisel juhul saame roboti pöördenurgaks 90 kraadi, eeldusel et rataste teljevahe on 110 mm ja diameeter 56 mm.

 

Õpilased on varasemalt lahendanud ülesandeid, mille käigus nad on pidanud vastupidist ülesannet lahendama, st. et on teada mitu kraadi peab robot pöörama ning õpilased peavad välja arvutama mitu kraadi peab ratas pöörama, et saavutada roboti õige positsioon.

Õpilased on siiani kasutanud valemit:

mootori pöördenurk

 

Käesoleva ülesande käigus peavad õpilased algatuseks avaldama valemist RobotiPöördenurga.

Kui neil on valem õigesti avaldatud, kirjutavad nad programmi, mille abil saab kuvada roboti pöördenurga ekraanile numbriliselt. See annab neile kohest tagasisidet, kas nad on õigesti avaldanud RobotiPöördenurga ning seda ka õigesti rakendada oskavad.

Antud etapi lahendus on alljärgnev programmikood.

//käesolev programm kuvab ekraanil roboti pöördenurga

//roboti mootorite pöörete järgi arvutatakse välja roboti pöördenurk

//ja kuvatakse see ekraanil

//testimiseks tuleb robotit käsitsi liigutada.

 

//Roboti pööramise nurk = (Diameeter * x kraadi)/(Rataste vahe * 2)

 

task main()

{

int RattaDiameeter = 56;  //ratta diameeter

int RatasteVahe = 110;   //ratastevaheline kaugus, teljevahe

int suund;             //mootori pöörete vahe

float BMootor;         //mootori B pöörded

float CMootor;         //mootori C pöörded

int RobotiNurk;        //roboti pööramise nurk

 

while (1)

        {

        //mootorite pöörded loetakse muutujatesse

  BMootor = MotorRotationCount(OUT_B);

  CMootor = MotorRotationCount(OUT_C);

 

        //lahutatakse ühe mootori pöördenurgast teise mootori pöördenurk

        //tulemuseks on ratastevaheline erinevaus pöördenurgas

          suund = BMootor - CMootor;

         

        //siin arvutatakse välja roboti pöördenurk, võttes arvesse rataste läbimõõtu

         //rataste teljevahe ja ratastevaheline kraadide erinevus

          RobotiNurk = (RattaDiameeter * suund)/(RatasteVahe * 2); 

         

               ClearLine(LCD_LINE1);

         

          //ekraani ülemisel real kuvatakse roboti nurk

          NumOut(0, LCD_LINE1, RobotiNurk);

          TextOut(30, LCD_LINE1, "kraadi");

        }

}


 

Kolmnurga lahendamine

Selle etapi eesmärk on lasta õpilastel lahendada kolmnurk, mille kohta on teada üks teravnurk ning hüpotenuus. Leida on tarvis lähiskaateti ja vastaskaateti pikkused.

kolmnurga lahendamineLahendatud kolmnurk tuleb kuvada ekraanil ning peab olema muutumises koos nurga muutmisega. Nurga muutmine teostada noolenuppudega parem-vasak, sammuga 5 kraadi.

Antud etapp on olulise tähtsusega, kuna selle abil jõuavad õpilased ülesande lõpuks äratundmisele, kuidas aitab kolmnurga lahendamine neid robootika liikumisülesande juures teekonna kuvamisel. Neil peaks tekkima side matemaatika õppimise vajaduse ja reaalse elu vahel.

Kolmnurga lähis- ja vastaskaateti pikkuste arvutamise valemid. Vaata joonist.

lähiskaateti arvutamine

vastaskaateti arvutamine

Kolnurk

Kui nad on kolmnurga lahendamisest aru saanud, tuleb selle kohta programm kirjutada. Programm võiks välja näha selline, et hüpotenuus on ette antud (ülesande lahenduses on see samuti mittemuutuv suurus), kuid nurka peab saama muuta ja tulemusena kuvatakse ekraanil kolmnurga lähis- ja vastaskaatetite pikkused.

Kolmnurga lahendamise programmikood.

//käesolev programm lahendab kolmnurga

//ja joonistab selle ekraanile

 

//lähiskaatet = teravnurga koosinu * hüpotenuus

//vastaskaatet = teravnurga siinus * hüpotenuus

 

task main()

{

 

int RobotiNurk=45; //roboti pööramise nurk

int Lkaatet;                   //lähiskaatet

int Vkaatet;                   //vastaskaatet

int Hypotenuus=80; //hüpotenuus

 

while (1)

        {

        ClearScreen();

        TextOut(0, LCD_LINE1, "Sisesta nurk");

        NumOut(85, LCD_LINE1, RobotiNurk);

        if(ButtonPressed(BTNCENTER, FALSE))

               {

               while(ButtonPressed(BTNCENTER, FALSE));

               break;

               }

        if(ButtonPressed(BTNRIGHT, FALSE))

               RobotiNurk += 5;

        while(ButtonPressed(BTNRIGHT, FALSE));

        if(ButtonPressed(BTNLEFT, FALSE))

               RobotiNurk -= 5;

        while(ButtonPressed(BTNLEFT, FALSE));

     

          //arvutatakse välja lähiskaateti pikkus

          Lkaatet = cosd(RobotiNurk) * Hypotenuus;

          //arvutatakse välja vastaskaateti pikkus

          Vkaatet = sind(RobotiNurk) * Hypotenuus;

                 

          TextOut(0, LCD_LINE2, "Lkaat");

          TextOut(50, LCD_LINE2, "Vkaat");

               NumOut(35,LCD_LINE2, Lkaatet);

               NumOut(85,LCD_LINE2, Vkaatet);

            

               //ekraanile joonistatakse lähiskaatet

               LineOut(1, 1, Lkaatet, 1);

               //ekraanile joonistatakse vastaskaatet

               LineOut(Lkaatet, 1, Lkaatet, Vkaatet);

               //ekraanile joonistatakse hüpotenuus

               LineOut(1, 1, Lkaatet, Vkaatet);

               Wait(100);

        }

}


 

Roboti liikumise suunanäidik

Roboti suunanäidik ekraanilSelle etapi eesmärk on panna kokku esimene ja teine etapp, ehk siis ühendada omavahel roboti pöördenurga arvutamine ja kolmnurga lahendamine.

 Etapi lõpptulemusena valmib NXT ekraanile suunanäidik, mis näitab suunda kuhu poole robot sõidab. Seda omadust kasutame lõpplahenduses roboti teekonna kuvamiseks.

Roboti suunanäitamise programmi kood.

//käesolev programm kuvab ekraanile roboti liikumise suuna
 
//Roboti pööramise nurk = (Diameeter * x kraadi)/(Rataste vahe * 2)
//lähiskaatet = teravnurga koosinu * hüpotenuus
//vastaskaatet = teravnurga siinus * hüpotenuus
 
task main()
{
int RattaDiameeter = 56; //ratta diameeter
int RatasteVahe = 110;   //ratastevaheline kaugus, teljevahe
int suund;               //mootori pöörete vahe
float BMootor;           //mootori B pöörded
float CMootor;           //mootori C pöörded
int RobotiNurk;          //roboti pööramise nurk
int Lkaatet;             //lähiskaatet
int Vkaatet;             //vastaskaatet
int Hypotenuus=60;       //hüpotenuus
 
while (1)
        {
        //mootorite pöörded loetakse muutujatesse
  BMootor = MotorRotationCount(OUT_B);
  CMootor = MotorRotationCount(OUT_C);
          suund = BMootor - CMootor; 
          
          //siin arvutatakse välja roboti pöördenurk, võttes arvesse rataste läbimõõtu
          //rataste teljevahe ja ratastevaheline kraadide erinevus
          RobotiNurk = (RattaDiameeter * suund)/(RatasteVahe * 2);
          
          //arvutatakse välja lähiskaateti pikkus
          Lkaatet = cosd(RobotiNurk) * Hypotenuus;
          //arvutatakse välja vastaskaateti pikkus
          Vkaatet = sind(RobotiNurk) * Hypotenuus;
          
          ClearScreen();
          //ekraanile joonistatakse roboti suunanäidik
          LineOut(50, 25, Vkaatet+50, Lkaatet+25);
                  
          //ekraani ülemisel real kuvatakse roboti nurk ning lähis- ja vastaskaatet
          NumOut(0, LCD_LINE1, RobotiNurk);
          NumOut(50,LCD_LINE1, Lkaatet);
               NumOut(80,LCD_LINE1, Vkaatet);   
        Wait(100);
        }
}

 

Lõplik ülesande lahendus

Alljärgnevalt roboti teekonna kaardistamise programmi kommenteeritud kood.

Sisuliselt tekib ekraanile joon hästi paljude pisikeste kolmnurkade lahendamise tulemusena.

Siin on lisandunud eelkirjeldatud etappidega võrreldes kaks olulist võtet.Ülesande lahendus roboti ekraanil

1.      Kaardistamise sageduseks kasutatakse rataste pöörlemist. Kui ükskõik kumb ratas teeb 360 kraadi, ehk ühe täisringi, arvutatakse ja salvestatakse selle hetke roboti olukord ekraanil. See võte on vajalik eelkõige seetõttu, et robot ei suuda ühe rattapöörde jooksul kuigi palju viga teha ning see on piisav et saada küllaltki täpne joon ekraanil. Alati võib proovida ise selle täpsust suurendada, vähendades roboti rataste kraadide arvu mille jooksul toimub kaardistamine.

2.      Kolmnurga hüpotenuusi seadmine. See võimaldab muuta ekraanile kujutatava joone pikkust ja täpsust. Kui hüpotenuus panna liiga lühike, näiteks 2 punkti, siis on kaatetite tulemuseks ainult 1 või 0 ning joone täpsus kannatab olulisel määral. Kui aga hüpotenuus panna liiga pikk, joonistatakse ekraanile korraga väga pikk joon, mis on samuti mõttetu ekraani väikse pinna tõttu.

Ekraanipilt antud programmi tulemusest NXT ekraanil.

//käesolev programm on roboti teekonna kaardistaja

//roboti mootorite pöörete järgi arvutatakse välja roboti teekonna kaart

//ja kuvatakse see ekraanil

 

//task soida on lihtsalt roboti sõitmise ja kaardistamise testimiseks

//task sõida abil sõidab robot südame kujutise ning joonistab selle ka ekraanile

task soida()

{

while(1)

        {

        RotateMotorEx(OUT_BC, 40, 360, 0, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 360, 15, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 1300, 0, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 1600, -20, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 370, 100, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 1400, -25, TRUE, TRUE);

        RotateMotorEx(OUT_BC, 40, 1300, 0, TRUE, TRUE);

       

        //sõidu lõppedes oodatakse kuni nuppu vajutatakse

        while(!ButtonPressed(BTNCENTER, FALSE));

        }

}

 

//siin paar abivalemit, mille alusel arvutatakse roboti teekonna kaart

//Roboti pööramise nurk = (Diameeter * x kraadi)/(Rataste vahe * 2)

//lähiskaatet = teravnurga koosinus * hüpotenuus

//vastaskaatet = teravnurga siinus * hüpotenuus

 

task main()

{

int RattaDiameeter = 56;       //ratta diameeter

int RatasteVahe = 110;         //ratastevaheline kaugus, teljevahe

 

int suund;                     //mootori pöörete vahe

float BMootor;                 //mootori B pöörded

float CMootor;                 //mootori C pöörded

float LastBMootor;    

float LastCMootor;

int RobotiNurk;                //roboti pööramise nurk

int Lkaatet=0;                 //lähiskaatet

int Vkaatet=50;                //vastaskaatet

int xLkaatet;

int xVkaatet;

int Hypotenuus=6;              //hüpotenuus, selle numbri ja nurga põhjal arvutatakse välja Lähis- ja Vastaskaatet

 

StartTask(soida);

 

while (1)

        {

        //mootorite pöörded loetakse muutujatesse

  BMootor = MotorRotationCount(OUT_B);

  CMootor = MotorRotationCount(OUT_C);

 

 //antud if lause tingimus on võte, millega tagatakse kaardistamise sagedus

 //1 rattapööre = 1 joonistus ekraanil

 //seega antud if lause käivitub alles siis, kui B või C Mootor on teinud 360 kraadi

 

  if (BMootor > LastBMootor+360 || CMootor > LastCMootor + 360)

               { 

          LastBMootor = BMootor;

          LastCMootor = CMootor;

          suund = BMootor - CMootor;

         

          //siin arvutatakse välja roboti pöördenurk, võttes arvesse rataste läbimõõtu

          //rataste teljevahe ja ratastevaheline kraadide erinevus

          RobotiNurk = (RattaDiameeter * suund)/(RatasteVahe * 2);

         

          //eelmise tsükli käigus saadud lähis- ja vastaskaatet salvestatakse ajutisse muutujasse

          //selle alusel määratakse ekraanil joone alguspunkt

          xLkaatet = Lkaatet;

          xVkaatet = Vkaatet;

         

          //arvutatakse välja lähiskaateti pikkus

          Lkaatet = cosd(RobotiNurk) * Hypotenuus;

          //arvutatakse välja vastaskaateti pikkus

          Vkaatet = sind(RobotiNurk) * Hypotenuus;

         

          //välja arvutatud lähis- ja vastaskaatetile liidetakse juurde nende

          //eelmise tsükli tulemus, et tagada joone jätkumine samast punktist

          //kus eelmise tsükli aja lõpetati

          Vkaatet += xVkaatet;

          Lkaatet += xLkaatet;

         

          //kui kaatetid omandavad väärtuse mis on ekraani piirdeist väljas

          //siis korrigeeritakse numbreid selliselt, et joon jätkuks ekraani vastasservast

          if (Vkaatet>100)

                       {

                       Vkaatet = 1;

                       xVkaatet = 1;

                       }

          if (Vkaatet<1)

                       {

                       Vkaatet = 100;

                       xVkaatet = 100;

                       }

          if (Lkaatet>48)

                       {

                       Lkaatet = 1;

                       xLkaatet = 1;

                       }

          if (Lkaatet<1)

                       {

                       Lkaatet = 48;

                       xLkaatet = 48;

                       }

         

          //ekraanile joonistatakse roboti teekonna joon

          LineOut(xVkaatet, xLkaatet, Vkaatet, Lkaatet);

         

               ClearLine(LCD_LINE1);

         

          //ekraani ülemisel real kuvatakse roboti nurk ning lähis- ja vastaskaatet

          NumOut(0, LCD_LINE1, RobotiNurk);

          NumOut(50,LCD_LINE1, Lkaatet);

               NumOut(80,LCD_LINE1, Vkaatet);  

               }

        }

}

3. 9 klass 1 õppetund: Pöördenurga ja teepikkuse arvutamine

Tiigrihype_logo

See materjal on loodud Tiigrihüppe Sihtasutuse programmi ProgeTiiger raames.

Ülesande eesmärk

Robot peab sõitma täisnurkse kolmnurga hüpotenuusi ühest tipust teise (külg c), kusjuures teada on vaid kaatetite pikkused (küljed a ja b) ja robot asub alguses kolmnurga tipus paralleelselt kaatetiga.

Alljärgneval joonisel on näidatud roboti algne asukoht ja lõpp-positsioon.

 

Roboti kolmnurga sõitmise ülesanne

Ülesande tingimused

Robot peab iseseisvalt lahendama nurga ja teepikkuse arvutamise. Kusjuures robot peab olema võimalikult sõltumatu rataste suurusest ja rataste omavahelisest kaugusest.

Robot peab olema sõltumatu kolmnurga külgede pikkustest. Selle saab tagada võttega, et programmi alguses küsib robot kasutaja käest lõikude a ja b pikkuseid, mille annab ette õpetaja. Peale lõikude sisestamist käivitub programm mis pöörab robotit vajaliku hulga kraade ning robot sõidab nõutud teepikkuse jõudes kolmnurga teise tippu.

NB! Õpilastel võiksid olla sellised robotid, millel saab kerge vaevaga rattaid vahetada suuremate-väiksemate vahel kuna see mõjutab otseselt programmi käitumist. Ratta suurus võib olla samuti alguse küsimus, mida kasutajalt küsitakse programmi käivitamisel. Alljärgnevas programminäites seda tehtud pole, kuid olemasoleva koodi analoogia põhjal on see kergesti teostatav.

Ülesande lahendamine

Ülesanne baseerub lihtsal matemaatikal ning teada on tarvis kahte valemit.

Tähistame tundmatud nimedega PöördeNurk ja teepikkus ehk c.

1)      Pöördenurga arvutamiseks on valem: pöördenurga arvutamine

2)      Teepikkuse arvutamiseks on Pythagorase teoreem Pythagorase teoreem hüpotenuusi leidmine

Lahendus

Tunni läbiviimise metoodika.

Anda õpilastele kätte ülesanne ja tingimused. Kogu edasise võiksid olla nad suutelised ise välja mõelda.

Kui tarvis siis järgmise asjana võib tahvlile kirjutada pöördenurga arvutamise valemi ja Pythagorase teoreemi juhuks kui need kohe meelde ei tule.

Kogu edasine protsess peaks olema nende enda looming. Alljärgnev on üks võimalik lahendus käesolevale ülesandele.

Muutujatena on kirjeldatud ratta diameeter ning rataste telje vahe. Kogu ülejäänud matemaatika toimub programmi siseselt.

 

//Robot peab sõitma täisnurkse kolmnurga hüpotenuusi ühest tipust teise (külg c),

//kusjuures teada on vaid kaatetite pikkused (küljed a ja b)

//ja robot asub alguses kolmnurga tipus paralleelselt lähiskaatetiga.

//

 

float WheelDiameter = 56; //ratta diameeter

float Wheel;              //ratta ümbermõõt

float TeljeVahe = 110;    //rataste telje vahe

float a=30;               //külg a sentimeetrites

float b=40;               //külg b sentimeetrites

float TeePikkus;

float PoordeNurk;

 

task main(){

 

Wheel = WheelDiameter * PI;

 

//järgmine tsükkel võimaldab kasutajal valida kolmnurga lähiskülje pikkuse

//algne pikkus 30cm, seda saab suurendada/vähendada 10 cm kaupa

while (TRUE){

        TextOut(0, LCD_LINE2, "Sisesta lahiskylg");

        NumOut(30, LCD_LINE3, a);

        if(ButtonPressed(BTNCENTER, FALSE))

               {

               while(ButtonPressed(BTNCENTER, FALSE));

               break;

               }

        if(ButtonPressed(BTNRIGHT, FALSE))

               a += 10;

        while(ButtonPressed(BTNRIGHT, FALSE));

        if(ButtonPressed(BTNLEFT, FALSE))

               a -= 10;

        while(ButtonPressed(BTNLEFT, FALSE));

        Wait(MS_100);

        ClearScreen();

        }

 

//järgmine tsükkel võimaldab kasutajal valida kolmnurga vastaskülje pikkuse

//algne pikkus 40cm, seda saab suurendada/vähendada 10 cm kaupa

while (TRUE){

        TextOut(0, LCD_LINE2, "Sisesta vastaskylg");

        NumOut(30, LCD_LINE3, b);

        if(ButtonPressed(BTNCENTER, FALSE))

               {

               while(ButtonPressed(BTNCENTER, FALSE));

               break;

               }

        if(ButtonPressed(BTNRIGHT, FALSE))

               b += 10;

        while(ButtonPressed(BTNRIGHT, FALSE));

        if(ButtonPressed(BTNLEFT, FALSE))

               b -= 10;

        while(ButtonPressed(BTNLEFT, FALSE));        

        Wait(MS_100);

        ClearScreen();

        }

 

ClearScreen();

 

//ekraanil kuvatakse valitud lähiskülje ning vastaskülje pikkused

NumOut(70, LCD_LINE1, a);

NumOut(70, LCD_LINE2, b);

TextOut(0, LCD_LINE1, "Lahiskylg:");

TextOut(0, LCD_LINE2, "Vastaskylg:");

 

//arvutatakse välja pöördenurk ja teepikkus

PoordeNurk = atan2d(b, a);

TeePikkus = sqrt(b*b+a*a);

 

//pöördenurk ja teepikkus kuvatakse ekraanil

TextOut(0, LCD_LINE3, "Poordenurk:");

TextOut(0, LCD_LINE4, "Teepikkus:");

NumOut(70, LCD_LINE3, PoordeNurk);

NumOut(70, LCD_LINE4, TeePikkus);

 

//Pöördenurk ja teepikkus teisendatakse robotile arusaadavateks ühikuteks

//pöördenurk saab uue väärtuse väljendades roboti jaoks seda

//mitu kraadi peab rattaid pöörama et robot keeraks soovitud hulga kraade

PoordeNurk = (PoordeNurk * TeljeVahe) / WheelDiameter;

 

//teepikkus saab uue väärtuse väljendades roboti jaoks seda

//mitu kraadi peab rattaid pöörama, et robot läbiks vajaliku teepikkuse

TeePikkus = TeePikkus * 10 / Wheel * 360;

 

//robot pöörab vajaliku nurga

RotateMotorEx(OUT_BC, 50, PoordeNurk, -100, TRUE, TRUE);

Wait(MS_100);

 

//robot sõidab edasi vajaliku teepikkuse

RotateMotorEx(OUT_BC, 75, TeePikkus, 0, TRUE, TRUE);

 

//programm jääb lõpus ootama, kuni kasutaja vajutab nuppu

//senikaua kuvatakse ekraanil roboti poolt välja arvutatud numbrid

while(!ButtonPressed(BTNRIGHT, FALSE));

 

}

5. 9 klass 3 õppetundi: Ping-Pong mäng NXT-le

Tiigrihype_logo

See materjal on loodud Tiigrihüppe Sihtasutuse programmi ProgeTiiger raames.

Ping-pong mäng seisneb selles, et ekraanil põrkab edasi-tagasi ja paremale-vasakule pall mis võib ekraani altservast nö. maha kukkuda. Palli ekraanil hoidmiseks on allservas värav mida saab nooltega paremale vasakule liigutada ning mille pealt pall on võimeline tagasi põrkama.

 

Õppetundide jaotus

Ping-Pong mängu algoritmÕppetundide jaotuse aluseks on arvestatud ühe tunni kestuseks 2x45 min.

1.      Tund.

a.      Töötava mängu tutvustamine NXT peal

b.      Programmi algoritmi tutvustamine

c.      Värava liigutamise funktsiooni loomine.

2.      Tund

a.      Palli liigutamise funktsiooni kirjutamine

b.      Palli ja värava alamprogrammide kokkupanek

3.      Tund

a.      Raskusastme lisamine

b.      Punktiarvestuse lisamine ja initsialiseerimine

c.      Mäng valmis

 

Mängu algoritm

Vaata joonist. Programmi käivitudes küsitakse kasutajalt mängu keerukust, peale selle valmisit lähevad paralleelselt käima kaks alamprogrammi: värava liigutamine ja palli põrkamine. Need kestavad seni kuni pall kukup ekraani altservast välja. Selle peale katkestatakse mäng, kuvatakse kasutajale tema punktisumma, küsitakse uuesti mängu keerukust ja seepeale algab mäng otsast peale.

Mängu programmeerimise etapid

1.      Värava liigutamise funktsioon

2.      Palli liigutamise funktsioon (lõpmatult ekraanil põrkamas)

3.      Palli ja värava liigutamise funktsioonid kokku pandud (kas pall põrkas?)

4.      Raskusastme valimine

5.      Punktiarvestuse lisamine ja initsialiseerimine

6.      Lõplik mängu kood

Koos kommentaaride ja tühjade ridadega (koodi parema loetavuse nimel) on programmi pikkus ca 220 rida.


 

Värava liigutamise funktsioon

Antud funktsiooni eesmärgiks on liigutada väravat paremale ja vasakule. Kui nuppu hoitakse alla, liigub värav sõites ühte või teise serva.

 

int Dash;

 

//Gate protseduur joonistab ekraanile värava

//antud alamprotseduur kutsutakse välja värava liigutamise juurest

void Gate(int i){

        ClearLine(LCD_LINE8);

        TextOut(i, LCD_LINE8, "__");

}

 

//MoveTheGate funktsioon liigutab väravat paremale/vasakule

task MoveTheGate(){

while (TRUE) {

        //liigutame värava paremale kuni lõpuni

        if (ButtonPressed(BTNRIGHT, TRUE)){

        //väravat liigutatakse 5 pikseli kaupa

        //kui ollakse piksli 85 juures jääb seisma ning värav on paremal

               if (Dash < 85)

                       Dash += 5;

               else

                       Dash = 85;

               }

        //liigutame väravat vasakule kuni algusesse

        else if (ButtonPressed(BTNLEFT, TRUE)){

        //väravat liigutatakse 5 piksli kaupa vasakule

        //kui ollakse 1 piksli juures jääb seisma ning värav on vasakul

               if (Dash > 1) 

                       Dash -= 5;

               else

                       Dash = 1;

               }

        //kutsutakse välja alamprotseduur Gate mis joonistab värava asukoha

        //vastavalt oma parameetrile dash

        Gate(Dash);

        //ootame 0,1 sekundit, et värav liiguks paraja kiirusega

        Wait(100);

        }

}

 

task main(){

        StartTask(MoveTheGate);

}

 


 

Palli liigutamise funktsioon

Antud funktsioon paneb palli ekraanil põrkama ning tulemuseks on palli lõpmatu põrkumine ekraanil 45 kraadise nurga all servade suhtes.

Pall liigub igas suunas ühe pikseli ehk punkti kaupa. Ekraani kõrgus on 64 ja laius 100 pikselit ehk punkti. Ülemist serva kontrollime numbriga 56 ja paremat numbriga 93, kuna ekraanil liigub tegelikkuses „o“ täht ja NXT arvestab selle tähe asukohta vasaku-alumise nurga järgi.

 

int Ball_X;            //palli asukoht x teljel

int Ball_Y;            //palli asukoht y teljel

bool Yles;             //palli liikumise suund üles-alla

bool Paremale;         //palli liikumise suund paremale-vasakule

int Ball_Last_X;       //palli eelmine asukoht

int Kiirus = 60;       //palli liikumise kiirus, kasutatakse raskusastme määramisel hiljem

 

//funktsioon Ball joonistab ekraanile palli

void Ball(int k, int i, int j){

        ClearLine(k);

        TextOut(j, i, "o");

}

 

//MoveTheBall liigutab palli üles-alla paremal-vasakule

task MoveTheBall(){

while (TRUE)

        {

        //Ball_Last_X postisioon on vajalik, et õige ekraani rida ära puhastada

        //seega, algselt salvestatakse palli asukoht ajutisse muutujasse

        Ball_Last_X = Ball_X;

 

        //pall liigub üles

        if (Yles)

               Ball_X += 1;

        //pall liigub alla

        else   

               Ball_X -= 1;

 

               //pall liigutatakse paremale

        if (Paremale)

               Ball_Y += 1;

               //pall liigutatakse vasakule

        else

               Ball_Y -= 1;

              

 

        //kutsutakse välja palli asukohta muutmise funktsioon

        //esimene parameeter määrab rea mis kustutatakse

        //teine ja kolmas parameeter määravad palli asukoha

        Ball(Ball_Last_X, Ball_X, Ball_Y);

 

        //kontrollitakse kas pall on all või üleval

        //vastavalt olekule põrkab pall järgmise tsükli käigus        vastassuunas

        if (Ball_X > 56)

               Yles = FALSE;

        else if (Ball_X <= 2)

               Yles = TRUE;

              

        //kontrollitakse/juhitakse, kas pall peab paremale-vasakule põrkama       

        if (Ball_Y > 93)

               Paremale = FALSE;

        else if (Ball_Y < 1)

               Paremale = TRUE;

 

        //palli liikumise kiirus, edaspidi kasutatakse raskusastme jaoks

        Wait(Kiirus);

        }

}

 

task main ()

        {

        StartTask(MoveTheBall);

        }

 

 


 

Palli ja värava liigutamise funktsioonid koos

Palli ja värava liigutamise funktsioonid kokkupandult tähendavad seda, et pall saab alla jõudes aru, kas tema alla on värav või mitte. Kui palli all on värav, põrkab pall üles tagasi või muidu kukub ekraani alt läbi ja mäng on läbi.

Antud funktsioonide kokkupanekul muutub palli liigutamise alamprogramm, värava liigutamine jääb samaks, seal ei muutu midagi. Seega värava liigutamise alamprogrammi siinkohal kordama ei hakka.

Palli liigutamise alamprogrammis muutub ainult koht koodis, mis kontrollib kas pall on all, seega välja on ainult see osa toodud.

        //kontrollitakse kas pall on all või üleval

        //vastavalt olekule põrkab pall järgmise tsükli käigus        vastassuunas

        if (Ball_X > 56)

               Yles = FALSE;

 

        //kontrollitakse kas pall on all

        if (Ball_X <= 2)

               {

        //kui pall põrkab vastu alust, saad punkti

        //ja pall liigub järgmise tsükli käigus üles

        //aluse kontroll on alusest 8 pikslit paremale või 5 vasakule

        //seega värava laiuseks on tegelikkuses 13 pikselit

               if (Ball_Y >= Dash-5 && Ball_Y <= Dash + 8)

                       {

                       Yles = TRUE;

                       }

               //kui pall ei põrka vastu alust

               else

               //kui pall ei põrka vastu alust, on mäng läbi

                       {

                       PlayTone(500, MS_20);

                       StopTask(MoveTheGate);

                       ExitTo(main);

                       }

               }      

Muutub ka alamprogramm main(), kus peab välja kutsuma kaks alamprogrammi. Alamprogrammid MoveTheGate ja MoveTheBall käivad paralleelselt, kuid alljärgnevas koodis on näha, et kõigepealt käivitatakse MoveTheGate() ja seejärel väljutakse main()-st ja käivitatakse MoveTheBall(). Selline koodijärjestus on vajalik, kuna kui käivitades lihtsalt mõlemad alamprogrammid käsuga StartTask lõpeb mõlema käivitamise järel main() programm ning rakendus sulgub koheselt.

NB! Selle küsimuse võib jätta koduseks ülesandeks: Miks käivitatakse paralleelselt käivad alamprogrammid alljärgneval moel ja mitte ei käivitata mõlemaid käsuga StartTask?

task main ()

        {

        StartTask(MoveTheGate);

        ExitTo(MoveTheBall);

        }

 

Lisaks tuleb koodi algusesse kirjutada alljärgnev rida. See deklareerib kompilaatorile, et eksisteerib alamprogramm nimega main(), mida kasutatakse MoveTheBall() alamprogrammis. Kompilaator kompileerib koodi järjest ning kui kõige alguses ei oleks deklareeritud main(), tekiks kompileerimisel viga kui programmi koodis kasutatakse viidet main()-le, kuna kompilaator ei tea veel, et see alamprogramm eksisteerib.

task main();

 

 


 

Raskusastme valimine

Raskusastme valimisega muutuvad mängus 2 omadust.

1)      Esiteks muutub palli liikumise kiirus, mis teeb mängimise raskemaks.

2)      Teiseks muutub punktiarvestus: kui pall liigub kiiremini, saab iga tagasipõrgatatud palli eest rohkem punkte kui palli aeglasemalt liikumise eest ehk kergema raskusastme korral.

 

int Score;             //loeb kokku mängu jooksul saadud punktid

int Raskus = 2;        //raskusastmed on 1..3, vaikimisi on 2, st. keskmine

int Kiirus = 250;      //mängu kiirus on vaikimisi 250, kuid erinevad raskusastmed mõjutavad kiirust

 

task Start(){

string msg;

bool ExitWhile = FALSE;

 

//mängu käivitamisel kuvatakse ekraanil allolevad kirjad

ClearScreen();

msg = "-= Ping Pong =-";

TextOut(1, LCD_LINE1, msg);

msg = "----------------";

TextOut(1, LCD_LINE2, msg);

msg = "Let's play it !";

TextOut(1, LCD_LINE3, msg);

msg = "Sinu punktid: ";

msg += NumToStr(Score);

TextOut(1, LCD_LINE5, msg);

msg = "< vali raskus  >";

TextOut(1, LCD_LINE6, msg);

 

//alljärgnev tsükkel on raskusastme valimiseks ning väljutakse siis kui

//kasutaja vajutab keskmist ehk oranzi nuppu

while (!ExitWhile)

        {

        //nupuvajutus lisab raskusastmele 1-e juurde

        if (ButtonPressed(BTNRIGHT, TRUE))

               {

               while(ButtonPressed(BTNRIGHT, TRUE));

               Raskus ++;

               }

        //nupuvajutus lautab raskusastmest 1-e

        if (ButtonPressed(BTNLEFT, TRUE))

               {

               while(ButtonPressed(BTNLEFT, TRUE));

               Raskus --;

               }

       

        //järgmised if laused tagavad selle, et raskusastme valimine käiks ringiratast

        if (Raskus > 3) Raskus = 1;

        if (Raskus < 1) Raskus = 3;

        ClearLine(LCD_LINE7);

       

        //switchi abil kuvatakse ekraanil raskusastmele vastav nimetus

        //lisaks muudetakse kiiruse muutujat, mis mõjutab mängu raskust

        switch (Raskus)

               {

               case 1:

                       TextOut(1, LCD_LINE7, "  ---Kerge---");

                       Kiirus = 350;

                       break;

               case 2:

                       TextOut(1, LCD_LINE7, "  --Keskmine--");

                       Kiirus = 250;

                       break;

               case 3:

                       TextOut(1, LCD_LINE7, "  ---Raske---");

                       Kiirus = 150;

                       break;

               }

              

        //kui kasutaja vajutab keskmist nuppu, hakkab mäng pihta

        if (ButtonPressed(BTNCENTER, TRUE))

               {

               while(ButtonPressed(BTNCENTER, TRUE));

               ExitWhile = TRUE;

               }

              

        //oodatakse 100ms et välistada juhuslikud nupuvajutused

        Wait(100);

        }

       

        //programm ootab enne väljumist 3 sekundit

        //see on vajalik ainult käesoleva mooduli testimiseks

        //mängus seda ootamist tarvis pole

        Wait(SEC_3);

}

 

task main ()

        {

        StartTask(Start);

        }

 


 

Punktiarvestuse lisamine ja initsialiseerimine

Punktiarvestus toimub põhimõttel, et mitu palli suudeti tagasi põrgatada. Erinevate kiiruste korral saab iga tagasipõrgatamise eest erineva arvu punkte. See osa koodist tuleb lisada sinna, kus kontrollitakse kas pall põrkab tagasi või kukub läbi.

               if (Ball_Y >= Dash-5 && Ball_Y <= Dash + 8)
                       {
                       Yles = TRUE;
                       //siin antakse vastavalt mängu raskusele punktid
                       switch (Raskus)
                               {
                               case 1:
                                      Score ++;
                                      break;
                               case 2:
                                      Score += 5;
                                      break;
                               case 3:
                                      Score += 10;
                                      break;
                               }
                       }

Initsialiseerimine tähendab seda, et enne iga mängu alustamist saaksid pall, värav ja punktiarvestus nullitud. Selleks otstarbeks käivitatakse alljärgnev alamprotseduur.

//See protseduur algväärtustab muutujad
void Initialize()
{
        Raskus;
        Dash = 50;             //see on värav ning alguses seatakse see keskele
        Ball_X = 9;            //rida millelt pall alustab liikumist
        Ball_Y = 20;   //veerg millelt pall alustab liikumist
        Yles = TRUE;   //muutuja, mis määrab et pall liigub alguses üles
        Paremale = TRUE; //muutuja, mis määrab et pall liigub alguses paremale
        Score = 0;             //punktid nulli
        ClearScreen(); //puhastame ekraani
        Gate(Dash);            //see joonistab värava algasukoha
}

 


 

Lõplik mängu kood

Kõik eelnevalt läbi käidud programmikoodi komponendid on alljärgnevalt kokku pandud üheks töötavaks tervikuks.

Esimesel real olev task Start() on siin põhjusel, et seda kutsutakse koodis välja enne kui antud alamprogramm on deklareeritud. Seetõttu on tarvilik defineerida kompilaatori jaoks tühi alamprogramm.

task Start();
 
int Dash;
int Score;             //loeb kokku mängu jooksul saadud punktid
int Raskus=2;          //raskusastmed on 1..3, vaikimisi keskmine
int Ball_X;            //palli asukoht x teljel
int Ball_Y;            //palli asukoht y teljel
bool Yles;             //palli liikumise suund üles-alla
bool Paremale;         //palli liikumise suund paremale-vasakule
int Ball_Last_X;       //palli eelmine asukoht
int Kiirus = 60;       //palli liikumise kiirus, kasutatakse raskusastme määramisel hiljem
 
//Gate protseduur joonistab ekraanile värava
//antud alamprotseduur kutsutakse välja värava liigutamise juurest
void Gate(int i){
        ClearLine(LCD_LINE8);
        TextOut(i, LCD_LINE8, "__");
}
 
//See protseduur algväärtustab muutujad
void Initialize()
{
        Raskus;
        Dash = 50;             //see on värav ning alguses seatakse see keskele
        Ball_X = 9;            //rida millelt pall alustab liikumist
        Ball_Y = 20;   //veerg millelt pall alustab liikumist
        Yles = TRUE;   //muutuja, mis määrab et pall liigub alguses üles
        Paremale = TRUE; //muutuja, mis määrab et pall liigub alguses paremale
        Score = 0;             //punktid nulli
        ClearScreen(); //puhastame ekraani
        Gate(Dash);            //see joonistab värava algasukoha
}
 
//MoveTheGate funktsioon liigutab väravat paremale/vasakule
task MoveTheGate(){
while (TRUE) {
        //liigutame värava paremale kuni lõpuni
        if (ButtonPressed(BTNRIGHT, TRUE)){
        //väravat liigutatakse 5 pikseli kaupa
        //kui ollakse piksli 85 juures jääb seisma ning värav on paremal
               if (Dash < 85)
                       Dash += 5;
               else 
                       Dash = 85;
               }
        //liigutame väravat vasakule kuni algusesse
        else if (ButtonPressed(BTNLEFT, TRUE)){
        //väravat liigutatakse 5 piksli kaupa vasakule
        //kui ollakse 1 piksli juures jääb seisma ning värav on vasakul
               if (Dash > 1)  
                       Dash -= 5;
               else 
                       Dash = 1;
               }
        //kutsutakse välja alamprotseduur Gate mis joonistab värava asukoha
        //vastavalt oma parameetrile dash
        Gate(Dash);
        //ootame 0,1 sekundit, et värav liiguks paraja kiirusega
        Wait(100);
        }
}
 
//funktsioon Ball joonistab ekraanile palli
void Ball(int k, int i, int j){
        ClearLine(k);
        TextOut(j, i, "o");
}
 
//MoveTheBall liigutab palli üles-alla paremal-vasakule
task MoveTheBall(){
while (TRUE)
        {
        //Ball_Last_X postisioon on vajalik, et õige ekraani rida ära puhastada
        //seega, algselt salvestatakse palli asukoht ajutisse muutujasse
        Ball_Last_X = Ball_X;
 
        //pall liigub üles
        if (Yles)
               Ball_X += 1;
        //pall liigub alla
        else    
               Ball_X -= 1;
 
               //pall liigutatakse paremale
        if (Paremale) 
               Ball_Y += 1;
               //pall liigutatakse vasakule
        else 
               Ball_Y -= 1;
               
 
        //kutsutakse välja palli asukohta muutmise funktsioon
        //esimene parameeter määrab rea mis kustutatakse
        //teine ja kolmas parameeter määravad palli asukoha
        Ball(Ball_Last_X, Ball_X, Ball_Y);
 
        //kontrollitakse kas pall on all või üleval
        //vastavalt olekule põrkab pall järgmise tsükli käigus        vastassuunas
        if (Ball_X > 56) 
               Yles = FALSE;
 
        //kontrollitakse kas pall on all
        if (Ball_X <= 2)
               {
               //kui pall põrkab vastu alust, saad punkti 
               //ja pall liigub järgmise tsükli käigus üles
               //aluse kontroll on alusest 8 pikslit paremale või 5 vasakule
               //seega värava laiuseks on tegelikkuses 13 pikselit
               if (Ball_Y >= Dash-5 && Ball_Y <= Dash + 8)
                       {
                       Yles = TRUE;
                       //siin antakse vastavalt mängu raskusele punktid
                       switch (Raskus)
                               {
                               case 1:
                                      Score ++;
                                      break;
                               case 2:
                                      Score += 5;
                                      break;
                               case 3:
                                      Score += 10;
                                      break;
                               }
                       }
               //kui pall ei põrka vastu alust
               else
               //kui pall ei põrka vastu alust, on mäng läbi
                       {
                       PlayTone(500, MS_20);
                       StopTask(MoveTheGate);
                       ExitTo(Start);
                       }
               }              
               
        //kontrollitakse/juhitakse, kas pall peab paremale-vasakule põrkama        
        if (Ball_Y > 93)
               Paremale = FALSE;
        else if (Ball_Y < 1)
               Paremale = TRUE;
 
        //palli liikumise kiirus, edaspidi kasutatakse raskusastme jaoks
        Wait(Kiirus);
        }
}
 
task Start(){
string msg;
bool ExitWhile = FALSE;
 
//mängu käivitamisel kuvatakse ekraanil allolevad kirjad
ClearScreen();
msg = "-= Ping Pong =-";
TextOut(1, LCD_LINE1, msg);
msg = "----------------";
TextOut(1, LCD_LINE2, msg);
msg = "Let's play it !";
TextOut(1, LCD_LINE3, msg);
msg = "Sinu punktid: ";
msg += NumToStr(Score);
TextOut(1, LCD_LINE5, msg);
msg = "< vali raskus  >";
TextOut(1, LCD_LINE6, msg);
 
//alljärgnev tsükkel on raskusastme valimiseks ning väljutakse siis kui
//kasutaja vajutab keskmist ehk oranzi nuppu
while (!ExitWhile) 
        {
        //nupuvajutus lisab raskusastmele 1-e juurde
        if (ButtonPressed(BTNRIGHT, TRUE))
               {
               while(ButtonPressed(BTNRIGHT, TRUE));
               Raskus ++;
               }
        //nupuvajutus lautab raskusastmest 1-e
        if (ButtonPressed(BTNLEFT, TRUE))
                {
               while(ButtonPressed(BTNLEFT, TRUE));
               Raskus --;
               }
        
        //järgmised if laused tagavad selle, et raskusastme valimine käiks ringiratast
        if (Raskus > 3) Raskus = 1;
        if (Raskus < 1) Raskus = 3;
        ClearLine(LCD_LINE7);
        
        //switchi abil kuvatakse ekraanil raskusastmele vastav nimetus
        //lisaks muudetakse kiiruse muutujat, mis mõjutab mängu raskust
        switch (Raskus)
               {
               case 1:
                       TextOut(1, LCD_LINE7, "  ---Kerge---");
                       Kiirus = 120;
                       break;
               case 2:
                       TextOut(1, LCD_LINE7, "  --Keskmine--");
                       Kiirus = 60;
                       break;
               case 3:
                       TextOut(1, LCD_LINE7, "  ---Raske---");
                       Kiirus = 40;
                       break;
               }
               
        //kui kasutaja vajutab keskmist nuppu, hakkab mäng pihta
        if (ButtonPressed(BTNCENTER, TRUE))
               {
               while(ButtonPressed(BTNCENTER, TRUE));
               ExitWhile = TRUE;
               }
               
        //oodatakse 100ms et välistada juhuslikud nupuvajutused
        Wait(100);
        }
 
//initialize algväärtustab kõik mängu vajalikud omadused
Initialize();
StartTask(MoveTheGate);
ExitTo(MoveTheBall);
}
 
task main () 
        {
        Initialize();
        StartTask(Start);
        }

Robootika 2011/2012 õppeaasta edukalt lõpetatud

Robootika.COM tiim

 

Microsofti kontoris tegime lõpupeo kuhu said vanemad kutsutud. Sõime kooki, vaatasime üle aasta jooksul saavutatu.

Siin on meie suurimad saavutused õppeaastal 2011/2012:

  • Novembris FLL robootikavõistlusel 2. koht Eesti põhikoolide seas
  • Märtsis Euroopa RobotChallenge meistrivõistlustelt hõbemedal
  • Aasta lõpus tunnustus “Eesti parim robootikakool!”

Lisaks sai üle antud tasemetöö tulemused ja diplomid.

Ja lõpuks muidugi Xbox Party mis kestis poole kümneni õhtul Quitar Hero’d ja Haloga. Halo oli muidugi tavapäraselt projektoriga kahel suurel seinal ning kokku kaheksa mängijat üle võrgu koos müdistamas.

Kaunist suve kogu tiimile!

Robootika tasemetöö

Aasta lõpus robootika diplomi välja andmiseks on tarvis kontrollida õpilaste teadmisi mitmes vallas.

Ülesanded said koostatud põhimõttel, et oleksid kaetud kõik peamised programmeerimisalased võtted, andurid ja NXT.

Kokku 5 ülesannet, igas ülesandes on kaks taset, lihtsam ja keerulisem. Diplom tuleb igaühele personaalne, arvestades tehtud ülesandeid ja taset.

Eeldus: programmeerimine on tehtud NXC-keeles, BricxCC keskkonnas.

Ülesannete vabadus: Võib spikerdada, maha kirjutada, kopeerida, kasutada enda või teiste varem tehtud programme

Ülesande vastuvõtmine: Iga üks selgitab oma koodi ja programmi toimise põhimõtet.

1. Stopper

Oranž nupp käivitab stopperi, seejärel kuvatakse ekraanil info, et stopper käib. Uuesti oranži nupu vajutamine peatab stopperi ning NXT kuvab ekraanil kulunud aja.

Kolmas oranži nupu vajutus nullib stopperi ja seejärel algab protsess otsast peale – st. saab jälle käivitada stopperi.

Teine tase

Ekraanil kuvatakse stopperi numbrid täpsusega kümnendik sekundit.

NXT teeb iga 10 sekundi järel piuksu sel ajal kui stopper käib.

2. Roboti liikumine

Ehitada kõige tavalisem bot, ehk robot mis liigub ja keerab kahe vedava rattaga.

Robot peab sooritama järgmise ülesande:

  1. Liigub edasi 50cm
  2. keerab 45 kraadi paremale ümber ühe ratta ja sõidab seejärel edasi 25 cm
  3. keerab 135 kraadi paremale kohapeal ja sõidab edasi 50 cm
  4. keerab 45 kraadi paremale kohapeal ja sõidab seejärel edasi 25 cm
  5. keerab 135 kraadi paremale ümber ühe ratta ja jääb seisma.

NB! Programmis peab kasutama roboti omadusi – ratta läbimõõtu, ratastevahelist kaugust ning liikumine tuleb välja arvutada mootori pööreteks.

Teine tase

Kasutada liikumiseks ja pööramiseks alamprotseduure. Parameetritena anda ette teepikkus, pöördenurk ja pööramise iseloom (ümber ühe ratta/kahe rattaga).

3. Inimeste lugemine

Ehitada robot, mis loendab uksest sisenevaid inimesi. Vabal valikul kasutada Ultrasonic, valguse või Mindsensor IR distance andurit.

Inimesed mööduvad ca 30 cm kaugusel andurist. Inimese möödumisest annab NXT heliga märku.

Teine tase

Arvestades inimeste möödumise tihedust, kuvada ekraanil eeldatav keskmine inimeste möödumise arv:

  • tunnis - vorming: “0000” inimest
  • tööpäevas (8 tundi) - vorming: “0000” tuh. inimest
  • nädalas (5 tööpäeva) - vorming: “0000” tuhat inimest
  • aastas (240 tööpäeva) - vorming: “0,0” miljonit inimest.

4. Värviliste Lego-klotside loendamine

Ehitada robot, mis tuvastab värviandurist mööduvate klotside värvid ja loendab kokku erinevat värvi klotsid ja kuvab informatsiooni ekraanil. Kasutada ühte mootorit klotside ükshaaval läbilaskmiseks.

Teine tase

Värviklotside loendamisel saadud informatsioon salvestada massiivi ja ekraanil kuvada massiivi salvestatud informatioon.

5. Joonejärgija robot

Ehitada joonejärgija robot kasutades valgusandurit.

Teine tase

Joonejärgija robot

1) Mindsensors LineLeaderiga või

2) programmeerida ning häälestada PID-controller koos ühe valgussensoriga

Windows Phone – Accelerometer, kiirendusandur

Windows Phone’i on sisse ehitatud kolmesuunaline kiirendusandur. Alljärgnevas rakenduses kasutatakse punase palli liigutamiseks kahte dimensiooni, kuid värvilised jooned ekraanil iseloomustavad telefoni liikumist kolmes erinevas suunas.

MSDN artikkel: http://msdn.microsoft.com/en-us/library/ff431810(v=vs.92).aspx 

Antud kood on internetinäidete põhjal kokku pandud kahest erinevast rakendusest – kolmemõõtmeliste joonte kuvamine ning palli edasi-tagasi sõitmine mööda ekraani.

How accelerometer is working–check it out!

MainPage.xaml

<phone:PhoneApplicationPage
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   x:Class="AccelerometerTest.MainPage"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">

    <Grid Name="MyGrid" Width="411" Height="768">
        <Line x:Name="xLine" X1="200" Y1="400" X2="260" Y2="400" Stroke="Red" StrokeThickness="4" Margin="0"/>
        <Line x:Name="yLine" X1="200" Y1="400" X2="200" Y2="340" Stroke="Green" StrokeThickness="4" Margin="0"/>
        <Line x:Name="zLine" X1="200" Y1="400" X2="260" Y2="340" Stroke="Blue" StrokeThickness="4" Margin="0"/>
        <Rectangle x:Name="Track" Height="80" Stroke="#FFC0C0C0"
            RadiusX="40" RadiusY="40" Margin="0" Width="410" />
        <Ellipse x:Name="Ball" Width="80" Height="80" Margin="0">
            <Ellipse.Fill>
                <RadialGradientBrush GradientOrigin="0.234,0.255">
                    <GradientStop Color="White"/>
                    <GradientStop Color="Red" Offset="0.759"/>
                </RadialGradientBrush>
            </Ellipse.Fill>
            <Ellipse.RenderTransform>
                <TranslateTransform x:Name="BallTransform" />
            </Ellipse.RenderTransform>
        </Ellipse>
        <TextBlock Height="50" HorizontalAlignment="Left" Margin="0" Name="textBlock1" Text="TextBlock" VerticalAlignment="Top" Width="200" />
        <TextBlock Height="50" HorizontalAlignment="Left" Margin="0,50,0,0" Name="textBlock2" Text="TextBlock" VerticalAlignment="Top" Width="200" />
        <TextBlock Height="50" HorizontalAlignment="Left" Margin="0,100,0,0" Name="textBlock3" Text="TextBlock" VerticalAlignment="Top" Width="200" />
    </Grid
>

</
phone:PhoneApplicationPage
>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using Microsoft.Phone.Shell;

namespace AccelerometerTest
{
    public partial class MainPage : PhoneApplicationPage
    {
        private const int sum = 25;
        private const double gravity = 32.2; // raskusjõud (ft/sec2)
        private const double damping = 0.5;  // põrketugevus
        private const double mul = 128.0;    // palli liikumise tundlikkus
        private double _sx = 0.0;
        private double _sy = 0.0;
        private double _vx = 0.0;
        private double _vy = 0.0;
        private double _ax = 0.0;
        private double _ay = 0.0;
        private double _time = DateTime.Now.Ticks;
        private double width, height;
        private double time;

        private Accelerometer _accel = new Accelerometer();
        Vector3 acceleration;
        public MainPage()
        {
            InitializeComponent();

            //järgmised kaks rida on selle jaoks, et telefonile ei tuleks "lukku" peale
            PhoneApplicationService phoneAppService = PhoneApplicationService.Current;
            phoneAppService.UserIdleDetectionMode = IdleDetectionMode.Disabled;

            width = (Application.Current.Host.Content.ActualWidth - Ball.Width) / 2.0;
            height = (MyGrid.Height - Ball.Height) / 2.0;

            // Start acceleroemeter
            _accel.CurrentValueChanged +=
                new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(OnReadingChanged);
            _accel.Start();
        }
        private void OnReadingChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            time = e.SensorReading.Timestamp.Ticks;
            acceleration = e.SensorReading.Acceleration;
            Dispatcher.BeginInvoke(() => UpdateDisplay());
            // käivita UI thread 
        }

        private double calculate(double[] k) {
            double ysum = 0;
            for (int i = 0; i < sum; i++)
                ysum += k[i];
            return ysum;
        }
        private void UpdateDisplay()
        {
            //saadakse kätte kiirendused kolmes suunas
            double x = acceleration.X;
            double y = acceleration.Y;
            double z = acceleration.Z;

            //time on suurusjärgus 0,02 ja = (praegune aeg - eelmine aeg) / 10 000 000
            double ajavahemik = (time - _time) / 10000000.0;

            //ax = ((kiirendus * raskusjõud (1G)) + eelmine kiirendus) / 2
            // keskmine kiirendus kahe ajavahemiku vahel
            double ax = ((x * gravity) + _ax) / 2.0;
            double ay = ((y * gravity) + _ay) / 2.0;

            // vx (kiirus) = eelmine keskmine kiirus + (keskmine kiirendus * aeg [ehk hetkel keskmine kiirus])
            double vx = _vx + (ax * ajavahemik);
            double vy = _vy + (ay * ajavahemik);

            //palli uus asukoht teljel = eelmine asukoht + ((((eelmine kiirus + praegune kiirus) / 2 ) * aeg ) * kordaja=128)
            //lühemalt: palli uus asukoht = eelmine asukoht + käesoleva asukoht
            double sx = _sx + ((((_vx + vx) / 2.0) * ajavahemik) * mul);
            double sy = _sy - ((((_vy + vy) / 2.0) * ajavahemik) * mul);

            //alljärgnev arvutus tekitab põrkamise
            // kui asukoht on väiksem kui -laius. laius on pool ekraanilaiusest - palli läbimõõt
            //siis palli asukoht on minimaalne laius ja kiirus on -kiirus * 0,5
            //(see on siis kiiruse vähenemine poole võrra aga vastassuunas)
            if (sx < -width)
            {
               sx = -width;
               vx = -vx * damping;
           }
           else if (sx > width)
            {
               sx = width;
               vx = -vx * damping;
           }
            if (sy < -height)
            {
                sy = -height;
                vy = -vy * damping;
            }
            else if (sy > height)
            {
                sy = height;
                vy = -vy * damping;
            }
            // salvesta parameetrid järgmise tsükli tarvis
            _time = time;
            _ax = ax;
            _ay = ay;
            _vx = vx;
            _vy = vy;
            _sx = sx;
            _sy = sy;

            //tehakse transformX ning omistatakse sellele asukoha väärtus
            //tulemus on see, et pall liigub ettenähtud kohale
            BallTransform.X = sx;
            BallTransform.Y = sy;

            //joonistatakse kolmemõõtmelised värvilised jooned
            xLine.X2 = xLine.X1 + acceleration.X * 400;
            yLine.Y2 = yLine.Y1 - acceleration.Y * 400;
            zLine.X2 = zLine.X1 - acceleration.Z * 200;
            zLine.Y2 = zLine.Y1 + acceleration.Z * 200;

            //kuvatakse kiirendusnumbrid
            textBlock1.Text = "X: " + x.ToString("0.000");
            textBlock2.Text = "Y: " + y.ToString("0.000");
            textBlock3.Text = "Z: " + z.ToString("0.000");
        }
    }
}

Windows Phone – EASE funktsioonid

EASE-funktsioonid on Silverlightis välja töötatud spetsiaalsete matemaatiliste algoritmidega funktsioonid, mis võimaldavad lihtsal moel objekte erilisel viisil liikuma ja põrkama panna.

Alljärgnevas näites on realiseeritud 4 kõige silmapaistvamat EASE funktsiooni, milleks on

·         BackEase

image

·         BounceEase

image

·         ElasticEase

image

·         ExponentialEase

image

Täpsemalt leiad Ease funktsioonide kohta siit lehelt: http://msdn.microsoft.com/en-us/library/ee308751.aspx 

Vaata kõigepealt antud rakenduse videot, et tekiks parem arusaamine antud funktsioonide eripäradest.

Windows Phone - how Ease functions working

MainPage.xaml

<phone:PhoneApplicationPage
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:Microsoft_Advertising_Mobile_UI="clr-namespace:Microsoft.Advertising.Mobile.UI;assembly=Microsoft.Advertising.Mobile.UI"
   x:Class="PhoneApp1.MainPage"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">

      <Grid x:Name="LayoutRoot" Background="Transparent">
        
        <Canvas>
            <Canvas.Resources>
                <Storyboard x:Name="myStoryboard" Completed="myStoryboard_Completed">
                    <DoubleAnimation x:Name="RectangleAnimation" From="0" To="300" Duration="00:00:04"
                                    Storyboard.TargetName="Myrectangle"
                                    Storyboard.TargetProperty="(Canvas.Top)"
                                    >
                                        </DoubleAnimation>
                    <DoubleAnimation x:Name="RectangleAnimation1" From="650" To="351" Duration="00:00:04"
                                    Storyboard.TargetName="Myrectangle1"
                                    Storyboard.TargetProperty="(Canvas.Top)"
                                    >
                    </DoubleAnimation>
                    <DoubleAnimation x:Name="RingAnimationX" From="0" To="1"
                                    Duration="00:00:04"
                                    Storyboard.TargetName="Ring"
                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
                                    >
                    </DoubleAnimation>
                    <DoubleAnimation x:Name="RingAnimationY" From="0" To="1"
                                    Duration="00:00:04"
                                    Storyboard.TargetName="Ring"
                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" >
                    </DoubleAnimation>
                    <DoubleAnimation x:Name="SliderRotation1" From="0" To="360"
                                    Duration="00:00:06"
                                    Storyboard.TargetName="slider1"
                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" >
                    </DoubleAnimation>
                    <DoubleAnimation x:Name="SliderRotation2" From="0" To="360"
                                    Duration="00:00:03"
                                    Storyboard.TargetName="slider2"
                                    Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" >
                    </DoubleAnimation>

                </Storyboard>
                <Storyboard x:Name="ProgressStoryBoard">
                    <DoubleAnimation x:Name="Progressbar" From="0" To="100"
                                    Duration="00:00:06"
                                    Storyboard.TargetName="progressBar1"
                                    Storyboard.TargetProperty="Value" >
                    </DoubleAnimation>
                </Storyboard>
            </Canvas.Resources>
            <Rectangle x:Name="Myrectangle" Width="50" Height="50" VerticalAlignment="Center" Canvas.Left="27" Canvas.Top="0" Fill="Blue" RadiusX="10" RadiusY="10" />
            <Rectangle x:Name="Myrectangle1" Width="50" Height="50" VerticalAlignment="Center" Canvas.Left="27" Canvas.Top="650" Fill="Red" RadiusX="10" RadiusY="10" />
            <RadioButton Canvas.Left="235" Canvas.Top="6" Content="Back Ease" Height="71" Name="backEase" Width="245" GroupName="EaseRadio" Checked="backEase_Checked" />
            <RadioButton Canvas.Left="235" Canvas.Top="77" Content="Bounce Ease" Height="71" Name="bounceEase" Width="245" GroupName="EaseRadio" Checked="bounceEase_Checked" />
            <RadioButton Canvas.Left="235" Canvas.Top="154" Content="Elastic Ease" Height="71" Name="elasticEase" Width="245" GroupName="EaseRadio" Checked="elasticEase_Checked" />
            <RadioButton Canvas.Left="235" Canvas.Top="231" Content="Exponential" Height="71" Name="exponentialEase" Width="245" GroupName="EaseRadio" Checked="exponentialEase_Checked" />
            <Slider Canvas.Left="235" Canvas.Top="360" Height="344" Name="slider1" Width="80" Orientation="Vertical" Visibility="Visible" SmallChange="0.5" ValueChanged="slider1_ValueChanged" RenderTransformOrigin="0.5,0.5">
                <Slider.RenderTransform>
                    <CompositeTransform Rotation="0"></CompositeTransform>
                </Slider.RenderTransform>
            </Slider>
            <Slider Canvas.Left="329" Canvas.Top="360" Height="344" Name="slider2" Width="80" Orientation="Vertical" SmallChange="0.5" ValueChanged="slider2_ValueChanged" RenderTransformOrigin="0.5,0.5">
                <Slider.RenderTransform>
                    <CompositeTransform Rotation="0"></CompositeTransform>
                </Slider.RenderTransform>
            </Slider>
            <TextBlock Canvas.Left="170" Canvas.Top="309" Height="46" Name="textBlock1" Width="145" TextAlignment="Center" FontSize="24" />
            <TextBlock Canvas.Left="329" Canvas.Top="309" Height="46" Name="textBlock2" Width="145" TextAlignment="Center" FontSize="24" />
            <TextBlock Canvas.Left="235" Canvas.Top="710" Height="51" Name="textBlock11" Width="80" TextAlignment="Center" />
            <TextBlock Canvas.Left="329" Canvas.Top="710" Height="51" Name="textBlock22" Width="80" TextAlignment="Center" />
            <Button Canvas.Left="98" Canvas.Top="697" Content="RUN" Height="71" Name="button1" Width="131" Click="button1_Click" />
            <Ellipse RenderTransformOrigin="0.5,0.5" Height="100" x:Name="Ring" Canvas.Left="117" StrokeStartLineCap="Round" StrokeEndLineCap="Square" StrokeThickness="10" Canvas.Top="607" Width="96">
                <Ellipse.RenderTransform>
                    <CompositeTransform ScaleX="0" ScaleY="0"></CompositeTransform>
                </Ellipse.RenderTransform>
                <Ellipse.Fill>
                    <RadialGradientBrush GradientOrigin="0.23,0.3">
                        <GradientStop Color="Black" Offset="1"/>
                        <GradientStop Color="White"/>
                    </RadialGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <ProgressBar Canvas.Left="0" Canvas.Top="350" Height="1" Name="progressBar1" Width="460" Value="0" Background="White" Foreground="Red" >
            </ProgressBar>
        </Canvas>
    </Grid
>

</
phone:PhoneApplicationPage
>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;


namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {
        int MyRadio = 0;

        public MainPage()
        {
            InitializeComponent();
        }
        private void backEase_Checked(object sender, RoutedEventArgs e)
        {
            //kuvatakse peidetakse vajalikud sliderid ja numbrite näitamised
            slider1.Visibility = Visibility.Visible;
            slider2.Visibility = Visibility.Collapsed;
            textBlock2.Visibility = Visibility.Collapsed;
            textBlock22.Visibility = Visibility.Collapsed;
            textBlock1.Text = "Amplituud";
            //algväärtustatakse slider
            slider1.Value = 1;
            //switchi jaoks määratud nupuvajutus
            MyRadio = 1;
        }

        private void bounceEase_Checked(object sender, RoutedEventArgs e)
        {
            slider1.Visibility = Visibility.Visible;
            slider2.Visibility = Visibility.Visible;
            textBlock2.Visibility = Visibility.Visible;
            textBlock22.Visibility = Visibility.Visible;
            textBlock1.Text = "Põrkeid";
            textBlock2.Text = "Tugevus";
            slider1.Value = 6;
            slider2.Value = 2;
            MyRadio = 2;
        }

        private void elasticEase_Checked(object sender, RoutedEventArgs e)
        {
            slider1.Visibility = Visibility.Visible;
            slider2.Visibility = Visibility.Visible;
            textBlock2.Visibility = Visibility.Visible;
            textBlock22.Visibility = Visibility.Visible;
            textBlock1.Text = "Võnkeid";
            textBlock2.Text = "Vetruvus";
            slider1.Value = 3;
            slider2.Value = 1;
            MyRadio = 3;
        }

        private void exponentialEase_Checked(object sender, RoutedEventArgs e)
        {
            slider1.Visibility = Visibility.Visible;
            slider2.Visibility = Visibility.Collapsed;
            textBlock2.Visibility = Visibility.Collapsed;
            textBlock22.Visibility = Visibility.Collapsed;
            textBlock1.Text = "Exponentsiaalsus";
            slider1.Value = 6;
            MyRadio = 4;
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            switch (MyRadio)
            {
                case 1:
                    BackEase be = new BackEase();
                    be.Amplitude = Convert.ToDouble(slider1.Value);
                    be.EasingMode = EasingMode.EaseOut;
                    RectangleAnimation.EasingFunction = be;
                    RectangleAnimation1.EasingFunction = be;
                    RingAnimationX.EasingFunction = be;
                    RingAnimationY.EasingFunction = be;
                    SliderRotation1.EasingFunction = be;
                    SliderRotation2.EasingFunction = be;
                    break;
                case 2:
                    BounceEase boe = new BounceEase();
                    boe.Bounces = Convert.ToInt32(slider1.Value);
                    boe.Bounciness = Convert.ToDouble(slider2.Value);
                    boe.EasingMode = EasingMode.EaseOut;
                    RectangleAnimation.EasingFunction = boe;
                    RectangleAnimation1.EasingFunction = boe;
                    RingAnimationX.EasingFunction = boe;
                    RingAnimationY.EasingFunction = boe;
                    SliderRotation1.EasingFunction = boe;
                    SliderRotation2.EasingFunction = boe;
                    break;
                case 3:
                    ElasticEase ee = new ElasticEase();
                    ee.Oscillations = Convert.ToInt32(slider1.Value);
                    ee.Springiness = Convert.ToDouble(slider2.Value);
                    ee.EasingMode = EasingMode.EaseOut;
                    RectangleAnimation.EasingFunction = ee;
                    RectangleAnimation1.EasingFunction = ee;
                    RingAnimationX.EasingFunction = ee;
                    RingAnimationY.EasingFunction = ee;
                    SliderRotation1.EasingFunction = ee;
                    SliderRotation2.EasingFunction = ee;
                    break;
                case 4:
                    ExponentialEase xe = new ExponentialEase();
                    xe.Exponent = Convert.ToInt32(slider1.Value);
                    xe.EasingMode = EasingMode.EaseOut;
                    RectangleAnimation.EasingFunction = xe;
                    RectangleAnimation1.EasingFunction = xe;
                    RingAnimationX.EasingFunction = xe;
                    RingAnimationY.EasingFunction = xe;
                    SliderRotation1.EasingFunction = xe;
                    SliderRotation2.EasingFunction = xe;
                    break;
            }
            ProgressStoryBoard.Begin();
            myStoryboard.Begin();
            }
        private void myStoryboard_Completed(object sender, EventArgs e)
        {
            //myStoryboard.Stop();
        }

        private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            textBlock11.Text = slider1.Value.ToString("0.00");
        }

        private void slider2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            textBlock22.Text = slider2.Value.ToString("0.00");
        }
    }
}