torsdag den 20. januar 2011

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

Ingen kommentarer:

Send en kommentar