Arduino Forum

International => Deutsch => Topic started by: kahmui on Jun 26, 2020, 09:46 am

Title: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 09:46 am
Hallo und einen schönen guten Morgen an alle!

Ich setze mich für eine kleine Projekt-Steuerung neuerdings mit dem Arduino auseinander und hänge aktuell fest. Vielleicht könnt ihr mir einen simplen Lösungsvorschlag aufzeigen, den ich dann umsetzen kann :) (Meine Kenntniss-Stand ist gleich +/- 0)


Das System an sich ist relativ einfach:
Es gibt zwei unabhängig voneinander arbeitende Kreise.
Jeder Kreis besitzt einen IR-Sensor und eine Pumpe. Sobald der IR-Sensor eine Bewegung erkennt, soll die Pumpe für 2 Sekunden laufen. Beide Kreise sollen jedoch unabhängig voneinander, parallel funktionieren!

Problem:
Hat jetzt allerdings der erste Sensor eine Bewegung festgestellt, ist der zweite Kreis für eine Zeit komplett außer Funktion. Wie kann ich die beiden Kreise unabhängig voneinander gestalten? Liegt meine Vermutung richtig, dass "delay" an dieser Stelle fehlplatziert ist?


Code: [Select]

int ir1Pin = 2;    // Infrarotsensor 1
int pump1Pin = 5;   // Pumpe 1
int ir2Pin = 3;   // Infrarotsensor 2
int pump2Pin = 6;   // Pumpe 2

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(pump1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(pump2Pin, OUTPUT);
}

 
void loop() {
 int s1 = digitalRead(ir1Pin);
  if( s1 == LOW){   
      Serial.println("sens1 = 0 Sensor 1: Kein Objekt gefunden..."); 
  }else{                       
      Serial.println("sens1 = 1 Sensor 1: Objekt erkannt!");     
      digitalWrite(pump1Pin, HIGH);                               
      delay(2000);                                                 
      digitalWrite(pump1Pin, LOW);                               
  } 
 
 int s2 = digitalRead(ir2Pin);
  if( s2 == LOW){   
      Serial.println("sens2 = 0 Sensor 2: Kein Objekt gefunden..."); 
  }else{                       
      Serial.println("sens2 = 1 Sensor 2: Objekt erkannt!");     
      digitalWrite(pump2Pin, HIGH);                               
      delay(2000);                                                 
      digitalWrite(pump2Pin, LOW);                               
  }
}



Ich danke vorab und wünsche schonmal einen guten Start in's Wochenende!

Mfg, Lars
Title: Re: Zwei parallele Programme laufen lassen
Post by: HotSystems on Jun 26, 2020, 09:50 am
Damit das sicher und richtig funktioniert, musst du delay aus dem Sketch entfernen und durch die Funktion mit millis ersetzen.

Sieh dir dazu "BlinkWithoutDelay" aus den Beispielen der IDE an.

Und tausche bitte die Quote-Tags durch durch Code-Tags, dann wird der Sketch besser lesbar.
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jun 26, 2020, 10:08 am
In anderen Worten,

mach einen Sketche ohne Delay sondern auf Basis Millis/BlinkWithoutDelay und wenn diese dann funktioniert, lege deine Variable als Arrays an und arbeite die zwei Einträge / Kreise ab.




Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 10:36 am
Ich setze mich für eine kleine Projekt-Steuerung neuerdings mit dem Arduino auseinander und hänge aktuell fest. Vielleicht könnt ihr mir einen simplen Lösungsvorschlag aufzeigen, den ich dann umsetzen kann :) (Meine Kenntniss-Stand ist gleich +/- 0)
Beste Voraussetzungen - herzlich willkommen!

Quote
Das System an sich ist relativ einfach:
Es gibt zwei unabhängig voneinander arbeitende Kreise.
Jeder Kreis besitzt einen IR-Sensor und eine Pumpe. Sobald der IR-Sensor eine Bewegung erkennt, soll die Pumpe für 2 Sekunden laufen. Beide Kreise sollen jedoch unabhängig voneinander, parallel funktionieren!

Problem:
Hat jetzt allerdings der erste Sensor eine Bewegung festgestellt, ist der zweite Kreis für eine Zeit komplett außer Funktion. Wie kann ich die beiden Kreise unabhängig voneinander gestalten? Liegt meine Vermutung richtig, dass "delay" an dieser Stelle fehlplatziert ist?
guten Morgen,

Zwei Dinge:
Ich empfehle erstmal mit einem Kreis anzufangen. Wenn der läuft, kannst Du das auf den zweiten Kreis adaptieren.
So wie Du jetzt anfängst, musst Du immer beide Kreise bearbeiten, bis Du sicher bist, das die sich nicht gegenseitig beeinflussen. (Was sie derzeit tun)

In der Erklärung fehlt noch etwas wichtiges:
Möchtest Du bei der ersten Erkennung die Pumpe starten - 2 sekunden laufen lassen und dann abschalten - und wieder auf Erkennung warten ODER
Möchtest Du permanent die Erkennung abfragen und die Pumpe "nachlaufen" lassen, wenn der letzte LOW gemeldet wurde?

In jedem Fall benötigst Du mindestens eine Statusvariable und eine weitere um Dir die Zeit zu merken. Und das für jeden Kreis. Daher nochmal eindringlich der Tip: Mach das erst mit einem...

Ich hatte mal einen User mit Wasser+Pumpenprojekt längere Zeit begleitet:
https://forum.arduino.cc/index.php?topic=673884.0 (https://forum.arduino.cc/index.php?topic=673884.0)
Da waren zwei Feuchtesensoren an zwei Pumpenkreisläufen mit Nachlauf etc.

Der Thread ist recht lang, aber in #96 ist dann die fertige Lösung auf wenige Codezeilen zusammengeschrumpft.
https://forum.arduino.cc/index.php?topic=673884.msg4556720#msg4556720 (https://forum.arduino.cc/index.php?topic=673884.msg4556720#msg4556720)
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 12:02 pm
Erstmal vielen Dank für die vielen und schnellen Rückmeldungen!

BlinkWithoutDelay.... klingt interessant, fühlt sich aber an wie 'ne Pfanne die an den Kopf fliegt. Leicht erschlagend :)

Von der Logik her verstehe ich die Funktion. Beim Umsetzen muss ich allerdings gestehen, dass ich überhaupt nichts zustande bringe.

Wie sage ich dem Arduino, dass die Pumpe für 2 Sekunden laufen soll, NACHDEM der Sensor ausgelöst wurde?

Also: if sensor1 = high -> zeitstempel setzen (?), pumpe1 betätigen und von 2 runterzählen (?) -> nach dem Runterzählen den Sensor wieder "scharf" (also auf low) schalten

Dazu muss ich (gehen wir jetzt mal nur, wie von euch geraten, von einem Kreis aus) meine Pins mit  Nummer und Input oder Output deklarieren. Zudem muss ich für die Zeitstempel meinen Kreis 1 und die Dauer der Pumpenbetätigung festlegen.

Code: [Select]

const int sensor1Pin =  2;
const int pumpe1Pin =  3;

unsigned long kreis1 = 0;

const long interval1 = 2000;

void setup() {
  pinMode(sensor1Pin, INPUT);
  pinMode(pumpe1PIN, OUTPUT);
}


Dann geht's los. Wie kann ich nun mitteilen, dass die Pumpe1 erst läuft, nachdem der Sensor1 ausgelöst wurde?

Code: [Select]

void loop() {
   unsigned long currentMillis = millis();

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

    if (sensor1Pin == HIGH) {
      digitalWrite(pumpe1PIN, HIGH);
    } else {
      digitalWrite(pumpe1PIN, LOW);
    //--------Müsste an dieser Stelle nicht der Code für Zeitablauf rein?
    }
  }
}


Sieht irgendwie murksig aus und wird wahrscheinlich auch nicht funktionieren.

In der Erklärung fehlt noch etwas wichtiges:
Möchtest Du bei der ersten Erkennung die Pumpe starten - 2 sekunden laufen lassen und dann abschalten - und wieder auf Erkennung warten ODER
Möchtest Du permanent die Erkennung abfragen und die Pumpe "nachlaufen" lassen, wenn der letzte LOW gemeldet wurde?

Erkennung -> Pumpe starten und 2 Sekunden laufen lassen -> abschalten (am besten mit 3 Sekunden Zwangspause) -> warten auf erneute Erkennung


Wie ihr seht, tu ich mich noch ziemlich schwer. Für weitere Gedankenstützen wäre ich dankbar.



Mfg Lars
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 12:37 pm
Erstmal vielen Dank für die vielen und schnellen Rückmeldungen!

Also: if sensor1 = high -> zeitstempel setzen (?), pumpe1 betätigen und von 2 runterzählen (?) -> nach dem Runterzählen den Sensor wieder "scharf" (also auf low) schalten
Moment: Du schaltest nicht den Sensor.... Du nutzt erst dann den Wert des Sensor, wenn die Bedingungen dafür stimmen.
Das geht mit einer Statusvariablen.

Quote
Dann geht's los. Wie kann ich nun mitteilen, dass die Pumpe1 erst läuft, nachdem der Sensor1 ausgelöst wurde?

Code: [Select]


    if (sensor1Pin == HIGH) {
      digitalWrite(pumpe1PIN, HIGH);
    } else {
      digitalWrite(pumpe1PIN, LOW);
    //--------Müsste an dieser Stelle nicht der Code für Zeitablauf rein?

Ja.


Quote
Erkennung -> Pumpe starten und 2 Sekunden laufen lassen -> abschalten (am besten mit 3 Sekunden Zwangspause) -> warten auf erneute Erkennung


Wie ihr seht, tu ich mich noch ziemlich schwer. Für weitere Gedankenstützen wäre ich dankbar.
Ach das wird.

Also mal aufgedröselt:
Loop - Anfang
WENN ir HIGH DANN
- Pumpe AN
- Zeit merken (Start der Laufzeit)

WENN Pumpe AN ist UND Laufzeit > 2000 DANN
- Pumpe aus
- Zeit merken (Begin der Pause)
Loop - Ende

Jetzt fällt auf, das die Pumpe wieder angehen würde, ohne das auf die 3 Sek.Pause gewartet wurde.
Also muss die erste Bedingung geändert werden in:
WENN ir HIGH  UND Pausezeit > 3000 DANN

Für Laufzeit und Pausenzeit brauchst Du Variablen.

Schliesslich könnte das so aussehen - ausm Bauch heraus
Code: [Select]


const int ir1Pin = 2;      // Infrarotsensor 1
const int pump1Pin = 5;    // Pumpe 1
const int laufzeit = 2000;
const int pausezeit = 3000;
long pausemillis = 0;
long laufmillis = 0;

void setup()
  {
  Serial.begin(115200);
  pinMode(ir1Pin, INPUT);
  pinMode(pump1Pin, OUTPUT);
  }


void loop()
  {
  if ((digitalRead(ir1Pin)) && (millis() - pausemillis > pausezeit))
    {
    Serial.println("sens1 = 1 Sensor 1: Objekt erkannt!");
    digitalWrite(pump1Pin, HIGH);
    laufmillis = millis();
    }
  if (millis() - laufmillis > laufzeit) // Hier könnte noch geprüft werden ob die Pumpe tatsächlich an ist
    {
    digitalWrite(pump1Pin, LOW);
    pausemillis = millis();
    }
  }




Und dann noch ein Hinweis
Wenn Du fertige Relaisboards benutzt, sind die oftmals LOW-aktiv. Das heisst, das LOW/HIGH für die Pumpe muss dann getauscht werden.
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jun 26, 2020, 12:56 pm
kanns erst jetzt posten,

das wäre meine Variante
Code: [Select]

/*
  https://forum.arduino.cc/index.php?topic=692478.msg
  by noiasca
*/

struct Messen                // jede Messstelle braucht 3 Variablen
{
  const byte irPin;          // Infrarotsensor
  const byte pumpPin;        // Pumpe
  uint32_t previousMillis;   // Zeitstempel vom letzten Einschalten
};

Messen messen[]
{
  {2, 5, 0},     // irPin, pumpPin, previousMillis
  {3, 6, 0}
};

const uint32_t interval = 2000;         // Laufzeit in Millisekunden
const size_t messstellen = sizeof(messen) / sizeof(messen[0]);

void setup() {
  Serial.begin(115200);
  for (byte i = 0; i < messstellen; i++)
  {
    pinMode(messen[i].irPin, INPUT);
    pinMode(messen[i].pumpPin, OUTPUT);
  }   
}

void check(byte actual)
{
  // checken, ob eingeschaltet werden soll
  if ( digitalRead(messen[actual].irPin == LOW) ) {
    Serial.print("sens = 0 Sensor ");
    Serial.print(actual + 1);
    Serial.println(": Kein Objekt gefunden...");
  } else {
    messen[actual].previousMillis = millis();                         // Zeit merken
    Serial.print("sens = 0 Sensor ");
    Serial.print(actual + 1);
    Serial.println(": Objekt erkannt");
    digitalWrite(messen[actual].pumpPin, HIGH);
  }
  // wenn EIN, checken auf Zeitablauf
  if (digitalRead(messen[actual].pumpPin) == HIGH && millis() - messen[actual].previousMillis >= interval )
  {
    digitalWrite(messen[actual].pumpPin, LOW);
    Serial.print("Pumpe ");
    Serial.print(actual + 1);
    Serial.println("abschalten");
  }
}

void loop() {
  for (byte i = 0; i < messstellen; i++)
    check(i);
}
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 01:00 pm
kanns erst jetzt posten,

das wäre meine Variante
Huch, vom Netz zwangsgetrennt? ;)

