Video af robot

http://www.youtube.com/watch?v=oDUHsJXiDHY

Opgaven

I denne opgave skal I hver især bygge en robot, der er en del af en større helhed, hvor robotterne (agenterne) i systemet i fællesskab skal løse en opgave, der består i at fragte et objekt fra A – B. Robotterne, der skal konstrueres tager udgangspunkt i teknologien i har benyttet i POPG02, men skal selvfølgelig tilpasses nye omgivelser og opgaver. De fem opgaver/robotter er som følger.

Opgave 1 – Robot 1: Find lyskilde, hvor objektet er (2 lyssensorer) – Send robot afsted

Robot 1 skal ikke kunne fragte objektet, men blot finde frem til robot 2 via dennes lyskilde, for at sende denne afsted med objektet. Robot 1 har altså som opgave at ”skyde missionen i gang”.

Opgave 2 – Robot 2: Følg linie på gulv med objekt (2 lyssensorer, afbræk i streg)

Robotten skal følge en fast defineret streg på gulvet, og kunne tage højde for afbræk i stregen og objekter undervejs.

Opgave 3 – Robot 3: Tag objekt fra robot i opgave 2 og aflever til robot i opgave 4.

Robotten er en mere eller mindre stillestående robot, der har til opgave at tage objektet fra robot 2 og give det videre til robot 4.

Opgave 4 – Robot 4: Før objekt fra gulv til bord (bestem selv transportform)

Robot 4 skal føre objektet fra gulv til bord, og kunne aflevere det til robot 5.

Opgave 5 – Robot 5: Find vej over bord med objekter ‐ labyrint (Sonar)

Robotten skal kunne gennemføre en labyrint med objektet for endelig at aflevere det i målet.

 

Udfordringer ved opgaven

Opgaven består af et multiagentsystem, hvor de forskellige robotter er afhængige af hinanden. Derudover kører robotterne i serie, og skal derfor vente på hinanden. I den sammenhæng er det vigtigt at finde en måde at kommunikere mellem robotterne, så de ved hvornår de skal stoppe og gå i gang. I opgaven har vi valgt at kommunikere gennem mekaniske metoder, såsom knapper, hvilket igen gør, at robotterne skal være meget præcise for at kunne ramme og kommunikere hinanden.

Arduino Motor Shield og motorer

Se Flash Sinatra.

 

SN754410NE

SN754410

SN754410NE er en quadruple half-h driver til brug af motorstyring af to motorer. Driveren har to separate kredsløb – det logiske kredsløb VCC1 og output kredsløbet VCC2. VCC1 kræver en spænding på mellem 4.5 og 5.5V, mens VCC2, som er det output motorerne får kan være på mellem 3.5 til 36V. Driveren kan styre op til to motorer, hvor strømmens retning og dermed også motorens retning kan bestemmes separat. Den ene motor styres med pin 3 og 6 og den anden med pin 11 og 14 på driveren. Styringen foregår ved at have spænding på den ene pin og 0V på den anden. I opgaven bruges driveren til styring af en motor, som bruges til at holde og slippe bolden der skal rundt i banen. Der bruges derfor kun pin 3 og 6 til styringen. Outputkredsløbet kommer fra V-in på Arduino boardet, som er den strøm Arduinoen får uden at nedregulere den til henholdvis 3.5V og 5V. I opgaven får Arduino-boardet strøm fra 8 AA batterier på 1.2V, og motoren får derfor samlet op til 9.6V.

http://www.ti.com/lit/ds/symlink/sn754410.pdf

 

Lego lyssensor

I portefølje opgave 2 blev der for robotten Flash Sinatra brugt Arduino boardets indbyggede mulighed for pull-up resistor på analogeinput til det input der kom fra lyssensoren. Ved brug af lyssensorens indbyggede lys er lyssensorens lysfølsomhed ved brug af Arduino-boardets indbyggede pull-up resistor ikke stor nok. For at opnå et større spænd af værdier bruges derfor i denne opgave en ekstern pull-up resistor på 10K ohm. Ved brug af denne resistor er der en forskel mellem den hvide streg og den mørke baggrund på cirka 200, og det er derfor nemt at sanse banen. Legosensorens indbyggede lys aktiveres ved at give femte pin et high signal.

 

Robottens opbygning

Robotten tager udgangspunkt i overvejelser fra forrige robot Flash Sinatra, såsom vægtfordeling og kompakt konstruktion. Den har ligeledes samme gearing som forrige robot. Der er blevet påmonteret gribearme, som bruges til at holde bolden rundt på banen. Ved brug af gribearme kan bolden trille på gulvet, mens dens position er fikseret af armene. Herved undgås en øget vægt, som ellers ville være tilfældet, hvis den havde båret bolden. De to arme har hvert et tandhjul, som er direkte forbundet til hinanden. På den måde går tandhjulenes retning mod hinanden når de drejer. Det ene tandhjul er forlænget med en stang, hvor endnu et tandhjul sidder, som forbinder den tredje motor med armene vha en kæde. Der er på robotten flere anordninger, som sikrer at tandhjul og motor sidder stabilt, da kæden ellers nemt falder af. Da den tredje motor tager plads der hvor batterierne før var på Flash Sinatra, er der lavet en batteriholder over breadboardet, som er midt på robotten over motor og hjul.

 

