Come realizzare un sensore di parcheggio con ultrasuoni (guida completa)
Introduzione
Quando si parla di robotica o di sistemi intelligenti per il monitoraggio dell’ambiente, spesso si pensa subito alle telecamere. In effetti, imitare la vista umana è stata una delle prime soluzioni adottate.
Tuttavia, le telecamere hanno un limite importante: funzionano male in condizioni di scarsa illuminazione o in presenza di ostacoli visivi (come nebbia o nuvole). Per questo motivo, in molte applicazioni si utilizzano tecnologie alternative, come i sensori ultrasonici.
In questo articolo vediamo come realizzare un semplice ma efficace sensore di parcheggio per garage, utilizzando un sensore a ultrasuoni e un microcontrollore.
Perché usare un sensore ultrasonico?
A differenza delle telecamere, i sensori ultrasonici:
- funzionano anche al buio
- non dipendono dalla luce
- sono economici e facili da usare
Questa tecnologia è utilizzata anche in ambiti avanzati, come nei satelliti (radar SAR) e nei robot domestici.
Il principio di funzionamento (come un pipistrello!)
Il funzionamento è ispirato alla natura, in particolare ai pipistrelli.
Il principio è semplice:
- Il sensore emette un’onda ultrasonica
- L’onda colpisce un ostacolo
- L’eco torna indietro
- Si misura il tempo impiegato
Da questo tempo possiamo calcolare la distanza.
Come si calcola la distanza
La distanza si ricava da una formula molto semplice:
- distanza = (velocità × tempo) / 2
Dividiamo per 2 perché il tempo misurato include sia l’andata che il ritorno dell’onda.
A temperatura ambiente (circa 20°C), la velocità del suono è:
- 343 m/s
Attenzione alla temperatura
La velocità del suono non è costante: varia con la temperatura.
Ad esempio:
- -10°C → circa 325 m/s
- 20°C → circa 343 m/s
Nel nostro caso (garage), l’errore massimo è circa 5%, quindi possiamo tranquillamente ignorarlo.
Ma volendo, si può aggiungere un sensore di temperatura per maggiore precisione.

