Teknologiskolen

Linjefølger Robot

Linjefølger robot

 

Denne guide tager udgangspunkt i anvendelse af lego klodser og motorer fra LEGO Mindstorm NXT men både klodser og motorer fra LEGO Mindstorm EV3 kan også anvendes.

Formål:

At bygge og programmere en robot, der kan følge en linje på gulvet.

Undersøgelse.

  • Hvordan virker den lyssensor der anvendes (IR sensor)
    • Hvilke andre metoder kunne der være til at køre efter en linje (linjen behøver ikke være synlig for mennesker)
    • Hvilke fordele/ulemper er der ved de forskellige teknologier
  • Hvordan får man robotten til at køre
    • Motor
      • Servo
      • DC-motor
      • Stepper Motor
    • Hvad er fordele og ulemper ved at bruge disse? – gerne holdt op mod hinanden.
  • Hvor hurtigt skal maskinen køre?
  • Hvor præcis skal den være?
  • Hvordan er sammenhæng mellem hastighed og robottens evne til at blive på linjen.

Tidsforbrug:

Hvis man kun følger instruktionerne som en tutorial: 4-6 timer

Hvis man samtidig underviser i de delkomponenter, der udgør det samlede projekt: 2-3 dage á 6 timer.

Robot:

Som hjælp til at bygge til at bygge robotten, kan vedhæftede byggevejledning med fordel anvendes til inspiration.

Det er ikke vigtigt at robotten bygges præcis som disse og fri fantasi kan anbefales hvis tiden er til det. Dog anbefales det at bygge et trehjulet (Tribot) robot da robotten herved får nemmere ved at dreje samt at styringen hertil er nemmere.

Resourselisten er som følger:

  • 2x IR sensorer – link.
  • 2x LEGO NXT eller EV3 motorer
  • 2x LEGO NXT eller EV3 kabler
  • 1x Batteriboks til 6xAA batterier – link.
  • 1x Arduino – link.
  • 1x Arduino Motor Shield – link.
  • 1x Arduino Prototype Shield – link.
  • 1x 9V Batteriklemme – link.
  • 1x USB Kabel (A-B)
  • Diverse ledning (stiv) – link.
  • Pin header til montage på ledning – link.
  • Ringetryk – link.
  • Modstand 10K – link.

Værktøj:

Skruetrækker til Arduino Motor Shield
Skævbider
Afisoleringstang
Loddekolbe

Teori

Når en robot skal følge en linje på gulvet er der grundlæggende to måder at gøre det på. Vi vil i det følgende se på disse.

På figuren herunder er vist to robotter (A og B). Robot A har en lyssensor (vist med blå cirkel) og robot B har to sensorer. Begge robotter har tre hjul (grå). To forrest der drives af hver sin motor, og et enkelt hjul bagerst til støtte robotten. Ved at have en motor koblet til hver af de forreste hjul, er det muligt for robotten at dreje rundt på en tallerken, hvis begge hjul kører rundt med samme hastighed i hver sin retning. Hvis begge hjul i stedet kører i samme retning med samme hastighed vil robotten køre enten lige frem eller tilbage. Hvis man vil dreje sænkes hastigheden på hjulet i den side hvorimod man ønsker robotten drejer.

Figur 1.

Som skrevet ovenfor er der to måder at følge en linje på med hhv. en eller to sensorer placeret forrest på robotten, et lille stykke foran de forreste hjem som vist på figuren herover.

I begge tilfælde er det en god ide at bruge en lys gulvbelægning og sort tape eller lignende for at gøre det nemmere at få robotten til at køre stabilt.

En lyssensor

Vælger man at anvende en lyssensor, vil det være som på billede “A” i figuren herover. Dette er den hurtigste og simpleste løsning, men også den der er mest ustabil.

Når en sensor anvendes kan man faktisk sige at robotten ikke følger linjen, men nærmere kanten af den. Det skyldes at robotten hele tiden vil køre fra side til side i en vrikkende bevægelse. Programmeringen er nemlig således at (med udgangspunkt i figuren herover) robot A når den rammer det hvide (gulvet) vil dreje til venstre til den ser sort (stregen). Når den ser det sorte (stregen) vil den straks begynde at dreje til højre til den igen ser hvidt (gulvet) og sådan vil den fortsætte og dermed følge stregen.