Robottens algoritme

Ifølge opgaven skal der bruges to lyssensorer, men der er blevet givet tilladelse til kun at bruge en, hvis dette er tilstrækkeligt for at løse opgaven. For god ordens skyld vil jeg komme med et eksempel på en algoritme til to lyssensorer og den aktuelle algoritme der er brugt til robotten, der som sagt kun har en lyssensor.

 

Eksempel med to lyssensorer

Med to lyssensorer, kan de arrangeres sådan, at de har en afstand svarende til stregens bredde. Med en sådan opstilling vil robotten stå midt på stregen når ingen af de to sensorer opfanger en lys streg. En anden forudsætning er, at de brudte stregerne har et forholdsvist lineært forløb mellem brudne. Derudover er det i eksemplet bestemt, at sensor 1 er på venstre side af robotten og sensor 2 på højre.

Pseudo-koden

Hvis sensor 1 og 2 modtager sort => kør ligeud

Hvis sensor 1 modtager hvidt (stregen) og sensor 2 modtager sort => drej mod højre

Hvis sensor 2 modtager hvidt (stregen) og sensor 1 modtager sort => drej mod højre

 

Udfra denne kode vil robotten holde sig indenfor stregen ved at korrigere ved afvigelser i det lineære forløb. Når robotten når til et af de steder på banen, hvor stregen er brudt, vil den blot fortsætte ligeud indtil den igen rammer stregen. Hvis den rammer stregen lidt skævt, vil den igen kunne korrigere for dette. Dette er dog kun, med denne pseudo-kode, tilfældet, hvis sensor 1 fortsæt er mest mod venstre side af stregen. Hvis det ikke er tilfældet vil robotten vende rundt. Pseudo-koden kræver derfor, at forudsætningerne er opfyldt, samt at robotten kører nogenlunde lige.

 

Den aktuelle algoritme med en lyssensor

I sidste portefølje fungerede algoritmen for robotten Flash Sinatra sådan, at den kørte ligeud, når stregen blev sanset af lyssensoren. Hvis ikke stregen blev sanset drejede robotten skiftevist mod højre og venstre. Problemet ved algoritmen var dog, at robotten ikke drejede lige meget til hver side, og den havde derfor en risiko for at dreje rundt om sig selv. En anden algoritme, som blandt andet blev brugt for robotten Al Zheimer var, at væk fra stregen når stregen blev set, og derefter tilbage mod stregen når robotten var udenfor denne. På den måde vekslede Al Zheimer mellem streg og baggrund. Denne algoritme er ikke nær så påvirkelig i forhold til om begge motorer kører lige godt, og jeg har derfor valgt at tage udgangspunkt i denne. Med denne algoritme vil der uden modificering være problemer når den møder områder hvor stregen er brudt, da den blot vender rundt. For at komme uden om det problem tager jeg udgangspunkt i algoritmens natur – nemlig at den konstant veksler mellem baggrund og streg. Der går ikke lang tid mellem denne vekslen, og der må derfor være en uoverensstemmelse, hvis den bliver i et stadie for lang tid. For denne opgave vil uoverensstemmelsen i hvert fald optræde når robotten når det brudte område. I algoritmen måler robotten derfor hvor lang tid den er i det sorte område, og hvis den er i dette for længe følger den en procedure for at komme tilbage til stregen.

Denne procedure fungerer sådan, at robotten først drejer mod den side af stregen hvor den normalt opholder sig, hvorefter den i en blød bue bevæger sig ind mod stregen igen. Når den møder stregen retter den op, så den ligger lige udenfor stregen på den rigtige side. Herefter fortsætter den dens almindelige cyklus. Hele denne algoritme sættes i gang af et tryk fra første robot i serien. Algoritmen fortsætter indtil der er et tryk foran robotten, som fortæller, at den nu er nået dens destination. Når dette er tilfældet åbner robotten dens arme, som ellers er lukkede under hele den tidligere del af algoritmen, hvorefter den trækker sig tilbage.

Koden

// Sets the current mode
int mode = -1;

void setup() {
  // Motors
  //Setup Channel A
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin

  //Setup Channel B
  pinMode(13, OUTPUT); //Initiates Motor Channel B pin
  pinMode(8, OUTPUT);  //Initiates Brake Channel B pin

  //Setup Channel C
  pinMode(5,OUTPUT); //Forward
  pinMode(6,OUTPUT); //Backward

  // Color sensor  
  pinMode(A3,INPUT);

  // Sets up serial at baud 9600
  Serial.begin(9600);

  // Front arm closes
  runMotorC(50,true);  
}

