Denne blog bruges af Kim Munk Petersen (20063667), Andreas Koefoed-Hansen (20062154) og Tim Rasmussen (20061947) som dagbog i forbindelse med kurset Embedded Systems/Legolab på Århus Universitet.

lørdag den 16. januar 2010

Projekt - 4

Dato:
16-01-2010

Antal timer brugt:
7 timer

Deltagende personer:
Kim Munk Petersen, Andreas Koefoed-Hansen og Tim Rasmussen

Målet:
  • Få oprettet Bluetooth-forbinelse mellem Legwayen og en computer.
  • Kunne styrre Legwayen, således den på kommandoer fra computeren kører frem og tilbage.
  • Evt. få Legwayen til at dreje.
Planen:
Planen for dagen er først og fremmest at få oprettet forbindelsen mellem Legwayen og en computer via Bluetooth. Til Robot Race'et udviklede Kim et program der gjorde at hans daværende gruppes robot kunne fjernstyres op ad Alishan train track. Vi ved derfor at det er muligt at fjernstyre en robot via Bluetooth og vi har altså også noget kode vi ved der virker. Denne kode bygger på eksemplet fra leJOS' communication tutorial [1], er meget lidt elegant og håndterer fx ikke tab af forbindelsen, så vi vil blot bruge den som skabelon til et nyt program. I første omgang vil vi blot få Legwayen til at kunne køre frem og tilbage, og senere også at kunne dreje. Når vi har fået oprettet forbindelse mellem computeren og Legwayen og vi er sikre på at de værdier NXT'en modtager stemmer overens med værdierne sendt fra computeren, vil vi arbejde videre med at få værdierne til at påvirke hvordan motorerne kører. Vi regner med at vi let kan tilføje funktionalitet således at vi kan dreje Legwayen efter vi har fået implementeret mulighed for at køre den frem og tilbage idet det blot er et spørgsmål om at give de to motorer forskellig power. At dreje robotten burde heller ikke bringe den ud af balance idet den har differential steering og drejer omkring sit tyngdepunkt.

Processen:
For at oprette forbindelse mellem computeren og Legwayen startede vi med at oprette de klasser der skal bruges for at kunne tilføje Bluetooth som en opførsel. Grunden til vi ville implementere det som en opførsel er at vi lettere kan udvide robottens funktionalitet med andre opførsler. Den fundne GELway-kode indeholder allerede Bluetooth funktionalitet, men da denne kun virker sammen med firmware 0.8 og ikke 0.85, samt har mangler som fx håndtering af mistet forbindelse, gør vi ikke brug af denne. I stedet benytter vi en klasse BTDriver, som implementer behavior-interfacet fra LeJOS. Denne klasse bruges på NXT'en til at omsætte en kommando til en fysisk handling. Klassen BTCommandReader står for selve kommunikationen med computeren. Grunden til at den hedder BTCommandReader at at den kun læser og altså ikke skriver tilbage til computeren. Vi mener at dette er tilstrækkeligt idet vi kun har brug for at sende kommandoer fra computeren til Legwayen, og ikke den anden vej. Der er således tale om envejskommunikation hvilket er praktisk anvendeligt idet Bluetooth er en connection-baseret protokol hvilket betyder at vi er garanteret at data der sendes også når frem medmindre forbindelsen afbrydes. I BTDriver klassen, har vi lavet en indre klasse ConnectionListener som "lytter" efter Bluetooth forbindelser. Så snart der er oprettet en Bluetooth-forbindelse, sendes objektet der repræsenterer denne videre til klassen BTCommandReader som så læser kommandoerne fra computeren. Herimens går ConnectionListener ind i en uendelig sleep hvorfra den kan vækkes vha. et interrupt fra BTCommandReader'en i tilfælde af at forbindelsen bliver afbrudt. Herefter starter ConnectionListener forfra med at vente på en forbindelse. Det betyder at vores Legway kan håndtere at forbindelser afbrydes og nye oprettes et vilkårligt antal gange. Konstruktøren i BTDriver ser ud som følgende:
public BTDriver(CtrlParam ctrl)
{
    car = new Car(ctrl);
    ConnectionListener cl = new ConnectionListener();
    cl.start();
}
Vi beskriver behavior endnu mere i sektionen behavior. 

