7.3 Senzor za parkiranje
Ovaj projekt gradi senzor za parkiranje pri vožnji natraške koji već poznaješ iz automobila. Ultrazvučni senzor promatra prostor pred sobom, i što nešto dođe bliže, to buzzer piska brže. Priđi dovoljno blizu i piskanje se stopi u jedan neprekinut ton, a upali se svjetlo upozorenja.
To je prvi projekt koji na pločicu stavlja Qwiic modul i krug na breadboardu u isto vrijeme. Senzor dolazi na jednom kabelu, točno kao u sekciji 3.1, dok su buzzer iz sekcije 2.4 i LED-ica iz sekcije 3.2 spojeni ručno. Dva izlaza, jedan senzor, i mali dio logike vremena koji ih spaja.
U ovoj dokumentaciji naučit ćeš:
- Kako pobuđivati dva različita izlaza iz jedne jedine vrijednosti senzora.
- Kako nešto natjerati da se događa odabranom brzinom bez pauziranja programa, tako da mjerenje nikada ne prestaje.
- Zašto jedinicu u kojoj senzor odgovara treba provjeriti prije nego je usporediš s bilo čim.
- Što je slijepa zona senzora, i zašto zbog nje ovaj projekt utihne kada priđeš previše blizu.
- Kako lanac
if/elifjedan broj pretvara u pet različitih ponašanja.
Potreban hardver:
- 1x Soldered NULA MINI pločica
- 1x Breadboard
- 1x Ultrazvučni senzor udaljenosti (Qwiic)
- 1x Qwiic kabel
- 1x Pasivni buzzer
- 1x LED-ica (bilo koje boje)
- 1x otpornik od 330 Ω (narančasti-narančasti-smeđi)
- 5x Jumper žice
- 1x USB-C kabel
Spajanje komponenti
Oba pina koje ovaj projekt koristi su na f–j strani pločice: IO2 u redu 25 za buzzer, i IO5 u redu 28 za LED-icu. Tijelo pločice prekriva stupce f–i, pa su j25, j28 i j30 rupice u koje stvarno možeš uvesti žicu. Sve ostalo odvija se dalje duž iste f–j strane, dobro odmaknuto od pločice.
IO5 na f–j strani i IO18 na a–e strani, a red 25 je IO2 na f–j strani ali TX na a–e strani. Broji redove na istoj strani na koju utiskuješ.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.

2. Postavi buzzer i spoji ga na IO2
U ovom koraku događaju se tri stvari, jer pripadaju zajedno.
Prvo povuci jumper žicu iz j30 (GND) do plave − vodilice. Ta vodilica postaje dijeljena linija mase za sve ostalo u projektu.
Zatim utisni buzzer u f–j stranu s njegove dvije nožice u redu 15 i redu 14. Pogledaj vrh njegovog kućišta prije toga: uz oznaku HWDZ nalazi se mali + unutar kružića, i nožica na toj strani je pozitivna. Ta nožica ide u red 15.
Na kraju, jedna jumper žica iz j15 u j25 (IO2) da nosi zvuk, i jedna iz j14 do plave − vodilice da zatvori krug.

3. Izvedi IO5 do LED-ice i dodaj otpornik
Jedna jumper žica iz j28 (IO5) duž do j8. To je žica koja će uključivati svjetlo upozorenja.
Zatim otpornik od 330 Ω iz i8 u i6, premošćujući ta dva reda. Prstenovi mu se čitaju narančasti-narančasti-smeđi.

4. Dodaj LED-icu
LED-ica ide unutra s dugom nožicom u redu 6, redu koji otpornik napaja, i s kratkom nožicom u redu 5.

5. Spoji LED-icu na masu
Još jedna jumper žica, iz j5 (red u kojem je kratka nožica LED-ice) do plave − vodilice.

Lanac je sada zatvoren od kraja do kraja: IO5 → otpornik → LED-ica → GND.
6. Utisni ultrazvučni senzor
Senzoru ne trebaju rupice breadboarda uopće. To je Qwiic modul, pa jedan kabel nosi njegovo napajanje i njegove podatke zajedno, i ulazi samo na jedan način.
Utisni jedan kraj u Qwiic konektor pločice, onaj bijeli na rubu između tipki USER i RST, a drugi u bilo koji konektor na ljubičastoj ULTRASONIC SENSOR QWIIC pločici. Ima ih dva, po jedan na svakom kraju, spojena međusobno, pa nije važno koji odabereš.

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

