Um den Wasserstand einer Zisterne zu ermitteln, wird der Wasserpegel benötigt. Warum also nicht mit einem Arduino gestützten Ultraschall-Sensor realisieren?
Gesagt getan - Um das Vorhaben umzusetzen, habe ich erst einmal eine Simulation mit thinkercad vorgenommen.
Das 10kΩ Potentiometer ist dazu da, um den Kontrast zu regeln. Den 200Ω Wiederstand habe ich zum Schutz der LED-Hintergrundbeleuchtung eingesetzt. Das Display soll später den Inhalt der Zisterne in Liter sowie den Prozentualen Anteil anzeigen.
Der Code des Mikrocontrollers sieht in der Simulation wie folgt aus:
#include <LiquidCrystal.h> // PINs LiquidCrystal lcd(7,8,9,10,11,12); const int signal = 6; // VARs const int durchgaenge = 3; float cm, dauer, dauergesamt; void setup() { // LCD lcd.begin(16, 2); } void loop() { // Reset Dauergesamt dauergesamt = 0; for (int i=0; i<durchgaenge; i++) { // Trigger für High Pulse pinMode(signal, OUTPUT); digitalWrite(signal, LOW); delayMicroseconds(2); digitalWrite(signal, HIGH); delayMicroseconds(10); digitalWrite(signal, LOW); // Erfassung - Dauer in Mikrosekunden pinMode(signal, INPUT); dauer = pulseIn(signal, HIGH); // Berechnung dauergesamt = dauergesamt + dauer; delay(500); } // Berechne Mikrosekunden in cm cm = ((dauergesamt/durchgaenge)/2)/29; // Ausgabe auf LCD lcd.clear(); lcd.setCursor(0,0); lcd.print(" Testmode"); lcd.setCursor(0,1); lcd.print("Abstand: "); lcd.print(round(cm), DEC); lcd.print(" cm"); delay(100); }
Ich habe in den Code mehrere Durchläufe eingebaut, um den cm-Durchschnitt zu ermitteln.
Die Berechnung stützt sich auf die physikalischen Eigenschaften von Ultraschall. Für einen cm benötigt der Ultraschall 29 Mikrosekunden. Da ich nur wissen möchte, wie lange der Schall für einen Weg benötigt, muss noch durch zwei geteilt werden.
Seit der Bestellung sind der Arduino sowie der Ultraschall-Sensor gekommen. Bisher sieht das Ganze noch so aus:
Der Unterscheid zur Simulation ist, dass der Ultraschallsensor 4-Pins, also einen mehr hat. Anstatt einen der beim Senden und Empfangen umgeschaltet werden muss, können diese fest definiert werden:
const int triggerPin = 5; //Trigger-Pin const int echoPin = 6; // Echo-Pin .. void setup() { // PIN-Modes pinMode(triggerPin, OUTPUT); pinMode(echoPin, INPUT); } void loop() { ... for (int i=1; i <=durchgaenge; i++) { // Trigger für High Pulse digitalWrite(triggerPin, LOW); delayMicroseconds(2); digitalWrite(triggerPin, HIGH); delayMicroseconds(10); digitalWrite(triggerPin, LOW); // Erfassung - Dauer in Mikrosekunden dauer = pulseIn(echoPin, HIGH); ... } }
Um den Sensor in der Zisterne geschützt anzubringen, hat sich ein Freund bereit erklärt, diesen Part umzusetzen. Mithilfe entsprechender CAD-Software und einem 3D-Drucker ist somit das Gehäuse für den Sensor entstanden. Einige Bilder dazu:
Mittlerweile ist auch das LCD-Display aus China angekommen. Zuerst habe ich die Steckleiste angelötet und wie geplant verkabelt. Funktionierte auf Anhieb!
Um den Füllstand über den cm-Wert zu ermitteln, haben wir mehrere Messungen durchgeführt. Der Ultraschall-Sensor soll später 20cm über dem Maximalstand angebracht werden:
Nach dem Übertrag in Excel und der Trendlinienfunktion, lies sich somit die Formel für den Füllstand ermitteln.
Dadurch konnte ich die Programmierung vorerst fertigstellen.
Um die Verkabelung im späteren Einbau einfach zu halten, habe ich mir ein I2C-Modul besorgt.
Dieses wird dann direkt an das Display gelötet und über (nur noch) zwei PINs angesprochen.
Die Verkabelung hat sich dann entsprechend entschlackt:
Mithilfe eines I2C-Scanners, entsprechender Bibliothek und Codeanpassung, ließ sich das Display dann auch problemlos ansprechen. Dadurch entfiel zusätzlich das Kontrast-Poti sowie der Hintergrund-Wiederstand.
Umsetzung/provisorischer Aufbau:
Der Mikrocontroller Code sieht jetzt nach der Anpassung wie folgt aus, die Ausgabe erfolgt in Zehnerschritten:
#include <Wire.h> #include <LiquidCrystal_I2C.h> // PINs LiquidCrystal_I2C lcd(0x3F, 16, 2); const int triggerPin = 5; const int echoPin = 6; // VARs const int cm_max = 20; const int cm_min = 106; const int liter_max = 1750; const int durchgaenge = 3; int liter, balken; float cm, dauer, dauergesamt; void setup() { // PIN-Modes pinMode(triggerPin, OUTPUT); pinMode(echoPin, INPUT); // LCD lcd.begin(); lcd.setCursor(3,0); lcd.print("Willkommen"); } void loop() { // Reset Dauergesamt dauergesamt = 0; for (int i=0; i<durchgaenge; i++) { // Trigger für High Pulse digitalWrite(triggerPin, LOW); delayMicroseconds(2); digitalWrite(triggerPin, HIGH); delayMicroseconds(10); digitalWrite(triggerPin, LOW); // Erfassung - Dauer in Mikrosekunden dauer = pulseIn(echoPin, HIGH); // Berechnung dauergesamt = dauergesamt + dauer; delay(500); } // Berechne Mikrosekunden in cm cm = ((dauergesamt/durchgaenge)/2)/29; // Berechne Liter if (cm < cm_max) { liter = liter_max; } else if (cm >= cm_max && cm <= cm_min) { liter = CmZuLiter(cm); } else { liter = 0; } // Berechne Balken balken = LiterZuBalken(liter); // LCD-Ausgabe lcd.clear(); // Zeile 1 lcd.setCursor(4,0); lcd.print(liter); lcd.print(" Liter"); // Zeile 2 for (int i=0; i<balken; i++) { lcd.setCursor(i,1); lcd.write((unsigned char)1023); } delay(100); } int CmZuLiter(float x) { int result; result = round((-0.000006*pow(x,4)+0.0029*pow(x,3)-0.4321*pow(x,2)+2.8503*x+1850)/10)*10; return result; } int LiterZuBalken(int x) { int result; result = round((16.0*x)/liter_max); return result; }
Der fast fertige Einbau in der Gartenhütte sieht jetzt wie folgt aus:
Damit ist das Projekt vorerst abgeschlossen.
Möchte man das ganze Platzsparend nachbauen, spricht nichts gegen einen Arduino Micro, Nano oder Mini.
Hier sind alle PINs gegeben und die Programmierung muss auch nicht angepasst werden.
Alternativ gibt es auch die Möglichkeit, statt einem Ultraschallsensor einen ToF-Sensor, der mit Lichtzeitmessung arbeitet, zu verwenden.
Über ein konstruktives Feedback würde ich mich freuen, auch unterstütze ich gerne bei ählichen Vorhaben 🙂