Ultraschallnebler mit Fuftfeuchtesenor steuern - Probleme im Hysteresebereich

Hallo zusammen,

aktuell versuche ich für ein kleines Bastelprojekt, einen Ultraschallnebler (das Modul von groove bzw. seed) über einen Temperatursensor zu zu steuern und somit die relative Luftfeuchtigkeit in einer geschlossenen Umgebung zu regeln.

Ich konnte den Code dafür vor allem auch dank der vielen Posts hier im Forum zusammenbauen; auch eine Hysterese habe ich bedacht :slight_smile:

Aktuell beträgt mein setting: minimal Feuchte: 60 %; maximale Feuchte: 80 %

Unterhalb des min Werts soll der Ultraschallnebler im 5s Takt alternierend on und off sein - das klappt gut. Oberhalb von 80% soll das Teil konstant aus sein - auch das führt der Sketch wunschgemäß aus.

Problematisch ist der Hysteresebereich. Ich hatte erwartet, dass der Nebler hier je nach Status beim Erreichen des Bereichs entweder weiter im 5s Takt alterniert oder eben konstant off ist - was er aber in der Realität tut ist: Er ist entweder konstant on oder konstant off. Ich möchte allerdings zu keinen Zeitpunkten im Sketch ein “konstant on” des Neblers haben. Wie kann ich es erreichen, dass on auch im Hysteresebereich bedeutet, dass der Nebler im 5s Takt zwischen on und off alterniert? Nachfolgend mein Code & ich würde mich sehr über einen Tipp freuen.

Vielen Dank,
Carola

#include "DHT.h"  
#include <Wire.h>

DHT dht1(8, DHT22);  

unsigned long currentTime;

#define Atomizer A0          
int AtomizerState = LOW;
unsigned long AtomizerPreviousTime = 0;
const unsigned long AtomizerInterval = 5000;

float maxFeuchte = 80.00; // The Max Feuchte allowed
float minFeuchte = 60.00; // The Min Feuchte allowed

void setup() {
   Serial.begin(9600);
  Serial.println("Sensor bereit");
  dht1.begin();
  pinMode(Atomizer, OUTPUT);
  digitalWrite(AtomizerState, LOW);
}

void loop() {
  delay(2000);
  float Feuchte = dht1.readHumidity();
  float Temp = dht1.readTemperature();
  unsigned long currentTime = millis();
  if (isnan(Feuchte) || isnan(Temp)) {
    Serial.println("Sensor konnte nicht gelesen werden!");
  } else {
    Serial.println(String("T:   ") + String(Temp) + 
                   String(" °C   RLF: ") + String(Feuchte) + String(" %"));
       if (Feuchte < minFeuchte) { 
      if (currentTime - AtomizerPreviousTime >= AtomizerInterval) {
        AtomizerPreviousTime = currentTime;
        if (AtomizerState == LOW) {
         AtomizerState = HIGH;
        } else {
         AtomizerState = LOW;
          }
      } 
    } else if (Feuchte >= maxFeuchte) {
      //Atomizerdown
      AtomizerState = LOW;
            }
    digitalWrite(Atomizer, AtomizerState);
         }
}

Hi

Dein Problem hier ist, daß Du den Nebler nicht mehr beachtest, wenn Du innerhalb des Feuchte-Fenster bist.
Ist der Nebler Da gerade aus - bleibt Er aus.
Ist Er an - bleibt Er an!

Ich hätte Das voneinander entkoppelt.
Über die Feuchte generierst Du ‘Nebler an’ oder ‘Nebler aus’.
<60 (Minumim) → AN

80 (Maximum) → AUS

In einer separaten IF prüfst Du, ob der Nebler AN sein soll und dort prüfst Du auch, ob die 5 Sekunden für die Aktiv/Passiv-Zeiten um sind/schaltest entsprechend um.
Somit hast Du AN AKTIV für Nebler_geht_AN und AUS oder PASSIV für Nebler_geht_AUS.

MfG

carola90:
Aktuell beträgt mein setting: minimal Feuchte: 60 %; maximale Feuchte: 80 %

Unterhalb des min Werts soll der Ultraschallnebler im 5s Takt alternierend on und off sein - das klappt gut. Oberhalb von 80% soll das Teil konstant aus sein - auch das führt der Sketch wunschgemäß aus.

