Nach etlichen erfolglosen Versuchen mit diversen Varianten bitte ich euch um Hilfe.
Geht das überhaupt und könnt ihr mir einen Anstoss geben auf welche weise.
Für unseren Kratzboden im Sandstrahlraum hätte ich gerne eine Überwachung gegen Verstopfung. Das ist keine Sicherheitsrelevante Überwachung. Und benötigt nur ein Code als Abfuhrmittel.
Erklärung zur Funktion:
8 Pneumatik Zylinder treiben Schrapper Rechen an. Gesteuert über ein Blinker Zeitrelais.
Die oberen 7 schieben den Sand in den einen Unteren, der das ganze dann zum Becherwerk schiebt. Die Überwachung müsste nur für den einen unteren sein, der schon öfters verstopft ist.
Nun zum angedachten Ablauf:
Über einen Endanschlag und einer Vorgabe Zeit, die oberen 7 Ein oder Ausschalten.
Mit dem angefügten Code funktioniert die Abschaltung sehr gut, wenn die Zeit überschritten wurde. Jedoch sollte jetzt beim nächsten Kontakt mit dem Endanschlag das Relais nicht gleich auf HIGH gehen, sondern erst geprüft werden, ob die Zeit wieder innerhalb der Vorgabezeit liegt.
Taktzeit ist ca. 2000ms Vorgabezeit ca. 2500ms
Für Tipps bin ich jetzt schon dankbar.
Gruss Marcel
[code]
const byte relaisPin = 0; // Pin für Relaisboard (OUTPUT)
const byte schaltPin = 1; // Pin für Endschalter (INPUT)
const int potiPin = A1; // Pin für Poti (INPUT) Externe einstellung der Zeitlimite - Relais Aus
void setup() {
pinMode(schaltPin, INPUT);
pinMode(relaisPin, OUTPUT);
}
void loop() {
int potiWert = analogRead(potiPin);
static uint32_t previousMillis = 0;
if (digitalRead(schaltPin) == HIGH) {
previousMillis = millis();
}
if (millis() - previousMillis > 5 * potiWert && digitalRead(relaisPin) == HIGH) {
digitalWrite(relaisPin, LOW);
}
if (millis() - previousMillis < 5 * potiWert && digitalRead(relaisPin) == LOW) {
digitalWrite(relaisPin, HIGH);
}
}
[/code]
Hallo Marcel,
na ja, Du musst halt die Vorgabezeit mit den Sketch aufnehmen und die Zeit zwischen 2 Schalter Betätigungen ausrechnen. Diesen Wert dann mit der Vorgabezeit vergleichen und gegebenenfalls die Differenz warten.
Was genau ist das "Blinker Zeitrelais"?
Ist das ein vom Arduino völlig unabhängiges Relais das durch simples an den Strom anschliessen von alleine Ein/Aus schaltet = von alleine blinkt?
oder
ist das ein Stück Programmcode das auch auf dem Arduino läuft?
Kann jeder der sieben oberen Schrapper-Rechen für sich ohne Synchronisation so vor/zurück vor sich hin rechen oder müssen die synchronisiert sein?
Der unterste Schrapper-Rechen hat
einen Endanschlagsschalter für vorne
und
einen Endanschlagsschalter für hinten
Im Falle von Verstopfung kann sich der unterste Schrapper-Rechen nicht mehr bis zum Endanschlag bewegen.
Und du willst jetzt die Verstopfung vom Programm erfassen lassen, dadurch das es eine Zeitüberwachung gibt die folgendermaßen funktioniert:
Der Schrapper-Rechen befindet sich ganz hinten, das heißt hinterer Endschalter ist betätigt.
Jetzt wird die Pneumatik auf Schrapper-Rechen nach vorne schieben geschaltet und die Zeitüberwachung beginnt. Wenn nach einer Zeit von 2500 Millisekunden der vordere Endschalter nicht betätigt ist, dann soll die Steuerung eine Meldung ausgeben
"Zeitüberwachung vordere Endlage nicht erreicht"
Und in der gleichen Art und Weise auch für die hinteren Endlagenschalter
wenn Schrapp-Rechen ganz vorne ist und der Schrapp-Rechen auf "bewege dich nach hinten" geschaltet wird Zeitüberwachung starten. Wenn hinterer Endschalter nach 2500 millisekunden noch nicht geschaltet hat dann soll die Steuerung eine Meldung ausgeben
"Zeitüberwachung hintere Endlage nicht erreicht"
Ist das eine zutreffende Beschreibung der Funktionalität die du haben möchtest?
In dem Code den du gespostet hast gibt es nur einen Relais-Pin und einen Schaltpin
Heißt das dass du nur eine Endlage so überwachen willst?
Oder
heißt das es gibt 16 Arduinos wobei auf jedem Arduino dieses Programm für einen Endschalter läuft?
oder
noch etwas anderes?
@my xy projekt
Der Controller ist ein Digispark / Joy-IT
@stefanL38
Es ist nur ein einziger Blinker, der ist von Finder 87.31 und dieser gibt den Takt für die Ventileinheiten an.
Eine Unterbrechung der oberen Rechen würde bei der Ventileinheit geschehen.
Geplant habe ich eine einseitige Endlagen Kontrolle, das sollte doch reichen? Rein Programm technisch.
Bis anhin wird eine Verstopfung erst bemerkt, wenn gar nichts mehr geht.
Ich glaube, wenn hier eine frühzeitige Abschaltung der Oberen Rechen und
natürlich auch den Strahlvorgang unterbricht. Sollte es reichen für den unteren Rechen
dass er den Sand los wird und wieder in die Vorgabe Zeit kommt.
Die Blinker Zeit ist natürlich etwas länger eingestellt als die Zylinder pro hub benötigen.
Dadurch gibt es eine kurze Verweilzeit in den Endpositionen.
Besten dank
Gruss Marcel
Ein Schema und Bilder werde ich morgen noch einstellen.
So jetzt habe ich ein Programm geschrieben dass die Zeitüberwachung realisiert.
Achtung alteingesessene Hasen: die State-Machine nennt sich eingedeutscht Schrittkette.
Bestimmte Detaildaten haben in der Beschreibung gefehlt. Da habe ich jetzt Annahmen getroffen.
Der Relais-Pin heißt jetzt "ZylVorPin" Annahme von diesem Relais wird der untererste Zylinder gesteuert.
Marcel hat was von Ventil-Insel abschalten geschrieben. Dafür gibt es jetzt auch einen IO-pin
Die Steuerung / Überwachung hat zwei unterschiedliche Abläufe
Normalablauf keine Verstopfung Ventil-Insel ist eingeschaltet alle Schrappen-Rechen sind aktiv Der unterste arbeitet mit Zeitüberwachung. Wenn Endschalter nach Maximalzeit nicht geschaltet hat umschalten auf 2.
Endschalter hat nicht geschaltet = Verstopfung =>
Ventil-Insel ausschalten
Der unterste arbeitet ohne Überwachung überprüft aber bei jedem nach vorne fahren des Rechens ob der Endschalter betätigt wird
Wenn das der Fall ist umschalten auf Normalbetrieb 1.
Das Ganze ist über eine Schrittkette programmiert in der wie der Name schon sagt bestimmte Schritte nacheinander durchlaufen werden.
Das Schöne an Schrittketten (state-machines) ist, dass der Code nicht-blockierend ist und man ihn sehr leicht erweitern / abändern kann und die Anzahl If-bedingungen durch das switch-case auf das notwendige Minimum reduziert ist
Man könnte mit cleverer Programmierung noch 2,3 Schritte einsparen, dann wird der Code aber schwerer zu verstehen. Deshalb lieber 3 Schritte mehr und dafür leicht verständlich.
const byte ZylVorPin = 0; // Pin für Relaisboard (OUTPUT)
const byte schaltPin = 1; // Pin für Endschalter (INPUT)
const int potiPin = A1; // Pin für Poti (INPUT) Externe einstellung der Zeitlimite - Relais Aus
const byte VentileAbschaltenPin = 2;
const byte betaetigt = HIGH;
const byte eingeschaltet = HIGH;
const byte ausgeschaltet = LOW;
const byte sk_leerLauf = 0;
const byte sk_Zylinder_vor = 1;
const byte sk_warte_auf_Endlage = 2;
const byte sk_Endlage_erreicht = 3;
const byte sk_Zylinder_zurueck = 4;
const byte sk_warten_bis_zurueck = 5;
const byte sk_Ventileinheit_aus = 6;
const byte sk_frei_rechen = 7;
const byte sk_frei_rechen_warten = 8;
byte SchrittNr = sk_leerLauf;
unsigned long ZylinderTimer;
unsigned long MaximalZeitVor;
unsigned long MaximalZeitZurueck;
void setup() {
pinMode(schaltPin, INPUT);
pinMode(ZylVorPin, OUTPUT);
pinMode(VentileAbschaltenPin, OUTPUT);
digitalWrite(VentileAbschaltenPin, eingeschaltet);
}
void loop() {
int potiWert = analogRead(potiPin);
MaximalZeitVor = 5 * potiWert;
MaximalZeitZurueck = 5 * potiWert;
Schrittkette_Schieber_Unten();
}
void Schrittkette_Schieber_Unten() {
switch (SchrittNr) {
case sk_leerLauf:
// mache gar nichts
break; // springe sofort zu switch-ENDE
case sk_Zylinder_vor:
digitalWrite(ZylVorPin, HIGH);
ZylinderTimer = millis();
SchrittNr = sk_warte_auf_Endlage;
break; // springe sofort zu switch-ENDE
case sk_warte_auf_Endlage:
// wenn Endschalter nach Ablauf der Maximalzeit
// immer noch nicht geschaltet hat => Verstopfung
if ( TimePeriodIsOver(ZylinderTimer, MaximalZeitVor) ) {
// obere Rechen abschalten (und dann unten freirechen)
SchrittNr = sk_Ventileinheit_aus;
break; // springe sofort zu switch-ENDE
}
// Endlage erreicht = alles IO
if (digitalRead(schaltPin) == betaetigt) {
SchrittNr = sk_Endlage_erreicht;
}
break; // springe sofort zu switch-ENDE
case sk_Endlage_erreicht:
digitalWrite(ZylVorPin, LOW); // Zylinder zurueck fahren
ZylinderTimer = millis();
SchrittNr = sk_warten_bis_zurueck;
break; // springe sofort zu switch-ENDE
case sk_warten_bis_zurueck:
if ( TimePeriodIsOver(ZylinderTimer, MaximalZeitZurueck) ) {
SchrittNr = sk_Zylinder_vor;
}
break; // springe sofort zu switch-ENDE
case sk_Ventileinheit_aus:
digitalWrite(VentileAbschaltenPin, LOW);
SchrittNr = sk_frei_rechen;
break; // springe sofort zu switch-ENDE
case sk_frei_rechen:
if ( digitalRead(ZylVorPin) == HIGH) { // wenn Zylinder vorne
digitalWrite(ZylVorPin, LOW); // Zylinder zurück
}
else { // wenn Zylinder zurück
digitalWrite(ZylVorPin, HIGH); // Zylinder vor
}
ZylinderTimer = millis();
SchrittNr = sk_frei_rechen_warten;
break; // springe sofort zu switch-ENDE
case sk_frei_rechen_warten:
if ( TimePeriodIsOver(ZylinderTimer, MaximalZeitVor) ) {
SchrittNr = sk_frei_rechen;
}
// wenn Endlage geschaltet hat = KEINE Verstopfung mehr
if ( digitalRead(schaltPin) == HIGH ) {
digitalWrite(VentileAbschaltenPin, eingeschaltet); // obere Rechen wieder einschalten
SchrittNr = sk_Endlage_erreicht; // mit Normal Steuerung weiter machen
}
break; // springe sofort zu switch-ENDE
} // switch-ENDE
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
Als erstes möchte ich ein grosses Dankeschön aussprechen.
Sehr tolles und informatives Forum.
@StefanL38 mit deinem Code hatte ich leider keinen Erfolg.
Ich habe dann noch einen Nano und Uno zum Ausprobieren zugelegt,
dachte das liegt am Digispark. Besten Dank nochmals.
Meinem Sohn ist dann ein Kumpel eingefallen der Programmierer
ist und sich das mal ansehen würde. Nach einigen Erklärungen
und Ablauf Skizzen, ist der Code nun fertig.
Anbei der Code und Schema, falls jemand mal das gleiche benötigt.
Gruss Marcel
[code]
const byte relaisPin = 0; // Pin für Relaisboard (OUTPUT)
const byte schaltPin = 1; // Pin für Endschalter (INPUT)
const int potiPin = A1; // Pin für Poti (INPUT) / Für Externe Einstellung der Zeitlimite
void setup() {
pinMode(schaltPin, INPUT);
pinMode(relaisPin, OUTPUT);
}
static uint32_t previousMillis = 0;
static uint32_t currentMillis = 0;
static uint32_t vorgabeZeit = 0; // diese Zeit bestimmt, ob erfüllt oder nicht erfüllt
static uint32_t vergangeneZeit = 0;
static uint32_t vorherigeZeit = 0;
static uint32_t potiWert = 0;
int schalterstatus = HIGH;
uint32_t debouncingCounter = 0;
const uint32_t zyklenAnzahl = 200; // Diese Zahl eventuell anpassen, je nach Arduino Clock und verwendetem Schalter
const uint32_t potiFaktor = 5; // Faktor Einstellung. Um den PotiWert zu erhöhen.
void loop() {
potiWert = analogRead(potiPin); // Potiwert ist die erlaubte Zeit in ms, welche nicht Überschritten werden darf
vorgabeZeit = potiWert * potiFaktor; // Benennung einer Variablen für (PotiWert inkl. Faktor)
schalterstatus = LOW; // Schalterstatus wird zurückgesetzt
if (digitalRead(schaltPin) == HIGH) { // Wenn der Endschalter betätigt wurde...
debouncingCounter = 0; // stelle den Counter auf Null
} else { // wenn nicht betätigt....
debouncingCounter++; // erhöht bei jedem Durchgang um 1 / wird für einen vergleich mit der ZyklenAnzahl benötigt
}
if (debouncingCounter == zyklenAnzahl) { // Wenn der Endschalter in der gewählten ZyklenAnzahl (wie als Zeit) nicht betätigt wurde,
schalterstatus = HIGH; // zählen wir dies als schaltvorgang
}
currentMillis = millis();
vergangeneZeit = currentMillis - previousMillis;
if (schalterstatus == HIGH) { // Wenn der Endschalter betätigt wird, passiert folgendes ....
vorherigeZeit = vergangeneZeit;
previousMillis = currentMillis; // previousMillis wird auf die aktuelle Zeit gesetzt
vergangeneZeit = 0; // vergangeneZeit wird auf 0 zurückgesetzt
}
if (vergangeneZeit > vorgabeZeit) { // Wenn die vergangeneZeit grösser als die vorgabeZeit ist
digitalWrite(relaisPin, LOW); // dann schalte das Relais der Oberen Zylinder Aus
} else { // wenn Zeit kleiner, dann weiter..
if (vorherigeZeit < vorgabeZeit) { // Wenn die vorherigeZeit kleiner als die vorgabeZeit ist
digitalWrite(relaisPin, HIGH); // dann schalte das Relais der Oberen Zylinder Ein
}
}
schalterstatus = LOW;
}
[/code]