Jump to content

Event Structure as State Machine


Recommended Posts

Anyone have an opinion on using an Event Structure inside a while loop as the state diagram instead of using a case structure.

The program i have seems a whole lot more complicated in regular state diagram form that it would be if i just used the event structure with a few user events.

My test lasts only 1 second, acquires about 4000 data points and displays a graph and writes data to a file.

The main thing is capturing settings changes (and storing to registry or disk), which is easy with events, catching initialization errors such as missing config files, etc. (easy with events).

It just seems to me the whole Case Structure state diagram is a little archaic since we have had an Event Structure for the last 4 Major versions of Labview.

I realize this post may start a forum riot (state diagram diehards), but i am curious to know people's current opinions.

Link to comment
  • Replies 72
  • Created
  • Last Reply

Top Posters In This Topic

QUOTE(EJW @ Nov 9 2007, 09:22 AM)

I realize this post may start a forum riot (state diagram diehards), but i am curious to know people's current opinions.

I have recently been to the mountaintop and have begun to discover what dynamic events can do (after having mangled the queue-driven state machine into almost every possible contortion). Upon my return, I now fear that I may have found my next hammer-which-makes-everything-within-arm's-reach-look-like-a-nail :P. I am currently hitting everything with it.

So yes, I think using the Event Structure in a state machine is absolutely a workable pattern. As with anything, there are right and horribly wrong ways to do it, but overall it's a great option.

Link to comment

QUOTE(EJW @ Nov 9 2007, 12:22 PM)

Anyone have an opinion on using an Event Structure inside a while loop as the state diagram instead of using a case structure.

The program i have seems a whole lot more complicated in regular state diagram form that it would be if i just used the event structure with a few user events.

My test lasts only 1 second, acquires about 4000 data points and displays a graph and writes data to a file.

The main thing is capturing settings changes (and storing to registry or disk), which is easy with events, catching initialization errors such as missing config files, etc. (easy with events).

It just seems to me the whole Case Structure state diagram is a little archaic since we have had an Event Structure for the last 4 Major versions of Labview.

I realize this post may start a forum riot (state diagram diehards), but i am curious to know people's current opinions.

What you are describing sounds like it could work. There are some problems that can occur when you put a lot of code in an Event Structure, if you avoid them, who is to say there is something wrong with the idea?

The two problems I find are if the code in the event structure takes a long time, then the user may load up the queue with commands while pecking around trying to get a reaction out of the software. The other is in getting a particular event to stop if vi's are cranking along inside it. This will hang your vi nicely.

The more complex the code becomes inside the structure, the more likely it is to have problems that are hard to debug. The Event Structure isn't deterministic, so it is fairly easy for unforseen combinations of input to cause trouble.

My favorite application of the Event Strucure is a producer consumer form with queues communicating between the event structure and the non-UI loops. Most of my work with labview is making instruments that need manual control. I am usually automating a variety of DAQ, storage, analysis, and display strictly for my own purposes. What I want in the end is often not apparent when I start. The event driven P-C form is very flexible expandable and predictable.

In this form the event structure is taking care to slow inputs from a human. I may have several activities underway in parallel loops. A state machine like you describe wouldn't be as easy to develop for these applications.

Anyway, I am not going to start loading up event structures. I've had enough of trying to figure why my vi is locked up.

Mike

Link to comment

QUOTE(mross @ Nov 9 2007, 12:54 PM)

..., then the user may load up the queue with commands while pecking around trying to get a reaction out of the software....

Mike

Ahh, but you can prevent the user from generating front panel input while in an event by LOCKING the front panel during an event.

Most of my "states" are fairly quick. 1 second for acquisition, milliseconds in computation, display a graph and other numbers on the front panel, and trigger 2 DIO output lines.

The program is part of a gauging machine in a production facility. It waits for a DIO input to start the test, does all the stuff above and waits for the signal again (about every 7 seconds) and the test time is a total of maybe 1.5 seconds with calculations.

Link to comment

QUOTE(Justin Goeres @ Nov 9 2007, 09:23 AM)

By dynamic events, are you referring to enabling and disabling events using the "Register For Events" node? Or User Events?

