Raspberry Pi

Raspberry Pi Mesafe Sensörü MQTT: Tank Seviyesi ve Varlık Algılama için HC-SR04

Bir HC-SR04 ultrasonik sensörü güvenli bir gerilim bölücüyle Raspberry Pi'ye bağlayın, gürültülü ölçümleri Python ile filtreleyin ve tank doluluk seviyesi ile varlık olaylarını panolar ve otomasyonlar için MQTT üzerinden yayınlayın.

Bir su tankının üzerine monte edilmiş ve seviye ölçümlerini gönderen bir Raspberry Pi'ye bağlı HC-SR04 ultrasonik sensör; Raspberry Pi mesafe sensörü MQTT projesi
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

HC-SR04 ile bir Raspberry Pi mesafe sensörü MQTT projesi, tek bir ucuz parçayla iki yaygın sorunu çözer: bir tank ne kadar dolu ve orada bir şey (ya da biri) var mı? Bu eğitimde ultrasonik sensörü güvenli şekilde bağlayacak, gpiozero ile Python'da kararlı ölçümler alacak ve bir panonun veya otomasyonun bunlara göre hareket edebilmesi için hem doluluk yüzdesini hem de varlık olaylarını MQTT üzerinden yayınlayacaksınız.

HC-SR04 Mesafeyi Nasıl Ölçer?

HC-SR04, TRIG pini 10 mikrosaniyelik bir darbe aldığında kısa bir 40 kHz ultrason patlaması gönderir, ardından yansıma geri dönene kadar ECHO pinini yüksekte tutar. Bu yankı darbesinin süresi ses hızıyla çarpılıp ikiye bölündüğünde mesafeyi verir. Sensör birkaç santimetreden birkaç metreye kadar çalışır; en iyi sonuçları bir su yüzeyi veya duvar gibi dik açıdaki düz, sert yüzeylere karşı verir.

Gerçek projeler için iki sonuç önemlidir. Birincisi, Pi yankı darbesini yazılımla zamanlamak zorundadır; bu yüzden Linux zamanlaması bir miktar titreşim (jitter) ekler, bunu filtreleyeceksiniz. İkincisi, ses hızı hava sıcaklığıyla değişir; bu nedenle soğuk bir sabah ile sıcak bir öğleden sonra arasında küçük bir kayma bekleyin. Bir tank seviyesi veya varlık dedektörü için her iki etki de yönetilebilir.

Gerilim Bölücü ile Kablolama

HC-SR04 5 V ile çalışır ve ECHO çıkışı da 5 V'tur; bu da bir Raspberry Pi GPIO pinine zarar verebilir. ECHO üzerinde her zaman bir gerilim bölücü kullanın:

HC-SR04 pini Bağlantı
VCC Pi 5 V (fiziksel pin 2)
GND Pi GND (fiziksel pin 6)
TRIG GPIO23 (fiziksel pin 16), doğrudan
ECHO GPIO24'e (fiziksel pin 18) 1 k direnç; GPIO24'ten GND'ye 2 k direnç

1 k ve 2 k çifti 5 V'u yaklaşık 3,3 V'a böler. 1 k ile 1,8 k veya 2,2 k kombinasyonu da çalışır. TRIG doğrudan bağlanabilir, çünkü Pi'nin 3,3 V çıkışı sensörü tetiklemek için yeterlidir. Modülün 3,3 V uyumlu sürümünü satın alırsanız dokümantasyonunu kontrol edin; bölücüye ihtiyacınız olmayabilir.

Yazılımın Kurulumu

sudo apt update
sudo apt install -y python3-venv python3-lgpio
mkdir -p ~/distance-mqtt && cd ~/distance-mqtt
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0" gpiozero

MQTT olmadan hızlı test:

python -c "from gpiozero import DistanceSensor; from time import sleep; s = DistanceSensor(echo=24, trigger=23, max_distance=4); sleep(1); print(round(s.distance * 100, 1), 'cm')"

Sensörü bir duvara doğrultun ve sonucu bir şerit metreyle karşılaştırın. Her zaman tam olarak max_distance değerini veren bir ölçüm, yankı algılanmadığı anlamına gelir; bu genellikle ECHO üzerindeki bir kablolama sorunudur.

İki Mod: Seviye ve Varlık

Aynı ölçüm iki şekilde yorumlanabilir ve betik ikisini de yayınlar:

Mod Hesaplama Topic Yayın zamanı Retained
Tank seviyesi (empty_distance - distance) / (empty_distance - full_distance) .../level Her 30 saniyede Evet
Varlık Histerezisli bir eşiğin altındaki mesafe .../presence Yalnızca değişiklikte Evet
Ham cm cinsinden medyan mesafe her iki payload'ın içinde

Her iki topic'i retained tutmak, herhangi bir zamanda açılan bir panonun güncel seviyeyi ve birinin orada olup olmadığını hemen göstermesi anlamına gelir. Varlığı yalnızca değişiklikte yayınlamak trafiği çok küçük tutar ve otomasyonları basitleştirir: abone olun ve her mesaja tepki verin.

