Schrittmotor mit millis() pausieren

Hallo,

ich lasse einen Schrittmotor mit den Werten eines MPU6050-Sensors eine Ausgangslage "mitte" anfahren. Danach werden wiederkehrend drei Positionen angefahren. Wenn eine Positionen erreicht wird, soll der Motor eine Pause von 20 Sekunden einlegen.

Mit meinem Code beginnt allerdings die Zählung für die erste Pause schon mit der Anfahrt in die Ausgangslage "mitte". Danach fährt der Motor alle Positionen wiederkehrend ohne Pause an.

Ich hoffe jemand kann mir helfen.

void loop()
{
  unsigned long AktuelleZeit = millis();
  unsigned long VergangeneZeit=0;               
  unsigned long interval = 20000; 

// fährt in die Ausgangslage "mitte"
// funktioniert

  if (E0_Achse_Foto_links == false && E0_Achse_Foto_mitte == false && E0_Achse_Foto_rechts == false)     
    {
      if (GyY_filtered > -25000&& GyY_filtered < -100)
       {
        E0_Achse.move(-30);
       }         
      else if (GyY_filtered < 25000&& GyY_filtered > 100)
       {
        E0_Achse.move(30);
        }
      else 
       {          
        E0_Achse_Foto_mitte = true; 
        E0_Achse.setCurrentPosition(0);
       }         
    }

// fährt von der Mitte nach links. 
// Allerdings wird die Zeit, die der Motor für die Anfahrt 
// in die Ausgangslage "mitte" (siehe oben) benötigt in die Pausenzeit (interval) 
// eingerechnet. 

    
  if (E0_Achse_Foto_mitte == true)
    {
      if (AktuelleZeit - VergangeneZeit >=interval)
        {           
          E0_Achse.runToNewPosition(500);                      // von der mitte nach links
          E0_Achse_Foto_links = true;
          E0_Achse_Foto_mitte = false;
          VergangeneZeit = AktuelleZeit;
        }    
      }

//fährt von links nach rechts
//leider keine Pause
    
  if (E0_Achse_Foto_links == true)             
    {
      if (AktuelleZeit - VergangeneZeit>=interval)
        {                  
          E0_Achse.runToNewPosition(-500);                       // von links nach rechts
          E0_Achse_Foto_rechts = true;
          E0_Achse_Foto_links = false;
          VergangeneZeit = AktuelleZeit;
        } 
      }      


//fährt von rechts zur Mitte
//leider keine Pause

  if (E0_Achse_Foto_rechts == true)             
    {
      if (AktuelleZeit - VergangeneZeit >=interval)
      {
          VergangeneZeit = AktuelleZeit;      
          E0_Achse.runToNewPosition(0);                       // von rechts zur mitte
          E0_Achse_Foto_mitte = true;
          E0_Achse_Foto_rechts = false;
    } 
}
E0_Achse.run();
}

Hallo,

naja, du setzt mit jedem loop Durchlauf deine "vergangene Zeit" immer wieder auf 0.

Vorschlag, initialisiere diese beiden Variablen als globale Variablen.

unsigned long VergangeneZeit = 0;               
unsigned long interval = 20000;

Hallo,

vielen Dank. Jetzt pausiert der Motor auf jeder Position. Allerdings ist in den 20s auch die Anfahrt zur Position enthalten.
Was muss ich tun um auf 20s Pause zu kommen.

Hallo,

formuliere das Anliegen bitte nochmal neu.

Ich schalte mal meine Glaskugel ein. Beim einschalten soll "Mitte" sofort angefahren werden. Ab da jede Position mit 20s Pause. Dann musst du als Startbedingung das intervall runtersetzen und danach einmalig erhöhen.

Tipp. Es ist immer ratsam einen Ablaufplan anzufertigen bis es passt wenn es komplizierter wird. Diesen dann in Code umsetzen ist einfacher. Man hat eine Basis vor sich liegen.

Noch ein Hinweis. Du kannst auch setup() nutzen um eine einmalige Aktion auszuführen beim Start.

1 Like