And when you write "Event Structure in a state machine" I think of the architecture where the Event Structure is located in one of the cases of a State Machine. So after a sequence of states completes, the state machine returns to the IDLE state to handle any new events. I think EJW is talking about an Event Structure in a While loop--nothing else there. But maybe that is what you meant...

QUOTE(mross @ Nov 9 2007, 09:54 AM)

My favorite application of the Event Strucure is a producer consumer form with queues communicating between the event structure and the non-UI loops. Most of my work with labview is making instruments that need manual control. I am usually automating a variety of DAQ, storage, analysis, and display strictly for my own purposes. What I want in the end is often not apparent when I start. The event driven P-C form is very flexible expandable and predictable.

This is a good description of what I am currently hitting everything with. Some additional benefits are having the Event Structure and Actions/States case structure both visible at the same time. This also separates the events from the actions, which provides that expandability. You can always set the cursor to 'Busy' if you want to lock the front panel.

David

Link to comment

QUOTE(JDave @ Nov 9 2007, 01:59 PM)

By dynamic events, are you referring to enabling and disabling events using the "Register For Events" node? Or User Events?

And when you write "Event Structure in a state machine" I think of the architecture where the Event Structure is located in one of the cases of a State Machine. So after a sequence of states completes, the state machine returns to the IDLE state to handle any new events. I think EJW is talking about an Event Structure in a While loop--nothing else there. But maybe that is what you meant...

This is a good description of what I am currently hitting everything with. Some additional benefits are having the Event Structure and Actions/States case structure both visible at the same time. This also separates the events from the actions, which provides that expandability. You can always set the cursor to 'Busy' if you want to lock the front panel.

David

Exactly. Eliminate the Case Structure altogether. Use the "Lock Front Panel Events..." checkbox for built in events to keep those from firing and user events only fire when called anyway.

Example: Timeout Event--Waits for a digital input (from a PLC) to start a test (50ms timeout or whatever)

User Event: Acquire-- Acquires Data, calls next user event-Process

User Event: Process-- Process the data (calculations), calls next user event-Status

User Event: Status-- Determine Pass/Fail conditions, calls next user event-Display

User Event: Display-- Display results on screen, calls next user event-Record Data

User Event: Record Data-- Records data to a file, calls next user event-Output

User Event: Output-- Sends Pass/Fail and Test Complete signals via two Digital outputs to a PLC. calls timeout event

User Event: Error-- Can be called from any event where an error occurs to terminate the regular cycle, or could possibly return you to the normal cycle where it left off.

Now, if someone changes a setting which triggers an event to record the new setting in the registry, that will be queued up or if you set the mouse busy at the beginning of the acquire, then no one can change anything on the front panel and they have to wait to change a setting.

Link to comment

QUOTE(JDave @ Nov 9 2007, 11:59 AM)

By dynamic events, are you referring to enabling and disabling events using the "Register For Events" node? Or User Events?

Actually, I was referring to both/either. I didn't exactly make that clear.

QUOTE

And when you write "Event Structure in a state machine" I think of the architecture where the Event Structure is located in one of the cases of a State Machine. So after a sequence of states completes, the state machine returns to the IDLE state to handle any new events. I think EJW is talking about an Event Structure in a While loop--nothing else there. But maybe that is what you meant...

It's in the ballpark of what I meant :). I see an Event Structure by itself in a While loop as a special case (no pun intended) of the "Case Structure with an Event Structure in one of its frames" layout. I've never actually designed or built anything with the structure EJW is talking about, but I see no reason why it wouldn't be worth looking into. I think that we mostly think of the queue-driven producer-consumer design because that's what NI kind of pushes at us in the standard templates, but there are lots of ways to do these things.

Link to comment

QUOTE(EJW @ Nov 9 2007, 12:08 PM)

Example: Timeout Event--Waits for a digital input (from a PLC) to start a test (50ms timeout or whatever)

User Event: Acquire-- Acquires Data, calls next user event-Process

User Event: Process-- Process the data (calculations), calls next user event-Status

User Event: Status-- Determine Pass/Fail conditions, calls next user event-Display

User Event: Display-- Display results on screen, calls next user event-Record Data

User Event: Record Data-- Records data to a file, calls next user event-Output

