onsdag den 12. december 2007

Vejfinder 4

Blog4:

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

Idag skal vi videre med MapMaker UIen, så den kan vise vejstykkerne. Vi vil oså udbygge Bluetooth API'et til at kunne hente de fundne blocks fra NXTen. Vi skal desuden begynde implementeringen af vores BlockGrid.

  • Få pc programmet til at tegne vejblokke i et grid system.
  • Udvidde Bluetooth API'et til også at kunne sende blocks til PCen
  • Arbejde videre med NXTens grid block system.

Tegne vejblokke i map maker programmet

Vi fik implementeret tegning af vejblokke i vores map maker. Den kan nu, givet en BlockType, tegne et vejstykke i en given grid-position. Billederne bliver loaded med et lille trick: via et ImageIcon får vi adgang til billeddata:

Image img = new ImageIcon(pathToImageFile).getImage();

Alle 4 typer vej[vejstruktur] kan hentes ind og vises, indtil videre ignoreres en eventuel rotation af vejblokken dog.

Selve korttegningsalgoritmerne er implementeret i MapZonePanel, som er en extension af JPanel, hvor paintComponent(Graphics g) methoden er reimplementeret til at tegne vores kort.

BlockGrids og sammenhængen med BlueTooth

For at opbygge et kort er det naturligvis nødvendigt at have en måde at repræsentere det på. Når det skal sendes over BlueTooth er det upraktisk blot at have det repræsenteret i form af Blocks og deres indbyrdes links til hinanden. Derfor har vi tilføjet et BlockGrid, som er en beholder (i software-mæssig forstand), som kan indeholde Blocks. I BlockGrids kan det lade sig gøre hurtigt og nemt at tilgå Blocks via deres position i et net. Dette gør det nemt at overføre hele det opbyggede kort fra NXTen til en computer, hvilket kan ske blot ved at gennemløbe alle de Blocks, som findes i nettet.
En anden vigtig effekt af at have et net istedet for blot kæder af Blocks er, at det vil blive nemmere at gennemskue komplekse sammenhænge - som f.eks. en situation, hvor en lang kæde af Blocks leder tilbage til den samme start-blok, eller hvor en kæde af Blocks krydser sig selv.

NXTen skal selvfølgelig have mulighed for at sende det opbyggede kort til en central computer således at mennesker har mulighed for at forstå kortet. Som nævnt andetsteds benytter computer-programmet en pull-teknik til at samle data op fra NXTens kort-lager. Dette sker i BTCommunication-klassen, hvor kommandoen "MAPREAD" modtages og behandles. Alle blokkene i det centrale kort, der er opbygget i NXTen, kan på denne måde overføres blok for blok med information om deres position, type og rotation. I tilfælde af at NXTen, i sit forsøg på at opbygge et kort, er stødt på en blok, som den enten endnu ikke er færdig med at identificere, eller hvor blokken er identificeret forkert, kan dette kommunikeres tilbage. Den interessante del af protokollen kan findes i kommentaren i Protol.java:

/**
 * MAPREAD asks the NXT to send the entire map that it has built
 * pc: MAPREAD
 * nxt: #blocks (may be 0)
 * for (blocks){
 *     nxt: (int) xposition
 *     nxt: (int) yposition
 *     nxt: (int) type
 *     nxt: (int) detectedType
 *     nxt: (int) rotation (-1 if no correct type or inconsistent block)
 *     nxt: (int) detectedTypeRotation (-1 if not detected)
 * }
 */
Som det kan ses starter den centrale computer med at spørge efter kortet, hvorefter NXTen svarer ved at fortælle hvor mange blokke den har opdaget, efterfulgt af en liste af information omkring hver af disse blokke.

Konklusion

Idag blev vi næsten færdige med map maker programmet. Efter at Bluetooth-kommunikationen omkring polling af blokke fra NXTen til PCen kom til at virke, kan map maker nu tegne kortet, som det er gemt på NXT'en - dog i øjeblikket uden rotationer af vejblokke. Et lige stykke vej vil derfor f.eks. altid være orienteret som "-" og aldrig "|"; det skal ordnes imorgen.

Noter

  • [Vejstruktur] I modsætning til andre tidligere eksperimenter med område-mapping (som f.eks. Maja J Mataric, Integration of Representation Into Goal-Driven Behavior-Based Robots, in IEEE Transactions on Robotics and Automation, 8(3), Jun 1992, 304-312.) giver legopladerne anledning til en stærkt struktureret "verden" for robotten. Der er f.eks. ikke veje som fylder mere end én blok, eller hvor vejen kræver at man sætter blokkene sammen forskudt for hinanden. Denne simplifikation gør det nemmere at repræsentere kortet.

tirsdag den 11. december 2007

Vejfinder 3

Blog3:

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

