Concurs : ROBOTL – Sistem de conducere a unui robot mobil pe baza Retelelor Neuronale Artificiale

Acest articol este publicat in cadrul concursului Robofun 2012.  Perioada de votare pentru acest proiect s-a incheiat. Acest proiect a acumulat un numar de 105 voturi.

Salut prieteni!

Ma numesc Tarida Lucian si sunt proaspat absolvent al facultatii de Inginerie Mecanica si Electrica, specializarea Automatica din cadrul Universitatii Petrol-Gaze din Ploiesti.

Scurt intro: Asa cum era normal, a venit momentul in care a trebuit sa-mi aleg o tema de licenta pentru a incheia cei 4 ani de studiu. Asadar, pe la sfarsitul lunii octombrie 2010 m-am hotarat: “vreau sa fac un robot mobil pentru ca, intotdeauna, mi-au placut robotii si sistemele automate”. La scurt timp, mi-am ales tema proiectului de licenta, si anume “Sistem de conducere a unui robot mobil pe baza retelelor neuronale artificiale” si un profesor care sa-mi supervizeze munca, Dl. Conf. Dr. Ing. Adrian Moise. Am inceput sa ma informez din diverse manuale de specialitate, articole, de pe internet, iar apoi a venit momentul in care a trebuit sa-mi achizitionez componentele robotului. Am apelat cu incredere la Robofun.ro, unde am avut placerea sa-l cunosc pe Dl. Viorel caruia ii multumesc pe aceasta cale pentru amabilitatea de care a dat dovada.

Astfel, mi-am achizitionat aproape toate componentele robotului ROBOTL de la Robofun.ro:

Schema bloc de functionare a robotului ROBOTL

Schema bloc

Functionare

ROBOTL (a se citi Robotel) este un robot mobil urmaritor de linie (line follower) ce se deplaseaza conform unui traseu reprezentat de o linie neagra pe un fundal alb. Linia neagra se traseaza cu o banda izoliera pe o bucata de carton duplex.

Citirea traiectoriei dupa care se deplaseaza robotul se face cu ajutorul senzorului analogic QRE1113 format dintr-un led cu infrarosu si un fototranzistor sensibil la lumina infrarosie. Am folosit 3 astfel de senzori ce alcatuiesc sistemul senzorial al robotului ROBOTL.

Semnalele provenite de la senzori sunt trimise spre procesare Unitatii Centrale reprezentata de Platforma de dezvoltare Arduino Uno ce contine microcontroller-ul ATmega328 de la ATMEL. Platforma de dezvoltare Arduino Uno reprezinta sistemul de comanda al robotului si contine 14 pini digitali de intrare-iesire si 6 pini analogici. Pentru ROBOTL s-au folosit urmatorii pini: analogici: A0, A1, A2 conectati fiecare la pinul de iesire al fiecarui senzor de linie si digitali: D3(PWM), D11(PWM), D12, D13 folositi pentru controlul motoarelor de curent continuu, D4, D5, D6, D8, D9, D10 pentru controlul ledurilor, pinul D2 pentru circuitul buzzer ce ofera sunetul de final de linie.

Semnalele procesate sunt apoi transmise catre shield-ul ArduMoto ce comanda, conform principiului unei punti H, cele doua motoare electrice de curent continuu ale robotului. Motoarele sunt incluse in cutia de viteze Tamiya impreuna ca angrenajele aferente ce confera drept rapoarte de transfer 58:1, respectiv 203:1. ROBOTL functioneaza in configuratia 58:1 drept raport de transfer.

Implementarea Retelei Neuronale Artificiale (RNA)

În cadrul acestui proiect, am folosit o rețea neuronala tip perceptron multistrat ce este formată dintr-un strat de intrare, un strat ascuns și unul de ieșire. Stratul de intrare cuprinde trei neuroni ce au drept intrări cele trei valori codificate în binar ale semnalelor provenite de la cei trei senzori de reflectanță. Stratul ascuns este alcătuit din patru neuroni, numărul lor fiind ales în mod arbitrar, totodată fiind suficient pentru implementarea rețelei neuronale pe baza căreia funcționează robotul ROBOTL. Stratul de ieșire conține doi neuroni ce furnizează la ieșire sensul de rotație al celor două motoare electrice de curent continuu ale robotului ROBOTL. Pentru implementarea retelei s-au folosit urmatoarele codificari: tensiune de iesire senzor >= 4V (valoare determinata experimental) => (i=1) altfel (i=0) ; sensul de rotatie a motoarelor – inainte(1), stop(0), inapoi(-1). In figura alaturata este reprezentata RNA pe baza careia functioneaza robotul ROBOTL.