Um volle Unterstützung geben zu können, wäre es auch gut, immer den kompletten Code zu posten, damit man erkennt, welche Bibliotheken eingebunden sind bzw. welche Variablen deklariert wurden, was im setup steht etc.

Hallo,

@Doc_Arduino:
Sorry, du hast recht. Als Anfänger fällt es mir schwer mich hier verständlich auszudrücken und die Probleme korrekt zu beschreiben. Da habe ich mich etwas verirrt. Ich versuche es noch mal.

Der Code im ersten Post ist so nicht korrekt. Eigentlich liegen die Bewegungsbefehle für den Motor E0 in einer eigenen Funktion "moveE0()" :confused:

Beim Einschalten wird ohne eine Pause die Mitte angefahren. Dazu wird ständig ein Mpu6050-Sensor abgefragt.
Wenn der GyY-Wert im Bereich zwischen +100 und-100 ist, wird die Position (mitte) auf Null gesetzt.
Dann brauche ich eine Pause von etwa 2 Sekunden um Fotos zu schießen.
Danach fährt der Motor auf die Position "links" und macht eine Pause von 2 Sekunden.
Danach.......................auf die Position "rechts" und macht eine Pause von 2 Sekunden.
Danach.......................auf die Position "mitte".

Ich hatte mich immer gewundert, dass wenn 2s als "interval" gesetzt waren, der Motor nicht pausierte. Das lag aber daran, dass das "interval" mit der Bewegung auf die Position beginnt. Und wenn die Bewegung länger als das "interval" dauert, gibt es keine Pause. Deshalb hatte ich das "interval" erst einmal auf sichere 20 Sekunden gesetzt.

Versteht ihr mein Problem jetzt besser? :o Ich möchte eine Bewegung zur Position und dann eine Pause von 2Sekunden.

So bewegt sich der Motor mit dem Code im Anhang

Bsp_motor_pause_millis.txt (12.3 KB)

Hallo,

Links bitte in Tags setzen.

[url] link [/url]

und wenn es nicht zu lange ist den Code in Code Tags, Button oben links </>
Die Leute wollen was zum klicken haben, dann wird besser gelesen und geholfen, obwohl ich Code als Anhang auch nicht schlecht finde. :slight_smile:

Zum Problem, ich denke jetzt weiß ich wie das ablaufen soll.
Im Grunde ist das ein Zustandsautomat den du programmierst, dass können dir andere hier besser erklären.
Von agmue und combie gibts dafür Links und Erklärungen, die Links, immer wenn man sie benötigt, findet man den Thread nicht. :confused:
Du hast 3 Positionssensoren, links, mitte, rechts, nehme ich an, der Code liest sich schwer, weil bestimmt wild zusammengeschustert? Dann müßtest du nur abfragen ob die Position erreicht ist, wenn ja, 2s warten und dann weitere Funktionen/Befehle ausführen.

Deine "aktuelle_Zeit = millis" muss noch in die loop an den Anfang und nicht in irgendeine Funktion.
Nur die loop ist die Schleife die immer ausgeführt wird.
Alles andere kann abgearbeitet werden, muss aber nicht, je nach Bedingungen.

Das kann dann so aussehen oder ähnlich. Wie du die Position tatsächlich erkennst musst du wissen. Ob an Hand der gemachten Schritte oder Sensor o.ä. Die Denklogik sollte erkennbar sein um die Wartezeit einzuhalten.

if (position_mitte == true) {       // Positionssensor erreicht?
  time_position_mitte = millis();   // wenn ja, aktuelle Zeit merken
  position_mitte = false;           // Funktionseintritt sperren
  start_aktion_mitte = true;        // Hilfvariable setzen
  
}


if ( (start_aktion_mitte == true) && (aktuelle_Zeit - time_position_mitte > 2000) ) {
  ... Foto knipsen
  start_aktion_mitte = false;        // Hilfvariable löschen
  ...
  
}

das Ganze kannste noch aufgeräumter in eine Funktion setzen und rufst in der loop nur noch action_Mitte(); auf.

