LabVIEWForum.de - Zeitgesteuert eine Queue triggern?

LabVIEWForum.de

Normale Version: Zeitgesteuert eine Queue triggern?
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Guten Abend, LVF.

Wir haben festgestellt, dass unser Geraet besser arbeitet, wenn ich es ueber eine Producer-Consumer-Schleife steuere. Interessanterweise kann der Motor ohne Probleme seine Richtung schnell aendern, wenn der User abwechselnd "Infuse" and "Withdraw" drueckt. Als ich das gesamte Programm noch in einem Continuous-Loop hatte, ging dies leider nicht sehr gut . Fuer eine wissenschaftliche Anwendung muss dies aber realisiert werden.
Deswegen habe ich jetzt den Auftrag bekommen, ein Programm zu schreiben, dass praktisch das manuelle Druecken der Buttons "Infuse" and "Withdraw" fuer den User uebernimmt. Das ganze soll natuerlich zeitgesteuert sein.
Ich habe zunaechst versucht ein Beispielprogramm zu basteln. Unter anderem habe ich nun noch das Problem, dass ich nicht weiss, wie ich im Eventcase "Trigger-User Event" dafuer sorge, dass der richtige Enum-Wert ausgeloest wird. Je nach Wert der Case-Struktur ganz links, die durch eine Bedingung der While-Schleife gesteuert wird, sollte entweder withdraw oder infuse als enum-Wert im Eventcase stehen. Spaeter soll die Case-Struktur via Timer ausgeloest werden. Koennte man dann vielleicht spaeter einen Timed Loop nutzen?

Falls das gesamte Programm so moeglich ist, wuerde ich versuchen, es als SubVi im Hautprogramm abzuspeichern. Geht das oder darf pro gesamten LabView-Programm nur eine einzige Eventstruktur verwendet werden?

Achtung: Leider ist das Programm im Moment in einer Endlosschleife gefangen, weil ich nicht weiss, wie ich das Enum richtig automatisch auswaehlen lasse im Eventcase.


[attachment=29987]
Lv09_img2

Gruss
blue

PS: Geht es eventuell auch einfacher zu realisieren?
' schrieb:Wir haben festgestellt, dass unser Geraet besser arbeitet, wenn ich es ueber eine Producer-Consumer-Schleife steuere.
Das liegt aber an sich nicht an der Producer-Consumer-Schleife - sondern daran, dass durch das Programmierkonzept "Producer-Consumer" eine Modularisierung entsteht. Diese Modularisierung ist der Grund, warum es besser geht. Ein Modul kann man übersichtlich(er) programmieren. Ein Modul alleine arbeitet wie in einer selbständigen Task. Da wird nur das abgearbeitet, was auch tatsächlich für das Modul (respektive in deinem Falle das Endgerät) notwendig ist. Ein Modul ist immer ein SubVI.
Ein solches Modul entspricht einer Klasse im OOP-Sinne.
Ein Modul sorgt intern dafür, dass das Endgerät optimal angesteuert wird. Das geht soweit, dass selbst eine Falschbedienung durch den Anwender ganz leicht ignorierbar ist.

Macht man alles in einer Schleife (in einem BD), kommen so viele Seiteneffekte zusammen - dass man sich irgendwann selbst nicht mehr auskennt.

Zitat:Interessanterweise kann der Motor ohne Probleme seine Richtung schnell aendern, wenn der User abwechselnd "Infuse" and "Withdraw" drueckt.
Das ist leicht erklärt: Bei anwendergesteuert vergeht zwischen den einzelnen Buttonklicks immer viel Zeit - das kommt dem Endgerät zugute. Außerdem entsteht bei diesem Verfahren nur minimaler Code. Du weist ja: Kein Code, kein Fehler. Wenig Code, wenig Fehler ...

