Skip to main content

3.1 Mjerenje udaljenosti

Cilj ovog primjera je izmjeriti udaljenost ultrazvučnim senzorom iz kita. Senzor odašilje kratak prasak zvuka, sluša odjek koji se odbija od onoga što se nalazi pred njim, i izračuna koliko je taj objekt daleko. Rezultat se ispisuje u konzolu.

Ovo je i prvi primjer koji koristi driver i Qwiic modul, pa je spajanje najlakše u cijelom kitu: jedan kabel i gotov si.

U ovoj dokumentaciji naučit ćeš:

  • Kako ultrazvučni senzor mjeri udaljenost mjerenjem vremena odjeka.
  • Kako spojiti Qwiic modul jednim kabelom i bez jumper žica.
  • Kako postaviti I2C vezu i zašto te MicroPython tjera da imenuješ pinove.
  • Što je driver i kako ga dobiti na pločicu.
  • Zašto ovaj senzor treba dva poziva funkcije da bi ti dao jedno mjerenje.
  • Kako prepoznati vrijednost koja nije pravo mjerenje.

Potreban hardver:

  • 1x Soldered NULA MINI pločica
  • 1x Breadboard
  • 1x Ultrazvučni senzor udaljenosti (HC-SR04)
  • 1x Qwiic kabel
  • 1x USB-C kabel
ℹ️
Ovaj put nema otpornika ni jumper žica. Svaki primjer do sada tjerao te je da krug sastavljaš rupicu po rupicu. Ovaj ne: senzor je Qwiic modul, pa jedan kabel odjednom nosi napajanje i podatke, a ulazi samo na jedan način.

Spajanje komponenti

1. Umetni NULA MINI pločicu na breadboard

Utisni pločicu u jedan kraj breadboarda tako da njezina dva reda pinova sjednu s obje strane središnjeg kanala, s čipom okrenutim prema dolje.

NULA MINI pločica postavljena na breadboard
Korak 1: pločica postavljena na breadboard
ℹ️
Breadboard u ovom primjeru ne radi nikakav električni posao, jer se ništa ne spaja na pinove pločice. Tu je samo da drži pločicu ravno i stabilno dok utiskuješ kabel. Primjer 3.2 dodaje LED-icu na ovaj isti sklop, i onda breadboard počinje zasluživati svoje mjesto.

2. Utisni Qwiic kabel u pločicu

NULA MINI ima jedan Qwiic konektor, na rubu pločice između tipki USER i RST. To je bijeli konektor označen s qwiic na silkscreenu. Utisni kabel dok ne klikne.

Qwiic kabel utisnut u NULA MINI pločicu, s drugim krajem još slobodnim
Korak 2: kabel u Qwiic konektoru pločice, drugi kraj još slobodan
⚠️
Ne pomiješaj ga s manjim konektorom s dva kontakta na suprotnom rubu pločice, označenim s - i +. To je konektor za bateriju, i Qwiic kabel u njega ne ulazi.
ℹ️
USB-C kabel je na ovim fotografijama već utisnut, a ljubičasto PWR svjetlo je upaljeno. Nije važno kada ga spojiš. Qwiic module je sigurno utiskivati u bilo kojem redoslijedu i u bilo kojem trenutku.

Ako želiš vidjeti točno o kojem se konektoru radi na goloj pločici, ovdje je istaknut:

NULA MINI pločica s istaknutim Qwiic konektorom
Qwiic konektor na NULA MINI, istaknut plavim

3. Utisni drugi kraj u senzor

Senzor su dvije pločice spojene poleđinom na poleđinu: plavi ultrazvučni modul koji nosi dva srebrna pretvarača, i ljubičasta Soldered pločica koja nosi elektroniku koja obavlja razgovor. Na ljubičastoj pločici silkscreenom je ispisano ULTRASONIC SENSOR QWIIC, i ona ima dva Qwiic konektora, po jedan na svakom kraju.