User Event: Output-- Sends Pass/Fail and Test Complete signals via two Digital outputs to a PLC. calls timeout event

User Event: Error-- Can be called from any event where an error occurs to terminate the regular cycle, or could possibly return you to the normal cycle where it left off.

Now, if someone changes a setting which triggers an event to record the new setting in the registry, that will be queued up or if you set the mouse busy at the beginning of the acquire, then no one can change anything on the front panel and they have to wait to change a setting.

You are trying to place a State Machine architecture into a structure designed to respond to events. This will work, but if nothing else it is more difficult to understand. Having two parallel loops (Event driven Producer-Consumer) and simply placing that state transition logic into the second loop does not seem (to me) like it is more complicated.

I have found by experience that saving a little time up front by using a simpler architecture only hurts me more when I try to force additional features in later on. I have never regretted making a VI more robust and flexible than I needed it to be.

My :2cents: ...

Link to comment

QUOTE(EJW @ Nov 10 2007, 06:08 AM)

Exactly. Eliminate the Case Structure altogether. Use the "Lock Front Panel Events..." checkbox for built in events to keep those from firing and user events only fire when called anyway.

Example: Timeout Event--Waits for a digital input (from a PLC) to start a test (50ms timeout or whatever)

User Event: Acquire-- Acquires Data, calls next user event-Process

User Event: Process-- Process the data (calculations), calls next user event-Status

User Event: Status-- Determine Pass/Fail conditions, calls next user event-Display

User Event: Display-- Display results on screen, calls next user event-Record Data

User Event: Record Data-- Records data to a file, calls next user event-Output

User Event: Output-- Sends Pass/Fail and Test Complete signals via two Digital outputs to a PLC. calls timeout event

User Event: Error-- Can be called from any event where an error occurs to terminate the regular cycle, or could possibly return you to the normal cycle where it left off.

Now, if someone changes a setting which triggers an event to record the new setting in the registry, that will be queued up or if you set the mouse busy at the beginning of the acquire, then no one can change anything on the front panel and they have to wait to change a setting.

My turn to chime in here.

First up can somebody please tell me whether firing off a User Event forces a switch into the UI thread or not ? Last time I tried to look up an answer I don't remember finding one.

Now on to a case study highlighting why not to attempt a large/scalable progam with the arhitecture proposed in this discussion.

A colleague of mine at work tried this approach with his second major LabVIEW project. I advised him against it for the reasons mentioned thus far. Additionally, instead of using User Events, he would change the value (property value:signalling) of one of many LEDs on the FP. I advised him against doing that because it would force a context switch into the UI thread, he said he wanted visibility of where his state machine was up to (I said there were other ways). Anyway, to cut a long story short, just yesterday he came back to me for advice when he discovered that his program slowed to a crawl and data was lost when any window was moved ! The data loss problem was solved by re-locating some code from an event structure case into another loop and also using a queue to transfer data between that loop and back to the event structure loop (rather than the LV2 global he was initially using. Hence the data loss problem was an issue unrelated to the Event Structure per say) however he still must live with the fact that code in the event structure isn't serviced as fast when somebody moves a window. In addition to those problems, he now needs to remember to ensure that every event case takes less than a certain amount of time (say 100ms or whatever it was) in order to keep it running smoothly.

regards

Peter

Link to comment

QUOTE(PeterB @ Nov 9 2007, 10:00 PM)

I BELIEVE the event does fire in the UI thread. That does not mean the Event case executes in the UI thread.

Property nodes do executes in the UI thread.

Controls and indicators should not be used to "store" data in all but the most simple VI's (and even then with great care!).

They lead to yet another form of race conditions. I tend to use controls and indicators as a "window" into the data I store in Action Engines.

Back to the subject of of the thread. :oops:

Events are great for responding to things that can happen at any time.

State Diagrams are wonderful for structuring complex processes.

Quoting from Ode to a State Diagram;

"

SD's and event structures do work together but "These things must be done delicately" (Wicked Witch, Wizard of Oz).

"

I avoid embeding one n the other. Everything I can do fast (<1 sec) I try to do in the event structure. If I have some process that will require more than a second, I'll use a second process to take care of the on-going actions so I can keep the UI snappy.