Dagens plan er at få konstrueret et kommunikations-API til at kommunikere imellem NXTen og en central computer via Bluetooth. Samtidigt ønsker vi at begynde på at udforme algoritmen til at følge streger (i bund og grund en modificeret udgave af vores tidligere LineFollower, dog nu via positioning-klasserner fra lejOS).

  • BlueTooth API og tests
  • LineFollower oversættes til at understøtte positionering i et grid
  • Start af kortopbyggelsesalgoritme
  • Begyndelsen til PC ui'en som skal bruges til at vise det fundne kort

BlueTooth API og tests

Idag startede vi med at lave en simpel test med lejos.pc.comm-klasserne - og nu virkede det! Vi kunne sende "int" og "String" over Bluetooth og modtage dem igen. Det vil sige at kommunikationen virkede både fra PC->NXT og NXT->PC.

Vi fortsatte selve opbygningen af vores Bluetooth-kommunikations-API.
API'en består af en klasse kaldet "BTCommunication", som findes både på PC'en og på NXT'en. Denne klasse tager sig af at oprette forbindelsen og stille metoder til rådighed til at sende og modtage int/String over den oprettede forbindelse.

Eksempel på brug af BTCommunication til at oprette en Bluetooth forbindelse, lave en GREET udveksling og derefter lukke forbindelsen igen.
String ADDRESS = "001653005c81";
BTCommunication btComm = BTCommunication.getSingleton();

//Try and open a connection
boolean open = btComm.openConnection(ADDRESS);

if( open ) {
    try {
        //Send GREET, and wait for response, then sent our response!
        btComm.startSending(this);
        btComm.sendCommand(Protocol.GREET);
        String response = btComm.readString();
        btComm.sendString("WE_ARE_BORG");
        btComm.stopSending(this);
        System.out.println("NXT Greeted us with: "+response);
        btComm.closeConnection();
    }
    catch(IOException e) {
        System.out.println("Error communicating: "+e);
    }
}

Som det ses fra eksemplet bruger vi en startSending() / stopSending() kommando omkring det vi vil sende. Dette er for at sikre, at ingen andre threads bruger Bluetooth-forbindelsen samtidigt med at vi selv er igang med at bruge den.

På NXT-siden er BTCommunication en Thread, som bliver startet op og derefter ligger og kører i baggrunden. NXTen kan ikke selv "sende" noget, men venter passivt på at den bliver kontaktet af PCen. Dette er et bevidst designvalg, med henblik på at gøre Bluetooth-koden i NXTen så kort og simpel som mulig.

Til at hjælpe med debugging har vi lavet en NXTLogger klasse til PC'en. Denne klasse bruger den nylavede Bluetooth API til at spørge NXTen om den har en string, som den vil have logget. På NXTen kan man kalde BTCommunication.getSingleton().log(besked). Denne metode returnerer når PCen har hentet beskeden. Med andre ord kan vi logge strenge fra NXTen via PCen så længe NXTLogger-klassen kører. Hvis den ikke kører vil NXTen gå i stå, hvilket er en konsekvens af at vi har valgt at NXTen ikke selv kan sende information, men kun blive forespurgt om information).

Her følger et eksempel på output fra PCen ved kørsel af vores Bluetooth API + NXTLogger

run:
Searching for device [001653005c81]...
BlueCove version 2.0.0 on winsock
Found: Min NXT
        Found: btspp://001653005c81:1;authenticate=false;encrypt=false
Found wanted device!
Opening connection...
Connected to Min NXT
NXT Greeted us with: VEJFINDER_NXT_3000
NXTLogger: We reached this point!!
NXTLogger: Just before we die!

Kort-opbyggelse

Vi har overvejet forskellige måder at opbygge softwaresystemet på i NXTen:

  1. Enten kan der være tale om en LineFollower-klasse med mulighed for at modtage kommandoer (som f.eks. "drej til højre", "følg linien 3 cm" etc.) hvor en GridBuilder styrer hvilke kommandoer, der bliver sendt, baseret på hvor den mangler at få opbygget en del af kortet.
  2. Eller også kan vi lægge selve kontrollen i LineFolloweren, hvorved GridBuilderen får en mere passiv rolle: den skal blot se hvor robotten befinder sig og hvordan verdenen omkring den ser ud og derudfra opbygge sit kort. GridBuilderen har i denne model ikke selv mulighed for at styre søgningen.
  3. Eller vi kan vælge at have et delt kontrol-system via suppression, hvor LineFollower kan suppresses af GridBuilderen, når denne har brug for f.eks. at dreje til højre eller venstre i et kryds. [subsumption]
  4. Sidst men ikke mindst kan vi vælge at bruge motivations-baseret behaviour styring[motivation], hvor GridBuilderen sætter en høj motivation når den har behov for at styre selv.

Efter at have diskuteret fordele og ulemper ved de to første løsninger blev det rimeligt klart (ud fra argumentation som også findes i de refererede kilder), at løsning 3 eller 4 ville være at foretrække, i tilfælde af at der senere skal udviddes med yderligere opførsel.

