torsdag den 20. januar 2011

Afsluttende projekt, 8. dag

Date: 7. Januar 2010
Duration of activity: ? hours (10.30)
Group members participating: Heine Stokholm, Michael Vilhelmsen og Mads Møller Jensen

Dagens mål
  • Modificer banen en smule
  • Få robotten til at huske, hvad den har set
  • Arbejde med BlueTooth-kommunikationen

Banen
Vi har arbejdet lidt med banen og gjort midterlinjerne lidt smallere, der hvor robotten kom i problemer i forhold til kanten af den pladen, hvorpå banen er bygget. Dette har hjulpet betydeligt, men der er stadig lidt småproblemer. Vi overvejer at pille alle midterstriber op og lave nogle nye. Arbejdet med at lægge de første er nemlig udført en smule sjusket, så vi har flossede kanter, som forvirrer PID-systemet i LineFolloweren, og derved gør det svært for robotten at rette helt op. Derudover kan vi se, at nogle af stregerne er lagt en anelse skævt med samme problem som før til følge. Vi planlægger at lægge de nye midterstriber på mandag, hvor vi kan skaffe en hobbykniv, som forhåbentlig kan give os nogle mere stabile streger.

BlueTooth
Pc delen af vores bluetooth kommunikation kan ses her : kode
Vi har taget udgangspunkt i BTSend.java som er et bluetooth eksempel der kom lejos. Vores program fungerer sådan at vi først skaber en bluetooth forbindelse til thor(1). Derefter looper vi 9 gange(2) hvori vi sender en int afsted og venter på at få en int tilbage.(3) Den modtagne int bliver sendt afsted til vores roadmapRepresentation som bliver beskrevet andet steds (4).
Robotten står så samtidig og venter på at modtage en int. Når den har fået en sender den representation af det næste tile tilbage til pc'en. Det er en meget simpel protokol vi har fået bygget op, men den opfylder vores behov.


    public void getMap(){
 NXTConnector conn = new NXTConnector();
 RoadmapRepresentation mads = new RoadmapRepresentation(this);
 // Connect to any NXT over Bluetooth
 boolean connected = conn.connectTo("btspp://");(1)

 if (!connected) {
     System.err.println("Failed to connect to any NXT");
     System.exit(1);
 }

 DataOutputStream dos = conn.getDataOut();
 DataInputStream dis = conn.getDataIn();

 for(int i=0;i<9;i++) {(2)
     try {
  System.out.println("Sending " + (0));
  dos.writeInt(0);
  dos.flush();

     } catch (IOException ioe) {
  System.out.println("IO Exception writing bytes:");
  System.out.println(ioe.getMessage());
  break;
     }

     try {
  int temp = dis.readInt();(3)
  System.out.println("fik " + temp);
  mads.addInt(temp);(4)
     } catch (IOException ioe) {
  System.out.println("IO Exception reading bytes:");
  System.out.println(ioe.getMessage());
  break;
     }
 }
 try {
     dis.close();
     dos.close();
     conn.close();
 } catch (IOException ioe) {
     System.out.println("IOException closing connection:");
     System.out.println(ioe.getMessage());
 }
 mads.main(null);
    }

Status
Robotten kan køre banen og sende information tilbage til computeren. Dog kører robotten ikke banen igennem hver gang, så vi håber at de nye streger kan rette op på den inkonsistens, vi har nu. 

Næste gang 
Næste gang skal vi lave de nye streger. Det betyder også at vi endnu engang skal regulere vores PID-system i LineFolloweren. Vi skal derudover også implementere, at vi gennem den grafiske repræsentation, kan få robotten til at et bestemt modul, som vi aktiverer på computeren.

Afsluttende projekt, 9-10. dag

Date: 10-11. Januar 2010
Duration of activity: 10 hours
Group members participating: Heine Stokholm, Michael Vilhelmsen og Mads Møller Jensen

Dagens mål
  • Optimere banen med tyndere streger
  • Optimere robotten til den nye bane
  • Få computeren til at lave en grafisk repræsentation af banen ud fra de informationer, den modtager fra robotten
  • Gøre så den grafiske repræsentation kan bruges til at navigere med robotten.
Banen
Vi fik vha. gaffatape skabt en ny midterlinje på banen. Den nye midterlinje er 1,2 cm modsat de "gamle" streger, som var 2,5 cm. Det betyder at robotten kommer længere ind mod midten af banemodulerne, og vi undgår at den sidder fast i kanten af pladen. Den nye gaffatape har en anden farve end den "gamle", og vi har derfor været nød til at regulere PID-systemet endnu en gang. Derudover gør den nye tynde midterstribe, at robotten kan skyde over linjen, når den drejer de 90 grader. Derfor har vi lavet en sikkerhedsmekanisme, som gør, at robotten søger efter en grå linje, inden PID-systemet bliver slået til.

PID-systemet


Sikkerhedsmekanismen


        public void findLine() throws Exception{
//if we are on the grey line we return
if(cs.green()) return;
//else we turn slowly right to find it
int time = 0;
while(time < 45){
tachoNav.rotate(1);
if(cs.green()) return;
time++;
Thread.sleep(10);
}
//if we still haven't found it we turn 90 degrees left and check for it
time = 0;
while(time < 90){
tachoNav.rotate(-1);
if(cs.green()) return;
time++;
Thread.sleep(10);
}
}


