Hymer-Fahrer kennen vermutlich das Problem: Die Anzeige für den Frischwassertank ist so ungenau, dass sie nicht wirklich etwas nutzt. Der Sensor im Tank hat ohnehin nur 4 Stufen, aber die können den Wasserstand nicht mal annähernd erfassen. Ein weiteres Problem ist, dass beim Wasser tanken keine Möglichkeit besteht, den Füllstand zu beobachten und das zufließende Wasser rechtzeitig abzustellen, wenn der Tank gefüllt ist. Natürlich kann eine zweite Person entweder auf die Füllstandsanzeige oder direkt auf den Tank schauen und rufen, wenn es soweit ist. Aber wir leben in modernen Zeiten und deshalb scheint es sinnvoll, ein elektronisches Helferlein zu installieren, welches beide Probleme löst. Etwa so könnte das aussehen:

Füllstandskontrolle beim Wassereinfüllen Alle wichtigen Informationen auf dem Display

Gesagt, getan… Ok, so einfach ist es dann doch nicht. Zunächst einmal ist zu klären, wie der Wasserstand gemessen werden kann. Es stehen hierfür verschiedene Methoden zur Wahl, wobei die von Hymer verwendete aus oben genannten Gründen nicht betrachtet werden soll.

Welche Möglichkeiten stehen ansonsten zur Verfügung?

  1. Masse des Tanks messen.
  2. Wasserdruck am Boden des Tanks messen.
  3. Mittels Ultraschall den Abstand zwischen Tankoberseite und Wasserspiegel messen.
  4. Die Wasserhöhe mit einem Schwimmkörper erfassen.
  5. Die Wasserhöhe kapazitiv erfassen.

Masse des Tanks messen

Diese Methode fällt aus verschiedenen Gründen aus. Zuerst einmal muss ein Gewichtssensor unter dem Tank platziert werden. Das ist eventuell bei einigen Konstrukionen möglich aber dann haben wir einen kaum zugänglichen Sensor und die Geometrie der Anordnung ist kaum sicher zu gestalten. Außerdem biegt sich der Plastiktank natürlich durch und damit wird eine Massebestimmung schwierig bis unmöglich.

Wasserdruck am Boden des Tanks messen

Das scheint eine ganz gute Sache zu sein. Problematisch ist hier nur die wasserdichte Verkapselung des Drucksensors. Das ist aber sicher lösbar.

Mittels Ultraschall den Abstand zwischen Tankoberseite und Wasserspiegel messen

Eigentlich eine sehr elegante Methode. Es wird die Laufzeit eines Ultraschallimpulses zwischen einem Geber, welcher an der Tankoberseite angebracht ist, zur Wasseroberfäche und zurück zu einem Empfänger, welcher ebenfalls an der Tankoberseite angebracht ist, gemessen. Hierbei treten zwei Probleme auf. Erstens ist die Schallgeschwindigkeit und damit auch die Laufzeit stark temperaturabhängig. Das kann man mit einem Temperatursensor jedoch kompensieren. Zweitens wird die Methode immer ungenauer, je kürzer der Abstand des Wasserspiegels von der Tankoberkante ist. Bei einem Abstand von 1 cm beträgt die Zeit nur noch etwa 60 ms. Das ist natürlich problemlos messbar, wenn man einen genügenden Aufwand betreibt. Einfache, stromsparende (und billige) MCUs (Microcontroller Units) mit einem ESP8266 kommen dabei jedoch schon ziemlich an ihre Grenzen.

Die Wasserhöhe mit einem Schwimmkörper erfassen.

Eine ziemlich mechanische Lösung, die ich nicht näher betrachtet habe, denn meine handwerklichen Fähigkeiten sind nur rudimentär vorhanden und würden eine solche Bastelei kaum stemmen 😉

Die Wasserhöhe kapazitiv erfassen

Hier werden zwei sehr einfache Elektroden in den Tank gegeben und die elektrische Kapazität zwischen den beiden Elektroden gemessen. Wegen der unterschiedlichen Dielektrizitätskonstanten von Luft und Wasser ändert sich die Kapazität der Anordnung mit dem Wasserstand ziemlich linear. Ein Selbstbau dieser Elektrodenanordnung ist dennoch nicht ganz einfach. Vor allem die Kalibrierung ist recht schwierig. Allerdings bietet die Firma Votronic bereits fertig konfektionierte Lösungen an, die sich einfach einbauen lassen. Hier findet man den Tankgeber . Ein hübsches Display für den Wasserstand, welches im Wohnmobil fest angebracht werden kann, ist ebenfalls im Angebot.

Tankelektrode von Votronic Frischwasser-Tankanzeige von Votronic



Realisierung

