MJR NXT Log-blog

fredag den 18. januar 2008

Rettelser til Blog, afsluttende kommentarer

Idag lavede vi rettelser til Blog'en. Dette foregik i CVS: Vejfinder/docs/rapport.html

Redigering

Varighed fredag d. 18: 9 timer, Deltagere: Rolf, Janus

Varighed lørdag d. 19: 7 timer, Deltagere: Rolf, Janus

Varighed torsdag d. 24: 2 timer, Deltagere: Janus

Afsluttende kommentar

Fremlæggelsen

Til fremlæggelsen startede vi naturligvis med det vi havde skrevet vi ikke burde gøre, nemlig at bruge den sidste kalibrering af lyset fra ca. en halv times tid inden vi fremlagde. Dette resulterede selvfølgelig i at robotten ikke så farverne på vejen korekt, og at den derfor fandt et t-kryds som et fuldt kryds. Efter en hurtig rekalibrering virkede det hele dog efter hensigten.
Da robotten nåede til det kryds, der var i vejnettet, og begyndte sin autokalibrering, var det tydeligt at der var lidt mere at arbejde med her. Robotten korrigerer nemlig kun ca. 0.5cm for hver gang den har målt sin vinkel på en akse. Som vi også sagde under fremlæggelsen ville vi gerne have regnet den eksakte afvigelse ud således at vi bare kunne justere robotten præcist det stykke, som den var ved siden af. Dette havde vi dog ikke nået. Ellers forløb hele fremlæggelsen efter planen, robotten fandt det kort vi havde lavet. Selve manøvreringen på det fundne kort virkede også som det skulle og robotten kørte glad og veltilfreds rundt på kortet.

Ideer / Udvidelser

Havde tiden været til det, var der flere ting, som vi synes kunne være interresante at undersøge. Vi ville gerne have set om det ville have været muligt at lave endnu mere præcis navigation, hvis vi havde haft en NXT compass sensor. Yderligere kunne det være interessant om det havde været nemmere at detektere vejen, hvis vi havde brugt farvesensorer istedet for lyssensorer. Vi ville også gerne have undersøgt muligheden for at sætte flere NXT'er sammen via Bluetooth og på den måde finde kortet hurtigere ved at lade flere robotter samarbejde.
Ideelt set ville meget gerne have prøvet med nogle større kort, men der var desværre ikke flere vejmoduler end de vi nu engang havde. Der er ingen tvivl om at vi sagtens ville kunne bruge mere tid på et så spændende projekt, og at der er masser af sjove ting, der endnu kunne udforskes, laves og testes.

Overordnet konklusion

Vi gik ind i projektet med et håb om at kunne lave en robot, der fandt alle de kort vi kunne smide efter den. Det var også vigtigt for os at den kunne finde de orginale lego vej moduler istedet for blot "hjemmelavet vej" med hvidt papir og sort tape. Et andet vigtigt kriterie for os var at robotten bagefter kunne køre rundt på kortet ved hjælp af shortest paths. Kigger vi på robotten/projektet som det var til fremlæggelsen, må vi sige at vi har nået vores mål med projektet. Der er ingen problemer med at finde de kort vi har bygget, og alt lige fra Bluetooth-kommunikation til TachoNavigator virkede.

Af problemer under projekt arbejdet kan nævnes: Kalibrering af TachoNavigator, kalibrering af lys sensorer, batteri niveauet og små unøjagtigheder i TachoNavigator. Selve kalibreringen af TachoNavigator kom vi til sidst til livs på ved at bruge den nye kalibreringstest, som vi nævner i Blog9. Efter at afstanden imellem hjulene er sat så præcist som muligt, var det kun små unøjagtigheder der var tilbage. Disse små unøjagtigheder, som langsomt hobede sig op, blev så igen rettet ved vores autokalibreringsalgoritme. Det endte med at TachoNavigator var ganske brugbar til at navigere rundt efter på trods af at den fra starten så ud til at være meget unøjagtig.
Hvad angår lyssensorerne, var deres nøjagtighed afhængig af kalibreringen og hvordan lyset i rummet var. Hvis man blot har dette i baghovedet, og heletiden rekalibrerer når lyset ændrer sig, er det ikke noget større problem.
Omkring batteriet fandt vi på den hårde måde ud af at tacho-sensorerne ikke virker optimalt ved lave spændinger, og man derfor skal sørge for at lade batteriet op ofte. Igen er det bare et spørgsmål om at være opmærksom på dette, men det gav alligevel lidt kvaler indtil vi havde identificeret problemet.

Selve vejfindingsprogrammet til NXT'en havde vi delt op i behaviours, hvilket viste sig at være en rigtig god ide. Nederst havde vi LineFollower, som bare forsøger at følge højrekanten af vejen. Herpå ligger så GridBuilder, som holder øje med hvilken vej robotten bevæger sig på og opbygger kortet. Når det var nødvendigt kunne GridBuilder bare tage over ved at supresse LineFollower. Ovenpå igen har vi MapFollower, som kan køre mellem 2 punkter på kortet via en shortest path. Når en "del" af kortet er fundet bliver GridBuilder og LineFollower supressed, robotten kører til et endnu ukendt område og "fortsætter herfra". Eftersom vores robot er blevet ganske god til at finde kortene, må det siges at denne opbygning har været en success.
Til bluetooth kommunikationen havde vi en thread, som kører i baggrunden på NXTen og som giver mulighed for at "logge" på robotten. Netop det at alt dette foregår i en isoleret thread betyder at ligemeget hvilken behavior, der er aktiv, og ligemeget hvad robotten er igang med, er det muligt at kommunikere med den. Også dette er vi blevet meget tilfredse med - det har været en stor hjælp med debugging at kunne se noget mere output end bare NXTens LCD display. F.eks. har vores UI en "freemem"-indikator, så vi hele tiden kan se hvor meget hukommelse NXTen har tilbage. Dette brugte vi til at sørge for at ingen af vores metoder havde memleaks.

Selve UI'en er vi er tilfredse med, da den giver et rigtigt godt indblik i hvordan robotten virker; og så har det som nævnt været en stor hjælp mht. debugging at at have adgang til masser af information fra NXTen. Det at kunne se det færdige kort på skærmen er utroligt tilfredsstillende.

Alt i alt er det et utroligt vellykket projekt, og vi er kommet godt rundt om alle de forhindringer, som vi er stødt imod undervejs. Vi har nået de mål, som vi satte i starten af projektet - og det er vi glade for.
Det har også været sjovt at kombinere lego-bygning, programmering og algoritmedesign i et enkelt fag og se resultaterne af arbejdet udfolde sig i den fysiske verden.

Relevante informationer

fredag den 11. januar 2008

Eksamensforberedelse