Ich hätte es wieder mit Array gelöst. Aber erstmal muss er das mit einem Zweig hinbekommen...
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 02:28 pm
Ich habe mir mal den Code von my_xy zur Brust genommen, da dieser für mich verständlicher ist als der von noiasca (nichts für ungut, aber das ist mir "noch" zu hoch). Trotzdem vielen Dank an dieser Stelle!!!  :)

Der Sensor erkennt die Bewegung und lässt den Motor auch drehen. Ebenso klappt das parallel mit dem zweiten Kreis. Die Überprüfung, ob die Pumpe überhaupt läuft habe ich auch mit reingenommen.
Code: [Select]
if ((millis() - laufmillis2 > laufzeit) && (digitalRead(pump2Pin) == HIGH))

Was allerdings nicht funktioniert ist die erste if-Abfrage mit dem millis Abgleich:

Code: [Select]
if ((digitalRead(ir1Pin)) && (millis() - pausemillis > pausezeit))

Wenn ich den Code beginnend ab "&&" ausblende,
Code: [Select]
if (digitalRead(ir1Pin)) //&& (millis() - pausemillis > pausezeit))

funktioniert es zumindest wie oben beschrieben (Sensor reagiert, Pumpe dreht). Nur drehen die Motoren permanent weiter und stoppen nicht mehr. Wo kann hier der Fehler liegen?


Gesamter Code:
Code: [Select]


const int ir1Pin = 2;      // Infrarotsensor 1
const int pump1Pin = 5;    // Pumpe 1
const int ir2Pin = 3;      // Infrarotsensor 2
const int pump2Pin = 6;    // Pumpe 2
const int laufzeit = 2000;
const int pausezeit = 3000;
long pausemillis1 = 0;
long laufmillis1 = 0;
long pausemillis2 = 0;
long laufmillis2 = 0;

void setup()
  {
  Serial.begin(115200);
  pinMode(ir1Pin, INPUT);
  pinMode(pump1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(pump2Pin, OUTPUT);
  }


void loop()
  {
  if (digitalRead(ir1Pin)) //&& (millis() - pausemillis1 > pausezeit))
    {
    Serial.println("Sensor 1: Objekt erkannt!");
    digitalWrite(pump1Pin, HIGH);
    laufmillis1 = millis();
    }
  if ((millis() - laufmillis1 > laufzeit) && (digitalRead(pump1Pin) == HIGH))
    {
    digitalWrite(pump1Pin, LOW);
    pausemillis1 = millis();
    }
 
  if (digitalRead(ir2Pin)) //&& (millis() - pausemillis2 > pausezeit))
    {
    Serial.println("Sensor 2: Objekt erkannt!");
    digitalWrite(pump2Pin, HIGH);
    laufmillis2 = millis();
    }
  if ((millis() - laufmillis2 > laufzeit) && (digitalRead(pump2Pin) == HIGH))
    {
    digitalWrite(pump2Pin, LOW);
    pausemillis2 = millis();
    }
 
  }



Übrigens vielen Dank für die Bemerkung mit den Relais. Tatsächlich wird am Ende ein Doppelrelais mit Optokoppler verwendet, um die beiden Pumpen (230V) zu schalten.

Übrigens hab ich mal ein Bild mit Schaltbeispiel angehangen.
Title: Re: Zwei parallele Programme laufen lassen
Post by: StefanL38 on Jun 26, 2020, 02:54 pm
Hallo Lars,

jetzt habe ich eine bestimmte Vermutung wie du dir das "Funktionieren" eines Programms vorstellst.
Wenn meine Vermutung zuträfe wäre es eine noch nicht korrekte Vorstellung. Wenn meine Vermutung falsch ist
bitte ich schon mal um Verzeihung.

Du hattest geschrieben:
Quote
Wie kann ich nun mitteilen, dass die Pumpe1 erst läuft, nachdem der Sensor1 ausgelöst wurde?
Das hört sich (in meinem Ohren) so an als ob man dem Microcontroller etwas sagen könnte wie einem Butler "Warte aber mit dem Autowaschen bis das Baby seinen Mittagsschlaf beendet hat" Und der Microcontroller bekommt dann Rest von alleine hin.


Es ist nicht so sehr ein Mitteilen von etwas sondern ein ständiges Überprüfen von verschiedenen Bedingungen.

Eine der Bedingungen lautet: meldet IR-Bewegungs-Sensor eine Bewegung?
Eine weitere Bedingung ist läuft Pumpe schon 2 Sekunden?
noch eine Bedingung ist: Ist es länger als drei Sekunden her, dass Pumpe abgeschaltet wurde

Ob diese Bedingungen zutreffen oder nicht wird innerhalb des Programms ständig überprüft.
Nur wenn bestimmte Bedingungen erfüllt sind werden bestimmte Befehle ausgeführt.


So als ob der Butler oben aus dem Beispiel: alle 10 Sekunden ins Kinderbettchen schaut ob das Baby noch schläft.
Wenn das Baby die Augen aufmacht und plärrt steht er auf "Hurra endlich Autowaschen!"

Du hattest geschrieben +-0-Ahnung. Nun über Null muss es hinausgehen weil du ja die Arduino-IDE installiert bekommen hast und auch halbwegs sinnvollen Code geschrieben hast.
Trotzdem ist dein Wissensstand vergrößerungsfähig.
Es macht auf jeden Fall Sinn ein Programmiertutorial durchzuarbeiten. Davon gibt es natürlich sehr viele und 95% davon sind Schrott. Wenn du ein bestimmtes Tutorial nicht verstehst  - abbrechen und ein anderes ausprobieren. Ganz im Ernst.
Ein leicht verständliches Tutorial ist leicht verständlich.


Auf Englisch habe ich ein entsprechendes gefunden:


Arduino Programming CourseArduino Programming Course (https://startingelectronics.org/software/arduino/learn-to-program-course/)



Auf deutsch habe ich noch keines gefunden was diesem englischen in Sachen leichte Verständlichkeit das Wasser reichen könnte. Wenn jemand eines kennt bitte Links posten. Ich möchte es finden.


viele Grüße Stefan

Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 03:07 pm
Übrigens hab ich mal ein Bild mit Schaltbeispiel angehangen.
Das ist gut, sagst Du mir auch noch, was das für IR-Sensoren sind?
Ich vermute mal, das die +5V an den Output schalten und keinen zusätzlichen Widerstand nach GND haben.
Damit wäre Dein PIN elektronisch bedingt immer HIGH.

Versuch mal einen Widerstand (unspektakulär zwischen 3,3K und 5K geht alles) sowohl von PIN2 als auch PIN3 nach GND zu stecken, damit Du definierte Zustände hast.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 03:15 pm
Das ist gut, sagst Du mir auch noch, was das für IR-Sensoren sind?
Ich vermute mal, das die +5V an den Output schalten und keinen zusätzlichen Widerstand nach GND haben.
Damit wäre Dein PIN elektronisch bedingt immer HIGH.

Versuch mal einen Widerstand (unspektakulär zwischen 3,3K und 5K geht alles) sowohl von PIN2 als auch PIN3 nach GND zu stecken, damit Du definierte Zustände hast.

Das sind ganz normale PIR-Sensoren die auch im Starterset vorhanden sind. Anschlüsse sind Leistung / Masse / Signal. Bei meiner Testschaltung ohne millis() hat das ganze auch ganz gut ohne Widerstand funktioniert, abgesehen vom delay-Dilemma (haha). Die Sensoren dienen hier nur als Platzhalter für ähnliche Sensoren die dann abschließend in der Praxis angewandt werden.

Siehe auch hier: klick klick! (https://www.makerblog.at/2017/01/pir-sensor-bewegungsmelder-am-arduino/)


Es ist nicht so sehr ein Mitteilen von etwas sondern ein ständiges Überprüfen von verschiedenen Bedingungen.
Danke für die Erklärung. Natürlich ist mir bewusst das Signale etc. laufend abgefragt werden. Trotzdem Danke!

So als ob der Butler oben aus dem Beispiel: alle 10 Sekunden ins Kinderbettchen schaut ob das Baby noch schläft.
Wenn das Baby die Augen aufmacht und plärrt steht er auf "Hurra endlich Autowaschen!"
Ich musste herzhaft lachen. Danke an dieser Stelle :)

Auf Englisch habe ich ein entsprechendes gefunden:

Arduino Programming CourseArduino Programming Course (https://startingelectronics.org/software/arduino/learn-to-program-course/)
Schaue ich mir an!



Dennoch bleibt mein das Problem weiterhin bestehen.


Mfg Lars
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 03:16 pm
Was allerdings nicht funktioniert ist die erste if-Abfrage mit dem millis Abgleich:

Code: [Select]
if ((digitalRead(ir1Pin)) && (millis() - pausemillis > pausezeit))
Und ich sag noch, mach erst einen Kreis fehlerfrei fertig - das macht sonst Mehraufwand ;)

Nachbearbeitet.
Ich sagte, Du brauchst eine Statusvariable.
Die hast Du mit dem PumpenPIN - Beim einschalten muss die natürlich auch rein.

Wenn Du nicht ständig die Bedingungen LOW und HIGH schreiben willst, geht das auch so wie ich das gemacht habe.



Code: [Select]

const int ir1Pin = 2;      // Infrarotsensor 1
const int pump1Pin = 5;    // Pumpe 1
const int ir2Pin = 3;      // Infrarotsensor 2
const int pump2Pin = 6;    // Pumpe 2
const int laufzeit = 2000;
const int pausezeit = 3000;
long pausemillis1 = 0;
long laufmillis1 = 0;
long pausemillis2 = 0;
long laufmillis2 = 0;

void setup()
{
  Serial.begin(115200);
  pinMode(ir1Pin, INPUT);
  pinMode(pump1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(pump2Pin, OUTPUT);
}


void loop()
{
  if ((digitalRead(ir1Pin)) && (millis() - pausemillis1 > pausezeit) && (!digitalRead(pump1Pin)))
  {
    Serial.println("Sensor 1: Objekt erkannt!");
    digitalWrite(pump1Pin, HIGH);
    laufmillis1 = millis();
    
  }
  if ((millis() - laufmillis1 > laufzeit) && (digitalRead(pump1Pin)))
  {
    Serial.println("Pumpe aus!");
    digitalWrite(pump1Pin, LOW);
    pausemillis1 = millis();
  }
}


Ausgabe auf dem seriellen Monitor:
Code: [Select]

15:11:42.542 -> Pumpe aus!
15:11:45.572 -> Sensor 1: Objekt erkannt!
15:11:47.571 -> Pumpe aus!
15:11:50.569 -> Sensor 1: Objekt erkannt!
15:11:52.568 -> Pumpe aus!
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jun 26, 2020, 03:17 pm
Quote
a dieser für mich verständlicher ist als der von noiasca (nichts für ungut, aber das ist mir "noch" zu hoch). Trotzdem vielen Dank an dieser Stelle!!!  
wenn du mal die beiden Codes vergleichst wirst du feststellen dass sich diese gar nichtso sehr unterscheiden. Außer dass meiner Codeduplikate vermeidet. Auch das hinzufügen eines weiteren Sensors/Relais wäre nur die Sache von einer einzigen Zeile. Gehe  es einfach mal durch und sollte etwas unklar sein dann frage.
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jun 26, 2020, 03:59 pm
Code: [Select]

#include <CooperativeTask.h>



class Pumpe: public Task
{
  protected:
    const byte inPin;
    const byte outPin;
    const unsigned long laufZeit;
    const unsigned long pauseZeit;
 
  public:
    Pumpe(const byte inPin,const byte outPin,const unsigned long laufZeit,const unsigned long pauseZeit):
       inPin(inPin),
       outPin(outPin),
       laufZeit(laufZeit),
       pauseZeit(pauseZeit)
    {
    }
   
    virtual void init() override
    {
      pinMode(inPin,INPUT);
      pinMode(outPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(inPin));
        digitalWrite(outPin,HIGH);
        taskPause(laufZeit);
        digitalWrite(outPin,LOW);
        taskPause(pauseZeit);
      }
    }
};

Pumpe pumpen[] { // {inPin,outPin,laufZeit,pauseZeit}
                    {2,    8,     2000,    3000},
                    {3,    9,     2000,    3000}
               };




void setup()
{
 Scheduler::instance().init();
}

void loop()
{
  Scheduler::instance().run();
}



Alles drin, was das Herz begehrt:

Nur die if() habe ich großzügig weggelassen, bzw. vergraben.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 04:18 pm
wenn du mal die beiden Codes vergleichst wirst du feststellen dass sich diese gar nichtso sehr unterscheiden. Außer dass meiner Codeduplikate vermeidet. Auch das hinzufügen eines weiteren Sensors/Relais wäre nur die Sache von einer einzigen Zeile. Gehe  es einfach mal durch und sollte etwas unklar sein dann frage.
Werde ich auf jeden Fall machen! Danke :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: gregorss on Jun 26, 2020, 04:24 pm
Quote
BlinkWithoutDelay.... klingt interessant, fühlt sich aber an wie 'ne Pfanne die an den Kopf fliegt.
Das Prinzip eines endlichen Automaten ist für einen Anfänger nicht leicht zu verstehen. Meistens liegt's aber nur daran, wie es erklärt wird.

Mein Gesabbel dazu findest Du hier (http://html.szaktilla.de/weekender/4.html). Eine Erklärung, die IMO erheblich leichter zu verstehen ist, findest Du hier (https://forum.arduino.cc/index.php?topic=423688.0).

Gruß

Gregor
Title: Re: Zwei parallele Programme laufen lassen
Post by: agmue on Jun 26, 2020, 04:25 pm
EDIT: Da ein vorhergehender Beitrag gelöscht wurde, habe ich meinen Text angepaßt.

Dann noch eine OOP-Variante, die auf combies Überlegungen basieren, der TO möge wählen:

Code: [Select]
class Pumpe {
    const byte irPin, pumpPin;
    const uint32_t punpzeit;
    uint32_t vorhin;
  public:
    Pumpe(const byte irPin, const byte pumpPin, const uint32_t punpzeit)
      : irPin(irPin), pumpPin(pumpPin), punpzeit(punpzeit), vorhin(0) {}

    void initPumpe() {
      pinMode(irPin, INPUT);
      pinMode(pumpPin, OUTPUT);
    }

    void runPumpe() {
      if (digitalRead(pumpPin)) {
        if (millis() - vorhin >= punpzeit)
        {
          digitalWrite(pumpPin, LOW);
        }
      } else {
        if (digitalRead(irPin)) {
          digitalWrite(pumpPin, HIGH);
          vorhin = millis();
        }
      }
    }
};

Pumpe pumpe[] {
  {2, 5, 2000},
  {3, 6, 2000}
};

void setup() {
  for (Pumpe &p : pumpe) p.initPumpe();
}

void loop() {
  for (Pumpe &p : pumpe) p.runPumpe();
}
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 26, 2020, 04:42 pm
Erstmal vielen Dank an alle, die mir bei meinem Problem so tatkräftig zur Seite stehen. Ich weiß eure Rückmeldungen und Hilfestellungen wirklich sher zu schätzen!

Natürlich wäre es einfach den fertigen Code von euch zu nehmen. Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)

Jetzt habe ich erstmal eine Menge Code-Schnipsel von euch die ich mir in Ruhe anschauen kann!
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jun 26, 2020, 04:49 pm
Quote
Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)
So ist recht!

Hast du denn schon so ein schönes dickes modernes C++ Buch?
Nein? Dann anschaffen!
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 26, 2020, 05:05 pm
Dann hier auch noch mein fertiges Konstrukt - mit ein wenig Kommentar und serieller Ausgabe ;)