void loop() {
  // Serial prints the current mode
  Serial.println(mode);

  // Mode switch
  switch(mode) {
    // First mode
    case -1:
        // Checks if front button is pressed. If so, the mode is changed and the robot goes a bit back.
        if(checkFrontButton()){
          mode = 0;
          runMotorA(50,false);
          runMotorB(50,false);
          delay(100);
        }
      break;
    // Second mode    
    case 0:
        runMotorA(50,false); // Turns around from start-position until the robot hits the white line
        runMotorB(50,true);
        if(!isBlack()) {
          breakMotorA();
          breakMotorB();
          mode=1;          
        }        
      break;      
    // Third mode
    case 1:
        normalMode(); // Executes the normal routine
      break;
    // Last mode
    case 2:
        endMode(); // Executes the last routine
      break;
    default:
      break;
  }

}

// Last routine
void endMode() {
  breakMotorA(); // breaks the motors
  breakMotorB();
  runMotorC(50,false); // Opens the arms
  delay(500);
  runMotorA(50,false); // Goes back
  runMotorB(50,false);
  delay(1000); // Stops
  runMotorC(0,true);
  breakMotorA();
  breakMotorB();
  mode=3;  
}

// Normal routine
void normalMode() {
  if(checkFrontButton()){ // If front button is pressed -> goes to last routine
    mode = 2;
  }

  runMotorC(50,true); // Closes the arms
  if(isBlack()) { // if black
    int times = 0; // counter var
    while(isBlack()){ // while the robot is off the line
      if(times<500) { // if it's been off for less than 500 loops it turns towards the line
        runMotorA(0,true);
        runMotorB(100,true); 
      } else { // if it's been off for more than 499 loops it runs the following procedure to get back to the white line
        breakMotorA();
        breakMotorB();
        delay(100);        
        runMotorA(100,true); // it makes a turn away from the line to make sure that the robot is on the right side of the line
        runMotorB(100,false);
        delay(450);
        while(isBlack()){ // afterwards it turns in a soft curve towards the white line
          runMotorA(30,true);
          runMotorB(50,true);
        }
        breakMotorA(); // Stops turning when it hits the line
        breakMotorB();
        delay(100);
        while(!isBlack()){ // Turns away from the line until it is exactly off the line
          runMotorA(30,true);
          runMotorB(30,false);
          delay(1);
        }
        runMotorA(30,true); // It turns a bit more to ensure that the robot can run the normal routine
        runMotorB(30,false);
        delay(100);
        breakMotorA();
        breakMotorB();
        times = 0; // Resets the times var
      }

      times++;
      delay(1); 
    }    
  } else { // If the robot is on the line it turns away from the line
    runMotorA(100,true);
    runMotorB(0,true);
  }

  delay(1);
}

void runMotorC(int speed, boolean forward) {
  if (forward) {
    analogWrite(6,(int) 255*(speed/100.0));
    digitalWrite(5, LOW);    
  } else {
    analogWrite(5,(int) 255*(speed/100.0));    
    digitalWrite(6, LOW);    
  }

}

void breakMotorC() {
  digitalWrite(5, LOW);
  digitalWrite(6,LOW);
}

void runMotorB(int speed, boolean forward) {
  if (forward) {
    digitalWrite(12,HIGH);
  } else {
    digitalWrite(12,LOW);    
  }
  digitalWrite(9,LOW);
  analogWrite(3,(int) 255*(speed/100.0));  
}

void runMotorA(int speed, boolean forward) {
  if (forward) {
    digitalWrite(13,HIGH);
  } else {
    digitalWrite(13,LOW);    
  }
  digitalWrite(8,LOW);
  analogWrite(11,(int) 255*(speed/100.0));  
}
void breakMotorB() {
  digitalWrite(9, HIGH);  //Engage the Brake for Channel A  
}

void breakMotorA() {
  digitalWrite(8, HIGH);  //Engage the Brake for Channel B  
}

boolean isBlack() {
 if (analogRead(A3)>300) {
   return true;
 } else {
   return false;
 }
}

 boolean checkFrontButton() {
   if (analogRead(A5)==0) {
     return true;
   } else {
     return false;
   }
}

 

 

Konklusion

Robotten kan klare banen, og arbejder fint sammen med første og anden robot. Robottens spænding har dog en stor betydning for hvor meget robotten drejer, hvilket kan resultere i, at robotten ikke rammer stregen igen når den er brudt. Derudover er knappen foran robotten lavet af to ledninger, som efter tryk kan forblive forbundet, hvilket får robotten til at tro, at den er nået destinationen. Hvis man kigger på opgaven som et samlet system, er robotterne gensidigt afhængig af hinanden. Opgaven er derfor ikke nødvendigvis løst fordi en eller to robotter i klare deres del af opgaven. Ved den endelige test oplevede vi ofte, at mindst en af robotterne i systemet fejlede, hvilket gik igen i resten af systemet. Det skete dog også flere gange at robotterne spillede fint sammen.

Links, video og billeder kommer..

Leave a Reply