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)
}
}
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.
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.
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.
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.
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
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.
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
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;
}