Robotnavn: ロボット

Gruppemedlemmer: Mikkel Andersen, Erik Monsen, Kenneth Christensen og Jakob Vest

Gearing, motorer og konstruktion:

Vi har valgt at bruge larvefødder til vores robot, da det giver et bedre vejgreb end alm. hjul og eliminerer behovet for støtteben eller hjul. Alternativet ville være have at have et minimum af tre kontaktpunkter eller et gyrometer til at balancerer på to kontaktpunkter. Det har gjort at den drejer med en større præcisionsgrad og at den klarede sig godt i vores sideprojekt som var terrænkørsel.
Der er anvendt to gearinger i robotten. Den ene er består af et 8 tands tandhjul på motoren drivaksel til et 24 tands tandhul, den anden gearing består af et 82mm gummihjul der presser ned på larvefoden, der er 32 cm langt.
Gearudvekslingsberegning for tandhjulsgearing: 24 tænder / 8 tænder = 3 = 3:1 gearudveksling.
Gearudvekslingsberegning for gummihjulsgearing: 32 cm / 8.2 cm = 3.9 ≈ 4:1 gearudveksling.
Det giver en samlet gearingsudveksling på 3:1 * 4:1 = 12:1 og derved et højt drejningsmoment og en lav top hastighed.
Begge motorer ligger forskudt, langs kørselsretningen, på hver side af robottens midte. Placeringen af gearingen sørger for at centrer drevhjulene lige over for hinanden, langs robottens midte. Denne opbygning har gjort det muligt at have de mekaniske dele i et lag, og har resulteret i en lav, bred kompakt klods, med et meget lavt tyngdepunkt. Den samlede effekt af dette var at robotten kunne køre op af skråninger på over 45 grader.

Sensor typer og placering

For at kunne detektere stregen blev der brugt to CNY 70 sensor bestående af en infrarød led og en fototransistorsom er placeret tæt ved gulvet foran på robotten, bygget ind i en holder lavet af lego. Disse sidder med et mellemrum på 3 cm, centeret over robottens midte. Der til skulle der bruges nogle udregninger for at bestemme hvilken resistor der var nødvendige til sensorene
R = U/I
R = (Ubb – Uled) / I
R = (5 – 1,6) / 0,05
R = 68Ω
Den udregnede værdi er mindste værdi for at undgå at brande leden af men da det er normalt at bruge en 200Ω resistor til en led diode er det det der blev brugt. Fototransistoren som bruges til at detekter refleksioner skal også bruge en resistor. Denne resistor skal som tommelfinger regel være på 10 til 100KΩ.
Derudover er der en Parallax ping ultrasonic sensor som er placeret foran, hvor den peger fremad og en smule op af for at undgå at opfange jorden.
8 Semester robot

Hardware udfordringer

Der har været nogle udfordringer med at få lavet den rette konstruktion til larvefødderne og et så kompakt design som muligt. Resten af LEGO konstruktionen forløb smertefrit.
Hardware delen af projektet har været tidskrævende da det og noget tid at lodde det hele sammen men da det var gjort så var de ret simple at bruge. Vi valgte at bruge 3x CNY 70 infrarød sensoren til at detektere stregen som vi skulle køre efter. Det virkede også meget godt og den kunne køre rundt på banen uden de store problemer. Der kom dog et lille problem da vi skulle bruge vores ultralydssensor. Da der kun er fire analoge porte til rådighed og vi skulle bruge fem. Dette resulterede i at vi droppede den ene infrarøde sensor. Da vi fik tilsluttet den sidste sensor virkede det som forventet og robotten kunne køre turen og undgå forhindringen. Herefter holdt ultralyds sensoren op med at virke, grunden er ikke helt sikkert men det er meget sandsynligt at det er på grund af en ledende dobbeltklæbende som var skyld i en kortslutning. Ultralyds sensoren blev erklæret død af en underviser og vi fik i stedet udleveret Parallax ping ultrasonic sensoren, som er monteret på den færdig robot.
Vi oplevede til sidst nogle problemer med en kortslutning der påvirkede robottens modtagelse af signal fra de infrarøde sensorer, hvilket resulterede i en falsk positiv i programmeringen og derved en manglende reaktion på detekteringen af tape linjen. Dette blev dog nemt fikset med en smule isoleringstape.

8 sem Fritzing Diagram

Software udfordringer

Programmeringen har været simpel og uden de store problemer. Vi fandt senere ud af at der var en 100ms delay, i rest fre et kodeeksempel, som gjorde at robotten var langsommere, end først antaget, til at se stregen. Dette resulterede i at det var meget mere kompliceret at få et godt resultat, da løsning på dette blev at sænke robottens top hastighed. Resten af udfordringen lå i test og optimering af robotten.