Blog10: Eksamensforberedelse

Varighed: 7 timer, Deltagere: Mads og Janus

Formålet med dagens øvelsesgang er at gøre projektet klart til fremlæggelse d. 17.

Planen for dagen er følgende:

  • Find den fejl i Bluetooth kommandoen doGoto, som gør at robotten "kører i trekanter" når kommandoen bliver udført.
  • Find fejlen i kommandoen doCalibrate, som gør at den "kører lidt i trekanter" og derefter ikke kalibrerer.
  • Find ud af om autokalibreringen kan forbedres.
  • Check om belysningen i fremlæggelseslokalet er til at have med at gøre (ie. ensartet belysning)

Find fejlen i Bluetooth kommandoen doGoto

Der var to problemer. Det første problem vi observerede var, at når vi beordrede robotten til at bevæge sig til et bestemt sted på kortet, så skete der ingenting. Dette problem var grundet i at en del af kommunikationsprotokollen ikke stemte overens imellem computer og robot. Rettelsen her var naturligvis at vælge at implementere den aftalte protokol; helt præcist hvordan denne konflikt er opstået er uklart.

Det andet problem vi mødte i forbindelse med doGoto var at robotten i nogle tilfælde kørte til centrum af nærvedliggende vejblokke før den udførte selve vejfinder-delen af kommandoen. Problemet var periodisk - det skete ikke hver gang vi forsøgte at bede robotten om at flytte sig imellem den samme start- og slutblok. Løsningen lå i noget, som vi tidligere havde diskuteret i forbindelse med korttegning på skærmen - nemlig i den metode, der udregner hvilken blok robotten står i ud fra et sæt koordinater i Navigatorens koordinatsystem.

Find fejlen i kommandoen doCalibrate

Vi kunne ikke se hvad doCalibrate egentlig foretog sig før vi fik rettet doGoto. Derefter kunne vi se at den nu virkede korrekt, bortset fra at den ikke kalibrerede; den fandt et kalibreringspunkt (et kryds), og så stoppede den. Løsningen var at dreje robotten i en bestemt retning og rent faktisk kalde kalibreringsmetoden...

Find ud af om autokalibreringen kan forbedres

Under autokalibrering havde robotten problemer med at rette sig pænt ind. Efter at have betragtet robottens bevægelsesmønster opdagede vi, at der var problemer med græskantsgenkendelse; legopladerne er opbygget med et smalt "fortov" adskilt fra den egentlige vej med en græsstribe, hvilket sensorerne nogle gange opdagede, andre gange ikke. Vi ville bruge græskanten til at kalibrere rotationen. Dette gøres når vi er på vej ud af krydset efter at have kalibreret positionen. Af denne grund havde detekteringen af græskanten stor betydning for præcisionen af rotationskalibreringen. Tilfældighed af denne slags gjorde autokalibreringen mindre brugbar.

Løsningen var at "fjerne fortovet", altså at sætte tape over den smalle vejstribe, hvilket bevirkede at den gang på gang stillede sig ganske præcist langs den valgte retning.

Check belysningen i fremlæggelseslokalet

Lyssensorerne er ganske følsomme overfor lysændringer. Sidebelysning og genskin fra f.eks. spots og solen ændrer de aflæste værdier så meget, at forskellen mellem græs og vej nogle steder udviskes. Som nævnt i en tidligere blogpost omkring lyssensorerne blev vi enige om at bruge et threshold-system med kalibrering, så det kræver at lyset på vejnettet er nogenlunde ligeligt fordelt uden store forskelle. Jævnt distribueret lys er vi glade for - så lysstofrør eller ovenlys, der befinder sig højt over os er at foretrække, mens vi dog kan acceptere en vis fejlmargin på lyssensorerne. Vi fandt ud af at lyset i Store Auditorium er ganske perfekt, da der kan blændes af for solen, spots kan slukkes og loftsbelysningen er ca. ti meter over gulvhøjde. Desværre er det ikke der vi skal fremvise projektet, så det er heldigt at Zuse også har en lyssætning der kan bruges.

Konklusion

Vi har afprøvet robotten under mange forskellige forhold, og det virker som om at systemet er helt stabilt og klar til fremvisning. Dog er vi overbevist om at en kalibrering er nødvendig inden fremvisning, da det omkringværende miljø nok ikke er som under sidste test.

onsdag den 19. december 2007

Vejfinder 9

Blog9:

Varighed: 7 timer, Deltagere: Rolf og Janus

Dagens mål er at færdiggøre selve projekt-delen, så robotten kan finde et relativt stort kort med så få problemer som muligt

Vi vil opnå vores mål idag ved at:

  • Rette fejl i vores kalibreringsmetoder
  • Finde kilden til den store mængde fejlrotationer, som begyndte at opstå i går eftermiddag.
  • Kigge på muligheder for dynamisk at justere den aktuelle rotation i koordinatsystemet baseret på input fra sensorer. Rotationen er den eneste problematiske variable faktor; specielt fordi den akkumulerede fejlmargin over tid er problematisk i sig selv - og den skaleres når der køres ligeud.
  • Forsøge at rette i BlueTooth-kommunikationsklassen, så den kan genoptage en forbindelse, hvor kommunikationslinket har været brudt

Korrekt kalibrering er vigtigt

Tidligere i denne blog (i afsnittet omkring robotten som finder vej rundt om kasser) fandt vi ud af at lejOS systemet ikke roterer præcist 90 grader når man laver rotate(90). Istedet roterer den ca. 88-92 grader, men gemmer fejlen i systemet. Kalibreringsmetoden fra i går antog at robotten foretog 90-graders sving og var derfor forkert, hvilket resulterede i en direkte forkert kalibrering.

Løsningen var at ændre kalibreringsmetoden, så den drejer i bestemte retninger med rotateTo() istedet for rotate(): Først rotateTo(90) grader (et 90 graders sving til højre), så rotateTo(135) grader (et 45 graders sving til højre) osv. På denne måde følger robotten sit indbyggede koordinatsystem og korrigerer for eventuel overskydende rotation i den næste rotering.

Ud fra dette fandt vi at den tidligere kalibrering var forkert med næsten en hel grads fejl i hvert sving. Efter at have testet de nye indstillinger i Vejfinder-programmet (og opladet batteriet, hvilket som nævnt andetsteds påvirkede præcisionen også), fandt robotten igen kortet helt korrekt. Efter at foretaget yderligere et par tests fandt vi at værdien 11.65cm (den faktiske afstand imellem hjulene er stadig 11cm) giver perfekte drejninger. Umiddelbart kan dette forklares ved at hjulenes omdrejningspunkt ikke er midt på hjulet, men derimod forskudt en smule imod ydersiden i nogle situationer, denne teori kan dog ikke understøttes af slidmærkerne på hjulene, som derimod peger på at de drejer omkring et punkt tættere på indersiden af hjulet.

