Al Zheimer – Arduino Lego robot

robot1

 

Vi har på 4. Semester Optek, i Hardware og Robotteknologi, fået til opgave at lave en Robot ud af Lego som styres af en Arduino. Robotten skal kunne følge en sort streg på et hvidt underlag, og undervejs kunne undgå en forhindring. Robotten skal desuden kunne stoppes og startes over en bluetooth forbindelse.

Til det har vi fået udleveret 2 Lego technic motorer og en Arduino med et motorshield. Derudover har vi lånt en Lego NXT lyssensor, en Lego NXT ultrasonisksensor og et BlueSMiRF bluetooth modem.

Ved opgavens slut vil der være en konkurrence i at gennemføre banen hurtigst muligt, dog under 1 minut.

 

Hardware

2 x Lego Technic motor

Lego NXT – lys sensor

BlueSMiRF – Bluetooth modem fra Sparkfun

Arduino Uno R3

Arduino Motorshield R3

 

Startup

Fordi der er flere dele i denne opgave som skal spille sammen, har jeg valgt at fokusere på de enkelte dele, og få dem til at virke hver for sig først, derefter bygge dem sammen til en robot.

Jeg kunne ikke få Lego NXT ultrasonicsensoren til at virke, i stedet bruger jeg en hjemmelavet knap. Mere information om den senere.

 

Trådløs kommunikation

Til trådløs kommunikation bruger jeg det udleverede bluetooth modem BlueSMiRF. Som standard bruger Bluesmirf serial kommunikation med 115200 Baud, så det skal man lave om, eller også bruge 115200 Baud arduino koden også. For at kunne bruge USB forbindelsen uden at skulle slukke for Bluesmirf, kan man sætte en SoftwareSerial forbindelse op. Med SoftwareSerial kan Bluesmirf køre fra 2 almindelige digitale pins på aduinoen i stedet for at skulle bruge de dedikerede TX og RX pins. Det frigør Arduinoens standard serial forbindelse, så den kan bruges til USB.

Sådan sættes BlueSMiRF til arduino – fra:http://wiring.org.co/learning/tutorials/bluetooth/

bluetooth

Når man bruger Software Serial sættes TX og RX fra Bluetooth modulet til de pins man i sin kode valgt til at være RX og TX. RX til TX og TX til RX.

Jeg fandt eksempel kode til Software Serial på: http://arduino.cc/en/Reference/SoftwareSerial

Her er det kode jeg bruger til bluetooth komminukation:

softwares

Derefter kan BlueSMiRF kommunikere med en Android telefon, eller konsollen i Arduino, eller hvad man nu har brug for. Til at styre min robot og overvåge de værdier den sender bruger jeg en gratis App ved navn BlueTerm. Efter at have etableret forbindelse med BlueTerm kan man se hvad der bliver sendt af Arduinoen over bluetooth, og ved at sende tekst beskeder kan man kommunikere med Arduinoen.

 

Lego NXT lys sensor

Lys sensoren fra Lego NXT er en analog sensor. Målinger skal læses af en analog port på arduinoen. Sensoren giver en spænding, som arduinoen digitaliserer til en værdi mellem 0 og 1023. Den værdi kan så bruges til at vurdere lys forholdene omkring sensoren. For at få en værdi der kan bruges til noget tænder jeg Arduinoens interne pull-up resistor på 20k ohm. Det giver et bedre spænd af værdier, som er til at arbejde med i robottens styrings algoritme.

Lego NXT Lyssensoren sættes til arduinoen ved at skære dens kabel over, også sætte de forskellige ledninger til arduinoen. Lyssensorens kabel har følgende opbygning:

legolys

 

Billede fra: https://sites.google.com/site/mccolganrobotics/

 

Legokabel – Arduino

Pin 1 – Pin A3

Pin 2 – Gnd

Pin 3 – Gnd

Pin 4 – 5v

 

Målingerne fra sensoren kan så aflæses med følgende Arduino kode

lyssens

 

Motorer og PWM