Forskellen mellem 3 og 4 er at den motivations-baserede løsning giver mulighed for "glidende skift" imellem forskellige opførsler. Dette er en fordel når det er ukendt præcist hvornår en opførsel skal overtage kontrollen fra de andre. Vi blev dog enige om, at i vores tilfælde er det mere relevant med pludselige og helt veldefinerede skift, hvor den mest kontrollerende delkomponent i hierarkiet direkte undertrykker underliggende komponenter. Netop det at vores komponenter kan opstilles i et hierarki peger på metode 3, hvor metode 4 i højere grad, pga. den øgede fleksibilitet, også henvender sig til situationer, hvor der findes flere komponenter i samme niveau i et hierarki - hvilket ikke er tilfældet for os. Vi har af denne grund valgt at benytte subsumption-/suppressionteknikken til at implementere vores styringssystem.

MapMaker UI

Vi kom igang med starten til vores UI, som skal bruges til at vise det fundne kort. Samtidigt kan UIen nu bruges til at forbinde til en NXT, og vise outputtet fra NXTLogger.


Her ses den spæde start til vores user interface

Konklusion

Bluetooth kommunikationen virker nu! Vi kan både sende og modtage int / String. Og vi har fået lavet vores Bluetooth API til både PC og NXT, så vi kan begynde at bruge Bluetooth til test og debugging. Samtidigt har vi fået lavet NXTLogger klassen, så vi nu kan logge debug beskeder fra NXTen direkte til PCen. På denne måde er vi kommet ud over problemet med den lille LCD skærm :)

Vi er også kommet igang med selve strukturen til vores styringssystem.

Noter

  • [Subsumption] Yderligere beskrivelse af subsumption og alternativer kan findes i Tom Deans noter omkring Robot Architectures og kapitel 10 i Dean, T., Wellman, M., Planning and Control, Morgan and Kaufmann, 1991.
  • [Motivation] Thiemo Krink beskriver i "Motivation Networks - A Biological Model for Autonomous Agent Control." hvordan motivations-værdier kan bruges til at udvælge behaviours og i "Cooperation and Selfishness in Strategies for Resource Management." (Proceedings of the Marine Environmental Modelling Seminar (MEMS-99), vol. 1, p. 295-305) hvordan man kan benytte motivation til optimering af resourcestyring ved at "tune" adaptive agents til omgivelserne.

mandag den 10. december 2007

Vejfinder 2

Blog2:

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

Dagens plan er at få sat projektfilerne op i netbeans og starte på de forskellige interfaces (i Java).

  • Opsætning af det softwaremæssige arbejdsmiljø
  • Forsøg med BlueTooth-kommunikation
  • Udformning af et fælles sæt af domæneobjekter (objekter fra vejfinder-domænet)

Netbeans, lejOS og hvordan det hele virker

Vi valgte at prøve at få LeJOS og NXT compiling til at virke igennem Netbeans eftersom dette er vores foretrukne udviklingsmiljø.

Vi fik det til at virke ved at "stjæle" et build.xml script fra en af lejos sample-filerne og så tilrette denne til at virke med vores projekt.

Det rettede build.xml script:build.xml
Den rettede build.properties:build.properties

Ved hjælp af disse 2 filer kunne vi importere vores nye VejFinder-projekt som et Netbeans projekt med eksisterende Ant script (build.xml).

De første tests med BlueTooth

Først ville vi gerne bare kunne sende et eller andet for at teste Bluetooth. Det kunne f.eks. være en "int" eller en "String", hvor vi kunne printe denne til LCD'en, så vi kunne bekræfte at vi havde korrekt fat i kommunikationen imellem PC og NXT. Derfor satte vi os til at kigge på Bluecove API'en, for at finde ud af hvordan det hele virkede.[bluecove]

De første tests gik godt og efter lidt tid havde vi nu en java klasse, som kunne finde Bluetooth adapteren på pc'en; og via den scanne efter og finde vores NXT.

Her løb vi ind i vores første problem, da API'en fra BlueCove er lidt svag lige omkring hvordan man rent faktisk opretter en forbindelse til et "RemoteDevice", som er den klasse man står med efter at man har fundet en anden Bluetooth enhed.
Vi fandt dog ud af, at man skulle lave en yderligere ServiceSearch på dette device for at få den URL, som man skal connecte til. Nu fik vi åbnet en forbindelse til NXT'en, og vi forsøgte derefter glade at sende en String via OutputStream'en fra connectionen. Denne blev dog ikke opdaget af NXT'en, som overhovedet ikke lod til at have modtaget noget i det hele taget.

Efter mange timers tests/forsøg endte vi med at kunne sende "noget", så NXT'en mente at den modtog noget. Den mente desværre bare ikke at det den modtog var det samme, som det vi mente at vi sendte!

Imorgen vil vi kigge nærmere på at oprette Bluetooth forbindelsen via de klasser der findes i "lejos.pc.comm" - en pakke, som vi netop fandt ud af eksisterede!

