Teilschritte in richtigen Zeitabständen aktivieren

Guten Morgen,
Ich bin ein Neuling und habe schon Stunden gegrübelt und vieles versucht, komme aber nicht dahin wo ich hin muss...
Ich habe eine Maschine gebastelt mit einem DC-Motor (über Relais), einem Näherungsschalter, 1 Druckluftventil(über Relais), 2 Servos und einem doppelt wirkenden Zylinder (noch nicht ganz fertig)
Folgendes Problem habe ich bei der Programmierung:
Der DC-Motor soll etwas Zeitverzögert ausschalten, wenn der Näherungssensor erreicht ist.
Danach soll das Druckluftventil NACH dem Motor ebenfalls etwas Zeitverzögert ausschalten.
Wärend die das Druckluftventil noch an ist, drehen die Servos ca. 200°, danach wieder zurück auf die alte Stellung.
Dann kommt das (noch unfertige) Relais für den Doppelt wirkenden Zylinder (an-und wieder aus)

Dann soll alles von vorne Starten.
Hier ist mein (unfertiger Sketch)

#include <Wire.h>
#include <Servo.h>

Servo Servo1;  
Servo Servo2;

unsigned long myTimer = 0;
unsigned long myTimeout = 8000;
unsigned long myTimeout1 = 6000;
unsigned long myTimeout2 = 500;

int sensorpin = 2; // induktiver Näherungsschalter


const int relaisIN1 = 3;  // DC-Motor
const int relaisIN2 = 4;  // Druckluftventil 1
const int relaisIN3 = 7;  // Druckluftventil 2



void setup() {
  Serial.begin(9600);
  
  Servo1.attach(5);  
  Servo2.attach(6);
  pinMode(sensorpin, INPUT);
  pinMode(relaisIN1, OUTPUT);
  pinMode(relaisIN2, OUTPUT);

}

void loop() {

 int sensorstate = digitalRead(sensorpin);
  
 if (sensorstate == 0) {
    digitalWrite (relaisIN1, HIGH); // der Motor sollte aber noch ein paar Millisekunden weiterlaufen
    digitalWrite (relaisIN2, HIGH); // das sollte eigentlich ebenfalls Zeitverzögert passieren
    Servo1.write(5);
    Servo2.write(153);
      }
  delay(10);

if (millis() > myTimeout1 + myTimer ) {
    Servo1.write(270);
    Servo2.write(-0);
    }
   
  if (millis() > myTimeout + myTimer ) {
    digitalWrite (relaisIN1, LOW); // wenn die Relais wieder auf ursprünglicher Position sind
    digitalWrite (relaisIN2, LOW); // hier sollte es wieder ca. 1 sekunde Zeitverzögert starten (Druckluft)   
    }   
  
}

Hallo und guten Morgen

Herzlich Willkommen im besten Arduino Forum der Welt :slight_smile:

Poste deinen Sketch in code tags und Schaltplan damit wir sehen können wir dir helfen können.

Wie kann ein Relais drehen?

Wozu delay, wenn du mit millis arbeitest?

Ups sorry ich meinte die Servos...
Das Delay ist evtl. noch ein Schnipsel bevor ich mit den millis angefangen habe.

LG Frank

Die einzelnen Schritte muss du jetzt noch in eine Statemaschiene packen. Da gibt es hier ganz viele Beispiele.

ich würde das zunächst aufzeichen wie der Ablauf werden soll

das ist vermutlich falsch und unvollständig, aber das ist was ich aus deiner textlichen Beschreibung entnehmen konnte:

Erstens erkennt man daraus besser die tatsächliche Abfolge, außerdem erkennt man auch leicht wenn was fehlt. Z.B. wodurch der DC Motor wieder einschaltet oder was eigentlich passieren soll wenn die Näherungssensor in welchem Schritt wieder "Entfernt" meldet.

Anschließend würde ich das wie schon angesprochen als Finite State Machine aufbauen.

Summary

gezeichnet mit: Graphviz Online

digraph G { 
  graph [
    label="Finite State Machine"
    labelloc="t"
    fontname="sans-serif"
  ]
  node [
    style=filled
    fillcolor=gray95
    fontname="sans-serif"
  ]
  
  step0 -> step1 [label="Entfernung LOW" fontsize=10];  
  step1 -> step2 [label="after 3s" fontsize=10];  
  step2 -> step3 [label="after 3s" fontsize=10];  
  step3 -> step4 [label="after 10s" fontsize=10];  
  step4 -> step5 [label="after 5s" fontsize=10];
  step5 -> step6 [label="after 5s" fontsize=10];
  step6 -> step0 [label="" fontsize=10];
  
  step0[label = "idle"]
  step1[label = "Servo 200"]
  step2[label = "Servo 0"]
  step3[label = "warten"] 
  step4[label = "DC abschalten"]
  step5[label = "Zylinder An"]
  step6[label = "Zylinder Aus"]
}
1 Like