Robotkoden i detaljer


Vores endelige kode kan findes i TurningRobot2.java - kode
Vi vil nu gennemgå alle metoder kort og forklare hvad de enkelte metoder bruges til i programmet.


Først har vi getIntFromTile(Tile t). Den tager et tile som input og returnerer så den int værdi som svarer til tilens opbygning. Vi har specificeret en værdi for alle ti forskellige tiles så vi kunne nøjes med at sende den int over bluetooth istedet for at sende hele tilet.

   //returns the int that represents the given tile
    public int getIntFromTile(Tile t){
 if(t.getNorth().isEmpty() && t.getEast().isEmpty()) return 0;
 if(t.getSouth().isEmpty() && t.getEast().isEmpty()) return 1;
 if(t.getNorth().isEmpty() && t.getWest().isEmpty()) return 2;
 if(t.getSouth().isEmpty() && t.getWest().isEmpty()) return 3;
 if(t.getNorth().isEmpty() && !t.getSouth().isEmpty() && !t.getWest().isEmpty() && !t.getEast().isEmpty()) return 4;
 if(!t.getNorth().isEmpty() && !t.getSouth().isEmpty() && !t.getWest().isEmpty() && t.getEast().isEmpty()) return 5;
 if(!t.getNorth().isEmpty() && t.getSouth().isEmpty() && !t.getWest().isEmpty() && !t.getEast().isEmpty()) return 6;
 if(!t.getNorth().isEmpty() && !t.getSouth().isEmpty() && t.getWest().isEmpty() && !t.getEast().isEmpty()) return 7;
 if(t.getWest().isEmpty() && t.getEast().isEmpty()) return 8;
 if(t.getNorth().isEmpty() && t.getSouth().isEmpty()) return 9;
 return 10;
    }


Derefter kommer map() metoden som er backbone i hele vores program. Den styrer den sekventielle gennemgang af vores program og vi vil nu gå et gennemløb af koden igennem.


Når map bliver kaldt første gang starter den med at tilføje et nyt tile der hvor den står(1). Derefter kommer vi ind i et while loop der bliver kørt indtil vi er færdig med at mappe banen(2). 
Vi kalder derefter getDirections() for at undersøge hvilken slags tile vi står på(3).
Når vi er færdige med at undersøge tilen vi står på skal vi bestemme hvilken retning vi nu vil køre i. I første omgang starter vi med at undersøge om en af de fire omkring liggende tiles har veje der mangler at bliver udforsket(4) og hvis ikke kalder vi metoden goToNull()(8) der finder den nærmeste tile der ikke er udforsket. 
Hvis vi har fundet en tile skal vi nu køre derhen. Vi starter med at finde den grå linie(5), så kalder vi lineFollow()(6) og derefter kører robotten bare ligeud indtil den ser den sorte markering med sin sekundære sensor(7).
Når vi er færdige med at mappe banen starter vi med at sende mappet(9), for derefter at gå ind i et loop der venter på en int fra computeren(10) og kører hen til den tile der svarer til den modtagne int(11). 


     

    public void map() throws Exception{
 //add the starting position to the map
 Tile start = new Tile(new Position(x,y)); (1)
 map.add(start);
 ma[x][y] = start;
 //loop until no tiles have a null pointer
 while(!finished()){ (2)
     //Check all the road that are null on a given tile
     checkDirections(); (3)
     //if we arent finished we move to a new tile
     if(!finished()){
  Sound.twoBeeps();
  int se = dir;
  //we checks if one of the four enclosing tiles has a nullpointer
  //and rotate to that direction if it does
  //We always starts with north
  boolean found = false;
  if(!ma[x][y].getNorth().isEmpty() && !found){ (4)
      if(ma[x][y+1].getNorth() == null || 
         ma[x][y+1].getEast() == null ||
         ma[x][y+1].getWest() == null ||
         ma[x][y+1].getSouth() == null){
   int rot = 90*(n-dir);
   if(rot < -180) rot = 90;
   if(rot > 180)  rot = -90;
   tachoNav.rotate(rot, false);
   dir = 1;
   found = true;
      }
  }
  if(!ma[x][y].getEast().isEmpty() && !found){
     ~~
  }
  if(!ma[x][y].getSouth().isEmpty() && !found){
     ~~
  }
  if(!ma[x][y].getWest().isEmpty() && !found){
     ~~
  }
  //if we have found a tile that needs checking we drive there
  if(found){
      //we update the position of the robot
      if(dir == 1) y++;
      if(dir == 2) x++;
      if(dir == 3) y--;
      if(dir == 4) x--;
      //tries to locate the gray line
      findLine();(5)
      //and use a pid line follower
      lineFollow();(6)
      
      //afterwards we drive forward until we see black on the secondary sensor
      tachoNav.stop();
      tachoNav.forward();
      while(secondaryColor.light() > secondaryColor.getBlackLightValue() + 100){}(7)
      tachoNav.stop();
      Thread.sleep(500);
      //if no tile is found with null we find the shortest route to a tile with null and drives there
  }else{
      goToNull(); (8)
  }
     }
 }
 //when we are finished mapping we tries to send our map
 sendMap();(9)
 //when finished we can control the robot from the computer
 while(true){
     LCD.drawString(waiting,0,0);
     LCD.refresh();

     //we wait for a incoming bluetooth connection
     BTConnection btc = Bluetooth.waitForConnection();(10)             
     LCD.clear();
     LCD.drawString(connected,0,0);
     LCD.refresh();

     DataInputStream dis = btc.openDataInputStream();
     //then we go to the tile that the int received represents
     goToStart(dis.readInt());(11)
     //and close the connections to start over
     dis.close();
     Thread.sleep(100); // wait for data to drain
     LCD.clear();
     LCD.drawString(closing,0,0);
     LCD.refresh();
     btc.close();
     LCD.clear();
 }
    }