Code: [Select]

// HIER DIE ANZAHL DER KREISE ANGEBEN
const int Kreise = 2;
// Für jeden Kreis ab hier einen Wert angeben!
// Hier die Angabe der PIN
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};
// Hier die Angabe für die Zeiten
const int laufzeit[] = {2000, 2000};
const int pausezeit[] = {3000, 3000} ;
// Zeitvariablen init immer 0
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};
// Ende Eintrag Werte
void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT);
    pinMode(pumpPin[i], OUTPUT);
  }
}
void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if ((digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (!digitalRead(pumpPin[i])))
    {
      Serial.print("Sensor ");
      Serial.print(i+1);
      Serial.println(": Objekt erkannt!");
      digitalWrite(pumpPin[i], HIGH);
      laufmillis[i] = millis();
    }
    if ((millis() - laufmillis[i] > laufzeit[i]) && (digitalRead(pumpPin[i])))
    {
      Serial.println("Pumpe aus!");
      digitalWrite(pumpPin[i], LOW);
      pausemillis[i] = millis();
    }
  }
}
Title: Re: Zwei parallele Programme laufen lassen
Post by: agmue on Jun 26, 2020, 06:53 pm
Allerdings nehme ich mir lieber die Zeit die ganzen Lösungsansätze mal genauer unter die Lupe zu nehmen, um auch das Konstrukt dahinter zu verstehen und auf lange Sicht selbst in der Lage sein zu können, solche Probleme zu lösen :)
Meine OOP-Variante faßt die Informationen, die zusammengehören, zusammen. Sagt combie und damit hat er mich eingefangen, weshalb ich es mal zeigen wollte.

Bei Interesse bitte nachfragen :)

Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jun 26, 2020, 09:43 pm
Quote
.... faßt die Informationen, die zusammengehören, zusammen. Sagt combie ....
Ja, das sage ich!
> Fasse zusammen, was zusammen gehört!

Ein wichtiges Stilmittel, um Übersicht zu schaffen.

Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 30, 2020, 11:26 am
Code: [Select]

const int ir1Pin = 2;      // Infrarotsensor 1
const int rel1Pin = 5;    // Relais 1

const int laufzeit = 1000;
const int pausezeit = 5000;

long pausemillis1 = 0;
long laufmillis1 = 0;


void setup()
{
  Serial.begin(115200);
  pinMode(ir1Pin, INPUT);
  pinMode(rel1Pin, OUTPUT);
}


void loop()
{
  if ((digitalRead(ir1Pin)) && (millis() - pausemillis1 > pausezeit) && (!digitalRead(rel1Pin)))
  {
    Serial.println("Sensor 1: Objekt erkannt!");
    digitalWrite(rel1Pin, HIGH);
    laufmillis1 = millis();
   
  }
  if ((millis() - laufmillis1 > laufzeit) && (digitalRead(rel1Pin)))
  {
    Serial.println("Pumpe aus!");
    digitalWrite(rel1Pin, LOW);
    pausemillis1 = millis();
  }
}



Dieser Code funktioniert in der Simulation einwandfrei (erstmal mit nur einem Kreis).

In meinem Nachbau hab ich allerdings das Problem, dass das Relais nach Einschalten des Arduino permanent schaltet (1s aus, 5s an) Was läuft falsch?

Zusätzlich beibt das Relais permanent geschaltet WÄHREND ich meine Hand vor den Sensor halte.

Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jun 30, 2020, 11:46 am
Wenn dir deine Automatenzustände durcheinander geraten, dann ist es meist an der Zeit, den Teil nochmal zu überdenken.

Tipp:
Denke in Zuständen
Benenne die Zustände
Schaffe klare Zustandswechsel.

Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 30, 2020, 02:03 pm
Ich gehe das hier nochmal Step für Step für einen Kreis durch. Vielleicht könnt ihr fehlerhafte Gedankengänge feststellen und mich korrigieren:

Code: [Select]

int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin , OUTPUT);
}

 
void loop() {
 digitalWrite(relais1Pin , HIGH);
 digitalWrite(ir1Pin, HIGH);
 
 int i1 = digitalRead(ir1Pin);
  if( i1 == LOW){   
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin , LOW);                               
      delay(2000);                                                 
  }
}



Damit schaltet das Relais schonmal wenn ich meine Hand vor den Sensor halte.


Als nächstes muss ich schauen, dass ich mein delay() durch millis() ersetze, um die Möglichkeit zu haben, zwei voneinander unabhängige Kreise laufen zu lassen und die Laufzeit sowie die anschließende Zwangspause zu timen.

Dazu benötige ich 2 weitere konstante Variablen sowie je Kreis 2 Variablen mit unsigned long:

- zwei konstante Variablen für die Laufzeit und die Pausenzeit
Code: [Select]
const int laufzeit1 = 1000
const int pausezeit1 = 3000


- zwei Variablen (je Kreis) für die Zeitenmessung von Laufzeit und Pause
Code: [Select]
unsigned long laufmillis1
unsigned long pausemillis1


Sieht im Kopf dann so aus:
Code: [Select]

int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1
int ir2Pin = 3;   // Infrarotsensor 2
int relais2Pin = 6;   // Relais 2

const int laufzeit1 = 1000;   // Laufzeit der Relaisbetätigung Kreis 1
const int pausezeit1 = 3000;   // Laufzeit der Zwangspause nach Relaisbetätigung Kreis 1

unsigned long laufmillis1;
unsigned long pausemillis1;

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(relais2Pin, OUTPUT);
}


Dann setze ich den Zustand meiner Bauteile (Sensor und Relais) fest und vergebe Namen für digitalRead:

Code: [Select]
void loop() {
 digitalWrite(relais1Pin, HIGH);
 digitalWrite(ir1Pin, HIGH);
 
 int i1 = digitalRead(ir1Pin);
 int r1 = digitalRead(ir1Pin);



Als nächstes muss ich meine Bedingungen zum Betätigen des Relais entsprechend anpassen und festlegen was passieren soll, wenn alle Bedingungen erfüllt sind.

Dazu prüfe ich:
- ob mein Infrarotsensor 1 etwas erkennt,
- mein Relais ausgeschaltet ist,
- die vergangene Zeit von jetzt bis zu meiner Pause größer als die festgelegte Pausenzeit ist (hier ist wahrscheinlich mein gedanklicher Knackpunkt)

und teile ihm mit:
- , dass ich eine Textzeile im Monitor haben möchte
- , dass Relais 1 schalten soll
- wie lange Relais 1 schalten soll

Code: [Select]

if ((i1 == LOW) && (r1 == HIGH) && (millis() - pausemillis1 > pausezeit1))  {
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin, LOW);                               
      laufmillis1 = millis();
}

 

Damit diese Bedingung funktioniert, muss ich zusätzlich sagen, dass er nach der Laufzeit:
- das Relais 1 abschaltet
- die vergangene Zeit von jetzt bis zu meiner erneut möglichen Betätigung des Sensors größer als die festgelegte Zwangspausenzeit ist.

Dazu prüfe ich
- ob das Relais 1 betätigt ist
- die Laufzeit von Relais 1 abgelaufen ist.

Code: [Select]

if ((r1 == LOW) && (millis() - laufmillis1 > laufzeit1)) {
       Serial.println("Relais ausgeschaltet!");
       digitalWrite(relais1Pin, HIGH);
       pausemillis1 = millis();
}


Fasst man das ganze jetzt nochmal zusammen sieht es wie folgt aus:

Code: [Select]
int ir1Pin = 2;    // Infrarotsensor 1
int relais1Pin = 5;   // Relais 1
int ir2Pin = 3;   // Infrarotsensor 2
int relais2Pin = 6;   // Relais 2

const int laufzeit1 = 1000;   // Laufzeit der Relaisbetätigung Kreis 1
const int pausezeit1 = 3000;   // Laufzeit der Zwangspause nach Relaisbetätigung Kreis 1

unsigned long laufmillis1;
unsigned long pausemillis1;

void setup() {
  Serial.begin(9600);
  pinMode(ir1Pin, INPUT);
  pinMode(relais1Pin, OUTPUT);
  pinMode(ir2Pin, INPUT);
  pinMode(relais2Pin, OUTPUT);
}

void loop() {
  digitalWrite(relais1Pin, HIGH);
  digitalWrite(ir1Pin, HIGH);
 
  int i1 = digitalRead(ir1Pin);
  int r1 = digitalRead(relais1Pin);

  if ((i1 == LOW) && (r1 == HIGH) && (millis() - pausemillis1 > pausezeit1))  {
      Serial.println("Sensor 1: Objekt erkannt!");     
      digitalWrite(relais1Pin, LOW);                               
      laufmillis1 = millis();
  }
  if ((r1 == LOW) && (millis() - laufmillis1 > laufzeit1)) {
       Serial.println("Relais ausgeschaltet!");
       digitalWrite(relais1Pin, HIGH);
       pausemillis1 = millis();
  }
}


