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 Lucian T. 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. 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:
- Arduino Uno
- Shield ArduMoto
- Senzori de reflectanta (linie)
- Cutia de viteze Tamiya
- Roti + Ball Caster
- Fire de conexiune si altele..
- Sasiu robot
- Leduri, componente electronice(rezistori, condensatori, tranzistori) si altele…
Schema bloc de functionare a robotului ROBOTL
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.
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 */ //----------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.
In incheiere, as vrea sa multumesc profesorului coordonator, Dl. Viorel de la Robofun si, nu in ultimul rand, prietenului meu F. Mihai.
Cu respect,
Lucian T.