//INIT
//First there is a lot of variables declared to be used later on.
long duration, inches, cm;
int onOff = 1;
int controller = 0;
int leftSpeed= 255; //255 is max speed
int rightSpeed = 255; //255 is max speed
int colSpeed = 50;
char leftOn = HIGH; //High == Off
char rightOn = HIGH; //High == Off
char leftDirection = LOW; //LOW == forward
char rightDirection = LOW; //LOW == forward

int threshold = 70; //Black to white threshold. Black = Tape
int leftSensor = 0;
int rightSensor = 0;
boolean tapeLeft = false;
boolean tapeRight = false;
boolean obstacles = false;

boolean turnedLeft = false;
boolean turnedRight = false;

const int pingPin = 7;

//In the setup we starts the serial to be able to send and receive data.
//Pins to control the motors are also established.
void setup() {
  //Serial.begin(9600);
  Serial.begin(115200);
  //Establish motor direction toggle pins
  pinMode(12, OUTPUT); //CH A -- HIGH = forwards and LOW = backwards???
  pinMode(13, OUTPUT); //CH B -- HIGH = forwards and LOW = backwards???
  //establish motor brake pins
  pinMode(9, OUTPUT); //brake (disable) CH A
  pinMode(8, OUTPUT); //brake (disable) CH B
}
void loop() {
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance and prints it out.
  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);

  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  delay(100);
  //Checks if ther is a obstacle in front of the robot (with in 15-10 cm) an sets a boolean.
  if(cm < 15 && cm > 10 && obstacles == false){
    obstacles = true;
  }
  // If there is a obstacle then the robot runs a preprogrammed route to avoid it.
  if(obstacles == true){
    obstacle();
  }
  //If there is no obstacle the program will try to navigate by the line. 
  if(obstacles == false){
    //onOff = Serial.read();
    if (onOff == 0) {
      leftOn = HIGH;
      rightOn = HIGH;
      // Motor On/Off
      //Right
      digitalWrite(9, rightOn); //ENABLE CH A HIGH = disable
      //Left
      digitalWrite(8, leftOn); //ENABLE CH B HIGH = disable
    }
    if (onOff == 1) {
      //----------------   IR Detectors    -------------------------
      //Read Signal 
      leftSensor = analogRead (A2);
      rightSensor = analogRead (A3);
      //Detect tape - left and sets the boolean
      if (leftSensor <= threshold) {
        tapeLeft = true;
      }
      else {
        tapeLeft = false;
      }
      //Detect tape - right and sets the boolean
      if (rightSensor <= threshold) {
        tapeRight = true;
      }
      else {
        tapeRight = false;
      }
      //----------------   Conditions   -------------------------
      //Here the program checks the booleans to decide what to do next.
      // Ret på tape
      if (tapeLeft == false && tapeRight == false && turnedLeft == false && turnedRight == false) {
        controller = 0;
      }
      //Ingen tape
      if (tapeLeft == false && tapeRight == false) {
        controller = 0;
        turnedLeft = false;
        turnedRight = false;
      }
      if (tapeLeft == false && tapeRight == false && turnedLeft == true && turnedRight == false) {
        controller = 1;
      }
      if (tapeLeft == false && tapeRight == false && turnedLeft == false && turnedRight == true) {
        controller = 2;
      }
      //Tape venstre. Drej højre
      if (tapeLeft == true && tapeRight == false) {
        controller = 3;
        turnedLeft = false;
        turnedRight = true;
      }
      //Tape på højre. Drej venstre
      if (tapeLeft == false && tapeRight == true) {
        controller = 4;
        turnedLeft = true;
        turnedRight = false;
      }

      //----------------   Behaviors    -------------------------
      //When it has decided what to do it then triggers the needed behavior.
      if(controller == 0){ //Frem
        leftOn = LOW;
        rightOn = LOW;
        leftDirection = LOW;
        rightDirection = LOW;
        //colSpeed = 50;
        accelerate();
        leftSpeed = colSpeed;
        rightSpeed = colSpeed;
      }
      if(controller == 1){ // Frem Venstre
        leftOn = LOW;
        rightOn = LOW;
        leftDirection = LOW;
        rightDirection = LOW;
        //colSpeed = 50;
        accelerate();
        leftSpeed = colSpeed;
        rightSpeed = int(colSpeed / 2);
      }
      if(controller == 2){ //Frem Højre
        leftOn = LOW;
        rightOn = LOW;
        leftDirection = LOW;
        rightDirection = LOW;
        //colSpeed = 50;
        accelerate();
        leftSpeed = int(colSpeed / 2);
        rightSpeed = colSpeed;
      }
      if(controller == 3){// Right
        leftOn = LOW;
        rightOn = LOW;
        leftDirection = LOW;
        rightDirection = HIGH;
        colSpeed = 50;
        rightSpeed = 180;
        leftSpeed = 255;
      }
      if(controller == 4){// Left
        leftOn = LOW;
        rightOn = LOW;
        leftDirection = HIGH;
        rightDirection = LOW;
        colSpeed = 50;
        leftSpeed = 180;
        rightSpeed = 255;
      }

      // Sets the speed of the motors and checks that the speed is not over the top speed of (255).
      if (rightSpeed > 255){
        rightSpeed = 255;
      }
      if (rightSpeed <= 255){
        analogWrite(3, rightSpeed); //Moves CH A
      }
      if (leftSpeed > 255){
        leftSpeed = 255;
      }
      if (leftSpeed <= 255) {
        analogWrite(11, leftSpeed); //Moves CH B 
      }
      // Turns motors On/Off
      //Right
      digitalWrite(9, rightOn);
      //Left
      digitalWrite(8, leftOn); 
      //Sends the information to the Motors to set the Direction 
      //Right
      digitalWrite(12, rightDirection); //Sets direction of CH A
      //Left
      digitalWrite(13, leftDirection); //Sets direction of CH B
    }
  }
}

long microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}
//The robot accelerate from 50 to 255 every time it has made a turn to give it a more fluid movement.
void accelerate(){
  if (colSpeed <= 255) {
    colSpeed +=10;
  }
  else if (colSpeed > 255) {
    colSpeed = 255;
  } 
}
//This piece of code makes the robot drive around the obstacle. 
void obstacle(){
  int turn = 1200;
  int strait_start = 1400;
  int strait_finish = 1300;
  int strait_long = 1800;
  digitalWrite(12, LOW);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(300);
  //left
  digitalWrite(12, LOW);    
  digitalWrite(13, HIGH);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(turn);    //vent et sekund
  //Forward
  digitalWrite(12, LOW);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(strait_start);    //vent et sekund
  //Right
  digitalWrite(12, HIGH);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(turn);    //vent et sekund
  //Forward
  digitalWrite(12, LOW);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(strait_long);    //vent et sekund
  //Right
  digitalWrite(12, HIGH);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(turn);    //vent et sekund
  //Forward
  digitalWrite(12, LOW);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(strait_finish);    //vent et sekund
  //left
  digitalWrite(12, LOW);    
  digitalWrite(13, HIGH);
  analogWrite(3, 255);
  analogWrite(11, 255);
  delay(turn);    //vent et sekund
  //Forward
  digitalWrite(12, LOW);    
  digitalWrite(13, LOW);
  analogWrite(3, 255);
  analogWrite(11, 255);
  obstacles = false;
}

Robottens opførsel

Som kan ses på flow diagrammet herunder så var robotten programmeret relativt hierarkisk. Sensor input fra sonaren, og den tilhørende forhindrings undvigelse, tager præcedens over navigationskoden. Grunden til dette var at det var den meste direkte og effektive måde hvorpå vi kunne implementeret undvigelsen af forhindringer. På denne måde ville robotten selv begynde at søge efter tapelinjen efter undvigelsen var færdiggjort. Et “pænere” resultat kunne have været opnået hvis vi satte en timer betingelse på undvigelsen så den kun ville aktiver undvigelsesmanøvren i et bestemt tidsrum, f.eks. mellem 20 – 45 sek. Resultat af dette ville være at et falsk positive input fra sonaren ikke ville start manøvren for tidligt.
8 sem lego_robot

Konklusion

Alt i alt blev opgaven klaret fint. Robotten kørte ruten på ca. 1 minut med 10 gennemgange uden fejl.
Vores robot fik ikke den bedste tid, hvis vi sammenligner med robotternes fra 4. semesters konkurrence. For at vores robot skulle kunne være konkurrencedygtig, på lige fod med deres, ville det kræve en omkonstruktion. Vi havde gearet robotten til en meget høj drejningsmoment, for at kunne køre over objekter og op af skråninger, hvilket selvfølgelig resulterede i en langt lavere tophastighed. Med en højere hastighed ville vi kunne sænkeomgangstiden og give robotten en mere dynamisk korrigering i sving. Det unødvendige stykke delay kode har, med al sandsynlighed, resulterede i at vores robot kørte af sporet flere gange, som vi prøvede at korrigerer for ved at sænke hastigheden. Dette trak også vores omgangstid op. Sidst men ikke mindst så skulle vi havde gentænkt vores undvigelsesmanøvrer. Vi startede med at ville lave den adaptiv, med en ekstra sonar, som kunne måle hvornår man var forbi et objekt og kunne dreje sikkert. Da vi senere gik over til en præprogrammeret rute så overvejede vi ikke om der var en mere tidseffektiv måde at gøre det på. Den bedre løsning ville have været at få robotten til at kører på skrå forbi objektet. Dette ville have elimineret 2 unødvendige sving, og derved give en hurtigere omgangstid.

Leave a Reply