Gruppemedlemmer: Daniel Rose, Nicolai Staal Hansen, Phillip Larsen, Simone Emma Pedersen, Maria Dyremose og Gustav Frank Larsen

Bedste tid: 22,44 sekunder på video ovenover og 180 sekunder ved konkurrencen.

Indledning;

Vi fik til opgave at kreere en robot, med funktionalitet som en bil. Denne robot har til opgave at gennemfører en bane, bestående af sorte striber, røde striber, samt en væg lavet af DUPLO-klodser. Nedenstående billede viser banen. Kravet til projektet var, at robotten skulle kunne gennemføre banen – der var altså ikke krav til, hvilke komponenter der skulle bruges. Robotten skal til at starte med følge den sorte streg rundt i svingene, indtil den kommer til den tværgående streg. Robotten møder nu en væg som den skal undvige, efterfulgt af en u-vending for at komme om på den anden side af væggen og nå målstregen. Det er ikke tilladt for bilen at ramme de røde striber. Til sidst i forløbet blev der afholdt et væddeløb, hvor de forskellige robotbiler dystede mod hinanden om at gennemføre banen på kortest tid.

Hardware og kredsløbet:

Til at løse opgaven er der til hardwaren anvendt en Arduino, et Arduino Motor Shield Rev3, to LEGO-Mindstorms-motorer, to IR-sensorer (infrarød udleder og modtager), en piezo-sensor (vibration) og en ultrasonic-sensor (distance).

Det anvendte Motor Shield gør det muligt, at køre begge motorer i to retninger fra dets A og B-udgange.

IR-sensorer har tre funktioner: udlede infrarødt lys, modtage infrarødt lys og sende informationerne til tilkoblede microcontroller. De bruges for at løse opgaven med at følge linien, ved at det infrarøde lys reflekteres bedre til modtageren, når sensoren befinder sig over lyst materiale og modsat. IR-sensorerne er placeret i GND, 5V og henholdsvis A0 og A1 i Arduinoen.

Piezo-sensoren reagere på rystelser, tryk m.m.. De ændringer for sensoren til at producere en elektrisk ladning som kan måles. Sensoren er brugt i forbindelse med opgavens andet stadie, hvor køretøjet skal navigerer rundt om en mur. Den er placeret i A3 og GND.

Ultrasonic-sensoren har et output, der sender en bestemt lydfrekvens, og et input, der lytter efter lydfrekvensen. På den måde kan sensoren måle distancen til forskellige objekter. Denne gør det muligt at navigere rundt om muren. Anvendte sensor er placeret i boardets digitale ”pins” 7 og 8 samt 5V og GND.

Konstruktion af robotten:

Robottens ydre er konstrueret primært af LEGO System-klodser, med enkelte LEGO Technic-detaljer. Størstedelen af robottens LEGO-korpus udgøres af en platform, som er sammensat af flere separate 1×8- og 2×8-plader, som er sat på tværs af hinanden for at opnå maksimal robusthed og stabilitet. På denne platform finder man den samlede hardware – en arduino, et Motor Shield og en batteriboks – samt de to Mindstorms-motorer, som sætter robotten i bevægelse. Hardware-komponenterne holdes på plads ved hjælp af et par vægge i siderne af platformen, som er bygget af System-klodser, der forstærkes af ekstra brede Technic-beams. De er desuden sikret med et sikkerhedssele-system, der er konstrueret af flere Technic-tubes, som strækker sig fra robottens forende til dens bagende.

Disse tubes blev taget i brug, da motorernes mangel på hestekræfter nødvendiggjorde en omstrukturering af hardware-komponenternes placering på platformen. Platformen selv blev da også ombygget, formindsket og berøvet en masse kosmetiske detaljer, for at gøre den samlede konstruktion lettere. De turkise tubes er ideelle til at holde komponenterne på plads, eftersom de både er utroligt lette (de er hule indvendigt), meget holdbare (takket være forbindelsen via sorte Technic-pins, som har mere friktion end lysegrå Technic-pins), OG tilgivende overfor rystelser og stød (grundet den samme fleksibilitet, der gør, at højhuse ikke vælter). De gav derudover mulighed for at tilføje et yderst personligt præg til bilen i form af et par øjne på stilke.