ON. On postavlja adresu na koju senzor odgovara, a kod očekuje tvorničku postavku.7. Spoji pločicu na računalo
Okreni senzor tako da njegova dva srebrna pretvarača gledaju u prostoriju, drži prostor pred njima čistim, i utisni USB-C kabel.

Kako jedan broj postaje pet ponašanja
Sve što ovaj projekt radi dolazi iz jednog jedinog mjerenja, provučenog kroz lanac if i elif:
| Udaljenost | Buzzer | LED-ica |
|---|---|---|
| više od 100 cm | tih | ugašena |
| 60–100 cm | polagano piskanje, 800 ms razmaka | ugašena |
| 30–60 cm | srednje piskanje, 400 ms razmaka | ugašena |
| 10–30 cm | brzo piskanje, 150 ms razmaka | ugašena |
| manje od 10 cm | jedan neprekinut ton | upaljena |
Pločica te raspone provjerava od najšireg prema dolje i zaustavlja se na prvom koji se poklopi, i zato svaka provjera treba samo donju granicu. Kada dođe do elif distance > 30, sve iznad 60 već je obrađeno.
Piskanje bez zaustavljanja programa
Očit način da se napravi pisak je: zvuk uključen, sleep, zvuk isključen, sleep. Ova skripta to ne radi, a razlog vrijedi razumjeti, jer je to jedna od najkorisnijih ideja u cijelom kitu.
time.sleep() ne znači "čekaj u pozadini". Znači stani. Tijekom time.sleep(0.8) pločica ne radi ništa drugo uopće. Ne može mjeriti, ne može primijetiti da se približavaš, ne može reagirati. Senzor za parkiranje koji prestane gledati na osam desetinki sekunde odjednom nije baš senzor za parkiranje.
Zato skripta umjesto toga vodi zapis o vremenu:
last_beep = 0
beep_interval = 0
buzzer_on = False
time.ticks_ms() vraća koliko milisekundi pločica radi. U svakom prolazu kroz petlju skripta uspoređuje trenutak posljednje promjene s trenutkom sada, i djeluje samo kada je prošlo dovoljno vremena:
if beep_interval > 0:
now = time.ticks_ms()
if time.ticks_diff(now, last_beep) >= beep_interval:
last_beep = now
buzzer_on = not buzzer_on
if buzzer_on:
buzzer.duty_u16(SOUND_ON)
else:
buzzer.duty_u16(SOUND_OFF)
Operator not preokreće True u False i natrag, pa svaki put kada interval istekne buzzer se prebaci na obrnuto od onoga što je bio. Uključen, isključen, uključen, isključen: to iznova i iznova je ono što čuješ kao piskanje. Manji beep_interval znači manje čekanja između prebacivanja, a to je brže piskanje.
beep_interval = 0 koristi se kao zastavica koja znači "ne piskaj uopće". I tihi pojas i pojas s neprekinutim tonom postavljaju ga na nulu, jer u nijednom slučaju buzzer ne treba prebacivanje: jedan ostavlja zvuk isključen, drugi ga ostavlja uključen.Čitanje senzora, i ispravno čitanje
Tri detalja u kodu zaslužuju bliži pogled.
Ide u dva poziva, ne u jedan
sensor.takeMeasure()
time.sleep_ms(MEASURE_WAIT_MS)
reading = sensor.getDistance()
takeMeasure() samo traži od senzora da ode i obavi posao. Senzoru zatim treba trenutak (odustaje od slušanja nakon oko 38 milisekundi ako odjek ne dođe), pa skripta čeka 50 ms prije nego getDistance() pokupi gotov odgovor. To je u cijelosti objašnjeno u 3.1 Mjerenje udaljenosti.
To čekanje od 50 ms također je i jedina pauza u cijeloj petlji, i zato na njezinom dnu nema sleepa. Mjerenje postavlja tempo: oko dvadeset vrijednosti u sekundi.
Odgovor dolazi u milimetrima
distance = reading // 10
Senzor prijavljuje udaljenost u milimetrima, pa vrijednost 250 znači 25 centimetara. Svaki prag dalje u skripti napisan je u centimetrima, jer bi tako osoba opisala udaljenost, pa se vrijednost ovdje pretvori jednom, a pretvorena vrijednost je ono s čime lanac if uspoređuje. // je cjelobrojno dijeljenje: odbacuje ostatak i drži vrijednost cijelim brojem, pa 253 milimetra postaje 25 centimetara.
distance > 100 značio bi 10 cm a ne 1 m, i cijeli senzor za parkiranje na kraju bi radio samo unutar mjehurića od 10 cm. Kad god koristiš novi senzor, provjeri u kojoj jedinici odgovara prije nego ga usporediš s bilo čim.Nula nije udaljenost
if reading == 0:
print("No echo received, nothing in range.")
buzzer.duty_u16(SOUND_OFF)
buzzer_on = False
led.value(0)
continue
Senzor odgovara 0 kad god nije čuo odjek koji može upotrijebiti, a to se događa u dvije suprotne situacije: kada ništa nije u dosegu, i kada je nešto bliže od oko 3 centimetra.
Druga ljude iznenađuje. Svaki ultrazvučni senzor ima slijepu zonu neposredno pred sobom. Senzor odašilje prasak zvuka i onda sluša da se vrati, ali se s vrlo blizu odjek vrati prije nego je prasak završio, pa dolazi dok senzor još govori i nikada ga ne čuje.
Nijedan slučaj nije pravo mjerenje. Kada bi skripta 0 tretirala kao udaljenost, čitalo bi se kao "nula centimetara daleko" i pokretalo bi alarm punom snagom kad god je put slobodan, pa umjesto toga sve gasi i čeka sljedeću vrijednost.
buzzer_on prije nego upotrijebi continue. Preskakanje ostatka petlje znači da se ništa od koda ispod ne izvršava, pa bi sve što je ostalo uključeno ostalo uključeno. Grana mora pospremiti za sobom.Kod
# Soldered driver za ultrazvučni senzor udaljenosti, koji se nalazi u lib folderu repozitorija primjera.
from UltrasonicSensor import UltrasonicSensor
# I2C je ono što Qwiic konektor nosi, PWM pobuđuje buzzer, a za LED-icu upozorenja dovoljan je običan Pin.
from machine import I2C, Pin, PWM
import time
# Ovo je varijabla kojoj predajemo broj pina na koji smo spojili buzzer.
# NULA pločica ima logiku imenovanja pinova ovako: IO2, gdje je 2 broj koji dajemo varijabli.
BUZZER_PIN = 2
# Ovo je varijabla kojoj predajemo broj pina na koji smo spojili LED-icu upozorenja.
# Zapamti da LED-ici treba otpornik od 330 ohma u seriji s njom.
LED_PIN = 5
# Ovo je frekvencija zvuka upozorenja, u hercima. Mali buzzeri kao ovaj najglasniji su negdje između
# 2 i 4 kHz, pa slobodno eksperimentiraj s ovom vrijednošću dok ti ne zvuči najbolje.
TONE_FREQ = 2700
# Ovoliko čekamo nakon što zatražimo mjerenje, u milisekundama. Senzor odustaje od slušanja odjeka
# nakon 38 milisekundi, pa čekanje malo dulje od toga znači da je odgovor uvijek gotov kada za njega pitamo.
# To čekanje također postavlja tempo cijele petlje, i zato na njezinom dnu nema pauze.
MEASURE_WAIT_MS = 50
# Ovdje postavljamo I2C vezu. 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.
i2c = I2C(0, scl=Pin(7), sda=Pin(6))
# Ovdje stvaramo naš objekt senzora i predajemo mu I2C vezu. Za senzor ne predajemo nikakve brojeve pinova:
# svaki Qwiic modul dijeli ta ista dva I2C pina, a ovaj senzor odgovara na adresi 0x30.
sensor = UltrasonicSensor(i2c)
# Ovdje stvaramo naš PWM objekt za buzzer i postavljamo mu visinu tona jednom, jer se u ovom projektu nikada ne mijenja.
# duty_u16() postavlja koji dio vremena pin ostaje uključen, a polovica cijelog raspona daje najčišći ton.
buzzer = PWM(Pin(BUZZER_PIN))
buzzer.freq(TONE_FREQ)
SOUND_ON = 32768
SOUND_OFF = 0
buzzer.duty_u16(SOUND_OFF)
# Ovdje stvaramo naš Pin objekt za LED-icu i pišemo u njega 0 da svjetlo upozorenja počne ugašeno.
led = Pin(LED_PIN, Pin.OUT)
led.value(0)
# Ove tri varijable su ono što nam dopušta piskanje različitim brzinama a da program nikada ne zaustavimo.
# "last_beep" pamti trenutak kada je buzzer posljednji put uključen ili isključen, "beep_interval" drži koliko želimo
# čekati između tih prebacivanja, a "buzzer_on" pamti oglašava li se buzzer trenutno ili je tih.
last_beep = 0
beep_interval = 0
buzzer_on = False
# begin() priprema senzor za upotrebu, prije nego počnemo čitati iz njega.
sensor.begin()
# Ispiši početnu poruku da znamo da se program uspješno pokrenuo.
print("Ultrasonic buzzer + LED reverse sensor started")
while True:
# Čitanje Qwiic senzora ide u dva koraka. takeMeasure() traži od senzora da pošalje puls i izmjeri vrijeme odjeka,
# a čekanje nakon toga daje mu trenutak koji mu treba da taj posao dovrši i spremi odgovor.
sensor.takeMeasure()
time.sleep_ms(MEASURE_WAIT_MS)
# getDistance() zatim dohvaća spremljeni odgovor. Primijeti jedinicu: senzor prijavljuje udaljenost u MILIMETRIMA,
# pa vrijednost 250 znači da je prepreka 25 centimetara daleko. Držimo je u varijabli imena "reading" da nas
# ime podsjeti da to još nije jedinica u kojoj želimo razmišljati.
reading = sensor.getDistance()
# Senzor odgovara s 0 kad god nije čuo odjek koji može upotrijebiti. To se događa u dvije suprotne situacije: kada
# ništa nije u dosegu, i kada je objekt bliže od oko 3 centimetra, jer se tada odjek vrati
# prije nego je senzor završio odašiljanje i on ga nikada ne čuje. Nijedno nije pravo mjerenje, a tretiranje
# jednog kao udaljenosti pokretalo bi alarm kad god je put slobodan, pa umjesto toga utihnemo i čekamo
# sljedeću. continue skače pravo natrag na vrh petlje.
if reading == 0:
print("No echo received, nothing in range.")
buzzer.duty_u16(SOUND_OFF)
buzzer_on = False
led.value(0)
continue
# Sada vrijednost pretvaramo u centimetre, jer bismo tako prirodno opisali udaljenost osobi, i
# tako je napisan svaki broj dalje u ovoj skripti. Deset milimetara čini jedan centimetar, pa dijelimo s deset.
# // je cjelobrojno dijeljenje, pa 253 milimetra postaje 25 centimetara, a to je i sva točnost koju ovaj
# senzor iskreno može ponuditi.
distance = reading // 10
# Ispiši izmjerenu udaljenost u konzolu da možemo pratiti dok testiramo.
print("Distance from obstacle: {} cm".format(distance))
# LED-icu gasimo na početku svakog prolaza kroz petlju. Samo je najbliži raspon nekoliko linija ispod
# ponovno pali, pa nas ta jedna linija poštedi toga da je gasimo u svakom drugom slučaju.
led.value(0)
# Ovaj lanac if izjava je srce projekta: pretvara udaljenost u brzinu piskanja. Svaki raspon
# dobiva drugačiju vrijednost beep_interval, a manji interval znači manje čekanja između pisaka, što čujemo
# kao brže piskanje. Pločica raspone provjerava od najšireg prema dolje i zaustavlja se na prvom koji se poklopi.
if distance > 100:
# Ništa u dosegu. Interval od 0 drži buzzer tihim, a ovdje se pobrinemo da stvarno i jest tih.
beep_interval = 0
buzzer.duty_u16(SOUND_OFF)
buzzer_on = False
elif distance > 60:
# Između 60 i 100 cm, piskaj polagano.
beep_interval = 800
elif distance > 30:
# Između 30 i 60 cm, piskaj srednjom brzinom.
beep_interval = 400
elif distance > 10:
# Između 10 i 30 cm, piskaj brzo.
beep_interval = 150
else:
# Bliže od 10 cm. Ovdje zvuk ostavljamo uključenim umjesto da piskamo, što pravi jedan neprekinut ton,
# i palimo LED-icu kao konačno upozorenje.
buzzer.duty_u16(SOUND_ON)
buzzer_on = True
beep_interval = 0
led.value(1)
# Ovdje se samo piskanje događa. Usporedbom time.ticks_ms() s trenutkom posljednjeg prebacivanja
# možemo čekati pravu količinu vremena bez pauziranja programa, što bi nas zaustavilo u mjerenju.
# Svaki put kada interval prođe, buzzer_on preokrenemo u obrnutu vrijednost operatorom "not", pa
# zvuk ili pokrenemo ili zaustavimo. To iznova i iznova je ono što proizvodi pisak.
if beep_interval > 0:
now = time.ticks_ms()
if time.ticks_diff(now, last_beep) >= beep_interval:
last_beep = now
buzzer_on = not buzzer_on
if buzzer_on:
buzzer.duty_u16(SOUND_ON)
else:
buzzer.duty_u16(SOUND_OFF)
Što bi trebao vidjeti
Pritisni Run. Skripta se najavljuje:
Ultrasonic buzzer + LED reverse sensor started
Od tada dobivaš liniju oko dvadeset puta u sekundi. Pomiči ruku polako prema senzoru i gledaj kako brojevi padaju:
Distance from obstacle: 26 cm
Distance from obstacle: 21 cm
Distance from obstacle: 12 cm
Distance from obstacle: 25 cm
Distance from obstacle: 10 cm
Distance from obstacle: 7 cm
Distance from obstacle: 4 cm
12 cm na 25 cm i odmah natrag na 10 cm. Ta zalutala vrijednost je normalna. Ultrazvučni senzor ponekad ulovi odjek s tvog rukava, stola ili ruba ruke umjesto s njezine ravnine. Ovdje to nije važno, jer druga vrijednost dolazi 50 milisekundi kasnije. To vrijedi zapamtiti kad god koristiš senzor udaljenosti: sudi ga po nizu vrijednosti, nikada po jednoj.To jedno izvođenje prolazi kroz kraj projekta. Vrijednosti počinju oko 26 cm, a to je brzo piskanje. Prelaze 10 cm oko trećine niz ispis, i od tamo piskanje prestaje i drži jedan neprekinut ton, a svjetlo upozorenja se upali:

Prinesi ruku polaganije od ovoga i na putu prema dolje čut ćeš sve tri brzine piskanja: polagano od 1 m, srednje od 60 cm, brzo od 30 cm.
Kada pred senzorom nema ničega, ili kada je nešto priljubljeno uz njega, umjesto toga dobiješ ovo:
No echo received, nothing in range.
Ako ništa ne piska, provjeri da su dvije nožice buzzera u dva različita reda i da jumper žica s IO2 sleti u isti red kao + nožica.
Ako ton nikada ne postane neprekinut, ili nisi dovoljno blizu, ili si previše blizu. Zapamti slijepu zonu: objekt koji dotiče pretvarače tjera senzor da prestane odgovarati, i sve utihne. Oko 5 cm je zlatna sredina.
Ako ton postane neprekinut ali LED-ica ostane tamna, kod radi svoj posao a greška je u krugu. Provjeri prvo je li LED-ica postavljena na pravu stranu: duga nožica pripada u red 6, okrenuta prema otporniku.
Ako se skripta zaustavi s IndexError: index out of range i pokazuje unutar UltrasonicSensor.py, pločica do senzora uopće ne dolazi. Driver sam hvata I2C grešku i vraća prazan odgovor, pa je ono što vidiš linija koja tu prazninu pokušava pročitati, a ne pritužba na sabirnicu. Provjeri scl=Pin(7), sda=Pin(6) u liniji I2C(), pa ponovno utisni oba kraja Qwiic kabela.
Cijeli primjer
Pogledaj cijeli kod primjera na linku ispod:
7.3_Parking_sensor.py
Projekt koji pomoću ultrazvučnog senzora, buzzera i LED-ice simulira sustav upozorenja pri parkiranju natraške.