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:

  1. Il sensore emette un’onda ultrasonica
  2. L’onda colpisce un ostacolo
  3. L’eco torna indietro
  4. 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:

  1. Invio impulso di 10 microsecondi al sensore
  2. Misura del tempo di ritorno
  3. Calcolo distanza
  4. Media di più misurazioni (per ridurre il rumore)
  5. 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:

  1. Invia un impulso al sensore:
    • LOW → HIGH per 10 microsecondi → LOW
  2. Questo attiva l’emissione dell’onda ultrasonica
  3. Usa pulseIn() per misurare il tempo di ritorno dell’eco
  4. 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:

  1. Viene eseguita continuamente nel loop()
  2. Ogni 50 ms:
    • legge una nuova distanza (readDistanceRaw())
  3. Salva i valori in un buffer
  4. 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:

  1. Chiama /distance
  2. Aggiorna il valore
  3. 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:

  1. Gestione client web
    • risponde alle richieste del browser
  2. Aggiornamento continuo sensore
    • misura distanza
    • aggiorna buzzer

Tutto gira in modo non bloccante e fluido

Riassunto logico del sistema

Il flusso è questo:

  1. ESP32 crea WiFi
  2. Smartphone si connette
  3. Sensore misura distanza continuamente
  4. Media dei valori → maggiore stabilità
  5. Buzzer segnala la distanza
  6. 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.

Ti sei iscritto alla newsletter

There was an error while trying to send your request. Please try again.

Quattrodispositivi utilizzerà le informazioni fornite in questo modulo per restare in contatto con te e fornire aggiornamenti del sito