I checkDirections() gør vi følgende for alle fire retninger:
 
Checker om den allerede er undersøgt. (1)
Hvis ikke drejer vi robotten den retning. (2)
Måler om der er sort eller ej. (3)
Og opdaterer tiles afhængig af hvad vi målte.(4)



    public void checkDirections() throws Exception{
 //we get the tile on thors current position
 Tile current = ma[x][y];
 try{
     
     Thread.sleep(100);
     
     int tempDir = dir;
     //we loops four times to check all four ways the robot can leave the tile
     //we start by checking the direction we are currently facing and then turn right
     for(int i = 0; i<4; i++){
  if(tempDir == 1){
      //we only check the road if we don't know where it leads
      if(current.getNorth() == null){(1)
   //we rotate the robot to point the right direction
   int rot = 90*(n-dir);
   if(rot < -180) rot = 90;
   if(rot > 180)  rot = -90;
   tachoNav.rotate(rot, false);(2)
   dir = 1;
   //if we dont see black
   if(!(cs.light() < cs.getGreenLightValue() - 50)){(3)
       Tile temp;
       //we get or create the tile in that direction(4)
       if(ma[x][y+1] != null){
    temp = ma[x][y+1];
       }else{
    temp = new Tile(new Position(x,y+1));
       }
       //and updates the references
       current.setNorth(temp);
       temp.setSouth(current);
       map.add(temp);
       ma[x][y+1] = temp;
       Sound.beep();
   }else{
       //else we point to the empty tile to symbolize a blocked road
       current.setNorth(emptyTile);
   }
      }
      Thread.sleep(100);
  }
  if(tempDir == 2){
      if(current.getEast() == null){
   ~~
      }

      Thread.sleep(100);
  }
  if(tempDir == 3){
      if(current.getSouth() == null){
   ~~
      }

      Thread.sleep(100);
  }
  if(tempDir == 4){
      if(current.getWest() == null){
   ~~
      }
      
  }
  tempDir = tempDir + 1;
  if(tempDir == 5) tempDir = 1;
     }
 }catch(Exception e){
     LCD.clear();
     LCD.drawString(e.toString(),0,0);
     LCD.refresh();
     Thread.sleep(5000);
 }
 Thread.sleep(300);
    }


Den sidste metode vi har valgt at gennemgå her har det noget vildledende navn goToStart(int t). Den gør faktisk det at den tager en int og ud fra den bruger den dijkstra til at finde den korteste rute hen til den tile.(1) Derefter har den så en løkke hvor kører derhen en tile af gangen.(2) Måden vi kører rundt mellem tilene er magen til den tidligere omtalt map() metode så det vil jeg ikke komme nærmere ind på her.

 public void goToStart(int t) throws Exception{
 // we start by finding the tile that is at position t
 // our tiles are mapped like this:
 //012
 //345
 //678
 // and tlx,tly is the position of number 0
 int tempx = 0;
 int tempy = 0;
 if(t == 0){
     tempx = tlx;
     tempy = tly;
 }else if(t == 1){
     tempx = tlx+1;
     tempy = tly;
 }else if(t == 2){
     tempx = tlx+2;
     tempy = tly;
 }else if(t == 3){
     tempx = tlx;
     tempy = tly-1;
 }else if(t == 4){
     tempx = tlx+1;
     tempy = tly-1;
 }else if(t == 5){
     tempx = tlx+2;
     tempy = tly-1;
 }else if(t == 6){
     tempx = tlx;
     tempy = tly-2;
 }else if(t == 7){
     tempx = tlx+1;
     tempy = tly-2;
 }else if(t == 8){
     tempx = tlx+2;
     tempy = tly-2;
 }
 if(tempx != x || tempy != y){
     //We find the shortest route using dijkstra
     Tile[] route = shortestRoute(ma[x][y], map, ma[tempx][tempy]);(1)
     //the tile the robot is located on 
     Tile current = ma[x][y];
     int i = 9;
     while(route[i] == null) i--;
     i--;
     Tile next = route[i];
     boolean f = false;
     //while we haven't reached our goal
     while(!f){(2)
  //we check which way is next and rotate that way
  if(next == current.getNorth()){
      int rot = 90*(n-dir);
      if(rot < -180) rot = 90;
      if(rot > 180)  rot = -90;
      tachoNav.rotate(rot, false);
      y = y + 1;
      dir = 1;
  }else if(next == current.getEast()){
      ~~
  }else if(next == current.getSouth()){
      ~~
  }else if(next == current.getWest()){
      ~~
  }
  //then we find the gray line
  findLine();
  //and use our pid line follower
  lineFollow();
  //drive forward until secondary sees black
  tachoNav.forward();
  while(secondaryColor.light() > secondaryColor.getBlackLightValue() + 100){}
  tachoNav.stop();
  Thread.sleep(500);
  //and updates how far in the route we have gone
  if(i == 1){
      f = true;
  }else{
      current = next;
      i--;
      next = route[i];
  }
     }
 }
    } 