Utisni slobodni kraj kabela u bilo koji od njih. Spojeni su međusobno, pa nije važno koji odabereš. Drugi je tu da možeš dalje nalančati još jedan modul.

Gotova veza: Qwiic kabel ide s NULA MINI na ultrazvučni senzor
Korak 3: kabel spaja pločicu sa senzorom. To je cijeli krug
ℹ️
Ostavi mali narančasti blok prekidača ADDR točno kako je došao, sa sva tri klizača odmaknuta od oznake ON. On postavlja adresu na koju senzor odgovara, a kod očekuje tvorničku postavku. Mijenjao bi je samo ako bi želio staviti dva takva senzora na isti kabel.

4. Usmjeri senzor u otvoreni prostor

Okreni senzor tako da dva srebrna pretvarača gledaju u prostoriju, i drži prostor pred njima čistim. To su dijelovi koji odašilju i slušaju zvuk, pa je sve što na njima leži (stol, kabel, tvoja ruka) jedina stvar koju će senzor ikada naći.

Senzor podignut s dva pretvarača okrenuta u prostoriju
Korak 4: pretvarači okrenuti prema van, s čistim prostorom pred njima

Kako senzor mjeri udaljenost

Zvuk kroz zrak putuje poznatom, ravnomjernom brzinom: oko 343 metra u sekundi, što izlazi na 0.0343 centimetra po mikrosekundi. Ta fiksna brzina je cijeli trik. Ako znaš koliko je zvuku trebalo da dođe negdje, znaš koliki je put prešao.

Zato senzor odašilje vrlo kratak cvrkut na oko 40 kHz, previsok da bi ga čovjek čuo, iako šišmiš s njim ne bi imao problema, i pokreće štopericu. Cvrkut otputuje, u nešto udari, i dio njega se odbije natrag. U trenutku kada ga senzor čuje da se vraća, zaustavlja štopericu.

Dijagram ultrazvučnog senzora koji odašilje puls koji se odbija od objekta i vraća
Puls izlazi iz odašiljača, odbija se od objekta i vraća u prijemnik

Pretvaranje tog vremena u udaljenost traži jednu malu korekciju:

Udaljenost = (Vrijeme × 0.0343) ÷ 2

ℹ️
Dijeljenje s dva je dio koji ljudi zaboravljaju. Zvuk je morao otputovati do objekta i onda cijeli put natrag, pa je štoperica izmjerila put u oba smjera. Objekt je udaljen samo pola toga.

Na ovom modulu taj račun nikada ne moraš raditi sam. Ljubičasta prilagodna pločica ima svoj mali mikrokontroler koji vodi štopericu, obavi računanje i drži odgovor pripremljen da ga pokupiš.


Postavljanje I2C veze

Qwiic kabel nije četiri odvojene žice koje vodiš kamo želiš. To je fiksni svežnjić od četiri: 3.3 V, masa i dvije signalne linije sabirnice koja se zove I2C. Na NULA MINI te dvije signalne linije spojene su na IO6 i IO7. Nisu čak ni izvedene na headere, pa nema se što birati.

MicroPython te ipak tjera da to izgovoriš naglas:

i2c = I2C(0, scl=Pin(7), sda=Pin(6))

Čitaj to kao: koristi I2C periferiju 0, s linijom takta na IO7 i linijom podataka na IO6. 0 govori koji od hardverskih I2C blokova unutar čipa koristiti, scl je takt, a sda su podaci.