Problematisch ist der Hysteresebereich. Ich hatte erwartet, dass der Nebler hier je nach Status beim Erreichen des Bereichs entweder weiter im 5s Takt alterniert oder eben konstant off ist - was er aber in der Realität tut ist: Er ist entweder konstant on oder konstant off. Ich möchte allerdings zu keinen Zeitpunkten im Sketch ein “konstant on” des Neblers haben. Wie kann ich es erreichen, dass on auch im Hysteresebereich bedeutet, dass der Nebler im 5s Takt zwischen on und off alterniert? Nachfolgend mein Code & ich würde mich sehr über einen Tipp freuen.

Bitte entschuldige, wenn ich es nicht direkt im Code mache.

Schreib Dir einen Ablaufplan:

WENN humidy <= 60 DANN alle 5 sekunden Nebler an
WENN humidy >= 80 DANN Nebler aus

Damit wäre Deine 60er bis 80er Bedingung aber nicht erfüllt

Du musst Dir merken, wo sich die Hysterese als letztes befand:
WENN humidy >= 80 DANN

  • nebler OFF
  • humidymerker ON

WENN humidy <= 60 DANN

  • nebler ON
  • humidymerker OFF

Für den Bereich zwischen 60 und 80:

WENN ((humidy > 60) && (humidymerker == OFF))

  • nebler ON

Wenn Dich was irritiert, frage…

[edit] Kurzfassung
WENN (humidy >= 80) DANN

  • nebler OFF
  • humidymerker TRUE
    SONST
    WENN ((humidy > 60) && (humidymerker FALSE)) DANN
  • nebler ON
    SONST
    WENN (humidy <= 60) DANN // Diese Abfrage kann auch entfallen, da keine weiteren Bedingungen
  • nebler ON
  • humidymerker FALSE

Hallo zusammen,

vielen Dank für eure Antworten! Ich muss ehrlich sagen dass mir die Lösung von postmaster-ino etwas eingänglicher ist und ich das zunächst gerne ausprobieren würde:

Ich finde die Idee super; so bleibt der Hauptcode schlank und wenn man zB etwas an der ON/Off Sequenz ändert muss man das auch nur noch an einer Stelle im Code tun!

Aber welchen Datentypus sollte ich für meine beiden neuen Variablen "NeblerOn" und "NeblerOff" denn wählen? Hast du ausserdem eventuell ein Beispiel parat wie so eine ausgelagerte, separate IF aussehen sollte und vor allem auch an welche Stelle im Code sowas eingefügt werden sollte? Ich frage nicht nach etwas extra für mich Geschriebenem; wenn es zB etwas Passendes aus der Sketchbeispielkiste von Arduino gäbe wäre das auch super.

Herzlichen Dank,
Carola

carola90:
Aber welchen Datentypus sollte ich für meine beiden neuen Variablen “NeblerOn” und “NeblerOff” denn wählen?

Keinen :slight_smile:

Die Namen der Variablen schreien danach, nur eine Variable vom Typ bool zu verwenden. Wenn Du diese Variable nebler nennst, kannst Du darin den Status an/aus in Form von true/false oder HIGH/LOW speichern.

Gruß

Gregor

Hi

Für AN/AUS würde uns bool reichen - da wir aber in Wirklichkeit noch zwei weitere Status haben - Warte_AN und Warte_AUS, wäre meine Wahl ein Byte.

//Forensketch
//Nebler-Intervall für *huch wurde gar nicht erwähnt*
//https://forum.arduino.cc/index.php?topic=692881.msg4658126#msg4658126

const float minfeuchte = 60.0;    //maximale Feuchte
const float maxfeuchte = 80.0;    //minimale Feuchte
float feuchte;                    //aktuelle Feuchte

uint32_t laston;                  //Merker Uhrzeit
const uint32_t ontime = 5000;     //Millisekunden ON-Time
const uint32_t offtime = 10000;   //dito OFF-Time
const byte neblerpin = 3;         //Pin, an Dem der Nebler hängt
const bool _AN = HIGH;            //Pinpegel für AN
const bool _AUS = !_AN;           //das gegenteil wird automatisch erzeugt
byte status;                      //unser Status - Programm-Abschnitt
//Die verschiedenen Status (Mehrzahl heißt ebenso), Die der Nebler haben kann
enum neblerstatus {nebleraus, nebleran, neblerpausean, neblerpauseaus};

