Gruppe Sw00shCar-3000

Josephine Plass-Nielsen, Bjørn Hansen, Oliver Nielsen og Michael Holton

16. maj 2018

 

Porteføljeopgave 2

Hardware og Robotteknologi

Gruppen har fået til opgave at bygge en bil, som skal gennemføre en bestemt bane helt automatisk uden hjælp.

Banen, som bilen skal igennem, ser således ud:

Den sorte streg, som er markeret igennem halvdelen af banen, er linjen, som bilen skal følge. Måden, hvorpå bilen gør dette, er via to “line-follow”-sensorer, som sidder foran på bilen og en sonar-sensor, der sidder på siden.. Til sidst i forløbet vil der blive afholdt en konkurrence om, hvilken bil, der hurtigst og mest fejlfrit kan manøvre sig igennem banen.

Opbygning af Sw00shCar-3000

Bilen er opbygget af LEGO brikker. Bilen har et hjul på hver side, samt et støttehjul i midten. Begge hjul i siderne er tilkoblet en DC-Motor. Helt fremme på bilen sidder en form for kofanger, hvor de to line-follow sensorer er tilkoblet forneden. Øverst på bilen er der bygget en platform, så der er plads til “breadboard”, batterier og Arduino.  

Platformen giver bilen en stabil ligevægt og opbygning, mens de to line-follow sensorer er så tæt på jorden som muligt. Gruppen har forsøgt at gøre bilen så let som muligt, da bilen skal kunne komme igennem banen med fire 1,2 Volts batterier (4,8V i alt).
Gruppen har valgt at sætte en sonar-sensor på højre side af bilen, hvilket giver gruppen mulighed for at opfange lydbølge fra muren, så man ved hvor tæt på muren bilen er og hvornår den skal dreje. Det er vigtigt at bilen køre lige ved siden af muren med en ret vinkel så ehco-porten får sit input korrekt og trigger-porten få sit output korrekt, ellers kan bilen komme ud af kurs. Derudover skal sonaren være stabil (den er sat fast med tape og elastik) på bilen, for ellers kan programmet ikke indlæse distancen mellem muren og bilen.

Bilens Hardware
Bilen er blevet bygget til at fremstå så simpel som muligt. Følgende komponenter er blevet anvendt:

  • Arduino Microcontroller
  • Arduino Motor-Shield
  • 4x AA-Batterier 1,2V
  • 2x Line-follow sensor
  • Ledninger
  • 2x DC-Motor
  • Switch Knap (ON-OFF)
  • Sonar-sensor

 

Arduino-controlleren bruges til at modtage analog-input fra de forskellige sensorer, som skal korrigere bilens retning, når den kører på banen. Når de to sensorer bliver påvirket tilstrækkeligt, vil det medføre, at enten den ene eller den anden motor, som sidder på siden af bilen, kører baglæns, så robotbilen kan dreje. Hertil bruges et motor-shield, som hjælper arduino-microcontrolleren med at omforme de to DC-motorer. Slutteligt vil de to linefollow-sensorer ramme den vandrette, sorte streg på samme tid, hvilket er afgørende for aktivere ‘part 2’ i koden, som aktiverer og behandler input fra sonar-sensoren.

Sonar-sensoren er til for at hjælpe med at korrigere bilen, når den skal køre forbi muren. Sonar-sensoren sidder ude på højre side af bilen, så den ved hjælp af lydbølger kan give information om afstanden, imens bilen kører langs muren.

Switch-knappen bruges til at tænde og slukke kredsløbet.

Bilens Opførsel

Når man tænder på switch-knappen, vil kredsløbet blive aktiveret og starte de to DC-Motorer. Bilens standard udgangspunkt er, at den kører fremad såfremt, at  linefollow-sensorerne ikke opfanger data om “mørke”. Sensorerne skal sørge for, at de to DC-motorer kører henholdsvis forlæns og baglæns, så bilen kan dreje skarpt nok og dermed korrigere efter den sorte streg. Bilen vil køre gennem første del af banen med linjen indtil begge sensorer kører over en vandret sort streg, der aktiverer, at bilen skal dreje til venstre. Herefter vil bilens sonar-sensor overtage styringen. Sonar-sensoren hjælper bilen med at korrigere langs med væggen og drejer bilen til højre, når muren ender, og kører det sidste stykke i mål stadig med hjælp af sonar-sensoren.

