LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Good way to "Interrupt" JKI State Machine

I know many around here are familiar with the JKI State Machine, and I enjoy it very much for its readability and use of macros. One thing that I run into is how to interrupt a process if something goes haywire. My current application ramps up the power according to a profile, and if something goes wrong (especially while they are still figuring out the profile) I want the user to be able to press abort. Of course, the JKI SM only looks for user events when the state machine is idle, so I have a couple of ideas. Please let me know if you have any others!

 

1) Set the timeout to 50 or 100ms. My ramp macro would look something like:

Set next power

Idle

Ramp macro

 

Concern: I don't like polling the event structure

 

 

2) I've also got a template where I take the event structure outside of the case structure. The timeout is set to 0 when there are states in the queue, and -1 when the queue is empty.

 

Concern: You can insert a state whenever you want, not just in the idle case, which could lead to race conditions. I would probably disable controls to address this.

 

JKI Side by Side.png

0 Kudos
Message 1 of 18
(6,034 Views)

Any long processes should be moved to a separate consumer loop, so that the user loop isn't tied up. You can turn the JKI State Machine in to a sort-of producer/consumer architecture to do what you're trying to do.

 

The Producer/Consumer architecture is based on a producer loop adding data to a queue and the consumer loop dequeueing the data. The process-intensive or time-hogging code goes in the consumer loop to free up the producer loop to run at the speed you need it to run.

For example, you have code that acquires data every 100ms and needs to write that data to file. It takes 50ms for the acquisition code to run and 80ms for the write-to-file code to run. Uh Oh! You're now taking 130ms per loop and your application is backing up. Now you move the write-to-file code to a consumer loop and enqueue data to it from your producer loop. Voila! Your 50ms code and 80ms code run in parallel and can both keep up with the 100ms period.

More information here.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 2 of 18
(6,028 Views)

Hi James,

 

I'm very familiar with the Producer/Consumer pattern, but I just really wanted to make use of the macros in the JKI SM!

Message 3 of 18
(6,022 Views)

Haha sorry gregoryj, I replied without looking at who I was responding to. I thought you were someone just trying to blindly push the limits on the state machine, which is common around here.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 4 of 18
(6,013 Views)
0 Kudos
Message 5 of 18
(6,004 Views)

Yes, i needed to do the same thing and didn't like adding an IDLE state to poll the UI either.  I moved the event structure into it's own loop and using a queue, I send messages into the JKI statemachine to process the UI events.  Inside this VI that I circled, i add the UI messages to the front of the remaining states so that it is processed immediately (for stopping a test, etc.) 

 

THe good thing about this is that when the UI message is first handled in the JKI SM, it doesn't have to actually do the processing right away because you can prioritize the event to happen later.  The UI is handled immediately but the event can happen later, at your own whim. 

 

For your ramp up, you would not want to use a loop inside of your state, otherwise the UI event won't be processed until after the state completes.  Just call the same state over and over until the ramp up is complete.

 

Capture.PNG

aputman
------------------
Heads up! NI has moved LabVIEW to a mandatory SaaS subscription policy, along with a big price increase. Make your voice heard.
0 Kudos
Message 6 of 18
(5,972 Views)

I use the JKI State machine quite often in my LabVIEW work and often have ran into the problem you are describing.

 

Assume I have a Macro that will loop for a while but I want the program to respond to a "STOP" command, this is what I do. (Not sure if this is the best method)

 

1.) I have a State that Changes the timeout on the event case to whatever I want. Assume here I go from -1 to 1 ms.

2.) I use this state BEFORE running my macro.

 

Assume this is my macro:

1) State A

2) State B

3) State C

4) Repeat 1-3

 

I modify my Macro as such

1) State A

2) State B

3) State C

4) Idle

5) Repeat 1-4

 

I explicitly send the State machine into an idle state to respond to any Front panel events. Since the timeout is small 1, it does not significantly slow down my program. If timing is critical then you will need another method. In this way is someone presses stop you can interrupt the macro.

 

