LabVIEWForum.de - Ist das so okay realisiert?

LabVIEWForum.de

Normale Version: Ist das so okay realisiert?
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Seiten: 1 2
Ich habe hier zwei Programmversionen programmiert und frage mich nun, ob das bei Main_v2.vi so richtig ist, also guter Stil? Es funktioniert zwar, aber ich bin mir nicht sicher, weil ich eher rumgespielt und getestet habe.

Worum geht es?

1. Main_Prog_v1.vi:
Im consumer loop wird einmal abgefragt, ob es ein Targetvolumen geben soll (Set Target) und dann werden die Target properties mitgeteilt. Das passiert innerhalb des grünen error-cases.
Nachteil dieser Version: Ändert der User etwas, wird dies erst beim nächsten Aufruf von "infuse" sichtbar. Die Pumpe zeigt auf dem Display erstmal keine Veränderung sofort an.

2. Main Prog_v2.vi:
Ich habe einen Eventcase oben im Producer-Loop eingefuegt, der Value changed "Target properties" und "Set target" hat. (Nebenfrage:Mir kommt es so vor, als dass dieses Event ausgeführt wird, wenn es entweder eine Veränderung im Target properties gab ODER im Set target. Stimmt das oder ist die logische Verknüpfung von zwei Parametern im Event case eine andere?)
Stimmt das so mit der Programmierung, also keine komischen Fehler oder race conditions mit diesem Event case?
Wie zuvor gibt es Set target und Target properties im Consumer Loop. Mit dem Eventcase zeigt die Pumpe auf dem Display aber sofortige Änderungen vom User an. Das gab es in Fall 1 nicht.

Die Idee war einfach:
Wenn set target =off gewählt worden ist und der User an den Target properties rumwurschtelt, z.b. das Volumen erhöht, soll nichts passieren, das Display soll immer noch zeigen, no target selected.
Wenn set target=on und der User an den Target properties rumwurschtelt, sollen diese aktualisiert werden im Pumpendisplay.

Ich dachte eventuell, das mit zwei Event cases umzusetzen, die sich gegenseitig triggern, aber das hat mir einen Knoten im Gehirn verpasst. Deswegen wollte ich einmal um Rat fragen.

Danke schoen.
Gruesse
blue

Lv09_img2
[attachment=29862]
Hallo Blue,

sieht doch schon ganz ordentlich aus...Smile

Du kannst mehrere Events in einem Eventcase abarbeiten lassen. Die Events werden dann ODER-verknüpft, jedes einzelne der Events löst diesen Eventcase aus.

Noch ein Tipp:
Ich würde noch ein QUIT-Kommando ins Enum nehmen, um den Consumer kontrolliert (d.h. programmatisch) runterfahren zu können. Dann könnte man sich auch überlegen, ob man die Queue mit einem TimeOut ausliest und den Stop der Whileloop an den QUIT-Befehl koppelt... Nur so 'ne Idee.
' schrieb:Hallo Blue,

sieht doch schon ganz ordentlich aus...Smile
Danke schoen! Interessanterweise funktioniert diese Art der Programierung viel besser als mein erster, murksiger Versuch, wo Producersachen+Consumersachen in einer gemeinsamen Schleife drin waren.

' schrieb:Du kannst mehrere Events in einem Eventcase abarbeiten lassen. Die Events werden dann ODER-verknüpft, jedes einzelne der Events löst diesen Eventcase aus.
Danke fuer die Erklaerung. Ich habe noch eine Frage zur Anzahl an Eventstrukturen. Wieviele sind pro .vi erlaubt? Soweit ich weiss, eine. Aber darf man dann noch in Sub.vis jeweils eine weitere Eventstruktur haben?
Hintergrund: Im Moment kann der User, wenn er will, ganz schnell die Buttons Infuse druecken und danach auch wieder Withdraw. Das "Button drucken" loest die Eventcases aus. Lustigerweise, kehrt die Pumpe die Richtung dann um, ohne kurz zu stoppen. Kann man sozusagen dieses Producer-Consumer-Pattern auch in eine Sub.vi packen und das die Events werden automatisch getriggert, z.b. alle 10s?

' schrieb:Noch ein Tipp:
Ich würde noch ein QUIT-Kommando ins Enum nehmen, um den Consumer kontrolliert (d.h. programmatisch) runterfahren zu können.
Was ist der Vorteil bitte? Bedeutet das Runterfahren des Cconsumers gleich einen Stopp des gesamten LabView-Programms oder stoppt as Geraet und wartet ggf. auf neue Befehle?
Ich hatte ueber sowas aehnliches am We schon ueberlegt. Ich dachte da an einen "globalen" Stop-Button, der das komplette LabView-Programm kontrolliert stop. Meinst du das vielleicht bitte?