THe second process are generlly implemented as state machines. They watch for commands that control their state. All background process of this type should avoid tight loops that do not have a check for an abort or exit. More often than not the commands from the UI are transfer using queues, stuffed by the UI and read by the the background process.

If there are settings or parameters that have to change on the fly, Action Engines are an efficient vehicle.

Using the State Diagram Editor to develop the background process has a lot of plus.

Most of what I wrote in Ode to a State Diagram is still true today (well in my book :rolleyes: ).

I am excited about what the State Chart tool can let me do. I tested it a little but have not had a chance to aplly it in an application yet. The big thing holding me up on the SC is it an implementation of UML. I don't know UML so I get lost in the help. :headbang:

I have started to read an introduction to UML but that takes time.

So for the time being, the SDE is still a big tool for complicated algorithms.

Ben

Link to comment

QUOTE(wevanarsdale @ Nov 9 2007, 12:01 PM)

I agree. A client's desires are not always in full evidence at the start of a project. The key for me is expandability.

I strongly agree with this comment. It really depends on what the code is for. For all customer projects I use a full (event structure inside case inside loop) state machine. The main reason is that ALL code I write changes in such drastic ways due to customer requirements that in the end it makes sense to start on the right foot. Customers come up to me after a project is full under way and ask to add several features. When I respond with: "Sure, just give me an hour and it's done" They are pleasantly surprised. I program with the expectation of that all the time. Expecting otherwise is foolish. Having said all that, there are places where a more simple approach is ok. Only you can be the judge of that.

To comment on User Events. I too am a fond user of them when it comes to interprocess messaging. They have many benefits but I don't think they should be use everywhere (Justin!).

Admin Note: neB Enough with the blank lines already. There are no points for the most use of screen space. :P

Link to comment

QUOTE(Michael_Aivaliotis @ Nov 11 2007, 06:41 AM)

To comment on User Events. I too am a fond user of them when it comes to interprocess messaging. They have many benefits but I don't think they should be use everywhere (Justin!).

Michael or anyone else, can you tell me if user events force a context switch into a UI thread ??

regards

Peter

Link to comment

QUOTE(Michael_Aivaliotis @ Nov 10 2007, 03:41 PM)

I strongly agree with this comment. It really depends on what the code is for. For all customer projects ... :P

Luckily for me, i don't do customer projects. These are all in house programs designed to run on production gaging equipment with little or no user input, aside from me or another qualified person making a setting or calibration change! ONe nice thing i like about the event structure though is when you respond to a control in the value change event, you have both NEW and OLD data available to you without using locals or shift registers.

Link to comment

QUOTE(PeterB @ Nov 9 2007, 11:00 PM)

SNIP Additionally, instead of using User Events, he would change the value (property value:signalling) of one of many LEDs on the FP. I advised him against doing that because it would force a context switch into the UI thread, he said he wanted visibility of where his state machine was up to SNIP

regards

Peter

I am one of those guys with an event driven P/C hammer. To see what my VI is up to, I put a string indicator for each action loop on the FP and write the case name to it. I could imgine doing this with a cluster similar to the error cluster which contains a status boolean or similar. Of course I never put this write operation in any fast running loop. If I wanted to know about the status of some fast loop I would write to an indicator only when it starts, when it pauses, or stops.

That is crazy talk what he did with the LED indicators.

Link to comment

I have built applications that use this concept. I even have one where there are two parallel loops, each with its own event structure. The top one responds to user interaction. The bottom one runs the test process. They can fire events at each other to start tests or to exit when done or an error occurs. This seemed like a good idea at the time but ended being very complex to 'keep straight in my head' and therefore, to debug. Here are a few reasons why I no longer do this:

1. You can fire off events within the event structure to 'queue up' the next event, but once fired you cannot recall them. So, if you are in one event case and you decide to fire off a series of three cases to perform the next 3 needed operations, then you are stuck with that order. If the first or second one of those cases produces an error, you cannot go to the error case until all three complete.

2. There is a much better way to accomplish this with a queued state machine. I didn't know much about these when I first tried the event state machine concept.