Domænespecifikke objektstrukturer

Inden for vores kortlægningssystem har vi valgt at lave en fælles repræsentation af et vejfelt, kaldet Block (blok).
En blok har en type, der kan findes i BlockType. Typen er en af CROSSING, TCROSSING, TURN, STRAIGHT eller UNKNOWN. Grunden til at der findes en ukendt type er, at mens kortet bygges op, kan en blok måske være ukendt, indtil samtlige ud- og indgange til denne blok har været besøgt.

En blok har derudover en position, som fortæller hvor denne blok er placeret. Vi har valgt at robotten altid befinder sig på (0,0) og peger mod "øst" i koordinatsystemet når den starter og hver blok er præcis 1 enhed lang. Hvis robotten kører fremad 1 felt vil den således befinde sig i (1,0). Hvis den istedet drejede til højre og kørte fremad 1 felt ville den være i (0,1).

Ud over en type og en position har en blok også en række forbundne nabo-blokke. Der kan kun findes forbindelser til naboer i de fire retninger, som er defineret i Direction (NORTH, SOUTH, EAST, WEST). Alt efter hvilken type blok, der er tale om, kan to eller flere af disse være sat til at referere til en anden blok (det er også tilladt kun at have én eller ingen sat under opbyggelsen af kortet men blokken er i så fald ikke "veldefinerede").


Figur: Illustration af hvordan en blok er defineret.

Alt efter i hvilke retninger der findes forbindelser til nabo-blokke, er det muligt at finde typen af en blok (via. detectType() eller getType() hvis den direkte er sat). Derefter kan man undersøge hvordan blokken vender (via getRotation()). Dette er specielt nyttigt i forbindelse med kommunikationen med den centrale computer-enhed.


Figur: De forskellige block-typer og rotationer er samlet i tabel-form med rotationsværdier i toppen, typeværdier til venstre og konstant-navne til højre.

I første omgang ville vi gerne have at en blok kunne repræsentere sig selv i tekstuel form - f.eks. som "[(x,y), type, rotation]". Dette blev vi dog nødt til at fjerne fra systemet, da lejOS havde en fejl i implementationen af StringBuffer, som bevirkede at man ikke kunne tilføje strengværdien af et heltal til en streng blot ved den normale Java brug:

String string = "[("+xPosition+","+yPosition+"),"+getType()+","+getRotation()+"]";
Det ovenstående oversætter kompileren til en liste af StringBuffer kald. Problemet er at så snart StringBuffer.appendInt(int) bliver kaldt, opstår der en uendelig løkke i lejOS firmwaren på NXTen. LejOS-udviklerne er blevet gjort opmærksomme på problemet og en rettelse vil være med i næste udgave af firmwaren. En midlertidig løsning er at lave nye Integer objekter for hver gang man vil tilføje et heltal - så kan man bruge StringBuffer.appendObject() istedet for StringBuffer.appendInt():
String string = "[("+new Integer(xPosition)+","+new Integer(yPosition)+"),"+new Integer(getType())+","+new Integer(getRotation())+"]";
Det eneste tilbageværende problem er så at lejOS ikke har en garbage-collector. Der vil derfor være en del hukomelses-spild ved denne metode.
Som endelig løsning valgte vi at flytte ansvaret for tekstuel repræsentation væk fra Block og ind i de klasser, som kommunikerer med den centrale computer. Ved at gøre dette kan vi istedet sende informationerne i seperate pakker og kan derfor undgå at skulle repræsentere dem som tekst-strenge.

Konklusion

Vi fik opnået det meste af det som vi ville idag. F.eks. virker lejos nu under Netbeans, så vi kan bruge denne til udviklingen. Vi fik også udført en lang række tests af Bluetooth-kommunikationen - og selvom det ikke virkede helt rigtigt er vi nu sikre på, at vi er så langt i processen, at det vil komme til at virke imorgen.

Vi fik startet på projektets klasse-struktur og nåede alt i alt en helt masse. Fundamentet er nu lagt for at kunne komme videre med VejFinder!

Noter

torsdag den 6. december 2007

Vejfinder 1

Blog1:

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

Dagens plan er at få at vide om projektet er accepteret og starte med den første del af planlægningen.

  • Snak med instruktor omkring projekt
  • Planlæg tidsramme for de første dele af projektet
  • Brainstorming omkring fundamentale dele i projektet

Instruktorsnak

Vi har haft kontakt med vores instruktor og projektet var godkendt. Han havde kommentaren at vi burde overveje hvilken del af projektet vi ville lægge mest vægt på i tilfælde af at det ville vise sig at være sværere end forventet:

  1. Vægten ligger på at opbygge et kort på pladerne (en anden gruppe havde før lavet et lignende projekt og havde haft svært ved at få sensorerne til at registrere vejen) eller
  2. Vægten ligger på at finde vej (og selve vejnettet "dekoreres" med f.eks. klodser og tape for at gøre vejnettet mere synligt for robotten)