' schrieb:Dann könnte man sich auch überlegen, ob man die Queue mit einem TimeOut ausliest und den Stop der Whileloop an den QUIT-Befehl koppelt... Nur so 'ne Idee.
Das verstehe ich absolut nicht. Was macht das? Danke fuer deine Vorschlaege!

Einen schoenen Abend.
Gruese
Blue
Guten Abend. Ich wuerde gerne mal wieder etwas fragen. Wub_anim
Ich moechte jetzt den Status des Geraetes ueberwachen und somit immer abfragen. Der Hersteller hat eine Status.vi mitgeliefert. Ich weiss aber nicht ganz genau, wo und wie ich sie einbinden soll.
Producer und Consumer-Loop werden scheinbar nur ausgefuehrt, wenn der User eine Aktion macht. Dann werden diese Zaehler hochgezaehlt. Das heisst aber wiederum, Status.vi wird nur dann ausgefuehrt, wenn der User etwas macht. Also irgendwie nicht so geeignet an diesen Stellen.

Ich habe versucht, Status.vi in einen extra-Loop einzubauen und mit dem lilanen Visa-Resource-Kabel zu verbinden. Spaeter auch noch mit dem gruenen Kabel.
Das klappt eigentlich gar nicht. Sei es nun, ob nur lila und gruen nach Status.vi verlaufen oder auch wieder herauskommen, der Datenfluss scheint da irgendwie haengen zu bleiben. Im ersteren Fall wird der Producer-Loop zwar ausgefuehrt, aber der Consumer-Loop macht nichts. Im letzteren Fall funktioniert nicht mal der Producer.

Status.vi fragt praktisch immer einen String der Pumpe ab und muesste wohl daher irgendwie parallel laufen.

2.Frage: In Status.vi bekomme ich immer einen Error aus dem Visa-Read. Fehlermeldung:
Error -1073807339 occurred at VISA Read in Harvard Apparatus PHD Ultra Series.lvlib:Status Query.vi->Main_program_v2.vi
Possible reason(s):
VISA: (Hex 0xBFFF0015) Timeout expired before operation completed.

Ich weiss nicht wieso. Danke schoen fuer einen Hinweis.


Gruesse blue
Lv09_img2
[attachment=29883]
[attachment=29881]
[attachment=29882]
So, mal ein paar kleine Kritikpunkte:

1. Da du in deiner Producer als auch Consumer-Loop auf "Events" wartest, kannst du dir das zusätzliche Wait sparen.
2. Wieso programmierst du bei den Buttons umständlich das "Latch" Verhalten nach? Stell die entsprechenden Buttons auf "Latch when released", und du kannst dir eine ganze Reihe lokaler Variablen sparen.

Jetzt noch zu deiner Frage:
Wenn du deine Consumer-Loop entsprechend programmierst, kannst du da auch zyklisch Code ausführen, auch ohne User-Interaktion.
Hier eine erste Anregung, einfach beim Dequeue einen Time-Out anschließen. Wenn jetzt nach der vorgegeben Zeit nichts in der Queue steht, dann wird der Time-Out-Case ausgeführt:
[attachment=29884]

Gruß, Jens
' schrieb:So, mal ein paar kleine Kritikpunkte:

1. Da du in deiner Producer als auch Consumer-Loop auf "Events" wartest, kannst du dir das zusätzliche Wait sparen.
Meinst du zufällig den Timeout-Case oder bitte welches Wait?

Zitat:2. Wieso programmierst du bei den Buttons umständlich das "Latch" Verhalten nach? Stell die entsprechenden Buttons auf "Latch when released", und du kannst dir eine ganze Reihe lokaler Variablen sparen.
Gerd hatte mir diesen Hinweis schon gegeben, aber ich habe es nicht hinbekommen. Er sagte, man muss die Buttos auf Default false setzen. Wie das geht, habe ich leider nicht herausgefunden. Ich kenne nur "Make current values default", aber das kann ja nicht der Sinn sein. Tut mir leid. Sieht der User mit "Latch when released" noch die Bewegung des Buttons? Ich muss das morgen früh in der Uni testen.