Das Grundprinzip das du brauchst ist zeitabhängig "weiterschalten".

Das macht mit einer sogenannten state-machine.
Du kannst dir das Vorstellen wie unterschiedliche Betriebsmodi.

Modus 0: darauf warten das der Näherungssensor schaltet
wenn Näherungssensorsignal erkannt umschalten auf Modus 1

Modus 1: Einen Motor-Nachlauf-Timer starten
sofort umschalten auf Modus 2

Modus 2: überprüfen ob die Nachlaufzeit des Motors vorbei ist
wenn vorbei Motor abschalten, Drucklufttimer starten
Servos 200° nach "vorne" drehen
umschalten nach Modus 3

Modus 3: Überprüfen ob Druckluft"nachlauf"zeit vorbei ist
überprüfen ob Servos vorne angekommen sind
wenn Druckluft"nachlauf"zeit vorbei ist und Servo wieder nach "hinten" gedreht hat umschalten auf Modus 4

Modus 4: Druckluftzylinder nach vorne
usw.

Das ganze macht man mit dem switch-case-break-statement

Achtung ! Das break ist besonders wichtig !
Durch das break; erreicht man, dass immer nur die functions ausgeführt werden die im jeweiligen "Modus" stehen

Die state-machine hat den Vorteil, dass die Anzahl if-bedingungen auf das notwendige Minimum reduziert werden.
Man kann die state-machine ganz leicht ändern, erweitern, kürzen
Wenn du die erst mal verstanden hast willst du es nie wieder ohne machen.

Es gibt eine Menge Beispiele zu state-machines ganz unterschiedlicher Qualiät und Herangehensweisen es zu erklären.
Hier ist meine.

Bei dem Verfahren knallt es nach ca 49 Tagen!

Siehe: [Bericht] Der (Millis) Ueberlauf im Test

Hallo,

wenn man den Arduino aus - und wieder einschaltet ist der Timer doch wieder auf 0- richtig?

Das Verfahren ist falsch!
Wenn es 2 Verfahren gibt, ein falsches und ein richtiges, dann nimmt man das richtige.

Es gibt keine Grund absichtlich einen Fehler einzubauen.
Auch ist die Selbstkonditionierung, auf ein fehlerhaftes Verfahren, auf Dauer doch arg kontraproduktiv.

Mein Rat ist da klar, und lässt keine Ausnahmen zu.
Natürlich kann ich dich nicht zwingen.
Muss allerdings alle (unbedarften) Mitleser vor deiner Methode warnen, nicht dass sie sich den "Irrtum" abschauen und danach ins offene Messer laufen. Fehler die erst nach langer Zeit auftreten sind sehr schwer zu finden und können großen Schaden anrichten.

Am Rande:

  1. der Rat ist kostenlos
  2. er kostet keine Rechenzeit oder Speicher
  3. er funktioniert

Hallo boba2fett

Nimm das BlinkWithOutDelay Beispiel aus dem IDE, das ist die Mutter aller Arduino-Timer, und baue daraus die eigene timer()-Funktion.

Diese timer()-Funktion sollte die folgenden Methoden enthalten:

  • make();
  • start();
  • stop(),
  • event();

Timer kann man immer gebrauchen.

Ich wünsche Ihnen einen schönen Tag und viel Spaß beim Programmieren in C++.

p.s. ENUMs, STRUCTs, ARRAYs und SWITCH/CASE sind deine Freunde

1 Like

Danke für die Erklärung!
Ich geh später gleich mal an einen Versuch.

der TO hat den Umgang mit millis schon probiert. Ist noch nicht ganz korrekt - aber der Hinweis auf die Substraktion wurde ihm auch schon gegeben.
Aus meiner Sicht ist es nicht notwendig, dass du deine Abneigung gegen BwD in jedem zweiten Thread festhältst. Die meisten wissen es bereits dass es dir nicht gefällt.

Mir (und vielen anderen) gefällt es gut.

Der TO wäre gut beraten einen Finite State Machine / einen endlichen Automaten zu erstellen.

@boba2fett: wenn du noch Fragen hast - Frage.

1 Like

Guten Abend,
ich habe schon gemerkt das es komplitzierter wird als ich es je angenommen hatte und ich mich erst einlesen muss um zu verstehen was eine Finite State Machine ist und wie man diese aufbaut.
Ich lese mich mal ein und die Fragen kommen dann bestimmt ...
Danke und Gruß
Frank