Vi har valgt først og fremmest at lægge vægten på nummer 2 - dog venter vi med at dekorere kortet før det er tydeligt at der er brug for det.[mapdeco]

Tidsramme for første del af projektet

Vi planlægger at mødes mandag, tirsdag og onsdag for at se hvor langt vi kan nå og derefter planlægge videre derfra. I denne tid vil vi:

  • klargøre bilen
  • afgøre om det er muligt at benytte de eksisterende plader uden modifikation til at styre ud fra
  • finde eller udvikle en algoritme til i første omgang at detektere hvilken type plade bilen i øjeblikket er placeret på
  • finde eller udvikle en algoritme til at opbygge et kort baseret på de fundne pladetyper
  • lave et kommunikationssystem til at sende det opbyggede kort og fundne plade til en computer
  • lave eller finde en algoritme til at finde den mest optimale vej imellem to punkter i det opbyggede kort

Brainstorming

Opbygningen af banen:
  • Vi skal tænke over hvordan kortet må være opbygget; er det f.eks. tilladt at have dead-ends eller plader, som leder ud af kortet?
Pladefindingsalgoritmen:
  • Det kan blive et problem at finde midten af plader og derved identificere dem - men det er ikke nødvendigvis nødvendigt.
  • Det kan være et problem at finde hvor en plade stopper og en anden starter.
Design af bil:
  • Der vil være flere forskellige muligheder for hvordan bilen kan udformes. Vi kan enten vælge at lave en bil, som selv forsøger at finde og følge vejens udformning - eller vi kan vælge at lave en bil, som er lavet til at lave perfekte 90-graders sving og udelukkende bevæger sig ifølge en "model" af brikkerne.
  • Et interessant aspekt ved et kompas er at fejlmarginen, når man drejer, er konstant over hele forløbet - et tachometer, som i motoren, har en konstant fejlmargin for hvert enkelt sving og vil derfor akkumulere denne over tid.
  • Alt efter hvor mange sensorer vi har, kan man enten følge den ene side af en plade eller begge sider på en plade. Derfor kan vi enten køre kortet igennem 2 gange - en for hver side - eller blot 1 gang hvor begge sider opbygges.
  • Evt. 3 lyssensorer.

Konklusion

Vi er klar til at gå igang på mandag - endda med en god ide om mulige algoritmer og opdeling af arbejdet.

Noter

  • [MapDeco] Det viste sig senere at del 1 var væsentligt sværere, men også væsentlig mere interessant end del 2. Af denne grund er fokus i det endelige projekt blevet flyttet mere over på selve opbyggelsen af kortet og på hvordan man kan genkende brik-typerne ved hjælp af de tilgængelige sensorer.

torsdag den 29. november 2007

NXT Programming, Lesson 11

"Planlægning", blog0

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

Dagens plan er at diskutere forskellige muligheder til projektet.

  • Gennemgang af de forskellige projekter på listen over forslag.
  • Valg af hvilket projekt vi vil lave.
  • Uddybning af vores projekt.

Gennemgang af projekterne

Navigation through LEGO road elements

Dette projekt går ud på at lave en robot, som kan lave et kort over et legovejnet, hvorefter den kan finde den korteste vej imellem 2 kendte punkter.

Hardware: NXT, Software: LeJOS

Udfordringer:
  • Opbygningen af kortet over vejnettet
  • Position af robotten på kortet

Til fremlæggelsen kunne man evt. bygge et tilfældigt kort og lade robotten opbygge sit kort, for derefter at vise hvordan den finder vej.

Sex Bots

Her er ideen at lave en flok af robotter, som skal udveksle noget kode, og på den måde ændre opførsel. Denne udveksling af kode kunne evt. ske via kommunikation over IR eller Bluetooth.

Hardware: Multiple NXT'er, Software: LeJOS

Udfordringer:
  • Hvis man bruger IR kommunikation kan det være svært at få en stabil kommunikation
  • Bluetooth rækker langt og det er derfor svært at begrænse udbredningen af kode til kun at omfatte de robotter, som man møder.
  • Lave et opførsels-framework, som kan varrieres, så robotterne får "gener"

Man ville kunne vise forskellige statistikker og grafer over hvor godt robotterne klarer sig efter at have "parret sig" på kryds og tværs gentagne gange således at parametrene er blevet optimeret.

LegWay

Projektet går ud på at få en legorobot til at balancere på to hjul.

Hardware: NXT, muligvis nogen andre sensorer end dem der er i pakken, Software: LeJOS

Udfordringer:
  • Som vi opdagede da vi selv prøvede at lave en LegWay, er det svært at lave noget der balancerer i længere tid

Til fremlæggelsen ville man forhåbentligt kunne vise en balancerende robot.

Synthetic Creatures

Dette projekt går ud på at lave et syntetisk væsen, i stil med en Sony hund.