Zitat:Jetzt noch zu deiner Frage:
Wenn du deine Consumer-Loop entsprechend programmierst, kannst du da auch zyklisch Code ausführen, auch ohne User-Interaktion.
Hier eine erste Anregung, einfach beim Dequeue einen Time-Out anschließen. Wenn jetzt nach der vorgegeben Zeit nichts in der Queue steht, dann wird der Time-Out-Case ausgeführt:
[attachment=58841:Image01.png]
Danke schön, dazu muss ich mir noch weitere Beispiele suchen. Ziel ist jedoch, ständig den Pumpenzustand zu beobachten. Also ihn nicht nur dann auszulesen, wenn nichts anderes gerade in der Queue steht, sonder eigentlich immer. In der Anwendung steht das Gerät nicht sichtbar vor mir. Daher dieser Wunsch. Ich suche mich morgen durchs Forum und teste deinen Vorschlag, Jens.
Vielen Dank.
Gruß
Blue
' schrieb:Meinst du zufällig den Timeout-Case oder bitte welches Wait?
Ich meine die beiden Wait-VIs, bei denen du dazugeschrieben hast: "Reduce processor load"
' schrieb:Gerd hatte mir diesen Hinweis schon gegeben, aber ich habe es nicht hinbekommen. Er sagte, man muss die Buttos auf Default false setzen. Wie das geht, habe ich leider nicht herausgefunden. Ich kenne nur "Make current values default", aber das kann ja nicht der Sinn sein. Tut mir leid. Sieht der User mit "Latch when released" noch die Bewegung des Buttons? Ich muss das morgen früh in der Uni testen.
Ja, sieht er, wenn du "Latch when released" nimmst. Das Schaltverhalten und damit das Event wird erst beim Loslassen ausgelöst. Dann sparst du dir die lokalen Variablen in der Event-Struktur und in deiner Initialisierung.
' schrieb:Danke schön, dazu muss ich mir noch weitere Beispiele suchen. Ziel ist jedoch, ständig den Pumpenzustand zu beobachten. Also ihn nicht nur dann auszulesen, wenn nichts anderes gerade in der Queue steht, sonder eigentlich immer. In der Anwendung steht das Gerät nicht sichtbar vor mir. Daher dieser Wunsch. Ich suche mich morgen durchs Forum und teste deinen Vorschlag, Jens.
Dann setze das Timeout am Dequeue kleiner.
Ich würde das nicht parallel setzen. Da ist ein Serial-Read drin, und wenn das Status-VI parallel läuft, schnappt es dir die Antworten auf sonstige Befehle, die du sendest, weg. Es kann immer nur einer aus dem Buffer lesen.
Im Block-Diagramm des Status-VI steht außerdem:
"Reads from the instrument for respond messages after a command has been executed."
Das verstehe ich so: Das kann man nach jedem Befehl-Antwort-Zyklus einbauen.

Gruß, Jens
Hallo Jens.

' schrieb:Ja, sieht er, wenn du "Latch when released" nimmst. Das Schaltverhalten und damit das Event wird erst beim Loslassen ausgelöst. Dann sparst du dir die lokalen Variablen in der Event-Struktur und in deiner Initialisierung.
Ich habe eben die lokalen Variabeln entfernt und auf Latch when releasd umgeschaltet. Mit "Make Current Values Default" habe ich die Schalter auf den gleichen logischen Wert gesetzt. Ob das nun true oder false ist kann ich nicht erkennen. Die Event cases reagieren ja nur auf ein "value changed". Mir ist das jedoch etwas unsicher. Was ist wenn der gelangweilte User mal zufaellig mit "Make Current Values Default" rumspielt und es verkehrt einstellt?

' schrieb:Dann setze das Timeout am Dequeue kleiner.
Ich würde das nicht parallel setzen. Da ist ein Serial-Read drin, und wenn das Status-VI parallel läuft, schnappt es dir die Antworten auf sonstige Befehle, die du sendest, weg. Es kann immer nur einer aus dem Buffer lesen.
Im Block-Diagramm des Status-VI steht außerdem:
"Reads from the instrument for respond messages after a command has been executed."
Das verstehe ich so: Das kann man nach jedem Befehl-Antwort-Zyklus einbauen.
Gruß, Jens