Zitat:Falls das gesamte Programm so moeglich ist, wuerde ich versuchen, es als SubVi im Hautprogramm abzuspeichern.
Dieses Vorgehen ist richtig.
Bei mir gibt es immer ein Haupt-VI mit Benutzeroberfläche. Dieses Haupt-VI hat eine Event-Struktur in einer While-Schleife. Hier werden lediglich Events (also einmalige Ereignisse) abgearbeitet, wie z.B. Buttonclicks. Neben dieser While-Schleife kann eine zweite While-Schleife mit einer Statemachine stehen. Diese Statemachine kann genau den automatischen Ablauf enthalten, den du haben willst. Diese zweite While-Schleife befindet sich deswegen in diesem Haupt-VI, weil Anzeigeelemente beschrieben werden sollen. Diese Statemachine kommuniziert mit dem Modul über Queues und Melder. Wäre keine Anzeige notwendig, würde man diese Statemachine auch in ein SubVI (also ein eigenständiges Modul) auslagern oder gar in das Endgeräte-Modul integrieren.
Die Gerätesteuerung selbst (also das ganz oben erwähnte Modul) liegt mit Queue/Melder/Ereignis-Referenzen am Eingang auf dem BD des MainVI. Dieses Modul läuft im Hintergrund parallel zum Haupt-VI.

Ich hab mal ein kleines Muster angehängt. Die untere While-Schleife ist das Endgeräte-Modul und sollte in einem SubVI ausgelagert werden. Benutzerereignisse sind in dieser Ausbaustufe noch nicht erforderlich.

Zitat:Geht es eventuell auch einfacher zu realisieren?
Einfach an sich ist Sache des Standpunktes.
Was für mich "einfach" ist - modulare, also gekapselte, klassenorientierte SubVI-Programmierung mit Queues/Melder und FGVs - erscheint dem einen oder anderen doch recht verwirrend. "Einfach" ist ein Programm dann, wenn es gut auf einen Bildschirm passt. Unabhängig vom Algorithmus ist es wichtig, dass das Programm funktioniert, debugbar, wartungsfreundlich und nach Möglichkeit erweiterbar ist.
Was du als "einfach zu realisieren" suchst, ist der für deine Belange richtige Algorithmus und das richtige Programmierkonzept - und da bist du mit Modularisierung (also SubVI, SubVI, SubVI ...) und Queue/Melder-Steuerung schon mal auf dem richtigen Weg ...
Lv09_img2
' schrieb:Macht man alles in einer Schleife (in einem BD)

Wofuer steht bitte BD?