Letztlich ist meine Wahl (auch wegen der käuflichen Komponenten) auf die kapazitive Methode gefallen, wobei die Tanksonde und das Display von Votronic zur Anwendung kommen. Der Vorteil dieser Lösung ist, dass der Sensor am Tank eine einfach auszuwertende, kontinuierliche Gleichspannung von 0 bis ca. 2,3 V als Messgröße ausgibt. Diese Spannung wird einmal an der Votronic-Tankanzeige ausgegeben und andererseits mit dem Analogeingang eines Microcontrollers WeMos D1 mini Pro erfasst. Der Microcontroller sendet den Wert der Sensorspannung dann über WLAN an einen Empfänger, der als Handgerät mit nach draußen genommen werden kann und den Tankvorgang in Echtzeit anzeigt. Der Empfänger ist ebenfalls ein Microcontroller ähnlicher Bauart (ich habe hier ein etwas abweichendes Modell genommen, das ist aber ohne Belang). Die Kalibration der Anordnung geschieht in drei Stufen:

  1. Mit einer genügend genauen Spannungsquelle werden die Tankanzeige und das Handgerät aufeinander abgeglichen. Im Empfänger-Programm wird dazu ein Korrekturfaktor so eingegeben, dass die Tankanzeige und das Display am Handgerät gleiche Werte ausgeben.
  2. Die Tankelektrode wird auf die in der Bedienungsanleitung angegebene Länge gekürzt und auf dem Messkopf wird die Tankhöhe grob eingestellt.
  3. Das Feintuning geht dann nur mit Wasser im Tank. Ist der Tank gefüllt, kann auf dem Messkopf eine Feinjustierung vorgenommen werden, so dass Anzeige und Display auf dem Handgerät jeweils 100% anzeigen.

Mein erster Prototyp sieht so aus:

 
Eingebaute Tankelektrode Eingebaute Tankanzeige Handgerät

Der Prototyp ist seit dem Anfang des Jahres 2023 im Einsatz und hat sich bewährt. Nur in einer Situation gab es dann doch einen Wasserüberlauf. Beim Wassertanken habe ich mit dem Campingplatzbetreiber geplaudert und dabei vergessen, auf das Display zu schauen… Nachdem der Schaden beseitigt war, sollte das natürlich nicht noch einmal passieren. Also habe ich noch einen kleinen Alarm-Buzzer in das Handgerät eingebaut, der mich bei künftigen Ablenkungen hoffentlich an das Abstellen des Wassers erinnern wird.



Für alle, die einen Nachbau ins Auge fassen, gibt es hier die Schaltpläne und die Sketche für die Microcontroller.

Für die Programmierung des Displays (Nextion 3.5″ Discovery Touch Display 480×320 HMI – NX4832F035) benötigt man einen Nextioneditor . Mit diesem Editor kann man aus der Datei tankanzeige.HMI die Datei tankanzeige.tft generieren, die dann mittels einer MikroSD Karte auf des Display geladen werden kann. Etwas umständlich, deshalb habe ich beide Dateien zum Download hier bereitgestellt.

Die Links für die wichtigsten Komponenten:

 

Die Schaltpläne für Sender und Empfänger

Sketch „Sender.ino“ für den Sender der Daten

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <EEPROM.h>

#ifndef STASSID
#define STASSID "WIFI_TANK_EM"
#define STAPSK "123456789+"
#endif

IPAddress ip(192, 168, 10, 10);
IPAddress gateway(192, 168, 10, 1);
IPAddress subnet(255, 255, 255, 0);
unsigned int sendPort = 9500; unsigned int sensor = 0; bool wifi_ok = false; WiFiUDP Udp;
void setup() { pinMode(LED_BUILTIN, OUTPUT); int count_wifi = 0; pinMode(A0, INPUT); Serial.begin(115200); wifi_ok = false; while (wifi_ok == false) { count_wifi = 0; WiFi.mode(WIFI_STA); WiFi.config(ip, gateway, subnet); WiFi.begin(STASSID, STAPSK); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { count_wifi++; digitalWrite(LED_BUILTIN, (count_wifi % 2) ? LOW : HIGH); Serial.print('.'); delay(500); if (count_wifi > 50) { Serial.println("WiFi not connected! Restart!");
break;
}
}
wifi_ok = (WiFi.status() != WL_CONNECTED) ? false : true; } Serial.print("Connected! IP address: "); Serial.println(WiFi.localIP()); Serial.printf("UDP server on port %d\n", sendPort); Udp.begin(sendPort); }
void sensor_status() { // Wir lesen hier nur die Rohdaten, // alles andere geschieht im Empfänger sensor = analogRead(A0); }

void loop() { sensor_status(); // Daten senden if (wifi_ok) {
Udp.beginPacket(gateway, sendPort);
Udp.write("sensor:");
Udp.print(sensor);
Udp.write(";count:");
Udp.print(0);
Udp.write(";wasser:");
Udp.print(sensor);
Udp.endPacket();

digitalWrite(LED_BUILTIN, LOW);
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
delay(900);
}
}