void action_Mitte ()
{
	static unsigned long time_position_mitte = 0;
	static bool start_aktion_mitte = false;
	
	// wenn Position erreicht, Zeit merken
	if (position_mitte == true) {             // Positionssenor erreicht?
		time_position_mitte = millis();   // wenn ja, aktuelle Zeit merken
		position_mitte = false;           // Funktionseintritt sperren
		start_aktion_mitte = true;        // Hilfsvariable setzen
	}


	// Position erreicht und Wartezeit abgelaufen?
	if ( (start_aktion_mitte == true) && (aktuelle_Zeit - time_position_mitte > 2000) ) {
		... Foto knipsen
		start_aktion_mitte = false;        // Hilfsvariable löschen
		... 
	}

}

Hallo,
@Doc Arduino: Der Code war halt >9000 Zeichen; deshalb als Anhang. Und ja, ganz schön zusammengeschustert.

Die Sharpsensoren kommen jetzt noch nicht zum Einsatz. Sie messen den Abstand zur Oberfläche des zu fotografierenden Objektes. Der E0-Motor richtet sich nach der Oberfläche aus und Die Z-Achse korrigiert den Abstand. Damit sich die Sensoren nicht gegenseitig beeinflussen, habe ich Mosfets eingebaut und schalte sie so nacheinander.
Da ich aber sehr gute Ergebnisse hatte mit drei verschiedenen Winkeln, Mitte(senkrecht), Links und Rechts möchte ich die meist nur leicht gewölbten Oberflächen der Objekte ohne Sharpsensoren aufnehmen. Diese kommen dann aber noch am Übergang von der Flachseite zur Schmalseite der Objekte zum Einsatz.

Deine Vorschläge habe ich versucht umzusetzen. Die Logic dahinter vestehe ich. Aber es ist in der Umsetzung noch der Wurm drin :frowning: . Eine Pause macht er nicht.
In der Loop habe ich "AktuelleZeit=millis();" ganz nach oben geschoben.

Die Ausrichtung "E0_action_AnfahrtMitte()", am Anfang, funktioniert ganz gut.
Danach keine (2s) Pause
"E0_action_Mitte()" fährt von der Mitte nach Links.
Danach keine (2s) Pause
"E0_action_Links()" fährt von Links nach Rechts.
Danach keine (2s) Pause
"E0_action_Rechts()" fährt von Rechts zur Mitte.
Danach keine (2s) Pause
Doch anstatt jetzt wieder nach Links zu fahren, überspringt er den Teil und fährt gleich wieder nach Rechts.

Im Video sieht man es ganz gut. :confused:

void E0_action_AnfahrtMitte()
{
  if (position_links == false && position_rechts == false && position_mitte == false)        //Position erreicht?
  {
    if (GyY_filtered > -25000 && GyY_filtered < -100) //(-249999)-(-101)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(-30);
    }
    else if ((GyY_filtered < 25000) && (GyY_filtered > 100))//(249999)-(101)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(30);
    }
    else
    {
      E0_Achse.setCurrentPosition(0); // setzt Position auf 0
      position_mitte = true;      // Hilfsvariable setzen
      Serial.println("position_mitte == true");
    } 
  }
}

void E0_action_Mitte()
{
    static unsigned long time_position_mitte = 0;
    static bool start_aktion_mitte = false;

// wenn Position erreicht, Zeit merken  
  if (position_mitte == true)         //Position erreicht?)
  {
    time_position_mitte = millis();   //wenn ja, aktuelle Zeit merken
    position_mitte = false;           //Funktionseintritt sperren
    start_aktion_mitte = true;        //Hilfsvariable setzen
  }
  if ((start_aktion_mitte == true) && (AktuelleZeit - time_position_mitte > 2000))
  {
    Serial.println("                                        Lage: mitte");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(500);   // fahre auf absolute Position
    start_aktion_mitte = false;       //Hilfsvariable löschen
    position_links = true;
  }
}