Robotten kører ved brug af to store Technic-hjul, der er dobbelt så brede som regulære Technic-hjul af denne størrelse. Da motorerne som tidligere nævnt var forholdsvis svage, blev alle simple mekaniske funktioner (gearing, snekker osv) fjernet fra robotten, for ikke at belaste motorerne med mere friktion end nødvendigt. De er således direkte forbundet til hjulenes akser, og roterer dem uden brug af tandhjul. Selvfølgelig er et tredje berøringspunkt med jorden uundværlig for robottens balance – i en tidlig prototype af robotten var dette en klods, der udelukkende havde nopper på oversiden, men var afrundet på undersiden. Denne løsning viste sig dog allerede at være for stor en udfordring for motorerne, så den blev erstattet af en lille Technic-konstruktion, der ved hjælp af to Bohrok Va-arme ”trækker” et lille hjul efter sig – lidt ligesom på en kuffert, hvor hjulene også kan tilpasse sig den retning, den nu bliver trukket i. Rotationen langs den vertikale akse muliggøres ved hjælp af en lille Technic-aksel, der er løst monteret i en af platformens bundplader.

Nedenunder kan et zip fil til byggevejledning af robotten findes (bygget i LEGO digital designer):

https://drive.google.com/file/d/1nWx2klwGWqw1XErvo0LcwGgZ3pgOH_4k/view?usp=sharing

Software og arduino:

Gruppens opgave var at læse input fra flere sensorer – i vores tilfælde uafhængigt af hinanden – da robotten først skulle læse input fra to IR-sensorer, dernæst læse input fra en knock-sensor og til sidst fra en ultrasonic-sensor. I programmeringsforløbet blev denne opgave løst, ved at opdele de forskellige adfærdssekvenser i hver deres sketch. På den måde kunne gruppen teste hver enkelt adfærd uafhængigt af en anden adfærd på banen. Det nedenstående billede viser de separate sketches:

Gruppen har forsøgt at gøre brug af Brooks’ koncept om layer-baserede kontrolsystemer. Brooks lægger vægt på, at adfærd kan deles op i forskellige layers, hvor et layer simpelthen placeres oven på det foregående, bygger videre på det og derved udvider robottens generelle evnesæt – men aldrig forandrer et tidligere layer, eftersom dette bør fungere fejlfrit i sig selv.

Robottens adfærd skal dog ikke blot udvides, jo længere den kommer i banen. På bestemte tidspunkter skal den nemlig kunne ignorere den information, den modtager via nogle enkelte sensorer – det vil sige, at tidligere layers (midlertidigt) skal sættes ud af kraft. Eksempelvis skal IR-sensorerne holde op med at tage input, for at robotten kan passere den tværgående linje på banen, så her var det ikke tilstrækkeligt at udbygge sensorernes funktionalitet, eller dette ”layers” ansvarsområde – tværtimod skulle IR-sensorerne her overgive styringen til nogle af de andre layers.

Da robotten kunne alternere mellem de forskellige sensorer og adfærdssekvenser – og kombinere dem til den ønskede, samlede adfærd – blev koderne sat sammen til en stor sketch.

Programmering og kode-highlights:

//SimpleTimer library
#include <SimpleTimer.h>
// the timer object
SimpleTimer timer;
// defines analog sensor input
int linesensor0  = A0;
int linesensor1 = A1;
int knocksensor = A4;
// defines pins numbers
const int trigPin = 7;
const int echoPin = 8;

int sort;
int hvid;
int difference; 
long duration;
int distance;
int blackandwhite;
int knocksensor1;
int antalknock = 0;
boolean fikdubank = false;
boolean distance1 = false;