Caracteristicile RNA:

  • Arhitectura retelei : Perceptron multistrat (multilayer perceptron) cu un strat ascuns
  • Functia de activare : Sigmoid pentru stratul ascuns si activare liniara pentru stratul de iesire
  • Algoritmul de invatare (antrenare) : Algoritmul de propagare inversa a erorii (backpropagation)

Soft educational – Antrenare Retea Neuronala Artificiala

Pentru a antrena reteaua neuronala prezentata mai sus, am dezvoltat o aplicatie in C++ Builder ce poate fi folosita cu incredere si in scop didactic, fiind un soft educational. Astfel, oricine doreste sa antreneze o retea neuronala artificiala de tip perceptron multistrat (cu un singur strat ascuns) si conform algoritmului de propagare inversa a erorii poate folosi acest soft. Softul ofera ponderile retelei la fiecare epoca in cadrul fisierului out.txt ce se deschide dupa antrenare si graficul evolutiei erorii patratice medii. Se pot efectua 5 astfel de reprezentari grafice iar utilizatorul o alege pe cea in care eroarea patratica tinde mai rapid spre 0 (zero). Interfata softului este prezentata in imaginea de mai jos.

Soft Antrenare Retea Neuronala
Soft Antrenare Retea Neuronala

Imagini ROBOTL :

 

Ponderile obtinute in urma antrenarii retelei neuronale artificiale cu ajutorul softului educational mai sus mentionat au fost utilizate la conducerea robotului mobil ROBOTL pe baza RNA. Iata codul programului din memoria microcontroller-ului ATmega328 cu ajutorul caruia functioneaza robotul ROBOTL:

/*
  07-04-2011
  Tarida Lucian Constantin

  Contact:
    * E-MAIL: lucian_ctin08@yahoo.com
*/
//----------Pini motoare si senzori----------------
int pwm_a = 3;
int pwm_b = 11;
int dir_a = 12;
int dir_b = 13;
int IRpins= 0;  // pin pentru senzor stanga
int IRpind = 1;  // pin pentru senzor dreapta
int IRpinm = 2; // pin pentru senzor centru
//--------------------------------------------------

//------led pins--------
long previousMillis = 0;
long interval = 75;
const int ledPin4 =  4;
const int ledPin5 =  5;
const int ledPin6 =  6;
const int ledPin8 =  8;
const int ledPin9 =  9;
const int ledPin10 =  10;
//-----------------------

//--------Note Muzicale--------
#define NOTE_G4  392
#define NOTE_A4  440
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_D5  587
#define NOTE_E5  659

int melody[] = {
  NOTE_C5, NOTE_G4, NOTE_G4, 0, NOTE_C5, 0 ,NOTE_A4, NOTE_A4, NOTE_A4,
  NOTE_B4, NOTE_C5, NOTE_D5, NOTE_B4, NOTE_C5, NOTE_E5, NOTE_C5};
int noteDurations[] = {4,8,4,16,4,16,4,8,2,4,8,4,4,4,8,2};
int looop=0;  // variabila utilizata la executarea sunetului o sg. data
//------------------------------

//---------------Retea Neuronala---------------------------
// Ponderile Retelei Neuronale
const double
w11 = -6.390470,
w12 = 3.475753,
w13 = -1.168266,
w21 = 4.685940,
w22 = -4.834824,
w23 = -4.389631,
w31 = 0.926425,
w32 = -4.021020,
w33 = -3.097896,
w41 = -3.659724,
w42 = -4.280046,
w43 = 0.800755,
v11 = 1.067345,
v12 = 2.492497,
v13 = -4.892565,
v14 = 1.341395,
v21 = 1.122284,
v22 = 2.182859,
v23 = -1.559597,
v24 = -1.766479;
// Variabile ale Retelei Neuronale
double neth1,neth2,neth3,neth4,oh1,oh2,oh3,oh4,o1,o2;
int i1,i2,i3; //intrarile RN
//-----------------------------------------------------------