Alles drin alles dran. Nichts funktioniert :( SObald ich die millis Funktion mit drin hab reagiert weder das Relais noch der Sensor.
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jun 30, 2020, 02:16 pm
gib dir auch die Werte deiner Variablen auf der seriellen aus bevor du pins veränderst!
Vermutlich hast du eine falsche Logik.

da du es zweimal machen musst (für beide Ifs), mach dir eine eigene Funktion
Code: [Select]

void debugAusgabe()
{

Serial.print ("irPin"); Serial.println(digitalRead(irPin);
Serial.print ("millis"); Serial.println(millis()); // mit der Unschönheit, dass es bei der Ausgabe schon weiter ist, musst leben
Serial.print ("pausemillis1"); Serial.println(pausemillis1);
usw.



zumindest kannst du dann beobachten auf Grund welcher Werte du in welchem if gelandest bist und deine (hingeschriebene) Logik überprüfen
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jun 30, 2020, 02:29 pm
Quote
Ich gehe das hier nochmal Step für Step für einen Kreis durch. Vielleicht könnt ihr fehlerhafte Gedankengänge feststellen und mich korrigieren:
Ich kann leider so vielen Entscheidungen/Bedingungen nicht folgen.
(und du selber offensichtlich auch nicht wirklich)

Da wäre also ein Punkt wo man/du ansetzen könntest.
Quote
Tipp:
Denke in Zuständen
Benenne die Zustände
Schaffe klare Zustandswechsel.
Beispiel:
Code: [Select]
enum Zustand {Bereitschaft,Pumpen,Pausieren};



Ein Tipp am Rande:
Das durchnummerieren von Variablen/Konstanten ist eigentlich IMMER eine schlechte Idee.
Es führt zu Codeduplikaten
Zu C&P Fehlern.
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jun 30, 2020, 05:41 pm
Code: [Select]

void loop() {
 digitalWrite(relais1Pin , HIGH);
 digitalWrite(ir1Pin, HIGH);

[...]

Was soll da passieren?

Code: [Select]

int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(ir1Pin);
[...]
if ((i1 == LOW) && (r1 == HIGH)


Was soll da passieren?
Hinweis: Diese Bedingung kann niemals erfüllt sein.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jun 30, 2020, 11:20 pm
Was soll da passieren?

Code: [Select]

int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(ir1Pin);
[...]
if ((i1 == LOW) && (r1 == HIGH)


Was soll da passieren?
Hinweis: Diese Bedingung kann niemals erfüllt sein.

Zu 1.
Die Idee war, die beiden Bauteile erstmal auf den Zustand high, also nicht aktiv zu zwingen.


Zu 2.
Es heißt natürlich
int i1 = digitalRead(ir1Pin);
int r1 = digitalRead(relais1Pin);

War ein Kopierfehler.


Bin bisher auch noch nicht zu einer Lösung gekommen. Um die Anlage zu testen und Versuche zu fahren läuft das Programm erstmal notwendigerweise mit der einfachen delay Variante.



Um dem ganzen ein wenig Durchblick zu verschaffen: es geht um eine Anlage die über zwei Kreise zwei bestimmte Desinfektionsmittel für hygienische Bereiche mittels zweier Pumpen, die über zwei Relais geschaltet werden, auftragen. Die beiden Kreise müssen am Ende zwingend unabhängig voneinander betrieben werden können,  da zu unterschiedlichen Zeiten unterschiedliche Mittel genutzt werden müssen.
Die Anlage steht nun und wird getestet. Da ich mit dem Code leider nicht weiterkomme, greife ich für Testzwecke auf meine erste Variante zurück.
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 01, 2020, 06:28 am
Zu 1.
Die Idee war, die beiden Bauteile erstmal auf den Zustand high, also nicht aktiv zu zwingen.

Die Anlage steht nun und wird getestet. Da ich mit dem Code leider nicht weiterkomme, greife ich für Testzwecke auf meine erste Variante zurück.
Du versuchst mit einer Krücke (delay) Deinen Fehler zu verwischen.
Kann man machen.

Was war denn an den Coden #6 #12 #14 #17 und schliesslich #20 nicht verständlich?
Gerade #12 ist doch genau das, was Du jetzt versuchst.


Was meinst Du denn, wie lange ein Durchlauf von loop() dauert?
Mit jedem Durchlauf schreibst Du - egal was da vorher passiert:

void loop() {
digitalWrite(relais1Pin, HIGH);

Du hörst nicht mal einen Ansatz eines Klacken von Deinem Relais - das Ding ist ständig HIGH!

In #23 schreibst Du:
Quote
In meinem Nachbau hab ich allerdings das Problem, dass das Relais nach Einschalten des Arduino permanent schaltet (1s aus, 5s an) Was läuft falsch?
Mach ein Bild vom Aufbau. Das man alle Kabel und Verbindungen erkennt.
Wenn permanent geschalten wird, ist der ir-INPUT ständig auf HIGH.

Wenn Du 1Sek aus und 5s an hast, beschreibt es das, auf was ich Dich in #5 ganz fett hingewiesen habe!
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jul 01, 2020, 07:15 am
hast du die Seriell Ausgaben ergänzt so wie in #26 empfohlen?
Welche neue Erkenntnis hast du daraus?

Hast du verstanden was dir Combie in #27 mitgeteilt hat?

Darauf aufbauend vieleicht noch ein Tipp: so lange du dein Programm nicht nachvollziehen kannst:
vermeide die langen If Bedingungen. Zerteile diese

aus

if ((i1 == LOW) && (r1 == HIGH) && (millis() - pausemillis1 > pausezeit1))

mach

Code: [Select]

if ((i1 == LOW)
{
  Serial.println("i1==LOW");
  if (r1 == HIGH)
  {
     Serial.println("r1==HIGH");
     if (millis() - pausemillis1 > pausezeit1))
     {
       Serial.println("Zeitablauf")
      ...



dann siehst du auch genau welche deine Bedinungen nicht das machst was du bisher geglaubt hast, was sie macht. In einer Kette von 3 UND ist es für dich offenbar schwierig rauszufinden, was an der  Logik nicht passt. Also zerlege es in kleine Teilschritte!

In aller Deutlichkeit: Nutze Serial Ausgaben um den Ablauf deines Programms zu verfolgen und Logikfehler zu erkennen!(!!!)
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 08:16 am
@ My_xy

Ich versuche nicht meine Fehler zu vertuschen. Ich brücke lediglich die Zeit bis mein Programm so funktioniert wie es gewünscht ist.

Die Codes sind super. Sie funktionieren in der Simulation auch wunderbar. In der Praxis sieht es alledings anders aus!

Muss man den Status der Bauteile überhaupt festsetzen? Ich meine irgendwo gelesen zu haben, das undefinierte Zustände PingPong spielen "können".

digitalWrite(relais1Pin, HIGH); vom loop in setup packen? Wenn ich mich recht erinnere, wird setup ja nur einmalig beim Start des Arduino ausgeführt.


Der Aufbau funktioniert mit der delay Variante ohne Probleme. Daher wäre es mir ein Rätsel, wenn es letztendlich an der Schaltung liegt. Habe trotzdem mal ein paar Bilder gemacht. Der Teufel ist ja bekanntlich ein Eichhörnchen :))



@noiasca

Ja das habe ich gemacht. Und nein ich hatte gestern keine Zeit mehr alles umzusetzen was mir emfpohlen wurde. Zudem kommt ehrlich gesagt auch ein wenig Ratlosigkeit und Unwissenheit meinerseits dazu :) Ich versuche mein betses. Allerdings fehlt mir im Gegensatz zu euch einfach die Erfahrung, um alles umzusetzen was ihr so von euch gebt.

Die Zerteilung werde ich gleich definitiv mal vornehmen. Eine einfache Verkettung von if Bedingungen, richtig?


---> Mehr Bilder kommen gleich. Bin noch forentechnisch begrenzt was die Menge angeht :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jul 01, 2020, 08:19 am
Eben die UND Verkettungen auflösen und geschachtelte If hinschreiben (eins nach dem anderen) um die Serial.print Ausgaben zu ermöglichen.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 09:59 am
Code: [Select]

[...]
10:01:19.748 -> Zeitablauf Pause
10:01:19.748 -> Zeitablauf Pause
10:01:19.788 -> Zeitablauf Pause
10:01:19.788 -> Zeitablauf Pause
10:01:19.828 -> irPin[i]==LOW               (Sensor erkennt Bewegung)
10:01:19.828 -> Zeitablauf Laufzeit         (Laufzeit beginnt....
10:01:19.868 -> pumpPin[i]==HIGH          ..... Pumpe soll hier auf LOW schalten....
10:01:19.868 -> Sensor 1: Objekt erkannt!
10:01:21.828 -> Zeitablauf Pause            (Laufzeit vorbei, Timer der Pause beginnt...
10:01:21.868 -> Pumpe aus!                   ... und die Pumpe wird abgeschaltet)
10:01:21.868 -> pumpPin[i]==HIGH
10:01:21.868 -> Zeitablauf Pause            (Wartezustand)
10:01:21.908 -> Zeitablauf Pause
10:01:21.948 -> Zeitablauf Pause
10:01:21.948 -> Zeitablauf Pause
10:01:21.948 -> Zeitablauf Pause

[...]


So... die If´s mal ein wenig aufgebröselt.

Code: [Select]

// Anzahl Kreise
const int Kreise = 1;

// Pin-Belegung
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};

// Zeitangaben
const int laufzeit[] = {2000, 2000};      // Laufzeit Pumpen
const int pausezeit[] = {3000, 3000} ;    // Zwangspause Pumpen

// Zeit- / Zählervariablen
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};


// Programm
void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT);
    pinMode(pumpPin[i], OUTPUT);
    digitalWrite(irPin[i], HIGH);
    digitalWrite(pumpPin[i], HIGH);
  }
}
void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if (digitalRead(irPin[i]) == LOW)
    {
      Serial.println("irPin[i]==LOW");
      if (millis() - pausemillis[i] > pausezeit[i])
      {
        Serial.println("Zeitablauf Laufzeit");
        if (!digitalRead(pumpPin[i]) == HIGH)
        {
            Serial.println("pumpPin[i]==HIGH");
            Serial.print("Sensor ");
            Serial.print(i+1);
            Serial.println(": Objekt erkannt!");
            digitalWrite(pumpPin[i], HIGH);
            laufmillis[i] = millis();
        }
      }
    }
    if (millis() - laufmillis[i] > laufzeit[i])
    {
      Serial.println("Zeitablauf Pause");
      if (digitalRead(pumpPin[i]))
      {
        Serial.println("Pumpe aus!");
        digitalWrite(pumpPin[i], LOW);
        Serial.println("pumpPin[i]==HIGH");
        pausemillis[i] = millis();
      }
    }
  }
}


Funktioniert schonmal ganz gut!

Das einzige Problem was vorliegt ist, dass das Relais direkt nach Einschalten des Arduino die Laufzeit startet und anschließend das Relais auf LOW (betätigt) setzt. Wechsel ich die Zustände im Code, reagiert das Relais allerdings nicht mehr.

Soll:
1. Arduino Ein / Reset -> Wartezustand (Sensor und Relais auf HIGH)
2. Programm wartet auf Erfüllung der Bedingung. Das heißt die Pumpe ist aus und der Sensor erkennt eine Bewegung (Sensor == LOW, Pumpe == HIGH, Zwangspause vorbei))
2. Hand vor Sensor -> Relais schaltet ein (also auf LOW)
3. Relais bleibt gemäß der festgelegten Dauer von "Laufzeit" betätigt und schaltet danach ab
4. Timer der Zwangspause läuft ab -> Neubeginn des Zyklus möglich

Ist:
1. Arduino Ein / Reset -> Relais ist aus (HIGH), Laufzeit läuft ab (2s) und Relais schaltet direkt auf LOW (also Pumpe betätigt) -> Wartezustand
2. Warten auf Erfüllung der Bedingung (wie oben)
3. Hand vor Sensor -> Relais schaltet ab (also auf HIGH)
4. Relais bleibt gemäß der festgelegten Dauer von "Laufzeit" UNbetätigt und schaltet danach wieder ein
5. Timer der Zwangspause läuft ab -> Neubeginn des Zyklus möglich

Ist, wenn Zustände gewechselt werden:
1. Arduino Ein / Reset -> Stillstand (Relais auf HIGH, also aus)
Code: [Select]

10:24:39.321 -> Pumpe aus!
10:24:39.321 -> pumpPin[i]==HIGH
10:24:39.361 -> Zeitablauf Pause
10:24:39.361 -> Pumpe aus!
10:24:39.401 -> pumpPin[i]==HIGH
10:24:39.401 -> Zeitablauf Pause
10:24:39.401 -> Pumpe aus!
10:24:39.441 -> pumpPin[i]==HIGH
10:24:39.441 -> Zeitablauf Pause
10:24:39.481 -> Pumpe aus!
10:24:39.481 -> pumpPin[i]==HIGH
10:24:39.521 -> Zeitablauf Pause
10:24:39.521 -> Pumpe aus!
10:24:39.521 -> pumpPin[i]==HIGH
10:24:39.561 -> Zeitablauf Pause
10:24:39.561 -> Pumpe aus!

2. Wenn hand vor Sensor
Code: [Select]
10:25:45.719 -> pumpPin[i]==HIGH
10:25:45.759 -> irPin[i]==LOW
10:25:45.759 -> Zeitablauf Pause
10:25:45.799 -> Pumpe aus!
10:25:45.799 -> pumpPin[i]==HIGH
10:25:45.799 -> irPin[i]==LOW
10:25:45.839 -> Zeitablauf Pause
10:25:45.839 -> Pumpe aus!

3. keinerlei Reaktion



Wo übersehe ich etwas? Rein theoretisch müsste ich doch nur die beiden digitalWrite(pumpPin) Zustände im Code wechseln?  :o

Code: [Select]

// Anzahl Kreise
const int Kreise = 1;

// Pin-Belegung
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};

// Zeitangaben
const int laufzeit[] = {2000, 2000};      // Laufzeit Pumpen
const int pausezeit[] = {3000, 3000} ;    // Zwangspause Pumpen

// Zeit- / Zählervariablen
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};


// Programm
void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT);
    pinMode(pumpPin[i], OUTPUT);
    digitalWrite(irPin[i], HIGH);
    digitalWrite(pumpPin[i], HIGH);
  }
}
void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if (digitalRead(irPin[i]) == LOW)
    {
      Serial.println("irPin[i]==LOW");
      if (millis() - pausemillis[i] > pausezeit[i])
      {
        Serial.println("Zeitablauf Laufzeit");
        if (digitalRead(pumpPin[i]) == HIGH)
        {
            Serial.println("pumpPin[i]==HIGH");
            Serial.print("Sensor ");
            Serial.print(i+1);
            Serial.println(": Objekt erkannt!");
            digitalWrite(pumpPin[i], LOW);              Hier auf LOW schalten, damit das Relais eingeschaltet wird
            laufmillis[i] = millis();
        }
      }
    }
    if (millis() - laufmillis[i] > laufzeit[i])
    {
      Serial.println("Zeitablauf Pause");
      if (digitalRead(pumpPin[i]))
      {
        Serial.println("Pumpe aus!");
        digitalWrite(pumpPin[i], HIGH);          Hier auf HIGH wechseln, damit das Relais abgeschaltet wird
        Serial.println("pumpPin[i]==HIGH");
        pausemillis[i] = millis();
      }
    }
  }
}
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 01, 2020, 10:29 am
Wo übersehe ich etwas? Rein theoretisch müsste ich doch nur die beiden digitalWrite(pumpPin) Zustände im Code wechseln?  
Die Relais sind LOW-aktiv.
Das heisst, wenn der Output-PIN LOW ist, zieht das Relais an.

