delay() vermeiden scheitert

Stimmt, hätte ich besser erklären sollen.

Real Life Beispiele:

Step-Mode:
Üblicherweise für Time Lapse Videos. Stepper steppt n Schritte, Kamera wird x-mal ausgelöst (x > 1 z.B. für HDR Video), Stepper steppt weiter....usw

Slide Mode
Variante 1: Üblicherweise für Video. Kamera wird 1x zum Fahrtbeginn aktiviert, und zum Ende wieder abgeschaltet
Variante 2: Time Lapse, wenn die Kamera selbstständig in Intervallen auslöst.

Dolly Zoom (auch "Vertigo" Effekt genannt)
Variante 1: Kamera fährt (meist von einem Offset) mit konstanter Geschwindigkeit auf ein Objekt zu, während ein Zoom-Controller (noch zu entwickeln) am Objektiv den Zoom reduziert. Das Motiv muss dabei immer gleich groß abgebildet werden.
Variante 2: wie vor, jedoch andersrum. Kamera fährt zurück, während Zoom vergrößert wird.

Macro Mode: Gedacht für Focus-Stacking (n Bilder mit unterschiedlichen Focus-Punkten werden zu einem zusammen gerechnet, welches dann durchgängig scharf ist). Immer ab einem großen Offset, Steppen im Millimeterbereich, Auslösen, Steppen im Millimeterbereich...usw.

Ich denke, dies wäre durch (mindestens) zwei unterschiedliche State Machines am besten abzubilden.

Danke für die Erklärungen.

Dies dürte ein typisches Projekt sein, wo am Ende ganz andere Lösungen stehen, als Du sie am Anfang erdacht hast. Daher würde ich mich langsam an die Materie herantasten und nicht zu viel Zeit in theoretische Überlegungen investieren, auch wenn es nicht ohne geht.

Wenn Du erstmal den Step-Mode im Griff hast, bist Du um einige Erfahrungen reicher.

Leider sind alle mir bekannten Themen in diesem Forum vorzeitig abgebrochen, so daß mir keine funktionierenden Lösungen in Erinnerung sind.

Hallo,

man kann alle State Machines einzeln entwickeln und diese dann je nach Menü-Auswahl aufzurufen. Dabei wird vieles doppelt und dreifach vorhanden sein. Eher unschön. Man kann auch Funktionen schreiben die von der State Machine aufgerufen werden und mittels weitere Parameter an die Funktionen mitteilen was diese machen sollen. Bevor du drauflos programmierst rate ich dir einen Ablaufplan zu erstellen. Diesen ausarbeiten und dann erst in Code umzusetzen.

Ergänzung zu agmue.
Zerlege das große Projekt in Teilaufgaben und probiere, mache und tue bis es funktioniert. Am Ende kopierst du nicht! alles wild zusammen, sondern ergänzt das eigentliche Projekt um diese neuen Dinge. Deswegen sind Funktionen so wichtig mit so vielen lokalen Variablen wie nur möglich. Das ganz grob zum A & O. Das dies alles nicht in 14 Tage fertig sollte dir bewusst sein denke ich.

  1. Ich nutze AccelStepper. Dieser benötigt ein "stepper.run();" im Loop. Gehört auch dieser in die State Machine, oder sollte man ihn außerhalb platzieren?

stepper.run(); ist Teil einer eigenen StateMachine
Also in loop().

Ich denke, dies wäre durch (mindestens) zwei unterschiedliche State Machines am besten abzubilden.

Ich stimme dir mal vorsichtig zu.

Ich denke, derzeit ist die State Machine zu fein granuliert. SETTLE bildet einen eigenen STATE nachdem der Stepper gelaufen ist. Den lasse ich auch separat, denn am physischen Ende des Sliders macht SETTLE keinen Sinn mehr. Das eigentliche Auslösen (1-n mal) inkl. jeweils LATENCY bildet einen weiteren, sinnvollen State, der für alle Betriebsarten passt. Eine Art State, der aus einer eigenen Mini State Machine besteht. Ich werde mal in diese Richtung weiter grübeln.