Herunder ses et flow-diagram, der viser bilens opførsel:

Som det fremgår af flow-diagrammet, så har bilen to faser. Den første fase, hvor der bliver lyttet efter input fra line-follow sensorerne. Og den anden, hvor der bliver lyttet efter input fra sonar sensoren. Denne opbygning gør, at bilen ikke skal bruge unødig energi og processorkraft, på at lytte efter input, hvor det ikke er relevant. Det sikrer også, at bilen ikke bliver påvirket af fysiske objekter under første forløb, hvor den kun skal følge en linje. Og i andet forløb, bliver bilen ikke påvirket af at køre uden for banen, og dermed potentielt opfange data fra gulvets mørke farve.

Bilens kredsløb

Robottens kredsløb er forsøgt gengivet i programmet fritzing. Komponenterne brugt til tegningen passer stort set overens med hardware-listen, pånær linefollow-sensorerne, der ikke var mulige at finde i programmet. Derfor er disse symboliseret ved en infrarød diode og en photoresister. Disse kan også bruges som en linefollow-sensor, da denne slags blot sender (infrarødt) lys ud og tjekker i hvilken grad, at lysbølgerne kommer tilbage igen.
I virkeligheden har gruppen dog brugt rigtige linefollow-sensorer. Gruppen har valgt at bruge et motor shield, så der nemt kunne tilføjes to DC-motorer i kredsløbet.

Gruppen har brugt et breadboard til at forbinde sensorer og aktuatorer til strømforsyning og jordforbindelse, og til Arduinoen. På Arduinoen bruger vi to analoge porte til de to linefollow-sensorer, to digitale porte til sonar-sensoren (echo-porten er tilsluttet en port med PWM signal), 5V og GND strøm og jord fra batteriet. Forbindelsen mellem batteriet og resten af kredsløbet er afbrudt af en switch, således at der kan tændes og slukkes for strømmen.   

 

 

Kodebeskrivelse

//Motor A
int Motor_A_Dir = 12;
int Motor_A_Speed = 3;
int Motor_A_Brake = 9;

//Motor B
int Motor_B_Dir = 13;
int Motor_B_Speed = 11;
int Motor_B_Brake = 8;

// Line follower sensor
int A_speed = 185;
int B_speed = 195;
int leftSensor = 4;
int rightSensor = 5;
int leftInput = 0;
int rightInput = 0;
int left = 0;
int right = 0;
int thresh = 500;

//Ultra Sonic Sensor
const int echo = 6;
const int trigger = 7;

// defines variables
long duration;
int distance;

bool part2 = false;
bool corner = false;

void setup() {
  Serial.begin(9600);
  //Motor setup
  pinMode(Motor_A_Dir, OUTPUT);
  pinMode(Motor_A_Brake, OUTPUT);
  pinMode(Motor_B_Dir, OUTPUT);
  pinMode(Motor_B_Brake, OUTPUT);
  // Ultra Sonic sensor setup
  pinMode(trigger, OUTPUT); // Sets the Trigger pin as an Output
  pinMode(echo, INPUT); // Sets the Echo pin as an Input
}

