Pumpensteuerung - schalten erst nach zeitablauf

Hallo!

Ich steuere eine Wasserpumpe für mein Hauswasserwerk mit einem Drucksensor, einem Arduino und einem Relais. Funktioniert soweit eigentlich auch. Nur schaltet sich das ganze nur sehr stotternd aus.

Ich würde gerne bei überschreiten des festgelegten Ausschaltdrucks über eine bestimmte Zeit (z.B. 3 Sek.) den Druck messen und wenn der Druck sich nicht mehr verändert erst ausschalten.

Wie stelle ich das am besten an?

So sieht das Ganze bis her aus:

/*
  Meine Pumpensteuerung
 */

int druckSensor = A2;
int pumpenRelais = 8;
byte state = 0;                 
int lastState = 0;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
  
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);
}

void loop() {
  
 long sensorSumme=0;
 
 #define SAMPLES 200
  
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);

  if(sensorWert <= 520) state = 0; // Pumpe AN
  if(sensorWert >= 550) state = 1; // Pumpe AUS
  
  if(lastState != state) {
  lastState = state;
    
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
      
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
      
      default:
      problem();
      }
  }
}

Du kannst mit millis() eine Zeit ablaufen lassen und dann nochmal messen. Aber deine Schalthysterese 520/550 ist viel zu eng, das wird immer zu Problemen führen. Ein- und Ausschaltpunkt sollten deutlich auseinander liegen.

Guten Morgen,

Soll eigentlich auch, meine Schalthysterese war ursprünglich 350/550. Das Problem ist, wenn der Druck abfällt, der Einschaltpunkt erreicht wird und die Pumpe anspringt, dann springt der Druck ganz kurz auf den Abschaltpunkt und die Pumpe hat nicht die Zeit den Druck in der Leitung aufzubauen.

Deshalb soll wenn der Auschaltpunkt erreicht wird für 3 Sek. gemessen werden ob der Druck stabil bleibt und dann erst abgeschaltet werden.

Ich hatte auch an millis() gedacht. Aber wie baue ich das ein?

Danke!

Mir ist eine Kleinigkeit aufgefallen: Die schreibst einmal pumpenrelais und einmal pumprelais, ist das beabsichtigt oder ein Tippfehler?

Hast du dir zu millis() schon das Beispiel BlinkWithoutDelay angesehen?

Tipfehler!! Danke!

Hab ich geändert!

Ist das korrekt:

/*
  Meine Pumpensteuerung
 */

int druckSensor = A2;
int pumpenRelais = 8;
byte state = 0;                 
int lastState = 0;
unsigned long previousMillis = 0;
const long interval = 3000;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
  
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);
}

void loop() {
  
 long sensorSumme=0;
 
 #define SAMPLES 200
  
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);

 unsigned long currentMillis = millis();

  if(sensorWert <= 350) state = 0; // Pumpe AN
  if(sensorWert >= 550) {

  if(currentMillis - previousMillis >= interval) 
    previousMillis = currentMillis;   

  if(sensorWert >= 550) state = 1; // Pumpe AUS
  }
  if(lastState != state) {
  lastState = state;
    
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
      
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
      
      default:
      problem();
      }
  }
}

Du solltest die Messwerte des Drucksensors im Loop kontinuierlich einlesen und "glätten", dann passiert bei kurzen Impulsen Nichts. Das ginge z.B. mit einem Array aus 5 Foat-Variablen so:

loop{
  press[4]=press[3];
  press[3]=press[2];
  press[2]=press[1];
  press[1]=press[0];
  press[0]=aktmess();

  medmess=(press[4]+press[3]+press[2]+press[1]+press[0])/5;

  if (medmess>auschalt_schwelle){ ausschalt();}
  if (medmess<einschalt_schwelle){ einschalt();}
  delay(20);
}

Man nennt sowas "kontinuierliche Mittelwertbildung" ... der gezeigte Code ist nur eine Denkanregung, man kann die Mittelwertbildung auch deutlich länger machen, dann natürlich in einer for-Schleife. Der Unterschied zu deiner Lösung ist, dass nicht das Programm quasi angehalten und mehrfach gemessen wird, sondern nach jeder Messung erneut eine Entscheidung getroffen wird ... find ich "flüssiger". Ein maßvoll eingesetztes delay bewirkt eine kalkulierbare Zyklus- und Integrationszeit.

Hallo qualidat!

Dein Vorschlag liest sich sehr gut, überfordert mich gerade aber ein klein wenig.
Ich bin ja aber hier um zu lernen und möchte das sehr gerne versuchen.

