07-05-2016 10:17 PM
So I have built a test program and wanted to incorporate an ABORT button. I have the test in 9 steps, as a state machine (case inside a while loop, where each current test case directs to the next with an enum ref.). At the last step, the input power is turned off and instruments reset, then back to step one (where I wait for user to press "TEST" again to test the next unit). As a beginner, the only way I could think of was to create an event structure for an ABORT button in each single state. While I am aware that strange behaviour will arise from trying to execute multiple event structures at once based on a single event, I'm not sure how this would pan out for a state machine, because technically it would only trigger the structure in the current case that it is in (if I am not mistaken). Is this bad practice/will cause problems in the future?
Furthermore, right now my problem is that when I press ABORT (value changed), it does the cleanup and goes back to step 1, which is what I want. However, in step 1, the event for ABORT (value changed) is triggered again, despite me clearing it. I have attached a "normal event" and "abort event" screenshot to help you visualize. Each of the steps (except #0) are more or less exactly like that. The only thing #0 has is a button to break a while loop to start the test. Let me if I was unclear about anything.
If you guys need the program, I would be happy to post it. However, there are ALOT of subVIs that are in it, so you may just be able to look at the concept and not actually run it (it requires instruments anyhow). Please let me know. Thanks in advanced!
07-05-2016 10:30 PM
You do not want mutliple event structures in the same VI, particularly ones in different cases of a case structure. Unless you reallyi know what you are doing, I guarantee you will screw it up.
The reason it doesn't work for you is that each event structure having an abort event is getting that event queued up when it occurs. There is no "clearing of the event'. Whichever case is active and gets to execute the event structure and handles the abort event, and clears it from its queue. But all of those other event structures each have their own event queues capturing that same event, even though they aren't currently in the path of execution. When that case finally does get to execute when you restart your order of states, it finally gets a chance to handle the event that is still in its queue you fired earlier.
Read Caveats and Recommendations when Using Events in LabVIEW - LabVIEW 2015 Help.
You need to find another way to handle your abort button. You should probably just check the status of that button when the case of the state machine ends before you loop iterates and goes on to the next step of the state machine. It would be a piece of common code after the case structure.
07-06-2016 01:15 AM
There are multiple ways to implement your requirement and it depends on how you implement the logic
You can proceed with Normal State machine architecture and check for the status of Abort button in Lobby area of state machine (Place where it decides the next state) "Checking the status inside each case is bit complicated"
Another method is by using event structure where you need to poll for event occurence frequently and then take the action for abort if abort event is pressed
Sharing your code may help much better
07-06-2016 09:58 AM
I like to put my event loop in its own separate loop and the only thing it will do is send messages to my state machine, instructing it to do a certain thing. No "code" is executed in my event loop. This will keep the UI fast and responsive. You do have to make sure events don't get intermingled by enabling/disabling controls to prevent other events/sequences from occuring until the current sequence is complete. One problem I see with your code pictures is that you have a lot of code in your timeout event. This can potentially make your UI unresponsive until the code in the timeout event completes. I would guess that your other events also have a good bit of code in them as well.
You might want to check out the JKI state machine template in your spare time.
07-06-2016 09:22 PM
Hi all, thank you for your replies!
RavensFan, thanks for the detailed clarification. I was not aware they were in queue. I had assumed that once "handled", the status would be as such and not trigger again until a second event. I actually did consider your suggestion previously, but there are a few seconds of delay within each case or state, with the longest one being about 10-15 seconds. I want to be able to find a way to immediately proceed to the "cleanup" state case, and then go back to the start at operator's will. Is this possible?
Palanivel, thanks for your suggestion as well. However, as I stated to RavensFan, I am trying to avoid that 10-15 second delay, should the operator press ABORT during that test case. Is there a better way than for me to check repeatedly 5-6 times in between steps in that state case? I have also attached the program for your review.
aputman, thanks for your suggestion. I think you identified my primary issue with the sheer amount of code I have in each state case. By "event loop in its own separate loop", do you mean to say that the event while loop runs in parallel with the state machine's while loop? If so, I think I've tried something similar, but it doesnt do the immediate execution that I'm looking for. Please let me know if I am missing something critical maybe. The JKI state machine looks pretty complicated for my skill level. I'll try to make some sense of it, but so far it looks like they tried to do very little in each state.
I've attached the file now, in case you guys wanted to take a look. Don't mind the subVIs too much. They're mostly just for measuring/parsing the results from the instruments.
Thanks again to all!
07-06-2016 09:53 PM - edited 07-06-2016 09:59 PM
Why does a given state take 10-15 seconds? Try breaking it into multiple, shorter sub-states. Or if it is something that iterates like processing in a loop, have the state keep returning back to itself until the job is done.
Also, don't use a ring constant for you state machine. That should be an enum and saved as a typedef. When you do that, the case structure will now have meaningful names for each case rather than just a number. I guarantee one day you'll get the numbers confused. ("What does #7 do again?")
As Aputman suggested in his post, have the event structure that detects the press of the abort button in its own separate loop. you can use a notifier to pass a message to each of the states as to when they can abort and feed that into individual subVI's if that is the part of the code that is taking 10-15 seconds to run.
Right now your multiple event structures, which you already see aren't working the way you want them to, don't really solved any thing now. The press of the abort has to happen before the state starts otherwise the timeout case happens after 0 delay. Once that timeout case starts, and if it is the code inside that is taking 10-15 seconds to execute, nothing about that abort event is going to cause it to end any earlier.
07-13-2016 03:53 PM
Sorry for my delayed response:
Yes I would suggest putting the event loop in its own parallel loop. However this won't help solve your problem because your states take too long to process. If you have a while/for loop in your states, remove the loop and call the same state again (as Ravensfan suggested). Doing it this way, you can check for a stop event by calling the state with the Event structure (typically the Idle state). If no stop event is detected, continue with the test sequence.
JKI state machine is not complicated at all. There are quite a few states already defined that help with initializing your VI, but it is well documented and easy to follow the flow of execution. After initialization, it just sits in the IDLE state and waits for user input. I have modified this template to move the Event structure into a parallel loop and then use a message queue to send events back into the state machine.