Den grafiske repræsentation


Status

torsdag den 6. januar 2011

Afsluttende projekt, 7. dag

Date: 6. Januar 2010
Duration of activity: 4 hours
Group members participating: Heine Stokholm, Michael Vilhelmsen og Mads Møller Jensen

Dagens mål
  • Få robotten til at køre gennem banen
Plan
  • Kigge på delene af programmet og optimere disse
  • Ændre banen, så robotten kan se de sorte markeringer, som fortæller den, at den befinder sig på midten af et modul
Problemer
I går havde vi store problemer med at få farten ned på PID-systemet i LineFollower-delen af programmet. Vi har løst dette på en "hovedet-under-armen"-metode, og divideret farten med 2. Dvs. at vi har leftMotor.controlMotor(power/2), og tilsvarende rightMotor.controlMotor(power/2). Dette har imidlertid virket og robotten kører gennem banen med en mere acceptabel fart. 

I dag opstod et nyt problem. Når vi har drejet 360 grader og scannet de åbne veje, kører vi lidt frem med PID-systemet i LineFolloweren for at rette de eventuelle fejl, der kan opstå ved rotationen. Når robotten er rettet ind, skal den så køre ligeud - uden PID-system - indtil den ser en sort markering. Grunden til at den skal køre uden PID-system er, at vi ser den sorte væg inden vi ser den sorte markering, og med PID-systemet ville robotten dreje helt skævt. Problemet består nu i, at vi har en fejl på en motor, formoder vi, som gør, at robotten drejer til venstre, når den blot skal køre ligeud. Vi lavede et simpelt program, som bare skulle få robotten til at køre ligeud, og det viste desværre, at vi havde ret i vores antagelse. Både ved høj og ved lav fart. Vi prøvede at køre med robotten på banen med det rigtige program, og pludselig ville robotten gerne køre ligeud, som den skulle.

Vi har indtil videre beholdt kompasset på robotten, så vi kunne bruge det til at sige, hvad der er nord, syd, øst og vest, så vi var fri for at huske hvilken retning, vi peger. Vi vidste, at kompasset var lidt fejlbarlig, men vi troede, at vi kunne bruge det til at angive en cirka retning. Denne antagelse var helt forkert! Kompasset var så forvirret, så den troede, robotten var drejet 235 grader, når den kun var drejet 180. Det betød at kompas værdien var tættere på 270 grader, og den fortalte robotten, at den pegede i en anden retning end den gjorde.

Den følgende video viser to ting:
  1. Videoen viser, hvor godt robotten efterhånden kører rundt på banen, holder sig til linjerne og læser de rigtige værdier.
  2. Samtidig viser videoen også, at kompasset forstyrrer robotten så den er i tvivl om hvilke retninger den skal læse.

For at løse problemet har vi lavet en variabel, som husker hvilken retning, robotten peger i.
Resultatet heraf var som følger:





Status
Vores robot kan efterhånden køre banen rundt. Vi har prøvet forskellige ting af i dag, og vi synes efterhånden at resultatet er ret godt. Det har virkelig givet pote, at fokusere på de små dele af programmet og optimere dem hver for sig. Robotten kører næsten banen som den skal. Vi er meget tilfredse med at have droppet at bruge kompasset. Derved har vi også fjernet noget af det mere dynamiske i miljøet, så det i sin helhed er blevet mere statisk og derved egner sig endnu bedre til vores sekvens strategi.


Næste gang
Næste gang skal vi have modificeret bane en lille smule. Robotten har lidt problemer i kanterne, hvor den støder i mod kanten af den plade som banen er på (Dette kan også ses på videoen). Derudover skal vi arbejde videre med, at robotten skal huske de moduler den ser, og at den ikke scanner de samme moduler flere gange, og forhåbentlig til sidst kan lave et 2-dimensionalt array som vi kan arbejde med på computeren.

onsdag den 5. januar 2011

Afsluttende projekt, 6. dag

Date: 5. Januar 2010
Duration of activity: 3½ hours
Group members participating: Heine Stokholm, Michael Vilhelmsen og Mads Møller Jensen

Dagens mål
  • Få optimeret de forskellige dele af programmet, som robotten skal køre
  • Forsøge at sætte de forskellige dele sammen, så robotten kan køre gennem banen, hvis vi bliver færdige med at optimere.
Plan
  • Dele programmet op i de forskellige sekvenser igen
  • Sætte farten ned i PID-systemerne
  • Forsøge at anvende tachocounteren i stedet for kompasset
Optimering
Efter en dag i går, hvor robotten ikke rigtigt lystrede, har vi valgt at forsøge at optimere vores robot. Vi har derfor delt programmet op i mindre dele:
  1. TurningRobot - kode
  2. LineFollower - kode