Selv om at vi i sidste blogpost understregede vigtigheden i kalibrering må vi indrømme at det er endnu vigtigere at denne kalibrering så rent faktisk er korrekt.

Autokalibrering af position/rotation

Grundet små unøjagtigheder som sniger sig ind i positionen/rotationen i TachoNavigator, og pga. at vi bruger TachoNavigator's koordinatsystem til at navigere på det færdige kort, har vi lavet så robotten kan autokalibrere sig selv.

Kalibreringen er kun implementeret til at kunne finde sted på et "fuldt" kryds, men der er mulighed for at implementere lignende kalibreringer på andre typer vej.

Ideen med autokalibreringen var at når vi var færdige med at detektere et vejkryds, burde robotten stå i en position, som vi ved hvor er: præcist midt på vejen, ca. 4cm fra det næste vejstykke og parallelt med vejretningen. Med andre ord har vi en metode til at regulere for de små unøjagtigheder hvis vi kan få robotten til at kalibrere sig selv, så den rent faktisk står på denne måde i den virkelige verden også.

Kalibreringen af en enkelt koordinat-akse foregår som følger:

  1. Robotten gemmer sin position og nuværende retning.
  2. Robotten kører til midten af krydset. Dette gøres ud fra TachoNavigator-koordinaterne, hvilket betyder at robotten bevæger sig til det punkt, som den tror er midten. Dette punkt kan på grund af ovennævnte fejl være forskudt for den faktiske midte med op til flere centimeter.
  3. Et loop startes:
    1. Robotten drejer sig, så den kigger ud af en sidevej, der ligger på aksen.
    2. En metode i stil med findAndGotoEdge() udføres, og vinklen som robotten nu står i gemmes.
    3. Der drejes nu 180 grader, så robotten burde stå i modsat retning.
    4. Igen udføres findAndGotoEdge().
    5. Vinklen w, mellem den gemte og den nuværende vinkel udregnes.
      • Hvis w afviger mere end 2 grader fra 180, drejes robotten 90 grader, så den nu står vinkelret på den akse, der kalibreres. Der køres lidt frem/tilbage alt efter om den fundne vinkelforskel var negativ eller positiv. Denne bevægelse flytter robotten tættere på det faktisk centrum.
      • Hvis ikke, springes ud af loopet.
  4. Robotten drejes nu så den kigger ned af den sidevej, som er i den gemte retning.
  5. findAndGotoEdge() udføres igen, for at være sikker på at robotten står lige.
  6. Positon og rotation nulstilles til de gemte værdier på TachoNavigator.

Denne algoritme udføres for hver akse, så robotten bliver kalibreret i begge retninger.

Selve algoritmen bliver udført hver gang robotten lige har opdaget et fuldt kryds, eller efter kortet er færdigopbygget og man via UI'en trykker på "Calibrate" (hvilket får robotten til at køre til et kendt kryds og autokalibrere).

Videomateriale


Her ses robotten efter dagens arbejde med forbedring af systemet. Det ses tydeligt at robotten nu bevæger sig mere flydende, og at den bruger den aktive GridBuilder ved kryds / t-kryds.



Her er en optagelse af map UIen, hvor man kan se hvordan robotten langsomt finder vejsystemet. (Grunden til at robotten står længe inde i krydset, er at denne video er optaget efter autokalibreringen er aktiveret.)

Konklusion

Idag handlede det meste om fejlrettelser og fejlkilder, da vi allerede sidste gang havde en robot der rent faktisk kunne finde hele kortet, men som blot ikke var 100% stabil.
Primært var der problemet med at robotten sidste gang, hen på eftermiddagen, begyndte at blive upræcis og ikke kunne finde kortet. Dette viste sig dog, til dels som antaget at være batteriets skyld og dels kalibreringen, da vi den her gang med et frisk opladet batteri atter kunne finde hele kortet.
Der var dog stadig små unøjagtigheder i positionen på TachoNavigator. Efter den nye metode til kalibreringen, som er beskrevet herover, blev det dog meget bedre. Den nye autokalibreringsalgoritme betyder også at vi nu hver gang vi kommer til et kryds, kan fjerne eventuelle unøjagtigheder, der skulle være opstået i løbet af et gennemløb. Dette resulterede tilsammen i at robotten nu finder kortet korrekt mere end 3/4 af gangene. De få gange, hvor det ikke virkede var fordi lyset havde ændret sig siden sidste lyskalibrering - og efter en rekalibrering virker det igen. Resultatet af arbejdet idag har været at vores robot nu virker helt stabil, så længe den er sat op til de lysforhold, som den bliver udsat for.

tirsdag den 18. december 2007

Vejfinder 8

Blog8:

Varighed: 14.6 timer, Deltagere: Rolf og Janus

Dagens mål er at bygge GridBuilder færdig, så den kan opbygge et fuldstændigt kort over vejnettet. Vi vil desuden lave en metode til at få robotten til at flytte sig til et bestemt sted på kortet.

Vi vil opnå vores mål idag ved at:

  • Lave en algoritme i MapFollower, som kan udregne den korteste vej imellem to punkter i koordinatsystemet - vel at mærke ved kun at følge kendte veje.
  • Tilføje mulighed for at suppresse LineFollower
  • Tilføje en ny behaviour (MapFollower), som får robotten til at køre imellem to blokke i kortet uden at køre "på skrå" over grønne arealer.
  • Få en bedre præcision på rotationerne ved at kigge på TachoNavigator klassen.
  • Få mere fart på kort-mappingen ved at ændre LineFollower til at kunne klare lige strækninger hurtigere.
  • Få mere præcision på sensor-aflæsningerne ved at lave bedre kalibrering.
  • Lave den "aktive" GridBuilder funktionalitet.

En shortest-path algoritme under lejOS

Det lidt specielle miljø (lejOS) stiller nogle lidt specielle krav til shortest-path algoritmen. Vi kan ikke blot benytte en helt normal implementation af vejfinder-algoritmer, eftersom lejOS ikke har understøttelse for garbage collection endnu. Det interessante er derfor at designe en algoritme, som udfører det samme, men som ikke skaber "tab" af objekter i hukkommelsen.

