Čidlo využívající ultrazvuku pro měření vzdálenosti na délku až 4 metrů.
Velice přesné měření vzdálenosti, s přesností +/- 3mm na vzdálenost do 4 metrů. Dá se použít téměř ke všemu, funguje na principu odrazu od překážky. Maximální dálka měření ale zaleží na napájení a jeho kvalitě.
Novější model RCWL-9610, které má inteligentnější komunikační čip a nativně umí I2C, UART a 1Wire režimy, které se volí proletováním propojek na zadní straně. Dále popsané řešení nebude s tímto novějším čidlem fungovat, pokud nebudou správně propájené spojky a čidlo bude nastavené na I2C, UART nebo 1Wire. Čidlo se musí nastavit do původního režimu GPIO (TRIGGER — ECHO měření času ozvěny).
Specifikace:
-
Pracovní rozsah: 2-400cm
-
Vysoká přesnost: až 3mm
-
Pracovní úhel: <15 stupňů
-
Klidový proud:< 2mA
-
Napájecí napětí: 3.3 - 5VDC
-
Velikost: 45x20x16mm
Použití
Čidlo se musí napájet z 5V, při napájení 3.3V nefunguje. Toto je pro starší verzi čidla, poznáte ji podle obrázků





Pokud jsou propojky M1 a M2 nepropojeny (jako je na obrázku), čidlo je nastavené na práci v režimu GPIO a bude fungovat. Novejší verze funguje s napájecím napětím 3.3V.

Čidlo funguje tak, že se na TRIG pin přivede impuls o délce minimálně \(10 \mu s\) a potom se měří časová délka impulsu na pinu ECHO. Po obdržení TRIG pulsu čidlo vyšle ultrazkukový tón o kmitočtu 40 kHz a čeká na ozvěnu tohoto zvuku. Doba mezi vysláním zvuku a ozvěnou je přímo úměrná dvojnásobku vzdálenosti, protože rychlost šížení zvuku ve vzduchu pokládáme za konstantní 334 m/s.
Délka impulsu na pinu ECHO je přímo úměrná vzdálenosti podle vzorce:
\(s = \frac{\Delta t}{2} \cdot v\), kde s je vzálenost objektu, \(\Delta t\) je čas měření (rozdíl mezi náběžnou a sestupnou hranou pulsu na ECHO pinu) a \(v\) je rychlost šíření zvuku ve vzduchu.