void E0_action_Links()
{ 
  static unsigned long time_position_links = 0;
  static bool start_aktion_links = false;
  
  // wenn Position erreicht, Zeit merken
  if (position_links == true)         //Position erreicht?
  {               
    time_position_links = millis();   //wenn ja, aktuelle Zeit merken
    position_links = false;           //Funktionseintritt sperren
    start_aktion_links = true;        //Hilfsvariable setzen
  }
  //Position erreicht und Wartezeit abgelaufen?
  if ((start_aktion_links == true) && (AktuelleZeit - time_position_links > 2000))
  {
    Serial.println("                                        Lage: links");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(-500);  // fahre auf absolute Position
    start_aktion_links = false;       //Hilfsvariable löschen
    position_rechts = true;
  } 
}

void E0_action_Rechts()
{ 
  static unsigned long time_position_rechts = 0;
  static bool start_aktion_rechts = false;
  
  // wenn Position erreicht, Zeit merken
  if (position_rechts == true)        //Position erreicht?
  {               
    time_position_rechts = millis();  //wenn ja, aktuelle Zeit merken
    position_rechts = false;          //Funktionseintritt sperren
    start_aktion_rechts = true;       //Hilfsvariable setzen
  }
  //Position erreicht und Wartezeit abgelaufen?
  if ((start_aktion_rechts == true) && (AktuelleZeit - time_position_rechts > 2000))
  {
    Serial.println("                                        Lage: rechts");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(0);     // fahre auf absolute Position
    start_aktion_rechts = false;      //Hilfsvariable löschen
    position_mitte = true;    
  } 
}

Hallo,

hmm, du musst immer den gesamten Code zur Verfügung stellen, man sieht sonst nicht was noch alles geändert wurde usw.

Hallo,

also immer den vollständigen Code posten. Merke ich mir.... :). Ist größer als 9000 Zeichen--> Anhang

Schrittmotor mit millis pausieren.txt (13.1 KB)

Hallo,
habe jetzt die Variablen "position_mitte=false;","position_links=false;" und "position_rechts=false;" der ersten if-Bedingung in die zweite if-Bedingung verschoben.
Der Bewegungsablauf ist jetzt korrekt.

Die Ausrichtung "E0_action_AnfahrtMitte()", am Anfang, funktioniert ganz gut.
Danach keine (2s) Pause
"E0_action_Mitte_Links()" fährt von der Mitte nach Links.
Danach keine (2s) Pause
"E0_action_Links_Rechts()" fährt von Links nach Rechts.
Danach keine (2s) Pause
"E0_action_Rechts_Mitte()" fährt von Rechts zur Mitte.
Danach keine (2s) Pause
"E0_action_Mitte_Links()" fährt von der Mitte nach Links.
usw.

Jetzt fehlen noch die zwei Sekunden Pause wenn die Position erreicht ist.

void E0_action_AnfahrtMitte()           // fährt einmalig die Mitte an und setzt den Motor auf 0 
{
  if (position_links == false && position_rechts == false && position_mitte == false)        //Postition erreicht?
  {
    if (GyY_filtered > -25000 && GyY_filtered < -100) //(-249999)-(-101)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(-100);
    }
    else if ((GyY_filtered < 25000) && (GyY_filtered > 100))//(249999)-(101)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(100);
    }
    else
    {
      E0_Achse.stop();
      E0_Achse.setCurrentPosition(0); // setzt Positiion auf 0
      position_mitte = true;      // Hilfsvariable setzen
      Serial.println("position_mitte == true");
    } 
  }
}

void E0_action_Mitte_Links()          //2s Pause,fährt dann von der Mitte nach Links
{
    static unsigned long time_position_mitte = 0;
    static bool start_aktion_mitte_links = false;


// wenn Position erreicht, Zeit merken  
  if (position_mitte == true)         //Postition erreicht?)
  {
    time_position_mitte = millis();   //wenn ja, aktuelle Zeit merken
    //position_mitte = false;           
    start_aktion_mitte_links = true;        //Hilfsvariable setzen
  }
  if ((start_aktion_mitte_links == true) && (AktuelleZeit - time_position_mitte > 2000))
  {
    Serial.println("                                        Lage: mitte");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(1000);   // fahre auf absolute Position
    start_aktion_mitte_links = false;
    position_mitte = false;            //Funktionseintritt sperren
    position_links = true;
  }
}