Wenn Du willst, das das Relais mit dem Start etwas macht, ohne das der IR-PIN einen Durchgang bemerkt, dann musst Du im Setup:
a) Den PumpenPIN setzen (LOW)
UND
b) Die Lauzeitvariable setzen (laufmillis=millis())

Die Frage ist, ist der IR-Sensor HIGH oder LOW aktiv?
Steht da irgendeine Bezeichnung drauf?

Im Normalfall sind die eigentlich HIGH-aktiv, Dein Code prüft auf LOW.
Las das:     digitalWrite(irPin, HIGH); mal komplett weg.

Und das:       Serial.println("Zeitablauf Pause");
wird ständig gemacht, weil Du nicht prüfst, ob der PIN auch den dementsprechenden Zustand hat.
 
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 10:54 am
Das ist das genutze Relais: 2-Relais Modul 5V (https://www.az-delivery.de/products/2-relais-modul#description)
Das ist der Sensor: E18-D80NK (https://www.roboter-bausatz.de/media/pdf/44/55/49/RBS10158-Manual_IR-Sensor-Switch-E18.pdf)

Wenn ich richtig gelesen habe, ist der Sensor LOW-aktiv (Whendistance of Sensor <= the specified distance detection, LED Status is ON and OUTPUT = 0)

Wenn ich dich richtig verstanden habe, müsste es folgendermaßen aussehen:

Code: [Select]
// Anzahl Kreise
const int Kreise = 1;

// Pin-Belegung
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};

// Zeitangaben
const int laufzeit[] = {2000, 2000};      // Laufzeit Pumpen
const int pausezeit[] = {3000, 3000} ;    // Zwangspause Pumpen

// Zeit- / Zählervariablen
unsigned long pausemillis[] = {0, 0};
unsigned long laufmillis[] = {0, 0};

// Programm
void setup()
{
  Serial.begin(9600);
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT);
    pinMode(pumpPin[i], OUTPUT);
    const int pumpPin[] = {5, 6};
    digitalWrite(pumpPin[i], LOW);
    unsigned long laufmillis[] = {millis(), millis()};
  }
}
void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if (digitalRead(irPin[i]) == LOW)
    {
      Serial.println("irPin[i]==LOW");
      if (millis() - pausemillis[i] > pausezeit[i])
      {
        Serial.println("Zeitablauf Laufzeit");
        if (!digitalRead(pumpPin[i]) == HIGH)
        {
            Serial.println("pumpPin[i]==HIGH");
            Serial.print("Sensor ");
            Serial.print(i+1);
            Serial.println(": Objekt erkannt!");
            digitalWrite(pumpPin[i], LOW);
            laufmillis[i] = millis();
        }
      }
    }
    if (millis() - laufmillis[i] > laufzeit[i])
    {
      if (digitalRead(pumpPin[i]) == HIGH) {
        Serial.println("Zeitablauf Pause");
        if (digitalRead(pumpPin[i]))
        {
          Serial.println("Pumpe aus!");
          digitalWrite(pumpPin[i], HIGH);
          Serial.println("pumpPin[i]==HIGH");
          pausemillis[i] = millis();
        }
      }

    }
  }
}



Funktioniert weiterhin wie vorher.
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 01, 2020, 11:58 am
Das ist das genutze Relais: 2-Relais Modul 5V (https://www.az-delivery.de/products/2-relais-modul#description)
Das ist der Sensor: E18-D80NK (https://www.roboter-bausatz.de/media/pdf/44/55/49/RBS10158-Manual_IR-Sensor-Switch-E18.pdf)

Wenn ich richtig gelesen habe, ist der Sensor LOW-aktiv (Whendistance of Sensor <= the specified distance detection, LED Status is ON and OUTPUT = 0)

Funktioniert weiterhin wie vorher.
Ich hab das mal nachgebaut. Wenn der Sensor LOW-aktiv sein soll, braucht es einen Pullup am ir-PIN.

Zudem habe ich im Setup festgelegt, das die Laufzeit dort gesetzt wird.
Ohne setzen:
Code: [Select]
11:51:48.540 -> Starte Setup
11:51:48.540 -> PumpenPIN 1 hat jetzt Status: 0
11:51:51.573 -> Pumpe aus!
11:51:51.573 -> PumpenPIN 1 hat jetzt Status: 1

mit setzen:
Code: [Select]
11:52:35.089 -> Starte Setup
11:52:35.089 -> PumpenPIN 1 hat jetzt Status: 0
11:52:38.087 -> Pumpe aus!
11:52:38.087 -> PumpenPIN 1 hat jetzt Status: 1

Wenn Du die millis also nicht in die Variable übernimmst, läuft die Pumpe 30ms länger im ersten Durchlauf.

Code: [Select]

/*
    Code für Topic https://forum.arduino.cc/index.php?topic=692478
    1.7.2020 - Post #37
*/


// HIER DIE ANZAHL DER KREISE ANGEBEN
const int Kreise = 1;
// Für jeden Kreis ab hier einen Wert angeben!
// Hier die Angabe der PIN
const int irPin[] = {2, 3};
const int pumpPin[] = {5, 6};
// Hier die Angabe für die Zeiten
const unsigned int laufzeit[] = {3000, 3000};
const unsigned int pausezeit[] = {5000, 5000} ;
// Zeitvariablen init immer 0
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};
// Ende Eintrag Werte
void setup()
  {
  Serial.begin(115200);
  Serial.println("Starte Setup");
  for (int i = 0; i < Kreise; i++)
    {
    pinMode(irPin[i], INPUT_PULLUP);
    pinMode(pumpPin[i], OUTPUT);
    digitalWrite(pumpPin[i], LOW);
    serielleAusgabe(i);
    laufmillis[i] = millis();
    }
  }
void loop()
  {
  for (int i = 0; i < Kreise; i++)
    {
    if ((!digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (digitalRead(pumpPin[i])))
      {
      Serial.print("Sensor ");
      Serial.print(i + 1);
      Serial.println(": Objekt erkannt!");
      digitalWrite(pumpPin[i], LOW);
      serielleAusgabe(i);
      laufmillis[i] = millis();
      }
    if ((!digitalRead(pumpPin[i])) && (millis() - laufmillis[i] > laufzeit[i]))
      {
      Serial.println("Pumpe aus!");
      digitalWrite(pumpPin[i], HIGH);
      serielleAusgabe(i);
      pausemillis[i] = millis();
      }
    }
  }

void serielleAusgabe(int y)
  {
  Serial.print("PumpenPIN ");
  Serial.print(y+1);
  Serial.print(" hat jetzt Status: ");
  Serial.println(digitalRead(pumpPin[y]));
  }

Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 12:30 pm
Okay... das leuchtet ein. Von alleine wäre ich da aber niemals hingekommen. Danke für deinen Hinweis!

Ich habe das ganze jetzt mal getestet und es funktioniert soweit gut. Das einzige Problem das bestehen bleibt ist, dass die beiden Relais beim Start / Reset noch kurzzeitig betätigt werden und somit die Pumpen schon arbeiten. Lässt sich das noch irgendwie vermeiden?

Ansonsten funktioniert es genau so wie es sein soll. Tausend dank!
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 01, 2020, 01:13 pm
Okay... das leuchtet ein. Von alleine wäre ich da aber niemals hingekommen. Danke für deinen Hinweis!
Dafür ist so'n Forum da.... ;)

Quote
Das einzige Problem das bestehen bleibt ist, dass die beiden Relais beim Start / Reset noch kurzzeitig betätigt werden und somit die Pumpen schon arbeiten. Lässt sich das noch irgendwie vermeiden?
Aehm.. Ich versteh das jetzt nicht. Sinn der Übung war doch mit laufender Pumpe zu starten.
Nach dem Reset starten die Pumpen einmal, weil im Setup so festgelegt.
Wenn Du das unterbinden möchtest, musst Du Zeile 28:
    digitalWrite(pumpPin, LOW);
ändern und ein HIGH rein schreiben.
Dann soll auch Zeile 30 auskommentiert werden.

Und nochwas: tausche mal bitte die Zeilen 29 gegen 30 , 43 gegen 44 und 50 gegen 51.
(serielleAusgabe(i); gegen den millis()-Merker)
Damit werden die Zeiten genauer, da sonst erst nach der Ausgabe der Startpunkt gesetzt wird.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 02:39 pm
Dafür ist so'n Forum da.... ;)

Aehm.. Ich versteh das jetzt nicht. Sinn der Übung war doch mit laufender Pumpe zu starten.
Nach dem Reset starten die Pumpen einmal, weil im Setup so festgelegt.
Wenn Du das unterbinden möchtest, musst Du Zeile 28:
    digitalWrite(pumpPin, LOW);
ändern und ein HIGH rein schreiben.
Dann soll auch Zeile 30 auskommentiert werden.

Und nochwas: tausche mal bitte die Zeilen 29 gegen 30 , 43 gegen 44 und 50 gegen 51.
(serielleAusgabe(i); gegen den millis()-Merker)
Damit werden die Zeiten genauer, da sonst erst nach der Ausgabe der Startpunkt gesetzt wird.

Zuallererst: Entschuldige wenn ich das falsch rübergebracht habe. Die Pumpe soll nicht direkt betätigt werden wenn das System mit Saft versorgt wird.

Zweitens: Hab ich gemacht. Funktioniert wunderbar! Vielen Dank!!

Drittens: Eine Frage zum Abschluss. Wo und womit platziere ich am besten die Funktion zur manuellen Betätigung der Pumpe mit einem normalen Schließ-Taster für einen Dauerlauf? (hier geht es darum, die Pumpe manuell zu "füttern" bis die Flüssigkeit dort ist wo sie hingehört (oder zum entlüften). Also solange der Taster betätigt wird, soll das Relais schalten. Mit if, while, do while, was ganz anderes?

Ganz grob:
Code: [Select]

if ((digitalRead(buttonPin[i]) == HIGH) && (digitalRead(irPin[i]) == HIGH))
  {
    digitalWrite(pumpPin[i], LOW);
   }

Habe ein wenig Sorge, dass ich den bestehen Code streife und das Relais nen Zappelkasper macht.


Ansonsten nochmal - Tausend Dank!
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 01, 2020, 03:02 pm
Hattest du diese Zusatzanforderung schon mal erwähnt?

Ist mir zumindest nicht aufgefallen...

Übrigens:
Salamitaktik ist mit der einfachste Weg, die Helfer zu frustrieren.
Denn bei jeder Scheibe ist klar/möglich/wahrscheinlich, dass alles/einiges vorherige für die Tonne produziert wurde.

Ist nicht immer alles für die Tonne. Aber viel zu oft, eben doch.
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jul 01, 2020, 03:05 pm
Quote
Drittens: Eine Frage zum Abschluss. Wo und womit platziere ich am besten die Funktion zur manuellen Betätigung der Pumpe mit einem normalen Schließ-Taster für einen Dauerlauf? (hier geht es darum, die Pumpe manuell zu "füttern" bis die Flüssigkeit dort ist wo sie hingehört (oder zum entlüften). Also solange der Taster betätigt wird, soll das Relais schalten. Mit if, while, do while, was ganz anderes?

na jetzt überleg mal ganz scharf.
Hast du nicht schon ein if, dass deine Pumpe einschaltet?
Was spricht dagegen in diese IF Kette auch noch ein ODER digitalRead(meinManuellerEingangsPin)== zu ergänzen?

läuft halt dann vermutlich die Nachlaufzeit nach.
Stört das? Dann mit weiteren Ifs auch den Nachlauf beenden.

Spätestens jetzt wären wir bei einem Zustandsautomaten / FSM und einem weiteren Status.
Das kommt davon wenn man Anforderungen so Scheibchenweise rauslässt, dann muss man in einer späteren Phase doch wieder mehr Umbauen.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 03:26 pm
na jetzt überleg mal ganz scharf.
Hast du nicht schon ein if, dass deine Pumpe einschaltet?
Was spricht dagegen in diese IF Kette auch noch ein ODER digitalRead(meinManuellerEingangsPin)== zu ergänzen?

läuft halt dann vermutlich die Nachlaufzeit nach.
Stört das? Dann mit weiteren Ifs auch den Nachlauf beenden.

Spätestens jetzt wären wir bei einem Zustandsautomaten / FSM und einem weiteren Status.
Das kommt davon wenn man Anforderungen so Scheibchenweise rauslässt, dann muss man in einer späteren Phase doch wieder mehr Umbauen.
Hattest du diese Zusatzanforderung schon mal erwähnt?

Ist mir zumindest nicht aufgefallen...

Übrigens:
Salamitaktik ist mit der einfachste Weg, die Helfer zu frustrieren.
Denn bei jeder Scheibe ist klar/möglich/wahrscheinlich, dass alles/einiges vorherige für die Tonne produziert wurde.

Ist nicht immer alles für die Tonne. Aber viel zu oft, eben doch.
Wie ich das umsetzen kann ist mir bewusst. Nur stelle ich mir immer die Frage, ob es elegantere / zweckmäßigere Lösungen gibt :)
Die Anforderung stand bisher nicht zu Debatte. Bei den Versuchen hat sich bloß gezeigt, dass die Pumpe bei der ersten Inbetriebnahme nur schlecht das Medium anzieht, wenn nur kurze Stöße getätigt werden. Ich will hier niemanden frustrieren oder nerven. Sollte das so sein, verzeiht mir bitte.

Ich hab es wie folgt gelöst und es erfüllt seinen Zweck.

Code: [Select]

   const int buttonPin[] = {8, 9};

  -> setup

  pinMode(buttonPin[i], INPUT);

  -> loop

    if ((digitalRead(buttonPin[i]) == LOW) && (digitalRead(irPin[i]) == HIGH) && (digitalRead(relPin[i]) == HIGH))
    {
      while (digitalRead(buttonPin[i]) == LOW)
      {
        digitalWrite(irPin[i], HIGH);
        digitalWrite(relPin[i], LOW);
        delay(250);
      }
    }
    else
    [...]


Ich habe eine weitere if- und whileAnweisung geschrieben. Solange ich den Taster gedrückt halte, läuft die Pumpe. Durch delay erzeuge ich nach dem Lösen einen bewussten minimalen Nachlauf. Zusätzlich blockiert die Betätigung des Tasters die Infrarotsensoren und verhindern somit eine ungewollte Auslösung.


Ich bedanke mich bei allen Helfern. Dickes Karma+ und vielen Dank an euch alle! :)

Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 03:51 pm
Abschließend nochmal der gesamte Code, falls mal jemand etwas ähnliches brauch oder die Geeks ihn tunen wollen :)


Code: [Select]
// Anzahl Kreise
const int Kreise = 2;

// Angabe PIN-Belegung
const int irPin[] = {2, 3};
const int relPin[] = {5, 6};
const int buttonPin[] = {8, 9};

// Zeitangabe
const unsigned int laufzeit[] = {1000, 2000};
const unsigned int pausezeit[] = {2000, 3000} ;

// Zeitvariablen init immer 0
unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};


