LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Agonizing over project architecture/paradigm, event vs state vs mixture - guidance, comments, experiences appreciated.

I just want to say, I don't want to come off as asking for anyone to do anything for me. I merely would appreciate anyone who reads my very general description of the project's goal and can perhaps help me decide on an overall general architecture to pursue. I think what's making this hard for me is that the last project I did, although not as big, I did indeed spend what I thought was an adequate amount of time planning only to realize that I had wished I had pursued a different strategy when I was 80% done.

 

In general, what I want to do is to be able to parse a "run" file that specifies various runtime variables, commands to be sent to a scientific instrument (in this case, a cartesian robot & some peripherals it will service in order to fulfill a set of processes to be performed on discrete units/widgets). All device com interfaces with the manufacturer's ActiveX interfaces. As an example, I would have lets say a config or XML file that will spell out which tasks, in sequential order, that the system must perform on a "unit". So it may be like

Step1: Pick unit 01 from storage

Step2, Place unit 01 on device X

Step3 Run program 4 on device X

Step4: Move unit 01 to device Y

Step5: Run program 1 on device Y

Step5: Move unit 01 from device Y to finished output station.

 

And basically as soon as unit 01 is done with step 1, unit 02 could begin step 1, and so on.

 

What's making this tough for me is I can't figure out whether something like a state machine or dynamic event style architecture would be better for working through the run file procedures. Then there is also the fact that the UI will also need to respond to user interaction even while running, things like Pausing, Resuming, Aborting, etc... Finally, the program needs to poll the devices to receive confirmation that a step has finished.

 

So in one sense it needs to respond to user front panel interaction, it needs to parse/process/perform the procedure listed in the run file, and it needs to poll the hardware for status & error messages to know when steps are completed.

 

My first thought is use a queued message handler for user UI and sequentially performing the tasks specified in the file. And have a state machine subvi that handles the polling and communicates back to the message handler as needed via a queue.

 

I'm a little concerned with how using a state machine would work for running through the procedures in a file. The steps will not be some fixed enumerated set. I'm having trouble with how to do that as I associate enums with state machines. What about dynamic events? I've not really had a need for those so I don't know enough yet to know whether that would be suitable.

 

But like I said, I'm gun shy about getting started after my most recent experience of deep regret over the architecture I initially began with.

 

I hope this was descriptive enough, I'm looking forward to any comments & suggestions.

0 Kudos
Message 1 of 14
(3,531 Views)

Hi DoctorAutomatic,

 

I would probably use a JKI State Machine for this type of task. You may want a helper loop that will send commands to your instrument and poll it for updates. You could communicate to the helper loop with a queue, and back to the JKI SM with user events. User Events are similar to queues, but instead of using "Dequeue Element", the event structure will handle the event when it has a chance. Also, multiple event structures could listen for the same event, while you would only want a queue to be dequeued from in a single place.

 

If you really like QMHs, you could use the DQMH framework with a couple of modules like, UI, Test Manager, and Instrument. These would communicate via user events, but the DQMH scripting does all the legwork for you.

 

I will try to do a mock-up of the JKI SM idea for you if I get a chance.

0 Kudos
Message 2 of 14
(3,523 Views)

This is an example of how you might add a helper loop to the JKI SM to do the instrument communication and polling. Now, you will have to decide what data type you need, I just used a string/variant cluster. You could create a different user event for different types of messages, or have the message be part of the data and then perform different actions based on that message. This is just to show you some of the elements, it will not run, I didn't wire all the errors, I didn't destroy the user event, but it could show you the big picture 🙂 Also, I used ctrl+alt+drag to make it smaller, so if you actually drag the code into LabVIEW a lot of the JKI SM stuff will be hidden behind structures.

 

Snippet.png

Message 3 of 14
(3,512 Views)

Is there an official or widely regarded link for documentation on this JKI state machine? I'm interested to know the difference sbetween it and just a "regular" state machine is. I think i once used some JKI xml libraries years ago, that I believe I had to pay for, I their state machine an add-on that costs money?

 

Thanks for all the suggestions so far fellas.

0 Kudos
Message 4 of 14
(3,499 Views)

The JKI State Machine is free and widely used. You can find info and tutorials here: https://github.com/JKISoftware/JKI-State-Machine

 

It is just a string-based state machine, that returns to the event structure when there are no more states to execute. The way I code it, is most things are called through a "macro" state, which is just multiple states strung together in a multi-line string. I find it very easy to debug and modify quickly once all my states are built. Sometimes when people pick it up though, they find it a little limiting. Like in your example you want to poll the instrument, which it is not that well suited for, which is why I suggest the additional loop.