void loop() {
  
  //ULTRA KILL
  // Clears the trigPin
  digitalWrite(trigger, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echo, HIGH);
  // Calculating the distance in cm
  distance = duration * 0.034 / 2;
  // Prints the distance on the Serial Monitor
  Serial.print("Distance: ");
  Serial.println(distance);


  leftInput = analogRead(leftSensor);
  rightInput = analogRead(rightSensor);
  //left = map(leftInput, 0, 1024, 0, 100);
  //right = map(rightInput, 0, 1024, 0, 100);
  Serial.print("LEFT: ");
  Serial.println(leftInput);
  Serial.print("RIGHT: ");
  Serial.println(rightInput);
  Serial.println(" ");

  if (part2) {
    if (distance < 11) {
      RightMotor();
      delay(100);
      Serial.println("CLOSE CLOSE CLOSE");
    }
    else if (distance >= 11 && (distance < 100 || corner == true))
    {
      LeftMotor();
      delay(100);
      Serial.println("TOO CLOSE, TOO CLOSE, TOO CLOSE");
    }
    else if (distance >= 100 && corner == false) {
      BothMotor();
      delay(400);
      Serial.println("CORNER CORNER CORNER");
      corner = true;
    }
  } else {

    if (leftInput > thresh && rightInput < thresh) {
      RightMotor();
      delay(100);
      Serial.println("LEFT LEFT LEFT");
    }
    else if (rightInput > thresh && leftInput < thresh) {
      LeftMotor();
      Serial.println("RIGHT RIGHT RIGHT");
      delay(100);
    }
    else if (leftInput < thresh && rightInput < thresh) {
      BothMotor();
      Serial.println("BOTH BOTH BOTH");
    }
    else if (leftInput > thresh && rightInput > thresh)
    {
      BothMotor();
      delay(1350);
      A_speed = 200;
      B_speed = 165;
      RightMotor();
      delay(1650);
      part2 = true;
    }
  }
}


void BothMotor() {
  digitalWrite(Motor_A_Dir, HIGH);
  digitalWrite(Motor_A_Brake, LOW);
  analogWrite(Motor_A_Speed, A_speed);

  digitalWrite(Motor_B_Dir, HIGH);
  digitalWrite(Motor_B_Brake, LOW);
  analogWrite(Motor_B_Speed, B_speed);
}
void StopMotor() {
  A_speed = 0;
  B_speed = 0;
  digitalWrite(Motor_A_Dir, HIGH);
  digitalWrite(Motor_A_Brake, HIGH);
  analogWrite(Motor_A_Speed, A_speed);

  digitalWrite(Motor_B_Dir, HIGH);
  digitalWrite(Motor_B_Brake, HIGH);
  analogWrite(Motor_B_Speed, B_speed);
}


void LeftMotor() {
  if (part2) {
    digitalWrite(Motor_A_Dir, HIGH);
    digitalWrite(Motor_A_Brake, HIGH);
    analogWrite(Motor_A_Speed, 0);
    B_speed = 200;
  } else {
    digitalWrite(Motor_A_Dir, LOW);
    digitalWrite(Motor_A_Brake, HIGH);
    analogWrite(Motor_A_Speed, 115);
  }

  digitalWrite(Motor_B_Dir, HIGH);
  digitalWrite(Motor_B_Brake, LOW);
  analogWrite(Motor_B_Speed, B_speed);
}


void RightMotor() {
  if (part2) {
    digitalWrite(Motor_B_Dir, HIGH);
    digitalWrite(Motor_B_Brake, HIGH);
    analogWrite(Motor_B_Speed, 0);
    A_speed = 255;
  } else {
    digitalWrite(Motor_B_Dir, LOW);
    digitalWrite(Motor_B_Brake, HIGH);
    analogWrite(Motor_B_Speed, 115);
  }

  digitalWrite(Motor_A_Dir, HIGH);
  digitalWrite(Motor_A_Brake, LOW);
  analogWrite(Motor_A_Speed, A_speed);
}

Programmet starter med at definere en række variabler. Disse variabler fortæller henholdsvis hvilke digitale og analoge porte, der bliver anvendt på Arduinoen. Både til de to DC-motorer, der er koblet til Arduino Motorshield’et, og sensorerne (linefollow og sonar).

Derudover anvendes også variabler til at styre hastigheden af højre og venstre motor. Fordelen ved at definere variabler for hastigheden er, at de nemt kan justeres for hver køretest der foretages. Dette gjorde arbejdet langt mere flydende, da der blev foretaget en del køretest, samt redigeringer i hastigheden. Det blev også opdaget, at de to motorer ikke kørte lige hurtigt, hvilket gav nogle udfordringer i de forskellige sving på banen. Variablerne for motorens hastighed kunne derfor justeres individuelt. Der er også defineret en variabel for grænsen, hvor linefollow-sensorerne skulle igangsætte en funktion. Det gjorde også det iterative arbejde nemmere, da der nemt kunne justeres på denne værdi. Til sidst defineres to boolean værdier. En “part2” der fortæller, om bilen kører i første del af banen eller anden del. Og en “corner”, der fortæller, om bilen er ved at dreje om hjørnet, rundt om væggen i anden del af banen.

