Abarbeitung und Abbruchbedingungen While-Schleifen über Schleifendauer

Hallo Leute,

wie schon aus meinem anderen Thread ersichtlich, bastele ich gerade an einer über ein Uno gesteuerte, pneumatische Kartschaltung.

Die Abfolge mit Setzen der benötigten Ausgänge wollte ich eigentlich über while-Schleifen realisieren.
Nun möchte ich aber gerne die Zeitdauer der Schleifen für den Fall mechanischer Störungen (Endlage wird nicht erreicht, also Schleifenabbruch, wenn vorgang zu lange dauert) begrenzen und dann wieder in eine sichere Ausgangslage (Mittelstellung des Pneumatikzylinders) zurückfahren.

Hier erstmal mein Code:

    time=millis();
    while (AS_unten == LOW && time<safetime) {
      digitalWrite(Sp_runter, HIGH);                // Pneumatikzylinder Runterschalten aktivieren
      digitalWrite(Sp_hoch, LOW);                  // Pneumatikzylinder Hochschalten deaktivieren
      digitalWrite(ZUE, HIGH);                        // Zündunterbrechung weiter aktiv
    }
    while (AS_mitte_unten == LOW) {          
      digitalWrite(Sp_runter, LOW);                // Pneumtakikzylinder Runterfahren wieder deaktivieren
      digitalWrite(Sp_hoch, HIGH);                 // Pneumtakikzylinder wieder Hochfahren in Mittelstellung aktivieren
      digitalWrite(ZUE, LOW);
    }

3 Fragen hätte ich dazu:

  1. Kann die Zeitdauer für den Vorgang auch noch ausgelesen werden, während der Controller in bereits in der While Schleife "festhängt"? Die Schleife als bei Überschreiten der vorgebenen Zeitdauer verlassen werden?

  2. Funktioniert das Auslesen der Bedingung für die While-schleife (Eingang == LOW) überhaupt ohne den digitalread-Befehl?

  3. Arbeitet das Programm wie in meiner Abfolge vorgesehen die verschiedenen While-Schleifen nacheinander ab und überspringt nicht, wenn die Bedingung für die 2. While-Schleife bereits erfüllt ist, "versehentlich" die erste Schleife?

Sry, für meine wahrscheinlich blöden fragen, aber bin eigentlich kein Programmierer und noch Arduino-Einsteiger.

Wenn ihr eine bessere Variante für meine Ablaufsteuerung als die while-Schleifen habt, dann bitte immer her damit. Die prinzipiellen Abläufe sind folgendermaßen: Schalten bis Endlage erreicht ist, dann Umschalten bis neue Endlage erreicht ist.

Wie immer vielen Dank für eure Hilfe im Voraus und
Freundliche Grüße
Marius

Ich glaube, du suchst einen endlichen Automaten.
Auch FSM oder Finite State Machine genannt.

Gibt hier schon etliche Threads dazu.....

Hallo,

eine while Schleife wird solange durchlaufen, solange ihre Eintrittsbedingung wahr ist. Das mußte verinnerlichen.
Das bedeutet, wenn Du die Variable safetime mit zur Bedingung machst, mußt Du diese auch in der Schleife aktualisieren, sonst nützt sie dir nicht zum Notausstieg während der Schleife. Denn die Gültigkeit von safetime würde sich für die while Schleife sonst nie mehr ändern. Ohne durchdachte Prüfung in while besteht die Gefahr zur Endlosschleife.

Hallo,

meinst du mit in der Schleife aktualisieren quasi so:

 while (AS_unten == LOW && time<safetime) {
      
      digitalWrite(Sp_runter, HIGH);                // Pneumatikzylinder Runterschalten aktivieren
      digitalWrite(Sp_hoch, LOW);                  // Pneumatikzylinder Hochschalten deaktivieren
      digitalWrite(ZUE, HIGH);                        // Zündunterbrechung weiter aktiv
      time=millis();
    }
    while (AS_mitte_unten == LOW) {          
      digitalWrite(Sp_runter, LOW);                // Pneumtakikzylinder Runterfahren wieder deaktivieren
      digitalWrite(Sp_hoch, HIGH);                 // Pneumtakikzylinder wieder Hochfahren in Mittelstellung aktivieren
      digitalWrite(ZUE, LOW);
    }

??

Die Variable "safetime" hole ich mir ja eigentlich aus einer globalen Variable.

Mein Tipp:
Die While Schleifen sollten ersatzlos gestrichen werden.
loop() wird in einer Schleife aufgerufen. Das sollte für dieses Problem reichen.

Hallo,

ja so meinte ich das. Ich war zu sehr in while verguckt.

Wenn Du aber nur auf

AS_unten == LOW

wartest, dann kannst Du das bestimmt in einer if Abfrage erledigen.

Etwas anderes wäre es, Du erweiterst while mit der Abfrage der Position Deiner Zylinder. Und Du mußt warten bis sie in Position sind und gleichzeitig gibts Du eine maximale Zeit vor in der das erfolgen muß. Dann macht while wieder Sinn, wenn Du die eine Aktion startest, wartest bis das erledigt ist und dann erst weiter machen möchtest.

