Pomiar poziomu cieczy

Tytuł brzmi wspaniale by odwrócić uwagę czytelników od faktu, że chodzi o czujnik poziomu nieczystości w szambie.  Zdarzyło mi się całkiem niedawno zapomnieć o konieczności sprawdzenia, czy już nie pora wezwać zaprzyjaźnionego szambelana.  O zaniedbaniu dowiedziałem się z nienacka, po wejściu do łazienki w piwnicy, gdzie w obniżeniu podłogi pod prysznicem wdzierała się do domu ciecz, rozsiewając zabójczą woń.  Był to piątek wieczór, sytuacja fatalna... Taki ze mnie magik od inteligentnych domów, a mam szambo w łazience.  Koniec.

Za 8$ kupiłem 5 czujników HC-SR04 na www.aliexpress.com.  Przesyłka doszła w 12 dni.  Cena śmieszna, a zapas się przyda, choćby dlatego, że podczas pracy łatwo coś popsuć. Czujniki te są bardzo proste w obsłudze - wystarczy podłączyć je do prądu (5V na nóżki VCC i GND), wysłać impuls na nóżkę Trig i czekać na odpowiedź (impuls) na nóżce Echo.  Czas pomiędzy wysłaniem impulsu a jego powrotem po przeliczewniu da zmierzoną odległość.

UltraSound0

Podłączenie czujnika do RPi oraz kod w PYTHONie w całości oparłem na pracy Matt'a Hawkins'a z raspberry-spy.co.uk.  Jako że zasilamy czujnik napięciem 5V, impuls echo, wracający do odczytu też będzie 5V.  To za dużo dla RPi, które akceptuje na GPIO 3,3V.  Należy więc napięcie obniżyć przy wykorzystaniu 2 oporników.  Oto schemat podłączenia znaleziony na raspberry-spy:

US RPi connection

W moim przypadku, jako że podłączam czujnik poprzez replikator GPIO, opisany w oddzielnym artykule, ochroną przed wyższym napięciem zajmują się diody zenera.  Opornik R330 jest też w standardzie.  Do skorzystania z czujnika HC-SR04 nie potrzebowałem więc nic.

Na obudowę wybrałem Z54JH firmy Kradex. Dodatkowo kupiłem na dziale elektrycznym zwykłe plastikowe rurki fi 18.  W obudowie wywierciłem otwory, rurki wkleiłem klejem dwuskładnikowym.  Po co w ogóle jakieś rurki? Podczas prób okazało się, że zbliżenie czujnika do pionowej ściany zakłóca odczyt.  W moim wypadku szambo jest ok 1,5m pod ziemią, prowadzi do niego studzienka z kręgów.  Czujnik jednak nie może być zbyt głęboko, by dało się go podłączyć, wymienić itd.  Stąd też od puszki do końca studzienki impulsy biegną w rurkach... Może tak być, że to zupełny bezsens i herezja, ale działa.  Odczyt zniekształcony jest o kilka cm, ale przecież nie chodzi mi o precyzyjny pomiar, ale o dane proporcjonalne...  Puste szambo da pomiar maksymalny, pełne minimalny... ostatecznie nie są w ogóle potrzebne jednostki.

UltraSound1

Ostateczny montaż trwał 2 tygodnie, jako że musiałem ułożyć 12m kabla i przełożyć na całej długości kostkę brukową.  Potem, zwiszony do pasa w studzience wierciłem i lutowałem wtyczkę (zrobioną z żeńskiej listwy goldpin-owej).  Ostatecznie całość wygląda następująco:

 UltraSound3

Jak widzicie, rurki przymocowane są zwykłą obejmą stosowaną w montażu instalacji elektrycznych.  Rozstaw rurek jest w niej nieco za duży... ale, jak się okazało, brak równoległego ułożenia nie przeszkadza w dokonywaniu pomiaru.

Teraz czas na programowanie. Oto plik do odczytu odległości (us.py):

#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# ultrasonic_1.py
# Measure distance using an ultrasonic module
#
# Author : Matt Hawkins
# Date   : 09/01/2013

# Import required Python libraries
import time
import RPi.GPIO as GPIO

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO = 24

# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Allow module to settle
time.sleep(0.5)

# Send 10us pulse to trigger
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
start = time.time()
while GPIO.input(GPIO_ECHO)==0:
  start = time.time()

while GPIO.input(GPIO_ECHO)==1:
  stop = time.time()

# Calculate pulse length
elapsed = stop-start

# Distance pulse travelled in that time is time
# multiplied by the speed of sound (cm/s)
distance = elapsed * 34000

# That was the distance there and back so halve the value
distance = distance / 2

print "%.1f" % distance

# Reset GPIO settings
GPIO.cleanup()

Aby umożliwić wysyłanie danych do PLC przygotowałem plik us.php.  Zwraca on odległość pomnożoną przez 10 i oddzieloną średnikiem, by do odczytu można było wykorzystać ten sam kod, który odczytuje temperatury (do znalezienia na dole innego artykułu):

<?php$
  level = exec('sudo python /var/python/us.py');
  echo $level*10;
  echo ";";
?>

 W celu wysyłania odczytów czujnika do bazy SQL (sql_us.py):

#!/usr/bin/python

import MySQLdb
import subprocess

from time import localtime, strftime
timer = strftime("%Y-%m-%d %H:%M:%S", localtime())

try:
  process = subprocess.Popen("/var/python/us.py", stdout=subprocess.PIPE)
  level = float(process.stdout.readline())*10

except:
  print timer + " : Error reading us distance (us.py)"

else:

  try:
    db = MySQLdb.connect("yourserver","youruser","yourpassword","yourdatabase")

  except:
    print timer + " : Error connecting to the SQL database"

  else:
    cursor = db.cursor()
    try:
      cursor.execute("INSERT INTO TankLevel(Time, Level)  VALUES (%s, %s)", (timer, level))
      db.commit()
      print timer + " : Sending data ok"
    except:
      db.rollback()
      print timer + " : Error executing query"

    db.close()

 Na koniec, aby wysyłanie danych odbywało się automatycznie, w można skonfigurować cron'a (crontab -e):

5 8,20 * * * /var/python/sql_us.py >> /var/python/log/sql_us.log 2>&1