ConnectionListener er som beskrevet den klasse der sørger for at forbindelser mellem computeren og enheden oprettes. Når der oprettes en instans af klassen, sættes tråden til at være en daemon tråd vha. setDaemon(). Grunden til at dette gøres, er for at sikre at tråden automatisk afsluttes når der ikke er andre user tråde kørende.

BTDriver implementerer som nævnt Behavior-interfacet i leJOS' subsumption framework. Det betyder at den skal have metoderne action(), supress() og takeControl(). Den tilkendegiver i takeControl-metoden at den gerne vil udføres, ved at returnere true hvis og kun hvis der er en aktiv Bluetooth-forbindelse hvilket giver mening idet den ellers ikke har nogle kommandoer at udføre. Dens action-metode udfører dens handling ved at hente den seneste kommando som NXT'en har modtaget. Er denne kommando anderledes end den forrige, udføres den. Bemærk at vi også har en kommando der svarer til "ingen handling" eller "stop" som bliver sendt når der ikke trykkes på nogen tast. Det betyder at man stadig kan udføre to ens egentlige kommandoer efter hinanden. Idéen er at Legwayen ikke skal begynde at udføre en kommando den allerede er ved at udføre. Suppress-metoden i BTDriver er tom siden Bluetooth opførslens action-metode terminerer hurtigt hvilket medfører at arbitratoren får kontrollen med det samme igen. Herved er der ingen grund til at stoppe udførslen af action-metoden selvom der findes en opførsel med højere prioritet.

Selvom vi bruger behaviors, er det vigtigt at nævne at vores BalanceControl, som er den klasse der sørger for at Legwayen holder balancen, ikke er en opførsel, men i stedet en tråd der hele tiden sørger for at Legwayen holder sig stående. Måden hvorpå man så får den til at køre frem og tilbage via Bluetooth er ved at ændre på tiltAngle parameteren, hvorved værdien Phi som bruges til at beregne error ændres. Dette betyder at Legwayen tror at den er ved at vælte forover hvorved den kører frem. Det modsatte er tilfældet baglæns.

- PC-programmet:
PC-programmet der skulle bruges til  styre robotten lavede vi som et andet projekt idet det skal compiles med den traditionelle Java-compiler, og ikke leJOS. Vi har sikret os at programmet kun opretter forbindelse til netop vores NXT-brick. Dette har vi gjort ved at navngive den "Legway" vha. nxjbrowse som er en del af leJOS-distributionen, og så sørge for at der kun ledes efter en NXT-brick med dette specifikke navn. Programmet bruger en bitmaske til at indikere hvilke knapper der er trykket ned. Vi registrerer en key-listener således at vi får kaldt en metode når en knap trykkes ned og en anden når den slippes igen. Dette er måden at gøre det på i Java idet det ikke umiddelbart er muligt på anden vis at kontrollere om en tast er trykket ned eller ej. Når der trykkes på en tast, OR'es bitstrengen med en hexadecimal konstant der angiver en bestemt tast og der AND'es med den inverse når tastes slippes igen. Vi har valgt de hexadecimale værdier som 0x01, 0x02, 0x04, 0x08 osv. således at bitmasken entydigt kan repræsentere at flere knapper er trykket ned. Når en tast trykkes ned eller slippes, sendes bitmasken til NXT-brick'en vha. den synkronierede metode sendKeys(). Grunden til at den er synkroniseret er at den kan tilgås af flere tråde på én gang og vi ønsker derfor at den udføres serielt. Vi kunne også have valgt at sende kommandoerne hele tiden, men dette ville bruge mere processorkraft og batteri på Legwayen pga. øget trafik hvorfor vi har valgt den anden løsning. Derudover mindsker vi også forsinkelsen ved at sende så snart der sker en ændring mht. tastetryk i stedet for hele tiden at sende den aktuelle tilstand. Herunder ses et snapshot af programmet. Det er blot et vindue med et tekstfelt der "fanger" tastetrykkene.