' schrieb:Dieses Vorgehen ist richtig.
Bei mir gibt es immer ein Haupt-VI mit Benutzeroberfläche. Dieses Haupt-VI hat eine Event-Struktur in einer While-Schleife. Hier werden lediglich Events (also einmalige Ereignisse) abgearbeitet, wie z.B. Buttonclicks. Neben dieser While-Schleife kann eine zweite While-Schleife mit einer Statemachine stehen. Diese Statemachine kann genau den automatischen Ablauf enthalten, den du haben willst. Diese zweite While-Schleife befindet sich deswegen in diesem Haupt-VI, weil Anzeigeelemente beschrieben werden sollen. Diese Statemachine kommuniziert mit dem Modul über Queues und Melder. Wäre keine Anzeige notwendig, würde man diese Statemachine auch in ein SubVI (also ein eigenständiges Modul) auslagern oder gar in das Endgeräte-Modul integrieren.
Die Gerätesteuerung selbst (also das ganz oben erwähnte Modul) liegt mit Queue/Melder/Ereignis-Referenzen am Eingang auf dem BD des MainVI. Dieses Modul läuft im Hintergrund parallel zum Haupt-VI.
Moment, das ist jetzt verwirrend. Das Haupt.vi besteht aus einem Producer-Consumer-Pattern. Im Producer sind bei Dir die Eventbuttons? Consumer-Schleife kann als Sub.Vi ausgelagert werden, wenn man moechte?
Was genau ist jetzt fuer dich ein Modul und was bedeutet bitte"liegt am Eingang auf dem BD des Main.vi"?
Generell ist mir nicht klar, wie ich die dauerhafte Ueberwachung meines Geraetes programmieren soll, ohne das Gerät für die Eventstruktur ("Buttonklicks" zu blockieren") Im Beispiel unten habe ich testweise eine weitere Schleife gebaut, in der ein wait sitzt. Es scheint zu klappen, aber ich weiss nicht, ob die Umsetzung richtig ist.

' schrieb:Ich hab mal ein kleines Muster angehängt. Die untere While-Schleife ist das Endgeräte-Modul und sollte in einem SubVI ausgelagert werden. Benutzerereignisse sind in dieser Ausbaustufe noch nicht erforderlich.
Der Consumer-Loop entspricht also in diesem Beispiel dem Endgeraet-Modul?

' schrieb:Was für mich "einfach" ist - modulare, also gekapselte, klassenorientierte SubVI-Programmierung mit Queues/Melder und FGVs - erscheint dem einen oder anderen doch recht verwirrend.
Haettest Du vielleicht ein Beispiel fuer ein FGVs, dass in einem "komplexeren" Programm eingebettet ist? Es heisst zwar immer, in FGVs kann man Daten speichern, nur weiss ich nicht, wie man an einem im Diagramm weiteren Ort, z.b. in einer anderen parallelen Schleife darauf zugreift.


Zu deinem Beispielprogramm einige Fragen:

1. Warum hast Du Dich fuer eine Sequenz entschieden?
2. Warum hast Du darauf verzichtet, ein Event dynamisch zu registrieren? Das war ja mein ursprünglicher Ansatz.
3. Warum sind in der zweiten while-Schleife im Producer-Loop waits eingebaut?


Ich habe dein Beispiel uebernommen und die Befehle fuer meine Pumpe eingebaut. Sie wechselt tatsaechlich automatisch die Richtung ohne merklich am Umkehrpunkt zu stoppen. Das ist wirklich ein guter Fortschritt.

Die naechste Herausforderung war nun, dem Geraet mitzuteilen, WANN die Richtungsumkehr erfolgen soll. Dafuer gibt es i.a. zwei Ansaetze:

1. Ueber die verstrichene Zeit. Das habe ich wieder ueber einen Timeout mit einer Eventstruktur realisiert. Das LabView-Style-Book empfiehlt ein solches Vorgehen jedoch nicht. Ich weiss nur nicht, wie man ansonsten die verstrichene Zeit in einer while-Schleife registrieren kann. Ich habe versucht, es mit der Tick Count.vi zu realsieren, aber das ging scheif.
Generell wechselt die Pumpe nach der angegebenen Zeit fuer den Timeout (10s) auch die Richtung, ohne am Umkehrpunkt lange zu stoppen. Ich nenne das mal glattes Umkehren. b] Problem hierbei[/b]: Sobald man der Pumpe den Befehl zu Umkehr schickt, kehrt sie auch sofort um. D.h., wenn die Pumpe 50ml injizieren soll und der Umkehrbefehl kommt nach 10s (Rate: 5ml/s), dann meldet das Pumpendisplay das z.b. erst 48.9ml als injiziertes Volumen. Ich habe den Verdacht, dass der Motor dann Schritte vergisst. Obwohl die Zeit eigentlich stimmt, braucht die Pumpe einen Tacken laenger als 10s. Diese Zeit kenne ich aber nicht.
Wie kann man eine Umkehr sicherstellen, die exakt nach 50ml injiziertem Volumen stattfindet, und der Umkehrprozess ohne Pause von statten geht?
(Beispiel 1 angehaengt. Ich bitte um Entschuldigung ob der beiden Eventstrukturen im selben vi. Dient nur der Veranschaulichung wegen.)
Ich habe das auch mit einem Timed Loop probiert (statt Timeout Eventstruktur). Es tritt das gleiche Problem auf. Die Pumpe wechselt "glatt" ihre RIchtung, aber das Volumen stimmt nicht. Pumpe zeigt z.b. 48ml oder dann mal nur 46ml an.
Lv09_img2
[attachment=29996]

2.Mein zweiter Versuch bestand darin, die Pumpe ständig nach ihrem Status in einer dritten, parallel laufenden Schleife zu fragen. Immer wenn sie meldet "Target reached", sollte dynamisch ein User-Event ausgelöst werden, das sich um die Richtungsänderung kümmert. Geklappt hat es. Jedoch wartet die Pumpe immer einen Moment (im Sekundenbereich), wenn "Target reached" gemeldet wird und bis das User-Event zur Richtungsumkehr ausgeloest wird. Damit stelle ich zwar sicher, dass die Umkehrung nach 50ml passiert, jedoch dauert der Umkehrprozess viel zu lange. Mein Betreuer moechte die Zeit, in der der Motor umkehrt, möglichst auf null reduzieren.
Dass das möglich ist, zeigt eine eingebaute Methode auf der Pumpe. Gefragtes Volumen wird injiziert und Richtungsumkehr erfolgt ohne merklichen Stop, also richtig glatt (im Prinzip wie eine Sinuskurve). Ich verstehe einfach nicht, wieso ich das nicht in LabView umsetzen kann.
Lv09_img2
[attachment=29995]