Tankı Kalibre Etmek

Sensörü tankın tepesine, dimdik aşağı bakacak şekilde, giriş borusundan ve duvarlardan uzak monte edin. Ardından iki mesafe ölçün:

  1. EMPTY_CM: sensörden tabana (veya kullanılabilir en düşük seviyeye) olan mesafe.
  2. FULL_CM: sensörden dolu işaretindeki suya olan mesafe. Sensör yüzeyi ile en yüksek su seviyesi arasında en az sensörün birkaç santimetrelik minimum menzili kadar boşluk bırakın.

Her iki değeri de ortam değişkenlerinde ayarlayın. Betik, sıçramaların veya boş bir tankın imkansız değerler üretmemesi için sonucu yüzde 0 ile 100 arasında sınırlar.

Raspberry Pi Mesafe Sensörü MQTT Betiği

distance_mqtt.py olarak kaydedin:

#!/usr/bin/env python3
"""HC-SR04 tank level and presence detection over MQTT."""
import json
import os
import statistics
import time
import uuid

import paho.mqtt.client as mqtt
from gpiozero import DistanceSensor

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"distance-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/9c3d55/tank1")

EMPTY_CM = float(os.getenv("EMPTY_CM", "120"))
FULL_CM = float(os.getenv("FULL_CM", "20"))
PRESENCE_ON_CM = float(os.getenv("PRESENCE_ON_CM", "60"))
PRESENCE_OFF_CM = float(os.getenv("PRESENCE_OFF_CM", "80"))
LEVEL_INTERVAL = 30
SAMPLES = 7

sensor = DistanceSensor(echo=24, trigger=23, max_distance=4, queue_len=5)


def measure_cm():
    """Median of several readings, ignoring out-of-range values."""
    values = []
    for _ in range(SAMPLES):
        d = sensor.distance * 100
        if 2 < d < 399:  # 400 cm means no echo within max_distance
            values.append(d)
        time.sleep(0.06)  # let echoes die down between pings
    return statistics.median(values) if values else None


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection refused: {reason_code}")
        return
    print(f"Connected as {CLIENT_ID}")
    client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()

present = None
last_level = 0.0

try:
    while True:
        distance = measure_cm()
        now = time.time()
        if distance is None:
            print("No valid echo")
            time.sleep(1)
            continue

        # Presence with hysteresis: switch on below ON, off above OFF.
        new_present = present
        if distance < PRESENCE_ON_CM:
            new_present = True
        elif distance > PRESENCE_OFF_CM:
            new_present = False
        if new_present is not None and new_present != present:
            present = new_present
            payload = {"present": present, "distance_cm": round(distance, 1), "ts": int(now)}
            client.publish(f"{PREFIX}/presence", json.dumps(payload), qos=1, retain=True)
            print("presence", payload)

        if now - last_level >= LEVEL_INTERVAL:
            span = EMPTY_CM - FULL_CM
            percent = max(0.0, min(100.0, (EMPTY_CM - distance) / span * 100))
            payload = {"level_pct": round(percent, 1), "distance_cm": round(distance, 1), "ts": int(now)}
            client.publish(f"{PREFIX}/level", json.dumps(payload), qos=1, retain=True)
            print("level", payload)
            last_level = now

        time.sleep(0.5)
except KeyboardInterrupt:
    pass
finally:
    client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True).wait_for_publish(2)
    client.loop_stop()
    client.disconnect()
    sensor.close()

Gerçek bir kurulumda genellikle sensör başına tek bir mod kullanırsınız: bir tank sensörünün varlık olaylarına, bir kapı girişi sensörünün de doluluk seviyesine ihtiyacı yoktur. İkisini tek bir betikte tutmak deneme yapmayı kolaylaştırır; ihtiyacınız olmayan bloğu silebilirsiniz.

Medyan Filtreleme ve Histerezis Neden Önemli?

Ultrasonik ölçümler zaman zaman sıçrar: tank duvarından gelen başıboş bir yankı, sudaki bir dalgalanma veya Linux'taki bir zamanlama aksaklığı. Ortalama almak tek bir kötü değerin sonucu çekmesine izin verir; yedi ölçümün medyanı ise onu basitçe yok sayar. Histerezis farklı bir sorunu çözer. Histerezis olmadan tam eşikte duran bir kişi varlık durumunu saniyede birkaç kez açıp kapatır ve aboneleri olaylara boğar. Ayrı açma ve kapama mesafeleriyle durum bir kez değişir ve öyle kalır.

Çıktıyı Test Etmek

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-9c3d55 \
  -t 'connectmq/demo/9c3d55/tank1/#' -v