Den del af programmet som vælger hvor robotten skal køre hen næste gang, er blot en algoritme og er derfor ikke relevant at tjekke i praksis med robotten.
TurningRobot programmet får robotten til at dreje rundt om sig selv, og for hver 90 grader måler den med lyssensoren, om den har set en åben eller en lukket vej. Vi har haft dette program til at virke før, men robotten kommer uregelmæssigt ud af programmet hver gang. Derfor bliver vi nødt til at optimere enten ved at optimere med kompasset eller bruge tachocounteren. Vi har forsøgt mange gange tidligere at bruge kompasset, men hver gang vi troede, at det virkede, har den skiftet opførsel til næste gennemløb. Derfor har vi prøvet at bruge tachocounteren. Vi ved i forvejen, at denne er upræcis, men i forhold til kompasset, er der ved tachocounteren større sandsynlighed for, at den er cirka lige upræcis hver gang. På den måde håber vi at få lidt mere kontrol med robotten, end vi har når vi bruger kompasset. 
I LineFollower programmet har vi tweaket lidt på de forskellige parametre. F.eks. har vi sat farten væsentligt ned og skruet lidt ned for Kc og Kp konstanten, for at få robotten til at oscillere mindre omkring linjen. Linjen skal jo bare bruges til at rette op efter, når robotten har drejet 360 grader om sig selv. Derfor dur det ikke hvis den oscillerer for meget, så den holder skævt, når LineFolloweren stopper. 

Repræsentation
Vi har også arbejdet videre med robottens repræsentation af kortet. Robotten husker på et 2-dimensionalt array bestående af Tiles. Disse Tiles kan man så spørge, om det er muligt at køre nord, syd, øst eller vest. Robotten finder ud af dette, når den kører rundt og scanner banen. I RoadmapRepresentation klassen har vi så lavet en metode, som tager et 2-dimensionalt array af Tiles og laver om til et streng.array, som vi så kan bearbejde på samme måde som de streng-arrays vi brugte i eksemplet fra sidste gang. Det eneste vi mangler nu er, at robotten kan konstruere det 2-dimensionale array ud fra det den læser på banen og efter færdigt gennemløb sender arrayet til computeren via BlueTooth. 

Status
Det hjalp os rigtig meget at skifte til tachocounteren. Vi får meget tæt på 90 graders rotation efter at have justeret lidt på hjulbredden osv. og sat farten meget ned. TurningRobot-delen er som det skal være nu, og det fungerer godt med at se om der er en væg i de forskellige retninger eller ej. 

LineFolloweren driller os rigtig meget, for vi har en LineFollower som fungerer rigtig godt, men når vi sætter den sammen med de andre komponenter, er der noget vi har overset, som gør at den kører alt for hurtigt, når den følger linjen. Vi troede, at det var TachoPilot-klassens regulateSpeed, der skulle sættes til false, men dette var ikke tilfældet. Vi har endnu ikke fundet fejlen.  

Vi har også modificeret robotten lidt. Vi har forlænget armen med den ene lyssensor, fordi robotten befandt sig lidt for langt væk fra markeringerne efter den retter ind efter den grå midterlinje. 

Næste gang
Næste gang skal vi have robotten til at køre endnu bedre end den gør. Og vi skal have den til at bruge de oplysninger den indsamler, så den ved hvilket modul, den skal køre hen til "næste gang". Hvis der bliver tid, skal vi se om den kan udfylde et array af Tiles og måske sende dette til computeren, som kan lave en grafisk repræsentation af dette.  

tirsdag den 4. januar 2011

Afsluttende projekt, 5. dag

Date: 4. Januar 2010
Duration of activity: 4 hours
Group members participating: Heine Stokholm, Michael Vilhelmsen og Mads Møller Jensen



Dagens mål
  • Få Thor til at køre efter vores sekvensstrategi.
  • (Rette fejl i koden)
  • Implentere brugen af en grå stribe på kortet til at navigere mere præcist efter.
  • Optimere kompasset
  • (Få Thor til at sende data og få vores PC til at modtage disse)
Plan

Sekvensstrategi:
Vores program består stadig af de 3 sekvenser:

  1. Identificer modulet
  2. Find ud af hvor vi skal hen næste gang
  3. Kør derhen
Thor er i stand til at følge disse strategier, men stadig uden brug af en "LineFollower"-del. Dette vil vi implementere i dag, da det simpelthen er nødvendigt for os for at kunne ordentligt.
Selve PID-systemet til at følge en linje har vi lavet, og vi vil i dag indsætte det i vores kode, så Thor benytter dette som et led i sin sekvensstrategi, under punkt 3.

Grå Stribe:
Vi fik sat en grå stribe på vores bane sidste gang, og stødte på et nyt problem, nemlig at vi aldrig kører midt på striben, men altid til en side af denne. Derfor vil vi i dag flytte alle de små sorte firkanter som vores sekundære lyssensor læser. Disse kan flyttes uden problemer, da de netop er sat på en måde der tager højde for fra hvilken side man kommer. Desuden bliver vi nødt til enten at forlænge armen med vores primære lyssensor på, eller udvide alle de brede sorte striber.

Sende og modtage data:
Vi vil i sidste ende have Thor til at opbygge et map af vores bane, og sende dette til vores PC, som så kan lave en grafisk repræsentation. For at tage hul på dette vil vi i dag forsøge at få Thor til at sende data som vi vil modtage.
Ideelt set vil Thor køre hele vores bane igennem, og så til sidst sende et komplet map af banen. Dette vil i sidste ende betyde at vi indfører et ekstra punkt i vores sekvensstrategi. I dag vil vi dog sende inden vi har et komplet map, da vi stadig er langt fra at kunne foretage et fuldstændigt gennemløb af vores bane. 

