Go Down

Topic: Pumpensteuerung - schalten erst nach zeitablauf (Read 3451 times) previous topic - next topic

petemanzel

Jun 29, 2016, 12:25 am Last Edit: Jun 29, 2016, 07:35 am by petemanzel
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:

Code: [Select]

/*
  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();
      }
  }
}
Der Pete

Scherheinz

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.
Hier könnte ihre Werbung stehen

petemanzel

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!
Der Pete

buffalo64

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?

petemanzel

#4
Jun 29, 2016, 07:49 am Last Edit: Jun 29, 2016, 07:55 am by petemanzel
Tipfehler!! Danke!

Hab ich geändert!

Ist das korrekt:

Code: [Select]

/*
  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();
      }
  }
}
Der Pete

qualidat

#5
Jun 29, 2016, 09:51 am Last Edit: Jun 29, 2016, 10:01 am by qualidat
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:

Code: [Select]

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.

petemanzel

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!
Der Pete

ardubu

das machst du schon hier
Code: [Select]
#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

ardubu

versuch es mal so
Code: [Select]

/*
  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();
      }
  }
}

petemanzel

#9
Jun 29, 2016, 06:39 pm Last Edit: Jun 29, 2016, 06:57 pm by petemanzel
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?

Code: [Select]

/*
  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();
      }
  }
}
Der Pete

petemanzel

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!
Der Pete

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 ?

petemanzel

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!
Der Pete

Serenifly

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

petemanzel

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?
Der Pete

Go Up