lejos-ohjelmointi Robottiohjelmoinnin harjoitustyö, kevät 2013
|
|
- Pertti Haavisto
- 9 vuotta sitten
- Katselukertoja:
Transkriptio
1 lejos-ohjelmointi Robottiohjelmoinnin harjoitustyö, kevät
2 Ohjelmoinnin aloittaminen Ennen ohjelmoinnin aloittamista on lejos-firmware kirjoitettava NXT:lle Varmista ensin, että akut on ladattu Kirjoitus tapahtuu valikosta lejos lejos Tools lejos NXJ Flasher GUI Kun firmware on kirjoitettu, NXT käynnistyy lejosiin ja valikko tulee näkyviin NXT:n voi sammuttaa tässä tilassa painamalla Escape-nappia (oranssin Enterin alapuolella) ja käynnistää jälleen painamalla Enter-nappia Muussa tapauksessa painamalla Enter- ja Escapenappeja yhtäaikaa
3 lejos-valikko Ruudun yläreunassa näkyy akkujen tila ja Bluetoothikoni Bluetooth-tiedonsiirto näkyy yhden pikselin korkuisena liikkuvana viivana ikonin alla Valikossa on seuraavat toiminnot Files palikan tiedostot: ohjelmien käynnistäminen, poistaminen ja asettaminen oletusarvoiseksi, ääninäytteiden soittaminen ja kuvien katselu Bluetooth Bluetooth-asetukset Sound Äänenvoimakkuusasetukset System Muistin tila ja sen alustus, uniajastin Version Versiotietoja
4 Ohjelman ajaminen Ohjelma siirretään tietokoneelta palikalle USBkaapelia tai Bluetooth-yhteyttä käyttäen Koodi käännetään ja linkataan NXT:lle lähetettäväksi, tuloksena on.nxj-tiedosto Kun NXT on vastaanottanut tiedoston, se päästää nousevan melodian ja ajaa ohjelman Ohjelman voi käynnistää myöhemmin uudestaan myös lejosin valikosta Automaattinen käynnistys on mahdollista ottaa pois käytöstä muokkaamalla build.xml-tiedostoa
5 Ohjelman ajaminen (jatk.) Kun ohjelma päättyy, lejos käynnistyy uudelleen valikkoonsa Jos esimerkiksi ohjelman tulostetta halutaan tarkkailla sen päätyttyä, pitää ohjelman loppuun lisätä napin painalluksen odottaminen tai viive, koska muuten tekstiä ei ehditä näkemään ennen uudelleenkäynnistymistä
6 Tiedostojen tallentaminen NXT:lle NXT:ssä on lejosin kirjoittamisen jälkeen noin 160kB vapaata flash-muistia ohjelmille Tähän mahtuu ohjelmia yllin kyllin, mutta tiedostotaulun koko on rajallinen, vain 256 tavua Tähän 256 tavuun pitää mahtua kaikkien tiedostojen nimet osoittimineen Tästä syystä tiedostonimien pituus saattaa täyttää muistin vaikka varsinaista tilaa olisi paljon jäljellä Hyvä pitää mielessä ja käyttää tarpeen mukaan lyhyempiä nimiä
7 NXT:n muisti ja lejos NXT:ssä on 64kB RAM-muistia, josta lejosohjelmalle on käytössä noin 58kB Ihan mitä tahansa ei muistiin mahdu lejos toteuttaa roskienkeruun, joten muistin vapauttamisesta ei tarvitse huolehtia itse Käytännössä muistin vähyys ei vaikuta suuremmin ohjelmointiin kun käytetään riittävän kevyitä tietorakenteita Dataa voi myös tallettaa flash-muistiin tiedostoksi jos halutaan suurempia määriä talteen
8 lejosin ominaisuuksia lejos on varsin kattava paketti ja mahdollistaa hyvin monimutkaistenkin robottien luomisen Ytimenä palikalla pyörivä pieni JVM jota tukee laitteistotason koodi Javan ominaisuuksista suuri osa olennaisimmista asioista on toteutettu Muun muassa: säikeet, moniulotteiset taulukot, rekursio, synkronointi, poikkeukset, eri tietotyypit, suurin osa java.lang, java.util ja java.io -luokista, ajastimet, kuuntelijat, hajautustaulut, iteraattorit ja niin edelleen
9 lejosin ominaisuuksia (jatk.) Myös toimintoja grafiikan piirtämiseen, äänen soittamiseen, tiedostojärjestelmän hallintaan Palikkaa voi etähallita Bluetoothilla ilman, että siinä itsessään ajetaan erillistä ohjelmaa (LCP) Näiden lisäksi lejosin pihvi on sen sisältämät robotiikkatoiminnot ja sensorien tuki Korkean tason abstraktioita erilaisille kaksipyöräisille Navigointi-, polunetsimis- ja karttatoimintoja Paikannustoimintoja (Monte Carlo) Rajapintojen käyttäminen tekee eri osasten yhteen sovittamisesta helppoa
10 lejos-ohjelman rakenne lejos-ohjelma ei eroa tavallisesta Java-ohjelmasta: public class HelloWorld { public static void main (String[] args) { } } System.out.println( Hello World ); Button.waitForPress(); Ohjelma tulostaa tekstin ja odottaa napin painallusta, jonka jälkeen palaa lejos-valikkoon Palikka suorittaa luokan main()-metodin
11 lejos-ohjelman rakenne (jatk.) Pääohjelmaa tukevia luokkia voi normaaliin tapaan kirjoittaa ja luoda näistä ilmentymiä Yksinkertainen ohjelma voi koostua esimerkiksi päättymättömästä while-silmukasta, jossa luetaan antureita ja liikutetaan lukeman perusteella moottoreita Monimutkaisemmat ohjelmat vaativat säikeitä Näiden käyttö on onneksi helppoa mutta rinnakkaisuuden hankaluudet ovat toki olemassa Oikeastaan käynnistyessään lejos pyörittää jo useita säikeitä
12 NXT-palikan toimintoja Napit ovat nimeltään ENTER, ESCAPE, LEFT, RIGHT ja määritelty luokassa Button Tilan lukeminen while(!button.enter.ispressed); Odota, kunnes Enteriä painetaan Button.ENTER.waitForPressAndRelease(); Odota, kunnes Enteriä painetaan Button.readButtons(); Palauttaa int:n, jossa bitit asetettu painettujen nappien mukaan: 1 = Enter, 2 = Left, 4 = Right, 8 = Escape 0 tarkoittaa, ettei mikään nappi ole pohjassa Button.waitForPress(2000); Odota painallusta 2000ms ajan, palauttaa kokonaisluvun kuten yllä
13 NXT-palikan toimintoja (jatk.) Tekstin tulostus Perinteisesti System.out.println( moikka ); Haluttuun kohtaan Grafiikka LCD.drawString( moikka, 0, 4); // (merkkijono, x, y) Mahdollista piirtää viivoja, neliöitä, ympyröitä, erikokoista tekstiä ja niin edelleen Kokeile samples/graphicstest
14 NXT-palikan toimintoja (jatk..) Äänen soittaminen Haluttu korkeus ja kesto Sound.playTone(2500, 1000); // 2500 Hz, 1000 ms Erilaisia systeemiääniä Sound.beep(), Sound.twoBeeps(), Sound.beepSequence(), Sound.beepSequenceUp(), Sound.buzz() Instrumentit (ks. API) Sound.playNote(Sound.XYLOPHONE, 2000, 300); WAV-tiedoston soittaminen (8 khz, 8-bit, mono) File hihat = new File( hihat.wav ); Sound.playSample(hihat);
15 Äänien (.wav) soittaminen WAV-tiedostot ovat pakkaamattomia ja muistiin ei siten mahdu pitkiä näytteitä Koska äänenlaatu on heikko, mahtuu palikkaan kuitenkin tyydyttävästi ääniä, esimerkiksi muutamia sanoja ja joitain sekunteja musiikkia Äänistä kannattaa leikata turhat alkuhiljaisuudet ynnä muut pois tilan säästämiseksi Lyhyistä näytteistä voi rakentaa esimerkiksi musiikkia tai lauseita Konversio sopivaan muotoon rojbosissa: sox -S -t wav -c 1-1 -r 8000 input.wav output.wav
16 Moottorit Moottoreita voidaan ohjata monin tavoin, erikseen käskemällä tai abstraktion kautta lejos käynnistää kullekin moottorille regulaattorisäikeen, joka pyrkii pitämään pyörimisnopeuden tasaisena säätämällä moottorin tehoa tarpeen mukaan Reguloinnin voi myös kytkeä pois päältä ja moottoreita ohjata asettamalla niille haluttu teho Moottoreita voidaan pyörittää haluttuun suuntaan tai käskeä liikkumaan tiettyyn kulmaan Takometrin voi nollata milloin vain, jolloin moottori katsoo olevansa kulmassa
17 Moottorit (jatk.) Reguloiduilla moottoreilla voidaan säätää kiihtyvyyttä ja nopeuden pitäminen tasaisena on helpompaa Moottoreilla on eri tiloja Liikkeessä (forward(), backward(), rotateto(..) jne.) Pysäytetty (stop()) Moottori pyrkii pitämään nykyisen sijaintinsa ja käyttää voimaansa kaiken liikkeen vastustamiseen Voimaton (flt()) Moottori ei käytä voimaa liikkumiseen tai liikkeen vastustamiseen
18 Moottorit (jatk..) Moottoreihin pääsee käsiksi eri tavoin luokkahierarkiasta BasicMotor on alhaisen tason luokka, joka toteuttaa alkeellisimmat ominaisuudet (voimansäätö, käynnistäminen, tilan seuranta) älä käytä NXTMotor on tästä ylempi abstraktio, jossa ei ole nopeuden säätelyä ja jolta saadaan takometrin lukema käytä tarvittaessa (harvoin) NXTRegulatedMotor käyttää regulaattorisäiettä ja mahdollistaa nopeuden asettamisen asteina sekunnissa käytä jos tarvitset yksittäisen moottorin ohjaamista
19 Moottorit (jatk...) Pilottiluokat (DifferentialPilot jne.) mahdollistavat kaksipyöräisen robotin ohjaamisen ilman moottorien käskyttämistä erikseen ja tarjoavat paljon liikettä helpottavia toimintoja, kuten ympyrän kaarta pitkin ajon, kääntymisen asteina ja matkan kulkemisen mittayksiköissä käytä aina kun mahdollista Motor-luokka sisältää kolme staattista NXTRegulatedMotor-instanssia kullekin moottorille A, B, C Jos halutaan viitata siis johonkin moottoriin esimerkiksi pilottien konstruktoreissa, voidaan sanoa kätevästi Motor.A kun tarkoitetaan porttiin A kytkettyä moottoria MotorPort-luokka sisältää vastaavat eri porteille
20 Moottorit (jatk...) Matalan tason moottoriohjaus voi tapahtua esimerkiksi seuraavasti, jossa asetetaan moottori pyörimään 50% voimalla eteenpäin NXTMotor moottori = new NXTMotor(MotorPort.A); moottori.setpower(50); moottori.forward(); Reguloidulla moottorilla voidaan antaa kääntymisen astemäärä ja kulmanopeus Motor.A.setSpeed(180); // 180 astetta / sekunti Motor.A.rotate(45); // käänny 45 astetta eteenpäin Motor.A.rotateTo(0); // käänny takaisin lukemaan
21 Moottorit (jatk...) Kaksipyöräisten robottien kanssa on helpointa käyttää esimerkiksi DifferentialPilot-luokkaa Seuraava rivi loisi esimerkkirobottia ohjaavan pilotin DifferentialPilot pilot = new DifferentialPilot(5.6f, 17f, Motor.A, Motor.B); Renkaiden halkaisija (5.6 cm, 2.0-setissä cm) Renkaiden keskipisteiden välinen etäisyys (17 cm) Vasen moottori (Motor.A) Oikea moottori (Motor.B)
22 Moottorit (jatk...) Ilmentymän luonnin jälkeen pilottia voidaan ohjata eri tavoin pilot.settravelspeed(10); // 10 cm sekunnissa pilot.setrotatespeed(90); // 90 astetta sekunnissa pilot.travel(40); // aja 40 cm eteenpäin // 50 cm-säteisen ympyrän kaarta pitkin ajaminen 90 // asteen verran pilot.arc(50,90); pilot.rotate(10); // käänny 10 astetta vasemmalle pilot.travelarc(50, 100); // kulje 100 cm kaarta pitkin
23 Moottorit (jatk...) Pilotit helpottavat robotin ohjaamista suunnattomasti Edellyttää itsenäisesti ohjautuvia pyöriä ja strategisten mittojen syöttämistä Kuitenkin lähtökohtaisesti epätarkka, koska ainoa tieto liikkeestä saadaan moottorien takometreistä Jos esimerkiksi pyörä lipsahtaa tai robotti osuu esteeseen, se ei pysty korjaamaan liikettään Ongelmaa voidaan lievittää antamalla robotille enemmän tietoa sijainnistaan, esimerkiksi kompassilla tai ultraäänisensorilla
24 Sensorit Sensorien lukeminen tapahtuu luomalla ilmentymä halutusta sensorista, missä konstruktorille määritellään portti johon sensori on kytketty UltrasonicSensor sonic = new UltrasonicSensor(SensorPort.S4); LightSensor light = new LightSensor(SensorPort.S1); Ilmentymän luomisen jälkeen voidaan lukea sensorin arvoja int distance = sonic.getdistance(); // lue etäisyys int lightlevel = light.getlightvalue(); // lue valoisuus
25 Valosensori Valosensorin voi kalibroida halutulle valoisuusvälille tai lukea absoluuttisia sensoriarvoja (0-1023) Olennaisimmat toiminnot getlightvalue() palauttaa Prosenttilukema kalibroidulla välillä ks. calibratelow() & calibratehigh() getnormalizedlightvalue() palauttaa Absoluuttinen sensorin arvo setfloodlight(boolean) kytke ledi päälle/pois
26 Ultraäänisensori Ultraäänisensorilla on useita toimintoja ja mittaustiloja, mutta hienostelulle on harvemmin tarvetta Sensori ilmoittaa arvonsa (cm) Käytännössä pienin etäisyys on noin 3 cm Lukema 255 tarkoittaa ei kaikua Olennaisimmat toiminnot getdistance() palauttaa etäisyyden senttimetreissä Mittaustila voidaan vaihtaa tuumiin (älä suotta)
27 Kosketussensori Kosketussensori on vain nappi jolla on kaksi tilaa Käyttäminen yksinkertaista Toiminnot ispressed() true jos nappi on pohjassa, false muuten
28 Äänisensori Sensori mittaa äänenpainetta, ei taajuutta Ei sisälly 2.0-settiin Mittaustiloja on kaksi, (db/dba) Eri taajuusvasteet Toiminnot setdba(boolean) true = dba-tila, false = db-tila readvalue() palauttaa arvon prosentteina
29 Värisensori NXT 2.0 -setissä on valosensori korvattu kyvykkäämmällä värisensorilla Sisältää punaisen ledin sijaan kolmiväriledin (RGB) Mahdollistaa kuuden eri värin erottamisen Valkoinen, musta, keltainen, punainen, vihreä, sininen Toimii väläyttämällä lediä eri värisenä nopeasti ja yhdistämällä havainnot Allekirjoittanut ei ole tätä vielä ehtinyt kokeilla Tärkeimmät toiminnot getcolor() kalibroitu lukema Color-oliona getrawcolor() raaka lukema Color-oliona
30 Kompassisensori Kompassista voi lukea suuntiman asteen tarkkuudella asteikolla Sijoittelu ratkaisevaa Tarpeeksi kauas aktiivista osista ja ulkoisista sähkömagneettisista häiriöistä (ainakin 10 cm moottoreista ja palikasta) Herkkä nykäisyille ja heilumiselle Kompassin pitää olla vaakasuorassa asennossa mittauksen onnistumiseksi Vain muutama kappale kurssilla käytettäväksi :(
31 Kompassisensori (jatk.) Olennaisimmat toiminnot Kompassisuuntima (0-360, myötäpäivään kasvava) getdegrees() Nollattu suuntima (0-360, vastapäivään kasvava) resetcartesianzero() aseta nollakohta getdegreescartesian() lue arvo suhteessa nollakohtaan Kalibrointi Kalibrointi suoritetaan kutsumalla startcalibration()- metodia, laittamalla robotti pyörimään esimerkiksi 720 astetta ja kutsumalla stopcalibration()-metodia liikkeen pysähdyttyä Pyöritystä ei kannata yrittää tehdä käsin
32 Harjoittelua
33 Käytösmallit Robottikoodi voidaan toteuttaa suoraviivaisesti ehtolausekkeita ja silmukoita käyttäen Tämä kuitenkin johtaa ennen pitkää siihen, että toimintaa on vaikea muuttaa hajottamatta kokonaisuutta lejos tarjoaa subsumption-arkkitehtuurin, joka mahdollistaa robotin käytöksen kuvaamisen käytösmoduuleina, jotka ovat Behavior-rajapinnan toteuttavan luokan ilmentymiä Toiminta voidaan määritellä toistensa suhteen priorisoituina loogisina toiminnan yksiköinä, jotka aktivoituvat eri tilanteissa Robotti voidaan kuvata tilakoneena
34 Käytösmallit (jatk.) Kokonaiskäytöstä ohjaa Arbitrator-luokka, joka erillisessä säikeessä tutkii toteutuuko jonkin käytöksen käynnistävä ehto Arbitratorille annetaan käytösmoduulit konstruktorissa Behavior[]-taulukkona, suurempi taulukon indeksi tarkoittaa korkeampaa prioriteettia Arbitrator arb = new Arbitrator(new Behavior[]{new Ajele(), new LopetaOhjelma()}); Ajele ja LopetaOhjelma ovat Behavior-rajapinnan toteuttavia luokkia LopetaOhjelma-käytöksellä on korkein prioriteetti Ehdot testataan peräjälkeen korkeimman prioriteetin käytöksestä matalimpaan
35 Käytösmallit (jatk..) Vain yksi käytös on kerrallaan toiminnassa Aktiivisena olevan käytöksen prioriteetti on korkein Toiminta suoritetaan loppuun, ellei sitä erikseen keskeytetä käytöksen sisällä Käytös ei saa sisältää ikuista silmukkaa! Rajapinnan toteuttava käytösmoduuli sisältää seuraavat metodit public boolean takecontrol() palauttaa true, kun käytöksen aloittamisen edellyttämä ehto täyttyy public void action() varsinainen toiminta public void suppress () toiminnan päättäminen
36 Käytösmallit (jatk...) Tyypillinen takecontrol() public boolean takecontrol() { } return Button.ENTER.isPressed(); Tyypillinen action() public void action() { } System.exit(0); Näistä ja tyhjästä suppress-metodista voisi muodostua käytös LopetaOhjelma
37 Käytösmallit (jatk...) suppress-metodia ei usein tarvitse edes erikseen määritellä Tarkoituksena suorittaa action()-metodin siististi keskeyttävät toimenpiteet Suositeltu tapa on käyttää luokan sisäistä booleanmuuttujaa suppressed, jonka action()-metodi ensimmäisellä rivillään asettaa arvoon false, mutta tarkistaa sitä käytöstä suorittaessaan Jos Arbitrator katsoo, että tämä käytös pitää alistaa, se kutsuu käytöksen suppress()-metodia, joka asettaisi suppressed-muuttujan arvoon true, jolloin action()- metodi lopettaisi toimintansa Jos action()-metodit ovat hyvin lyhyitä eivätkä voi jäädä jumittamaan, suppress voi olla tyhjäkin
38 Käytösmallit (jatk...) Alimman prioriteetin peruskäytös voidaan määritellä kätevästi public boolean takecontrol() { } return true; Näin käytös aktivoituu aina jos mikään sitä korkeamman prioriteetin käytös ei halua aktivoitua Käytännön esimerkki voisi olla esimerkiksi robotti, joka kulkee eteenpäin kunnes ultraäänisensori havaitsee esteen alle 20 cm etäisyydellä, jolloin robotti tekee 90 asteen käännöksen vasemmalle
39 Käytösmallit (jatk...) public class Vaistelija { DifferentialPilot pilot = new DifferentialPilot(...); UltrasonicSensor sonic = new UltrasonicSensor(...); Arbitrator arb; class Aja implements Behavior { public boolean takecontrol() { return true; } // ei tarvita suppressia, koska forward() palaa heti public void action() { pilot.forward(); } public void suppress() { } }
40 Käytösmallit (jatk...) } class Vaista implements Behavior { } public boolean takecontrol() { } return sonic.getdistance() < 20; public void action() { pilot.rotate(90); } public void suppress() { } public Vaistelija (...) { } arb = new Arbitrator(new Behavior[]{ new Aja(), new Vaista()}); arb.start();
41 Käytösmallit (jatk...) Nyt Vaistelija-robotti voidaan luoda tekemällä pääohjelma public class VaistelijaTest { public static void main (String[] args) { } } // parametreina voitaisiin antaa esimerkiksi pilotin // mitat, käytetyt moottori- ja sensoriportit jne. Vaistelija veikko = new Vaistelija(...);
42 Käytösmallit (jatk...) Käytösmalleilla voi luoda nopeasti monimutkaisia käytöksiä ja muunnella näitä helposti Mahdollisuus kaatua omaan näppäryyteensä Käytösmallit vaativat hieman suunnittelua, mutta oikein tehtynä tekevät koodista joustavampaa, helpommin ymmärrettävää ja toimivampaa Joskus yksinkertaisemmat lähestymistavat voivat kuitenkin toimia paremmin tai käytösmalliabstraktio on liian raskas käyttää
43 Rakentelusta Setissä on paljon pieniä osasia Käytännön vinkki: suorita kasaaminen jollain reunallisella alustalla Esimerkiksi muovisen säilytyslaatikon kansi, jossa on uria, toimii varsin hyvin ja paloja voi ryhmitelläkin Palat eivät lentele pitkin ja ovat helppoja löytää Modulaarisuus on valttia Robotti on hyvä rakentaa niin, että se koostuu selkeistä kokonaisuuksista, jotka voi tarvittaessa irrottaa pienellä vaivalla jos robottiin pitää tehdä muutoksia Helppo sanoa
44 Rakentelusta (jatk.) Pyri jättämään paristoluukulle tilaa aueta, ettei robottia tarvitse purkaa (paljoa) akkuja vaihdettaessa Rakennusohjeita on netissä hyvin paljon ja näistä kannattaa häikäilemättömästi lainata ideoita ja mekaanisia kikkoja Youtube-videot Constructopedia Lego Engineering jne. Valmista mallia on hyvä alkaa muokkaamaan
45 Rakentelusta (jatk..) Jotta robotti suoriutuisi tehtävästään hyvin, pitää sille tehdä asiat mahdollisimman helpoksi Tukeva rakenne liikevirheiden minimoimiseksi Painopiste alas, rakenteet tuetaan eri suunnista ja pyritään pitämään tiiviinä Koita kevyesti väännellä ja hypistellä robottia eri puolilta Jos osat heiluvat tai eivät ole suorassa toistensa suhteen, kiinnitä ne paremmin, mikäli ne ovat olennaisia toiminnan kannalta Liian jykevä rakenne taas voi vääntää osia vinoon Huolellisesti tehty rakenne voi tehdä eron toimivan ja toimimattoman toteutuksen välillä Hyvälle robotille voi koodata luottavaisin mielin
46 Rakentelusta (jatk...) Jos rakennat niveliä, käytä harmaita ja beigejä tappeja Nämä ovat mustia ja sinisiä tappeja väljempiä Lineaarinen liike voidaan saada aikaiseksi esimerkiksi mäntärakenteella tai hammastangoilla Hammastankoja ei valitettavasti setissä ole valmiina Hauskoja ideoita: Kestää jonkin aikaa että osat tulevat tutuiksi