To lyssensorer

Med to lyssensorer opnår man en større stabilitet og robotten kan også klare flere udfordringer med denne løsning. Opsætningen vil være som på billede “B” i figuren herover.

Når to lyssensorer anvendes prøver robotten hele tiden at se hvidt. Hvis f.eks. den højre sensor registrerer sort, sænkes hastigheden på den højre hjule, hvorved robotten drejer væk fra stregen igen. Den bliver ved med at dreje til højre sensor igen ser hvidt.

På samme måde reagerer robotten hvis lyssensoren i venstre side registrerer sort.

Beskrivelse af elektronisk kredsløb

I dette afsnit beskrives de komponenter der udgør det elektroniske kredsløb i vores maskine, og nederst vises hvordan komponenterne skal sættes sammen for at maskinen kan virke.

Arduino UNO

Figur 2.

Arduino UNO’en på figur 3 er vores computer. Den består af en programmerbar microcontroller kreds fra firmaet Microchip. En microcontroller er basalt set en hel computer, der er lagt ind i en chip. D.v.s. den har både en CPU, noget hukommelse og en disk, samt forskellige typer porte man kan skrive til og læse fra. Du kan læse og lære meget mere om Arduino UNO på https://www.arduino.cc/ – og i særdeleshed på https://www.arduino.cc/en/Guide/ArduinoUno.

For at kunne programmere din Arduino skal du bruge en PC og hente softwaren til Arduino på https://www.arduino.cc/en/Main/Software. På samme side er der også online værktøjer der kan bruges til at arbejde med Arduino.

Arduino Motor Shield

Figur 3.

Arduino Motor shield på figur 4 er et udvidelsesprint til Arduino, der gør at man kan styre elektriske motorer. Det får vi brug for, når vi skal styre vores LEGO EV3 motorer. Grunden til, at det er nødvendigt med et ekstra print for at styre motorer, er at motorer ofte bruger højere spænding og mere strøm end der kan leveres direkte fra mikrocontrolleren. Derfor har Motor Shield’et muligheden for at tilføje en anden spændingeskilde via skrueterminalerne i nederste venstre hjørne (Vin og GND) og den store IC, der sidder midt på printet sørger for, at de signaler, der sendes fra Microcontrolleren på Arduino Uno bliver forstærket, så de er stærke nok til at kunne få en motor til at dreje rundt. Derudover bruges kredsen også til at vende spændingen, så man med kontrolsignaler fra Arduino Uno’en kan få motoren til at dreje i begge retninger.

Motor Shield’et kan styre 2 jævnspændings-motorer (også kaldet DC motorer) via de 4 andre skrueterminaler i venstre side af Figur 4. De nederste 2 er motor A + og -, og de øverste 2 er motor B + og -.

Når Motor Shield’et skal bruges bygger man det sammen med Arduino Uno ved at sætte det oven på, således det passer ned i de stik, der er rundt i kanten på Arduino Uno.

Du kan læse mere om Motor Shield’et her: https://www.arduino.cc/en/Main/ArduinoMotorShieldR3?setlang=it

Når vi skal styre Motor Shield’et fra vores Arduino skal vi bruge følgende porte på Microcontrolleren til at styre hhv. Retning (Direction) og Hastighed (PWM). Bremse (Brake) og Strømmåling (Current Sensing) bruger vi ikke i dette projekt.

Figur 5.

Protoshield

Figur 4.

Protoshieldet i figur 6 er det øverste shield i vore Arduino stak, og det indeholder et breadboard, som vi kan bruge til at sætte vores egne komponenter fast i, så vi undgår at skulle lodde.

I vores udgave af sorteringsmaskinen har vi lavet vores eget protoshield, men man kan også købe et.

Beskrivelse af lyssensorer

