HC-SR04 koristi beskontaktni ultrazvučni sonar za mjerenje udaljenosti do objekta, a sastoji se od ultrazvučnog odašiljača (u osnovi zvučnika), prijemnika i elektronike koja kontrolira senzor. Odašiljač emitira visokofrekventni ultrazvučni zvuk frekvencije 40 kHz, koji se odbija od bilo kojeg čvrstog objekta u blizini. Prijemnik osluškuje povratni odjek. Taj odjek zatim obrađuje upravljački dio senzora kako bi izračunao vremensku razliku između signala koji se šalje i prima. To se vrijeme uz pomoć matematike može upotrijebiti za izračunavanje udaljenosti između senzora i reflektirajućeg objekta.
Dobro je znati da će VIDI X moći izračunati udaljenost uz pomoć HC-SR04 senzora i bez korištenja djelitelja voltaže, te ga smijete direktno spojiti na VIDI X bez da se VIDI X ošteti, iako, na ovaj način senzor nešto sporije reagira te time neće imati velik broj mjerenja i vaš program će se izvršavati nešto sporije.
Senzor HC-SR04 najbolje mjeri udaljenosti između 2 cm i 400 cm unutar stošca od 30 stupnjeva i točan je do najbližih 0,3 cm. Dakle, on ne mjeri udaljenost linearno iz centra svoje osi, nego se zvuk širi u obliku spomenutog stošca. Iz tog razloga ga nije moguće koristiti postavljenog na dno vozila, tj. općenito nisko s podlogom jer će konstantno očitavati tu kosu udaljenost prema podu.
Iz tog razloga smo ih od podloge podignuli koristeći stare tvrde diskove kao stalak na kojem će stajati.
Za početak, uz priloženu shemu spajanja, spojimo jedan HC-SR04 senzor kako biste uz ovaj kod promatrali njegovo ponašanje na serijskom monitoru. Proučite shemu spajanja u nastavku te proizvoljno odaberite jednu od tri ponuđene metode spajanja i spojite jedan HC-SR04 senzor tako da njegov Trig PIN spojite s GPIO 13 VIDI X mikroračunala, a Echo PIN s GPIO 14 mikroračunala.
Pokrenite ovaj kod:
int PinTrig = 13; // deklaracija pinova: Trig 13, Echo 14 int PinEcho = 14; long t; // deklaracija varijable vrijeme int s; // deklaracija varijable udaljenost int n = 0; void setup() { pinMode(PinTrig, OUTPUT); // deklaracija Trig kao izlazne varijable pinMode(PinEcho, INPUT); // deklaracija Echo kao ulazne varijable Serial.begin(115200); // pokretanje serijske veze } void loop() { // postavi Trig LOW 2 mikrosekunde – čišćenje Trig pina digitalWrite(PinTrig, LOW); delayMicroseconds(2); // generiraj ultrazvuk trajanja 10 mikrosekundi digitalWrite(PinTrig, HIGH); delayMicroseconds(10); digitalWrite(PinTrig, LOW); t = pulseIn(PinEcho, HIGH); // mjeri vrijeme puta ultrazvuka s = t * 0.034 / 2; // pretvori vrijeme u udaljenost Serial.print("Udaljenost = "); Serial.println(s); }
Primijetit ćete kako vrijednosti ponekad variraju. Ovisno o čvrstoći vašeg spoja, breadboard može imati slabije spojeve od direktnoga spoja, dakle imat ćete manje ili više greški u očitanjima.
No za početak je bitno razumjeti kako senzor radi te da ne možete mijenjati vrijednosti vremena kod naredbe delayMicroseconds() jer nećete dobiti dobre vrijednosti očitanja.
Dakle, pokretanjem Trig PIN-a u trajanju od 10 mikrosekundi pokrenut će se interni mehanizam senzora koji će ispustiti osam impulsa od 40 KHz, nakon čega promatramo povratni ECHO signal čija duljina trajanja pokazuje izmjerenu udaljenost.
Do idućeg mjerenja mora proći minimalno 60 milisekundi kako bi mjerenje bilo ispravno.
Trikovi za korištenje HC-SR04 senzora
Koristite li razne biblioteke koje paralelno mogu izvršavati neki drugi kod, moguće je da se taj dodatni kod izvrši baš u krivom trenutku te vremenski odgodi izvršavanje mjerenja udaljenosti. Primjer takvog koda može se kriti u funkciji prekida, te pri korištenju FreeRTOS biblioteke ili u sličnim slučajevima.
Koristite li senzor u blizini elektromotora koji ima četkice za pogon, iskra generirana na četkicama smeta pravilnom očitanju udaljenosti, te je potrebno isključiti struju motora prilikom očitavanja.
Kada koristite više od jednog senzora, Trigger PIN svih njih je moguće spojiti na jedan GPIO mikrokontrolera kako biste očitavali udaljenosti od više senzora. No ukoliko su senzori preblizu jedan drugome, moguće je da će doći do interferiranja signala, pa morate testirati radi li takva konfiguracija u vašem okruženju.
Umjesto djelitelja voltaže možete koristiti i konverter logičkih signala za pretvaranje ECHO logičkog signala s 5 V na 3,3 V. Primjer korištenja LLC konvertera proučite na linku https://hr.vidi-x.org/radionice/vidi-project-x-92-serijska-komunikacija/.
Za HC-SR04 senzor postoji pregršt biblioteka. Neke se bave mjerenjem udaljenosti s obzirom na temperaturu, jer i temperatura zraka utječe na brzinu zvuka. Druge se bave eliminiranjem greški u očitanju. Treće iskazuju udaljenosti u milimetrima, centimetrima i inčima. I tako ih se već mnogo može pronaći, no nekako nam se čini da ne postoji idealna biblioteka koja bi obuhvatila sve. Upravo iz tog razloga, ovdje vam pokazujemo kako koristiti senzor bez upotrebe biblioteka, a vi slobodno u tražilicu biblioteka utipkajte ime senzora i istražite dostupne biblioteke.
Eliminiranje greški očitanja
Znamo da senzor mjeri otprilike do četiri metra, te da su sva očitanja veća od toga sigurno pogrešna. Dakle, osnovna očitanja možemo filtrirati upotrebom jednostavnog uvjeta.
if (s < 500) { Serial.print("Udaljenost = "); Serial.println(s); } else { Serial.print("Greška"); }
Kako udaljenost mjerimo u centimetrima (iako je senzor sposoban mjeriti i milimetre), lakše nam je uspoređivati dva mjerenja kako bismo vidjeli podudaraju li se. Ukoliko su dobivena mjerenja različita, potrebno je još jednom mjeriti kako bismo utvrdili koje je od prethodna dva bilo pogrešno.
Ovisno o tome kako se kreće vaš objekt do kojeg mjerite udaljenost, algoritam ćete morati prilagoditi jer može nastati situacija da se objekt kreće prema senzoru, pa će radi pomicanja nastati razlike u očitanju koje ustvari nisu greška.
Svakako bi bilo poželjno tri puta mjeriti, pa onda utvrditi mijenja li se udaljenost za isti iznos te odstupa li jedno od mjerenja kako bismo ga mogli eliminirati.
Još jedna odlična metoda eliminiranja greške je mjerenje s dva senzora, no tu opet treba uzeti u obzir da će najprije jedan senzor detektirati objekt, a drugi nešto kasnije kada objekt dođe u njegovo radno polje. Tu dolazi do izražaja ranije spomenuti kut djelovanja senzora od 30°.
Ako trebate još preciznije očitanje, možete kombinirati spomenute dvije metode mjerenja nekoliko puta s dva senzora. Uz nekoliko testiranja i proučavanja mjerenja senzora, napišite vlastite algoritme za različite situacije. Mi se nećemo u ovoj radionici baviti takvim manje ili više pametnim algoritmima, nego ćemo vas uputiti u osnove korištenja HC-SR04 senzora, a razvoj što boljeg algoritma prepoznavanja i eliminacije greški ostavljamo vama kao zanimaciju ili za neku drugu radionicu.
Shema spajanja HC-SR04 senzora
Na priloženoj shemi treba primijetiti kako imamo tri moguća načina spajanja HC-SR04 ultrazvučnog senzora udaljenosti.
HC-SR04 se napaja naponom od 5 V s istoimenog izlaza VIDI X-a i relativno je precizan. Zapamtite, HC-SR04 ima logički izlaz od 5 V koji bi se trebao smanjiti na 3,3 V da bi pravilno radio s VIDI X-om. To ćete postići spajanjem njegovog ECHO pina putem djelitelja voltaže ili pomoću konvertera logičkih napona sa 5 V na 3,3 V.
Djelitelj voltaže dobit ćemo tako da između ECHO pina senzora i GND konekcije VIDI X-a u seriju spojimo dva otpornika, od kojih drugi ima duplo manje ohma od prvoga. Dakle, uzmimo da prvi otpornik spojen na GND ima 2 kohma, drugi spojen s njime i ECHO pinom trebao bi imati 1 kohm.
Moguće je koristiti djelitelj voltaže i na način da prvi otpornik, onaj spojen na GND, ima 1 kohm, dok drugi spojen u seriju s tim otpornikom prema ECHO pinu ima 470 ohma. Kako ne postoji otpornik od 500 ohma za dobivanje idealnog spoja, ovaj od 470 ohma je sasvim dovoljan te ćete njime dobiti oko 3,4 V u sredini spoja ta dva otpornika.
U spomenutu sredinu spoja dva otpornika potrebno je spojiti GPIO konekciju prema VIDI X mikroračunalu. Naime, na toj točci između dva otpornika dijeljenjem voltaže dobili smo napon od oko 3,3 V. Ovdje treba primijetiti kako neki otpornici imaju dozvoljena odstupanja od npr. 10% u odnosu na nazivne vrijednosti, pa tako u nekim slučajevima ta voltaža može varirati i do 3,6 V. Za ovaj primjer to neće stvarati probleme, no bitno je znati odstupanja vaših otpornika te je poželjno izmjeriti njihove vrijednosti i odstupanja prije njihovog korištenja.
Zamijenite li slučajno mjesta otpornicima, dobit ćete djelitelj voltaže koji smanjuje voltažu na 1,6 V, a u tom slučaju vam HC-SR04 neće raditi kako očekujete.
Kako biste saznali više o djeliteljima voltaže, na linku https://bit.ly/djelitelj proučite i ostale radionice hr.vidi-x.org portala koje ga koriste.
Zadatak: Sjetite se Ohmovog zakona i pokušajte dobiti otpornik od 500 ohma korištenjem dva otpornika od 1 kohma.
Rješenje: Spojite li dva otpornika od 1 kohma paralelno, dobit ćete spoj od 500 ohma.
Ako kojim slučajem imate dostupno manje od osam senzora, isprobajte ovu radionicu spajanjem samo tih senzora koje imate i pokrenite priloženi kod. Kod će raditi, osim što ćete za senzore koje nemate dobivati vrijednost nula.
Programski kod:
Kako biste mogli kompajlirati ovaj programski kod, potrebna vam je biblioteka imena „GFX Library for Arduino“.
Za ovu biblioteku smo se odlučili jer ima podršku za crtanje luka kružnoga isječka, što će nam biti potrebno kako bismo iscrtavali pozicije na kojima se nalazi naš vlakić.
Nakon uključivanja biblioteke potrebno je definirati pinove na koje je spojen ekran VIDI X-a, a potom objektu sabirnice (bus) dodijeliti definirane pinove. I kao posljednji korak, moramo objektu ekrana (display) dodijeliti sabirnicu.
#include <Arduino_GFX_Library.h> #define TFT_SCK 18 #define TFT_MOSI 23 #define TFT_MISO 19 #define TFT_CS 5 #define TFT_DC 21 Arduino_ESP32SPI bus = Arduino_ESP32SPI(TFT_DC, TFT_CS, TFT_SCK, TFT_MOSI, TFT_MISO); Arduino_ILI9341 display = Arduino_ILI9341(&bus);
Sada želimo kreirati dva niza u kojima će biti GPIO brojevi pinova na koje spajamo redom senzore. Dakle, prvi senzor je spojen na pinove GPIO 32 i GPIO 34, drugi na GPIO 33 i GPIO 39, i tako redom.
static int RedniBrojSenzora = 7; //Prvi senzor je rednog broja 0(nula) int PinTrigArray[10] = {32, 33, 14, 27, 13, 1, 4, 2}; // deklaracija pinova: Trig i Echo int PinEchoArray[10] = {34, 39, 36, 35, 22, 3, 0, 15};
Kreiramo i nizove za njihove izmjerene vrijednosti.
long tArray[10]; // deklaracija varijable vrijeme int sArray[10]; // deklaracija varijable udaljenost
Zatim postavljamo vrijednosti za iscrtavanje pruge.
Prugu ćemo iscrtati funkcijom crtajPrugu(), tako da prvo nacrtamo zeleni krug, a potom prema stvarnoj poziciji senzora za svaki senzor crtamo crveni dio pruge. To činimo putem uvjeta if(sArray[n]<25) koji iscrtava crveni dio pruge ukoliko imamo udaljenost manju od 25 centimetara.
int xArc = 255; int yArc = 170; int r1Arc = 60; int r2Arc = 50; void crtajPrugu() { display.fillArc(xArc, yArc, r1Arc, r2Arc, 0, 360, GREEN); //display.fillArc(xArc, yArc, r1Arc - 3, r2Arc + 3, 0, 360, BLACK); //if ((sArray[0] < 25) && (sArray[7] < 25)) display.fillArc(xArc, yArc, r1Arc, r2Arc, 90, 180, RED); //if ((sArray[1] < 25) && (sArray[2] < 25)) display.fillArc(xArc, yArc, r1Arc, r2Arc, 0, 90, RED); //if ((sArray[3] < 25) && (sArray[4] < 25)) display.fillArc(xArc, yArc, r1Arc, r2Arc, 270, 360, RED); //if ((sArray[5] < 25) && (sArray[6] < 25)) display.fillArc(xArc, yArc, r1Arc, r2Arc, 180, 90, RED); if (sArray[0] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 90, 130, RED); if (sArray[1] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 50, 90, RED); if (sArray[2] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 0, 40, RED); if (sArray[3] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 320, 360, RED); if (sArray[4] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 270, 310, RED); if (sArray[5] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 230, 270, RED); if (sArray[6] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 180, 220, RED); if (sArray[7] < 25) display.fillArc(xArc, yArc, r1Arc, r2Arc, 140, 180, RED); }
Ne zaboravite se kasnije poigrati i s ovim linijama koda koje smo ostavili u komentaru.
U setup dijelu prvenstveno moramo odrediti input i output pinove svakog senzora. To je najbezbolnije učiniti putem for petlje.
void setup() { for (int n = 0; n <= RedniBrojSenzora; n++) { pinMode(PinTrigArray[n], OUTPUT); // deklaracija Trig kao izlazne varijable pinMode(PinEchoArray[n], INPUT); // deklaracija Echo kao ulazne varijable } display.begin(); display.fillScreen(0); display.setRotation(3); display.setTextColor(YELLOW, BLACK); display.setTextSize(5); display.println(«VIDI X»); display.setTextSize(3); display.println(« microcomputer»); display.setTextColor(GREEN, BLACK); display.setTextSize(2); }
Naposljetku, tu je i glavna funkcija u kojoj ponovno putem for petlje očitavamo vrijednosti svakog senzora, te putem formule za računanje udaljenosti ovisno o brzini zvuka računamo tu udaljenost. Ukoliko je ta udaljenost izvan „normalnih“ granica, nećemo je niti ispisati. To postižemo upotrebom uvjeta if(sArray[n]<1000) u kojem, dođe li do ispisivanja vrijednosti, možemo vrijednosti manje od 25 cm ispisati crvenom bojom radi lakše uočljivosti. Bitno je odmah nakon tog ispisa vratiti boju teksta na zelenu kako bi se ostatak ispisa nastavio zelenom bojom.
Za kraj glavne petlje pozivamo ranije kreiranu funkciju koja crta prugu prema trenutno izmjerenim vrijednostima.
void loop() { for (int n = 0; n <= RedniBrojSenzora; n++) { // postavi Trig LOW 2 mikrosekunde – čišćenje Trig pina digitalWrite(PinTrigArray[n], LOW); delayMicroseconds(2); // generiraj ultrazvuk trajanja 10 mikrosekundi digitalWrite(PinTrigArray[n], HIGH); delayMicroseconds(10); digitalWrite(PinTrigArray[n], LOW); tArray[n] = pulseIn(PinEchoArray[n], HIGH); // mjeri vrijeme puta ultrazvuka sArray[n] = tArray[n] * 0.034 / 2; // pretvori vrijeme u udaljenost if (sArray[n] < 1000) { display.setCursor(0, 80 + n * 15); display.print(«Sen.»); display.print(n); display.print(« = «); if (sArray[n] < 25) display.setTextColor(RED, BLACK); display.print(sArray[n]); if (sArray[n] < 25) display.setTextColor(GREEN, BLACK); display.println(« cm «); } } crtajPrugu(); }
Potpuni kod dostupan je na linku: https://github.com/VIDI-X/Train-and-HC-SR04-distance-sensor
Kako bi prijenos koda na VIDI X bio moguć, potrebno je pri samom uploadanju odspojiti senzore spojene na GPIO 0, 1, 3 i 4. Naime, nula i četiri su dio strapping pinova ESP32 procesora VIDI X-a. Strapping pinovi pri pokretanju VIDI X-a moraju imati točno određene vrijednosti, te ukoliko senzori spojeni na njih utječu na promjene njihovih vrijednosti, VIDI X se ne može pokrenuti ili ne može učitati novi programski kod.
Radite li ovaj projekt na breadboard pločici, najjednostavnije je žicu koja povezuje spomenute strapping pinove VIDI X-a i breadboard jednostavno odspojiti od breadboarda dok se VIDI X ne upali nakon bootanja.
Pri inicijalnom paljenju će kod za te senzore pokazivati udaljenost nula, no vi sada „na živo“ tj. dok je VIDI X upaljen, spojite spomenute žice natrag na breadboard, pazeći pri tome da ih upiknete na pravo mjesto. Nakon uspješnog spajanja će VIDI X sada i za te senzore ispisati izmjerene udaljenosti.
Više o strapping pinovima pročitajte u VIDI Project X #60 radionici na linku https://hr.vidi-x.org/radionice/vidi-project-x-60-vidi-x-kao-video-nadzor-za-psa/, a oni spretniji među vama zaista mogu istražiti kako dodati prekidače s vremenskom odgodom na kritične pinove.
Iako bismo za praćenje vlakova u željezničkom prometu preferirali GPS koji bi javljao točnu poziciju vlaka, i ovaj projekt bi se lako mogao skalirati za korištenje u realnom željezničkom prometu kada bi se umjesto ovih senzora koristili senzori većeg dometa. Bitno je na umu imati kako redundantnost senzora uvijek dobro dođe kao dodatna kontrola, bez obzira na to koje senzore koristimo.