Optimere kompas:
Da vi allerede nu forudser problemer med den grå stribe som vi vil implementere, vil vi gøre et sidste forsøg på at gøre kompasset brugbart. Det primære problem skønner vi er elektronisk forstyrrelse fra de mange elektriske kilder der er tilstede i lokalet og tæt ved vores bane. Derfor vil vi undersøge om det vil hjælpe noget at hæve kompasset yderligere, eller måske endda om vores kompas er defekt.


Resultater:

Fejl:
Vi har introduceret adskillige fejl i vores kode, så nu kaster Thor exceptions i vildskab. Derfor arbejder vi på at få disse fejl elimineret, da vi så burde have en (vel)fungerende sekvensstrategi.

Kompas:
Det viste sig at vores kompas stort set er ubrugeligt. Når den blot drejer på stedet fungerede det nogenlunde. 
Her var fejlmarginenen på +/- 10 grader, hvilket ikke er optimalt, men dog brugbart til eks. at dreje 360 grader.
De største udsving viste sig når vi tog vores robot, og pressede den op mod kanten af vores bane, og aflæste kompasværdien, for derefter at rykke vores robot x antal cm. frem.
Her viste det sig, at hvis vi starter i den ene ende af vores bane, hvor vi eks. har værdien 100, og rykker op i den anden ende af vores bane, ender vi på 130. Og talene ændrer sig lineært undervejs, dvs at halvvejs har vi værdien 115. Lignende målinger foretaget andre stedet i lokalet, og med kompasset rykket længere væk fra Thor gav samme resultat - kompasset er ubrugeligt. 
Vi vil derfor undersøge om vi får andre resultater med et andet kompas. Hvis ikke vil vi måske foretage vores sving vha. tachocounter i stedet for kompasset. Navigering må vi i givet fald foretage vha. den grå stribe som vi også har planlagt.

Status:
Vi fik identificeret fejl ved kompasset og overvejer nu andre metoder til at foretage præcise sving på. 
Vi fik ikke arbejdet med at sende data over bluetooth endnu. Dette må vente til senere.
Vi fik dog rettet fejlene i Thor, så han nu igen kan følge en linje.
Den grå stribe og de sorte firkanter "virker" tilfredstillende indtil videre. De skal dog rettes til en gang.


Næste gang:
Vi skal finde en brugbar metode til at foretage præcise sving på.
Vi skal finde ud af at sende og modtage data fra robotten via bluetooth.
Vi skal højst sandsynligt have rettet striberne på banen til, så de er mere præcise.

mandag den 3. januar 2011

Afsluttende projekt, 4. dag

Date: 3. Januar 2010
Duration of activity: 4½ hours
Group members participating: Heine Stokholm og Mads Møller Jensen

Dagens mål
  • Lave stregen på banen som robotten skal følge
  • Få robotten til at køre på banen vha de forskellige sekvenser
  • Kigge på repræsentationen af robottens input på computeren
  • Evt. Bluetooth-kommunikation


Plan
  • Lave en grå streg på banen som robotten kan navigere efter. Vi ønsker denne streg pga. af præcision vanskeligheder ved kompasset.
  • Implementere et program som robotten skal køre vha. de forskellige systemer, vi allerede har udviklet
  • Implementere et program som skal lave en grafisk repræsentation af de data vi får fra robotten

Stregen
Vi forsøgte at lave en grå streg af gaffatape på vores bane, men vi mødte et stort problem. For at stregen skal få robotten til at blive på midten af banen, skal stregen placeres ved siden af midten, da robotten jo vil korrigere i forhold til den grå farve på stregen og den hvide farve på pladen. Dette giver os et stort problem, da vi ikke kan vide med sikkerhed, hvilken vej robotten kommer fra, og dermed ikke kan vide på hvilken side af midten, stregen skal placeres. Vi vil derfor i første omgang forsøge at teste, om det er muligt for robotten at gennemføre uden at have en streg at korrigere efter. Dette er meget risikabelt, da vi tidligere har haft problemer med kompassets præcision og derved har en potentiel stor fejlmargin. Vi lægger derfor hovederne i blød for at finde et alternativ.

Sekvensstrategi
Vores program består af tre sekvenser:

  1. Identificer modulet
  2. Find ud af hvor vi skal hen næste gang
  3. Kør derhen
Disse tre sekvenser består af en masse små operationer. Ingen af de tre sekvenser var helt færdige, men vi kunne få robotten til at kører rundt 4x90 grader og bippe, når den så hvid, altså en mulig vej. Herefter valgte robotten en tilfældig vej, og kørte indtil den så en sort markering. Her fandt vi ud af, at vi er nødt til at have en rettesnor til robotten i form af en streg. Det var tydeligt for os at se, at det ikke ville fungere i længden ved kun at bruge kompasset, der simpelthen er for upræcist.  

Fred Martin skriver om fordele og ulemper ved en sekventiel strategi i kapitel 5.3 i bogen "Robotic Explorations". En sekventiel tilgang er en række handlinger man udfører for at opnå et ønsket mål. I vores tilfælde at mappe en bane, der er opbygget af moduler. Men disse handlinger er ikke nok i sig selv, hverken i Fred Martins Groucho tilfælde eller i vores. Da robotten er upræcis, er vi nødt til at have nogle feedbackloops for at korrigere. Dette har vi bl.a. i vores kompas PID-system og i den LineFollower vi er nødt til at lave. Sekventielle strategier egner sig godt i et statisk miljø. Groucho er en robot, som kæmper mod andre robotter i Robo-Pong, og den befinder sig dermed i et dynamisk miljø. Vi har derimod et rimeligt statisk miljø med en fast bane og kun en robot. Alligevel er der nogle ændringer i miljøet, som gør at robotten ikke fungerer perfekt. F.eks. Er det et stort problem at der løber strøm i gulvet og i sidepanelerne og det giver vores kompas store problemer. Vi mener dog, at den sekventielle tilgang er vejen at gå, da den opgave vi har opstillet minder meget om en matematisk algoritme, som også består af en række operationer som anvendes på noget data.