Til at registrere linjen vi ønsker at følge, anvender vi i denne opgave 2 stk IR sensorer. Dette er en type sensor der udsender infrarødt (IR) lys og herefter måler hvor meget lys der bliver reflekteret. Måden det virker på er, at når en sensor er over noget sort (linjen) så vil der ikke blive registreret ret meget reflekteret lys fordi farven sort ikke er godt til at reflektere lys. Modsat, hvis en sensor er over noget hvidt eller lyst, så vil der blive reflekteret væsentligt mere lys, fordi lyse overflader generelt reflekterer bedre.

Den sensor vi anvender giver en spænding, der afhænger af mængden af reflekteret lys og kan derfor aflæses direkte vha. en analog indgang på Arduino’en.

Trykknap/kontakt

Som kontakt anvendes et simpelt ringetryk. Det er en helt enkel kontakt, der slutter forbindelsen mellem to poler. For at kontakten virker korrekt skal den kobles med en modstand til GND (stel) som vist på diagrammet herunder.

Figur 5.

Vin er vores forsyningsspænding på 5V. Switchen er vores kontakt, og Pulldown Resistor er vores modstand på 10KOhm. Ground er vores stel, som også er benævnt GND på Arduino.

Det midterste punkt mellem kontakten og modstanden i kredsløbet forbindes til et digitalt input på Arduino’en, som så repræsenterer den Logic Gate, der er vist i figur 9. Grunden til at man laver dette kredsløb, er at vi gerne vil have at der er 5V på vores Logic Gate, når kontakten er sluttet, og 0V, når den er brudt. Det kan vi kun få ved at have modstanden i kredsløbet. Hvis der ikke var nogen modstand ville vi lave en kortslutning mellem 5V og GND, når vi slutter kontakten.

Ledninger

Til at forbinde NXT motorerne med vores Arduino motorshield har vi i dette projekt valgt at klippe et langt Mindstormskabel midt over, så vi får 2 kabler der kan forbindes til vores motorshield..

Kablerne er lavet som vist på figur 6.

Figur 6.

De stik, der er loddet på i de afklippede ender er f.eks disse., der kan knækkes af enkeltvis, hvor man så lodder en stift på hhv. den sorte og hvide ledning. Resten af ledningerne skal ikke anvendes hvorfor de kan klippes af. For at sikre lodningen mod træk i kablet har vi valgt at bruge varmelim til at isolere og forstærke den øverste del af stikket, som også vist på figur 10.

De resterende ledninger, der bruges i kredsløbet er almindelige stive monteringsledninger som vist herunder. For at de passer i breadboard skal de typisk afisoleres, så 0.5 cm leder bliver fritlagt.

Overordnet elektronisk diagram.

Herunder ses hvordan de ovenstående komponenter er sat sammen for at få det elektroniske kredsløb til at virke, så man efterfølgende kan bruge det til at styre robotten.

Det er vigtigt at lægge mærke til at det drejer sig om 3 printkort, der skal sættes oven på hinanden med Arduino Uno i bunden, Motorshield’et i midten og protoshield’et øverst.

 

Figur 7.

Herunder er billeder af robottens opbygning.

Figur 8.

Figur 9.

Figure 10.

Figure 11.

Programmering

I det følgende forventes der et forudgående kendskab til programmering af en Arduino samt anvendelse af programmeringsmiljøet Arduino IDE.

Den kode, der bliver gennemgået herunder er et forslag der som udgangspunkt virker, men vil kræve tilpasning til den enkelte robot. Under gennemgangen vil de steder hvor der skal laves tilpasninger blive gennemgået.

Programmeringen tager udgangspunkt i en standardskabelon for Arduino IDE som ses herunder:

void setup() {
// put your setup code here, to run once:

}

void loop() {
// put your main code here, to run repeatedly:

}