For at løse dette problem har vi lavet en graffarvnings-algoritme, som med et konstant memory-footprint (dvs. uafhængigt af antal gange, der skal findes en vej) kan finde den korteste rute imellem to blokke i vejnettet.
Algoritmen er opbygget som følger:

  1. Klargør farverne på kortet og afstandsvariablene således at alle farver er 0 og alle afstande er "uendelig".
  2. Sæt farven på destinationen til 1 og på oprindelsesstedet til 2.
  3. Så længe der ikke findes en blok, som har en nabo farvet med 1 og en anden nabo farvet med 2: Farv alle blokke ved siden af allerede farvede blokke og sæt deres distance til én højere end den blok, som de fik deres farve fra.
  4. Nu findes der (mindst) én blok der har naboer i to forskellige farver. Vi ved at eftersom dette skridt var det første, hvor dette var tilfældet, vil en af de korteste ruter inkludere denne brik i midten af ruten. Vi kan derfor kalde rekursivt og dele ruten op i to dele:
    rute(start, den fundne mellem-blok);
    rute(den fundne mellem-blok, stop);
    

Når vi har kaldt rekursivt så mange gange, at ruten kun er 2 blokke lang (start-blokken og stop-blokken), kan vi se hvordan disse blokke er forbundet til hinanden, og derefter flytte os direkte fra den ene blok til den anden.

I forhold til en normal depth-first eller width-first søgning kræver denne søgnings-algoritme ingen ekstra datastrukturer ud over dem, som vi allerede har i forvejen. Algoritmen bruger en farve og en distance-værdi, som sættes som fields på selve blokken - og den udnytter at BlockGrid i forvejen er lavet til ikke at lave memory-leaks på lejOS. I dette divide-and-conquer-pattern skal man dog være opmærksom på at nogle af de gemte objekter er klasse-variable, hvilket er grunden til at vi kalder rekursivt på følgende måde:

lookatBlock = existsPathBlock(1,2);
intermediateX = lookatBlock.getXPosition();
intermediateY = lookatBlock.getYPosition();
navigateFromBlockToBlock(fromBlock, core.getBlockGrid().getBlock(intermediateX, intermediateY));
navigateFromBlockToBlock(core.getBlockGrid().getBlock(intermediateX, intermediateY), toBlock);
istedet for at kalde som man normalt ville:
lookatBlock = existsPathBlock(1,2);
navigateFromBlockToBlock(fromBlock, lookatBlock); <-- Denne linie ændrer lookatBlock(!)
navigateFromBlockToBlock(lookatBlock, toBlock); <-- Vi kan ikke bruge den igen her fordi nu er den en anden

Vores shortest-path algoritme bliver kaldt som en del af GridBuilderen når den skal bevæge sig fra et kendt område på kortet til det næste ukendte sted, som skal udforskes. Den kan også kaldes via BlueTooth, så robotten via kortet i hukkommelsen kan bevæge sig langs vejene på kommando.

Under dette afsnit findes en visuel gennemgang af algoritmens udførsel. Figuren læses fra venstre mod højre i hver linie, og viser et lille vejsystem med nogle forbundne blokke:

  1. Oprindelsesstedet (rød) og destinationen (blå) markeres.
  2. Efter som der endnu ikke findes en blok, som har både røde og blå naboer, "gror" vi det besøgte område, så naboer i alle udgående veje bliver farvet.
  3. Nu findes der mindst én blok (grøn), som har både røde og blå naboer. Vi ved at denne blok nødvendigvis må være med i ruten fra oprindelsessted til destination.
  4. Der kaldes nu rekursivt; først på turen fra det oprindelige oprindelsessted til den blok, som vi fandt i forrige skridt. Oprindelsesstedet markeres med rød og destinationen (den fundne blok) markeres med blå.
  5. Der findes allerede i denne opsætning en blok med både blå og røde naboer, og den må nødvendigvis være med i ruten.
  6. Vi kalder rekursivt på oprindelsesstedet til den blok, som vi lige fandt i sidste skridt. Dette er et kald, hvor de to blokke ligger direkte ved siden af hinanden, og der er derfor en triviel rute (gul). Nu udføres det andet rekursive kald, som startede i (3). Start og destination markeres (henholdsvist rød og blå).
  7. Her findes igen direkte en blok, som både har røde og blå naboer, og vi behøver ikke at "gro" farverne.
  8. Vi kalder rekursivt i to skridt, og finder den resterende rute trivielt. Vi har dermed en fuld rute fra det oprindelige oprindelsessted til den oprindelige destination.

Billedet viser idéen i vores shortest-path algoritme.

MapFollowerBehaviour - en klasse med undertrykkelses-attitude

MapFollowerBehaviours største ønske er at udføre ruten fundet i shortest-path-algoritmen, derfor undertrykker den de andre behaviours så længe den har en rute at følge. Selve udførslen af ruten er relativt simpel: Hvis der er en positions-ændrende forespørgel i kø, bevæger den robotten en plades længde i den retning, som svarer til retningen i forespørgslen.

Kalibrering er vigtigt

Som nævnt i [fodnote] vil der mange gange være stærkt forskellige situationer alt efter lysforhold, strømstyrke på batteriet, underlag osv. Af denne grund har vi lavet et system til at kalibrere hvor meget robotten skal dreje for at have udført et x-graders sving. Den parameter vi ændrer på er afstanden imellem hjulene i TachoNavigatoren, da TachoNavigatoren skal "dreje mere" hvis hjulene var længere væk fra hinanden. På denne måde har vi fundet at hjulene skal stå til at være 12cm væk fra hinanden, selv om de faktisk fysisk er 11cm fra hinanden.

Kalibreringen foregår ved at foretage en række 90-graders sving og køre lidt frem og tilbage (for at skalere fejlen, så den bliver mere synlig). Hvis hjulafstanden er indstillet forkert bliver det tydeligt efter ganske få drejninger om tallet skal sættes op eller ned.

Aktiv GridBuilder

Vores første passive del af GridBuilder, som ikke på noget tidspunkt tager styrringen af motorerne, virker ikke helt optimalt til at detektere kryds og t-kryds. Derfor har vi lavet en "aktiv" del af GridBuilder, som bliver kørt, hvis der er mulighed for at det nuværende vejstykke kunne være et kryds/t-kryds.

Når et vejstykke er kørt igennem, og den passive GridBuilder-del står med kryds/t-kryds som mulige valg, startes den aktive del, som gør som følger:

  1. Supress LineFollowBehavior.
  2. Gem positionen/rotation.
  3. Kør til centrum af den nuværende plade.
  4. Rotér, så de to lyssensorer til LineFollowing er over det sted, hvor den ene mulige sidevej burde være.
  5. Se på input fra de to lyssensorer om de er over vej / græs.
  6. Rotér, så de to lyssensorer til LineFollowing er over det sted hvor den anden mulige sidevej burde være.
  7. Se på input fra de to lyssensorer om de er over vej / græs.
  8. Sæt typen på vejstykket alt efter om der var set vej i de to tilfælde.
  9. Kør tilbage til den gemte position, og roter til den gemte rotation.
  10. Unsupress LineFollowBehavior.