Når man kun har 2 motorer kan man lave 2 simple former for kørende robot. En hvor den ene motor bruges til at styre robotten, og den anden til fremdrift. Og den metode jeg har valgt, at sætte begge motorer til fremdrift på et hjul i hver sin side. Så kan Styring af robotten opnås, ved at bede om forskellig hastighed på de 2 hjul, lige som en kampvogn.

Motorerne fra Lego Technic er ikke så kraftige, så det er en god idé at lave en gearing ud af lego. Jeg har kun fået lavet en 2:1 gearing ved hjælp et medium legotandhjul på motoren og et stort legotandhjul på hjulets aksel. Mere gearing ville være en god idé, et af de helt små legotandhjul og et af de store ville nok have passet godt.

PWM står for Pulse Width Modulation, og er en metode som kan bruges til at styre strømmen til fx en motor. Modstanden i en motor er rimelig konstant og kan ikke styres, derfor bruger man PWM til at regulere hvor meget strøm motoren skal trække. Et PWM signal ligger mellem 0 og 255, og får Arduinoen til at tænde og slukke for strømmen på den valgte PWM-pin. Ved at pulsere strømmen kan man teoretisk set opnå mellem 0 og 100% motorkræft, uden at ændre på strøm styrke, spænding eller modstand. Imellem at motoren modtager impulser vil motoren bare trille lidt af sig selv. Der kan opstå timings problemer i forhold til motorens faser, så især ved lave hastigheder kan man ikke regne med at få præcis den procent motorkræft man beder om.

 

Robottens fysiske udformning

 

opbyg1

 

Robottens lego karrosseri, kun med motorer

opbyg2

Den færdige robot

 

Styrings overvejelser

Robotten skal følge en streg. Det kan man bruge lyssensoren til, fordi stregen vil reflektere lys anderledes end underlaget. Fx vil en sort streg reflektere mindre lys end en hvid baggrund.

Da vi kun har 1 lyssensor at arbejde med vil robotten ikke kunne følge stregen direkte. Hvis lyssensoren måler at nu er den ikke over stregen længere, så ved robotten ikke hvilken side af stregen den er kørt ud over. Her vil jeg gennemgå nogle mulige løsninger på dette problem.

 

Dreje søger – flipflop

Når stregen ikke længere er under lyssensoren, drejer robotten fx mod venstre. Fanger den stregen hurtigt kører den videre lige ud. Går der lang tid fra den drejer til stregen nås, så skal den fortsætte forbi stregen til den finder stregen igen, før den kører lige ud. Hvis den bare kørte når den rammer stregen efter at have drejet i lang tid, vil den følge stregen i den forkerte retning. Det kan også udnyttes, ved at lade robotten køre baglæns i stedet for at vende rundt igen, en metode som jeg vil kalde flipflop.

 

Myre søger

I stedet for at dreje rundt om sig selv for at finde stregen, kan man lave et lignende søge system hvor robotten i stedet skifter søge retning hvis der går for lang tid med at finde stregen. For så ikke at afsøge det samme område igen og igen kan man få robotten til at køre lidt fremad for hver retningsskift. Det resulterer i en søge mekanisme som ligner den myrer bruger til at finde et spor som er blevet brudt.

 

Bounce søger

For at slippe for problemerne med ikke at vide hvilken side man skal dreje til for at finde stregen, fik jeg den idé at lave en modsat søger. En robot som forsøger at holde sin sensor over den hvide baggrund i stedet for over stregen. Den kan så laves med en bias mod at dreje ind mod stregen mens den kører. Når den så rammer stregen ændres kørselen midlertidigt til at dreje væk fra stregen.

 

Metode valg

Da robotten er under tidspres har jeg valgt at forsøge mig med Bounce-søgeren. Fordi jeg tror den vil kunne følge stregen hurtigst. Flipflop er ikke en mulighed fordi min robot fysisk kun har ét baghjul, som ikke egner sig til at køre baglæns. Bounce-søgeren er nok også den mest simple løsning at implementere.

 

Kasse undvigelse

