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ść.
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:

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.
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:
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