3. Events seem to work best when there is some sort of asynchronous interaction happening, like a human or an external device. I use an event structure to poll a TCP connection (using the timeout case) and place the data into a queue which is then processed by a consumer loop. Sometimes, the data sent to the consumer contains a pattern when requires something to be sent out the TCP connection. In that case, I fire a user event from the consumer to tell the polling event loop to send the necessary command to the TCP port and then go back to polling for new data. This works very well.

Good luck with your implementation!

-John

Link to comment

QUOTE(neB @ Nov 12 2007, 11:43 PM)

QUOTE(PeterB @ Nov 11 2007, 07:03 PM)

Michael or anyone else, can you tell me if user events force a context switch into a UI thread ??

The events "fires" in the UI thread. That does NOT mean the code for the event executes in the UI thread, only the "firing".

Hi Ben, I now have an authoritative answer to my question from Stephen Mercer. Apparently the "Firing" of a User Event is not even done in the UI thread - as that would be considered a context switch which doesn't actually happen. There is however one exception - see below - copied from Info-LabVIEW.

QUOTE

-----Original Message-----

From:
Stephen Mercer

Sent:
Tuesday, 13 November 2007 4:25 AM

To:
Info-LabVIEW@labview.nhmfl.gov

Subject:
Re: Do user events run in the UI thread ?

I forwarded your e-mail to the folks that own the Event Structure. I got this authoritative response:

> User Events do not cause thread context switches.

> The only exception is if you use the Register Event Callback

> node to register them, which always runs in the UI thread.

To be clear, that's the Register node itself that runs in the UI thread. The event cases that are triggered by those registered events are still non-UI.

Pojundery,

Stephen R. Mercer

-= LabVIEW R&D =-
Link to comment

QUOTE(PeterB @ Nov 12 2007, 05:29 PM)

The events "fires" in the UI thread. That does NOT mean the code for the event executes in the UI thread, only the "firing".

Hi Ben, I now have an authoritative answer to my question from Stephen Mercer. Apparently the "Firing" of a User Event is not even done in the UI thread - as that would be considered a context switch which doesn't actually happen. There is however one exception - see below - copied from Info-LabVIEW.

</FONT>

I stand corrected!

Ben

Link to comment

I think that an Event Structures As State Machine architecture works well. It's what I'm using for my project. It's not the sort of structure that is taught by NI, however I think it has some distinct benefits.

Three other architectures have been mentioned in this topic:

1) State Diagram

2) Producer/Consumer (Producer can either be a normal While Loop or an Event Structure)

3) Event Structure With State Machine Inside An "Idle" Event Case

As EJW stated "The program I have seems a whole lot more complicated in regular diagram form that it would be if I just used the event structure with a few user events."

A State Diagram is very inefficient at responding to User events since you need polling.

If you look at the Producer/Consumer model it has wires running everywhere and a lot of "code" before you even start putting anything useful in.