Kommt man mit break() nicht auch heraus?

Ich teile aber die Meinung daß Du hier while falsch anwendest.

Grüße Uwe

uwefed:
Kommt man mit break() nicht auch heraus?

Ja.
Eine Schleife mit Seitenausstiegen ist aber sehr unschön.
Das riecht schon etwas wie ein GOTO, oder mehreren Return in einer Funktion.
Und ist hier ganz und gar unnötig.
(aus meiner bescheidenen Sicht auf die Dinge)

Wenn ihr eine bessere Variante für meine Ablaufsteuerung als die while-Schleifen habt, dann bitte immer her damit.

Bedingungen, soweit ich sie verstanden habe:

  1. Zündung wird während der Schaltvorgänge abgeschaltet.
  2. Schaltung bleibt für eine Mindestzeit in Ruhestellung
  3. Schaltvorgänge werden nach einer Zeit ober bei erreichen des Endschalters abgebrochen
  4. Schalthebelrückstellung erfolgt per Federkraft

Das Programm könnte so aus sehen, wenn ich es schreiben wollte/müsste:

const bool on  = true;
const bool off = false;

const int upschalter      = 2;
const int downschalter    = 3;
const int upzylinder      = 4;
const int downzylinder    = 5;
const int upendschalter   = 6;
const int downendschalter = 7;
const int ignition        = 8;

const unsigned long schaltzeit = 100; // zeit für Schaltvorgang
const unsigned long ruekstellzeit = 300; // zeit für schalthebelrückstellung

unsigned long lastHit; // Zeitstempel


typedef enum SchaltStatus{S_Start,S_Ruhestellung,S_GoUp,S_GoDown};
SchaltStatus schaltstatus = S_Start;


void handleSchaltAutomat()
{
  switch(schaltstatus)
  {
    case S_Start : digitalWrite(upzylinder,off);  
                   digitalWrite(downzylinder,off); 
                   digitalWrite(ignition,on); 
                   schaltstatus = S_Ruhestellung;
                   lastHit = millis();
                   break;
                   
    case S_Ruhestellung : if(millis()-lastHit > ruekstellzeit) // warte auf Rückstellzeit
                          { 
                             if(digitalRead(upschalter))
                             {
                                 digitalWrite(upzylinder,on);   
                                 // digitalWrite(downzylinder,off);  
                                 digitalWrite(ignition,off);
                                 lastHit = millis(); 
                                 schaltstatus = S_GoUp;
                             }else if(digitalRead(downschalter))
                             {
                                 // digitalWrite(upzylinder,off);  
                                 digitalWrite(downzylinder,on);  
                                 digitalWrite(ignition,off);
                                 lastHit = millis(); 
                                 schaltstatus = S_GoDown;
                             }
                          }   
                          break;
                          
    case S_GoUp : if(digitalRead(upendschalter)|| (millis()-lastHit > schaltzeit))
                  {
                    schaltstatus = S_Start;
                  }
                  break;
                  
    case S_GoDown: if(digitalRead(downendschalter)|| (millis()-lastHit > schaltzeit))
                   {
                     schaltstatus = S_Start;
                   }
                   break;
   }
}


void setup() 
{
  pinMode(upschalter,INPUT);
  pinMode(downschalter,INPUT);
  pinMode(upzylinder,OUTPUT);
  pinMode(downzylinder,OUTPUT);
  pinMode(upendschalter,INPUT);
  pinMode(downendschalter,INPUT);
  pinMode(ignition,OUTPUT);
}

void loop() 
{
  handleSchaltAutomat();
}

ungetestet und vermutlich sowieso noch unvollständig
Wie man sieht, geht das ganze auch ohne While().

Hallo,

jetzt hast Du auch mehrere break's drin. :grin: :grin: :grin:

while ist kompakter, rein vom leserlichen her. :wink: Dafür hat alles ohne while, wie Du schön gezeigt hast, den großen Vorteil, dass der Code nicht blockiert. Er kann also noch währenddessen auf andere zusätzliche Ereignisse reagieren. Zum Bsp. einen Not-Aus.

Doc_Arduino:
Hallo,
jetzt hast Du auch mehrere break's drin. :grin: :grin: :grin:

Ich sachte ja auch:

Eine Schleife mit Seitenausstiegen ist aber sehr unschön.

Und ich vermute mal, dass switch() jetzt nicht gerade als Schleife durch geht.

Es geht auch ohne switch().
z.B. mit einer Tabelle/Array mit Funktionspointern
Oder mit Funktionspointern, ohne Array.
Oder mit einem großen IF Geschlingel, dann würde sogar goto wieder Sinn machen. Aber schön wird das nicht....

Dafür hat alles ohne while, wie Du schön gezeigt hast, den großen Vorteil, dass der Code nicht blockiert. Er kann also noch währenddessen auf andere zusätzliche Ereignisse reagieren.

Genau!
Das war das Hauptziel bei der Vorführung.

Hallo,

Genau!
Das war das Hauptziel bei der Vorführung.

das war auch mein Hauptziel, der Rest war nur Spass. Wollte Dich etwas aufziehen mit dem "break". :wink:

Hallo,

vielen Dank für eure Anregungen. Werde mich demnächst, wenn wieder Zeit ist, genauer mit allen möglichkeiten befassen.

@ combie:

Punkt 4 deiner Annahme ist falsch: Die Schalthebelrückstellung erfolgt NICHT durch Federkraft, sondern durch komplettes Umschalten eines 5/3-Wege-Ventils, welches zur Richtungsumkehr des doppeltwirkenden Pneumatikzylinders führt. Gehalten (in Mittelstellung) wird der Zylinder dadurch, dass einfach keine Spule des Wege-Ventils bestromt wird (beide Ventilstränge sind gesperrt). So kann der Zylinder theoretisch in jeder beliebigen Stellung gehalten werden.

In der Mittelstellung gibt es 2 Positionssensoren (einer der Schaltet, wenn der Zylinder die Mittelstellung von unten erreicht, einer bei Erreichen der Mittelstellung aus der oberen Endlage. Anders war das nicht machbar, da Reedschalter ja leider keinen definierten Schaltpunkt sondern einen Schaltbereich haben. Für die Endlagen ja kein Problem, nur die Mittelstellung lässt sich damit leider nicht exakt erfassen. Deshalb dieser etwas umständliche Weg der Auswertung.

Wo bekommste denn überhaupt die Pressluft her?

Paintball-Flasche 1,1l 300bar, mit Druckminderer von ner Einweg-Schweißgasflasche.

Reicht laut meinen (theoretischen, ideales Gasgesetz) Berechnungen für ca. 50min bei 33-Schaltvorgängen/min.

Vorteil: Kompakt und somit crashsicher unterzubringen und das gewicht ist nicht allzuhoch.

Hallo,

Du möchtest Dir also eine Art Automatikgetriebe ins Kart bauen? So ein Go-Kart oder was ist das? Macht das Zusatzgewicht denn nicht alles wieder zu Nichte? Oder ist das nur zum Spass ob's funktioniert?

Motorrad Motor, oder Motorradgetriebe im Kart.

SchaltRinge am Lenkrad sind schon typisch.
Aber per Seilzug Kraft aufwändig und recht zäh zu bedienen.

Und das Problem der Schubabschaltung, beim schalten, ist damit auch noch nicht erledigt.
Zumindest beim hochschalten kann man damit problemlos auf die Kupplung verzichten.

Was ist Deiner Meinung eine Schweißgasflasche?
Azetylen? Das steht aber nicht unter Hochdruck sondern max 15 bar. Darüber zerfällt das Molekül.

Grüße Uwe

Kein Brenngas.
Schutzgas.

Vielleicht sogar Atemgas.
Auch da kommen die Verdichter in diese Druckbereiche.

Hallo,

@ doc_arduino:

ja ist nur zum spaß und freude am basteln, obs funktioniert. Es gibt ein kommerzielles System dazu, kostet aber um die 1000€, was den wert meines karts übersteigt.

@ all: ist vom prinzip her ein motorradmotor, aber eben speziell für kartsport. Die kupplung wird hier standardmäßig eh nur zum anfahren genutzt. Hochgeschaltet wird im Normalfall mit gas kurz lupfen (Fuß vom Gas), beim runterschalten ist man eh auf der bremse und gibt kein gas, erfolgt also auch ohne kupplung. Normalerweise alles manuell mit einem schaltknüppel.
Das gas lupfen beim hochschalten will ich mir halt durch zündunterbrechung sparen, so wirds beim kommerziellen system auch gemacht. So kann man sich das gas lupfen sparen, was vielleicht ne zehntel sekunde und jede menge rennsportfeeling bringt. :wink:
runterschalten könnte wie schon beschrieben auch ohne zündunterbrechung ohne kupplung erfolgen, da man da eh vom gas runter ist.
automatisches schalten wär ein projekt für nexten winter (drehzahlerfassung über arduino fehlt dazu noch), ist aber eher spielerei und gehört eigentlich nicht zum schaltkart fahren. Dann kann man auch gleich auf einen getriebelosen motor zurückgreifen.

Thema Druckminderer: aus der HP-Paintballflasche gehts bis der fülldruck soweit abgesunken ist mit max 58bar in den vordruckminderer. Dieser druckminderer kommt aus ner einweg-schweißgasflasche (inertgas, z.B. Argon) welcher max. 120bar vordruck kann und dann auf die für den pneumatikzylinder benötigten max. 6 bar ausgangsdruck reduziert zum einsatz. Das "mechanische" System ist auch schon soweit getestet und funktioniert einwandfrei.
Fehlt halt nur noch die Steuerung dazu...

Hallo,

ich finde das echt cool. Die Autoindustrie nennt sowas "drive by wire". :smiley:
Nur solltest wissen, dass es wirklich nur ein Spass Projekt sein wird. Denn auf einer Rennstrecke dürfest du mit einer Gasflasche am Kart nie fahren. Wegen "zum Geschoß werden ...". Ich denke jedoch Du weist was Du machst, deshalb bin ich mal gespannt was daraus wird ...