void setup() {
  // put your setup code here, to run once:
  digitalWrite(neblerpin, _AUS);  //Nebler auf AUS
  pinMode(neblerpin, OUTPUT);     //Pin auf AUSGANG
}

void loop() {
  // put your main code here, to run repeatedly:
  feuchte = 55; //hier die aktuelle Feuchte einlesen
  if (feuchte < minfeuchte) status = nebleran;
  if (feuchte > maxfeuchte) status = nebleraus;
  switch (status) {
    case nebleraus:
      digitalWrite(neblerpin, _AUS);
      break;
    case nebleran:
      digitalWrite(neblerpin, _AN);
      laston = millis();
      status = neblerpausean;
      break;
    case neblerpausean:
      if (millis() - laston >= ontime) {
        digitalWrite(neblerpin, _AUS);
        laston = millis();
        status = neblerpauseaus;
      }
      break;
    case  neblerpauseaus:
      if (millis() - laston >= offtime) {
        digitalWrite(neblerpin, _AN);
        laston = millis();
        status = neblerpausean;
      }
      break;
    default:break;
  }
}

Der Sketch schaltet den Nebler <60 an, >80 aus.
Wenn ANgeschaltet, wird der Pin auf AN gesetzt und die ON-Wartezeit - gewartet.
Danach wird der Pin ABgeschaltet und die OFF-Wartezeit gewartet.
Dann wieder ANgeschaltet und mit der ON-Wartezeit weiter gemacht - diese beiden Wartezeiten wiederholen sich, bis der Nebler AUSgeschaltet wird (>80). (diese Abschaltung erfolgt ohne das Einhalten einer Wartezeit)

Wenn Du dazu Fragen hast - immer her damit.
Ein/zwei Kleinigkeiten musst Du noch anpassen/einbringen - so ist mein Feuchtewert fest auf 55 ‘verdrahtet’.

MfG

Uno:Nano:
Der Sketch verwendet 758 Bytes (2%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 9 Bytes (0%) des dynamischen Speichers, 2039 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Hallo postmaster-ino,

ganz viel Dank für deinen umfangreichen und erklärten Code. Da sind ein paar echt spannende Funktionen vorhanden :-). Ich freue mich schon sehr darauf, den Sketch auszutesten und zu verstehen! Es geht übrigens um einen selbstgebauten Humidor.

Vielen Dank,
Carola

carola90:
Ich freue mich schon sehr darauf, den Sketch auszutesten und zu verstehen!

Tu das!

Schau Dir auch an, wie der Sketch formatiert ist - echt hübsch! Deine Version ist diesbezüglich verbesserungsfähig. Mit einer gut lesbaren Formatierung hilfst Du nicht nur Dir (bei der Fehlersuche hast Du mehr Hirn für die Fehlersuche [Resultat: Weniger Kopfweh]), sondern auch Leuten, die nicht „im Code stecken“, weil sie Deinen Code schneller überblicken und verstehen.

Gruß

Gregor

Hallo zusammen & hallo postmaster-ino,

nochmal Danke für deinen sketch. Allerdings komme ich damit nicht ans Ziel und auch ohne weitere Hilfe auch nicht so richtig weiter :confused:

Ich habe deinen code in meinen sketch integriert; evtl habe ich die Variablenbezeichnung ein wenig modifiziert, an der Logik aber nichts (bewusst) verändert.

So wie unten dargestellt ist der Nebler daueran - und zwar direkt ab Initialisierung! Oberhalb von 80% Feuchte ist er daueraus.
Mit dem Originalsketch von postmaster-ino (lediglich modifiziert um die Abfrage der Feuchte) habe ich exakt das gleiche Problem.

Ich glaube es handelt sich um ein systemisches Problem, von alleine komme ich leider nicht drauf. Deshalb würde ich mich sehr freuen, wenn sich jemand nochmal dem Problem annehmen könnte und mir hilft.

Vielen Dank schonmal,
Carola

#include "DHT.h" // Library von Adafruit (benötigt auch Adafruit unified sensor library) 
#include <Wire.h>
DHT dht1(8, DHT22);  // Sensor an Pin 8
const unsigned long SensorInterval = 2000;
unsigned long previousSensorabfrage = 0;