Danke schoen fuers Lesen.
Gruss
Blue
' schrieb:Wofuer steht bitte BD?
Blockdiagramm.

Zitat:Moment, das ist jetzt verwirrend. Das Haupt.vi besteht aus einem Producer-Consumer-Pattern.
Ein Pattern ist eine Vorlage - die man nicht unbedingt exakt so einhalten muss. Man kann "Producer-Consumer-Pattern" auch als Konzept sehen. Ein VI ist der Producer, ein anderes der Consumer. Producer und Consumer müssen nicht zwangsweise in einem VI liegen. Lediglich die Queue-Referenz (allgemein: Datenreferenz) haben sie gemeinsam.

Zitat:Im Producer sind bei Dir die Eventbuttons?
In dem VI, das den "Producer" enthält, befindet sich auch die GUI-Schnittstelle. Die GUI-Schnittstelle enthält die Buttons, deren Werte der "Producer" dem "Consumer" senden soll.

Zitat:Consumer-Schleife kann als Sub.Vi ausgelagert werden, wenn man moechte?
Ja natürlich.
Du muss das Gesamtprogramm betrachten. In welchem VI eine Operation ausgeführt wird, ist völlig egal. Zwei VIs (das, das den Producer enthält, und das, das den Consumer enthält) sind ja durch die Queue verbunden. Eine Queue ist eine imaginäre Verbindung zwischen Producer und Consumer. Die Queue-Verbindung zwischen den beiden ist nicht sichtbar - was im BD sichtbar ist, ist nur die Referenz. Da Producer und Consumer keine explizite Verbindung haben, kann man sie auch in unterschiedliche VIs legen. Eine explizite Verbindung wäre ein Draht zwischen beiden.

Zitat:Was genau ist jetzt fuer dich ein Modul
Ein Treiber z.B. ist ein Modul. Ein Modul ist eine Klasse, die das Endgerät komplett steuern kann. Eben je nach Vorgabe durch den Producer.

Zitat:und was bedeutet bitte"liegt am Eingang auf dem BD des Main.vi"?
Du weist ja noch: Producer und Consumer sind durch die Queue verbunden. Liegen beiden z.B. in unterschiedlichen SubVIs muss man den SubVIs die Queuereferenz mitteilen. Dies kann man machen, über einen Eingangsparameter am SubVI.

