Jump to content

Architecture Help - Actor Framework, State Machine?


Recommended Posts

I have to develop an application and I would like some help designing the architecture.

 

The system controls a number of pumps and valves to create flow around a network of pipes.  There are flow meters in the network which are used as feedback for PID to maintain a flow.  The network of pipes is gradually opened up to get flow and then PID kicks in to maintain a flow.  The test sequence is pretty much a big state machine.  For example:

1.       Open valve 1

2.       Wait for pressure to build

3.       Ensure temperature is not over limit

4.       Etc

 

I will have a number of different screens which I want to load into a main sub-panel:

·         Main SCADA screen (show state of all valves pumps etc)

·         Test setup screen (configure tests)

·         I/O screen

·         Alarm screen

I will also have a number of I/O processes:

Inputs

·         Digital (valve sates)

·         Analogue (flow meters, temperature etc)

·         Modbus and serial devices (flow meters)

Outputs

·         Digital Output – Valves etc

·         Analogue  - Proportional valves

 

I want to use the Actor Framework because I’ve used it 3 times now and it is easy to spawn processes, make popups, inter-process messaging, error handling etc.  I can have all my processes separate (high cohesion) with separate user interfaces (if they have a UI) .

 

My problem is that AF and State machines don’t really go that well together (correct me if I’m wrong).

What happens when I want to do PID or loop in the same state?

Time delayed message?

A a VI for each state and enqueue the next or same state from within that VI?

 

Does anybody know a good way to incorporate a state machine into AF or should I chose a different way of doing things?

 

Any thoughts will be appreciated.

Cheer

Lewis

Link to post
Share on other sites

You definitely do not want to have you PID timing based on time delayed send or AF messages in general. Remember, a message is guaranteed to get there, but it's not guaranteed to be handled in any time. So if you have a "Check PID" message, but the "Log data" message gets in there before it, the log data will happen first, then the "Check PID" will happen as soon as it can after the logging is done. This could introduce a lot of jitter.

 

Another design principal that you should follow when writing actors is that messages shouldn't take too long to execute. Obviously "long" is very subjective, but in general you shouldn't have a message for something like "Wait for pressure to build" since it probably takes a handful of seconds at minimum. This means that you Actor's thread is locked for that time. So you cant send it an abort message if needed, you cant stop the actor, etc.

 