Grafisk repræsentation
Vi har lavet et meget simpelt program, som tager et array af strenge, og laver en grafisk repræsentation af disse strenge. I alt sin enkelthed ud på følgende:
  1. Vi gemmer de 11 forskellige banemoduler i et map. Hvert modul er repræsenteret af et 300x300 pixel jpeg-billede, som vi har lavet meget primitivt i paint.
  2. Vi læser array'et igennem, hvor hver streng repræsenterer et specifikt modul. Strengens placering i arrayet, afgør hvor i griddet det placeres. 
  3. Til sidst vises billederne i et grid som svarer til banens opbygning.
Programmet er lavet til at mappe vores specifikke bane, eller i hvert fald en bane af samme størrelse, dvs. 3x3 moduler. Placeringerne i arrayet giver følgende placering i griddet:
Koden for programmet kan ses her: RoadmapRepresentation.java
For at programmet virker skal man lave de 11 moduler og give dem de rigtige navne som er angivet i koden.

Stregen, del 2
Vi har besluttet os for alligevel at lave en grå streg på midten af banemodulerne. Vi kan kompensere for at robotten ikke kører præcis midt på modulet ved at flytte de små sorte markeringer. Markeringerne er i forvejen placeret i forhold til hvilken vej man kommer ind på et modul. Da vi altid vil køre på samme side af den grå streg, er det derfor muligt at flytte markeringerne. Dette betyder, at vi vil have problemer med at få lyssensoren helt ud og læse kanterne, fordi robotten ikke længere holder midt på modulet. Dette kan løses ved enten at forlænge armen som lyssensoren sidder på eller ved at gøre kanterne bredere.
Vi har lavet den tynde grå streg på banen.

Status
Vi har fået et program , der kan tage et streng-array og vise en grafisk repræsentation af de forskellige banemoduler. Vi har fået en streg som kan korrigere robotten, når kompasset er upræcist. Vi har set, hvor langt vi er med vores program.

Næste gang
Næste gang skal vi arbejde med at få sekvensstrategien til at virke og så skal vi flytte alle de sorte markeringer, så de passer til, at robotten kører ved siden af midten.

Referencer
Fred G. Martin, Robotic Exploration: "A Hands-On Introduction to Engineering", 2001 Prentice-Hall 

torsdag den 16. december 2010

Afsluttende projekt, 3. dag

Date: 16. December 2010
Duration of activity: 4 hours
Group members participating: Heine Stokholm og Mads Møller Jensen


Dagens mål:

  • Færdiggøre PID-systemet
  • Finde ud af robottens endelige navigation i banen
  • Kigge på Bluetooth kommunikation
Plan:
  • Arbejde videre med gårsdagens PID-system
  • Undersøge muligheder for at navigere i banen
  • Få robotten til at sende de læste kompasværdier til computeren vha. Bluetooth, og eventuelt fortæller detaljer om hvordan den har kørt
PID-systemet
I dag har vi arbejdet videre med PID-systemet og fået et rigtig fornuftigt resultat. Robotten overstyrer stadig, når den skal dreje til en bestemt kompasværdi, men nu har vi fået den til at oscillere tilbage mod målet, så vi ender med en errorværdi på 0, og robotten altså peger præcis den vej, som kompasset fortæller den, den skal. Desværre har vi stadig lidt problemer med kalibreringen af kompasset, så robotten ikke drejer 90 grader, selvom den tror, den gør. Alligevel drejer den "omkring" 90 grader, og vi kan godt bruge dette resultat, selvom det ikke er perfekt.
Planen er, at robotten skal køre til midten af et banemodul, dreje 90 grader og læse om der er en sort streg, og gentage dette fire gange, og på den måde genkende banemodulet. Her er det ikke så vigtig om robotten drejer 90 eller 95 grader, da vi i begge tilfælde vil være muligt at se om der er en sort streg.
Koden for at dreje 90 grader med PID-systemet kan ses her


De største forskelle på PID-systemet til at følge en linie  og det til at følge kompasset er måden vi finder vores offset i starten og måden vi beregner error værdien løbende. Vores metode til at dreje med PID-systemet tager to værdier, start og t, som er i hvilken retning peger og hvor meget vi gerne vil dreje den. Ud fra det beregner vi så offsettet. Error værdien bliver beregnet ud fra offsettet minus den retning vi peger, men med nogle yderligere tjek da vi skal sikre os at vi altid drejer kortest vej. Derfor har vi sagt at hvis vi skal dreje over 180 grader skal vi istedet dreje error - 360 grader. 
Udover det har vi lavet en variabel der meget passende er døbt awesome som bliver talt op hver gang vores error er lig nul, og nulstillet hvis error er forskellige fra nul. Med den kan vi registrere om robotten har fundet hvile i den rigtige retning, eller om den bare står og oscillerer over offsettet. Hvis de sidste 100 errors har været 0 går vi ud af løkken og går ud fra at robotten peger i den rigtige retning. 