For at kunne undvige kassen har min robot en hjemmelavet lego knap ude foran. Så når den kører ind i kassen bliver knappen trykket ind, og robotten kan aktivere en undvigelses manøvre. Undvigelses manøvren er preprogrammeret og er ikke afhængig af sensorer, før robotten igen skal finde stregen.

Knappen virker ved at jeg gennem en resistor har sat strøm til en ledning. Når knappen så trykkes ind forbindes en ledning fra en analogpin med den strømførende ledning, og strømmen kan aflæses af den analoge pin.

 

Styrings implemetering

Jeg har valgt at lave styrings implementeringen ved hjælp af modes. Som basis har jeg 3 simple modes i min kode, kun 1 er aktiv af gangen.

mode 0 – Sæt motorer til 0 i fart – venter på mode ændring over bluetooth

mode 1 – hvidt underlag – skifter til mode 2 hvis lyssensoren måler sort underlag.

mode 2 – sort underlag – skifter den til mode 1 hvis lyssensoren måler hvidt underlag.

Disse 3 modes er nok til at få robotten til at følge en streg. De kræver dog noget fin justering i forhold til motorhastighed.

Når robotten så kan følge en streg aktiveres mode 1 eller 2 over bluetooth, og robotten går igang.  Robotten “vrikker” sig fremad ved skiftevis at køre på hver motor og lade en anden trille imens, så den både opnår retnings skift og fremdrift.

For at kunne komme uden om en forhindring har jeg preprogrammeret en sekvens i mode 5, som aktiveres af mode 1 og 2 når knappen bliver trykket ind. Robotten kører ind i kassen, knappen bliver trykket ind, også startes sekvensen til at køre uden om.

Efter sekvensen i mode 5 er færdig, skiftes til modes 6-8 som bruges til at finde stregen igen. Fordi robotten kommer med fart på, så overskyder den stregen første gang den ser den, og kommer derfor på den forkerte side. Mode 7-8 bruges til at få robotten tilbage på den rigtige side.

 

Kode

 

// inkludering af Software Serial library
#include <SoftwareSerial.h>

// definer TX og RX pins til Software Serial 
#define TXPIN 4
#define RXPIN 7

// instanciering af Software Serial objekt
SoftwareSerial BTSerial(RXPIN, TXPIN);

// mode sættes til en værdi
char mode = 'H';
// ledpin som digital pin 6
const int ledpin = 6;

// deklarering globale variabler
int lightlvl;
int touch;
int lightTres = 260;

// sæt analog input pins
const int lightsense = A3;
const int touchpin = A4;

// sæt konstanter for motor styring
const int dirA = 12;
const int dirB = 13;
const int speedA = 3; // venstre
const int speedB = 11; // højre
const int brakeA = 9;
const int brakeB = 8;

void setup() {
  // sæt ledpin som output
  pinMode(ledpin, OUTPUT);

  // Alle Pins opsættes som output-pins
  pinMode(dirA, OUTPUT);
  pinMode(dirB, OUTPUT);
  pinMode(speedA, OUTPUT);
  pinMode(speedB, OUTPUT);
  pinMode(brakeA, OUTPUT);
  pinMode(brakeB, OUTPUT);

  // motor retning
  digitalWrite(dirA, LOW);
  digitalWrite(dirB, HIGH);

  // motor bremser fra
  digitalWrite(brakeA, LOW);
  digitalWrite(brakeB, LOW);

  // sæt lego sensors analog pin til input
  // og tænd for arduinos indbyggede pull-up resistor
  pinMode(lightsense, INPUT);      
  digitalWrite(lightsense, HIGH);
  // samme for touchpin
  pinMode(touchpin, INPUT);      
  digitalWrite(touchpin, HIGH);

  // Definer pins til bluetooth som input/output pins
  pinMode(RXPIN, INPUT);
  pinMode(TXPIN, OUTPUT);

  // Start kommunikation med Bluetooth 
  BTSerial.begin(115200);
  //Serial.begin(115200);

  analogWrite(ledpin, 200);  // tænd LED

}