const byte neblerpin = A0;      //A0 Pin controls Atomizer 
unsigned long laston;                  //Merker Atomizer
const unsigned long ontime = 5000;     //Millisekunden ON-Time
const unsigned long offtime = 10000;   //dito OFF-Time
const bool _AN = HIGH;            //Pinpegel für AN
const bool _AUS = !_AN;           //Pinpegel für AUS
byte status;                      //Status Programmabschnitt
enum neblerstatus {nebleraus, nebleran, neblerpausean, neblerpauseaus}; //Die verschiedenen Status (Mehrzahl heißt ebenso), Die der Nebler haben kann

const float maxFeuchte = 80.00;  //The Max Feuchte allowed
const float minFeuchte = 60.00;  //The Min Feuchte allowed
float Feuchte;                //aktuelle Feuchte
const float maxTemp = 28.00;     //The Max Temp allowed
const float minTemp = 26.00;     //The Min Temp allowed
float Temp;                   //aktuelle Temp

void setup() {
  Serial.begin(9600);
  Serial.println("Sensor bereit");
  dht1.begin();
  digitalWrite(neblerpin, _AUS);  //Nebler auf AUS
  pinMode(neblerpin, OUTPUT);     //Pin auf AUSGANG
 }

void loop() {
  //updates frequently
 unsigned long currentTime = millis();
//query Sensor
  if (currentTime - previousSensorabfrage >= SensorInterval){
//get  Temp und Feuchte 
  float Feuchte = dht1.readHumidity();
  float Temp = dht1.readTemperature();
//check Sensorstatus
   if (isnan(Feuchte) || isnan(Temp)) {
     Serial.println("Sensor konnte nicht gelesen werden!");
       }
   else {
 //show Sensorresults   
     Serial.println(String("T:   ") + String(Temp) +
                    String(" °C   RLF: ") + String(Feuchte) + String(" %"));
      }
   previousSensorabfrage = currentTime;
  }
 // Neblercode
  if (Feuchte < minFeuchte) {
    status = nebleran;
  }
  if (Feuchte >= maxFeuchte) {
    status = nebleraus;
  }
switch (status) {
    case nebleraus:
      digitalWrite(neblerpin, _AUS);
      break;
    case nebleran:
      digitalWrite(neblerpin, _AN);
      laston = millis();
      status = neblerpausean;
      break;
    case neblerpausean:
      if (currentTime - laston >= ontime) {
        digitalWrite(neblerpin, _AUS);
        laston = millis();
        status = neblerpauseaus;
      }
      break;
    case  neblerpauseaus:
      if (currentTime - laston >= offtime) {
        digitalWrite(neblerpin, _AN);
        laston = millis();
        status = neblerpausean;
      }
      break;
    default:break;
  }
}

(deleted)

Hallo Peter,

vielen Dank für den sketch - jetzt ohne switch Funktion!

Ich habe getestet: Das On/Off-Alternieren im 5s Takt bei Feuchte < 80 klappt wunderbar. Allerdings ändert der Nebler auch bei > 80 seinen Status nicht und macht im On/Off Modus weiter. Jedoch sollte er hier dauerhaft Off sein. Woran könnte das liegen?

50d am Stück soll das Programm nicht laufen insofern wird das hoffentlich kein Problem darstellen. Ausserdem; gehts dann nicht einfach wieder bei 0 los?

Bleib ebenso gesund und Grüße
Carola

(deleted)

Hallo Peter,

hm ich denke der Sensor funktioniert. Meine Argumente hierfür sind, dass beispielsweise mit den Codealternativen hier im thread ein unterschiedliches Neblerverhalten in Abhängigkeit der vom Sensor reporteten Feuchte induziert werden kann. Ausserdem sind die Werte des Sensors schlicht plausibel & korrelieren mit einem analogen Hygrometer. Auch reagiert der Sensor wie erwartet. Nach mehrmaligem Anhauchen gibt er zb eine Feuchte von ~95% zurück.

Noch eine Beobachtung: Wenn ich die thresholds für minFeuchte und maxFeuchte variiere, ändert sich nichts am Fehlerbild des sketches bzw dem falschen Verhalten des Neblers oberhalb des eingestellten maxFeuchte Wertes.

Ich habe noch eine weitere Ausführung des Sensortyps. Um sicherzugehen werde ich dieses Bauteil deshalb heute Abend mal austauschen.