Měření založené na událostech
Program pro měření je velmi jednoduchý. Pico SDK nám umožňuje pohodlně měřit čas s přesností na \(\mu s\) pomocí funkce time_us_64().
Tato funkce vrací 64bitové celé číslo, počet mikrosekund od startu mikrokontroléru.
Pico má v sobě registr iobank0_hw, kde jsou zaznamenány události, které se staly na pinu. Viz Měření pulsů pomocí událostí.
Nejprve vynulujeme události na pinu pomocí funkce gpio_get_events(uint gpio) a poté periodicky voláme funkci gpio_get_events(uint gpio), dokud nezachytíme událost.
Je to ve funkci mer_vzdálenost().
/*
* Měření vzdálenosti čidlem HC-SR04 v režimu trigger - echo
* na Raspberry Pi Pico
*
* (c) Jirka Chráska 2025; jirka@lixis.cz. Všechna práva vyhrazena.
*
* Redistribuce a použití zdrojových i binárních forem díla,
* v původním i upravovaném tvaru, jsou povoleny za následujících podmínek:
*
* Šířený zdrojový kód musí obsahovat výše uvedenou informaci o copyrightu,
* tento seznam podmínek a níže uvedené zřeknutí se odpovědnosti.
*
* Šířený binární tvar musí nést výše uvedenou informaci o copyrightu, tento seznam podmínek
* a níže uvedené zřeknutí se odpovědnosti ve své dokumentaci
* a/nebo dalších poskytovaných materiálech.
*
* Ani jméno vlastníka práv, ani jména přispěvatelů nemohou být použita při podpoře
* nebo právních aktech * souvisejících s produkty odvozenými z tohoto softwaru
* bez výslovného písemného povolení.
* TENTO SOFTWARE JE POSKYTOVÁN DRŽITELEM LICENCE A JEHO PŘISPĚVATELI „JAK STOJÍ A LEŽÍ“
* A JAKÉKOLIV VÝSLOVNÉ NEBO PŘEDPOKLÁDANÉ ZÁRUKY VČETNĚ, ALE NEJEN, PŘEDPOKLÁDANÝCH OBCHODNÍCH
* ZÁRUK A ZÁRUKY VHODNOSTI PRO JAKÝKOLIV ÚČEL JSOU POPŘENY. DRŽITEL, ANI PŘISPĚVATELÉ NEBUDOU
* V ŽÁDNÉM PŘÍPADĚ ODPOVĚDNI ZA JAKÉKOLIV PŘÍMÉ, NEPŘÍMÉ, NÁHODNÉ, ZVLÁŠTNÍ, PŘÍKLADNÉ NEBO
* VYPLÝVAJÍCÍ ŠKODY (VČETNĚ, ALE NEJEN, ŠKOD VZNIKLÝCH NARUŠENÍM DODÁVEK ZBOŽÍ NEBO SLUŽEB;
* ZTRÁTOU POUŽITELNOSTI, DAT NEBO ZISKŮ; NEBO PŘERUŠENÍM OBCHODNÍ ČINNOSTI) JAKKOLIV ZPŮSOBENÉ
* NA ZÁKLADĚ JAKÉKOLIV TEORIE O ZODPOVĚDNOSTI, AŤ UŽ PLYNOUCÍ Z JINÉHO SMLUVNÍHO VZTAHU,
* URČITÉ ZODPOVĚDNOSTI NEBO PŘEČINU (VČETNĚ NEDBALOSTI) NA JAKÉMKOLIV ZPŮSOBU POUŽITÍ TOHOTO
* SOFTWARE, I V PŘÍPADĚ, ŽE DRŽITEL PRÁV BYL UPOZORNĚN NA MOŽNOST TAKOVÝCH ŠKOD.
*/
#include "pico/stdlib.h"
#include "hardware/structs/iobank0.h"
#include <stdio.h>
#include "hardware/gpio.h"
#include "pico/time.h"
#include "pico/types.h"
uint TRIGGER_PIN = 0;
uint ECHO_PIN = 1;
uint LED_PIN = 25;
// přehled událostí na pinu
uint32_t gpio_get_events(uint gpio)
{
int32_t mask = 0xF << 4 * ( gpio % 8 );
return (iobank0_hw->intr[gpio / 8] & mask) >> 4 * ( gpio % 8 );
}
// vymazání událostí na pinu
void gpio_clear_events(uint gpio, uint32_t events)
{
gpio_acknowledge_irq(gpio, events);
}
// inicializace ultrazvukového čidla HC-SR04 (klasického)
void uzcidlo_init( uint trigger_pin, uint echo_pin )
{
gpio_init(trigger_pin);
gpio_init(echo_pin);
gpio_set_dir( trigger_pin, GPIO_OUT);
gpio_set_dir( echo_pin, GPIO_IN);
gpio_pull_down( echo_pin );
gpio_put(trigger_pin, 0);
}
// měření vzdálenosti v centimetrech
// měříme dobu mezi náběžnou a sestupnou hranou na echo pinu,
// polovina doby vynásobená rychlostí zvuku nám dá vzdálenost
// funkce vrací vzdálenost v centimetrech, v případě chyby vrací -1
float mer_vzdalenost(uint trigger_pin, uint echo_pin )
{
float centimetry = -1.0;
uint64_t t, rtime, ftime;
int i = 0;
uint32_t rise=0, fall=0;
gpio_put(trigger_pin, 1);
sleep_us(10);
gpio_put(trigger_pin, 0);
t = time_us_64();
gpio_clear_events( echo_pin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL );
// čekáme na nábežnou hranu na ECHO pinu
do {
rise = (gpio_get_events(echo_pin) & GPIO_IRQ_EDGE_RISE);
if( rise ) {
rtime = time_us_64();
break;
}
i++;
} while ( i<400000 ); // toto je timeout, když nedostáváme z čidla nic
// tento timeout je možné odstranit, ale má to za následek, že při poruše čidla
// nebo jeho připojení program bude viset a celé Pico se zakousne
if( ! rise ) { // nedostal jsem náběžnou hranu v časovém limitu
return centimetry;
}
gpio_clear_events( echo_pin, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL );
i = 0;
// čekáme na sestupnou hranu na ECHO pinu
do {
fall = (gpio_get_events(echo_pin) & GPIO_IRQ_EDGE_FALL);
if( fall ) {
ftime = time_us_64();
break;
}
i++;
} while ( i<400000 ); // toto je timeout, když nedostáváme z čidla nic
// tento timeout je možné odstranit, ale má to za následek, že při poruše čidla
// nebo jeho připojení program bude viset a celé Pico se zakousne
if( ! fall ) { // nedostal jsem sestupnou hranu v časovém limitu
return centimetry;
}
// rozdíl času mezi sestupnou a náběžnou hranou/2 * rychlost zvuku dává vzdálenost
centimetry = (ftime-rtime)*0.5*0.0343;
// printf("ftime - rtime: %llu us; vzdálenost %5.1f cm, měření trvalo: %llu us. \n",
// ftime-rtime, centimetry, ftime-t);
return centimetry;
}
// testování měření
// -----------------------------------------------------------------------
int main() {
float vzdalenost;
stdio_init_all();
sleep_ms(2000);
// nastavení ultrazvukového čidla HC-SR04
uzcidlo_init( TRIGGER_PIN, ECHO_PIN);
printf("Měření vzdálenosti čidlem HC-SR04.\n");
gpio_init( LED_PIN );
gpio_set_dir( LED_PIN, GPIO_OUT);
while (true) {
// blikáme LEDkou, abychom viděli, že žijeme
gpio_put( LED_PIN, 1);
sleep_ms(200);
vzdalenost = mer_vzdalenost(TRIGGER_PIN, ECHO_PIN);
if( vzdalenost > 0.0 ) {
printf( "Nejbližší objekt je %5.1f cm vzdálen.\n", vzdalenost );
} else {
printf( "Chyba měření.\n");
}
gpio_put( LED_PIN, 0);
sleep_ms(800);
}
}
// -----------------------------------------------------------------------
Celý program je velmi jednoduchý, do vašeho projektu si zkopírujte funkce
-
uint32_t gpio_get_events(uint gpio), -
void gpio_clear_events(uint gpio, uint32_t events), -
void uzcidlo_init( uint trigger_pin, uint echo_pin )a -
float mer_vzdalenost(uint trigger_pin, uint echo_pin )
a vložte
-
#include "hardware/structs/iobank0.h" -
#include "hardware/gpio.h"
a můžete čidlo používat.
Funce mer_vzdalenost() vrací -1.0 v případě chyby čidla.
Na začátku vašeho programu nezapomeňte zavolat funkci uzcidlo_init.
Doba jednoho měření je přibližne 5 ms.
| Pokud je překážka malá, nemusí být čidlem zachycena. Pokud není překážka kolmo na osu čidla (osu měření), měřená vzdálenost nebude zcela přesná. |
Celý projekt si můžete stáhnout: uzcidlo.tar.gz.
Měření vzdálenosti čidlem HC-SR04.
Nejbližší objekt je 10.8 cm vzdálen.
Chyba měření.
Nejbližší objekt je 10.3 cm vzdálen.
Chyba měření.
Nejbližší objekt je 10.8 cm vzdálen.
Chyba měření.
Nejbližší objekt je 10.7 cm vzdálen.
Chyba měření.
Nejbližší objekt je 10.8 cm vzdálen.
Chyba měření.
Nejbližší objekt je 10.7 cm vzdálen.
Chyba měření.
Nejbližší objekt je 8.7 cm vzdálen.
Nejbližší objekt je 29.7 cm vzdálen.
Nejbližší objekt je 28.4 cm vzdálen.
Nejbližší objekt je 27.9 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 29.8 cm vzdálen.
Nejbližší objekt je 28.9 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 29.4 cm vzdálen.
Nejbližší objekt je 29.8 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.1 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.5 cm vzdálen.
Nejbližší objekt je 28.9 cm vzdálen.
Nejbližší objekt je 29.8 cm vzdálen.
Knihovna založená na PIO
Knihovna Pico C++ HC-SR04 Library je psaná v C++, musíme proto dát příponu našemu programu buď .cxx nebo .cpp aby se spustil překladač C++.
Pokud budeme překládat překladačem C, tak program neslinkujeme s knihovnou.
Kvůli implementaci PIO je potřeba, aby echo pin byl o jednu větší než trigger pin.
Jestliže zapojíte trigger pin na GPIO5, potom echo pin musí být na GPIO6. (V našem případě používáme GPIO0 a GPIO1.)
Měření vzdálenost je s přesností na centimetry.
DistanceSensor(PIO pio, uint sm, uint trigger_gpio); (1)
| 1 | Parametr pio je PIO koprocesor, buď pio0 nebo pio1; parametr sm je state machine; parametr trigger_gpio je GPIO pin kam se připojí spouštecí pin (pin pro odpověď je o 1 větší). |
// Include the library
#include <stdio.h>
#include "pico/stdlib.h"
#include "distance_sensor.h"
int main() {
stdio_init_all();
// Create an instance of the sensor
// specify the pio, state machine, and gpio pin connected to trigger
// echo pin must be on gpio pin trigger + 1.
DistanceSensor hcsr04{pio0, 0, 0}; // pio0, state machine 0, GPIO0
while(1) {
// Trigger background sense
hcsr04.TriggerRead();
// wait for sensor to get a result
while (hcsr04.is_sensing) {
sleep_us(10);
}
// Read result
printf("Reading %d centimeters\n", hcsr04.distance);
sleep_ms(1000);
}
}
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(vzdalenost1 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
include_directories(
pico-distance-sensor/include
)
add_executable(vzdalenost1
main.cxx
)
add_subdirectory(pico-distance-sensor)
target_link_libraries(vzdalenost1
pico_stdlib
hardware_pio
hardware_irq
distance-sensor
)
pico_enable_stdio_usb(vzdalenost1 1)
pico_enable_stdio_uart(vzdalenost1 0)
pico_add_extra_outputs(vzdalenost1)
git clone https://github.com/dangarbri/pico-distance-sensor
cd mereni_vzdalenosti_HC-SR04
mkdir build
cd build
cmake ..
make -j12
minicom -b 115200 -D /dev/ttyACM0Reading 78 centimeters
Reading 34 centimeters
Reading 27 centimeters
Reading 48 centimeters
Reading 58 centimeters
Reading 49 centimeters
Reading 58 centimeters
Reading 58 centimeters
Reading 58 centimeters
Reading 49 centimeters
Reading 58 centimeters
Reading 48 centimeters
Reading 47 centimeters
Reading 46 centimeters
Reading 45 centimeters
Reading 46 centimeters
Reading 53 centimeters
Reading 51 centimeters
Reading 50 centimeters
Reading 49 centimeters
Reading 48 centimeters
Reading 38 centimeters
Reading 47 centimeters
Reading 47 centimeters
Závěr
Moje řešení měření vzdálenosti čidlem pomocí událostí na GPIO pinu mi přijde jednodušší na použití, je tam velmi málo kódu a je to dobře otestované. Je o něco pomalejší, ale nemusíme používat PIO automat. TRIGGER pin a ECHO pin si můžeme připojit, kam chceme, nemusí být nutně zapojeny za sebou.
Řešení pomocí knihovny Pico C++ HC-SR04 Library je rychlejší, použítí kódu je také velmi jednoduché. Nevýhodou je slučování kódu v C a C++. V případě poruchy čidla, kdy nedostáváme na ECHO pinu odpověď se program zakousne.