// a function to be executed periodically
void repeatMe() {
     Serial.print("Uptime (s): ");
     Serial.println(millis() / 1000);
  
    //Motor A forward @ full speed
    digitalWrite(12, HIGH);  //Establishes forward direction of Channel A
    digitalWrite(9, LOW);   //Disengage the Brake for Channel A
    analogWrite(3, 200);    //Spins the motor on Channel A at 200
    
    //Motor B backward @ lower speed
    digitalWrite(13, HIGH); //Establishes forward direction of Channel B
    digitalWrite(8, LOW);   //Engage the Brake for Channel B
    analogWrite(11, 200);   //Spins the motor on Channel B at 200
  
    Serial.println("hej Gamle");
    
    delay(1300);
  
    } 

void setup() {
    Serial.begin(9600);
  
     // timer interval (11 seconds)
    timer.setInterval(11000, repeatMe); 
    
    //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 A pin
    pinMode(8, OUTPUT);  //Initiates Brake Channel A pin
  
    //Setup Ultra Sonic sensor 
    pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
    pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  
}
 
void loop(){

    //locale variables 
    sort = analogRead(linesensor0);
    hvid = analogRead(linesensor1); 
    knocksensor1 = analogRead(knocksensor);
    difference = sort-hvid;
    blackandwhite = sort+hvid;
  
     //fikdubank boolean sættes til true
    if (knocksensor1 > 300) {
      fikdubank = true;
    }
    
    //Running timer 
     timer.run();
 
  //Hvis differencen mellem de to LDR sensorer er mellem -2 og 2 kører bilen ligeud
  if (difference>-2 && difference < 2 && distance1 == false){

           //Motor A forward @ full speed
      digitalWrite(12, HIGH);  //Establishes forward direction of Channel A
      digitalWrite(9, LOW);   //Disengage the Brake for Channel A
      analogWrite(3, 255);    //Spins the motor on Channel A at full speed
      
      //Motor B backward @ full speed
      digitalWrite(13, HIGH); //Establishes forward direction of Channel B
      digitalWrite(8, LOW);   //Engage the Brake for Channel B
      analogWrite(11, 255);   //Spins the motor on Channel B at full speed
    
      //Hvis differencen er større mindre end -2 kører bilen til venstre
        } else if (difference < -2 && distance1 == false ) {
    
       //Motor A backward @ full speed
      digitalWrite(12, HIGH);  //Establishes forward direction of Channel A
      digitalWrite(9, LOW);   //Engage the Brake for Channel A
      analogWrite(3, 255);    //Spins the motor on Channel A at full speed
      
      //Motor B forward @ lower speed
      digitalWrite(13, HIGH); //Establishes forward direction of Channel B
      digitalWrite(8, LOW);   //Disengage the Brake for Channel B
      analogWrite(11, 10);   //Spins the motor on Channel B at 10
      
      //Hvis differencen er større mere end 2 kører bilen mod højre
      } else if (difference > 2 && distance1 == false) {
    
       //Motor A forward @ lower speed
      digitalWrite(12, HIGH);  //Establishes backward direction of Channel A
      digitalWrite(9, LOW);   //Disengage the Brake for Channel A
      analogWrite(3, 10);    //Spins the motor on Channel A at 10
      
      //Motor B backward @ full speed
      digitalWrite(13, HIGH); //Establishes forward direction of Channel B
      digitalWrite(8, LOW);   //Engage the Brake for Channel B
      analogWrite(11, 255);   //Spins the motor on Channel B at full speed

  } 
 

  
//Når knocksensorens input er over 300 begynder bilen at dreje til venstre
if (knocksensor1 > 300 && distance1 == false) {

      //Motor A backward @ full speed
      digitalWrite(12, HIGH);  //Establishes backward direction of Channel A
      digitalWrite(9, LOW);   //Engage the Brake for Channel A
      analogWrite(3, 250);    //Spins the motor on Channel A at 250
      
      //Motor B forward @ full speed
      digitalWrite(13, LOW); //Establishes backward direction of Channel B
      digitalWrite(8, LOW);   //Disengage the Brake for Channel B
      analogWrite(11, 150);   //Spins the motor on Channel B at 150
    
      // bilen drejer i 0.75 sek
      delay(750);
    
      //distance boolean sættes til true
      distance1 = true;
    
      //antalknock værdien plusses med 1
      antalknock++;



 } 

  //Backup-knock-sensor, hvis bilen kører ind i muren efter svinget omkring muren. 
 if (knocksensor1 > 300 && antalknock == 2) {

      distance1 = false;
    
      //Motor A backward @ lower speed
      digitalWrite(12, LOW);  //Establishes backward direction of Channel A
      digitalWrite(9, LOW);   //Engage the Brake for Channel A
      analogWrite(3, 250);    //Spins the motor on Channel A at no speed
      
      //Motor B forward @ full speed
      digitalWrite(13, HIGH); //Establishes backward direction of Channel B
      digitalWrite(8, LOW);   //Disengage the Brake for Channel B
      analogWrite(11, 250);   //Spins the motor on Channel B at full speed
    
      
      //Bilen drejer til venstre i 0.75 sek
      delay(750);
    
      //distance1 boolean sættes til true
      distance1 = true;

 } 

//Dette if-statement der forudsætter at distance1 boolean er true - dette gør sig gældende når knocksensoren er over 300.
if (distance1 == true) {
         // Clears the trigPin
        digitalWrite(trigPin, LOW);
        delayMicroseconds(2);
        // Sets the trigPin on HIGH state for 10 micro seconds
        digitalWrite(trigPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPin, LOW);
        // Reads the echoPin, returns the sound wave travel time in microseconds
        duration = pulseIn(echoPin, HIGH);
        // Calculating the distance
        distance= duration*0.034/2;
        // Prints the distance on the Serial Monitor
        Serial.print("Distance: ");
        Serial.println(distance);
        
                //Når afstanden er lig med 7 cm kører bilen ligeud
                if (distance == 7 ) {

                       //Motor A backward @ lower speed
                    digitalWrite(12, HIGH);  //Establishes forward direction of Channel A
                    digitalWrite(9, LOW);   //Engage the Brake for Channel A
                    analogWrite(3, 200);    //Spins the motor on Channel A at 200 speed
                    
                    //Motor B forward @ full speed
                    digitalWrite(13, HIGH); //Establishes forward direction of Channel B
                    //digitalWrite(8, LOW);   //Disengage the Brake for Channel B
                    analogWrite(11, 200);   //Spins the motor on Channel B at 200 speed
                   
                   
                 //Når afstanden er større end 7 kører bilen mod højre
                 } else if (distance > 7) {
        
                      //Motor A backward @ lower speed
                      digitalWrite(12, HIGH);  //Establishes forward direction of Channel A
                      digitalWrite(9, LOW);   //Engage the Brake for Channel A
                      analogWrite(3, 50);    //Spins the motor on Channel A at 50 speed
                      
                      //Motor B forward @ full speed
                      digitalWrite(13, HIGH); //Establishes forward direction of Channel B
                      //digitalWrite(8, LOW);   //Disengage the Brake for Channel B
                      analogWrite(11, 220);   //Spins the motor on Channel B at full 220 speed

                  //Når afstanden er mindre end 7 kører bilen mod venstre 
                  } else if (distance < 7) {

                         //Motor A backward @ lower speed
                        digitalWrite(12, HIGH);  //Establishes backward direction of Channel A
                        digitalWrite(9, LOW);   //Engage the Brake for Channel A
                        analogWrite(3, 220);    //Spins the motor on Channel A at no speed
                        
                        //Motor B forward @ full speed
                        digitalWrite(13, HIGH); //Establishes forward direction of Channel B
                       // digitalWrite(8, LOW);   //Disengage the Brake for Channel B
                        analogWrite(11, 50);   //Spins the motor on Channel B at full speed 
                        
                  }
             }
        }