The easiest way to do long running tasks or time dependent tasks using the AF is to have helper loops. To do this you override actor core, and drop another loop on the block diagram. Now you need to create some communication mechanism (regular old Qs, notifiers, etc) to communicate between the message handler Q (which is what the Parent's actor core is) and your new helper loop. You'll probably store a copy of this reference in your private data so Messages can communicate with your helper loop. You're probably already done something similar to this when writing UI Actors.

 

Your helper loops will probably look very similar to a traditional state machine. The only difference is this additional communication mechanism.

Link to post
Share on other sites

Thanks for the reply!

 

If I was to have a wait for pressure to build, I would keep en-queuing the "Wait for pressure" message from within the message until it was up to pressure and then enqueue the next state.  I wouldn't have a blocking message.

 

I don't like the idea of parallel helper loops because you are basically re-creating the AF.  Why not just create a nested actor? I could create a state machine nested actor.  In the nested actor, when it is time to do PID, enqueue the PID message and the PID message can keep enqueueing itself until it is finsihed.  I don't really like this solution (hence my initial post) because it gets difficult if PID as enqueued a message to itself but the caller has sent a message to go idle.  The nested actor goes idle but there is still a PID message in the Queue.

Link to post
Share on other sites

Helper loops are an essential part of any AF project. Helper loops do all of the heavy lifting of your actor, while messages are just the public interface for the actor. There are times when you can get away with just doing things in messages (like a file logger for example), but anything that's doing anything meaningful will probably need to happen in helper loops. The reason you don't create nested actors is because you need finer control of things like timing or execution order or whatever. With a  helper loop you can make sure that the Idle message stops any PID messages, or that the PID checking happens every X ms or whatever.

Link to post
Share on other sites

My problem is that AF and State machines don’t really go that well together (correct me if I’m wrong).

.....

or should I chose a different way of doing things?

 

You have already answered your question. You know that it doesn't fit the task but perhaps not why. Look at what will be needed for system wide state control, sequencing and subsystem interaction. If they are required and must be deterministic; there are better, less painful solutions.

Link to post
Share on other sites

You definitely do not want to have you PID timing based on time delayed send or AF messages in general. Remember, a message is guaranteed to get there, but it's not guaranteed to be handled in any time. So if you have a "Check PID" message, but the "Log data" message gets in there before it, the log data will happen first, then the "Check PID" will happen as soon as it can after the logging is done. This could introduce a lot of jitter.

 

Another line of reasoning would be to ask why you have PID and Logging in the same actor.  If a “PID actor†is only handling messages to do with PID control, then there may be advantages to keeping all actions serialized in one loop.  

BTW, Lewis, the AF group at NI.com is the best place to ask AF questions.  More people who use the AF extensively will be watching.

Link to post
Share on other sites

BTW, Lewis, the AF group at NI.com is the best place to ask AF questions.  More people who use the AF extensively will be watching.

 

I don't frequent the NI groups nearly as much and enjoy having some of this discussion at LAVA.  

Link to post
Share on other sites

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.

  • Similar Content

    • By jhoehner
      Hello All,
      First time LAVA poster here with my first question. Why do some LabVIEW programmers insist on wiring the error cluster to the bottom of their VI as opposed to the sides as shown in most NI documentation. Is there any benefit to it? Is it 100% a preference thing? Is there a way to make LabVIEW connect error wires like this automatically?
      I've only seen it in advanced LabVIEW code from experienced programmers and some parts of the Actor Framework.
      Your insight and experience is appreciated! 

    • By the_mitten
      The introduction of parallel, read-only access for DVRs in LabVIEW 2017 adds a great deal of flexibility to using DVRs to monitor values in parallel executions of code. Fo\The downside of this, of course, is the necessity of using the In Place Element (IPE) throughout your code simply to read the value. Having IPEs throughout your code just to read a value both takes up block diagram real estate and also takes more clicks than desirable to insert.
      Similarly, though less frequently, there are times when you only need to update the value within a DVR without actually performing any logic inside of the IPE.  This situation is less frequent, at least for me, as I am usually using arrays or classes with DVRs such that I actually need to modify the existing data rather than simply replacing it.
      A more preferable solution to the above situations would be to have Read/Get and Write/Set VIs for the DVRs to simplify the process of working with them. This way, and IPE on the block diagram would only be needed when you were actually modifying the existing data within the DVR, rather than simply overwriting or returning the current value.
      Thanks to the power of malleable VIs and the type specialization structure that is now officially released in LabVIEW 2018, a better solution is now available. I’ve created two malleable VIs, Read  DVR Value (Parallel) and Write DVR Value that allow you to perform a write and a parallel read on any DVR data type.
       Now, you can use a single VI that you can insert via Quick Drop to read or to write DVR values.  
      Download the attached ZIP file to access the two malleable VIs and example code, and please let me know your thoughts in the comments!
       


      DVR Read and Write VIs 1.0.0.zip
    • By takanoha
      Hi 
      I have a simple program which has only 2 buttons for the user interface. When the user clicks OK I want the program to get into the event structure case called "OK Button". Once it is inside there is a loop which continuously waits for 1 second until "Stop Button" is called from the user. 
      But because once the user presses the "OK Button" the program gets into the event and therefore I can not call the "Stop Button". 
      Is there a way to call the "Stop Button" even if the program is inside the event ?
       
      Thanks

      event_out.vi
    • By A Scottish moose
      Hello everyone,
      TL;DR - Any thoughts on if it's a good or bad idea to spin off an actor from a QMH framework?  I've got some library code that would be valuable but the project itself doesn't justify AF.
      I'm brainstorming ideas for a tester that I'll be building over the next few months. The project that I'm currently winding down is an Actor Framework test system that has come out really nice. Part of the project was an actor built to handle all of the DAQ and digital control.  The main actor spins it off an tells it when and what tasks to launch.  It send back data and confirms commands, uses Dynamic events to keep up with the generated signals, and uses actor tasks to ship the data back to the controller.  Works amazing. Nothing revolutionary for sure but very handy.
      This next project doesn't really need actor framework, it's much smaller and has a lot smaller list of requirements.  That being said I'm curious about integrating my DAQ actor (Dactor, because who can resist an amalgamation?!) into the project. Any thoughts on if it's a good or bad idea to spin off an actor from a QMH framework?  Is this even possible based on how the AF tree is designed to work?
      Thanks for reading!
      Tim
       
    • By ACS
      Here's a heads-up for any LabVIEW developers in Central Texas, or any Certified LabVIEW Architects coming to Austin for the CLA Summit next month.  I will be teaching Actor-Oriented Design in LabVIEW, Sept. 13th - 15th, in the training center at NI's corporate headquarters.  Come take the class, enjoy Austin for the weekend, and stay over for the Summit! Details on the course offering here:
      Actor-Oriented Design in LabVIEW
      There are offerings in October as well, in MI, MA, and Santa Clara, if those locations are more convenient.
×
×
  • Create New...

Important Information

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