Herefter køres metoden “setup”, der definerer, om de digitale porte i Arduinoen bliver brugt til “input” eller “output”.  

“loop” funktionen er den, der kører hoveddelen af programmet. Her startes der med at blive hentet input fra den soniske sensor, og linefollow-sensorerne. Derefter tjekkes det, om bilen er i første eller anden del af banen, ved hjælp af boolean værdien “part2”. Hvis bilen er i første del, så lytter linefollow-sensorerne efter input, og drejer bilens motorer, alt efter hvilken sensor, der får højt input. For at dreje motorerne, er der blevet defineret en metode for hver funktionalitet henholdsvis venstre sving, højre sving og kør ligeud. Metoderne påvirker både den venstre og den højre motor, ved at ændre på retningen og hastigheden således, at når bilen skal dreje til venstre, så kører højre motor fremad, og venstre motor kører baglæns med en lavere hastighed – omvendt når, den drejer mod højre.

Når bilen rammer en sort lige streg, påbegyndes en “hardcoded” køresekvens. Her kører bilen ligeud i et bestemt stykke tid, før den drejer mod venstre i et bestemt stykke tid. Hvorefter boolean værdien “part2” sættes til sand, og bilen kan nu gå ind i anden fase af programmet, hvor der lyttes efter input fra den soniske sensor. Denne del af koden minder meget om første del, bortset fra, at det er nogle andre grænseværdier, der arbejdes med, før bilen skal dreje til en side. Når bilen ikke længere opfanger en væg, vil den køre ligeud i et kort stykke tid og sætte boolean værdien “corner” til at være sand. Dette betyder, at bilen nu er igang med at dreje om hjørnet rundt om væggen. Så selvom bilen ikke længere opfanger en væg ved siden af sig, så skal den altså ikke køre ligeud igen, men fortsætte med at dreje så længe input værdien er over 11.     

Samspillet mellem elektronik, mekanik og software

I dette projekt er der blevet lagt meget arbejde i samspillet mellem elektronik, mekanik og software, da det alle er parametre der kan ændres på, for at optimere bilens opførsel. Gruppen startede projektet med at der bygge en bilkonstruktion, imens der blev arbejdet med sensorere og aktuatorere ved siden af. Siden har der måtte foretages en del iterationer og ændringer i både design og programmering. I det første design, fandt gruppen ud af, at bilens konstruktion var for tung til at kunne drives af to LEGO motorer. Selvom der blev arbejdet med at bilens software, kunne motorerne ikke dreje kraftigt nok, til at drive konstruktionen. Gruppen diskuterede muligheden for, at geare motoren ned, hvilket ville medføre en hurtigere rotation. Men dette ville stadig ikke påvirke trækkraften, som var den betydende faktor her. Samspillet mellem mekanikkens vægt og elektronikkens kraft, var altså her ret betydelig. Senere havde bilen problemer med at komme rundt i svingene, da den ikke kunne dreje skarpt nok, og i visse tilfælde drejede bilen for skarpt og kørte derfor ud over banen. Her var det et samspil både mellem elektronik, mekanik og software, i den forstand, at bilens hastighed kunne justeres gennem software, men i visse tilfælde kom bilen ind i en alt for skarp vinkel der gjorde, at uanset hvad så kørte den af banen. Her måtte en omkonstruktion af mekanikken til, for at ændre på bilens kørebane i svingene. Og på det punkt i banen hvor bilen skal læse input fra en lige sort streg, krævede det en ændring i elektronikkens placering, for at sensorerne kunne opfange data.  

 

Bilen i aktion

Til undervisningstimerne i Hardware og Robotteknologi, skulle bilen til dens endelige eksamen. Her skulle gruppen vise, at bilen var bygget og programmeret korrekt, så den kunne gennemføre den tidligere anviste bane. Gruppen havde tre forsøg af tre minutter pr. gang til at få bilen igennem. Det lykkedes bilen at gennemføre banen på første forsøg uden fejl. Bilens gennemførelsestid lød på 37,6 sekunder, hvilke rakte til den tredje bedste tid blandt alle fremmødte grupper. Herefter prøvede gruppen at slå egen rekord ved at optimere bilens fart. Dette resulterede desværre i, at bilen ikke kunne gennemføre i højere fart grundet afkørsel af banen og derfor blev forsøg nummer to og tre sat til de maksimale 180 sekunder.
Det vigtigste var dog, at bilen kom igennem banen, og det gjorde den uden fejl. Der er vedhæftet en videofil, hvor man kan se, at bilen gennemfører banen.   