På grund af at vi kører til "centrum" af vejstykket, er det kritisk at robottens position i TachoNavigator svarrer temmeligt nøjagtigt til dens rent fysiske position, da lys sensorerne ellers ikke vil være positioneret korrekt over sidevejene, og de derfor muligvis ikke bliver detekteret.

Optimering af LineFollowBehavior

Vores oprindelige kode til LineFollowBehavior brugte rotate(5) og travel(5) til at bevæge sig i små trin, da den oprindelige TachoNavigator ikke kunne opdatere position/rotation imens der køres. Samtidigt checkede vi ikke i driveForwardABit() om vi stadig holdt "ok" til bare at køre videre fremad, hvilket gjorde at vi, specielt på lige strækninger, heletiden stoppede op og spurgte findAndGotoEdge() om robotten holdt lige - selvom dette allerede var tilfældet.

Med den nye TachoNavigator, som vi som nævnt tidligere har hentet fra SVN, var det ikke længere et krav at robotten skulle holde stille når der kaldes updatePosition(). Med andre ord behøvede vi ikke længere at bevæge os i små hak, men kunne istedet for at kalde travel(5), bare kalde forward(), og opdatere position/rotation hele tiden. (Naturligvis skal man så huske at kalde stop(), når man er færdig med at bevæge robotten.)

For at optimere den hastighed, som robotten kunne følge lige kanter med, ændrede vi driveForwardABit() yderligere, så den nu blev ved med at køre frem, så længe venstre sensor er på vej og højre sensor på græs.

Videomateriale


Her er en video, hvor det ses at robotten bruger det allerede opbyggede kort til at finde rundt på, således at det resterende kort kan opbygges (Det ses at robotten her stadig laver små hak, men nu kører hurtigt frem på lige stykker, denne video er fra før de nye "bløde" bevægelser blev lavet)



På videoen ses en del af kalibreringsmanøvren. Robotten forsøger at foretage 90-graders sving.

Konklusion

MapFollower virker efter hensigten, og sammen med GridBuilder og LineFollower betyder det at robotten nu kan finde hele kortet. Når GridBuilder er færdig med at finde så meget af kortet som muligt ved bare at følge højre kant (ie. når den rammer noget, som den allerede har været ved før), tager MapFollower over og kører robotten til det første ukendte sted på kortet. Derfra fortsætter GridBuilder og LineFollower med at opbygge kortet. Som det ses på videoen, resulterer det i at hele kortet rent faktisk bliver fundet! Efter tilføjelsen af den aktive GridBuilder-del, som tager over i kryds / t-kryds, fik vi også en stabil detektering af disse typer af vejblokke. (Dette er ikke inkluderet i videoen ovenfor).
De nye optimeringer af LineFollower har også virket efter hensigten. Robotten kører nu både mere flydende og samtidigt også hurtigere. Vi havde dog et større problem senere på dagen, hvor robotten pludselig kørte mere og mere "skævt" - TachoNavigatorens position passede overhovedet ikke med hvor robotten fysisk befandt sig. Efter mange timers debugging, kalibrering og testing, kom vi frem til at det var strømniveauet, der var kommet for langt ned. Næste gang håber vi at det hele virker igen med et nyt, opladet batteri.

Noter

  • [Fodnote] Roland Siegwart og Illah Reza Nourbakhsh beskriver i 5.2.3, s. 188 i "Introduction to Autonomous Mobile Robots" (2004, MIT press) hvordan "effector noise" kan give problemer i forbindels med positionering af robotter. En af kilderne til den slags "støj" er netop usikkerheden omkring motorernes og tachonavigatorens ydeevne under forskellige spændingsstyrker på batteriet. Hele afsnit 5.2 omhandler udfordringer i forbindelse med positionering, og har desuden interessante bemærkninger omkring sensor aflæsninger og støj for disse.

mandag den 17. december 2007

Vejfinder 7

Blog7:

Varighed: 6 timer, Deltagere: Rolf og Janus

Dagens mål er at bygge selve GridBuilder-funktionaliteten i NXT'en og tilføje flere muligheder for debugging af systemet over BlueTooth.

Vi vil opnå vores mål idag ved at:

  • Tilføje og aktivere den nye sensor til robotten og til Core, så sensoren bliver startet op og kan bruges.
  • Udføre målinger på sensorerne for at se om de har samme lysfølsomhed (og dermed giver de samme værdier for de samme farver) som de andre sensorer vi har.
  • Bygge en passiv udgave af GridBuilder, der kigger på hvordan robotten bevæger sig og hvad "mapper light" ser.
  • Starte på at forberede den aktive udgave af GridBuilder - en udgave, som også til tider styrer motererne for at pege robotten i retninger, der endnu ikke er blevet udforsket.

Ny sensor

For at se om der skulle være sideveje på de vejstykker, som vi bevæger os på, er det nødvendigt med en sensor på den anden (venstre) side af robotten. Denne sensor blev placeret, så den sidder uden for vejen - dvs. præcis der, hvor en evt. sidevej ville være. Den kan bruges som input til den passive GridBuilder, så denne kan se om der har været en sidevej. (Sideveje til højre er ikke nødvendige at kigge efter, da LineFollower altid vil dreje ned af sådan en.)

Måling på sensorerne

Efter at have tilføjet mulighed for at aflæse sensor-input over BlueTooth kunne vi ret hurtigt se, at den nye sensor var under 400 når den var over græs og over 400 når den så vej. Som med alle de andre sensorer hardcoder vi disse værdier mens vi arbejder med projektet, senere laver vi muligvis en automatisk kalibreringsmetode. Under udviklingen har vi valgt at styre lysmiljøet omkring robotten ved at sætte en skærm op så direkte sollys ikke forstyrrer målingerne.

TachoNavigator

GridBuilderen baserer en del af sine valg på hvor robotten befinder sig og hvordan den vender. Derfor har vi udført en lang række tests af præcisionen af lejOS TachoNavigatoren.


Som det ses på billedet havde vi en del problemer med rotationen, mens afstandsmåling (længden af cirklerne) fungerede ganske fint.

Som det måske kan ses på billedet herover, havde vi problemer med at robotten pludselig "hoppede" i sin angivne position. Den beyndte uden videre at rapportere en ny position lige pludseligt; typisk ca. 5-10cm ved siden af den position, hvor den havde været et øjeblik før. Efter nogen søgen på LeJOS forummet kom vi frem til at dette skyldes en fejl i updatePosition()-metoden i den TachoNavigator, der er i version 0.4 af LeJOS. [updateposbug]