Poste später einen Versuch!

Danke!

das machst du schon hier

#define SAMPLES 200
 
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden

versuch es mal so

/*
  Meine Pumpensteuerung
 */

const int druckSensor = A2;
const int pumpenRelais = 8;
bool state = 0;                 
bool lastState = 0;
unsigned long previousMillis = millis();
const int interval = 3000;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
 
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);
}

void loop() {
 
 long sensorSumme=0;
 
 #define SAMPLES 200
 
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);

  if(sensorWert <= 350) state = 0; // Pumpe AN

  if(millis() - previousMillis >= interval && sensorWert >= 550)
  {
    previousMillis = millis();   
    state = 1; // Pumpe AUS
  }
  if(lastState != state) {
  lastState = state;
   
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
     
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
     
      default:
      problem();
      }
  }
}

Danke ardubu!

Ich habe jetzt noch eine Ermittlung des Maximaldruckes in das setup eingebaut und entsprechende Variablen angelegt. Ich hab das ganze noch nicht im Einsatz gehabt.

Funktioniert das so eurer Meinung nach?

/*
  Meine Pumpensteuerung
 */

const int druckSensor = A2;
const int pumpenRelais = 8;
bool state = 0;                 
bool lastState = 0;
unsigned long previousMillis = millis();
const int interval = 3000;
const int kalibrieren = 30000;

int maxDruck = 0;
int newDruck = 0;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
 
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);

  digitalWrite(pumpenRelais, LOW);

if(millis() - previousMillis >= kalibrieren)
  {
    newDruck = analogRead(druckSensor);
    
    if(newDruck > maxDruck)
    maxDruck = newDruck;
  }
  digitalWrite(pumpenRelais, HIGH);
}

void loop() {
 
 long sensorSumme=0;

 #define SAMPLES 200
 
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);

  if(sensorWert <= maxDruck - 100) state = 0; // Pumpe AN

  if(millis() - previousMillis >= interval && sensorWert >= maxDruck)
  {
    previousMillis = millis();   
    state = 1; // Pumpe AUS
  }
  if(lastState != state) {
  lastState = state;
   
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
     
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
     
      default:
      problem();
      }
  }
}

Das ganze funktioniert immer noch nicht so wie es soll.

Es werden irgendwie nicht die 3000 millis (interval) abgewartet bis sich der druck stabilisiert hat. Was habe ich denn da immer noch falsch?

Danke!

setup() wird einmal aufgerufen, da liefert millis() zunächst eine 0 zurück.

also ist if(millis() - previousMillis >= kalibrieren) nicht erfüllt

  digitalWrite(pumpenRelais, HIGH);  wird ausgeführt und setup ist fertig.
Und wie soll es statt dessen sein ?

michael_x:
setup() wird einmal aufgerufen, da liefert millis() zunächst eine 0 zurück.

also ist if(millis() - previousMillis >= kalibrieren) nicht erfüllt

  digitalWrite(pumpenRelais, HIGH);  wird ausgeführt und setup ist fertig.
Und wie soll es statt dessen sein ?

In diesem Teil (setup) soll der maximale Wert, der in 30 Sek. gemessen wurde, in die Variable "maxDruck" geschrieben werden.

Dann muss das wohl so:

if(millis() >= kalibrieren)

Richtig?

Der Teil im Loop funktioniert aber auch nicht:

if(millis() - previousMillis >= interval && sensorWert >= maxDruck)

Danke!

petemanzel:
In diesem Teil (setup) soll der maximale Wert, der in 30 Sek. gemessen wurde, in die Variable "maxDruck" geschrieben werden.

Dann schaue mal nach was "if" genau macht und wie oben gesagt wie oft setup() ausgeführt wird

Ok! "if" möchte gerne durchlaufen. Kann aber nicht weil "setup" nur einmal durchläuft.

Die Ermittlung der Varianle "maxDruck" soll aber nur einmal ausgeführt werden. Deshalb dachte ich eben nicht in "loop" damit.

Wie kann ich das lösen?

Ich hab´s gefunden!

Ich werde das jetzt so mal testen.

/*
  Meine Pumpensteuerung
 */

const int druckSensor = A2;
const int pumpenRelais = 8;
bool state = 0;                 
bool lastState = 0;
unsigned long previousMillis = millis();
const int interval = 3000;
const int kalibrieren = 30000;

int maxDruck = 0;
int newDruck = 0;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
 
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);

  digitalWrite(pumpenRelais, LOW);