Die Status.vi ist dafuer gedacht den Status waehrend der Motorbewegung der Pumpe zu ueberwachen. Theoretisch koennte die Pumpe ja lange in eine Richtung fahren und dann ploetzlich ins Limit kommen. Das macht sie ja nicht auf Befehl. Oder sie laeuft schon, bevor man das vi gestartet hat und man will den Status wissen. So muss der Status halt immer oder alle paar Sekunden z.B. ausgelesen werden bzw. abgefragt werden. Deswegen verstehe ich den von dir zitieren Satz auch nicht, d.h. mir ist nicht klar, warum der Hersteller das so rein schreibt. Der Hersteller hat in einem Beispiel-Programm die Status.vi auch in eine Schleife gepackt, die z.B. bei jeder 10. Iteration einer anderen Schleife ausgeführt wird. Ich hänge das einmal mit an. Das Programm heisst Push Button.vi im Ordner. Da wird z.b. der Pumpenstatus auch ausgelesen, wenn die Pumpe nichts macht und nicht erst auf User-Aktion hin. (Das soll nicht unfreundlich Dir gegenueber klingen, ich steht gerade nur mit den Beispiel.vis vom Hersteller auf Kriegsfuss. Auf dieser Push-Button.vi habe ich mein erstes Programm gebaut und na ja, es funktionierte nur maessig, denn dann kam der Vorschlag Producer und Consumer Pattern anzuwenden.)

Timeout am Dequeuer habe ich nach deinem Beispiel eingebaut. Das erforderte dann wohl einen Extra-Case true/false. Funktioniert soweit auch okay. Jedoch wird nach 1000ms auch noch aus der Queue der Befehl "Infuse" ausgelöst und die Pumpe bewegt sich, obwohl sie das nicht soll. Mein Vorgehen war wohl doch nicht ganz richtig dabei. Wie verhindert man bitte, dass aus der Queue noch ein "Befehl" raus kommt und die Pumpe nicht in Gang setzt? (Main Prog 3.vi, bitte Schalter ignorieren, das ist in eine anderen Version)

Lv09_img2

Gruss,
Blue
[attachment=29908]
[attachment=29909]
' schrieb:Hallo Jens.
Ich habe eben die lokalen Variabeln entfernt und auf Latch when releasd umgeschaltet. Mit "Make Current Values Default" habe ich die Schalter auf den gleichen logischen Wert gesetzt. Ob das nun true oder false ist kann ich nicht erkennen.
False ist der "hellere" Zustand, True der mit mehr "Schatten".
' schrieb:Die Event cases reagieren ja nur auf ein "value changed". Mir ist das jedoch etwas unsicher. Was ist wenn der gelangweilte User mal zufaellig mit "Make Current Values Default" rumspielt und es verkehrt einstellt?
Dieser Fall ist für mich rein theoretischer Natur. Irgendwann wird aus einem VI eine Exe, da gibt es kein "Make Current Values Default" mehr.
' schrieb:Timeout am Dequeuer habe ich nach deinem Beispiel eingebaut. Das erforderte dann wohl einen Extra-Case true/false. Funktioniert soweit auch okay. Jedoch wird nach 1000ms auch noch aus der Queue der Befehl "Infuse" ausgelöst und die Pumpe bewegt sich, obwohl sie das nicht soll. Mein Vorgehen war wohl doch nicht ganz richtig dabei. Wie verhindert man bitte, dass aus der Queue noch ein "Befehl" raus kommt und die Pumpe nicht in Gang setzt? (Main Prog 3.vi, bitte Schalter ignorieren, das ist in eine anderen Version)
Falsch umgesetzt, in den Time-Out-Case kommt NUR die Status-Abfrage, also so:
[attachment=29915]
[attachment=29916]
Gruß, Jens
Zwei kleine Anmerkungen:

1. Wenn du Producer/Consumer mit Events einsetzt, ist es zu 95% der Fälle sauberer nicht nur das Kommando runter zu schicken und dann asynchron die Controls auszulesen, sondern direkt im Eventcase alle zum Kommando gehörenden Daten zu sammeln und als Message (Kommando + Daten (z.b. Variant)) zu senden... sonst drohen race conditions.

2. Schon bei beim "normalen" Entwickeln den Queuetimeout zu (miss-)brauchen, um zyklische Sachen zu realisieren ist nicht gut. Wenn du dich dann wirklich drauf verlassen willst, daß es halbwegs zyklisch gerufen wird, musst du ab dann immer daran denken, daß du diese Annahme/Vorgabe gilt. Solche Timeout-Spielchen haben ihre Berechtigung und das funktioniert auch meistens "irgendwie" oder kommen als Inbetriebnahme Workaround vor, aber schön sind die nicht.
Seiten: 1 2
Referenz-URLs