Vi havde nogle problemer med at få Bluetooth-kommunikationen til at virke. For det første brugte programmet fra Robot Race'et tovejskommunikation, dvs. både computeren og NXT'en sendte og modtog data. Vi lavede Legwayens program således at det kun læste data, men idet PC-programmet forventede respons ved et blokerende kald til readInt(), frøs kommunikationen fast. Dette rettede vi ved at fjerne kaldet til readInt() i PC-programmet således at det ikke længere ventede på respons fra NXT'en. For det andet var vi kommet til at bruge metoden write() til at sende bitmasken, i stedet for metoden writeInt(). Det betød at bitmasken blev sendt som en byte hvilket klart nok gjorde at NXT'en fortolkede de modtagne data forkert. Denne fejl var heldigvis også let at rette. Efter vi havde fået kommunikationen op at køre opstod et problem i form af en unchecked exception hvis vi ikke havde sendt kommandoer til NXT'en i ca. 15 sekunder idet forbindelsen fik timeout og derfor blev afbrudt. Måden vi løste det på var blot at få programmet til at sende bitmasken til NXT'en hvert femte sekund, udover også at sende når en tast blev trykket ned eller sluppet. Herved undgås timeout og det har ingen praktisk betydning at vi sender den samme kommando gentagne gange idet NXT'en som beskrevet ignorerer gentagne kommandoer. Vi havde også andre småproblemer som i sig selv ikke er interessante, men de krævede at vi lærte en ny teknik til at debugge programmer på NXT'en. NXT brick'en kastede en unhandled exception som blev vist på skærmen hvor årsagen var angivet som et klassenummer og et metodenummer. Disse numre sagde os intet, men vi fandt ud af at linkeren der linker leJOS-programmet udskriver disse numre og navnet på den tilhørende klasse. Derudfra kunne vi se at klasse 16 var en NullPointerException og metoden hvori den blev kastet. Herved blev fejl noget nemmere at lokalisere.


- Behavior:
Vi anvender en subsumption arkitektur, hvor vi har et lag 0 som er vores BalanceController, hvor på der er bygget flere forskellige lag ovenpå der alle kan påvirke vores BalanceController. Hver af disse ekstra lag, bliver beskrevet som opførsler. Hver af disse opførsler køres i tråd der har adgang til motoren og som også nævnt, så kører vores BalanceControler i en tråd der ikke kan suppreses af andre opførsler idet BalanceController ikke er en opførsel. Med andre ord, så kører BalanceControlleren hele tiden. Fordelen ved sådan en arkitektur er at vi kan blive ved med at tilføje flere lag til systemet uden at skulle ændre på de underliggende lag. Til at håndtere hvilke af de forskellige tråde der har ret til motorerne, bruger vi Arbitrator klassen fra leJOS biblioteket. Måden den fungerer på er ved at den tager en liste af forskellige behaviors, hvor den giver den behavior indsat sidst i listen højest prioritet.
Behavior[] bArray = { b1, b2 };
Arbitrator arby = new Arbitrator(bArray);
arby.start();
Koden viser hvordan man laver sin liste af opførsler som man så sender med til Abitratoren som derefter startes. Når Arbitratoren registrerer en opførsel der har højre prioritet end der kører, suppresser den den kørende og giver i stedet den anden lov at køre. Arbitratoren er opbygget af to dele som vi kalder executer og monitor. Monitor delen sørger for hele tiden at finde den opførsel med højest prioritet der ønsker at tage kontrol og derefter giver execute delen besked om dette. Execute sørger derefter for at starte den opførsel.