Sketch „Empfaenger.ino“ für das Handgerät

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <SoftwareSerial.h>

#ifndef APSSID
#define APSSID "WIFI_TANK_EM"
#define APPSK  "123456789+"
#endif

SoftwareSerial nextion(12, 13); // RX, TX

IPAddress ip(192, 168, 10, 1);
IPAddress gateway(192, 168, 10, 10);
IPAddress subnet(255, 255, 255, 0);

unsigned int receivePort = 9500;

// Puffer für Empfangene Daten
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1];
char * values[4];
char * buf[4];
char cmEinheit[11];
char fuellstand[21];
char relFuellstand[21];
char num[21];
unsigned int sensor = 0.0;
float batt = 0.0;
unsigned int w_stand;
int led_status = HIGH;
int delay_count = 0;
int delay_limit = 10;

// Max. Füllhöhe des Tanks in cm:
int maxFuellhoehe = 30;
int fuellhoehe;
bool data_ok = false;

// Alarmsound
int alarmStufe = 0;
int pitch[] = {0, 523, 659, 784};
int duration = 100;  // 100 miliseconds

WiFiUDP Udp;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(A0, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
nextion.begin(9600);
WiFi.softAPConfig(ip, gateway, subnet);
WiFi.softAP(APSSID, APPSK);
delay(500);
Udp.begin(receivePort);

nextion.print("p0.pic=");
nextion.print(0);
sendToDisplay();
}

void sendToDisplay() {
nextion.write(0xFF);
nextion.write(0xFF);
nextion.write(0xFF);
}

float batt_status() {
return analogRead(A0) / 1024.0 * 4.5;
}

void displayBattSymb(float battV) {
nextion.print("p0.pic=");
nextion.print(((battV >= 3.42) ? 4 : 
              ((battV >= 3.10) ? 3 : 
              ((battV >= 2.80) ? 2 : 1))));
sendToDisplay();
}

void setAlarmLevel(int fuellstand) {
if (fuellstand < 90) {
  alarmStufe = 0;
  return;
}

  //  90 <= fuellstand <= 100
alarmStufe = 
(fuellstand < 94) ? 1 :
(fuellstand < 97) ? 2 : 3;
}

void loop() {
String cmd = "\"";
// sind Daten vorhanden, lies ein Paket
int packetSize = Udp.parsePacket();
  if (packetSize) {
  // lies das Paket in packetBuffer
  int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
  packetBuffer[n] = 0;

  // Empfangene Daten zerlegen
    char * ptr = strtok(packetBuffer, ";");
  for (byte i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
    values[i] = ptr;
    ptr = strtok(NULL, ";");
  }    
  buf[0] = strtok(values[0], ":");
  // Sensor Rohwert (zwischen 0 und 1024)
  sensor = atoi(strtok(NULL, ":")); 
  data_ok = true;
  sprintf(cmEinheit, " cm. ");
  // Kalibration Sensorwert - Votronic-Display
  sensor = sensor * 3 / 2; 
  w_stand = sensor * 100 / 1024;
  w_stand = min((uint)100, w_stand);
  sprintf(relFuellstand, "%i %%", w_stand);
  setAlarmLevel(w_stand);
}
else {
  data_ok = false;
  sprintf(cmEinheit, " cm  ");
}

  fuellhoehe = min(sensor * maxFuellhoehe / 1024, (uint)maxFuellhoehe);
sprintf(fuellstand, "%i%s", fuellhoehe, cmEinheit);

//Daten an das Display senden
batt = batt_status();
sprintf(num, "%.1f", batt);
nextion.print("batterie.txt=" + cmd + num);
nextion.print(" V" + cmd);
sendToDisplay();

// rel. Füllstand in %
nextion.print("rel_fs.txt=" + cmd + relFuellstand + cmd);   
sendToDisplay();

// Füllhöhe in cm
nextion.print("w_stand.txt=" + cmd + fuellstand + cmd); 
sendToDisplay();

// Wert für Säule Wasserstand (0 ... 100)
nextion.print("wstand.val=");
nextion.print(w_stand);     
sendToDisplay();

displayBattSymb(batt);

if(alarmStufe == 0) {
  delay(100);
}
else {
  tone(BUZZER_PIN, pitch[alarmStufe], duration);
}

delay_limit = (led_status == HIGH) ? 1 : 20;
if((delay_count % delay_limit) == 0) {
  digitalWrite(LED_BUILTIN, led_status);
  led_status = (led_status == HIGH) ? LOW : HIGH;
}
delay_count++;
if(delay_count > 200) {
  delay_count = 1;
}
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

WordPress Cookie Hinweis von Real Cookie Banner