1 Like

Nabend, habe nun mal die einzelnen Schritte angeschaut und bin so verblieben:

Ablauf Maschine
1. DC Motor über Relais AN
2. 1 sekunde warten
3. Relais für Druckluftentil AN
4. Näherungssensor wird getriggert (Hebel vom DC-Motor läuft aber drüber, d.H. Näherungssensor ist dann schon wieder aus)
5. 50 ms warten
6. DC Motor über Relais AUS
7. 100 ms warten
8. Servo1 200
9. Servo2 0
10. Servo1 0
11. Servo2 200
12. Relais für Druckluft AUS
13. Relais für doppelt wirkenden Zylinder AN
14. warten 2 sec
15. Relais für Doppelt wirkenden Zylinder AUS
16. warten 2 sec
17. Alles beginnt von vorn

Geht das überhaupt?

Im Prinzip ja.
Aber so Sachen wie deinen Schritt 8 und 10:
da musst dir was einfallen lassen ob da nicht auch ein Warten braucht.
Wenn du z.b. diese zwei Schritte nacheinander Aufrufst wird sich der Servo faktisch nicht bewegen.

Weiß nicht... Punkt 4 sieht noch komisch aus.

Wenn du in 8 den Sevo1 auf 200 stellst, was ist die Bedingung für 9? Ein Endschalter? Eine feste Zeit? Da fehlt noch was.

Ja sicher geht so ein Ablauf. Es könnten auch - jetzt ohne Übertreibung - noch 200 Schritte extra sein. 217 Schritte würde auch gehen.

Das Grundprinzip einer state-machine ist.
Rufe die State-Machine immer wieder neu auf. Tausende male pro Sekunde.
von "Befehlen" die nur einmal ausgeführt werden müssen wird sofort nach diesem einmaligen ausführen weitergeschaltet.

Es gibt dann Schritte in denen auf das erfüllt sein einer Bedingung gewartet wird
In so einem Schritt werden die Befehle die die Bedingung überprüfen immer wieder neu aufgerufen. Bis die Bedingung erfüllt ist.

Führe einen Teilabschnitt des Programms aus
und
prüfe ob die Bedingung (oder die Bedingungen) für das Weiterschalten auf den nächsten Teilabschnitt erfüllt sind.

Wenn die Bedingung erfüllt ist schalte weiter auf den nächsten Teilabschnitt.

Am Beispiel der Schritte 8, 9, 10, 11

Schritt 8:

  • führe die function servo1.write(200) aus
    schalte sofort auf Schritt 8b

Schritt 8b:
prüfe ob Servo1 bei 200 Grad angekommen ist
WENN servo1 bei 200 Grad angekommen ist
schalte weiter auf Schritt 9

Schritt 9:

  • führe die function servo2.write(0) aus
    schalte sofort auf Schritt 9b

Schritt 9b:
prüfe ob Servo2 bei 0 Grad angekommen ist
WENN servo2 bei 0 Grad angekommen ist
schalte weiter auf Schritt 10

Schritt 10:
führe function servo1.write(0) aus
Schalte sofort weiter auf Schritt 10b

Schritt 10b:
prüfe ob Servo1 bei 0 Grad angekommen ist
WENN servo1 bei 0 Grad angekommen ist
schalte weiter auf Schritt 11

Schritt 11:
führe function servo2.write(200) aus
Schalte sofort weiter auf Schritt 11b

Schritt 11b:
prüfe ob Servo2 bei 200 Grad angekommen ist
WENN servo2 bei 200 Grad angekommen ist
schalte weiter auf Schritt 12

Guten Morgen,

wollte fragen ob ich mit dieser Programmierung total auf dem Holzweg bin oder ob die Richtung stimmt.
Was ich aber noch nicht verstehe was ich beim Setup usw. schreiben muss...


void loop() {

  switch (Maschine) {
    case DC-Motor start:
      digitalWrite (relaisIN1,LOW);
      break;
      
    case Warten auf Druckluft:
      myTimer = millis();
      if myTimeout1 => myTimer - myTimeout1;
      break;
      
    case Druckluftventil start:
      digitalWrite (relaisIN2, LOW);
      break;
      
    case Näherungssensor:    
      if (sensorstate == 0) {
      myTimer = millis();
  }
    case Warten auf DC-Motor aus:    
      myTimer = millis();
      if myTimeout2 => myTimer - myTimeout2;
      break;

    case DC-Motor aus:
      digitalWrite (relaisIN1,HIGH);
      break;
  }