07-18-2024 10:56 AM - edited 07-18-2024 11:07 AM
Hello all,
I am writing a program where I am using an event-driven state machine to handle a user interface for an external instrument, sending commands via serial corresponding to button presses.
Some processes that the instrument undertakes are quite long, and I want to be able to read back from the instrument when they finish. Reading back requires sending another command after the correct amount of time. Originally I implemented this as:
Write the "process" command > Wait x milliseconds whilst the process occurs > Write the "read values" command > Read the output
Where the sequence is triggered by a button press event.
The issue I am having is that for safety reasons the program also needs to be able to interrupt the process with another button press which will overwrite the original command, but because of the wait time the front panel is completely unresponsive until it finishes and reads back. I can't simply exit the loop or the VI because the instrument itself will continue with what it was doing unless specifically told to stop.
I have tried running another event structure in parallel (which I know is generally advised against) to no avail. I have also tried having a case strucutre within each event structure, connected to a boolean outside the event structure to control them all - this gives a broken wire from the boolean (?) which I don't understand.
Could I wrap the entire event machine in a case structure and have the "emergency stop" button press as the true case, having only the "stop" command inside, with the false case having the event-driven state machine inside? Would a change in the button interrupt the event case during execution, or would the front panel remain frozen? i.e., would a change in the case structure execute even if the code inside the event case was still continuing? Edit: I tried this, and it also does not work.
Any help would be greatly appreciated! Many thanks!
Solved! Go to Solution.
07-18-2024 11:18 AM - edited 07-18-2024 11:20 AM
Would be easier to advise if some code, but...
You have an event driven state machine, TAKE Advantage of it!!
Make the following states:
Any event that occurs before the timeout is complete will allow you to stop/change the process.
EDIT: Your states should not be in the Event Structure, look at the JKI State Machine for an example. Download it from VIPM
07-18-2024 11:33 AM
@smallen wrote:
Hello all,
I am writing a program where I am using an event-driven state machine to handle a user interface for an external instrument, sending commands via serial corresponding to button presses.
Some processes that the instrument undertakes are quite long, and I want to be able to read back from the instrument when they finish. Reading back requires sending another command after the correct amount of time. Originally I implemented this as:
Write the "process" command > Wait x milliseconds whilst the process occurs > Write the "read values" command > Read the output
Where the sequence is triggered by a button press event.
The issue I am having is that for safety reasons the program also needs to be able to interrupt the process with another button press which will overwrite the original command, but because of the wait time the front panel is completely unresponsive until it finishes and reads back. I can't simply exit the loop or the VI because the instrument itself will continue with what it was doing unless specifically told to stop.
I have tried running another event structure in parallel (which I know is generally advised against) to no avail. I have also tried having a case strucutre within each event structure, connected to a boolean outside the event structure to control them all - this gives a broken wire from the boolean (?) which I don't understand.
Could I wrap the entire event machine in a case structure and have the "emergency stop" button press as the true case, having only the "stop" command inside, with the false case having the event-driven state machine inside? Would a change in the button interrupt the event case during execution, or would the front panel remain frozen? i.e., would a change in the case structure execute even if the code inside the event case was still continuing? Edit: I tried this, and it also does not work.
Any help would be greatly appreciated! Many thanks!
If this is indeed a safety issue, I would rely on a physical e-stop button to physically shut the test station down!
07-18-2024 11:33 AM
Once an event case starts, it has to either finish or the entire VI hierarchy has to stop because its execution was interrupted (which is not recommended...). There's no way to just do a hard stop on one small bit of a VI.
As some of the other posters here like to say, "THINK DATAFLOW!". Execution order is entirely dependent on the rules of dataflow, which do not allow for hard stops of any kind without completing every single step remaining.
This isn't to say your task is impossible, it just means you need to write code inside the event structure that is more interruptible.
For instance, instead of this:
Replace it with this:
+ +
Using something like that still obeys the rules of dataflow but allows for an interrupt between each VI because of the way the loop is designed.
Similarly, with anything built-in that uses a timeout, you can manage it by lowering the timeout and managing it yourself:
07-18-2024 12:16 PM
@smallen wrote:
Hello all,
I am writing a program where I am using an event-driven state machine to handle a user interface for an external instrument, sending commands via serial corresponding to button presses.
Some processes that the instrument undertakes are quite long, and I want to be able to read back from the instrument when they finish. Reading back requires sending another command after the correct amount of time. Originally I implemented this as:
Write the "process" command > Wait x milliseconds whilst the process occurs > Write the "read values" command > Read the output
Where the sequence is triggered by a button press event.
The issue I am having is that for safety reasons the program also needs to be able to interrupt the process with another button press which will overwrite the original command, but because of the wait time the front panel is completely unresponsive until it finishes and reads back. I can't simply exit the loop or the VI because the instrument itself will continue with what it was doing unless specifically told to stop.
I have tried running another event structure in parallel (which I know is generally advised against) to no avail. I have also tried having a case strucutre within each event structure, connected to a boolean outside the event structure to control them all - this gives a broken wire from the boolean (?) which I don't understand.
Could I wrap the entire event machine in a case structure and have the "emergency stop" button press as the true case, having only the "stop" command inside, with the false case having the event-driven state machine inside? Would a change in the button interrupt the event case during execution, or would the front panel remain frozen? i.e., would a change in the case structure execute even if the code inside the event case was still continuing? Edit: I tried this, and it also does not work.
Any help would be greatly appreciated! Many thanks!
You know what? I once posted a response about revising a State Machine to help interrupt "Long Processes. " I suggested A trip to Grandma's House as a better method of structuring States.
07-19-2024 04:59 AM
Hi Bill,
We do have a physical interrupt button, don't worry! The cutoff in LabVIEW is just an extra feature that has been requested by members of the lab.
Sam
07-19-2024 05:04 AM
Hi there,
Just to check I am understanding you correctly - you mean send the command, set the timeout of the event structure to the calculated time the command takes to execute, have the read in the timeout case, then set the timeout back to -1?
This seems like it would work if I had only one read command and one command to send, but I have many such different commands and as far as I am aware I can only have one timeout case!
i.e., I need to be able to send "change x", wait, "read x", "change y, wait, "read y", etc where the wait times for x, y are different!
Forgive me, but I don't really understand how you have shown that being implemented in the pictures you provided. What is selecting between the two cases in the case structure?
Thank you,
Sam
07-19-2024 05:12 AM
Hi there,
Am I right in thinking that the case structures are being selected for by the processes/subVIs 1 and 2 completing? So the case is being determined by the iteration of the loop?
Also, will this not still freeze up the VI if the "2" box is just a wait? I think your suggestion will allow me to interrupt the write and read which are over serial and practically instantaneous compared to the exection time of the process on the instrument (which is variable depending on the command and could be any value from 20 ms to several minutes)
Thank you for your help, but I think if the wait is "2" in your example, I am looking for how I can interrupt "2" itself rather than between the three processes.
Please correct me if I am misunderstanding you!
Thanks,
Sam
07-19-2024 05:25 AM
Hi there,
Reading your analogy I think I understand better, but I am still unsure how I would implement this.
I had a thought reading your post however. The instrument in question has been built in-house, and is based on an arduino microcontroller. Would a better way to handle the wait to be to program the arduino to send the data itself when it is finished (very easy to do, just adding a serial.print() at the end of the function) rather than requesting it by writing a command?
I could then just have a timeout state where I just repeatedly read until I get the data back. This way the VI could still respond to new events but would also automatically read the values back when the process ends?
i.e., button press triggers event case > case writes the command > VI returns to timeout > timeout reads for output constantly (so will catch the values when the command has finished executing on the instrument)
Does that make sense or is that more complicated than the other suggestions that have been made?
Thanks,
Sam
07-19-2024 08:35 AM
@smallen wrote:
Hi there,
Just to check I am understanding you correctly - you mean send the command, set the timeout of the event structure to the calculated time the command takes to execute, have the read in the timeout case, then set the timeout back to -1?
This seems like it would work if I had only one read command and one command to send, but I have many such different commands and as far as I am aware I can only have one timeout case!
You need multiple states:
The states would proceed like so, Write -> Set Timeout -> Timeout State -> Read State.
The Read does not occur in the timeout state, it is its own separate state.
If you need to interrupt a current state because a button is pressed, you will need to implement a parallel loop. One loop to monitor, one loop to process. You will have to send a message (queue, channel, user event) to the state that you want to stop.
How are you monitoring the "Stop Button"? If it is a hardware switch and you have a DIO module, a DAQmx change detection event could work. That could be embedded in the loop.