Hardware: NXT, Software: LeJOS

Udfordringer:
  • Få opførslen til at virke overbevisende.
  • Hvad skal væsnet kunne

Man ville kunne vise det færdige syntetiske væsen til fremlægglesen.

Interactive Robot Games

Implementere et computerspil ved hjælp af fysiske agenter.

Hardware: En mængde NXT'er, Software: LeJOS

Udfordringer:
  • Vælge et spil, der er sjovt, men stadig simpelt nok til at kunne laves med nxt'er
  • Flytte ideen med spillet over til den fysiske verden.

Til fremlæggelsen ville man kunne vise det færdige spil

SHG Lagerrobot

Ideen er at lave et system til lagring af ting og fremskaffelse af ting fra lageret, når flere robotter skal arbejde sammen.

Hardware: Flere NXTer, et lager bygget af lego, Software: lejOS

Udfordringer:
  • At placere og hente varer fra lageret uden at robotterne "snubler over hinanden".

Lageret i funktion kan fremvises til fremlæggelsen.

Vores projektvalg

Vi har valgt at beskeftige os med "Navigation through LEGO road elements" projektet, da det var det projekt, som vi synes var mest spændende.

Vi har tænkt os at udvidde projektet, så robotten kommunikerer med en PC, som så kan vise det kort, som robotten har opbygget indtil nu. Samtidigt skal programmet på PC'en kunne bruges til at bede robotten om at køre til et bestemt sted på kortet.

Dette giver en god basis for en visuel demonstration til fremlæggelsen, da man kan vise at robotten opbygger et kort, hvorefter man på en PC viser hvordan man kan kommandere bilen til at køre til et bestemt punkt.

Algoritmen der kortlægger vejnettet skal være så generel, at der i princippet ikke er nogen grænser for størrelsen af vejnettet.

Planen for projektet

  • Først vil vi bygge en bil, som skal kunne navigere rundt på f.eks. de lego-by plader, som har et tegnet vejnet på. Dette kunne f.eks. være standardbilen som vi har brugt tidligere eller en special-designet model.
  • Dernæst vil vi undersøge hvilken metode der bedst kan bruges til at navigere på underlaget - lyssensor, tachometer eller måske en kombination.
  • Derefter udvikles softwaren til opbygning af kortet i robotten
  • Så styringen som gør det muligt at finde den korteste rute imellem to punkter og udføre den faktiske manøvre.
  • Hvis tiden tillader det, vil vi udvide projektet med muligheden for at sende kortet til en computer og styre robotten derfra - f.eks. over Bluetooth.
  • Evt. kan projektet udvides yderligere ved at tilføje muligheden for at mere end en robot koordinerer arbejdet forbundet med at opbygge kortet.
  • Desuden kan robotterne bygges om, så de kan hente og læsse ting af på de forskellige destinationer.
/MJR

torsdag den 22. november 2007

NXT Programming, Lesson 10

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

Vi vil undersøge hvordan Behaviour og Subsumption API'en i lejos fungerer.

  • Først vil vi teste Bumpercar klassen som den findes i lejos samples biblioteket.
  • Vi vil også kigge på en alternativ implementation af Arbitrator.
  • Til sidst vil vi kigge på Motivation functions.

BumperCar

Bumpercar kører langsomt frem, når bumperen aktiveres bakker bilen lidt tilbage og drejer en anelse til venstre. Herefter kører bilen igen fremad.

Hvis bumperen holdes inde stopper bilen efter den har lavet sin "undvige" manøvre.

For at teste om takeControl metoden i DriveForward bliver kørt, blev metoden udbygget med en counter som tæller op hver gange metoden bliver kørt, og herefter skrevet til LCD'et

public boolean takeControl() {
    count ++;
    
    LCD.clear();
    LCD.drawInt(count, 0, 1);
    LCD.refresh();
    
    return true;
}

Vi implementerede PlaySounds i det nye Behavior framework, og indsatte den i BumperCar som højeste prioritet behavior. Når der som foreskrevet i lesson 8 er gået 10 sekunder stopper bilen, spiller sin musik, og fortsætter så igen.

HitWall metoden kan godt kontrollere motorerne selvom den bliver supressed, netop ved at lave noget kontrol kode i supress().

Efter et par testkørsler har vi fundet ud af at det hele kører i en thread, altså Arbitratoren får ikke kontrollen tilbage før en Behavior har afsluttet sin action() metode. Derfor kan HitWall også blive ved med at kontrollere motorerne selvom den bliver supressed, fx med en while(true) i sin action().

Another Arbitrator

Efter at have rettet i programmet som foreskrevet i opgaven testede vi igen BumperCar. Nu bliver takeControl som forventet kaldt selvom en højere prioritets behavior har "kontrollen".

Den nye interrupt mekanisme virker efter hensigten, fx. hvis bilen er igang med at bakke væk fra muren og det er blevet musik tid, stopper bilen med at bakke og spiller musik istedet!