Come funziona il sensore (dentro il dispositivo)
Il sensore ultrasonico è composto da:
- Trasmettitore
- Ricevitore
Entrambi utilizzano un materiale chiamato piezoelettrico.
Cosa fa il materiale piezoelettrico?
- Se applichi tensione → si deforma → genera un’onda sonora
- Se riceve un’onda → si deforma → genera tensione
Questo permette sia di trasmettere che di ricevere ultrasuoni.
Il progetto: sensore di parcheggio per garage
L’idea è semplice ma molto utile:
- montare il sensore sul muro del garage
- misurare la distanza dall’auto
- visualizzare i dati sul cellulare
- aggiungere un buzzer per segnalazione sonora
Come funziona il feedback
- Più ti avvicini → più il buzzer suona velocemente
- Sul telefono → vedi la distanza in tempo reale
Connessione: ESP32 come Access Point
Il sistema utilizza un microcontrollore (ESP32) configurato come Access Point WiFi.
Questo significa che:
- NON serve una rete WiFi in garage
- il dispositivo crea la sua rete
- ti connetti direttamente con lo smartphone
E puoi visualizzare i dati tramite una semplice pagina web.
Logica del software
Il codice segue questi passaggi:
- Invio impulso di 10 microsecondi al sensore
- Misura del tempo di ritorno
- Calcolo distanza
- Media di più misurazioni (per ridurre il rumore)
- Aggiornamento:
- display web
- buzzer
#include <WiFi.h>
#include <WebServer.h>
// ===== WIFI =====
const char* ssid = "GarageSensor";
const char* password = "12345678";
WebServer server(80);
// ===== PIN =====
#define TRIG 5
#define ECHO 18
#define BUZZER 23
// ===== DISTANZA =====
float distance = 400;
// ===== TIMER =====
unsigned long lastSensorRead = 0;
unsigned long sensorInterval = 50;
int sampleIndex = 0;
float sampleSum = 0;
// ===== BUZZER =====
unsigned long lastBeep = 0;
// ===== LETTURA RAW =====
float readDistanceRaw() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long duration = pulseIn(ECHO, HIGH, 20000);
float d = duration * 0.034 / 2;
if (d == 0 || d > 400) return 400;
return d;
}
// ===== BUZZER =====
void updateBuzzer(float d) {
unsigned long now = millis();
int interval;
int frequency;
if (d > 100) {
noTone(BUZZER);
return;
}
else if (d > 50) {
interval = 800;
frequency = 1000;
}
else if (d > 20) {
interval = 300;
frequency = 1500;
}
else {
interval = 100;
frequency = 2000;
}
if (now - lastBeep > interval) {
tone(BUZZER, frequency, 50); // beep 50 ms
lastBeep = now;
}
}
// ===== TASK SENSOR =====
void updateSensor() {
unsigned long now = millis();
if (now - lastSensorRead >= sensorInterval) {
lastSensorRead = now;
float d = readDistanceRaw();
sampleSum += d;
sampleIndex++;
if (sampleIndex >= 5) {
distance = sampleSum / 5;
sampleSum = 0;
sampleIndex = 0;
updateBuzzer(distance);
}
}
}
// ===== API =====
void handleDistance() {
server.send(200, "text/plain", String(distance));
}
// ===== PAGINA WEB =====
void handleRoot() {
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: Arial;
text-align: center;
margin-top: 40px;
}
#distance {
font-size: 50px;
font-weight: bold;
}
.bar {
width: 80%;
height: 30px;
background: lightgray;
margin: 30px auto;
border-radius: 20px;
overflow: hidden;
}
.fill {
height: 100%;
width: 0%;
background: green;
transition: width 0.3s, background 0.3s;
}
</style>
</head>
<body>
<h1>Sensore Parcheggio</h1>
<div id="distance">-- cm</div>
<div class="bar">
<div class="fill" id="fill"></div>
</div>
<script>
function update() {
fetch('/distance')
.then(r => r.text())
.then(data => {
let d = parseFloat(data);
document.getElementById("distance").innerHTML = d + " cm";
let fill = document.getElementById("fill");
// Percentuale barra (max 200 cm)
let percent = Math.max(0, Math.min(100, (200 - d)));
fill.style.width = percent + "%";
// Colore dinamico
if (d > 100) {
fill.style.background = "green";
}
else if (d > 50) {
fill.style.background = "yellow";
}
else {
fill.style.background = "red";
}
});
}
setInterval(update, 500);
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
// ===== SETUP =====
void setup() {
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(BUZZER, OUTPUT);
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("Access Point attivo");
Serial.println(WiFi.softAPIP());
server.on("/", handleRoot);
server.on("/distance", handleDistance);
server.begin();
}
// ===== LOOP =====
void loop() {
server.handleClient();
updateSensor();
}
Descrizione codice
1. Funzione readDistanceRaw()
Questa è la funzione più importante: misura la distanza reale.
Cosa fa:
- Invia un impulso al sensore:
- LOW → HIGH per 10 microsecondi → LOW
- Questo attiva l’emissione dell’onda ultrasonica
- Usa pulseIn() per misurare il tempo di ritorno dell’eco
- Converte il tempo in distanza
Formula utilizzata:
- distanza = tempo × 0.034 / 2
(dove 0.034 cm/µs è la velocità del suono)
Gestione errori:
if (d == 0 || d > 400) return 400;
Se non viene rilevato nulla, restituisce 400 cm (considerato “nessun ostacolo”).
2. Funzione updateBuzzer(float d)
Gestisce il comportamento del buzzer in base alla distanza.
Logica:
- > 100 cm → nessun suono
- 50–100 cm → beep lento
- 20–50 cm → beep medio
- < 20 cm → beep veloce
Come funziona tecnicamente:
- Usa millis() per non bloccare il programma
- Genera beep brevi (50 ms) con tone()
- Frequenza e intervallo cambiano con la distanza
Più ti avvicini al muro → più il suono diventa rapido e acuto
3. Funzione updateSensor()
Questa funzione è il “motore” del sistema.
Cosa fa:
- Viene eseguita continuamente nel loop()
- Ogni 50 ms:
- legge una nuova distanza (readDistanceRaw())
- Salva i valori in un buffer
- Dopo 5 letture:
- calcola la media
- aggiorna la distanza globale
- aggiorna il buzzer
Perché è importante?
Riduce il rumore e gli errori del sensore
Rende la misura più stabile
4. API handleDistance()
Questa funzione crea un piccolo endpoint web:
/distance
Cosa fa:
- Restituisce la distanza come testo semplice
server.send(200, “text/plain”, String(distance));
Serve alla pagina web per aggiornare i dati in tempo reale
5. Funzione handleRoot()
Questa è la parte più “visibile”: crea la pagina web.
Contenuto della pagina:
- Titolo: Sensore Parcheggio
- Distanza in grande
- Barra grafica colorata
JavaScript integrato:
Ogni 500 ms:
- Chiama /distance
- Aggiorna il valore
- Aggiorna la barra
Logica grafica:
- Verde → lontano
- Giallo → medio
- Rosso → vicino
È una mini interfaccia real-time molto efficace
6. Setup (setup())
Qui viene inizializzato tutto.
Operazioni principali:
- Configura i pin:
- pinMode(TRIG, OUTPUT);
- pinMode(ECHO, INPUT);
- pinMode(BUZZER, OUTPUT);
- Attiva ESP32 come Access Point:
- WiFi.softAP(ssid, password);
- Avvia il server web:
- server.on(“/”, handleRoot);
- server.on(“/distance”, handleDistance);
- server.begin();
Il dispositivo crea una rete WiFi a cui puoi collegarti direttamente
7. Loop (loop())
È il ciclo principale del programma.
server.handleClient();
updateSensor();
Due cose fondamentali:
- Gestione client web
- risponde alle richieste del browser
- Aggiornamento continuo sensore
- misura distanza
- aggiorna buzzer
Tutto gira in modo non bloccante e fluido
Riassunto logico del sistema
Il flusso è questo:
- ESP32 crea WiFi
- Smartphone si connette
- Sensore misura distanza continuamente
- Media dei valori → maggiore stabilità
- Buzzer segnala la distanza
- Pagina web aggiorna i dati in tempo reale
Considerazioni (molto importanti)
Hai fatto alcune scelte molto intelligenti:
✔ Media su 5 campioni → ottima stabilità
✔ Uso di millis() → niente blocchi
✔ Web server integrato → niente app necessaria
✔ Access Point → funziona anche senza internet
Attenzione ai livelli logici (3.3V vs 5V)
Uno degli aspetti più importanti è la compatibilità elettrica:
- ESP32 → 3.3V
- Sensore → spesso 5V
Problema:
- il segnale di ritorno può danneggiare l’ESP32
❌ Soluzione non ideale:
- partitore resistivo
✅ Soluzione corretta:
- traslatore di livello logico
Componenti utilizzati
- Sensore ultrasonico (tipo HC-SR04 compatibile 3.3V)
- ESP32
- Buzzer (es. HY006)
- Alimentazione
Il circuito è molto semplice e adatto anche a chi è alle prime armi.
Schema elettrico

Possibili miglioramenti
Puoi espandere il progetto aggiungendo:
- sensore di temperatura
- display LCD
- notifiche su smartphone
- integrazione IoT
Conclusione
Questo progetto dimostra come, con pochi componenti e un po’ di codice, sia possibile realizzare un sistema utile nella vita quotidiana.
Abbiamo visto:
- come funzionano i sensori ultrasonici
- come calcolare la distanza
- come realizzare un sistema completo di parcheggio
È un ottimo progetto sia didattico che pratico, perfetto per chi vuole approfondire elettronica e microcontrollori.