Den nedenstående kode muliggør robottens første adfærd, der består i at følge den sorte streg på banen. Dette gøres ved at læse de to IR-sensorers input – der er placeret under robotten – hvorefter der findes en difference mellem de to sensorer. Ligger denne difference mellem 2 og -2 kører robotten ligeud; er differencen mindre end -2 to kører den til venstre; og er difference større end 2 (ses ikke på billedet) kører den til højre. Når robotten kører ligeud, sættes motorernes retning til at dreje forlæns med maksimal hastighed (255). Er differencen mellem de to sensorer for stor, vil den motor, der sidder i den side robotten drejer mod, dreje med nedsat tempo (10) – den anden motor forbliver uændret.

Der er sat en timer, der får robotten til at køre ligeud, efter den har fulgt den sorte streg i 11 sekunder – denne timer er lavet som en lappeløsning, da IR-sensorerne ikke ville registrere den tværgående sorte streg samtidigt, få samme input og passere den. Derimod registrerede den linjen og fulgte den i en vilkårlig retning, som var det endnu et sving. Et bibliotek kaldet SimpleTimer var nødvendigt for at lave denne timer – til højre på nedenstående billede vises det, hvordan man inkluderer et bibliotek i en sketch og laver et objekt af dette bibliotek.

Efter at have lavet en instans af timer-objektet kan dets metoder benyttes.