void setup()
{
  pinMode(pwm_a, OUTPUT);
  pinMode(pwm_b, OUTPUT);
  pinMode(dir_a, OUTPUT);
  pinMode(dir_b, OUTPUT);
  pinMode(ledPin4, OUTPUT);
  pinMode(ledPin5, OUTPUT);
  pinMode(ledPin6, OUTPUT);
  pinMode(ledPin8, OUTPUT);
  pinMode(ledPin9, OUTPUT);
  pinMode(ledPin10, OUTPUT);

  Serial.begin(9600);

}
void loop()
{
// Citire si Afisare Valoare Senzori
    float senzor_centru = analogRead(IRpinm)*((float) 5 / 1024) ;
    float senzor_stanga = analogRead(IRpins)*((float) 5 / 1024) ;
    float senzor_dreapta = analogRead(IRpind)*((float) 5 / 1024) ;
    if(senzor_stanga>=4) i1=1; else i1=0;
    if(senzor_centru>=4) i2=1; else i2=0;
    if(senzor_dreapta>=4) i3=1; else i3=0;

 // Parcurgerea Inainte a Retelei Neuronale
    neth1=i1*w11+i2*w12+i3*w13;
    neth2=i1*w21+i2*w22+i3*w23;
    neth3=i1*w31+i2*w32+i3*w33;
    neth4=i1*w41+i2*w42+i3*w43;
    oh1=1/(1+ exp(-neth1));
    oh2=1/(1+ exp(-neth2));
    oh3=1/(1+ exp(-neth3));
    oh4=1/(1+ exp(-neth4));
    o1=oh1*v11+oh2*v12+oh3*v13+oh4*v14;  //iesirile RN: o1 si o2
    o2=oh1*v21+oh2*v22+oh3*v23+oh4*v24;

 // Inainte
 if (round(o1)==1 && round(o2)==1)
   {
   digitalWrite(dir_a, HIGH);
   digitalWrite(dir_b, HIGH);

   analogWrite(pwm_a, 90);
   analogWrite(pwm_b, 90);
   leduri(1);
   }

 // Viraj catre stanga
 if (round(o1)==-1 && round(o2)==1)
   {
   digitalWrite(dir_a, LOW);
   digitalWrite(dir_b, HIGH);

   analogWrite(pwm_a, 40);
   analogWrite(pwm_b, 60);
   leduri(1);
    }

 // Viraj catre dreapta
 if (round(o1)==1 && round(o2)==-1)
    {
    digitalWrite(dir_a, HIGH);
    digitalWrite(dir_b, LOW);

    analogWrite(pwm_a, 60);
    analogWrite(pwm_b, 40);
    leduri(1);
    }

 // Stop
 if (round(o1)==0 && round(o2)==0)
   {
   digitalWrite(dir_a, HIGH);
   digitalWrite(dir_b, HIGH);

   analogWrite(pwm_a, 0);
   analogWrite(pwm_b, 0);
   leduri(0);
   }

 // Sunet
  if (i1==1 && i2==1 && i3==1 && looop==0)
  {  for (int thisNote = 0; thisNote < 16; thisNote++) {
    int noteDuration = 1000/noteDurations[thisNote];
    tone(2, melody[thisNote],noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    noTone(2);
    looop+=1; }
  }
}

 // Leduri
 void leduri(int x)
 {
  if(x==1)
  {
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval*6) {
      previousMillis = currentMillis;
    digitalWrite(ledPin10, HIGH);
    digitalWrite(ledPin9, LOW);
   }

  else   if(currentMillis - previousMillis > interval*5) {
    digitalWrite(ledPin9, HIGH);
    digitalWrite(ledPin8, LOW);
   }

 else  if(currentMillis - previousMillis > interval*4) {
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin6, LOW);
   }

 else  if(currentMillis - previousMillis > interval*3) {
    digitalWrite(ledPin6, HIGH);
    digitalWrite(ledPin5, LOW);
   }

 else if(currentMillis - previousMillis > interval*2) {
    digitalWrite(ledPin5, HIGH);
    digitalWrite(ledPin4, LOW);
   }

  else  if(currentMillis - previousMillis > interval) {
    digitalWrite(ledPin4, HIGH);
    digitalWrite(ledPin10, LOW);
   }
  }
  if(x==0)
  {
    digitalWrite(ledPin4, LOW);
    digitalWrite(ledPin5, LOW);
    digitalWrite(ledPin6, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    digitalWrite(ledPin10, LOW);
  }
 }

Cam atat despre robotul meu. Cei interesati de alte informatii ma pot contacta la adresa de e-mail: lucian_ctin08@yahoo.com.

In incheiere, as vrea sa multumesc Dl. Conf. Dr. Ing. Adrian Moise, Dl. Viorel de la Robofun si, nu in ultimul rand, prietenului meu Florea Mihai.

Cu respect,
Tarida Lucian

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s