⚠️
Ova dva broja pinova nisu neobavezna i nisu zamjenjiva. MicroPython ne pretpostavlja koje pinove tvoj Qwiic konektor koristi, pa ti njihovo izostavljanje ili zamjena daje I2C sabirnicu usmjerenu na pogrešne pinove. Senzor tada nikada ne odgovori i skripta padne s OSError: [Errno 19] ENODEV, što izgleda kao pokvaren senzor, a samo je pogrešno upisan broj pina. scl=Pin(7), sda=Pin(6), svaki put.
ℹ️
To je prava razlika u odnosu na Arduino. Tamo biblioteka poziva Wire.begin() bez argumenata, a pinovi dolaze od pločice koju si odabrao u IDE-u, pa skica koja ne imenuje pinove i dalje radi, dokle god je odabrana prava pločica. MicroPython nema odabir pločice, pa pinovi umjesto toga žive u tvom kodu. Biti izričit je više tipkanja, ali jedna stvar manje koja može tiho poći po zlu.

Objekt senzora zatim se stvara s I2C vezom, i bez vlastitih brojeva pinova:

sensor = UltrasonicSensor(i2c)

Ono što driver mora znati je s kojim modulom na kabelu razgovara, jer I2C dopušta da nekoliko modula dijeli jedan par žica. Svaki od njih odgovara na svoj broj, koji se zove adresa, a adresa ovog senzora je 0x30. Driver to već zna, i zato je ne predaješ.

ℹ️
Ovo je uzorak za svaki Qwiic modul u kitu. LCD u sekciji 4 i senzor temperature u sekciji 5 stvaraju se na isti način, iz istog i2c objekta, jer sjede na istim dvjema žicama na različitim adresama.

Dobavljanje drivera na pločicu

Driver je kod koji je napisao netko drugi a ti ga posuđuješ. Bez njega bi morao sam mjeriti vrijeme pulsa odjeka i sam raditi računanje; s njim pozoveš getDistance() i dobiješ broj.

Ovom primjeru treba UltrasonicSensor.py, koji živi u lib folderu repozitorija primjera zajedno s Qwiic.py, dijeljenim helperom na kojem je izgrađen. Za razliku od Arduina, gdje Library Manager instalira u IDE na tvom računalu, MicroPython driver mora biti kopiran na samu pločicu. Pločica je ono što izvršava kod, i može uvesti samo ono što nađe u svom /lib folderu.

Ako si prošao Postavljanje MicroPythona, sva četiri drivera već su na mjestu. Ako nisu, najbrži način je pomoću mip:

mpremote mip install github:SolderedElectronics/Soldered-NULA-Beginner-kit-MicroPython-project-examples/lib
⚠️
Ako se skripta zaustavi s ImportError: no module named 'UltrasonicSensor', driver nije na pločici, ili je sletio negdje drugdje osim u /lib. Spajanje i senzor nisu problem. Prekopiraj lib folder i pokreni ponovno.

Čitanje senzora ide u dva koraka

Skripta ne traži jednostavno udaljenost. Umjesto toga radi ovo:

sensor.takeMeasure()
time.sleep_ms(MEASURE_WAIT_MS)
distance = sensor.getDistance()

Tri linije gdje si možda očekivao jednu, a razlog je to što mjerenje traži stvarno vrijeme. takeMeasure() govori senzoru da ode i obavi posao: pošalje cvrkut, sluša, vodi štopericu, spremi odgovor. Taj zahtjev se vraća odmah. Pločica je samo poslala uputu, nije čekala rezultat.

Senzoru zatim treba trenutak. Odustaje od slušanja nakon oko 38 milisekundi ako odjek nikada ne dođe, pa mjerenje u najgorem slučaju može toliko trajati. Skripta čeka 50 ms, ugodno dulje, prije nego getDistance() pokupi gotov odgovor.

ℹ️
Pitaj prerano i dobit ćeš prethodnu vrijednost, ili ništa smisleno. Ovo razdvajanje na "pokreni posao" i "pokupi rezultat" vrlo je često kod senzora, pa ga vrijedi prepoznati.

begin() se poziva jednom prije nego petlja počne. Za Qwiic senzor to otvara razgovor na adresi modula, a senzor bi uvijek trebao biti inicijaliziran prije nego iz njega čitaš.

Nije svaki broj pravo mjerenje