Motivation Functions

Implementationen af motivations funktionen kunne ske ved at ændre så takeControl returnerer int istedet for boolean. Så kunne 0 indikere at en metode ikke vil tage kontrollen.

public int takeControl() {
    //Drive forward has low priority so return 1
    return 1;
}

Motivations funktionen gør det muligt for en takeControl metode at returnere en højere motivation ved et senere kald. Fx hvis bilen rammer en væg, men er inde i en behavior som ligenu har en højere prioritet, så kan takeControl ved andet kald i HitWall returnere en højere motivation fordi den nu har været "inde" i vægen i længere tid, og derfor på et tidspunkt overstige motivationen af alle andre funktioner. Det er så vigtigt at motivations faktorer igen falder.

Vi har valgt at springe over: How could takeControl be programmed to give high values when touch is pressed and lower values when it is ok to reactivate the action method ? da vi umiddelbart ikke synes at spørgsmålet giver mening. (Hvilket vores instruktor var enig i)

Konklusion

Ummidelbart må konklusionen være at motivations funktioner er det der virker bedst når man arbejder med behaviors, fordi en behavior så kan stige i "prioritet". Altså er man ikke så fastlåst i et prioritets hieraki som man er ved prioritets arrayet. Den Arbritrator som følger med LejOS har klart mangler omkring supression, og afgivelse af kontrollen til behaviors med højre prioritet.

torsdag den 15. november 2007

NXT Programming, Lesson 9

Varighed: 4 1/2 timer, Deltagere: Rolf og Janus

Målet med dagens øvelser er at prøve at navigere ved hjælp af den indbyggede tacho-tæller i NXT motorerne og se hvordan to motorer i lejOS-systemet kan benyttes med lejOS klassen TachoNavigator til at styre så præcist som muligt - og hvor præcist systemet kan holde styr på position og retning.

Eftersom vi har været venlige at udlåne bilen fra sidste uge til en anden gruppe er planen følgende:

  • Genbyg standardbilen fra 9797 instruktionshæftet
  • Test af TachoNavigator-klassen fra lejOS omkring navigation
  • Undersøgelse af hvordan dette kan kombineres med et avoiding-system
  • Konklusion baseret på resultaterne

Navigation

For at undersøge TachoNavigator-klassen har vi lavet klassen Navigator som laver en instans af TachoNavigator og bruger denne. Den første test er at udføre en række bevægelser og så returnere til start-punktet:

  resetAndWait();
  nav.goTo(100, 0);
  nav.goTo(50, 50);
  nav.goTo(50,-25);
  nav.goTo(0,0);

TachoNavigator-klassen benytter hjul-diameteren og afstanden mellem de 2 hjul til at bedømme hvor den er, det er derfor vigtigt at få de korrekte målinger af disse for at få så korrekt en navigation som muligt. Først havde vi fejlmålt afstanden mellem hjulene til 13cm, hvilket gav en helt forkert positionering i testen. Da vi målte efter til 11,3cm var testen stadig en smule forkert. Vi kiggede derfor nærmere på hvor hjulene havde kontakt med jorden (omdrejningspunkterne) og brugte en afstand på 11cm. Dette gjorde at testen nu blev udført med stor nøjagtighed, robotten stoppede indenfor omkring 2cm af oprindelsespunktet, hvilket kan siges at være meget præcist givet de tekniske begrænsninger i NXT'en.

Vores anden test var et forsøg på at bedømme TachoNavigatorens evne til at måle afstand. I Brian Bagnall's noter skriver han at "Blightbot does a good job of measuring distance but his weekness arises when he rotates". Vi vil derfor se præcist hvor god Tacho-controlleren er til at måle afstand:

  // Test 2
  resetAndWait();
  nav.goTo(200, 0);

I denne test kører vi 2 meter fremad. Vi gentog testen 3 gange og selv om det var svært at få robotten til at køre i præcis samme retning (når vi sætter robotten ned kan der være en grads forskel på retningen) stoppede den på præcist den samme afstand hver gang.
Men hvad så hvis man vil køre den samme afstand men i mindre stræk af gangen?

Vores tredje test var en afstandstest, hvor navigatoren blev sat til at teste en kørsel på 200cm men i træk af 20cm:

  resetAndWait();
  for (int i=1; i<11; i++){
   nav.goTo(20*i,0);
  }

Robotten holder en synlig pause imellem hver kommando, hvor det er tydeligt at lejOS laver små korrektioner (f.eks. for at undgå at motoren overskyder og kommer for langt). I et enkelt af forsøgende var denne korrektion forskellig på de to motorer, hvilket resulterede i at robotten drejede en lille smule til venstre - hvilket klart ikke er intentionen. Ud over dette problem var den tilbagelagte afstand den samme som før.