Und zum Projekt: Ich habe mich selbst mit 60 verrentnert, und bastle mir jetzt alles, was ich für mein weiteres Hobby (Foto/Video) immer vermisst habe. Dabei bin ich unendlich leidensfähig und ausdauernd. Den Slider baue ich nur zum "aufwärmen" - allerdings mit professionellem Anspruch. Endziel ist ein programmierbarer Kamera-Robot (auf dem Slider) mit 4 weiteren Achsen: Dreh- und Neigeachse plus motorischem Fokus und Zoom. Dazu wird der Uno nicht reichen, aber ein Mega liegt bereits in der Schublade. Bislang habe ich alles in meinem Leben auch zu Ende gebracht. Einziges Risiko eines vorzeitigen Projektabbruchs ist mein Primärhobby: Motorradfernreisen. Da kann jede Fahrt die letzte sein :slight_smile:

Begonnen mit dem Arduino habe ich vor 6 Wochen. Seit dem lerne ich C (OO/PHP, Python und diverse Web Sprachen beherrsche ich bereits - was beim Erlernen von C eher hinderlich scheint). Parallel habe ich mich in KiCad eingearbeitet, einen 3D Drucker bestellt (steht noch verpackt im Arbeitszimmer) und eine 3D CAD Software (FreeCAD) installiert, in die ich mich auch noch einarbeiten muss. Das schöne ist aber: Ich habe Zeit.

Seit dem lerne ich C

Arduino ist C++

OO/

C++ ist voll OOP!
Nahezu alle Arduino Libraries sind in OOP

Ja, ist bekannt. Was ich ausdrücken wollte, ist etwas anderes. Vieles, was in PHP normal und üblich ist, ist in C#/C++ ein großes no, no.

Demokrit:
Ich habe mich selbst mit 60 verrentnert, ...

Dann sieht die Sache schonmal ganz anders aus.

Wenn Dich OOP nicht schreckt, empfehle ich Dir unbedingt, den Vorschlägen von combie (#15) nachzugehen. Vergiß switch/case von mir und folge seinen Pfaden, es dürfte sich lohnen!

Ja, werde ich machen. Ich hatte schon im Hintergrund einen Test damit gemacht - und der Mehrbedarf an Speicher ist minimal. Morgen geht's weiter. Jetzt erst mal einen Glenfiddich am Kamin, und etwas die analoge Seele baumeln lassen.

Anstoßen werde ich auf Euch - ihr habt mich einen Riesenschritt weiter gebracht - Danke an alle Beteiligten

Kleine Denkanstöße für das Konzept:

  • Wie willst Du die Daten für die Bewegungsabläufe in den Arduino bringen? Bedienelemente am Arduino, SD-Karte, Funk?
  • Hast Du immer einen PC dabei oder wäre ein Display sinnvoll?
  • Selbst ein Mega dürfte bei der letzten Ausbaustufe nicht genügen. ESP32 und Teensy arbeiten aber mit 3,3V, das müßte man ggf. frühzeitig einplanen. Auch ist ein int beim UNO (16 Bit) was anderes als beim Teensy (32 Bit). Mit int16_t und dergleichen lassen sich Umstiegsprobleme verkleinern.

Old Pulteney (12 Jahre) Prost!

Der Slider soll autark und netzunabhängig arbeiten. Ich nutze ein 20x4 LCD zusammen mit der LCDMenuLib2 und einem Drehgeber. Dieser Teil steht bereits weitgehend, ich habe ihn nur aus diesem Thread heraus gelassen, um die Sache nicht zu komplizieren. Am aktuellen Menüsystem stört mich noch etwas der fehlende "dynamische" Aufbau. Wünschenswert wäre, wenn nach Wahl eines Betriebsmodus nur Felder angezeigt würden, die für diesen relevant sind. Auch die Sprachauswahl wird derzeit erst nach einem Rücksprung in eine tiefer liegende Menüebene berücksichtigt. Das sind aber Luxusprobleme.

Im realen Code nutze ich plattformunabhängige Variablendefinitionen, um einen späteren MC Wechsel zu vereinfachen. Den derzeit genutzten Uno habe ich bewußt gewählt, um von Anfang an speicherbewusst zu entwickeln.

Wenn später der Mega nicht passt, dann nehme ich was größeres. Die Dinger sind ja alle erfreulich günstig.

Ich habe noch etwas wichtiges vergessen. Der Sketch von combie hat anfangs Fehler geworfen ('TASK' does not name a type). Nach Ersatz von TASK durch void (wie in den Beispielen) lief es durch - und tat, was es soll. Ob das jetzt so richtig ist, kann ich (derzeit noch) nicht beurteilen.

Ja, bei der älteren Version ist das so!

Ein

typedef void Task; // Task Type
am Anfang der Lib schafft Abhilfe

Alles richtig gemacht!

Da habe ich nicht aufgepasst.
Danke, für den Hinweis!

Prima. Danke für die Rückmeldung. Ich habe die Lib aus dem verlinkten Thread genommen. Gibt es eine jüngere Version?

Ja, es gibt eine jüngere.

Der Kern ist identisch.
Und das Drumrum ist allerdings noch nicht fertig, verbuggt.
Ich habe dummer weise den Code mit der neuen getestet.

Nimm ruhig die ältere... das passt schon.
Die tut, wie in dem Thread beschrieben.
Ist schlank und stabil.

Wichtiger, ob alt oder neu, ist, dass du verstehst, was sie tut.
Sonst kann man sich damit super gut selber ein Beinchen stellen.

Ja, ich bemühe mich gerade um das Verständnis. Erste Umbauten haben schon mal auf Anhieb funktioniert (mehrere Auslösungen bevor der Fotoautomat wechselt, sowie Verschieben des 'carriageSettle' in den Motorteil, wo es eigentlich doch hingehört, denn auch nach dem letzten Schritt sollte noch ausgelöst werden.

Bislang bin ich ziemlich begeistert.

Hallo combie,

darf ich Dich noch mal was fragen? Ist folgendes Konstrukt zulässig:

Task goHomeT() {
 taskBegin();
 while (1)
 {
   taskWaitFor(goHome);

   lcd.setCursor (0, 2); lcd.print(F("    Going home      "));
   stepper.enableOutputs();
   if (homePos) {
     // Home on off-motor side
     stepper.setSpeed(-MAXSPEED);
     stepper.moveTo(limitBPos);
   } else {
     // Home on motor side
     stepper.setSpeed(-MAXSPEED);
     stepper.moveTo(0);
   }
   taskWaitFor(stepper.distanceToGo() == 0);
   Serial.println(F("At Home "));
   goHome = false;
   goneHome = true;
 }
 taskEnd();
}

Es geht speziell um die Frage, ob das zweite 'taskWaitFor(stepper.distanceToGo() == 0)' ok ist, oder ob ich mir damit doch wieder eine delay-ähnliche Blockade einbaue?

Der Hintergrund: Ich hatte bislang Homing, Limiting und goHome im Setup. Letzteres benötige ich aber mehrmals, und habe es deshalb in den Loop gezogen. Funktionieren tut es - aber ist es auch ohne unangenehme Nebenwirkungen?

aber ist es auch ohne unangenehme Nebenwirkungen?

Welche Nebenwirkungen hättest du denn gerne?
:o :o :o :o :o

Es geht speziell um die Frage, ob das zweite 'taskWaitFor(stepper.distanceToGo() == 0)' ok ist, oder ob ich mir damit doch wieder eine delay-ähnliche Blockade einbaue?

Ich wüsste jetzt nicht wie dir die Blockade gelingen sollte....
Dabei nehme ich mal an, dass stepper.distanceToGo() selber nicht wartet, sondern sofort wieder mit seinem Wert zurückkommt.

Ja, der Stepper antwortet direkt.

Demokrit:
Ja, der Stepper antwortet direkt.

Dann wird (bei dem Schritt) der Vergleich "stepper.distanceToGo() == 0" ebenso oft ausgeführt, wie der Automat aufgerufen wird, bis der Vergleich wahr wird.