Scaneaza si afiseaza harta cu obiectele detectate
Autor: Ro-Bot-X -25/06/2010-
Dupa cum spuneam in unul din articolele anterioare, am instalat pe MiniEric un shield cu ecran LCD color de tip Nokia. Scopul acestui ecran color este de a afisa harta cu pozitia robotului pe ea si obiectele intalnite in raza de detectie, si, ulterior, suprapunerea acestei harti de puncte cu harta reala a incaperii in care se afla robotul. O alta functie a ecranului va fi de a afisa obiectele detectate cu ajutorul camerei AVRcam. Acest proiect este inspirat de proiectul LoMoR.
Ecranul se afla conectat la modului de Cartografiere si comunica prin interfata SPI. Exista mai multe biblioteci de functii pentru diferitele modele de ecran color. Cel pe care il folosesc in prezent are controler Philips (integrat in ecran), altele au controler Epson (cele puse in vanzare de SparkFun si RoboFun). Dar functiile de folosire sunt similare, adica se poate seta culoarea unui pixel, se poate desena o linie, un dreptunghi (gol sau plin) sau un cerc, si se poate afisa o imagine bitmap (scrisa ca un text, exista programe de convertire). Practic, o data inclusa biblioteca de functii, folosirea ecranului este foarte simpla.
Cand am facut programul de scanare si afisare, robotul era inainte de faza integrarii modulelor R-Dev-Ino, asa ca ecranul (pe vremea aceea era cu controler EPSON si nu afisa corect culorile; de atunci biblioteca de functii a fost imbunatatita) era conectat la modulul de control al motoarelor. Dar asta nu conteaza prea mult, ceea ce vreau sa va arat este felul in care este facuta scanarea si afisata harta de puncte pe ecran.
Pentru a replica acest proiect aveti nevoie de:
- un Arduino
- un shield cu ecran color Nokia (avei grija sa luati si conectori cu 6 si 8 pini)
- un servomotor
- un senzor de masurat distanta, fie ultrasonic, fie infrarosu (plus cablu).
Se monteaza shield-ul pe Arduino, apoi se conecteaza senzorul si servomotorul folosind fire si pini tata. Alimentarea senzorului se face de la un pin de 5V iar cea a servomotorului la un pin de tensiune neregulata (Vin, daca nu depaseste 6V). Daca alimentati Arduino de la 9V, este mai bine sa alimentati servomotorul de la tensiunea stabilizata de 5V.
Exista o diferenta de functionare intre senzorul ultrasonic Ping))) folosit de mine si cele pe care le puteti gasi in Romania. Acesti senzori folosesc 2 pini de semnal, unul pentru Trigger si unul pentru Echo, fata de un singur pin folosit de Ping))). Acest senzor se conecteaza la 2 pini digitali. Daca folositi senzorul infrarosu, acesta se conecteaza la un pin analogic. Exemple de cod pentru citirea acestori senzori va voi da in tutorialul urmator.
Programul functioneaza in felul urmator: servomotorul porneste de la 0 grade si se misca din grad in grad. La fiecare grad, senzorul de distanta face o masuratoare si valoarea obtinuta se transforma in centimetri si se scrie intr-un sir. Se calculeaza coordonatele carteziene si se “aprinde” un pixel pe ecran. Ecranul are 132×132 pixeli, daca asezam in centrul ecranului pozitia robotului, putem afisa obiectele pe o raza de 65 cm. Daca pozitia robotului se aseaza mai jos, putem afisa obiectele aflate in fata robotului la o distanta de pina la 130 cm.
Formula de calcul pentru afisarea punctelor in functie de unghiul servomotorului si distanta pina la punct este clasica, se foloseste in masuratorile topografice de ani de zile. Practic, se instaleaza statia de masuratori pe un punct cu coordonate cunoscute (este marcat in asfalt cu un bulon special), apoi se fac masuratori in diverse directii in functie de necesitati, notand unghiul si distanta (masurata cu ruleta!) pina la acel par dungat (pentru a determina inaltimea) asezat pe punctul de interes. Evident, azi se folosesc aparate speciale, care masoara folosind ultrasunete si laser si coordonatele statiei sunt date de catre satelit. Aparatul respectiv salveaza masuratorile pe un memory stick si operatorul le poate descarca pe computer ulterior.
In functiile matematice din C, calculele trigonometrice se fac folosind unghiuri exprimate in radiani, de aceea trebuie convertit unghiul masurat (in grade) prin inmultirea unghiului cu 0.0174532925. Apoi formula e simpla, coordonata x = distanta * sin(unghi) si coordonata y = distanta * cos(unghi). Pentru afisarea pe ecran mai trebuie plasate coordonatele relativ la mijlocul ecranului si trebuie rotite cu 90 de grade, deci formula finala este:
x=131-(MapXcenter+USValue[a]*(sin((a-90)*0.0174532925)));
y=131-(MapYcenter+USValue[a]*(cos((a-90)*0.0174532925)));
Unde USvalue[a] este distanta masurata pentru unghiul “a” si 131 reprezinta numarul maxim de pixeli ei ecranului.
Iata cum arata programul:
/*
Scan and display map on Nokia LCD (Epson).
Ping sensor on a pan servo.
Released into the public domain.
*/
#include
#include
#define PanPin 16
#define PingPin 15
// Nokia LCD Setup settings
// Basic Colors
#define WHITE 0xFFF
#define BLACK 0x000
#define RED 0xF00
#define GREEN 0x0F0
#define BLUE 0x00F
#define CYAN 0x0FF
#define MAGENTA 0xF0F
#define YELLOW 0xFF0
#define BROWN 0xB22
#define ORANGE 0xFA0
#define PINK 0xF6A
// Nokia LCD pins:
#define CSE 4
#define RST 5
#define SDA 11
#define SCK 13
#define MapXcenter 65
#define MapYcenter 35
Servo Pan;
NokiaLCD nokiaLcd;
byte PingDistance = 0;
byte USValue[181];
byte x=0;
byte y=0;
byte a=0;
char text [50];
char byteString[4];
void setup()
{
pinMode(CSE, OUTPUT);
digitalWrite(CSE, HIGH);
pinMode(SCK, OUTPUT);
digitalWrite(SCK, HIGH);
pinMode(SDA, OUTPUT);
digitalWrite(SDA, HIGH);
pinMode(RST, OUTPUT);
digitalWrite(RST, HIGH);
pinMode(PingPin, OUTPUT);
digitalWrite(PingPin, LOW);
Pan.attach(PanPin);
Pan.write(90);
nokiaLcd.lcd_init();
delay(500);
}
void loop()
{
ScanMap();
}
void ScanMap()
{
nokiaLcd.lcd_clear(BLUE, 0, 0, 131, 131);
strcpy(text,"o"); //mark the robot's position
nokiaLcd.lcd_draw_text(PINK, BLACK, (131-MapXcenter-3), (131-MapYcenter), text);
for (a=0; a<=180; ++a) //scan left to right
{
ScanAndDisplay();
}
delay(1000);
nokiaLcd.lcd_clear(BLUE, 0, 0, 131, 131);
strcpy(text,"o"); //mark the robot's position
nokiaLcd.lcd_draw_text(PINK, BLACK, (131-MapXcenter-3), (131-MapYcenter), text);
for (a=180; a>=0; --a) //scan right to left
{
ScanAndDisplay();
}
delay(1000);
}
void ScanAndDisplay()
{
Pan.write(a); //pan the servo from 0 to 180 degrees
USValue[a] = Read_Ping_Sensor(); //do a measurement
if (USValue[a]<200) //if objects are closer than 200 cm
{
byte pos=57; //start position for the value display
if (USValue[a]<100) //change the start position depending on the number of digits
{
strcpy(text," ");
nokiaLcd.lcd_draw_text(CYAN, BLACK, pos, 115, text);
pos=63;
}
itoa(USValue[a], byteString, 10); //integer to ascii, convert the number to a string of bytes
strcpy(text, byteString); //write the string into text
nokiaLcd.lcd_draw_text(CYAN, BLACK, pos, 115, text); //display the text
// multiply the angle° of the servo by 0.017453292 to convert to radians;
// a is the angle of the servo ( 90° is to twist result sideways for display)
x=131-(MapXcenter+USValue[a]*(sin((a-90)*0.0174532925)));
y=131-(MapYcenter+USValue[a]*(cos((a-90)*0.0174532925)));
nokiaLcd.LCD_put_pixel(CYAN, x, y); //display the pixel
}
}
// Read Sensors
int Read_Ping_Sensor() {
//trigger the sensor
int Ping = 0;
pinMode(PingPin, OUTPUT);
digitalWrite(PingPin, LOW);
delayMicroseconds(2);
digitalWrite(PingPin, HIGH);
delayMicroseconds(5);
digitalWrite(PingPin, LOW);
//receive the echo
pinMode(PingPin, INPUT);
digitalWrite(PingPin, HIGH); // turn on pull up resistor
Ping = pulseIn(PingPin, HIGH);
return Ping/58.138; //convert to cm
}
afisare harta , arduino , LCD shield , scanare obiecte