0 Kudos
Message 5 of 14
(3,484 Views)

I wanted to add, don't get caught up on the JKI SM. You can replace that with an event handling loop and a message handling loop if you are more comfortable with QMHs. The user event is optional as well, but is very convenient if you already return to the event structure when idle. Instead you could check a queue or notifier (just make sure to set a timeout) to get data from the instrument loop.

0 Kudos
Message 6 of 14
(3,446 Views)

I'd personally stay away from all "one size fit's all" "solutions". All those frameworks solve a few problems, introduce other problems and do not address the real issue**.  They're just general architectures that might or might not fit your needs.

 

I feel a flame war coming on... No need, it's all up to you (the reader not only the OP).

 

That being said: you do need (some sort of) an architecture, so you might as well pick a template you like. But only if you really like and understand it.

 

**

The real issue here is how to parse commands, and execute them in a particular order.

 

I'd make a parent command class, and make each child a particular command. Each command can parse itself if it matches, and a Command Factory method in the parent will simply try all the commands if they match and outputs an array of commands.

 

The array of commands can then be used in a sequencer class, that simply executes the current command for each station, and rotates them each time all stations commands are done.

 

Give the sequencer class and\or the command class pause\continue\stop methods\options, and you're 90% there... No need for Dynamic VI's, call and forget\collect, etc.

 

I'd personally start prototyping this way without any architecture. Just you and the basic building blocks. Then, design and build on that. Eventually a complete application might arise, that will be the simplest solution that does the job.

 

If not, you'll still have reusable, scalable building blocks (commands class, sequencer class), that will work in any architecture because the solution is decoupled from any architecture.

Message 7 of 14
(3,425 Views)

I wonder if a Action Engine would be a good for what he wants to do. I've never had a need to use it, but he does state that "as soon as unit 01 is done with step 1, unit 02 could begin step 1, and so on." If I recall how the architecture works, it could communicate with other steps and let each AE know when the step is finished and keep track of where each unit is at in the process.

 

Like I said, I have never had to use it and I could be making assumptions on how it works too.

0 Kudos
Message 8 of 14
(3,399 Views)

I use a JKI State machine like gregoryj. However, I set up my system a bit different.

 

  1. Every loop in my Main vi is a JKI State Machine.
  2. I communicate  to each loop over a Message Bus. See https://forums.ni.com/t5/Example-Program-Drafts/Message-Bus-Architecture-An-Intro/ta-p/3512280  (I have modified multiple parts of this example, but the idea is the same)
  3. Each Message has a type, command and data payload.
    1. Type means which loop, like Instrument loop, Data loop, etc
    2. Command is a string command to the state machine
    3. Data payload is a variant
  4. For each loop there is a helper loop that filters out the messages by type and only sends the ones that are subscribed to by the loop.

Here are the advantages in my opinion of this architecture:

  1. One wire can send a message anywhere in the program, that is, do need multiple queues, etc.
  2. Event loops have the most flexibility. In my loop I can mix events from DAQmx events or messages from other loops.
  3. I can make other windows pop-up, interact with front panel, send messages back etc.

Just my 2 cents.

 

mcduff

Example architectureExample architecture

 

 

 

0 Kudos
Message 9 of 14
(3,392 Views)

You need more than 1 state machine Period.  You need to do more than one thing at a time so, a single loop won't do.

 

From the brief write-up you will need:

  • A "Move Thing" QMH (Queued Message Handler) with at least these parameters:
    • Init Mover
    • Close Mover
    • Move Start-Station1
    • Move Station1 - Station2
    • Move Station2 - End  - Pass
    • (Likely) Move  Station2 - Fail Bin and  Station1 -Fail Bin as well

Where the stations send request to remove part and request to receive part There is a natural order of precedence in those states and the private data needs to maintain who is full and who is empty HINT: Station 1-Fail Bin is Pri1 followed by Start-S1,S1-S2, S2-F, S2-P.  A correctly written Queue Data type can allow you to preview the queue order by Message Priority (use an enum and sort) and operate on the highest priority move that can be made if any can be made.

  • A Station 1 Test sequence that:
    • Requests Parts (Move request Start to Station 1)
    • Request part removal (To location Station 2 or junk-bin depending on result of test sequence)
  • A station 2 sequence that simply Requests part removal to the correct bin (Sta1 requested to load Sta 2 and the mover will get to it as soon as Sta2 is empty)
  • A Logger to write to the record file for the UUT
  • Some UI to show what's going on where and let the user pause start or abort stuff

Thats the free version- Other versions are available from 8-Ball Consulting


"Should be" isn't "Is" -Jay
0 Kudos
Message 10 of 14
(3,384 Views)