Hallo,
ich benötige für eine Anwendung einen PLC/Ähnliche Programmabarbeitung.
Im Endeffekt will ich mit einer festen Zykluszeit alle Eingänge lesen,
dann Berechnungen durchführen und als letztes alle Ausgänge schreiben.
Input --> Calculate --> Output
Ihr ahnt es schon: Es geht um etwas zeitkritisches ;).
Bzw. eine Berechnung, die eine feste Zykluszeit erfordert.
Das Ganze soll auf einem ESP32 mit Arduino laufen.
Gibt es sowas schon? (Beispielprojekt?)
Oder gibt es irgendwo Infos wie man sowas am besten implementiert?
(Artikel, Blog usw.?)
Ein Umsetzung mit RTOS-Funktionen ist aus meiner Sicht nicht notwendig.
Die drei Abschnitte müssen ja komplett durchlaufen und dürfen nicht
unterbrochen werden. Es muss eher geprüft werden ob es zu einer
Zeitüberschreitung kommt.
Vielen Dank für konstruktive Antworten.
PLCler schrieb:> Ihr ahnt es schon: Es geht um etwas zeitkritisches ;)
Prinzipiell würde das schon gehen,
aber bei Arduino und loop() wäre ich vorsichtig, da der von Arduino
verwendete Timer deine loop() unterbricht.
Was ist bei dir zeitkritisch?
Die Verarbeitungszeit wird ja wohl fix sein.
PLCler schrieb:> Input --> Calculate --> Output>> Ihr ahnt es schon: Es geht um etwas zeitkritisches ;).
Du musst ja nur sicherstellen dass keiner dieser 3 Schritte länger
braucht als deine minimal zulässige Zykluszeit.
Dann lässt du diese Routinen über einen Timerinterrupt aufrufen um eine
gleichmäßige Zeitbasis zu haben.
Und du lässt die Finger von Arduino weil du da nie weißt was dir wie
reinquatschen kann.
um welche Zykluszeit geht es denn? Im Millisekundenbereich kann man doch
durchaus das FreeRTOS benutzen, das ist ja eingebaut.
Dann haben die meisten ESP32 2 Cores, wovon einer für die eigene App
frei ist. Damit sollte Wifi auch nicht stören, oder wird das
abgeschaltet?
Und auch Arduino stört nicht wenn die Task eine höhere Prio bekommt als
das main. Für das EVA sehe ich auch keine 3 Aufgaben, das kann ja eine
Sequenz sein die nicht aufgeteilt werden muss.
Danke für die Antworten.
Cyblord -. schrieb:> Du musst ja nur sicherstellen dass keiner dieser 3 Schritte länger> braucht als deine minimal zulässige Zykluszeit.> Dann lässt du diese Routinen über einen Timerinterrupt aufrufen um eine> gleichmäßige Zeitbasis zu haben.
Das ist tatsächlich eine Idee. Ich habe noch zu sehr im Kopf verankert
keine langen Programmabschnitte in ISRs zu legen.
Dann muss ich mir aber noch überlegen wie ich abfange, dass sich zwei
ISR-Aufrufe überschneiden weil die Berechnung zu lange dauert.
Das ist zwar nicht gewünscht aber zur Laufzeit möglich. Eine Warnung und
kein kompletter Absturz wäre wünschenswert.
J. S. schrieb:> um welche Zykluszeit geht es denn? Im Millisekundenbereich kann man doch> durchaus das FreeRTOS benutzen, das ist ja eingebaut.> Dann haben die meisten ESP32 2 Cores, wovon einer für die eigene App> frei ist. Damit sollte Wifi auch nicht stören, oder wird das> abgeschaltet?> Und auch Arduino stört nicht wenn die Task eine höhere Prio bekommt als> das main. Für das EVA sehe ich auch keine 3 Aufgaben, das kann ja eine> Sequenz sein die nicht aufgeteilt werden muss.
Bezüglich dem FreeRTOS habe ich immer die Bedenken, dass ein Task ja
unterbrochen werden kann. Das will ich ja nicht.
Kann man abfragen ob ein Task unterbrochen wurde? Dann wäre es ja
möglich eine Warnung auszugeben.
Bezüglich der Zykluszeit wäre kleiner gleich 20ms das Ziel. Das hängt
aber eher von der Kommunikation nach außen ab, also die "Ein- und
Ausgänge". Die Verarbeitung dazwischen ist bei 240Mhz eher unkritisch.
PLCler schrieb:> Ich habe noch zu sehr im Kopf verankert> keine langen Programmabschnitte in ISRs zu legen.
Das solltest du weiterhin so handhaben.
PLCler schrieb:> Bezüglich der Zykluszeit wäre kleiner gleich 20ms das Ziel
Das ist ja mehr als eine menge Zeit.
PLCler schrieb:> Bezüglich dem FreeRTOS habe ich immer die Bedenken, dass ein Task ja> unterbrochen werden kann. Das will ich ja nicht.
Wenn es nur eine Task auf dem Core gibt, dann wird auch nicht
unterbrochen, ausser von Interrupts. Und bei mehreren Task gibt es
Prioritäten, wichtiges bekommt eben eine hohe Prio.
Sollen keine Werte verloren gehen, schreibt man die in der IO Taksk mit
der hohen Prio in eine Queue. Die Verarbeitung läuft in einer anderen
Task und holt in einer while Schleife die Daten aus der Queue. Sind
keine Daten da, wartet diese Task und kostet keine Zeit. Das
funktioniert solange die Queue nicht überrant wird, aber da kann man
Fehler beim schreiben detektieren.
Und einen 240 MHz Xtensa Kern muss man erstmal überlastet bekommen.
PLCler schrieb:> Ich habe noch zu sehr im Kopf verankert> keine langen Programmabschnitte in ISRs zu legen.
und es gibt Funktionen die nicht in einer ISR ausgeführt werden möchten.
Da ist die Entkopplung durch Threads auch besser.
J. S. schrieb:> Wenn es nur eine Task auf dem Core gibt, dann wird auch nicht> unterbrochen, ausser von Interrupts. Und bei mehreren Task gibt es> Prioritäten, wichtiges bekommt eben eine hohe Prio.
Dann habe ich da etwas nicht ganz verstanden. Ich dachte immer dass beim
FreeRTOS mit Round-Robin mit 1ms Taktung die Tasks immer 1ms ausgeführt
und dann pausiert werden. Und wieder weiter ausgeführt werden sobald sie
wieder dran sind.
Ich Dachte dass dann sowas herauskommt:
(Task1_T1 entspricht Task1 Teil1)
1ms 1ms 1ms 1ms
Task1_T1 Task2_T1 Task1_T2 Task2_T2
ein Task im RTOS wird gestartet und läuft solange du willst. Nicht
zyklisch, das muss man selber implementieren. Wenn eine Aufgabe in 0,1
ms erledigt ist, dann kann man sich schlafen legen. Vorher rechnet man
den nächsten Aktivierungszeitpunkt aus und wartet dann bis man geweckt
wird.
PLCler schrieb:> ich benötige für eine Anwendung einen PLC/Ähnliche Programmabarbeitung.> Im Endeffekt will ich mit einer festen Zykluszeit alle Eingänge lesen
Genau das passiert bei einer "normalen" SPS nicht. Da wird die
"Mainloop" immer so schnell wie möglich durchlaufen und damit die
Zustandsautomaten (aka. Merkerketten) so schnell wie möglich bedient.
Nur "besondere" Eingänge werden per Interrupt abgeholt und bearbeitet
oder der Mainloop zur Verfügung gestellt.
PLCler schrieb:> Bezüglich dem FreeRTOS habe ich immer die Bedenken, dass ein Task ja> unterbrochen werden kann. Das will ich ja nicht.
Wieso nicht? Weil deine Programme so ausgelegt sind, dass immer ein
kompletter Block durchlaufen werden muss?
Diese ganze "getaktete" Denkweise kommt nur daher, dass sich Menschen
(und vor allem die programmierenden Menschen) mit "schnellstmöglich" so
unheimlich schwertun.
Adam P. schrieb:> PLCler schrieb:>> Bezüglich der Zykluszeit wäre kleiner gleich 20ms das Ziel> Das ist ja mehr als eine menge Zeit.
Du hast noch nie eine richtig ausgelastete SPS gesehen...
Adam P. schrieb:> Die Verarbeitungszeit wird ja wohl fix sein.
Nein, eben das ist niemals der Fall. Denn je nach Zustand der Automaten
muss ja etwas anderes getan werden. Und "andere Arbeit" dauert eben auch
unterschiedlich lange.
Adam P. schrieb:> PLCler schrieb:>> Ich habe noch zu sehr im Kopf verankert>> keine langen Programmabschnitte in ISRs zu legen.>> Das solltest du weiterhin so handhaben.
Immer Zielorientiert bleiben und nicht dogmatisch.
Wenn ein SPS-like Ablauf geplant ist, der sonst durch gar keine anderen
Interrupts unterbrochen werden kann, spricht nichts dagegen die
Hauptschleife in einem Timerinterrupt ablaufen zu lassen.
Hier will man ja gar nicht, dass evt. ein anderer Interrupt unterbricht
und man dann vielleicht die Zykluszeit reißt.
Ansonsten kann man auch einfach die Hauptschleife in der main ansiedeln
und per Timer Interrupt lediglich ein Flag umschalten wonach die
Hauptschleife dann einen weiteren Zyklus fährt.
Das letzte Beispiel auf
http://stefanfrings.de/multithreading_arduino/index.html#exakte zeigt,
wie man einen klassischen Zustandsautomaten in regelmäßigen festen
Intervallen ausführt.
Ich würde die Intervalle allerdings variabel halten, solange dazu kein
wichtiger Grund besteht. Die main Loop kann ja unabhängig davon einen
Check enthalten, ob ein Task (oder alle zusammen) seine erlaubte Zeit
überschritten hat und das dann irgendwie melden.
die Task Aktivierung muss man in FreeRTOS auch nicht mehr selber
berechnen, das macht vTaskDelayUntil()
https://www.freertos.org/vtaskdelayuntil.html
Wenn das ganze EVA dann in einem Task stattfindet, dann jittert die
Ausgabe nur um die Varianz der Berechnungszeit. Wenn die Berechnung
länger als die Zykluszeit dauert, dann würde der Task nach der Ausgabe
sofort wieder weiterlaufen, was man aber auch abfangen kann.
Lothar M. schrieb:> Adam P. schrieb:>> PLCler schrieb:>>> Bezüglich der Zykluszeit wäre kleiner gleich 20ms das Ziel>> Das ist ja mehr als eine menge Zeit.> Du hast noch nie eine richtig ausgelastete SPS gesehen...
Doch habe ich.
Lothar M. schrieb:> Adam P. schrieb:>> Die Verarbeitungszeit wird ja wohl fix sein.> Nein, eben das ist niemals der Fall. Denn je nach Zustand der Automaten> muss ja etwas anderes getan werden. Und "andere Arbeit" dauert eben auch> unterschiedlich lange.
Jedoch sprach er von ein paar Eingänge lesen.
Habe da nichts von SPS gelesen.
Und sein Vorhaben aus seinem User Namen zu schliessen, naja.
Also wenn es mehr als ein paar I/O sind, dann gebe ich dir natürlich
recht.
Lothar M. schrieb:> PLC ist das englische Wort für SPS.
Ja, aber er erwähnte "ähnlich" und "nur" ein paar I/O.
Schien mir jetzt nicht so Rechenintensiv, dass man es wie ein SPS OS
handhaben müsste.
Dazu kam noch "Arduino".
Wie dem aus sei ;)
Wenn es so ist, dann sollte man erstmal drüber nachdenken welche
Algorithmen man für Berechnung etc. laufen lassen möchte.
Dann worst case Szenario simulieren, dann hätte man zumindest ein
Anhaltspunkt für die Laufzeit.
Lothar M. schrieb:>> Und sein Vorhaben aus seinem User Namen zu schliessen, naja.> Überschrift? Achtes Wort im ersten Post?
ja ;) du hast mich.
war vorhin noch auf Arbeit im Code vertieft und irgendwie hab ich es
überlesen.