Den fjerde test testede rotation. Det viste sig dog at hvis man kalder rotate(360) bevæger robotten sig ikke ud af stedet idet den automatisk ser at den allerede har den korrekte placering. Vi lavede derfor en ny test, hvor robotten drejede 360 grader rundt om sig selv i træk af 45 grader:

  resetAndWait();
  for (int i = 0; i<8; i++){
   nav.rotate(45);
  }

Resultatet var rimeligt præcist, men der var en lille fravigelse på omkring 8 grader. Dette passer fint med antagelsen om at drejning er en smule upræcist mens afstandsmåling er ganske præcist. Dette skyldes muligvist at "trædepuden" for hjulet er næsten en centimeter bredt og det derfor kan være svært at beregne den korrekte hjulafstand i alle situationer (små ujævnheder i overfladen der køres på kan også have indvirkning). Legos egen tacho-meter har en usikkerhed på omkring 1 grad pr roterings-kommando, hvilket med 2 hjul giver en større (omend fast) usikkerhed.

At finde vej uden om objekter

For igen at afprøve suppression-idéen fra sidste uge har vi valgt at lave et robot-styrings-system, der ved hjælp af forskellige behaviours finder vej uden om forhindringer i sin søgning efter målet (et forudbestemt punkt i koordinat-systemet fra TachoNavigoteren).

Som udgangspunkt forsøger NavigateCourse at bevæge sig imod destinationspunktet, denne opførsel kan dog undertrykkes af AvoidObject, som vil forsøge at forhindre kollision med forhindringer (baseret på input fra ultralydssensoren).

AvoidObject vil først forsøge at se (ved at dreje robotten) om det er muligt at køre til venstre rundt om objektet, og derefter om det er muligt at køre til højre rundt om objektet. Der er ikke nogen grund til at vælge denne rækkefølge frem for omvendt - i grunden kan valget være tilfældigt, men for at kunne genskabe fejl har vi valgt at fastlåse det.

En af de ting vi tidligere observerede omkring ultralydssensoren var at den har svært ved at "se" ting når lyden reflekteres fra en vinkel. Af denne grund har vi forsøgt at designe NavigateCourse således at vinklen når der måles så vidt muligt altid er 90 grader. Her antages det at robotten starter således at den står orthogonalt eller parallelt med alle flader i forhindringsbanen og at alle forhindringer er udformet som kasser af forskellige størrelser. Begge behaviours "forsøger at holde robotten langs linierne i koordinatsystemet" - dvs. alle drejninger er 90 grader. Et interessant problem er her muligheden for en større og større akkummuleret fejlprocent på grund af de mange drejninger.

En observation vi lavede var at det også er nødvendigt at NavigateCourse can suppresse inputet til AvoidObject når der drejes, således at målingerne kun foretages når NavigateCourse har positioneret robotten så den bevæger sig langs en af de imaginære linier - og ikke f.eks. imens der drejes.

En anden observation er at getAngle()-funktionen selv forsøger at korrigere for evt. fejl i forbindelse med sidste drejning, således at hvis der blev drejet for meget eller for lidt vil den på en 90-graders drejning ende med at returnere f.eks. 89 eller 91. Dette giver problemer i vores system, da modellen kun kan arbejde i hele drejninger. Vi har derfor valgt at kategorisere alt som er tæt på hele drejninger som værende præcis en hel drejning. Med andre ord vil robotten betragte et sving som "godt" hvis den tilnærmelsesvis ramte 90 grader i den rigtige retning.

Vores NavigateCourse-klasse bruger den udgave af goTo(), som returnerer med det samme (alternativet var at vente indtil kommandoen var udført). Det sidste problem vi løb ind i var at hver gang man kalder goTo(...) sker der en kalibrering af den sidst kørte afstand. Det betyder at hvis man konstant kalder goTo(...) vil robotten næsten stå stille. Som løsning lod vi derfor NavigateCourse se om robotten var i bevægelse i forvejen og i så fald vil den ikke kalde en ny goTo(...) blot for at sætte den samme destination.

Kildekode, billeder og film

Kildekoden til Navigator, NavigateCourse og AvoidObject kan findes her.

Test-banen, som ses på nedenstående billede var en samling papkasser spredt ud på gulvet. Opgaven var at bevæge sig 2 meter frem (målet er markeret på gulvet og robotten skal starte fra blyanten):
Følgende film viser et par forskellige forsøg på gennemløb.

Konklusion

Alt i alt virkede det ganske godt. Men det er lidt ærgeligt at den har den lille fejlmargen når den roterer, det betyder desværre at vores Avoidrobot ikke altid kommer helt pænt frem når den drejer meget. Selvom det i de fleste tilfælde (Som set på videoen) virker ret godt. Det trick som fik den til at virke til sidst var at korrigere for den forskel, der var i det vi ville rotere i forhold til det den troede den var roteret - hvis denne forskel kom over 2 grader lavede vi en korrigering. Bilen havde nemlig svært med at dreje bare 1 grad, hvilket også passer med den unøjagtighed som der er på grad tælleren på motorerne.