void E0_action_Links_Rechts()                //2s Pause,fährt dann von Links nach Rechts
{ 
  static unsigned long time_position_links = 0;
  static bool start_aktion_links_rechts = false;
  
  // wenn Position erreicht, Zeit merken
  if (position_links == true)         //Postition erreicht?
  {               
    time_position_links = millis();   //wenn ja, aktuelle Zeit merken
    //position_links = false;           //Funktionseintritt sperren
    start_aktion_links_rechts = true;        //Hilfsvariable setzen
  }
  //Position erreicht und Wartezeit abgelaufen?
  if ((start_aktion_links_rechts == true) && (AktuelleZeit - time_position_links > 2000))
  {
    Serial.println("                                        Lage: links");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(-1000);  // fahre auf absolute Position
    start_aktion_links_rechts = false;       //Hilfsvariable löschen
    position_links = false;		//Funktionseintritt sperren
    position_rechts = true;
  } 
}

void E0_action_Rechts_Mitte()         //2s Pause,fährt dann von Rechts zur Mitte
{ 
  static unsigned long time_position_rechts = 0;
  static bool start_aktion_rechts_mitte = false;

  // wenn Position erreicht, Zeit merken
  if (position_rechts == true)        //Postition erreicht?
  {               
    time_position_rechts = millis();  //wenn ja, aktuelle Zeit merken
    start_aktion_rechts_mitte = true;           //Hilfsvariable setzen
    //position_rechts = false;          //Funktionseintritt sperren
  }
  //Position erreicht und Wartezeit abgelaufen?
  if ((start_aktion_rechts_mitte == true) && (AktuelleZeit - time_position_rechts > 2000))
  {
    Serial.println("                                        Lage: rechts");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(0);     // fahre auf absolute Position
    start_aktion_rechts_mitte = false;      //Hilfsvariable löschen
    position_rechts = false;		//Funktionseintritt sperren
    position_mitte = true;    
  } 
}

Schrittmotor mit millis pausieren.txt (13.5 KB)

Hallo,

laut meiner Logik, dürfte der Motor nach erreichen der ersten Mitte nie weiter drehen, weil die erste Zwischenzeit time_position_mitte und später auch die anderen ständig aktualisiert werden. Damit kann der Vergleich > 2000 nie wahr werden. Die Funktionseintrittssperre ist ja leider auskommentiert wurden. Warum eigentlich? Nun kam ich ins grübeln warum er dennoch weiter macht.

Der Grund wird sein, dass die du die nächste Startbedingung für die nächste Funktion, Bsp. E0_action_Mitte_Links()
schon in der vorherigen immer schon aktiv setzt mit position_mitte = true;
Damit greift der Sinn der Abfrage ins leere,
if (position_mitte == true) //Postition erreicht?)
weil der Motor zu dem Zeitpunkt noch nicht in Mitte steht, er dreht ja noch dort hin, aber schon die Variable gesetzt ist, womit in der nächsten Funktion die Zwischenzeit schon genommen wurde und dann der 2s Vergleich natürlich schon lange vorher gültig ist usw.

Diese Positionabfrage muss eine echte Positionsabfrage sein. Das war nur ein Bsp. was an der Stelle gemacht werden soll, deswegen auch der Kommentar. Vielleicht falsch verstanden, soll vorkommen in einem Forum.
if (position_mitte == true) // Postition erreicht?

Ich meine hier eine Positionabfrage mit Sensor oder du nimmst die Schritte deines Motors zum Vergleich. Erst wenn er in der gewünschten Position wirklich ist, darf die Eintrittsbedingung für die nächste Funktion gültig werden. Ist das verständlicher gewesen?

Das kannst du gut sehen, wenn du dir einen seriellen Monitor baust, wo benötigte Variablen zyklisch ausgegeben werden zum debuggen. serieller_Monitor(); ruftste in loop auf. Funktioniert erstmal nur mit globalen Variablen.
Bsp.