Lidt gransken i deres SVN repository viste sig at give pote, da changelog for TachoNavigator.java angav at de havde rettet netop denne fejl. Vi hentede den nye version af TachoNavigator.java fra SVN, og indsatte denne i vores project istedet for den, som følger med til version 0.4. Dette løste problemet med at robotten hoppede tilfældigt og gav desuden mulighed for at kalde updatePositon() mens robotten kører - ikke kun efter endt bevægelse som i den gamle udgave. Vi kan nu lave robotten om, så den drejer mere flydende, da vi ikke behøver at stoppe hele tiden for at aflæse positioner / vinkler.

Copy & paste af de 2 changelog afsnit der er interresante i den nye TachoNavigator vi hentede:

Revision 1093 - (view) (download) (annotate) - [select for diffs]
Modified Thu Nov 22 19:45:38 2007 UTC (8 weeks ago) by rogergla
File length: 14381 byte(s)
Diff to previous 921

Fixed bug in identified in forum - new algorithm for update position
Revision 1143 - (view) (download) (annotate) - [select for diffs]
Modified Mon Dec 3 18:46:36 2007 UTC (6 weeks, 3 days ago) by rogergla
File length: 15665 byte(s)
Diff to previous 1093

updatePosition()  now can be called at any time, even while the robot is moving.

GridBuilder

De informationer som GridBuilder har brug for er:

  1. Hvad ser den sensor, som er monteret til venstre på robotten? Ser den vej eller græs?
  2. Er vi igang med at dreje til højre eller kører vi ligeud?
  3. Hvor langt har vi kørt siden vi sidst fandt et nyt stykke vej?
Med disse informationer kan man se forskel på T-kryds, sving og lige veje. Det er dog uklart hvordan man kan se forskel på et fuldt kryds og et T-kryds. Dette bliver vi nødt til at tage højde for i softwaren.
To af disse stykker information kan hentes via henholdsvis isOnRoad() og isTurningRight() i GridBuilder-klassen. isOnRoad() er implementeret som en simpel test af sensorens normaliserede værdi.
isTurningRight(), derimod, er interessant fordi robotten hele tiden drejer både til højre og til venstre pga. LineFollowerBehaviours måde at følge vejen på. Det svære her er at finde ud af om robotten i øjeblikket har tendens til at køre til højre eller om dens generelle retning er at fortsætte ligeud. Dette er nemt at se for et menneske, men computere arbejder i hårde tal, så istedet valgte vi i starten at bruge et decaying average. Hvert sekund opdaterer isTurningRight() hvilken vinkel der er drejet siden sidst. Dette lægges sammen med det løbende gennemsnit. Ud fra dette vil det være muligt at se hvilken rotation (hvis nogen) robotten i øjeblikket er igang med at udføre.
Selve udregningen af denne vinkel kræver lidt kendskab til hvordan lejOS TachoNavigatoren sender rotationen tilbage. Efter lidt undersøgelser viste det sig at denne vinkel altid vil ligge i området fra -180 grader over 0 til +180 grader. Derfra skal der udføres lidt matematisk vinkelregning (i leastDifference(v,w)) for at finde den rent faktiske ændring imellem de to vinkler. Dette kan være lidt besværligt når der både er negative og positive tal og overflowing imellem disse med i udregningen.

Efter at have testet vores decaying average dreje-detekteringssystem, kom vi frem til at det ikke virkede efter hensigten. Måden som vores robot drejer fra side til side på, for at finde kanten af vejen, fik isTurningRight() til at returnere helt forkerte resultater. Dette resulterede i, at gridbuilder overhovedet ikke virkede, da den hele tiden mente at vi havde drejet; hvilket resulterede i at der blev sat alt for mange sving ind i banen.

Efter nogen overvejelse og tuning af systemet, blev det besluttet at afprøve en noget simplere løsning. Et nyt retningsbaseret dreje-detekteringssystem blev implementeret: Her husker vi på hvilken retning (N/S/Ø/V) som robotten sidst var på vej i, Hvis den kommer inden for +-20 grader af en af de andre retninger bliver retningen opdateret til den nye, og typen af sving (højre/venstre) bliver returneret.

Dette nye detekteringssystem skulle vise sig at være meget bedre end det forrige; faktisk så godt at vi nu uden fejl kan detektere alle svingene som robotten tager, med det resultat at kortet begynder at ligne det rigtige, når robotten kører på vejsystemet.

Video


Robotten søger efter hvilke plader kortet består af. Denne udgave af robotten kan kun lave højre-sving



Robottens data bliver fremvist på en skærm samtidigt med at de bliver opsamlet i robottens mapper-algoritme. (Grunden til at den tegnede cirkel afviger fra vejen, er at robotten ikke blev startet på midten af vejen men for enden, altså var robotten ikke fysisk der hvor TachoNavigator tror.)

Konklusion

Som det ses i videoen af MapMaker UIen, virker Gridbuilder ganske godt. Endnu finder den ikke sideveje til venstre, og derfor bliver det fundne kort til en oval. Men dette vil blive færdiggjort næste gang. Ud fra de to videoer og de andre tests vi har lavet idag, er det tydeligt at det her kommer til at virke, og at det bestemt er muligt at opbygge kortet i NXTen. Samtidigt har vi nu også testet vores UI, og kan bekræfte at den virker helt efter hensigten.

Noter

fredag den 14. december 2007

Vejfinder 6

Blog6:

Varighed: 6 timer, Deltagere: Rolf og Janus

Målet idag er at få LineFollower til at virke og evt. få yderligere funktioner - f.eks. i GridBuilderen - skrevet og testet.