void setup()
{
  Serial.begin(9600);
  Serial.println("Starte Setup");
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT_PULLUP);
    pinMode(relPin[i], OUTPUT);
    pinMode(buttonPin[i], INPUT);
    digitalWrite(relPin[i], HIGH);
    laufmillis[i] = millis();
    serielleAusgabe(i);
  }
}

void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    if ((digitalRead(buttonPin[i]) == LOW) && (digitalRead(irPin[i]) == HIGH) && (digitalRead(relPin[i]) == HIGH))
    {
      while (digitalRead(buttonPin[i]) == LOW)
      {
        digitalWrite(irPin[i], HIGH);
        digitalWrite(relPin[i], LOW);
        delay(250);
      }
    }
    else
    {
      if ((!digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (digitalRead(relPin[i])))
      {
        Serial.println(digitalRead(buttonPin[i]));
        Serial.print("Sensor ");
        Serial.print(i + 1);
        Serial.println(": Objekt erkannt!");
        digitalWrite(relPin[i], LOW);
        laufmillis[i] = millis();
        serielleAusgabe(i);
      }
      if ((!digitalRead(relPin[i])) && (millis() - laufmillis[i] > laufzeit[i]))
      {
        Serial.println("Pumpe aus!");
        digitalWrite(relPin[i], HIGH);
        pausemillis[i] = millis();
        serielleAusgabe(i);
      }
    }
  }
}

void serielleAusgabe(int y)
{
  Serial.print("PumpenPIN ");
  Serial.print(y + 1);
  Serial.print(" hat jetzt Status: ");
  Serial.println(digitalRead(relPin[y]));
}
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 01, 2020, 07:57 pm
Abschließend nochmal der gesamte Code, falls mal jemand etwas ähnliches brauch oder die Geeks ihn tunen wollen :)


Code: [Select]
// Anzahl Kreise
const int Kreise = 2;

// Angabe PIN-Belegung
const int irPin[] = {2, 3};
const int relPin[] = {5, 6};
const int buttonPin[] = {8, 9};

Na bitte! Du hast es mitgenommen.

Code: [Select]

        delay(250);

um es hier wieder zu versauen!
NEIN!!! Kein delay() in produktiven Umgebungen!

Es wurde bereits erwähnt, die Anforderung zu ändern sehe ich ebenfalls kritisch - hier wurde im Einsatz festgestellt, das da was fehlt.
Auch wenn Software "lebt" heisst das nicht, das sowas jederzeit mal eben so "angepasst" werden kann.
Und Nein, BMA, Entrauchung, Türsteuerungen etc. beim BER sind kein Beispiel dafür das es geht.

Zurück zur Sachfrage:
Was mich irritiert, warum Du den ir-PIN sperren willst.
Das halte ich für unsinnig.
Dazu kommt, das Du Deine Bedingungen mehrfach benutzt. Das benötigt unnötige Rechenzeit und Du kannst nicht auschliessen, das sich zwischen if und else der Wert, von dem Du abhängig bist, ändert.

Nebenbei hast Du auch noch ein Problem im Setup mit der Initialisierung deiner Buttons.
Wenn Du auf LOW prüfen willst, musst Du dafür sorgen, das, wenn die Taste NICHT gedrückt ist ein HIGH-Pegel anliegt.
Das geht zum einen mit einem externen Widerstand von +5V nach PIN oder mit der Initialisierung des PULLUP im Chip selbst.
Wenn Du die externe Variante nicht hast, musst Du zwingend INPUT_PULLUP für
Code: [Select]
pinMode(buttonPin[i])
 festlegen!

Und dann würde ich das, was bisher lief nicht anrühren.
Neue Bedingung? Neuer Ablauf!

Ich denk noch drüber nach, ob ich Dir einen Vorschlag mache.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 01, 2020, 10:51 pm
Na bitte! Du hast es mitgenommen.

Code: [Select]

        delay(250);

um es hier wieder zu versauen!
NEIN!!! Kein delay() in produktiven Umgebungen!

Es wurde bereits erwähnt, die Anforderung zu ändern sehe ich ebenfalls kritisch - hier wurde im Einsatz festgestellt, das da was fehlt.
Auch wenn Software "lebt" heisst das nicht, das sowas jederzeit mal eben so "angepasst" werden kann.
Und Nein, BMA, Entrauchung, Türsteuerungen etc. beim BER sind kein Beispiel dafür das es geht.

Zurück zur Sachfrage:
Was mich irritiert, warum Du den ir-PIN sperren willst.
Das halte ich für unsinnig.
Dazu kommt, das Du Deine Bedingungen mehrfach benutzt. Das benötigt unnötige Rechenzeit und Du kannst nicht auschliessen, das sich zwischen if und else der Wert, von dem Du abhängig bist, ändert.

Nebenbei hast Du auch noch ein Problem im Setup mit der Initialisierung deiner Buttons.
Wenn Du auf LOW prüfen willst, musst Du dafür sorgen, das, wenn die Taste NICHT gedrückt ist ein HIGH-Pegel anliegt.
Das geht zum einen mit einem externen Widerstand von +5V nach PIN oder mit der Initialisierung des PULLUP im Chip selbst.
Wenn Du die externe Variante nicht hast, musst Du zwingend INPUT_PULLUP für
Code: [Select]
pinMode(buttonPin[i])
 festlegen!

Und dann würde ich das, was bisher lief nicht anrühren.
Neue Bedingung? Neuer Ablauf!

Ich denk noch drüber nach, ob ich Dir einen Vorschlag mache.
Aua. So dolle verk****? :(

Lass mich morgen früh nochmal daran arbeiten um eine andere Variante zu präsentieren. Wenn die dann auch unzufrieden machen sollte nehme ich gerne nochmal Hilfe an. Aber erstmal versuche ich deine Ratschläge umzusetzen und selbst was auf die Beine zu stellen.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 02, 2020, 07:45 am
So. Also wie du sagtest, einfach erweitern.

Den bestehenden Code habe ich um

Code: [Select]
const int buttonPin[] = {8, 9};

pinMode(buttonPin[i], INPUT_PULLUP);

if (!digitalRead(buttonPin[i]))
{
   digitalWrite(relPin[i], LOW);
}


erweitert.

Damit ist delay() raus (Memo an mich selbst: Streiche delay() aus dem Kopf um my_xy nicht auf die Palme zu bringen). Eine einfache Betätigung des Relais, solange der Taster des jeweiligen Kreises betätigt wird.

Ich muss vorerst mit dem PULLUP arbeiten, da ich hier keine Widerstände vor Ort habe.
Title: Re: Zwei parallele Programme laufen lassen
Post by: noiasca on Jul 02, 2020, 08:16 am
der INPUT_PULLUP ist per se nichts schlechtes. Ich würde sogar sagen, besser als Widerstände mit ihren langen aber hauchdünnen Beinchen in ein Breadboard gewurstelt.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 02, 2020, 12:36 pm
der INPUT_PULLUP ist per se nichts schlechtes. Ich würde sogar sagen, besser als Widerstände mit ihren langen aber hauchdünnen Beinchen in ein Breadboard gewurstelt.
Kein Breadboard. Schaltschrank, alles ordentlich :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 07, 2020, 11:35 am
So. Nach einigen Tagen der Testerei steht noch ein Problem im Raum.

Und zwar muss die Leitung nach der Pumpe entlastet werden, damit der darin stehende Druck abfällt (und nein, die Pumpe kann nicht kurzzeitig in die andere Richtung drehen ;) ). Dazu nutze ich für jeden Kreis ein seperates 2/2 Wegeventil, dass elektrisch für jeweils 200ms über ein weiteres Relais angesteuert werden soll. Hardwareseitig funktioniert alles optimal.

Beim Code hapert es allerdings mal wieder. Wie auch bei den anderen gehe ich davon aus, dass ich erneut mit millis() arbeiten muss. Die Entlastung soll DIREKT nach der Laufzeit der Pumpe stattfinden (Laufzeit vorbei, Wegeventil für 200ms öffnen, Wegeventil schließen).

Dazu habe ich folgendes ergänzt:

Code: [Select]

const int druckPin[] = {10, 11};    // Ausgänge für die Relaissteuerung
 

const unsigned int entlastungszeit[] = {200, 200};    // Entlastungszeit

unsigned long entlastungmillis[] = {0, 0};


void setup() {
pinMode(druckPin[i], OUTPUT);    // Relaisansteuerung natürlich als OUTPUT
}



Die manuelle Entlastung mit Rücklauf am Ende des Codes funktioniert ohne Probleme.


Ich habe nun versucht, die automatische Entlastung an die Laufzeit anzuknüpfen. Wahrscheinlich liegt hier schon der Fehler?

Code: [Select]