while (millis() >= kalibrieren)
  {
    newDruck = analogRead(druckSensor);
    
    Serial.println(maxDruck);

    if(newDruck > maxDruck)
    maxDruck = newDruck;
  }
  digitalWrite(pumpenRelais, HIGH);
}

void loop() {
 
 long sensorSumme=0;

 #define SAMPLES 200
 
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);
   Serial.println(maxDruck);

  if(sensorWert <= maxDruck - 100) state = 0; // Pumpe AN

  if(millis() - previousMillis >= interval && sensorWert >= maxDruck)
  {
    previousMillis = millis();   
    state = 1; // Pumpe AUS
  }
  if(lastState != state) {
  lastState = state;
   
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
     
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
     
      default:
      problem();
      }
  }
}

Kann man da noch was verbessern?

Das ist nie wahr!

while (millis() >= kalibrieren)

millis() ist am Anfang 0 ist inkrementiert jede Millisekunde.

<= geht vielleicht. Das println() muss da aber weg. So schnell kannst du nicht auf die serielle Schnittstelle schreiben

Wenn du es umdrehst:   while (millis() < kalibrieren)
dauert setup 30 sek und sammelt in dieser Zeit das Maximum von

    analogRead(druckSensor)

Ich würde aber die Serial.println Ausgaben verringern, indem ich sie höchstens in die maxWert-Erkennung einbaue.

if(newDruck > maxDruck) {
      maxDruck = newDruck;
      Serial.print(millis()); Serial.print(" : "); Serial.println(maxDruck);
   }

Das kann allerhöchstens 1023 Zeilen geben :wink: und du siehst auch, ob 30s kalibrieren nicht völlig überdimensioniert sind

michael_x:
Wenn du es umdrehst:  while (millis() < kalibrieren)
dauert setup 30 sek und sammelt in dieser Zeit das Maximum von

    analogRead(druckSensor)

So hatte ich mir das auch gedacht!

Also: Stecker rein -> Pumpe geht an -> Ermittelt 30 Sek. lang den Maximaldruck -> übergibt den ermittelten maxDruck -> geht über zum Normalbetrieb.

Werde das also jetzt so probieren und mich dann melden und berichten!

/*
  Meine Pumpensteuerung
 */

const int druckSensor = A2;
const int pumpenRelais = 8;
bool state = 0;                 
bool lastState = 0;
unsigned long previousMillis = millis();
const int interval = 3000;
const int kalibrieren = 30000;

int maxDruck = 0;
int newDruck = 0;

void problem(void) {
  digitalWrite(pumpenRelais, LOW);
}

void setup() {
 
  Serial.begin(9600);
  pinMode (pumpenRelais, OUTPUT);

  digitalWrite(pumpenRelais, LOW);

while (millis() < kalibrieren)
  {
    newDruck = analogRead(druckSensor);
    
    if(newDruck > maxDruck) {
      maxDruck = newDruck;
      Serial.print(millis); Serial.print(" : "); Serial.println(maxDruck);
   }
  }
  digitalWrite(pumpenRelais, HIGH);
}

void loop() {
 
 long sensorSumme=0;

 #define SAMPLES 200
 
  for (int i=0; i<SAMPLES; i++) // Signal mehrmals messen, ca. 20 Millisekunden lang
  {
    sensorSumme+=analogRead(druckSensor);
  }
  int sensorWert = sensorSumme/SAMPLES; // Mittelwert bilden
   Serial.println(sensorWert);
   Serial.println(maxDruck);

  if(sensorWert <= maxDruck - 100) state = 0; // Pumpe AN

  if(millis() - previousMillis >= interval && sensorWert >= maxDruck)
  {
    previousMillis = millis();   
    state = 1; // Pumpe AUS
  }
  if(lastState != state) {
  lastState = state;
   
      switch (state)
      {
      case 0:   // Pumpe Aus
        digitalWrite(pumpenRelais, LOW);
      break;
     
      case 1:   // Pumpe An
        digitalWrite(pumpenRelais, HIGH);
      break;
     
      default:
      problem();
      }
  }
}

Bekomme jetzt diese Fehlermeldung:

mioPressControlIntervall.ino: In function 'void setup()':
mioPressControlIntervall:33: error: call of overloaded 'print(long unsigned int (&)())' is ambiguous

Hab die serielle Ausgabe in "setup" jetzt erstmal Auskommentiert.

Setup scheint yu funktionieren.

Die Pumpe geht jetzt aber nicht an bei maxDruck -(minus) 100.