Konklusion

Det kan hermed konkluderes, at gruppens robotbil har løst opgaven (som var, at køre igennem banen ved hjælp af sensorere) på tilfredsstillende vis. Robotbilen kom, ved hjælp af de to linefollow-sensorer og en sonar-sensor, igennem banen på tiden 37,6 sekunder og fik dermed en tredjeplads i konkurrencen.

 

Perspektivering

Hvad kunne have været gjort bedre?

Hvis man havde benyttet 3 linefollow-sensorer i stedet for 2, ville bilen muligvis køre mere stabilt på banen, da man ville have haft 3 til at kontrollere med i stedet for 2. Med 2 sensorer kører bilen lidt stift og ustabilt og kan derfor godt lave fejl, som ødelægger dens gennemførelse af banen.

Kunne LEGO bilen bygges bedre?

Selve designet kunne selvfølgelig have været bedre, men da der var mange grupper, som var aktive på samme tid, så var det en med betydende faktor, at mange af de ‘gode’ legokomponenter allerede var i brug.
Første design af bilen gjorde brug af et stort hjul i midten af bilen samt en motor på hver side af hjulet, hvortil der sad et mindre hjul fast på hver side. Forrest var der også et lille hjul til balance. Problemet med det første design var, at bilen blev for tung grundet det store hjul og DC-motorerne havde dermed svært ved at trække robotbilen frem i svingene på første del af banen.
På grund af dette fik bilen sit andet design, som i højere grad skulle tage hensyn til, hvor meget vægt motorerne kunne trække. Dette design bestod af to mindre hjul, som hver var tilknyttet en DC-motor og i mellem motorerne var der en mindre legoplatform, hvor arduino, breadboard og batterierne kunne ligge på. Foran hjulene gik to legobjælke(aflange stænger) samt en på tværs, som bærende element for et hjul, og længere fremme de to sensorer. Desværre oplevede gruppen efter ombygningen, at kofangeren på fronten af denne udgave var ustabil og rystede derfor sensorerne ud af kurs. Derfor blev forparten af robotten bygget mere robust, og således fik robotbilen sit tredje og endelige design, som kunne tage hensyn til begge dele. Alligevel var der adskillige tiltag, som kunne have været fordelagtigt i forhold til designet. Heriblandt kan det nævnes, at såfremt det havde været muligt at fremskaffe lidt større hjul, var det måske muligt for robotten at køre hurtigere. Ligeledes havde det også været fordel, hvis linefollow-sensorerne var blevet sat mere ind i centrum af bilen, så robotten havde nemmere ved at dreje.

Kunne kredsløbet være mere effektivt?

Gruppen har umiddelbart ikke nogle ideer til, hvordan kredsløbet kunne have været mere effektivt. Det havde været en mulighed at benytte sig af flere batterier( flere volt) for, at bilen kunne køre hurtigere – men så skulle koden og designet justeres i forhold til dette.

Kunne koden skrives anderledes?

Man kunne have programmeret bilen til at køre mere uforhindret gennem den første del af banen ved at justere yderligere på motorernes hastigheder, samt sensorernes grænseværdier for, hvornår aktuatorerne skulle aktiveres. Det ville betyde, at bilen ikke hele tiden skulle korrigere fra side til side for at følge linjen. Derudover kunne der optimeres i koden, ved at fjerne kode-gentagelser (der, hvor det ikke har nogen betydning) samt udskrifter til serie monitoren. Den største ændring/forbedring, der kunne foretages, var, at vente med at læse input fra sensorerne til der, hvor det skal bruges. Som koden ser ud nu, bliver der læst sensorværdier som det allerførste, før der tjekkes, om vi er i første eller anden del af banen, altså før programmet ved, hvilken type input,  der skal anvendes.

Leave a Reply