void serieller_Monitor ()
{
  static unsigned int intervall = 500;    // Ausgabeintervall
  static unsigned long last_millis = 0;

  if ( millis() - last_millis > intervall )  {    // aller x [ms] frische Daten
    last_millis = millis(); 
    Ueberschriftszeile();
    Serial.print(position_links); Serial.print('\t');
    Serial.print(position_mitte); Serial.print('\t');
    Serial.print(position_rechts); Serial.print('\t');
    Serial.print(AktuelleZeit); Serial.print('\t');
    Serial.println();
  }  
}


void Ueberschriftszeile ()
{
  static int counter = 33;

  counter++;
  
  if (counter<25) return; // Zeit noch nicht erreicht, Funktion abbrechen
  
  counter = 0; 
  Serial.print(F(" L ")); Serial.print('\t');
  Serial.print(F(" M ")); Serial.print('\t');
  Serial.print(F(" R ")); Serial.print('\t');
  Serial.print(F("ms ")); Serial.print('\t');
  Serial.println();
}

Problematisch könnte noch sein oder werden, dass du im Code Zeitvergleiche einmal mit millis() direkt machts und dann wieder mit "AktuelleZeit". Die sind bedingt nie gleich. millis() ist immer unmittelsbar aktuell. AktuelleZeit wird nur beim loop Durchlauf aktualisiert.
Wenn alle Funktionen in einem loop Umlauf mit der gleichen Zeit handieren sollen, dann nimmt man "AktuelleZeit" am loop Anfang. Dann ist es egal wie lange die loop für einen Umlauf benötigt.
Wenn man aber innerhalb eines loop Umlaufes mit genauen Differenzen arbeiten möchte, dann muss man immer aktuell bleiben, also nimmt man immer millis() für jeden Vergleich. Weil Dein Code macht ja noch mehr als Positionen anfahren.

Übrigens, static verwendet man für lokale Variablen die sich bei Aufruf einer Funktion nicht "nullen", sondern den alten Wert behalten sollen aber innerhalb änderbar bleiben. Hinweis für deine static unsigned long interval = 2000;
Entweder ohne static als normale globale Variable oder wenn wirklich immer konstant, dann mit const davor.
Das sind Feinheiten, sollte man jedoch kennen wenn man damit handiert.

Hallo,

@ Doc_Arduino:
Du nimmst Dir viel Zeit um meine Fragen zu beantworten. Und obwohl Du Dir wahrscheinlich die Haare raufst und denkst "was fürn Hirni", gibst Du (noch ;-))nicht auf. Bin ich echt beeindruckt und dankbar.

Die Funktionseintrittssperre ist ja leider auskommentiert wurden. Warum eigentlich?

Ich hatte die Variable "position_mitte=false; in die zweite if-Bedingung verschoben. So war der Bewegungsablauf "mitte" nach "links" nach "rechts" und zur Mitte.... wieder hergestellt.
Ich weiß nicht wie ich mit der Variable position_mitte = true; umgehen soll. Wenn ich in der ersten Funktion Void E0_action_AnfahrtMitte() mit E0_Achse.setCurrentPosition(0) den Motor auf "0" setzte, gehe ich doch davon aus, dass dies der Abschluß ist und keine Bewegung innerhalb der Funktion mehr stattfindet. Ich setzt den Motor auf "0" und ändere die Zustandsvariable in position_mitte = true;. Wenn ich in der nächsten Funktion void E0_action_Mitte_Links() dann diese Variable zusammen mit AktuelleZeit - time_position_mitte > 2000 in eine "If-Anweisung" packe, sollte der Motor doch 2Sekunden stehen. Dachte ich. Aber so einfach ist das nicht:

Der Grund wird sein, dass die du die nächste Startbedingung für die nächste Funktion, Bsp. E0_action_Mitte_Links()
schon in der vorherigen immer schon aktiv setzt mit position_mitte = true;
Damit greift der Sinn der Abfrage ins leere,
if (position_mitte == true) //Postition erreicht?)
weil der Motor zu dem Zeitpunkt noch nicht in Mitte steht, er dreht ja noch dort hin, aber schon die Variable gesetzt ist, womit in der nächsten Funktion die Zwischenzeit schon genommen wurde und dann der 2s Vergleich natürlich schon lange vorher gültig ist usw.