The Event Structure with a state machine inside an "idle" event case offers, in my opinion, no benefit over using the one event structure and firing off some Programmatic Events (NI uses the term User Events for programmatically-generated events. That is, events not generated by the user are called User Events. Talk about calling something the exact opposite of what it is! I'll use the term Programmatic Event for programmatically-generated Events.)

Having highlighted what I see as the disadvantages of the three main architectures, let's look at the elegance of an Event Structure As State Machine architecture.

You put down a while loop that takes up your entire screen and then put in an Event Structure. Your architecture is now complete. Simple, quick and easy to understand. Compare this to NI's example of template Producer/Consumer structure!!!

You would now add whatever your software has to do. For each user interface control, you can readily create an Event Case to handle it. Most can be done within the one event case. For Programmatic Events, start with an Initialize Event Case, which you fire using the technique mentioned below. Add others as required, including an Exit one that sets the While Loop's conditional terminal to True.

All cases can be readily viewed by clicking on the Event Structure heading. There they are all listed, just scroll down and select one and you are instantly there. With the closest method to an Event Case Structure As State Machine architecture, which is the Event Structure With State Machine Inside An "Idle" Event Case architecture, you need to click on the Event Structure heading to list all User Events and then on the "idle" case and then the Case Structure to get a list of Programmatic Events. Why do multiple clicks when one will do it. Why have two structures, when one will do.

If you ever want to print out your code, it prints out such that each Event Case is on one page. For those that like to work on public transport on the way to work and home, this is great.

If you need to do something that takes up more than one page, rather than expand the diagram to go beyond one screen, just fire a Programmatic Event to another Event Case and continue from there. My initialization happens over four event cases and can be readily expanded to more. This allows sequencing, which is very important when initializing, but also ensures that things are not crammed together.

The Event Structure as State Machine also cuts down on subVI's. SubVI's are great when you have a specific task to do or do such a task in multiple places. But how many times have you created a subVI just because you ran out of space. Delegating code to the subVI in this situation does not help legibility as you need to open a subVI to see the program flow (and you'll forget to pack it for when you work on the bus!). It's so much nicer to get the current Event Case to fire another Event Case and you continue looking at your code in the next Event Case (a three dimensional block diagram!).

When using an Event Structure As State Machine architecture, we have to be careful that each case can be executed quickly. By quickly I'm talking about less than 1, 2, maybe 5 milliseconds. This is a long time to do a unit of work. I've got 1 kHz data with 20 data channels coming at me at 10 Hz (100 element arrays) from which I select six channels, decimate, buffer, scale and then graph (with scrolling) and the whole thing happens in 3 milliseconds on a middle-of-the-road PC.

Most responses to user action or chunk of data processing can be handled in well under 1 millisecond. If you're doing a long task such as processing an array of data and it takes over a few milliseconds, it can often simply be broken up and processed in smaller chunks. This takes care of 90% of actions. What happens when we have something that can take a long time? Here you must use one of two techniques. If your task goes off and does something that you don't need any output from it (writing to disk, displaying something complex, etc) you can use VI Server to serve up the VI and set it up so that it executes in parallel and immediately returns control. This way the Event Case is exited quickly. Finally, you can set up a queue and parallel loop that is communicated to. This is the Producer/Consumer model, but only those activities that cannot be done quickly, sliced or parallel launched need to be worried about. In a medium complexity program you'll probably only have one or two of these.

So yes, there are some Consumer Loops, but very few. And they are very simple. Each consumer will have its own queue. Rather than having a Consumer Loop with multiple commands and having to send a superset of data that fits all the Consumer's commands, you just send data to the Consumer Loop along its dedicated queue. The consumer loop is waiting for data, it sees it and processes it. Compare this to the typical consumer loop that has to read the command, then pull out its data from a one-size-fits-all data structure and then execute its. The simplified Consumer model works since there are only a few (generally about 3) Consumer Loops since only tasks that take longer than about 5 milliseconds and can't be sliced or served, need to be send to a Consumer.

Now for the controversial bit. How do you fire off Programmatic Events (again which NI call User Events, even though they are not initiated by the user – talk about confusing). The purists would say that you need to register events and define things. For those that wish to go this conventional and conservative path, go for it. Personally, I hate the complexity.

There is a simple method. Before everyone jumps down my throat, I know that the method I'm proposing forces executing to go through the user interface thread. Yes, there is some latency (but no less efficiency), but if someone can quantify it, I suspect it's negligible. [As an aside, does anyone know how often the user interface thread is run?]

The method of firing Programmatic Events is it to put a Boolean indicator on the front panel and label it with the action (eg. Initialize, Update Graph, Exit, etc). Now, whenever you programmatically want to execute one of these Programmatic Events just create a Property Node with Value (Signaling) and wire a constant set to True. You can now create a new Event Case that responds to a Value Change for the indicator. What I do is put all these indicators on a tab labeled Programmer (I'm sure they can be hidden if required). I also write a false to the indicator as the last step of the handler Event Case. This way, when I want to, I can click the Programmer Tab and I can see where my program activity is. I can also see where it is if, during development, it is stuck – it's the Event Indicator that is on. Sure there is latency in using Value (Signaling), but the added visibility allows you to make up for the loss of efficiency.

I hope I've presented a simple, elegant and efficient architecture. It could certainly do with some refining and I look to the community to find holes in the architecture and give me the opportunity to address them.

The benefits I see are:

1) Quick and simple to set up

2) Very legible as all actions are an Event Case that is readily listed and jumped to

3) Easy to expand.

4) Can be used for small or large projects

5) If you're willing to use Value (Signaling), great visibility on where you're code is at without any extra programming.

See attachment for a template.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.