Zitat:Generell ist mir nicht klar, wie ich die dauerhafte Ueberwachung meines Geraetes programmieren soll, ohne das Gerät für die Eventstruktur ("Buttonklicks" zu blockieren") Im Beispiel unten habe ich testweise eine weitere Schleife gebaut, in der ein wait sitzt. Es scheint zu klappen, aber ich weiss nicht, ob die Umsetzung richtig ist.
Kuck ich mir später an.

Zitat:Der Consumer-Loop entspricht also in diesem Beispiel dem Endgeraet-Modul?
Genau.

Zitat:Haettest Du vielleicht ein Beispiel fuer ein FGVs, dass in einem "komplexeren" Programm eingebettet ist? Es heisst zwar immer, in FGVs kann man Daten speichern, nur weiss ich nicht, wie man an einem im Diagramm weiteren Ort, z.b. in einer anderen parallelen Schleife darauf zugreift.
Für ein Beispielprogramm muss ich mal kucken. Zum darauf zugreifen: Einfach das FGV-SubVI auf das BD setzen und aufrufen ...

Zitat:1. Warum hast Du Dich fuer eine Sequenz entschieden?
Müsste ich jetzt erst kucken. Eine Sequenz (Statemachine?) ist das, was das Modul mit dem Endgerät macht: Nämlich "der Reihe nach" diverse Operationen ausführen: Überwachen dies; Überwachen da; Kucken, ob der Producer was geschickt hat und entsprechens ausführen.

[_quote]2. Warum hast Du darauf verzichtet, ein Event dynamisch zu registrieren? Das war ja mein ursprünglicher Ansatz.[_/quote]Warum soll ich ein dynamisches Event verwenden, wenn es auch ohne und einfacher geht.

[_quote]3. Warum sind in der zweiten while-Schleife im Producer-Loop waits eingebaut?[_/quote]Damit diese While-Schleife nicht unendlich schnell läuft. While-Schleifen dürfen nicht unendlich schnell laufen, sonst blockieren sie die CPU.

[_quote_]Die naechste Herausforderung war nun, dem Geraet mitzuteilen, WANN die Richtungsumkehr erfolgen soll.[_/quote_]Das kuck ich mir später mal an.

Ich muss mal was arbeiten - und mal endlich einen Kaffee holen. Außerdem ist die ANnahl der Quotes schon wieder überschritten.
Hattte mir auch vor ein paar Tagen dein erstes VI angeschaut und das etwas verändert und und mit Kommentaren versehen. Ich poste es mal, selbt auf die Gefahr hin, daß jetzt alles nicht mehr aktuell ist.
Lv86_img[attachment=30010]
Deine VIs hab ich noch nicht ankucken können.

' schrieb:2. Warum hast Du darauf verzichtet, ein Event dynamisch zu registrieren?
Aber hierzu hab ich noch einen Hinweis.
Die Steuerung deines Endgerätes läuft ja in einem Modul als SubVI ab. Das Modul selbst wird durch eine Queue gesteuert. Es ist also nicht notwendig, das Modul zusätzlich durch ein Benutzerereignis steuern zu steuern. Wenn du zusätzlich ein Benutzerereignis verwendest, hast du zwei Kanäle, über die du das Modul steuerst. Das aber - Steuern über zwei Kanäle - ist steuerungstechnisch ungünstig. Ein Kanal, nämlich der mit der Queue, ist zum Steuern ausreichend. Was über das Benutzerereignis in das Modul kommen soll, kann man genau so gut auch über die Queue senden.
' schrieb:1. Ueber die verstrichene Zeit.
Zwei Event-Strukturen in einem SubVI soll man nicht machen. Mehrere Event-Strukturen kann man immer in eine zusammen legen. Notfalls muss man halt die im Timeout-Case erforderlichen Daten (Drähte) durch alle anderen Cases durchziehen.

Guckst du Beispiel.

Zitat:Mein zweiter Versuch bestand darin, die Pumpe ständig nach ihrem Status in einer dritten, parallel laufenden Schleife zu fragen.
Eigentlich bin ich ja auch der Meinung, dass es so gemacht gehört (nach Status fragen und reagieren). Problem ist aber, dass die RS232-Schnittstelle an sich langsam ist und schon mal betriebssystembedingt Pausen (allerdings nur im 200ms Bereich) auftreten können.
Ich glaube du hast dich beim Erstellen von Beispiel_2 vertan. Beispiel_2 ist mit Beispiel_1 identisch ??

Zitat:Jedoch wartet die Pumpe immer einen Moment (im Sekundenbereich), wenn "Target reached" gemeldet wird und bis das User-Event zur Richtungsumkehr ausgeloest wird.
Naja, theoretisch kann diese große Zeitverzögerung bei ungünstiger Programmierung schon auftreten.

Zitat:Dass das möglich ist, zeigt eine eingebaute Methode auf der Pumpe. Gefragtes Volumen wird injiziert und Richtungsumkehr erfolgt ohne merklichen Stop, also richtig glatt (im Prinzip wie eine Sinuskurve). Ich verstehe einfach nicht, wieso ich das nicht in LabView umsetzen kann.
Die Pumpe hat ja eine eingebaute Steuerung. Die ist selbstverständlich zeit-unverzögert.
Alle anderen, also externen Steuerungen sind da im Nachteil. Und wenn du erst noch einen Status über RS232 lesen musst ...
Guten Abend. Vielen Dank fuer Eure Antworten! Ich habe sie mir kurz angeschaut, aber morgen ausfuerlicher, da ich heute noch Paper lesen muss. Aber wirklich vielen Dank, dass ihr Euch die Zeit genommen habt, sie Euch anzuschauen.
Bis morgen, viele Gruesse
blue
Referenz-URLs