void loop()
{
  for (int i = 0; i < Kreise; i++)
  {

    if ((!digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (digitalRead(relPin[i])))           
    { 
      digitalWrite(relPin[i], LOW);                                                                                   
      laufmillis[i] = millis();                                                                                       
    } 
 
    if ((!digitalRead(relPin[i])) && (millis() - laufmillis[i] > laufzeit[i]))                                       
    {     
      digitalWrite(relPin[i], HIGH);                                                                                 
      pausemillis[i] = millis();                                                                                     

      entlastung[i] = 1;
      entlastungmillis[i] = millis();                                                                                 
    }

    if ((millis() > entlastungmillis[i] + entlastungszeit[i]) && (entlastung[i] == 1)) {                                                                                   
      digitalWrite(druckPin[i], LOW);                                                                               
      entlastung[i] = 0;
      }

    if (!digitalRead(buttonPin[i]))                                                                                   
    {                                                                                                                 
      digitalWrite(relPin[i], LOW);                                                                                   
      digitalWrite(druckPin[i], LOW);                                                                                 
    }
  }
}


Funktioniert alles nicht so ganz recht. Wo und wie positioniere ich die Entlastung am optimalsten? Hab schon einige Varianten ausprobiert und komme nie so recht dahin wo ich hin möchte.


Oder muss ich hier zwei  separate if-bedingung schreiben, die zum einen auf das Ende meiner Laufzeit prüfen, die Relais für´s Wegeventil schalten und zum anderen das Ende meiner Entlastung checken (was wiederrum in den Anfang der Zwangspause muss)? Ich bin verwirrt....
Das ganze funktioert ja als gedachter Kreislauf. Aber wie haue ich jetzt eine Zwischenaktion mit hinein, die parallel zu meiner Zwangspause arbeitet? Fragen über Fragen.

Hier mal mein gedachter Code mit zwei separaten if-Bedingungen:


Code: [Select]


const int Kreise = 2;

const int irPin[] = {2, 3};
const int relPin[] = {5, 6};
const int buttonPin[] = {8, 9};
const int druckPin[] = {10, 11};

const unsigned int laufzeit[] = {2500, 2500};
const unsigned int pausezeit[] = {3000, 3000};
const unsigned int entlastungszeit[] = {200, 200};

unsigned long laufmillis[] = {0, 0};
unsigned long pausemillis[] = {0, 0};
unsigned long entlastungmillis[] = {0, 0};

void setup()
{
  for (int i = 0; i < Kreise; i++)
  {
    pinMode(irPin[i], INPUT_PULLUP);
    pinMode(relPin[i], OUTPUT);
    pinMode(buttonPin[i], INPUT_PULLUP);
    pinMode(druckPin[i], OUTPUT);
    digitalWrite(relPin[i], HIGH);
    laufmillis[i] = millis();
  }
}

void loop()
{
  for (int i = 0; i < Kreise; i++)
  {
    // Nach Ablauf der Zwangspause: Pumpe bei Bewegung einschalten
    if ((!digitalRead(irPin[i])) && (millis() - pausemillis[i] > pausezeit[i]) && (digitalRead(relPin[i])))         
    {                                                                                                               
      digitalWrite(relPin[i], LOW);                                                                                 
      laufmillis[i] = millis();                                                                                     
    }   
   
    // Nach Ablauf der Pumpenlaufzeit: Abschalten und Zwangspause starten
    if ((!digitalRead(relPin[i])) && (millis() - laufmillis[i] > laufzeit[i]))                                     
    {                                                                                                 
      digitalWrite(relPin[i], HIGH);                                                                           
      pausemillis[i] = millis();                                                                                                                                                                     
    }

    // Nach Ablauf der Pumpenlaufzeit: Relais für Entlastung schalten
    if (millis() - laufmillis[i] > laufzeit[i])
    {                                                                                                                 
      digitalWrite(druckPin[i], LOW);                                                                                 
      entlastungmillis[i] = millis(); 
    }
   
    // Nach Ablauf der Entlastungszeit: Relais für Wegeventil abschalten
    if ((millis() > entlastungmillis[i] + entlastungszeit[i]))
    {                                                                                                                 
      digitalWrite(druckPin[i], HIGH);                                                                                 
    }

    // Manuelle Betätigung Entlüftungskreislauf
    if (!digitalRead(buttonPin[i]))                                                                                   
    {                                                                                                                 
      digitalWrite(relPin[i], LOW);                                                                                   
      digitalWrite(druckPin[i], LOW);                                                                               
    }
  }
}


Eines der Hauptprobleme hier ist, dass das Relais für das Wegeventil (druckPin) permanent betätigt bleibt (außer bei der normalen Auslösung durch IR-Sensor) und auf Dauer natürlich heiß wird.

Danke schonmal! :smiley-confuse:
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 07, 2020, 12:26 pm
Hmm...
Fein, noch eine Salamischeibe...
Ja, so ist das manchmal....


Quote
Ich bin verwirrt....
Wenn du den gewünschten Ablauf schon nicht mit Worten logisch hintereinander bekommst, dann wirds schwierig diesen zu programmieren.
Oder?

Quote
die parallel zu meiner Zwangspause arbeitet?
Du hast jetzt schon 2 Abarbeitungsfäden für die Pumpen.
Was hindert dich, für die Druckentlastungsventile 2 weitere Fäden aufzuspannen?


Mein Tipp:
Denke in Zuständen
Denke nebenläufig
Beachte den Daten und hier auch den Materialfluss
Baue Module und lass die Module miteinander quatschen (Nachrichten austauschen)

Konzentriere dich nicht so sehr auf den Kontrollfluss (if-else usw).
Denn wie du siehst werden die Bedingungen immer komplexer.
Ich bin da schon lange raus! (siehe Posting #24 und #27)
Ein Wunder dass du da noch durchblickst.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 07, 2020, 12:27 pm
Ich denke, dass ich den Fehler gefunden habe.

Vorher:
Code: [Select]

    if (millis() - laufmillis[i] > laufzeit[i])
    {                                                                                                                 
      digitalWrite(druckPin[i], LOW);                                                                                 
      entlastungmillis[i] = millis(); 
    }


Nachher:
Code: [Select]

    if (millis() - laufmillis[i] == laufzeit[i])
    {                                                                                                                 
      digitalWrite(druckPin[i], LOW);                                                                                 
      entlastungmillis[i] = millis();
    }


> in ==
Damit funktioniert es so wie es soll.

@ Combie. Wo genau fehlt der logische Zusammenhang im Text? Vielleicht kann ich es weiter erläutern, um es verständlicher zu machen.

Die Grundfunktion sieht wie folgt aus:
1. Wenn Sensor Bewegung erkennt -> Löse Pumpe aus
2. Wenn Pumpe eine definierte Zeit gelaufen ist -> Pumpe aus
3. Wenn Pumpe aus
     -> Entlastung der Druckleitung und
     -> Beginn einer Zwangspause bis zur erneut möglichen Betätigung
4. Manuelle Betätigung des Pumpenkreislaufes zur Entlüftung / Erstbefüllung

Habt ihr dennoch Verbesserungsvorschläge für mich?
Danke :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: Tommy56 on Jul 07, 2020, 12:35 pm
Nimm besser >= anstelle von >

Gruß Tommy
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 07, 2020, 01:17 pm
Quote
Die Grundfunktion sieht wie folgt aus:
Und die Extrawurst, Handbedienung...?
Ist nicht nach der Handbedienung auch eine Druckentlastung nötig?

Überhaupt, allgemein gefragt:
Wie verhalten sich Handbedienung zu Druckentlastung?
Muss der Haupthandlungsfaden zurückgesetzt werden, bei/vor der Handbedienung?



Quote
Habt ihr dennoch Verbesserungsvorschläge für mich?
Ich habe dir schon in #14 den Vorschlag gemacht, den ich zu dem Zeitpunkt für den bestmöglichen gehalten habe.
Dort deine Druckentlastung unter zu bringen, ist trivial und deine "Grundfunktion" somit dann vollkommen abgedeckt.




Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 07, 2020, 01:37 pm
Und die Extrawurst, Handbedienung...?
Ist nicht nach der Handbedienung auch eine Druckentlastung nötig?
Die Druckentlastung ist bei der Handbedienung automatisch mit drin, da der Druck und das Medium in den Vorratsbehälter abgeführt wird. Dies dient gleichzeitig zum Entlasten der Druckleitung sowie zum Entlüften und Erstbefüllen der Schläuche.

Überhaupt, allgemein gefragt:
Wie verhalten sich Handbedienung zu Druckentlastung?
Muss der Haupthandlungsfaden zurückgesetzt werden, bei/vor der Handbedienung?
Da die manuelle Betätigung nur zu Wartungszwecken genutzt wird, ist es nicht nötig den "Haupthandlungsfaden" zurückzusetzen (wobei dies auch kein großes Problem darstellen sollte). Bei Tests gab es dahingehend keinerlei Probleme. Zumal ein Sicherungsschalter (bei geöffneter Wartungsklappe) die beiden Sensoren außer Kraft setzt und somit ein "unbeabsichtigtes" Auslösen durch Bewegungen unterbunden wird.

Ich habe dir schon in #14 den Vorschlag gemacht, den ich zu dem Zeitpunkt für den bestmöglichen gehalten habe.
Dort deine Druckentlastung unter zu bringen, ist trivial und deine "Grundfunktion" somit dann vollkommen abgedeckt.
Danke. Ich greife aber lieber auf Codezeilen zurück, die ich zumindest halbwegs nachvollziehen und mit meinem Kenntnisstand anpassen kann :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: my_xy_projekt on Jul 07, 2020, 10:14 pm
Moin,

ich fang mal da an, wo es weh tut:

(Memo an mich selbst: Streiche delay() aus dem Kopf um my_xy nicht auf die Palme zu bringen).
Wenn ich es nicht schon geahnt hätte, dann. Achso, Denk mal drüber nach ;)

Quote
Vielleicht kann ich es weiter erläutern, um es verständlicher zu machen.

Die Grundfunktion sieht wie folgt aus:
1. Wenn Sensor Bewegung erkennt -> Löse Pumpe aus
2. Wenn Pumpe eine definierte Zeit gelaufen ist -> Pumpe aus
3. Wenn Pumpe aus
     -> Entlastung der Druckleitung und
     -> Beginn einer Zwangspause bis zur erneut möglichen Betätigung
4. Manuelle Betätigung des Pumpenkreislaufes zur Entlüftung / Erstbefüllung
Nana...
Die Grundfunkton hast Du erklärt als:
Quote
Das System an sich ist relativ einfach:
Es gibt zwei unabhängig voneinander arbeitende Kreise.
Jeder Kreis besitzt einen IR-Sensor und eine Pumpe. Sobald der IR-Sensor eine Bewegung erkennt, soll die Pumpe für 2 Sekunden laufen. Beide Kreise sollen jedoch unabhängig voneinander, parallel funktionieren!
Und ja, ich kann combie's Hinweis auf die Wurstscheiben nicht verdenken.

Ich denke, dass ich den Fehler gefunden habe.

Vorher:
Code: [Select]

    if (millis() - laufmillis[i] > laufzeit[i])


Nachher:
Code: [Select]

    if (millis() - laufmillis[i] == laufzeit[i])


> in ==
Damit funktioniert es so wie es soll.

NEIN!
Wenn Du genau hinschaust, ist "Nachher"-Bedingung genau nur zu einer bestimmten Abhängigkeit erfüllt. GENAU 1ms lang. Wenn die sich ergebene Differenz "laufzeit" aus der Subtraktion millis - laufmillis nicht genau dann erfüllt, passiert genau: nichts!


Danke. Ich greife aber lieber auf Codezeilen zurück, die ich zumindest halbwegs nachvollziehen und mit meinem Kenntnisstand anpassen kann :)
Abhängige Bedingungen sind ab einer nicht näher zu bezeichnenden Tiefe für den Leser schwer bzw. nicht nachvollziehbar.
Ich arbeite damit - und kann das "WENN - DANN / WENN NICHT - DANN" ganz gut umsetzen - auch dank gewisser Formarmatierungsregeln ;)

Eigentlich hat combie nicht Unrecht, aber der Weg dahin ist bedingt aufwändig und kann eher nicht am erlernen des kleinen Einmaleins festgemacht werden.

Und zu Guterletzt:

Ich hätte das:
Code: [Select]

if ((millis() > entlastungmillis[i] + entlastungszeit[i]) && (entlastung[i] == 1))

von vornherein anders geschrieben:
Code: [Select]

if ((millis() > (entlastungmillis[i] + entlastungszeit[i])) && (entlastung[i] == 1))


Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 16, 2020, 08:20 am
Danke an alle für die Hinweise und Hilfstellungen.

Ich habe mir jetzt mal Combies #14 Post zur Seite genommen und kann langsam auch einigermaßen nachvollziehen, wie das ganze funktioniert und aufgebaut ist.
Seit seinem Post sind ja noch ein paar Funktionen hinzugekommen, die vorher nicht geplant waren.

Diese sind zum einen eine Entlastung der Druckleitung nach der Laufzeit der Pumpe, sowie eine manuelle Betätigung der Pumpenkreise.

Hier nochmal der combie-Code, damit niemand durch die Seiten springen muss :)

Code: [Select]


#include <CooperativeTask.h>



class Pumpe: public Task
{
  protected:
    const byte inPin;
    const byte outPin;
    const unsigned long laufZeit;
    const unsigned long pauseZeit;
 
  public:
    Pumpe(const byte inPin,const byte outPin,const unsigned long laufZeit,const unsigned long pauseZeit):
       inPin(inPin),
       outPin(outPin),
       laufZeit(laufZeit),
       pauseZeit(pauseZeit)
    {
    }
   
    virtual void init() override
    {
      pinMode(inPin,INPUT);
      pinMode(outPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(inPin));
        digitalWrite(outPin,HIGH);
        taskPause(laufZeit);
        digitalWrite(outPin,LOW);
        taskPause(pauseZeit);
      }
    }
};

Pumpe pumpen[] { // {inPin,outPin,laufZeit,pauseZeit}
                    {2,    8,     2000,    3000},
                    {3,    9,     2000,    3000}
               };




void setup()
{
 Scheduler::instance().init();
}

void loop()
{
  Scheduler::instance().run();
}


Wenn ich das richtig verstehe, müssten meine Entlastungs-Funktion wie folgt mit eingegliedert werden. Zudem müssen meine Sensoren doch als INPUT_PULLUP behandelt werden, richtig? (Ebenso wie meine Taster für die manuelle Betätigung).

Korrigiert mich bitte wenn ich falsch liege. Das hab ich bisher:

Code: [Select]

#include <CooperativeTask.h>

class Pumpe: public Task
{
  protected:
    const byte inPin;
    const byte outPin;
    const byte entlastungPin;
    const unsigned long laufZeit;
    const unsigned long pauseZeit;
    const unsigned long entlastungZeit;
 
  public:
    Pumpe(const byte inPin,const byte outPin,const byte entlastungPin,const unsigned long laufZeit,const unsigned long pauseZeit,const unsigned long entlastungZeit):
       inPin(inPin),
       outPin(outPin),
       entlastungPin(entlastungPin),
       laufZeit(laufZeit),
       pauseZeit(pauseZeit),
       entlastungZeit(entlastungZeit)
    {
    }
   
    virtual void init() override
    {
      pinMode(inPin,INPUT_PULLUP);
      pinMode(outPin,OUTPUT);
      pinMode(entlastungPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(inPin));
        digitalWrite(outPin,HIGH);
        taskPause(laufZeit);
        digitalWrite(outPin,LOW);
        digitalWrite(entlastungPin,HIGH);
        taskPause(entlastungZeit);
        taskPause(pauseZeit-entlastungZeit);
      }
    }
};

Pumpe pumpen[] { // {inPin, outPin, entlastungPin,  laufZeit, pauseZeit,  entlastungZeit}
                    {2,     7,      6,              2000,     3000,       300},
                    {3,     5,      4,              2000,     3000,       300}
               };

void setup()
{
 Scheduler::instance().init();
}

void loop()
{
  Scheduler::instance().run();
}


Was combie mit "marginal" meinte, wenn es darum geht eine weitere zeitliche Komponente einzufügen kann ich nun nachvollziehen :)

Meine Fragen:
- WIE baue ich eine manuelle Betätigung meiner Pumpenkreise ein?
- WO baue ich sie ein?
- Sind "Klassen (class)" als eine Art Baustein zu verstehen, die ich später im Loop nur noch abrufe?
- Müsste ich für die manuelle Betätigung eine weitere Klasse hinzufügen oder kann ich die Funktion mit in die bestehende mit einbauen?

Danke :)
Title: Re: Zwei parallele Programme laufen lassen
Post by: agmue on Jul 16, 2020, 09:20 am
Auf die Gefahr hin, den C++ Freaks kräuseln sich die Fußnägel, versuche ich eine Antwort:

- WIE baue ich eine manuelle Betätigung meiner Pumpenkreise ein?
Ich würde das als Schrittkette (= endlicher Automat, = finite state machine) realisieren, wo man zwischen Manuell und Automatik umschalten kann.

- WO baue ich sie ein?
Beispielsweise in die Methode run.

- Sind "Klassen (class)" als eine Art Baustein zu verstehen, die ich später im Loop nur noch abrufe?
Die "Bausteine" nennt man Objekte, die sowas wie der Typ einer Variablen sind, nur mit verschiedenen Variablenypen und Methoden. Beispiel: Taster tasten[] { ... };

Das Feld tasten enthält Elemente entsprechend das Klasse Taster.

- Müsste ich für die manuelle Betätigung eine weitere Klasse hinzufügen oder kann ich die Funktion mit in die bestehende mit einbauen?
Die "Funktion" wird Methode genannt. Packt man zu viele Methoden in eine Klasse, baut man eine Monsterklasse. Bei vielen Klassen muß man die selben Informationen mehrfach eintragen. Da können dann Vererbungen helfen.

Mal abwarten, wer gekräuselte Fußnägel bekommt ;D
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 16, 2020, 10:16 am
Also wenn ich dich richtig verstehe, entwerfe ich eine zweite Klasse die nur die manuelle Betätigung enthält.

In etwa so?

Code: [Select]

class Manuell: public Task
{
  protected:
    const byte manuellPin;
    const byte outPin;
    const byte entlastungPin;
 
  public:
    Manuell(const byte manuellPin,const byte outPin,const byte entlastungPin):
       manuellPin(manuellPin),
       outPin(outPin),
       entlastungPin(entlastungPin)
    {
    }
   
    virtual void init() override
    {
      pinMode(manuellPin,INPUT_PULLUP);
      pinMode(outPin,OUTPUT);
      pinMode(entlastungPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(manuellPin));
        digitalWrite(outPin,HIGH);
        digitalWrite(entlastungPin,HIGH);
      }
    }
};
Title: Re: Zwei parallele Programme laufen lassen
Post by: agmue on Jul 16, 2020, 10:55 am
Also wenn ich dich richtig verstehe, entwerfe ich eine zweite Klasse die nur die manuelle Betätigung enthält.
Das wäre prinzipiell so möglich, allerdings wäre meine Herangehensweise eher, die bestehende Methode run zu erweitern, da die Klasse schon viele Informationen enthält, die auch für den manuellen Betrieb notwendig sind.

Aber viele Wege führen nach Rom ;D

Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 16, 2020, 11:23 am
Und wie strukturiere ich das richtig?

Code: [Select]

#include <CooperativeTask.h>

/*-------------------------Pumpe----------------------------*/

class Pumpe: public Task
{
  protected:
    const byte inPin;
    const byte outPin;
    const byte entlastungPin;
    const unsigned long laufZeit;
    const unsigned long pauseZeit;
    const unsigned long entlastungZeit;
 
  public:
    Pumpe(const byte inPin,const byte outPin,const byte entlastungPin,const unsigned long laufZeit,const unsigned long pauseZeit,const unsigned long entlastungZeit):
       inPin(inPin),
       outPin(outPin),
       entlastungPin(entlastungPin),
       laufZeit(laufZeit),
       pauseZeit(pauseZeit),
       entlastungZeit(entlastungZeit)
    {
    }
   
    virtual void init() override
    {
      pinMode(inPin,INPUT_PULLUP);
      pinMode(outPin,OUTPUT);
      pinMode(entlastungPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(inPin));
        digitalWrite(outPin,HIGH);
        taskPause(laufZeit);
        digitalWrite(outPin,LOW);
        digitalWrite(entlastungPin,HIGH);
        taskPause(entlastungZeit);
        taskPause(pauseZeit-entlastungZeit);
      }
    }
};

Pumpe pumpen[] { // {inPin, outPin, entlastungPin,  laufZeit, pauseZeit,  entlastungZeit}
                    {2,     7,      6,              2000,     3000,       300},
                    {3,     5,      4,              2000,     3000,       300}
               };

/*-------------------------Entlueften----------------------------*/

class Entlueftung: public Task
{
  protected:
    const byte entlueftenPin;
    const byte outPin;
    const byte entlastungPin;
 
  public:
    Entlueftung(const byte entlueftenPin,const byte outPin,const byte entlastungPin):
       entlueftenPin(entlueftenPin),
       outPin(outPin),
       entlastungPin(entlastungPin)
    {
    }
   
    virtual void init() override
    {
      pinMode(entlueftenPin,INPUT_PULLUP);
      pinMode(outPin,OUTPUT);
      pinMode(entlastungPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(digitalRead(entlueftenPin));
        digitalWrite(outPin,HIGH);
        digitalWrite(entlastungPin,HIGH);
      }
    }
};

Entlueftung entlueften[] { // {entlueftenPin, outPin, entlastungPin}
                          {8,             7,      6},
                          {8,             5,      4}
               };



void setup()
{
 Scheduler::instance().init();
}

void loop()
{
  Scheduler::instance().run();
}



Den Zusammenhang verstehe ich noch nicht so ganz. Ist es so richtig aufgebaut? Läuft mein loop() jetzt und wartet permanent auf die Bedingungen von "taskWaitFor" aus beiden Klassen ?


P.s.: Hab mal den Code von combie hochgeladen. Er schaltet die Pumpen abwechselnd ein und aus :D
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 16, 2020, 02:40 pm
Ich kann gerade gar nicht testen usw... nix dergleichen.

> pinMode(inPin,INPUT_PULLUP);
Damit ist der Pin sowohl input, als auch dauerhaft HIGH, bis eine Betätigung erfolgt.

> taskWaitFor(digitalRead(inPin));
Diese Bedingung ist damit wohl üblicherweise wahr, und das Programm spult dauernd ab.



Ist das so beabsichtigt?
Logisch erscheint mir das nicht unbedingt.

Vielleicht suchst du ja taskWaitFor(not digitalRead(inPin))?


Im Moment ist mir auch gar nicht mehr klar, welche Ein- und Ausgänge jetzt aktiv Low sind, und welche nicht.



Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 16, 2020, 04:15 pm
Das Relais ist high aktiv, die Sensoren low aktiv.
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 16, 2020, 04:24 pm
Welches Relais?

Quote
Ist das so beabsichtigt?
Also Nein! ?
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 17, 2020, 08:50 am
Welches Relais?
Also Nein! ?
Nein. Natürlich ist nicht beabsichtigt, dass die Pumpen ohne Grund anlaufen und sich die Klinke geben :)

Ich benutze ein Relais Shield, welches meine 230-Verbraucher schaltet. Diese Relais Pins sind HIGH-aktiv und schalten meine beiden 230V Pumpen sowie meine 230V-Wegeventile.

Meine beiden Sensoren sind LOW-aktiv. Daher hast du natürlich recht und es muss

> "taskWaitFor(!digitalRead(inPin));" oder wie du schreibst ""taskWaitFor(not digitalRead(inPin));"

heißen.

PINS 2 und 3 sind LOW-aktiv (IR-Sensoren)

PINS 4, 5, 6 und 7 sind HIGH-aktiv (Relais-Shield - 2 Pumpen (7 und 5) und 2 Wegeventile zur Druckentlastung (6 und 4))

PINS 8 und 9 sind meine beiden Taster (Schließer), die für die manuelle Betätigung genutzt werden. (Wenn jeweils betätigt, dann zugehörige Pumpe und Druckentlastung an)

Code: [Select]

#include <CooperativeTask.h>

/*-------------------------Pumpe----------------------------*/

class Pumpe: public Task
{
  protected:
    const byte inPin;
    const byte outPin;
    const byte entlastungPin;
    const unsigned long laufZeit;
    const unsigned long pauseZeit;
    const unsigned long entlastungZeit;
 
  public:
    Pumpe(const byte inPin,const byte outPin,const byte entlastungPin,const unsigned long laufZeit,const unsigned long pauseZeit,const unsigned long entlastungZeit):
       inPin(inPin),
       outPin(outPin),
       entlastungPin(entlastungPin),
       laufZeit(laufZeit),
       pauseZeit(pauseZeit),
       entlastungZeit(entlastungZeit)
    {
    }
   
    virtual void init() override
    {
      pinMode(inPin,INPUT_PULLUP);
      pinMode(outPin,OUTPUT);
      pinMode(entlastungPin,OUTPUT);
    }
   
    virtual void run() override
    {
      TaskBlock
      {
        taskWaitFor(!digitalRead(inPin));
        digitalWrite(outPin,HIGH);
        taskPause(laufZeit);
        digitalWrite(outPin,LOW);
        digitalWrite(entlastungPin,HIGH);
        taskPause(entlastungZeit);
        taskPause(pauseZeit-entlastungZeit);
      }
    }
};

Pumpe pumpen[] { // {inPin, outPin, entlastungPin,  laufZeit, pauseZeit,  entlastungZeit}
                    {2,     7,      6,              2000,     3000,       300},
                    {3,     5,      4,              2000,     3000,       300}
               };

/*-----------------------------------------------------*/

void setup()
{
 Scheduler::instance().init();
}

void loop()
{
  Scheduler::instance().run();
}



UPDATE:

Also... das Programm funktioniert soweit, BIS die 230V scharf geschaltet werden (Stinknormaler Nockenschalter mit Sicherung etc). Ist die 230V-Spannungsquelle nicht aktiv, funktioniert alles soweit wie es soll. Ich löse mittels Handbewegung einen beliebigen Sensor aus, das zugehörige Relais wird geschaltet, die Laufzeit passt und die Druckentlastung findet auf dem anderen Relais ebenfalls statt. Beide Kreise funktionieren, auch unabhängig voneinander. (zu beobachten an den Relais-Shield LED´s).

Jetzt kommt´s aber:
Ich lege den Nockenschalter um und habe die 230V an meinen Verbrauchern. Löse ich mittels Handbewegung einen Ablauf aus, funktioniert dieser zwar soweit, ABER der zweite Kreis wird im Anschluss ebenfalls direkt ausgelöst! Dies passiert beidseitig. Läuft Kreis 1 an, kommt Kreis 2 direkt im Anschluss und umgekehrt.

Habt ihr eine Ahnung woran das liegen kann? Die Relais schalten meine Spannung doch nur durch? Die Relais auf dem Shield sollten normalerweise die 230VAC verkraften. Relais 4 fach (https://www.reichelt.de/arduino-shield-relais-v3-hls8l-dc5v-s-c-ard-shd-relay-v3-p191269.html?&trstct=pos_3&nbc=1)
Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 17, 2020, 10:23 am
Schön auch mal ein solches Relaisboard kennen lernen zu dürfen.

Quote
? Die Relais auf dem Shield sollten normalerweise die 230VAC verkraften. Relais 4 fach
Das Datenblatt/Anleitung (https://cdn-reichelt.de/documents/datenblatt/A300/103030009_01.pdf) ist da eindeutig!
Switching Voltage - - 35 VDC
...
2. Do not operate voltage more than 35V DC


Und, wenn ich mir die Leiterbahnführung auf dem Board anschaue, dann ist das auch mehr als berechtigt.

Keinesfalls ist das Board für Netzspannung geeignet.
Nimmer.


Deine Störungen kommen allerdings daher, dass du die Snubber vergessen hast.

Also andere Relais und Snubber verwenden.
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 17, 2020, 10:35 am
Laut Reichelt und auch der Beschreibung auf den Relais sollte das möglich sein.

Technische Daten
• Betriebsspannung: 4,75 ... 5,25 V
• Betriebsstrom: 8 ... 250 mA
• Schaltspannung: 250 VAC / 30 VDC
• Schaltstrom: 15 A / 7 A

Foto im Anhang
Title: Re: Zwei parallele Programme laufen lassen
Post by: Tommy56 on Jul 17, 2020, 10:44 am
Das Relais allein, aber nicht auf dieser Platine.
Der Hersteller schreibt solche Einschränkungen nicht umsonst rein.
Wenn Du es trotzdem tust, ist das Vorsatz - mit allen juristischen Konsequenzen für Dich.

Gruß Tommy
Title: Re: Zwei parallele Programme laufen lassen
Post by: kahmui on Jul 17, 2020, 10:48 am
Dann werde ich das Ding wohl mal unverzüglich zurückschicken.  :smiley-roll-sweat:


Zurück zum Thema :)

Wie kann ich nun meine Taster mit integrieren? Für die beiden Pumpenkreise kann ich ja einen Ablauf schreiben der der Reihe nach abgearbeitet wird.

Wie sieht das nun mit Tastern aus?
Ich kann zwar fragen ob der Taster betätigt ist, aber was passiert wenn der Taster NICHT gedrückt ist?

Also während Taster gedrückt-> Betätige Pumpe x -> wenn Taster nicht mehr betätigt, schalte Pumpe x aus und die Entlastung im Anschluss kurz (200ms) ein und wieder aus .

Er würde ja permanent meine Pumpe abschalten und das Ventil kabwechselnd ein- / abschalten, wenn der Taster NICHT gedrückt ist.



Title: Re: Zwei parallele Programme laufen lassen
Post by: combie on Jul 17, 2020, 12:37 pm
Naja, du könntest Semaphore, oder einen Mutex einführen, so dass die jeweils 2 konkurierenden Tasks sich gegenseitig ausschließen.

Oder du lässt die Tasks über Methoden miteinander kommunizieren.