Ovaj senzor radi od oko 2 centimetra do oko 4 metra. Dalje od toga zvuk se vraća preslab da bi ga se prepoznalo, a senzor nema načina da ti to kaže. Nema odgovor "nije nađeno". Jednostavno ti ipak preda broj.

U praksi taj broj izađe vrlo velik, negdje blizu 1000 cm, i pomiče se po nekoliko centimetara od vrijednosti do vrijednosti. Deset metara je daleko izvan svega što ovaj senzor stvarno može čuti, pa vrijednost od nekoliko stotina centimetara ili više tretiraj kao "ništa nije nađeno", a ne kao daleki objekt.

Ista se stvar događa i s objektom dobro unutar dosega, ako je taj objekt slučajno mekan ili strmo zakrenut od senzora. Jastuci, zavjese i džemperi upijaju zvuk; tvrda ravna površina okrenuta pravo prema senzoru odbija ga najbolje.

Skripta također provjerava vrijednost točno 0 i ispisuje No echo received, nothing in range. umjesto udaljenosti. Nula je ono što senzor odgovori kada nije čuo nikakav upotrebljiv odjek, što se događa i kada je nešto bliže od približno 3 cm: odjek dolazi prije nego je izlazni cvrkut završio, pa ga senzor nikada ne prepozna.


Kod

# I2C je način da nekoliko uređaja razgovara s pločicom preko samo dvije žice, i to je ono što Qwiic konektor
# nosi. Treba nam ovdje jer je senzor Qwiic modul.
from machine import I2C, Pin

# Uvoz modula daje nam pristup gotovim funkcijama koje teški posao rade za nas. Ovdje uvozimo
# Soldered driver za ultrazvučni senzor udaljenosti, da ne moramo sami mjeriti vrijeme odjeka.
# Taj driver živi u lib folderu repozitorija primjera. Kopiraj cijeli lib folder na svoju pločicu,
# inače ga MicroPython neće moći naći.
from UltrasonicSensor import UltrasonicSensor
import time

# Ovdje postavljamo I2C vezu. Dva pina fiksirana su pločicom: na NULA MINI, I2C koristi IO6 za
# liniju podataka (SDA) i IO7 za liniju takta (SCL), a to su točno pinovi na koje je Qwiic konektor spojen.
# Uvijek ih sami imenujemo, jer pločica ne pretpostavlja koje pinove konektor koristi.
i2c = I2C(0, scl=Pin(7), sda=Pin(6))

# Ovdje stvaramo naš objekt senzora, koji smo nazvali "sensor", i predajemo mu I2C vezu. Objekt je naš način
# razgovora sa senzorom: svaku funkciju koju na njemu pozovemo, pozivamo preko ovog imena.
# Primijeti da za senzor ne predajemo nikakve brojeve pinova. Svaki Qwiic modul dijeli ista dva I2C pina, i zato
# ih možeš nalančati nekoliko zajedno, a ovaj senzor odgovara na adresi 0x30.
sensor = UltrasonicSensor(i2c)

# Ovoliko čekamo nakon što zatražimo mjerenje, u milisekundama. Senzor odustaje nakon 38
# milisekundi ako odjek ne dođe, pa čekamo malo dulje od toga.
MEASURE_WAIT_MS = 50

# begin() priprema senzor za upotrebu. Senzor bi uvijek trebao biti inicijaliziran prije nego počnemo čitati iz njega.
sensor.begin()

# Ispiši početnu poruku da znamo da se program uspješno pokrenuo.
print("Ultrasonic Measuring Distance Example started!")
print("Move an object in front of the sensor to see the distance change.")

# Petlja while True ponavlja se unedogled, pa se kod unutar nje izvršava dok ne zaustavimo program.
while True:

# Čitanje Qwiic senzora ide u dva koraka. takeMeasure() je prvi: traži od senzora da pošalje
# puls i izmjeri vrijeme odjeka. Senzor taj posao obavi sam i zapamti odgovor, i zato
# onda moramo čekati prije nego ga pokupimo.
sensor.takeMeasure()
time.sleep_ms(MEASURE_WAIT_MS)