Det første vi vil se på er kode der står før void setup(){ i koden. Her bliver forskellige variabler defineret som anvendes igennem programmet.

 

//Motorer
int motor_A_Retning = 12; //Motor A’s retning styres med et digitalt signal (digital_write()) på ben 12 på Arduinoen
int motor_B_Retning = 13; //Motor B’s retning styres med et digitalt signal (digital_write()) på ben 13 på Arduinoen
int motor_A_Hastighed = 3; //Motor A’s hastighed styres med et PWM (analog_write()) signal på ben 3 på Arduinoen
int motor_B_Hastighed = 11; //Motor B’s hastighed styres med et PWM (analog_write()) signal på ben 11 på Arduinoen 

// Motor A’s bremse kan styres via ben 9 og Motor B’s bremse via ben 8 – Disse er dog ikke brugt i dette eksempel
// Motor A’s strømforbrug kan læses på A0 og Motor B’s strømforbrug kan læses på A1 – Disse er heller ikke brugt i dette eksempel

//Liniesensorer
int sensor_A = A2; // Linie sensor A (venstre side) læses fra den analoge indgang A2
int sensor_B = A3; // Linie sensor B (højre side) læses fra den analoge indgang A3
int sensor_A_Value = 0; // Variabel, der kan indeholde den værdi, der læses fra sensor A
int sensor_B_Value = 0; // Variabel, der kan indeholde den værdi, der læses fra sensor B

int sort_Hvid = 800; // Konstant, der fortæller hvad grænseværdien mellem sort og hvid er (hvid < 800 < sort). //Trykknap int tryk_Knap = 7; // Trykknap forbundet til ben 7 på Arduinoen int knap_Value = 0; // Variabel, der kan indeholde den værdi, der læses fra trykknappen (tændt eller slukket (HIGH / LOW)) int knap_Sidste_Value = 0; // Variabel, der indeholder den værdi knappen havde sidst den blev læst (tændt eller slukket) int tilstand = 0; // Variabel, der indeholder den tilstand programmet er i nu afhængigt af om knappen har været trykket på eller ej (tændt eller slukket)

 

 

Linje 19-22: Her fortæller vi programmet hvor kontrol signaler til motorboardet er koblet. Disse ben er bestemt af motorboardet og kan ikke flyttes.

 

Linje 28-31: Her fortæller vi programmet hvor de to lyssensorer er monteret på Arduino boardet i linje 28 og 29 på hhv ben A2 og A3 der er to analoge indgange. På linje 30 og 31 defineres to variabler til at gemme de læste værdier fra sensorerne. Være sikker på, på hvilke indgange du har forbundet dine lyssensorer.

 

Linje 33: Denne variable holder en grænseværdi til at adskille hvornår lyssensorerne ser hhv sort og hvid.

 

Linje 36-39: På robotten er en trykknap til at kontrollere start og stop af robotten. I linje 36 fortæller vi programmet at denne er forbundet til ben “7”. Vær sikker på at du har koblet knappet til dette ben, eller ændre benet. I linje 37 og 38 opsættes to variabler til at gemme hhv knappens nuværende position og den sidste position. Vi skal bruge de værdier senere i koden. I linje 39 vi gemmen robottens nuværende tilstand.

 

 

PAGE_BREAK: PageBreak

 

void setup() {
//De følgende linier fortæller Arduinoen, hvilke ben der skal fungere som input eller output
pinMode(motor_A_Retning, OUTPUT); //
pinMode(motor_A_Hastighed, OUTPUT);
pinMode(motor_B_Retning, OUTPUT);
pinMode(motor_B_Hastighed, OUTPUT);
pinMode(sensor_A, INPUT);
pinMode(sensor_B, INPUT);
pinMode(tryk_Knap, INPUT); 

// Linierne nedenfor fortæller vores Arduino, hvilken retning Motor A og B skal have
// – enten høj (HIGH), hvis motoren skal køre fremad eller
// lav (LOW), hvis den skal køre baglæns
digitalWrite(motor_A_Retning, HIGH);
digitalWrite(motor_B_Retning, HIGH);

// For at starte motoren, skal vi fortælle vores Arduino hvor
// hurtigt den skal køre. Dette gøre i linien herunder. Ved
// at ændre den sidste værdi mellem 0-255 kan hastigheden
// på motoren styres.
analogWrite(motor_A_Hastighed, 0);
analogWrite(motor_B_Hastighed, 0);
//Serial.begin(9600);
}

 

 

Herover ses den det af koden der står under “void setup()” og dermed køres én gang når programmet startes. Det er her grundlæggende ting settes up i programmet.

 

Linje 45-51: Her fortælles Arduinoen hvilke ben der skal fungere som enten input eller output. Ting der skal styres, såsom en motor, vil være et output og ting der måles på vil være input.

 

Linje 56-57: For at få robotten til at køre fremad, skal retningen på motorerne indstilles. Hvis output sættes til “HIGH” køre motoren i en retning og hvis “LOW” i den anden retning. I dette tilfælde er det “HIGH” for begge for at robotten køre fremad, men dette er ikke nødvendigvis det samme for din robot, så vær opmærksom.

 

Linje 64-65: For at robotten ikke bare begynder at køre når man sætter strøm til, skal vi aktivt fortælle robotten at den skal være stoppet. Dette gøres her ved at sætte “motor_A_Hastighed” til “0”.

 

PAGE_BREAK: PageBreak

void loop() {
// Først læser vi fra alle vores sensorer og gemmer værdien i de variabler vi lavede i starten af programmet
knap_Value = digitalRead(tryk_Knap); // Læser trykknappen (digital værdi)
sensor_A_Value = analogRead(sensor_A); // Læser liniesensor A (analog værdi mellem 0 og 1023)
sensor_B_Value = analogRead(sensor_B); // Læser liniesensor B (analog værdi mellem 0 og 1023) 

if(knap_Value == HIGH && knap_Sidste_Value == LOW) //Hvis trykknappen bliver trykket ind
{
delay(100); //Et lille delay på 100 millisekunder for at fjerne dobbelttryk (undgå at knappen bliver læst flere gange mens man trykker på den)
if(knap_Value==1){
tilstand = !tilstand; //Hvis der er tændt slukkes der eller omvendt
}
}

knap_Sidste_Value = knap_Value;

if(tilstand == 1){ // Hvis knappen har været trykket og tilstanden er 1 (tændt)

//Send en besked til computeren med den værdi vi læser
//Serial.print(sensor_A_Value);
//Serial.print(“, “);
//Serial.println(sensor_B_Value);

if (sensor_A_Value < sort_Hvid && sensor_B_Value < sort_Hvid) { // Hvis både liniesensor A og B ser hvidt // Kør ligeud digitalWrite(motor_A_Retning, HIGH); // Kør fremad med motor A (venstre) digitalWrite(motor_B_Retning, HIGH); // Kør fremad med motor B (højre) analogWrite(motor_A_Hastighed, 150); // Med hastighed 150 på begge analogWrite(motor_B_Hastighed, 150); } else if (sensor_A_Value > sort_Hvid && sensor_B_Value < sort_Hvid) { // Hvis venstre liniesensor (A) ser sort og højre liniesensor (B) ser hvidt // Drej til venstre digitalWrite(motor_A_Retning, LOW); // Kør baglæns med motor A (venstre) digitalWrite(motor_B_Retning, HIGH); // Kør fremad med motor B (højre) analogWrite(motor_A_Hastighed, 150); // Med hastighed 150 på begge analogWrite(motor_B_Hastighed, 150); } else if (sensor_A_Value < sort_Hvid && sensor_B_Value > sort_Hvid) { // Hvis venstre liniesensor (A) ser hvidt og højre liniesensor (B) ser sort
// Drej til højre
digitalWrite(motor_A_Retning, HIGH); // Kør fremad med motor A (venstre)
digitalWrite(motor_B_Retning, LOW); // Kør baglæns med motor B (højre)
analogWrite(motor_A_Hastighed, 150); // Med hastighed 150 på begge
analogWrite(motor_B_Hastighed, 150);
}
}
else{ // Hvis knappen har været trykket og tilstanden er 0 (slukket)
analogWrite(motor_A_Hastighed, 0); // Stop begge motorer
analogWrite(motor_B_Hastighed, 0);
}
}

 

Vi er nu nået til den del af programmet hvor selve robottens opførsel kodes. I vores tilfælde er det at få robotten til at følge en linje på gulvet vha to lyssensorer. Denne del af koden køre konstant i rind eller i en “løkke” mellem linje 70 og 122. Når programmet når linje 122 starter det forfra fra linje 70, og det går meget stærkt.

 

Linje 72-74: Her starter vi med at læse om knappen er trykket ind eller ej, samt at læse værdien af de to lyssensorer. De læste data gemmes i hver deres variable.

 

Linje 77-83: Knappen vi har monteret på robotten skal kunne tænde eller slukke for kørslen ved et tryk. Hvis robotten kører skal den standse hvis der trykkes på knappen og hvis den er standset skal den begynde at køre. På linje 77 starter vi med at spørge om knappen er trykket ind (HIGH) samt om knappen sidst den blev læst var sluppet (LOW). Hvis det er tilfældet går vi ind i “if-løkken” og venter 100ms. Herefter spørger vi igen om knappen stadig er trykket ind (HIGH) og hvis det er tilfældet ændre vi vores tilstand. Hvis tilstanden var “tændt” (“1”) bliver den “slukket” (“0”) og omvendt. Forsinkelsen på 100ms er for at sikre at knappen bliver læst korrekt.

 

Linje 85: Vi gemmer knappens værdi således at vi kan sammenligne næste gang løkken gentages og knappen trykkes ind (HIGH).

 

Linje 87-120: Vi starter en “if-sætning” her, som spørger på vores variabel “tilstand”. Hvis variablen er “HIGH” fortsætter vi ind i løkken da det betyder at robotten er tændt og skal køre. Hvis den er “LOW” (robotten er slukket og står stille) går vi til “else-delen” der starter i linje 118 hvor begge motorer får sat hastigheden til “0” og dermed stopper.

 

Linje 90-113: Styringen af selve robotten sker i disse linjer. Som det ses er der en “if”-sætning med to “else-if” sætninger efterfølgende. Dette betyder at hvis den første “if”-sætning ikke er sand (korrekt) vil den herefter kontrollere den første “else-if” sætning og hvis den heller ikke er korrekt går programmet til den sidste “else-if” sætning. Dette giver tre områder – 1, 2, 3 – som hver i sær har deres egen opførsel ud fra de sensordata der registreres. Det er de samme to sensorer alle tre områder læser fra, men afhængig af data vil de tre områder opføre sig forskelligt.

 

Område 1: Her spørger man i “if”-sætningen om begge sensores data er mindre end vores “sort_Hvid” variabler der er vores grænseværdi. Hvis begge er mindre end denne variabel betyder det at begge sensorer ser hvid. Når begge sensorer ser hvis, betyder det at robotten køre ovenpå streget, og derfor er det ikke nødvendigt at korrigere robotten

 

Område 2: Her spørger vi om sensores i den ene side ser sort “stregen”. Hvis den gør det ændre vi retningen på retningen motoro for dermed at tvinge robotten tilbage på kurs.

 

Område 3: Dette er præcis det samme som for område 2, blot vil robotten dreje til den anden side når

 

 

Tilpasning

Når programmet er færdigt, skal man forvente lidt tilpasning for at få robotten til at køre. Dette drejer sig om lyssensorene, hvor den grænseværdi for hhv hvid og sort underlag skal justeres. Grænseværdien ændres i linje 33.

 

For at instille denne værdi, kan man først programmare Arduino’en med følgende program.

 

//Opretter en variable til at gemme den værdi sensoren måler
int SensorA2Value = 0; 

//Opretter en variable til at genne navnet på det
//ben sensoren er forbundet til
int SensorA2Pin = A2;

void setup() {
//Opretter forbindelse mellem Arduino og computer
//så vi kan læse beskeder fra vores Arduino på computeren
Serial.begin(9600);

}

void loop() {
//Læser værdi fra vores sensor og gemmer den i variablen SensorA0Value
SensorA2Value = analogRead(SensorA2Pin);

//Senser en besked til computeren med den værdi vi læser
Serial.println(SensorA2Value);

//Venter 200ms
delay(200);
}

 

 

Dette program vil aflæse værdien fra sensor A2 og printe den i Arduino IDE terminalen. Ved at lade sensoren “se” den sorte linje og derefter det hvide (gulvet) fås to værdier. Ved at tage gennemsnittet af disse to, opnås et tal der vil være et godt udgangspunkt for en grænseværdi til at adskille sort og hvid.

 

Herefter burde robotten kunne følge en sort linje på gulvet. God fornøjelse.