After the macro is complete, I can change the timeout back to -1. Does this make sense? Or did I not explain it correctly.

 

Cheers,

mcduff

0 Kudos
Message 7 of 18
(5,960 Views)

Yup with a single loop state machine, I handle it very similarly.  I might have a VI that takes several inputs from the big cluster, or take the whole cluster itself and then type def it.  Then using logic in the subVI I can determine what I want to set my timeout value to.

 

So lets say I have a loop that talks to some serial hardware periodically, but I don't want to poll that hardware unless the hardware has been initialized.  I'll have a boolean in the cluster labeled "HW Initialized" and in the subVI if that is false then my event timeout is set to -1.  But if that is true then I set it to something reasonable like 50ms.  Then in my state machine if I close the hardware for some reason all I need to do is also set that boolean to false and now my polling stops.  Some times a VI isn't needed and really I just need a select function, select -1 or 50.

 

Combining this with user events I don't really have a need to poll blindly, I only poll if a user event, or action from the user, did something that sets a variable, that then tells my event structure to perform periodic time outs.  Not running a test?  Well then hardware shouldn't be initialized, and no polling.  Not logging to a file?  Then there is no user event telling it to do stuff.

 

Additional logic can be used too.  Like one of my logging modules is for TDMS and I wanted to periodcially defrag the file.  So I have the timeout be small (if a test is running), but then in the timeout I have the elapsed timer which is only true if 10 minutes have passed.  If it has been that long then go defrag.  The reason I don't set this to a 10 minute timeout is because events will cause that timeout to reset, and to not happen.

0 Kudos
Message 8 of 18
(5,920 Views)

@Gregory wrote:

1) Set the timeout to 50 or 100ms. My ramp macro would look something like:

Set next power

Idle

Ramp macro

 

Concern: I don't like polling the event structure

 

 

2) I've also got a template where I take the event structure outside of the case structure. The timeout is set to 0 when there are states in the queue, and -1 when the queue is empty.

 

Concern: You can insert a state whenever you want, not just in the idle case, which could lead to race conditions. I would probably disable controls to address this.

 


Go with (1).  Nothing wrong with polling the event structure.  By calling "idle", you allow your macro to be interupted only at one place, so you only have to worry about the effect of interuption only at one place.  Option (2) has MUCH greater portential for race condition bugs.  

 

Also, as a general suggestion to those using the JKI template: don't try to "fix" it untill you've used it.  A lot.  I used the JKI in projects for seven years before I created a significantly modified template, and my template actually deliberatly reduces the number of options in how to use it (you can't call "idle" in my template, for example).

 

BTW> I have a package on the Tools Network called Cyclic Table Probes that includes a "history" probe for the JKI state queue (you can see it in the image in the link).   History probes are very valuable for debugging things like the JKI.

0 Kudos
Message 9 of 18
(5,876 Views)

Hi all, thanks for your feedback.

 

It seems the consensus is that there's nothing wrong with polling the event structure for ~50ms if it fits with the program. This time around I've already started putting my instrument communications into a separate loop with a queue, but I do not like relegating the JKI SM to hardly more than a UI loop, especially with the ability to make macros and the great addons from carmody and bobillier. (Check out CaseSelect and State Editor quick drop plugins if you haven't seen them).

 

Aputman, you've got a lot going on in that picture! It looks like you modified the "Add State(s)" VI. Does it have an event structure inside?

 

mcduff, yes you explained it well. I've made "Wait" one of my core states so I can just type "Wait >> 50" to Wait 50ms. Perhaps I should do the same with timeout!

 

Hooovahh, that seems reasonable. As I said just above, I think a "Timeout" case that takes an argument of milliseconds might be a useful state to have.

 

drjdpowell, I believe I got your cyclic probes addon when I downloaded the messenger library, I'll have to try it out with the state queue. Would you mind elaborating on your warning to not edit the template before using it a lot? Did you learn some lessons you can share after using it for 7 years?

0 Kudos
Message 10 of 18
(5,839 Views)