De relevante steder i koden står med fed i kodestykket nedenfor.


public static void pidTurn(int start, int t){
 long kp = 300;
 long ki = 10;
 long kd = 500;
 long offset = (start + t)%360;
 long tp = 10;
 long integral = 0;
 long lastError = 0;
 long error = 0, derivative, turn, power;
 int awesome = 0;
 while(awesome < 100){
     LCD.drawInt((int)us.getDegrees(),3,13,0);
     LCD.drawString("offset", 0, 1);
     LCD.drawInt((int)offset,3,13,1);
     LCD.drawString("error", 0, 2);
     LCD.drawInt((int)error,3,13,2);
     error = (start + t)%360 - (int)us.getDegrees();
     if(error > 180) error = error - 360;
     integral = integral + error;
     derivative = error - lastError;
     turn = kp * error + ki * integral + kd * derivative;
     turn = turn / 100;
     power = tp + turn;
     leftMotor.controlMotor((int)power,1);
     rightMotor.controlMotor((int)power,2);
     
     lastError = error;
     if(lastError == 0){
  awesome++;
     }else{
  awesome = 0;
     }
 }
    }
    
Navigation på banen
Problemet i at vores robot ikke drejer præcist er, at vi så har svært ved at få det til at køre "rigtigt" rundt på banen. Vi har derfor valgt at bruge en sekventiel strategi. Først og fremmest vil vi modificere banen, så vi får en midterlinje på hele banen. Derved kunne vi bruge en LineFollower til at køre imellem de forskellige moduler og skifte til kompasfunktionen, når vi skal genkende de forskellige moduler. Et problem, vi dog stadig slås lidt med, er, at vi mangler en god idé, så robotten kan se når den er på midten af et modul, og altså kan bruge genkendelsesprocessen. Indtil videre har vi to forslag:
  • Bruge en tacocounter for at måle, hvor langt vi er kørt. Da vi ved hvor store de forskellige moduler er burde dette være en mulig løsning, og også den vi ville have brugt, hvis kompasset fungerede optimalt. Men da vi nok bliver nødt til at bruge en LineFollower, bliver det svære at bedømme afstanden, da robotten skal navigere efter stregen, samtidig med at den skal køre en bestemt længde frem.
  • En anden løsning kunne være at lave en markering på midten af hvert modul. På den måde ville robotten kunne genkende midten, når den vha. LineFolloweren nåede derhen. Problemet er her, at vores lyssensor er placeret et stykke foran robotten, så vi alligevel er tvunget til at bruge tacocounteren til at køre det sidste stykke frem, og derved igen er i fare for at miste præcision. En løsning her er dog at bruge en ekstra lyssensor, som vi placerer ud for hjulene. På den måde ved vi, at vi skal stoppe, når denne lyssensor læser markeringen midt på modulet. 
Endnu et PID-system
Vi begyndte at lave et PID-system, så robotten kunne følge en linje, så vi kan være sikre på, at robotten kører "rigtigt" på banen. Igen fulgte vi metoden fra PID_Controller_For_Lego_Mindstorms, da vi føler, at denne metode har en stor succesrate. Dette var overstået rimelig hurtigt og robotten kunne følge en linje uden at oscillere. Eftersom robotten ikke skal følge en linje gennem et sving, gjorde det opgave rimelig overskuelig, og vi fik hurtigt rigtig gode resultater med meget få justeringer. 

Status
De nye tiltag, vi har lavet i dag, har betydet, at vi har lavet to modifikationer i forhold til tidligere.
For det første har vi ombygget robotten:
Dvs. vi nu har en robot med tre sensorer: Et kompas (som er placeret ca. 20 cm væk fra selve NXT'en), en lyssensor (som er placeret foran robotten) og en ekstra lyssensor(som er placeret bag hjulene). Det er nu meningen at robotten skal mappe, som følger:
Følge en streg vha lyssensor1 indtil lyssensor2 ser en markering. Herefter drejer robotten 4x90 grader, og for hver 90 grader scanner den med lyssensor1 efter sort eller hvid. Næste skridt vælger robotten en af de mulige veje, som (den lige har opdaget), eksisterer og følger så vha. lyssensor1 en streg videre til næste gang lyssensor2 ser en markering, osv.


Dette har betydet, at vi også har ændret vores bane:
Selve banen er i for sig den samme, men nu har vi tilføjet alle de markeringer lyssensor2 skal aflæse (de mange små sorte prikker).  Vi mangler dog stadig at lave en streg som robotten skal følge, men dette gemmer vi til næste gang.


Til gengæld har vi nu en klar idé om, hvordan vi skal få robotten til at mappe banen. Vi har et godt PID-system til kompasset og et godt PID-system til at følge linjen med. Det sidste skal muligvis revideres, når vi får testet det på vores endelige bane, altså på den streg vi mangler at tegne op.


Næste gang
Næste gang vil vi:

  • Lave stregen på banen, som robotten skal følge
  • Få robottens sekvensstrategi til at fungere (altså få sat de forskellige dele sammen til et helt program)
  • Kigge på Bluetooth-kommunikation (som vi ikke nåede i dag)
  • Kigge på repræsentationen af robottens input på computeren