I ovenstående kode laves der en ny funktion kaldet repeatMe() – denne funktion kaldes efter 11 sekunder, da robotten efter dette tidsinterval befinder sig på den sidste del af den sorte streg.  Tidsintervallet, og funktionen der kaldes på efter tiden er udløbet, laves i setup()-funktionen. Her benyttes timerens setInterval()-metode til at specificere tidsrummet og funktionen, der kaldes, når tiden er udløbet. Timeren køres i loop()-funktionen.

I det øjeblik timeren udløser repeatMe(), fortsætter robotten ligeud, indtil den rammer muren med knock-sensoren, der så får bilen til at køre til højre. Dette sker, når inputtet fra knock-sensoren er over 300. Efter robotten har drejet til venstre i 0.75 sek., sættes en boolean kaldet distance1 til at være true. Denne boolean bruges til at aktivere ultrasonic-sensoren, der ved hjælp af en sonar måler robottens afstand fra muren. Robotten styrer mod højre eller venstre for at holde afstanden konstant, og følger således muren frem til målstregen.

I ovenstående kode ses det, hvordan ultrasonic-sensoren aktiveres i et if-statement, der har den forudsætning, at distance1 er sat til at være true. En ultrasonic-sensors trigPin (kilden til lydsignalet) skal først sættes til low, hvorefter den sættes til high (sender lyd ud) og lynhurtigt efter sættes til low igen (stopper med at sende lyd) – på den måde kan echoPin måle den reflekterede lyd, og afstanden til muren kan efterfølgende beregnes på baggrund af den tid, det tager for lyden at vende tilbage til sensoren (duration*0.034/2). Den distance, som robotten skal tilstræbe at holde, blev efter mange justeringer sat til 7 cm, da robotten med denne afstand kunne svinge rundt om muren uden problemer. Højre- og venstresving foretages på samme måde, som når robotten følger den sorte streg – dog med nogle få ændringer i hastigheden.

Hvordan spiller de 3 sammen (mekanik, elektronik og software)?

Som tidligere nævnt er robottens konstruktion designet til at muliggøre høje hastigheder og optimal manøvrering, for at understøtte komponenternes maksimale ydeevne. Der er bevidst forsøgt at bruge så få klodser som muligt, for at gøre den samlede konstruktion lettere. Robottens korpus har så begrænset et omfang, som arduinoen tillader, hvilket bidrager til robottens førlighed i højre- og venstresving.

Både IR-sensorerne og ultrasonic-sensorerne er placeret foran hjulene, så robotten kan registrere ændringer i dens omgivelser (murens ende, sving på den sorte streg) og reagere hurtigere.

For at forhindre “støj” i IR-sensorernes input – for eksempel varierende lysforhold – blev det overvejet at afskærme de to sensorer ved hjælp af en forrude-klods. Dette viste sig hurtigt at være kontraproduktivt, da denne klods selv havde en negativ effekt på IR-sensorernes følsomhed – uden tilstrækkeligt lys havde robotten endnu sværere ved at følge den sorte streg.