Viele Grüße,
Carola

Nachtrag: Auch mit einem anderen Sensor das gleiche Ergebnis! VG

carola90:
Nachtrag: Auch mit einem anderen Sensor das gleiche Ergebnis! VG

Zeigen die Sensoren denn im seriellen Monitor jeweils die richtigen Ergebnisse an ?
Wenn ja, dann ist mein Tipp, baue den Sketch neu auf und fange mit einfachen Funktionen an.

  1. Nebler einschalten, wenn Feuchte unter Sollwert
  2. Nebler ausschalten, wenn Feuchte über Sollwert
  3. die gewünschten Zeitläufe einbauen

In etwar diesen Schritten vorarbeiten, dann immer weiter aufbauen, bis alles fertig ist.

Das Programm in #9 kompiliert nicht: "'myMills' was not declared in this scope" sollte myMillis sein.

    float Feuchte = dht1.readHumidity();
    float Temp = dht1.readTemperature();

Das sind lokale Variablen, die Du auch noch global verwendest. Damit stellst Du Dir ein Bein.

carola90:
Woran könnte das liegen?

Bitte ändere in diesen Zustand:

    //get  Temp und Feuchte
    Feuchte = dht1.readHumidity();
    Temp = dht1.readTemperature();

Bei mir in der Simulation geht es, ich hoffe, bei Dir auch?

(deleted)

Peter-CAD-HST:
Danke für deinen Hinweis.

Moin, bitte gerne! Nun muß es nur noch mit dem echten Nebler funktionieren ;D

(deleted)

Hallo zusammen,

danke euch für die zahlreichen Tipps!

Peter-CAD-HST:
Moin agmue

Danke für deinen Hinweis. Ich hab den Beitrag geändert.

[…]

Ja, es gab zwei Typos , die ich nicht erwähnt aber natürlich korrigiert habe - sonst hätte es ja auch einen Kompilierfehler gegeben. Jedenfalls sorry dafür!

HotSystems:
Zeigen die Sensoren denn im seriellen Monitor jeweils die richtigen Ergebnisse an ?
Wenn ja, dann ist mein Tipp, baue den Sketch neu auf und fange mit einfachen Funktionen an.

  1. Nebler einschalten, wenn Feuchte unter Sollwert
  2. Nebler ausschalten, wenn Feuchte über Sollwert
  3. die gewünschten Zeitläufe einbauen

In etwar diesen Schritten vorarbeiten, dann immer weiter aufbauen, bis alles fertig ist.

Ja das tun sie; auch in einem externen LCD werden die Werte korrekt angezeigt. Danke, dein Tipp zum sukzessiven Neuaufbau ist super denn gerade wenn man wenig Grundlagen und -wissen hat lernt man dadurch enorm dazu.

agmue:
[…]

    float Feuchte = dht1.readHumidity();

float Temp = dht1.readTemperature();



Das sind lokale Variablen, die Du auch noch global verwendest. Damit stellst Du Dir ein Bein.

Bitte ändere in diesen Zustand:



//get  Temp und Feuchte
    Feuchte = dht1.readHumidity();
    Temp = dht1.readTemperature();




Bei mir in der Simulation geht es, ich hoffe, bei Dir auch?

Wow - das wars ! Der Sketch funktioniert nun einwandfrei - vielen Dank für deinen Rat! An dem was im seriellen Monitor angezeigt wird ändert sich nix aber sowohl das Alternieren <60% Feuchte also auch das Daueroff >80% Feuchte des Neblers funktioniert! So ein doofer Fehler von mir :frowning:

Ich habe nochmal eine Grundverständnisfrage an euch:
Im sketch wird der Neblerpin ja in der setup Phase als pinMode(Neblerpin, OUTPUT) definiert. Dass ich ihn danach via digitalWrite steuern kann ist mir klar; nur wundert es mich, dass er auch via digitalRead adressiert werden kann - ich dachte dazu müsste er als INPUT definiert sein?

Lieben Dank nochmal

carola90:
Wow - das wars ! Der Sketch funktioniert nun einwandfrei - vielen Dank für deinen Rat!

Bitte gerne!

Mit digitalWrite wird das zugehörige Bit im Portregister gespeichert, mit digitalRead kann man es auch wieder lesen. Dadurch spart man sich eine Statusvariable.