Suche Schleifenspezialisten

Hallo,

ich möchte mit einem Stepper jeweils 3x hintereinander die Positionen -100 und +100 anfahren, und danach jeweils 5x die Geschwindigkeit erhöhen (100000, 150000, 250000, 350000, 500000).
Momentan habe ich das einfach nacheinander weg geschrieben, was natürlich völlig irre ist.
Wie kriege ich das möglichst kurz und übersichtlich in Schleifen verpackt?
Mir fällt da nicht so richtig was Gutes zu ein ::slight_smile:

  stepper.setMaxSpeed(100000);
  stepper.setAcceleration(100000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(150000);
  stepper.setAcceleration(150000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(250000);
  stepper.setAcceleration(250000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(350000);
  stepper.setAcceleration(350000);
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(500000);
  stepper.setAcceleration(500000);
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }

Hi

State-Maschine.
0: mache nix
1: laufe links, wechsel auf 2
2: Position 100 erreicht? Status=3
3: laufe rechts, wechsel auf 4
4: Position -100 erreicht? Status=5
5: Schligger++; Schligger<5 → wechsel auf 1, sonst auf 0

.run kommt in die loop(), keine while-Schleifen, Nix, was blockiert.
Du gibst jeweils nur die Endposition an und prüfst in den entsprechenden Status, ob wir ‘am Ziel sind’ - ob absolute Position, oder relativ auf 0 ist Dabei wohl egal.

Würde die State-Maschine in eine Funktion auslagern - dann hast Du zwei Zeilen in der loop() dafür und bist ‘durch’.

MfG

...kapier ich das nicht, oder du nicht?

Ohne die while-Schleifen läuft da gar nichts. bzw. maximal ein Schritt.

In der Loop läuft das normale Programm.

In dieser Prozedur läuft meine "Freirüttelroutine" völlig losgelöst von der Loop.
Die Loop muss dafür quasi komplett unterbrochen werden.

Vielleicht nochmal kurz die Idee des Gesamtprogramms.

Freirüttelprozedur(){
Stepper Geschwindigkeit 100000
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper Geschwindigkeit 200000
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper Geschwindigkeit 300000
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Stepper soll sich 100 Schritte nach links bewegen
Stepper soll sich 100 Schritte nach rechts bewegen
Fertig freigerüttelt
Und wieder Rückgabe an die Loop
}

Loop(){
neue Zielposition für den Stepper setzen
stepper.run
Stepper SOLL-IST Vergleich
Wenn SOLL-IST Vergleich ergibt, dass eine Blockade vorhanden ist, dann Freirüttelprozedur
}

Kein Schrittmotor macht Dir mit solchen Geschwindigkeiten mit.

Mal vom Blockieren und den Geschwindigkeiten abgesehen...

Mach dir doch einfach eine Funktion, der du die Geschwindigkeit, Beschleunigung und Position übergibst.
Pro Schleife hast du dann nur einen Funktionsaufruf.

Kein Schrittmotor macht Dir mit solchen Geschwindigkeiten mit.

Für meinen Geschmack macht der Stepper perfekt genau das, was ich möchte, er rüttelt sich frei:

Allerdings soll das das eigentlich nur dann tun, wenn er blockiert wird, aber daran arbeite ich aktuell noch in Gerade Fehleranzahl erzeugt richtiges Ergebnis? - Deutsch - Arduino Forum

Dennoch sind die Werte momentan aus der Luft gegriffen und können später sicher noch optimiert werden.

Die Freirüttelprozedur, die ihr da auf dem Video seht ist folgende:

void StepperShake() {
  StepperShakeCount ++;
  Serial.print("Shake: ");
  Serial.println(StepperShakeCount);
  stepper.setCurrentPosition(0);
  stepper.setMaxSpeed(100000);
  stepper.setAcceleration(100000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(150000);
  stepper.setAcceleration(150000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(250000);
  stepper.setAcceleration(250000);
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(350000);
  stepper.setAcceleration(350000);
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.setMaxSpeed(500000);
  stepper.setAcceleration(500000);
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(-100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
  stepper.moveTo(100);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
    yield();
  }
}

Du musst das ganze in einen endlichen Automaten packen. Dann ist freirütteln (muss natürlich blockierungsfrei sein) ein Betriebszustand und deine essentiellen Dinge laufen in der loop weiter.

Was GENAU bedeutet blockierungsfrei? Was darf nicht blockiert werden?

themanfrommoon:
Was GENAU bedeutet blockierungsfrei? Was darf nicht blockiert werden?

blockierungsfrei -> nichts wird blockiert.

Was genau könnte denn blockiert werden?

Wenn eine Loop läuft und von dort aus eine Prozedur aufgerufen wird und eine Weile braucht um fertig zu werden, ist das dann bereits eine Blockade?

Wenn ja, dann weiss ich überhaupt nicht mehr wie man programmieren könnte.

Also was GENAU darf nicht blockiert werden? Die Loop?

Und was genau ist eine Blockade? Wenn eine Prozedur 10ms dauert, wenn sie 100ms dauert oder wenn sie 1000ms dauert?

Oder erst wenn sie garnicht mehr zurück im die Loop läuft? Dann müsste aber ein Watchdog anspringen und das merken und neu booten wie beim ESP8266.

Wenn ich in einer Prozedur eine while Schleife habe blockiert die dann?

Und wenn ich in der while Schleife ein yield(); schreibe blockiert die dann nicht mehr?

Die normale Laufzeit ist damit nicht gemeint. Sondern Dinge die künstlich blockieren:

  • auf irgendein Ereignis warten
  • delay()
  • blockierende Funktionen der Arduino API aufrufen wie readBytes(), parseInt(), pulseIn() oder dergleichen. Auch manche Stepper Bibliotheken haben blockierende Funktion die nicht sofort zurückkehren

Und wenn ich in der while Schleife ein yield(); schreibe blockiert die dann nicht mehr?

yield() ist generell eher eine Notlösung statt eine vernünftige Programmiertechnik

Keine delays und kein while/for/loop mit einer Zeitbedingung, was ist daran so schwer zu verstehen?

Solltest du tatsächlich Berechnungen haben,
die länger als ein paar Millisekunden dauern,
könnte man überlegen die in Einzelschritte aufzubrechen.

Wenn loop länger als 50 ms dauert merkt man das bei Tasten.

Wenn du mit delays und blockierendem Kode arbeiten willst, brauchst du ein (mini) OS.
Ob das kooperative Multitasking mit yield auf einem ESP8266 dazu reicht halte ich für fraglich,
auf einem ESP32 kann man so programmieren.

Hallo,

mal abgesehen von der Realisierung des "Freirüttelns" rennst Du vermutlich einem Denkfehler hinterher. Ich gehe jetzt mal davon aus das kein absolut Weggeber vorhanden ist , da du ja distanceToGo nutzt um zu erkennen das die SollPosition erreicht ist. Spielen wir das mal gedanklich durch.

Du willst einen Stepper auf irgendeine belibige Position fahren, da macht nur Sinn wenn du vorher eine Refferenzfahrt gemacht hast und "genullt" hast. Dann kannst Du mit "fahre auf Position" auf eine gewünschte position fahren. Die Abfrage mit distanceToGo meldet 0 zurück wenn nichts mehr zu fahren ist. Damit ist normal alles ok, leider tut sie das aber auch wenn er blokiert hat, damit kannst du ein blokieren also nicht wirklich erkennen.

Also nehmen wir jetzt mal an er hat blokiert und du willst ihn "freirütteln" , in dem du den Motor abwechseln links/rechts und mit unterscheidlicher Speed laufen lassen willst. Eventuell läuft er aber ja die ersten 5 mal beim rütteln garnicht. Dann macht es auch keinen Sin Ihn schneller laufen lassen zu wollen, wobei theoretisch das Drehmoment real ehr kleiner wird mit höherer Geschwidigkeit.

Ok nehmen wir jetzt an irgendwann hätte er sich freigerüttelt, und fährt dabei irgendwann tatsächich los. Dann weisst du allerdings nicht wann und auf welcher Position das war. Damit weisst du aber auch nicht auf welcher Position er tatschlich steht, eigendlich muss man neu refferieren in so einem Fall.

Wenn ein Schrittmotor blokiert liegt ein mechanischer Fehler vor und der muss zunächst behoben werden und anschliessend neu refferieren.

Heinz

Hallo,

kleiner Einwand. :wink: Egal ob relativer oder absoluter Encoder. Solange man ohne Fehler die Encodersignale eingelesen bekommt, solange weiß man genau wo er steht. Man hat ja sicherlich einen Softwareabsolutzähler programmiert. Man muss nur unterscheiden was man bei Schrittverlusten macht. Im Normalfall hat man ein mechanisches Problem. Man geht in den Fehlermodus. Beim frei rütteln ignoriert man den Fehlermodus der Schrittverluste. An Hand der Encodersignale kennt man weiterhin die genaue Position. Ob das Sinn macht ohne "Homing" weiterzufahren hängt von der Anwendung ab.

Hmm, so richtig kann ich damit noch nichts anfangen.

-Ich warte auf kein Ereignis (also z.B. einen Tastendruck)
-Ich habe da kein delay() drin
-Ich habe kein readBytes(); parseInt() oder pulseIn() da drin
-Das runToNewPosition() von Accelstepper hab ich schon rausgeschmissen

Ob yield() jetzt eine Notlösung ist oder nicht weiss ich nicht, aber ich weiss das einiges (auch einige Biliotheken) auf dem ESP8266 nicht funktioniert wenn darin kein yield() benutzt wird.

Tasten habe ich (bisher?) nicht, daher merke ich das nicht.

Trotzdem kann ich jetzt nicht beurteilen, ob ich blockierend oder nicht blockierend programmiert habe.

Ich hatte es ja bereits in #3 erklärt was ich machen möchte, und im Video in #6 kann man es auch sehen was passieren soll.
Nach dem Freirüttln kann man auch sehen, das mit gringerer Geschwindigkeit wieder sauber zur nächsten Startstellung gefahren wird.

Momentan gehts eigentlich nur noch um das "Blockieren".

Also in #3 ist ja genau erklärt wie es momentan programmiert ist.
Ist das jetzt blockierend oder nicht?
Wenn ja, wie löst man das denn nicht blockierend?

Aktuell habe ich die Idee dies mit folgenden Schleifen zu machen. Sinngemäß (etwas mit TurboPascal von vor 25 Jahren gemischt, aber es geht ja nur um die Idee):
For i = 1 to 5
If i = 1 then stepperspeed = 100000
If i = 2 then stepperspeed = 200000
If i = 3 then stepperspeed = 300000
If i = 4 then stepperspeed = 400000
If i = 5 then stepperspeed = 500000
stepper.setMaxSpeed(stepperspeed);
stepper.setAcceleration(stepperspeed);
For x = 1 to 6
If x = 1 then steppertarget = -100
If x = 2 then steppertarget = 100
If x = 3 then steppertarget = -100
If x = 4 then steppertarget = 100
If x = 5 then steppertarget = -100
If x = 6 then steppertarget = 100
while (stepper.distanceToGo() != 0) {
stepper.run();
yield();
}
next x
next i

Wäre das jetzt blockierend?
Die Loop läuft natürlich nicht während dieser Prozedur.
Da yield() aber in der tiefsten Schleife sehr oft aufgerufen wird blockiert es doch nicht?!
Also laufen wird das sicher auf einem ESP8266 ohne dass der Watchdog anspringt.

Aber wie könnte das denn vernüftig programmiert werden?

Ich gehe jetzt mal davon aus das kein absolut Weggeber vorhanden ist

Doch, ich habe einen absoluten Positionssensor, von daher gibts da kein Problem.
Siehe Video, funktioniert bestens :slight_smile:

Hallo,

mal ernsthaft. Wieviele Jahre bist du schon dabei?
Dein Pseudocode mit for ist wohl eher ein switch case. Dein while ist blockierend. Solltest du doch wissen.
Bei for kommt es darauf an was es macht, ob es blockierend wirkt oder nicht.

yield() und ESP ... keine Ahnung.

steppertarget=100*(x&1)?1:-1;

Ob man hier unbedingt die Blockade raus bekommen muß - ohne das Freirütteln geht's eh nicht weiter und das Freirütteln hat halt diese 6 Einzelschritte.
Ok, man könnte WÄHREND des Freirütteln bereits bemerken, daß der Stepper dem Soll wieder folgt und so das Freirütteln abbrechen.
Da die Perlen zerdrückt werden können, wäre Das vll. gar keine so schlechte Idee - ob die Perle bei normaler Fahrt eingequetscht wird, oder beim Freirütteln mit Schmackes noch zwei/drei Mal eine auf's M*ul bekommt, wird Ihr wohl recht egal sein - zumindest hinterher.

MfG

mal ernsthaft. Wieviele Jahre bist du schon dabei?
Dein Pseudocode mit for ist wohl eher ein switch case. Dein while ist blockierend. Solltest du doch wissen.
Bei for kommt es darauf an was es macht, ob es blockierend wirkt oder nicht.

Ähm, nee, bei meiner for Schleife wird alles durchlaufen, das soll es ja auch. Bei Switch case wird doch nur ein case durchlaufen, was ja nicht das Ziel ist.

Wie sollte das ohne while funktionieren?
Der Stepper macht ohne die while Schleife nur einen Schritt und ist dann wieder draußen aus der Prozedur. Das soll er ja nicht, er soll ja pro schleife zu jedem Ziel laufen.

Endweder fehlt mir das Verständnis dafür wie man das richtig programmiert, oder euch fehlt das Verständnis dafür was überhaupt gemacht werden soll. Das ist mir bisher noch nicht klar.

teppertarget=100*(x&1)?1:-1;

Ob man hier unbedingt die Blockade raus bekommen muß - ohne das Freirütteln geht's eh nicht weiter und das Freirütteln hat halt diese 6 Einzelschritte.
Ok, man könnte WÄHREND des Freirütteln bereits bemerken, daß der Stepper dem Soll wieder folgt und so das Freirütteln abbrechen.
Da die Perlen zerdrückt werden können, wäre Das vll. gar keine so schlechte Idee - ob die Perle bei normaler Fahrt eingequetscht wird, oder beim Freirütteln mit Schmackes noch zwei/drei Mal eine auf's M*ul bekommt, wird Ihr wohl recht egal sein - zumindest hinterher.

Ja, genau das ist auch mein Verständnis davon. Man könnte ja wieder in die Schleife einen SOLL-IST Abgleich einbauen. Das wird dann aber nur noch mit relativen Positionen funktionieren, da in dem Moment die Absolute Position nicht mehr bekannt ist.

Das hast in loop() schon eine Schleife. Dadurch kann man andere Schleifen auflösen und pro loop() Durchlauf einen Schritt machen. Man muss dann mitzählen in welchen Schritt oder Zustand man ist. Dazwischen kann man dann noch andere Dinge tun.