# getDistance() je drugi korak: dohvaća odgovor koji je senzor izračunao i spremio, već
# pretvoren u centimetre.
distance = sensor.getDistance()

# Senzor odgovara s 0 kada nije čuo nikakav odjek, što se događa kada ništa nije u dosegu ili kada
# površina pred njim raspršuje zvuk. To nije pravo mjerenje, pa to i kažemo umjesto da
# prijavimo udaljenost od nule, što bi upućivalo na objekt koji dotiče senzor.
if distance == 0:
print("No echo received, nothing in range.")
else:
print("Distance: {} cm".format(distance))

# time.sleep() započinje pauzu u kodu, zadanu u sekundama. Bez ove pauze vrijednosti bi promicale
# daleko prebrzo da bi ih se pročitalo, a ona i pušta odjeke prošlog pulsa da se ugase prije sljedećeg.
time.sleep(0.5)
ℹ️
"Distance: {} cm".format(distance) gradi jedan string iz teksta i broja. {} je rezervirano mjesto, a format() ubacuje vrijednost u njega. To je MicroPython ekvivalent onih nekoliko poziva Serial.print() koje Arduino skica treba da bi sagradila istu liniju.

Što bi trebao vidjeti

Pritisni Run. Nakon dvije početne linije dobivaš novu vrijednost dvaput u sekundi.

Usmjeri senzor preko prostorije i mahni rukom pred njim, i brojevi prate ono što je najbliže:

Ultrasonic Measuring Distance Example started!
Move an object in front of the sensor to see the distance change.
Distance: 52 cm
Distance: 52 cm
Distance: 160 cm
Distance: 96 cm
Distance: 39 cm

Prve dvije vrijednosti stoje na 52 cm, a tu je najbliži objekt mirno stajao. Vrijednosti koje skaču (160 cm, 96 cm, 39 cm) su trenuci kada se nešto pomaknulo kroz vidno polje senzora, ili kada je zvuk umjesto toga našao nešto dalje.

ℹ️
Vrijednosti su cijeli centimetri, i kolebaju se po nekoliko čak i kada je sve savršeno mirno. To je normalno. To je iskrena točnost jeftinog ultrazvučnog senzora, a ne greška.

Sada usmjeri senzor u prazan prostor, ili pravo gore u strop, i slika se potpuno mijenja. Gotovo svaka linija sada pokazuje negdje između 996 i 1000 cm:

Distance: 997 cm
Distance: 999 cm
Distance: 996 cm
Distance: 1000 cm

To je način na koji ovaj senzor prijavljuje da nije našao ništa, kako je opisano iznad, a ne objekt deset metara daleko. Korisno je prepoznati taj skup vrijednosti, jer ti kaže da pločica i senzor savršeno dobro razgovaraju međusobno, a problem je samo u tome kamo je senzor usmjeren.

⚠️
Ako se skripta odmah zaustavi s OSError: [Errno 19] ENODEV, pločica ne može naći senzor na sabirnici. Provjeri prvo dva broja Pin u liniji I2C(), a zatim je li Qwiic kabel do kraja utisnut u oba svoja konektora.

Probaj sam: promijeni time.sleep(0.5) na kraju petlje u time.sleep(0.1) i pokreni ponovno. Vrijednosti sada dolaze oko šest puta u sekundi umjesto dvaput, i praćenje ruke koja se kreće postaje mnogo glađe. Skratiš li ga još mnogo više, svaki novi cvrkut izlazi dok se odjeci prošlog još odbijaju po prostoriji, što brojeve tjera da skaču.


Cijeli primjer

Pogledaj cijeli kod primjera na linku ispod:

3.1_Measuring_Distance.py

Primjer koji čita Qwiic ultrazvučni senzor udaljenosti i ispisuje udaljenost u konzolu.