void loop() {
   // hvis der er data tilgængelig på bluetooth serial
   // så læs den, og gem i variabel mode
  if( BTSerial.available() )       
  {
    mode = BTSerial.read();        
  }
  // læs sensorer
  lightlvl = analogRead(lightsense);
  touch = analogRead(touchpin);

  if (touch < 900) { mode = '5'; }

  // udskriv værdier til bluetooth serial forbindelse
  BTSerial.print(lightlvl);
  BTSerial.print(" | ");
  BTSerial.print(touch);
  BTSerial.print(" | ");
  BTSerial.println(mode);

  if( mode == '0' )               // mode 0 - stop motorer, sluk LED
  {
    digitalWrite(ledpin, LOW); // sluk LED

    // Stop
    analogWrite(speedA, 0); 
    analogWrite(speedB, 0);

  } else if( mode == '1' )     // kør mode 2, drej venstre, hen mod streg
  {
    analogWrite(ledpin, 200);  // tænd LED

    analogWrite(speedA, 0);
    analogWrite(speedB, 80);
    if (touch < 900) { mode = '5'; } // hvis robotten rammer noget, skift til mode 5
    else if (lightlvl > lightTres) { mode = '2'; }

  } else if ( mode == '2' )    // kør mode 2, drej højre, væk fra streg
  { 
    analogWrite(speedA, 80);
    analogWrite(speedB, 0);
    if (touch < 900) { mode = '5'; }
    else if (lightlvl < lightTres) { mode = '1'; }

  } else if ( mode == '3' ) {   // mode til testing
    analogWrite(speedA, 0);
    analogWrite(speedB, 60);

    if (lightlvl > lightTres) { mode = '4'; }

  } else if ( mode == '4' ) {   // test mode
    analogWrite(speedA, 60);
    analogWrite(speedB, 0);

    if (lightlvl < lightTres) { mode = '3'; }

  } else if ( mode == '5' ) {  // undgå kasse   
    // motor pause
    digitalWrite(brakeA, HIGH);
    digitalWrite(brakeB, HIGH);
    delay(100);
    digitalWrite(brakeA, LOW);
    digitalWrite(brakeB, LOW);
    // bak væk fra kasse  
    digitalWrite(dirA, HIGH); // motor a baglæns
    digitalWrite(dirB, LOW); // motor b baglæns
    analogWrite(speedA, 100);
    analogWrite(speedB, 0);
    delay(300);
    analogWrite(speedA, 0);
    analogWrite(speedB, 90);
    delay(300);  
    // motor pause
    digitalWrite(brakeA, HIGH);
    digitalWrite(brakeB, HIGH);
    delay(100);
    digitalWrite(brakeA, LOW);
    digitalWrite(brakeB, LOW);
    // drej uden om kasse, med bremse på den ene hjul    
    digitalWrite(dirA, LOW); // motor A fremad
    digitalWrite(dirB, HIGH); // motor B fremad
    analogWrite(speedA, 120);
    analogWrite(speedB, 0);
    digitalWrite(brakeB, HIGH); // brems B
    delay(600);
    digitalWrite(brakeB, LOW); // brems B fra
    // kør fremad
    analogWrite(speedA, 70);
    analogWrite(speedB, 70);
    delay(300);
    // pause
    analogWrite(speedA, 0);
    analogWrite(speedB, 0);
    delay(200);

  // fang stregen igen
    analogWrite(speedA, 30);
    analogWrite(speedB, 60);

    if (lightlvl > lightTres) { mode = '7'; }

  } else if ( mode == '7' ) {   // tilbage på stregen
    analogWrite(speedA, 100);
    analogWrite(speedB, 0);

    if (lightlvl < lightTres) { mode = '8'; }

  } else if ( mode == '8' ) {   // tilbage til den rigtige side af stregen
    analogWrite(speedA, 70);
    analogWrite(speedB, 0);

    if (lightlvl > lightTres) { mode = '1'; }
  }
  delay(5);
}

 

Konkurrence

 

Konklusion

Al Zheimer virker! Det er lykkedes at lave en robot som kan klare opgaven.

 

Leave a Reply