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.

Ingen kommentarer: