Go Down

Topic: delay() vermeiden scheitert (Read 2657 times) previous topic - next topic

combie

#15
Dec 12, 2018, 09:37 am Last Edit: Dec 12, 2018, 03:06 pm by combie
Quote
Das ist das Wichtigste bei der Sache.
Ja!

Dennoch behagt mir folgendes nicht:
> const unsigned int carriageSettle = 500;   
Die Zeit wird mit unsigned long verglichen.
Also Äpfel, mit Birnen.
Ja, es gelingt hier.
Solange die Zeiten unter 63 Sekunden sind.




Hier mal eine Variante, welche etwas Speicherhungeriger ist, aber im Grunde das gleiche tut:
Code: [Select]
#include <TaskMacro.h>
// Macros aus: https://forum.arduino.cc/index.php?topic=415229.msg2859554

const byte triggerPin = 10; // Camera trigger

//Interval/delay when/where this Timer expires
const unsigned long dummyStartInterval = 1000UL;    // 1000ms to simulate other code
const unsigned long carriageSettle     =  500UL;    // 500ms
const unsigned long triggerOpen        = 1000UL;    // trigger needs 2 ms in MF mode, 500 ms in AF
const unsigned long camLatency         =  500UL;
const unsigned long dummyEndInterval   = 1000UL;      // 1000ms to simulate other code

bool fotoMerker = false; // Uebergabe Merker, startet den Fotoautomaten, verhindert Motorlauf


Task fotoAutomat()
{
  taskBegin();
  while(1)
  {
    // Schritt warte auf Uebergabemerker belegt (Foto Anforderung)
    taskWaitFor(fotoMerker);
    Serial.println("Fotoautomat gestartet ");

    // Schritt warte carriageSettle
    taskPause(carriageSettle);
    Serial.println("carriageSettle abgelaufen ");

    // Schritt Trigger begin
    digitalWrite(triggerPin, HIGH);

    // Schritt warte triggerOpen
    taskPause(triggerOpen);
    Serial.println("triggerOpen abgelaufen ");

    // Schritt Trigger ende
    digitalWrite(triggerPin, LOW);

    // Schritt warte camLatency
    taskPause(camLatency);
    Serial.println("camLatency abgelaufen ");


    // Schritt Foto fertig, Ubergabemerker zuruecksetzen
    fotoMerker = false;
   
    // und wieder von vorn
  }
  taskEnd();
}

Task motorAutomat()
{
  taskBegin();
  while(1)
  {
    // Schritt warte auf Uebergabemerker frei (Fotoautomat fertig)
    taskWaitFor(not fotoMerker);
    Serial.println("Motor fährt ");

    // Schritt warte Motor fertig
    taskPause(dummyStartInterval+dummyEndInterval);
    Serial.println("Motor ist angekommen ");

    fotoMerker = true;
    Serial.println("Nachricht an Fotoautomat gesendet ");

    // und wieder von vorn
  }
  taskEnd();
}

Task blinkAutomat() // blinkt vor sich hin, um zu zeigen, dass alle Automaten Zeit bekommen
{
  taskBegin();
  while(1)
  {
    digitalWrite(LED_BUILTIN,HIGH);
    taskPause(500);
    digitalWrite(LED_BUILTIN,LOW);
    taskPause(500);
  }
  taskEnd();
}


void setup()
{
  Serial.begin(9600);
  Serial.println("Start");
  pinMode(LED_BUILTIN,OUTPUT);
  pinMode(triggerPin,OUTPUT);
}

void loop()
{
  fotoAutomat();
  motorAutomat();
  blinkAutomat();
}


Zusätzlich zum Fotoautomaten hat es noch:
1. einen Motorautomaten, welche eine Schlittenfahrt simuliert
2. und einen Blinkautomaten, welcher als Herzschlag fungiert, also zeigt, das der µC noch "lebt".



Die Synchronisation, die gegenseitige Verriegelung der Tasks, erfolgt über einen Merker
Säge kein Sägemehl.

Doc_Arduino

#16
Dec 12, 2018, 11:36 am Last Edit: Dec 12, 2018, 11:36 am by Doc_Arduino
Ja!

Dennoch behagt mir folgendes nicht:
> const unsigned int carriageSettle = 500;  
Die Zeit wird mit unsigned long verglichen.
Also Äpfel, mit Birnen.
Ja, es gelingt hier.
Solange die Zeiten unter 63 Sekunden sind.
Ich nehme immer den Datentyp wo mein größtmöglicher Wert reinpasst den ich verwende. Warum soll man für kleine Werte den größten Datentyp verwenden? Würde im Umkehrschluss bedeuten man müsste immer long bzw. unsigned long verwenden. Halte ich für nicht Zielführend.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

michael_x

Quote
man müsste immer long bzw. unsigned long verwenden.
Immerhin wird (millis()-prev > interval) in unsigned long berechnet.
Aber im Grunde hast du recht und kannst dich drauf verlassen, dass dein short interval richtig erweitert wird.

Demokrit

Auch das alternative Konzept wirkt sehr aufgeräumt und überzeugend - und bildet wohl ebenfalls eine State Machine. Ich, als C-Neuling, möchte den Ball jedoch anfangs flach halten. Speicherbedarf ist bei meiner Anwendung ein sehr kritischer Faktor. Die (mehrsprachige) Menüsteuerung (LCD/Rotary Encoder) nagt schon gewaltig daran.

Zum Konzept der State Machine habe ich noch zwei Fragen.

1) Ich plane mehrere Betriebsarten, deren Ablauf grundverschieden sein wird. (schrittweise, gleiten, Dolly Zoom Fahrt, Macro Mode). Sehe ich das richtig, dass man in diesem Fall unterschiedliche State Machines für die Betriebsarten definiert - oder ist es besser, nur eine State Machine zu definieren, die so abstrahiert ist, dass sie zu allen Modi passt?

2) 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?

agmue

#19
Dec 12, 2018, 12:24 pm Last Edit: Dec 12, 2018, 12:38 pm by agmue
Zu 1: Da ich nicht weiß, wie sich Dolly Zoom Fahrt von Macro Mode unterscheidet, kann ich Dir keine Empfehlung geben. Die Frage ist, was "grundverschieden" aus Programmierersicht bedeutet.

Ganz allgemein: Eine Schrittkette, ich denke an switch/case, kann zwischen den Schritten frei "springen". Also Schritt 7 kann nach 3 kommen. Man kann also auch grundverschiedene Dinge in eine Schrittkette packen. Bei vielen Überschneidungen, also doch gleichen Schritten, würde ich das in Erwägung ziehen. Sonst wird es aber so lang und unübersichtlich wie Spagetticode, was man sicherlich nicht möchte.

Ich würde mit einer sprechenden Festlegung der Namen in enum und einer Schrittkette anfangen. Aufteilen geht immer noch.

Zu 2: Außerhalb!

Leider eines der nicht ordentlich beendeten Themen, aber möglicherweise kannst Du dennoch was abschauen: Steuerung eines Kamerasliders
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Demokrit

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.

agmue

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.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Doc_Arduino

#22
Dec 12, 2018, 02:38 pm Last Edit: Dec 12, 2018, 02:48 pm by Doc_Arduino
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.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Quote
2) 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().


Quote
Ich denke, dies wäre durch (mindestens) zwei unterschiedliche State Machines am besten abzubilden.
Ich stimme dir mal vorsichtig zu.
Säge kein Sägemehl.

Demokrit

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 :-)

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.

combie

Quote
Seit dem lerne ich C
Arduino ist C++

Quote
OO/
C++ ist voll OOP!
Nahezu alle Arduino Libraries sind in OOP
Säge kein Sägemehl.

Demokrit

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.

agmue

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!
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Demokrit

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

agmue

#29
Dec 12, 2018, 09:10 pm Last Edit: Dec 12, 2018, 09:12 pm by agmue
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!
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Go Up