LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Question for Producer Consumer with State Machine Consumer Loop

Dear forum

 

I am working on the basic architecture for an application I need to build.  I think I have grasped the basics of what I'm trying to do, but would really appreciate a glance at my code from someone experienced in LabVIEW.  I've attached a VI that runs, but it has dummy comments instead of working code.  I will use the Producer to handle the UI, and the Consumer Loops will deal with state machines for assemblies of hardware for data collection and sample manipulation. Sometimes not all the hardware will be present, so I don't want them to it to try to initialise unless a button is pressed.  If I should provide a better explanation please let me know, but you can get a pretty good idea from running it!

 

I have a couple of questions:

1. I was unable to find examples of this type of program online, which worries me.  Does that mean I didn't look hard enough, or that I am over-complicating things and there is actually an easier way?

2. Does the general construction and flow of the program look OK?  I'm not looking to win any prizes, but I'd like to know if there is anything glaring!

 

I'd really appreciate feedback as there is nobody here who can comment, so this would be a good 'sanity check' for me.

 

Many thanks.

0 Kudos
Message 1 of 10
(5,566 Views)

The overall structure looks good.  

When dealing with the control of a State Machine, you should use a Type Def Enum for the states (passing enum constants as the Queue Element) instead of a string.  Less prone to error and easily updated from the Type Def when adding new states.  I tend to pass a cluster of the state enum and a variant, allowing any state to easily pass information to another.  Simply use "To Variant" and Bundle when you Enqueue an element and then use the Variant to Data to convert back to the proper data type.  This allows multiple producers to trigger the same consumer state with relevant parameters; instead of using local variables within the consumer state.  You just need to configure each state to convert variants to the required type (or ignore if nothing is expected).

 

On a side not:  I would recommend naming the Queues (Obtain Queue).  In the event you need to utilize another VI running in parallel, it will be able to gain access to those queues by using Obtain Queue with the appropriate name.  

Message 2 of 10
(5,546 Views)

Thank you very much!

 

I found the following example: https://forums.ni.com/t5/Example-Programs/Using-Variants-to-Pass-Multiple-Data-Types-Through-a-Singl... which I will use to tell me more about using variants - I think it is what you are suggesting.

 

In the meantime I am trying to convert the states to a TypeDef Enum, but have broken everything and I am getting the error "Wired refnums are of different types.  The type of the source is Queue Refnum.  The type of the sink is Queue Refnum."  Just when I think I beginning to understand LabVIEW...

 

I will see if I can get it to work and perhaps re-post it in case that is useful for anyone.  Thank you again.

 

0 Kudos
Message 3 of 10
(5,528 Views)

The "Element" datatypes of your Queues must not match at some point.

 

1) ensure Obtain Queue using the "enum"/"variant" cluster to establish the data type of the queue.

obtain queue.PNG

2) Ensure each "Enqueue Element" uses the cluster as an input (use a null variant if passing no data)

enqueue.PNG

3) Since you are using Bundle by Name to pass the two Queues together in your Producer Loop, make sure the input cluster matches your actual Queues

0 Kudos
Message 4 of 10
(5,522 Views)

I think it was the Input Cluster of the Bundle by Name that was the problem.

 

Despite your good advice, I haven't added the variant data to my queue yet - but I have managed to change the states to a TypeDef.  As far as I can see, my data will always be passed from front-panel controls.  I have learnt a lot from what you suggested - much easier in context.  I shall have to see if I can go on a training course.

 

I've attached my VI, which I hope looks in better shape than before!

 

Edit: I also note the coercion bullet in the Enqueue Element for Loop 2, I guess pointing out that I am using the state TypeDef for Loop 1.  I think that's probably OK, since I will set default cases that ignore unwanted commands.

 

Download All
0 Kudos
Message 5 of 10
(5,513 Views)

Your second consumer loop1 is a mishmash of state machine and queues! This will lead to issues and you are mitigating it by adding stop cases in two separate states which is not a good idea as this will become unmanageable as your software grows. You can enqueue states to the queue within consumer loop itself. Use enable / disable controls to guide your user. I'd recommend TLB if you are able to take in a slightly complex architecture: https://forums.ni.com/t5/Reference-Design-Content/Top-Level-Baseline-Prime-TLB-Application-Template/...

 

I have edited your VI to give you an idea of what I am talking about. Sorry I had to disconnect all typedefs as you hadn't attached those.

 

P.S: Using Strings instead of enums are often preferred in a multi process application as you don't have the enum coupling between instances. In a single VI / project or for someone starting out, enums are a good starting point for queue messages.


CLA CTAChampionI'm attending the GLA Summit!
Subscribe to the Test Automation user group: UK Test Automation Group
0 Kudos
Message 6 of 10
(5,501 Views)

That coercion dot for typedef enums should be fixed right away. An enum is just a number, and it doesn't know that "initialise" from your first typedef is similar to "initialise" in your second typedef, it is just going by order. So for instance, if you have the following states for your typedef:

 

Enum1: Initialise, Measure A, Stop

Enum2: Initialise, Measure B, Stop

 

Then you are probably ok... for now...

 

But later someone tells you that you need new functionality, and you forgot that you were throwing enums around willy-nilly, so now you have:

 

Enum1: Initialise, Measure A, Stop

Enum2: Initialise, Measure B, Launch Missile, Stop

 

Now sending a "Stop" message might stop your first loop, but tell your second loop to launch a missile Smiley Surprised

0 Kudos
Message 7 of 10
(5,497 Views)

Ace,

That template looks interesting.

Do you have an example of the TLB architecture showing some complexity?  The base template makes some features a little difficult to follow (like registering events for the Event structure within an Event structure).

0 Kudos
Message 8 of 10
(5,462 Views)

Thank you very much .aCe.

 

I installed the TLB' example, but I'm afraid I am not ready to take in that complexity of architecture.  Your edited VI, however, makes good sense and I really appreciate it - thank you.

0 Kudos
Message 9 of 10
(5,436 Views)

gregoryj,

 

Thank you, excellent example and I feel a little daft now.  Luckily I don't have the capability to launch missiles, but still...

0 Kudos
Message 10 of 10
(5,433 Views)