Knock-sensoren, som befinder sig for enden af robottens “tunge”, havde intet problem med at tage input fra kontakten med muren. Det var nødvendigt at vinkle tungen, da signalet fra knock-sensoren ikke kunne nå hurtigt nok tilbage til arduinoen og få robotten til at dreje mod venstre. Ved at lade sensoren ramme muren med denne indfaldsvinkel, blokerer den ikke for robottens rotation, og den kan fortsætte sin færd uden noget større tab af hastighed.

Konklusion – hvor godt klarer Mr Froggy sig?

I væddeløbet mod de andre robotter, ydede robotten en af de bedste præstationer på den del af banen, hvor den skulle følge den sorte linje. Venstresvinget efter den sorte linjes ende blev også udført til fuld tilfredsstillelse, men desværre opstod der vanskeligheder i forbindelse med u-vendingen rundt om muren. Robotten startede vendingen i en meget åben vinkel, men halvvejs gennem svinget begyndte den at dreje skarpere ind imod muren. Dette resulterede enten i, at den kørte frontalt ind i muren og sad fast, eller at den vendte tilbage til muren med en indfaldsvinkel, der gjorde det umuligt for ultrasonic-sensoren at “se” muren og rette ind efter den. I testløbet havde kurvens radius været passende, men under væddeløbet formåede robotten beklageligvis ikke at gennemføre hele banen.

Perspektivering:

Robotten har flere dele der kan forbedres. Hver af de tre dele af den; hardware, lego opbygningen og software, kan alt sammen ændres og finpudses.

I hardware delen er der blevet brugt 2 IR sensorer, 1 sonar sensor, 1 piezo sensor, 1 batteriholder med flere batterier og 2 DC motorer. Her kunne robotten forbedres ved at placere flere sensorer af samme slags, sådan at hvis en sensor registrerer forkerte værdier, at en anden af samme slags overtager. Blandt andet kunne sonaren spontant give meget høje værdier, som kunne påvirke robottens kørsel langs væggen. Her ville to af slagsen forhindre dette i at ske. Flere DC-motorer kunne også gøre det muligt at få robotten til at køre meget hurtigere, men så vil IR-sensorerne få problemer med at følge med den sorte linje. Batterierne påvirkede også farten af robotten. Med nye batterier ville robotten køre hurtigere end med afladte batterier. Der kunne også tilføjes flere batterier, for at øge hastigheden. Vægten er der også taget højde for, sådan at robotten ikke bliver alt for tung og sænker farten. Derfor kan det også være en fordel ikke at sætte for meget hardware på robotten. Modsat gør timeren dog, at robotten skal bruge en vis tid på at følge den sorte streg – hvis den er for hurtig til at følge den til dens ende, kan den tværgående streg stadig give problemer for IR-sensorerne.

I LEGO-opbygningen er der også et par ting der kan forbedres. Her er vægten også en faktor. Jo flere klodser der bruges, jo tungere bliver bilen. Nogle af klodserne kan med fordel fjernes, for at forbedre farten. Afstanden mellem hjulene kan der også blive eksperimenteret mere med, for at finde den optimale afstand, der drejer bilen bedst. En for stor afstand mellem hjulene kan gøre det langsomt for bilen at dreje, og modsat kan en for lille afstand mellem hjulene gøre det svært for robotten at dreje.

Nogle af bilens funktioner er stadig styret af tid og delay-funktionen i arduino-sketchen. Blandt andet kan robotten ikke selv fortsætte lige ud efter de to første sving, og opfanger enden på den sorte linje som endnu et sving. Her kunne det være muligt at ændre i koden, sådan at den opfangede enden af den sorte linje korrekt. Det samme gør sig gældende på den anden side af muren, hvor robotten skal stoppe. En anden del af koden som kunne ændres, er hvordan sonaren registrerer væggen i slutningen af banen. Når robotten kommer til enden af væggen, hvor den skal dreje, så vil den ikke altid dreje skarpt nok eller også drejer den alt for skarpt. Dette kunne også forbedres, sådan at robotten kørte mere stabilt rundt om væggen.

Referencer:

Brooks, R.A. (1986) A Robust Layered Control System For A Mobile Robot. In: IEEE JOURNAL OF ROBOTICS AND AUTOMATION, VOL. RA-2, NO. I, March 1986

 

Leave a Reply