Vi vil opnå vores mål idag ved at:

  • Færdiggøre LineFollower-koden fra igår
  • Rette koden og sensorerne således at robotten så vidt muligt følger linierne i højre side af vejen.
  • Undersøge hvor præcist vi kan få robotten til at følge en linie (dette vil have inflydelse på hvor nemt det bliver at opdage sideveje i både højre og venstre side af vejen

LineFollowerBehaviour

LineFollowerBehaviour er lavet til at følge kanten imellem græsset og vejen rundt langs højrekanten på en vejplade. Algoritmen er 2-delt: en del der kører lidt frem, og en del som drejer i forhold til vejen.

(Bemærk venligst at den følgende kode er fra den nyeste version af LineFollowBehavior og altså ikke den kode, som giver de lidt "hakkende" bevægleser, der ses på videoen længere nede)

while (!core.isDone()) {
    findAndGotoEdge();
    driveForwardABit();
    Thread.yield();
}

Ovenfor ses hovedløkken i vores line follow behaviour. For hvert gennemløb udføres to opgaver: Først drejer robotten sig efter kanten af vejen, derefter kører den en smule frem. I de følgende afsnit gennemgår vi de to funktioner i detaljer.

findAndGotoEdge()

core.getNavigator().rotateLeft();
while(getRightSensor() == RoadSensorValue.ONGRASS) {
    try {
        Thread.sleep(10);
    }
    catch(Exception e) {
    }
}
core.getNavigator().stop();

float angleBefore = core.getNavigator().getAngle();

Først roterer vi robotten mod venstre, indtil den højre sensor ikke længere ser græs. Vi gemmer så den vinkel, som robotten står i.

core.getNavigator().rotateRight();
while(getLeftSensor() == RoadSensorValue.ONROAD) {
    try {
        Thread.sleep(10);
    }
    catch(Exception e) {

    }
}
core.getNavigator().stop();

angleBefore = leastAngleBetween(angleBefore, core.getNavigator().getAngle());

Så roterer vi nu robotten mod højre, indtil den venstre sensor ikke længere er på vejen. Herefter udregner vi den mindste vinkel imellem den forrige gemte vinkel, og den nye målte vinkel.

float rotation = angleBefore / 2.0f;

// We now know the approximate direction of "straight forward"
core.getNavigator().rotate(rotation);

Nu kan vi tage halvdelen af den udregnede vinkel, og dette er den vinkel vi skal dreje for at køre "langs" med kanten af vejen. Derfor drejer vi robotten den udregnede vinkel.


På billedet er skitseret hvordan findAndGotoEdge() fungerer. Pilene angiver den vej robotten er drejet, når man bevæger sig fra billede (1) til (2), og fra (2) til (3). Vinklerne v og w, bruges til at udregne den afvigelse, som robotten i øjeblikket har fra at køre ligeud langs vejen.

driveForwardABit()

boolean first = true;
core.getNavigator().forward();
do {
    try {
        if( first ) {
            Thread.sleep(500);
            first = false;
        }else {
            Thread.sleep(10);
        }
        core.getNavigator().updatePosition();
    }
    catch(Exception e) {

    }
} while (getLeftSensor() == RoadSensorValue.ONROAD && getRightSensor() == RoadSensorValue.ONGRASS);
core.getNavigator().stop();

Her kører vi for hvert løkkegennemløb fremad i 10msec. Bortset fra første gang løkken udføres hvor der køres frem i 0.5sec. Vi stopper med at køre frem når den højre sensor enten ikke længere ser græs, eller den venstre sensor ikke længere ser vej. Grunden til at vi i første gennemløb kører frem i 0.5sec istedet for de 10msec er at robotten ellers ikke nødvendighvis får flyttet sig nok. Hvis den er kommet til at holde et dumt sted kan den "låse sig fast". Ved først at køre i 0.5sec er vi sikre på at robotten ihvertfald bliver flyttet en smule, derfor kan vi altid komme videre.

Test af LineFollowBehaviour

Vi byggede en bane med de forskellige vejelementer vi havde tilgængelige og kiggede efter hvordan robotten bar sig ad med at følge højre kant rundt langs banen. Resultatet kan ses i videoen herunder.

LightSensorer

Generelt er det svært at bruge lyssensorer[light] , fordi vi som mennesker er vænnet til at opfatte objekter næsten uanset hvilken lyssætning de er i, og vi ingen problemer har med at genkende endda ganske mange forskellige farvevariationer. Det forholder sig anderledes for robotter, som har enddog særdeles svært ved at "abstrahere" imellem forskellige lyssætninger, de opfatter verden i absolutte værdier.

Lyssensorerne på vores robot skal kunne kende forskel på grøn og grå. Det viste sig at den mest simple metode til denne type genkendelse var den der virkede bedst, men for god ordens skyld gennemgår vi lige nogle af de ander metoder, som vi også forsøgte.

Det største problem var at lyset i vores testlokale var delvist retningsbestemt. Det vil sige at når robotten vendte mod nord modtog den mere lys end når den vendte mod syd. Af denne grund valgte vi at afprøve et system, hvor vi tillod at skillepunktet imellem grøn og grå farve kunne "flytte sig" iløbet af en gennemkørsel. Det viste sig dog at det gjorde robotten særdeles følsom over for mørkere slidmærker på vejen.

Vi forsøgte os også med en alternativ løsning: se på forskellen i lys, hvis det pludseligt er blevet meget lysere for en sensor er det fordi den er gået fra grøn til grå (grå er lysere end grøn). I samme stil må man være gået fra grå til grøn hvis det pludseligt bliver meget mørkere.
Denne tilgang virkede til dels, det eneste problem var at forskellen imellem grøn og grå tilnærmelsesvis var den samme forskel som imellem hvid og grå, og kortet indeholder hvide fodgængerfelter.
Vi prøvede derfor med en 3-farvet udgave af algoritmen, som skulle kunne kende forskel på grå, grøn og hvid. Det viste sig dog at være næsten umuligt at holde styr på de tre farver på denne måde, når man samtidigt skal tage højde for at lyset kan ændre sig (ie. der kan komme en forskel som svarrer til et spring fra hvid til grå hvis robotten drejer sig så den skygger for sig selv).

Ander forsøg inkluderede udskårne pap-plader til blokering af lyset, prøver med forskellige typer af lys (der er forskel på lysstofrør, sollys, spotlamper osv.).[lyssammenligning]

Den endelige løsning blev at kalibrere lyssensorerne før selve kørslen. Hvis der er mere lys end en givet tærskel betyder det at en sensor ser grå, hvis der er mindre betyder det at den ser grøn.

Vi havde i starten lavet den forkerte antagelse, at begge lyssensorer ville returnere den samme værdi hvis de blev holdt over det samme sted, dette resulterede i at vores robot ikke fulgte vejen eftersom værdierne for vej/græs var forkerte for den ene af lyssensorerne. Dette rettede vi ved at have særskilte grænseværdier for hver lyssensor.

Videomateriale


På film-sekvensen ses LineFollower i aktion. Den følger den højre side af vejen.

Konklusion

Vores LineFollowBehavior virkede bedre end vi havde håbet på. Den følger kanten rundt på alle vejstykkerne, også hvis det er meget skarpe sving. Det burde give et godt fundament at bygge GridBuilder på, da vi nu er sikre på at vi kan følge vejen - endda uden alt for store afvigelser fra den "bedste" linje. Som det tydeligt ses på videoen virker LineFollowBehavior med de seperate sensor grænseværdier som den skal!

Noter

  • [Light] Tom Dean skriver i sine noter omkring sensorer netop et afsnit omkring nogle af de problemer, som vi har observeret i forbindelse med dette projekt. Yderligere nævner TD at overfladens teksturelle komposition og egenskaber spiller en stor rolle for hvordan lyset tilbagekastes. Vi har ikke lavet forsøg med andre overflader end de overflader der findes på legopladerne. Det er dog klart at hvis pladerne var mindre reflektive, ville målingerne kunne have været mere præcise og i mindre grad være påvirket af reflektioner af f.eks. loftslamper. Mere information på http://www.cs.brown.edu/people/tld/courses/cs148/02/sensors.html.
  • [LightComparison] En beskrivelse af nogle af egenskaberne for de gammeldags RCX sensorer er udført af Timo Paukku Dinnesen, Århus Universitet. Selv om denne undersøgelse beskæftiger sig med de gamle sensorer er mange af konklusionerne omkring farvegenkendelse relevante for de nye NXT-sensorer også. Undersøgelsen kan findes her: http://legolab.daimi.au.dk/DigitalControl.dir/RCX/PropertiesOfTwoLightSensors.pdf.

torsdag den 13. december 2007

Vejfinder 5

Blog5:

Varighed: 5 timer, Deltagere: Mads, Rolf og Janus

Idag skal vi færdiggøre MapUIen og Bluetooth-kommunikationen således at NXTen kan sende et kort til en central computer, der så kan vise det på skærmen. Vi vil også begynde på "oversættelsen" af LineFollower.

Vi vil opnå vores mål idag ved at:

  • Rette i MapUIen så eksisterende blocks på samme plads bliver overskrevet når kortet opdateres; istedet for blot at tilføje dem til en evigt voksende liste.
  • Tilføje understtøtelse for rotation af blokke i UIen, så blokkene vender som NXTen fortæller at de skal vende.
  • Få NXTen til at sende et forud-lavet kort for at teste kommunikationen
  • Forhåbentligt få adgang til vores kort-plader (som tilsyneladende har været udlånt til Viby Gymnasium) - evt. kan vi lave vores egne plader baseret på papir og tusch-streger.

Færdigørelse af MapMakerUIen

Map maker programmet blev idag udviddet med rotationer af blokke, så alle vejelementerne nu kan tegnes i deres korekte position + rotation, Samtidigt blev tilføjelsen af nye blokke til kortet opdateret, så gamle blokke i samme position på griddet bliver fjernet inden de nye tilføjes. Før blev nye blokke bare tilføjet i listen over blokke, så der i princippet kunne være flere blokke på samme grid position (hvilket ikke nødvendigvis giver nogen form for mening i praksis, men kunne være nyttigt til debugging). En anden udviddelse af MapMaker blev også implementeret: man kan nu vælge mellem at tegne kortet med "satte" typer/rotationer, eller "opdagede" typer/rotationer. Dette betyder at vi, når vi begynder at teste vores kortfindingsalgoritme på bilen, både kan se det kort som algoritmen mener den har fundet, men også det kort, som man logisk kan opbygge ud fra de detekterede "veje".


Kortet her er et testkort, som er hardcodet ned i NXTen - det er ikke noget som bilen har fundet.

At sende et kort over BlueTooth: en udfordring

Efter mange tests af kort-strukturen, som vi udviklede i går, fandt vi ud af at der var et eller andet galt. På selve NXTen gik alting fint: den opbyggede kortet og ved at skrive forskellige egenskaber om kortet ud på skærmen kunne vi teste at selve kort-softwaren faktisk fungerede uden problemer. Så snart vi sendte kortet over BlueTooth fortalte NXTen dog at det var tomt...

Efter lang tids debugging viste problemet sig at være omkring vores centrale singleton mediator pattern (Core-klassen), som giver adgang til alle systemets vigtige komponenter på en nem måde - f.eks. ved et kald som Core.getBlockGrid().
I normal Java findes der kun én instans af hver singleton for hver classloader i systemet - dvs. at man under normale forhold kan antage at der altid kun findes én Core; og dermed f.eks. kun ét BlockGrid. lejOS, derimod opfører sig (i nogle situationer) som om den har en classloader for hvert thread man kører. Dette betyder at der kan eksistere to eller flere instanser af en singleton (!) - et klart problem, som lejOS udviklerne er blevet gjort opmærksomme på [clicky]. Dette var grunden til at kortet tilsyneladende var helt korrekt i det ene thread og helt tomt i et andet thread på NXT.
Løsningen har været at droppe singleton-designet og istedet sende en instans af Core med, når diverse Threads startes op. På denne måde findes der igen kun 1 instans af Core og dermed også kun én instans af hver af de klasser, der er tilgang til igennem Core.

Dette var et lidt mystisk problem, som nok skal koste folk en del kvaler rundtomkring. Den eneste grund til at vi kunne gætte på at NXT'en ved en fejl gav mulighed for at lave multiple instanser af singletons var, at vi i et tidligere projekt har arbejdet med flere classloaders i Java og har observeret tilsvarrende opførsel. Det er de færreste Java-programmører der nogensinde får brug for mere end én classloader i deres programmer og lejOS's opførsel vil derfor virke absolut forvirrende i de tilfælde hvor det sker.
Efter at have debugget sammen med lejOS udviklerne er grunden til problemet endnu ikke fundet. I simple testcases fungerer singletons fint, men i et komplekst system fungerer det ikke. Der er en mulighed for at der er tale om et synkroniseringsproblem, hvor to instanser simpelthen får lov til at blive lavet samtidigt. Dette mener vi dog at kunne afvise, da der kun findes en enkelt statisk variabel til indeholdelse af singleton-objektet i Core og de to involverede threads startes forskudt for hinanden.
Vi har valgt at fortsætte og bare sende coren med som konstruktor-argument til de threads, som har brug for den.

Memleaks

Vi udviddede vores Map Maker program og Bluetooth API så vi kan lave forespørgsler til NXTen efter hvor meget fri hukommelse den har. Ved at teste den nye funktion opdagede vi at vores MAPREAD protocol lavede memory leaks når NXTen blev forespurgt om kortet. Dette blev debugget og vi fandt at der blev kastet exceptions inde i Block, hvis det var en "unkown" type når vi bad om dens rotation. Exceptions er objekter og alle objekter der ikke bliver genbrugt laver memory leaks. Dette er nu istedet ændret til at den pågældende funktion returnerer -1 som fejlkode. Dette virkede, og vores NXT ser nu ud til at have et ganske stabilt hukkomelsesforbrug når den kører[mem].

Konklusion

MapMakerUIen blev færdig idag og er nu klar til at blive brugt som debugger til vores kortfindingsalgoritme. Det var også rart at få testet den kode, som kører på NXTen og se at vi kunne fjerne de memleaks den havde. Fra nu af er det nemmere at se om vores LineFollower algoritme og grid-opbygnings algoritme laver memleaks, da vi ved resten allerede er ok.

Noter

  • [Mem] Det skal bemærkes at lokale, simple variable som "int" automatisk bliver ryddet op når et funktionskald afsluttes - det er kun objekter, som giver problemer. Den nye version 0.5 af leJOS NXJ indeholder en garbage collector, så i fremtiden bør der ikke være helt så store problemer omkring dette.