Elinizi sensöre doğru hareket ettirin: 60 cm'yi geçtiğinizde "present": true içeren bir presence mesajı, 80 cm'nin ötesine geçtiğinizde de false mesajı görünür. Her 30 saniyede bir level mesajı kalibrasyonunuza göre doluluk yüzdesini raporlar. Genel MQTT test broker'ının herkes tarafından okunabildiğini unutmayın; rastgele bir önek kullanın ve gerçek saha adlarını test topic'lerinden uzak tutun.

Verilerle Otomasyon

Seviye ve varlık bilgisi MQTT'ye ulaştığında otomasyon bir sensör sorunu olmaktan çıkıp bir abone sorununa dönüşür:

  1. Pompa kontrolü: ikinci bir betik veya Node-RED akışı level topic'ine abone olur ve seviye yüzde 20'nin altına düştüğünde Raspberry Pi röle MQTT denetleyicisi üzerinden bir pompayı çalıştırır, yüzde 90'ın üzerinde ise kapatır.
  2. Alarmlar: özel bir ConnectMQ broker'ında level_pct üzerindeki bir eşik alarm kuralı, MQTT eşik alarmları yazısında anlatıldığı gibi neredeyse boş bir tank konusunda sizi uyarır.
  3. Ev otomasyonu: Home Assistant retained presence topic'ini bir doluluk sensörü olarak okuyup ışıkları açabilir.

Şebeke elektriği olmayan uzak bir tankta pille çalışan bir seviye sensörüne ihtiyacınız varsa ESP32 su tankı seviye sensörü projesi derin uyku ile aynı payload'ı kullanır; böylece ikisi de aynı panoyu besleyebilir.

Sorun Giderme

Sorun Olası neden ve çözüm
Her zaman 400 cm okuyor Yankı algılanmıyor; bölücüyü ve ECHO kablolamasını kontrol edin
Ölçümler aşırı sıçrıyor Sensör tank duvarını görüyor; merkeze ve kenarlardan uzağa monte edin
Ölçümler gün içinde kayıyor Ses hızı sıcaklıkla değişir; yeniden kalibre edin veya sıcaklık kompanzasyonu ekleyin
Tankta yoğuşma hataları Dönüştürücüler üzerinde nem; su geçirmez bir ultrasonik modül kullanın
GPIO busy GPIO23 veya GPIO24'ü başka bir betik kullanıyor

Üretim Kurulumu

Bir çiftlikteki, atölyedeki veya binadaki bir tank için test broker'ından özel bir broker'a geçin. ConnectMQ, 8883 portunda TLS ve otomatik oluşturulan kimlik bilgileri sunan yönetilen bir MQTT broker hizmetidir. Ortam değişkenlerinde MQTT_PORT=8883, MQTT_USERNAME=YOUR_USERNAME, MQTT_PASSWORD=YOUR_PASSWORD, MQTT_CLIENT_ID=YOUR_CLIENT_ID ve farm1/water/tank1 gibi anlamlı bir önek ayarlayın, ardından betiği bir systemd servisi olarak çalıştırın. Raspberry Pi MQTT eğitimi servis dosyası şablonunu içerir ve burada kullanılan yeniden bağlanma davranışını açıklar.

ConnectMQ ile Başlayın

Seviye ve varlık verilerinizi her panonun ve otomasyonun erişebileceği bir bulut MQTT broker üzerine taşıyın. Kredi kartı gerekmeden ücretsiz Serverless planla ConnectMQ'ya kaydolun, bir broker oluşturun ve Pi'nizi dakikalar içinde TLS üzerinden bağlayın.

Sık Sorulan Sorular

HC-SR04 için gerçekten bir gerilim bölücüye ihtiyacım var mı?

Standart 5 V modül için evet. ECHO pini 5 V çıkış verir ve Raspberry Pi GPIO pinleri yalnızca 3,3 V için tasarlanmıştır.

HC-SR04, Raspberry Pi üzerinde ne kadar doğrudur?

Ölçümler medyan filtrelemeden geçirildiğinde iyi koşullarda yaklaşık bir santimetre doğruluk sağlar. Linux'taki yazılım zamanlaması ve sıcaklık değişiklikleri bir miktar sapma ekler.

HC-SR04 kapalı bir tankta su seviyesini ölçebilir mi?

Evet, yüzeye dimdik baktığı ve kuru kaldığı sürece. Nemli tanklarda su geçirmez bir ultrasonik modül daha uzun ömürlüdür.

Varlık bilgisi neden yalnızca değiştiğinde yayınlanıyor?

Bu, trafiği minimumda tutar ve otomasyonları basitleştirir. Mesaj retained olduğu için yeni aboneler yine de güncel durumu hemen alır.

İlgili yazılar

RC522 Okuyucu ile Raspberry Pi RFID MQTT Erişim Kaydı

Bir RC522 RFID okuyucuyu Raspberry Pi'ye bağlayın, etiketleri Python ile okuyun, yerel bir izin listesiyle karşılaştırın ve her erişim denemesini kayıt araçlarının, panellerin ve uyarı araçlarının tüketebileceği bir MQTT olayı olarak yayınlayın.

6 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.