Mir dreht sich der Kopf. :o
Ich habe dann die Position des Motors zusammen mit der Variablen position_mitte abgefragt:

void E0_action_AnfahrtMitte()           // fährt einmalig die Mitte an und setzt den Motor auf 0 
{
  if (position_links == false && position_rechts == false && position_mitte == false)        //Postition erreicht?
  {
    if (GyY_filtered > -25000 && GyY_filtered < -170) //(-249999)-(-171)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(-80);
    }
    else if ((GyY_filtered < 25000) && (GyY_filtered > 170))//(249999)-(171)
    {
      Serial.println("Lage: irgendwo");
      E0_Achse.move(80);
    }
    else
    {
      E0_Achse.setCurrentPosition(0); // setzt Positiion auf 0
      position_mitte = true;      // Hilfsvariable setzen
      Serial.println("position_mitte == true");
    } 
  }
}

void E0_action_Mitte_Links()          //2s Pause,fährt dann von der Mitte nach Links
{
    static unsigned long time_position_mitte = 0;
    static bool start_aktion_mitte_links = false;
    
// wenn Position erreicht, Zeit merken  
  if (E0_Achse.currentPosition()==0 && position_mitte == true)       //absolute Postition erreicht?)
  {
    time_position_mitte = AktuelleZeit;   //wenn ja, aktuelle Zeit merken
    position_mitte = false;                     //Funktionseintritt sperren
    start_aktion_mitte_links = true;        //Hilfsvariable setzen
    
  }
  if (start_aktion_mitte_links == true && AktuelleZeit - time_position_mitte > interval)  //2000ms
  {
    Serial.println("                                        Lage: mitte");
    Serial.println(E0_Achse.currentPosition());
    E0_Achse.runToNewPosition(-500);      // fahre auf absolute Position
    start_aktion_mitte_links = false ;
    position_links = true;      
  }
}

Da ist noch der Wurm drin.

Was mache ich falsch? Das Intervall ist 10s lang. Und wieder beginnt die Zählung der 10s vom Start der Funktion bis zum Start der nächsten Funktion.

Schrittmotor mit millis pausieren.txt (14.4 KB)

Hallo,

Ich habe es nicht geschafft jede Bewegung in eine eigene Funktion zu stellen und jeder Bewegungen noch eine Pause anzuhängen.
Die (vorläufige) Lösung liegt in einer Switch-Anweisung. Doc_Arduino hatte schon darauf hingewiesen.

Geholfen hat: #45
https://forum.arduino.cc/index.php?topic=396397.45

Noch etwas dichter an dem was ich möchte (weil mit Schrittmotor und Pause) ist #5
http://forum.arduino.cc/index.php?topic=426558.0

Ein Video vom Bewegungsablauf:

Die Pausen sind jetzt auf 1s verkürzt und das Licht schaltet sich in den Pausen an.

Ganz glücklich bin ich nicht. Es müssen noch Bewegungen der X-,Y- und Z-Achse integriert werden, welche auf Sharp ir-Sensoren reagieren sollen. Ich vermute mal, dass das Switch dafür etwas unflexibel ist.

Vielen Dank erstmal :slight_smile:

Schrittmotor mit millis pausieren.txt (12.2 KB)

Hallo,

naja, eigentlich muss sowas "einfaches" wie Position anfahren, warten, knipsen, weiter drehen ... ja zu lösen sein. :slight_smile:

Das Projekt nochmal neu aufziehen als Zustandsautomaten wäre eine Idee. Nur funktioniert das auch nur, wenn du weißt wann der Motor wo in Position ist. Deshalb nochmal die Frage. Woher weißt du ob der Motor an der gewünschten Position ist? Ich sehe ja im Video das du eine Position anfährst und dann erst fotografierst. Ich sehe das aber leider im Code nicht. Da müsstest du mir mal auf die Sprünge helfen.

Übrigens, überschaubare wiederverwendbare Funktionen schreiben ist immer gut. Umso leichter wartbar ist der Code. Klingt erstmal unsinnig, warum soll ich alles aus loop in Funktionen verbannen, aber man blickt eher durch und hat weniger globale Variablen. Das am Rande. Lernt man über die Jahre eben, musste ich auch verstehen lernen.

Edit: Quatsch, deine loop sieht ja schon aufgeräumt aus

Hallo,

eines kann ich dir schon sagen, der Code aus #13 kann nicht kompilieren. Bitte nichts posten was eh nicht funktioniert.
Das verwirrt nur als was es hilft. Dein state funktioniert so nicht. Das geht nur im Zusammenspiel mit enum. Ist aber eine gute Idee. Verschafft Überblick im Code.

void E0_BewegungenFlachseite()
{
  static int state = E0_MOVE_MITTE;

  switch (state)
  {
    case E0_MOVE_MITTE:
      {

du fährst offentsichtlich mit dieser Funktion deine Positionen an. Ist die Funktion blockierend oder nicht?
Also verbleibt er während der Bewegung stur in dieser und kehrt erst bei "fertig" zurück oder wird die loop während der Bewegung weiterhin duchlaufen? Das müßtest du am seriellen Monitor sehen. Ob während Motorbewegungen Ausgaben stattfinden oder nicht.

E0_Achse.runToNewPosition(500);

Hallo,

wegen enum. Du definierst damit einen neuen eigenen Datentyp.

Die erste auskommentierte Version funktioniert auch. Er hat nur einen anonymen Datentyp. Ob das der Compiler dann intern vergibt weiß ich nicht genau, wahrscheinlich schon, sonst könnte er die die unterscheiden.

Die zweite wäre die ganz saubere Programmierung, hatte ich gelernt. Du definierst damit deinen Datentyp namens zustand.

void E0_BewegungenFlachseite()
{
  /*
  enum {E0_MOVE_MITTE, E0_PAUSE_MITTE_SHOT, E0_MOVE_MITTE_LINKS};
  static byte state = E0_MOVE_MITTE;
  */

  
  typedef enum {
      E0_MOVE_MITTE,
      E0_PAUSE_MITTE_SHOT,
      E0_MOVE_MITTE_LINKS
  } zustand;
  static zustand state = E0_MOVE_MITTE;
   
  switch (state)
  {

Doc_Arduino:
Ob das der Compiler dann intern vergibt weiß ich nicht genau, wahrscheinlich schon, sonst könnte er die die unterscheiden.

enums sind letztlich nur Integer Konstanten. Und fangen normal bei 0 an. Der Standard Datentyp dafür ist int.

In C++11 gibt es aber auch "strongly typed enums". Die kann man z.B. auf byte/unsigned char beschränken und sie sind nicht mehr einfach einem Integer zuweisbar.

Hallo Serenifly,

es war gestern schon spät und ich hatte den wirren Gedanken was der Compiler wohl macht, wenn man mehrere enums ohne eigenen Datentyp anlegt. Problem der Unterscheidung. Für mich ist jetzt wieder alles klar nach Gedankensortierung. Wenn ich den Gedankenabschweif erklären müßte, dass würde jetzt nichts bringen. :slight_smile:

Doc_Arduino:
es war gestern schon spät und ich hatte den wirren Gedanken was der Compiler wohl macht, wenn man mehrere enums ohne eigenen Datentyp anlegt. Problem der Unterscheidung.

Selbst wenn man das nicht anonym macht gibt es da Probleme. Aber auch das wird mit "strongly typed enums" gelöst.

Das hier kompiliert aber er meint es wäre gleich:

enum test1 { RED, GREEN };
enum test2 { BLUE, YELLOW };

int _tmain(int argc, _TCHAR* argv[])
{ 
 test1 value = RED;

 if (value == BLUE)
   cout << "gleich" << endl;
 else
   cout << "nicht gleich" << endl;
 
 getchar();
}

Wenn man dagegen "enum class" macht kompiliert das nicht, weil man den Scope Operator braucht um auf die Konstanten zuzugreifen und man nicht test1:: mit test2:: vergleichen kann