Som beskrevet så har vi en tom suppress metode i vores BTDriver klasse. Grunden til dette ligger i den måde Arbitratoren fungere på. Når Arbitratoren har fundet en tråd med højere prioritet en den kørende tråd, kalder den godt nok suppres på denne tråd, men hvis den tråd som i vores tilfælde alligevel ikke tilgår motoren ret langt tid af gangen, betyder det ikke noget at andre tråde venter denne tid.

Principperne anvendt i Arbitratoren ligner fuldstændig de principper anvendt af Fred. G. Martin[2], hvor hver behavior bliver tildelt en prioritet (i vores kode bliver prioriteten tildelt ud fra rækkefølgen af behaviors. Sidste element i listen har højest prioritet). Der er derefter Arbitratorens job at sørge for hele tiden af give den rigtige behavior retten til motorerne. Arbitratorens job kan sammenlignes med klassen Priority fra Martin.

Sammenligner man Fred. G. Martins[2] tilgang til hvordan håndteringen af de forskellige behaviors skal foregå med Rodney A. Brooks[3], så er der en væsentlig forskel. Martin anvender en central arbitrator til at bestemme hvilken af de forskellige opførsler der skal have adgang (selvfølgelig kun ud fra dem der ønsker at tage kontrol), mens Brooks i stedet giver opgaven til de enkelte opførsler. Dette løses ved at hver opførsel ved når de oprettes hvilken anden (underliggende) opførsel den skal suppresse. Nettop denne form for kontrol anvendte vi under øvelse 8, hvor eksemplet også er taget fra:
rd = new RandomDrive("Drive",1, null);
af = new AvoidFront ("Avoid",2,rd);
ps = new PlaySounds ("Play ",3,af);

Koden viser hvordan AvoidFront tager RandomDrive som parameter og PlaySound tager AvoidFront. Dette betyder at PlaySound er den opførsel med højest prioritet og når den kalder suppress() bliver alle underliggende lag suppresset eftersom metoden kaldes rekursivt ned igennem lagene.

Vi har valgt at gør brug af Fred Martins tilgangevinkel, eftersom vi ikke behøver at udføre noget egentligt suppress på vores opførsler. Grunden til dette er som beskrevet tidligere at vores opførsler alle afsluttes hurtigt og derfor ikke holder fast i retten til motorene. Vi har derfor blot brug for en enhed til at styre hver der skal have retten til motorene og dette tilbyder Martins metode.

Konklusion:
Konklusionen er at det lykkedes os at få Bluetooth til at virke. Udover at få robotten til at køre frem og tilbage, blev det også muligt at dreje den. Legwayen understøtter endnu ikke at man kan holde flere taster nede på én gang, selvom vores PC-program rent faktisk sender en bitmask der indikerer dette. Denne feature implementerer vi ved næste møde.
Derudover vil vi også tilføje to knapper til vores PC-program til at oprette og lukke forbindelsen til Legwayen således at vi ikke behøver at lukke programmet og starte det op igen hver gang vi vil lave en test.

Vi har overvejer meget hvordan vi skulle håndtere den subsumption arkitektur vi ønskede at anvende til de forskellige opførsler. Valget faldt på Martin, hvor vi har en central arbitrator der styre hvilken opførsel der skal have adgang til motorene.

Referencer:
  1. leJOS Tutorial: Communications: http://lejos.sourceforge.net/nxt/nxj/tutorial/Communications/Communications.htm
  2. Sequential and reactive control strategies, Chapter 5, pp.190-233 of Fred G. Martin, Robotic Explorations: A Hands-on Introduction to Engineering, Prentice Hall,2001. 
  3. Rodney Brooks, A robust layered control system for a mobile robot, IEEE Journal of Robotics and Automation, RA-2(1):14-23, 1986, MIT AI Memo 864, September 1985.

Ingen kommentarer:

Send en kommentar

Faste læsere