Jump to content


Photo
- - - - -

Re-Designing Multi-Instrument, Multi-UI Executable

lvoop framework hmi messaging

  • Please log in to reply
36 replies to this topic

#21 drjdpowell

drjdpowell

    The 500 club

  • Premium Member
  • 543 posts
  • Location:Oxford, UK
  • Version:LabVIEW 2011
  • Since:1999

Posted 08 February 2012 - 04:32 PM

I must need an AF-Lite...something that allows you to launch an actor, get the queue from it, and then send it messages to tell it what to do. That's it, something a Hard Drive, Air Conditioner, and Fire Suppression can all do: message = start fan, message = increase speed...

I understand having a dynamic dispatch for different types of fans but why does Fan need one for different types of fan callers? I'm missing something fundamental here aren't I?

I too didn’t like that “Low Coupling Solution”. I spent some idle time trying to think of a way to make the “Zero Coupling Solution” simple enough that one wouldn’t ever need to consider the “Low Coupling Solution”. After I while I realized: it already is simpler! Not trivial to see at first. So I think it would be better if the documentation never mentioned the “Low Coupling Solution”, and instead concentrated more on demonstrating how to do zero coupling, and presented it as the standard way to use the Actor Framework. In fact, with a simple guideline, one could write “High Coupled” actors in such a way that they could later be easily upgraded to zero-coupled actors. I’ll try and get this suggestion, with more detail, in the 2012 beta forum (once I’ve figured out how to download the beta software :rolleyes: ).

— James

Edited by drjdpowell, 08 February 2012 - 04:35 PM.


#22 PaulL

PaulL

    Extremely Active

  • Premium Member
  • 462 posts
  • Location:Flagstaff AZ
  • Version:LabVIEW 2011
  • Since:1997

Posted 08 February 2012 - 06:32 PM

There are a few different ways to implement M-V-C. In http://www.amazon.co...28725276&sr=8-1, for instance, the authors show a flavor where the Controller subscribes to the Model's published state, and another whether the View subscribes to the Model state directly.

In our components the Model publishes its state (in both senses, the current parameter values, and particularly a value that describes in which State it is currently, e.g., DisabledState). Each of our Views has the responsibility of deciding what to display based on the value of the State parameter. It is pretty simple to implement this sort of thing.

(There is another flavor of M-V-C where the controller takes a much more active role in determining what the View should display. We have decided to date not to implement that flavor for our purposes.)

#23 monzue

monzue

    Active

  • Members
  • Pip
  • 12 posts
  • Location:Huntsville, AL
  • Version:LabVIEW 2011
  • Since:2004

Posted 08 February 2012 - 09:45 PM


I am running the UI on the control machine but the operator can also access a GUI from a remote machine which will plug in much like Steen's system noted above. I do keep the "business" seperate by making each channel the commander of it's own routines. It runs by itself only receiving change commands through a queue from the mediator. My education from this forum lead me to believe that was the best way to do it. I was going to have each channel write its data to the tdms file as well but maybe I should message the data to a central "Storage" vi and have it write the data??



I am leaning towards messaging the data to a central "Storage" vi and have it write the data. The reason for this is that in one of my projects, I have NOT done this and I am now realizing that I might should have. I simply passed the TDMS reference to my parallel processes, and as the processes needed to write to Disk, I just use the Write to TDMS vi's. This worked, because my file never really needed to change. Now I am wanting to implement a new feature to allow the user to interrupt this constant stream of Data and redirect it to another file. So I need to close the TDMS reference and Open a new File. Problem is that since I passed all the references from a top level down, and I am constantly streaming to disk, I cannot easily change files. If I had used a messaging system back to a storage VI, I could buffer up the data flowing in while the process of closing and opening a new file completed. I would only have 1 place to change the TDMS reference.

I just thought of another way to do this, without using a messaging system back to the "storage" vi. I could go ahead and open another file, then
pass the new TDMS reference to all of my parallel processes, with a message that the TDMS reference has changed.

The advantage with using a single storage VI is that one could parse the data flowing in to determine the correct "point" at which to cut the flow, start buffering, and wait for the new file to open. I feel that it would be much harder to "line up" the TDMS channel streams if a new TDMS reference was simply passed to the parallel loops.
Ben Yeske

#24 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 08 February 2012 - 10:21 PM

How does Controller get data from Model if Model only sends messages to View?

Good question. I agree with AQ. The line between View and Controller is a lot fuzzier than between the Model and the other two. If you're looking at diagrams like the one one wikipedia, my advice is to ignore it and do what makes sense to you. There are lots of ways to skin a cat but they all result in the same thing... tasty soup.

My preference is more along the lines of Paul's "other flavor" MVC implementation. There is no direct communication between the model and view at all; it all goes through the controller. (Instead of a triangle my three components are in a line with the controller in the middle.) The controller is where I put the glue code that translates output messages from one into input messages for the other. I actually don't like calling it MVC because I don't think it's an accurate description. It's closer to a Model-View-Mediator architecture, but that's not exactly right either.


If my controller is running a PID loop commanding Heat & Cool Models how should it get the Temp from the Thermocouple Model? Does thermocouple send value messages to both View and Controller? Does it send a third value message to the data logger?

Depends on your messaging topology. Applications using the observer pattern lean towards a lot of direct point-to-point communication. In these the message source usually sends a copy of the message to each receiver.

I prefer a hierarchical messaging topology. In that system the thermocouple sends out a single Temp message to it's owning mediator, which then forwards it to the next mediator, and so on down the line. Copies are only made if a mediator has to forward the message to multiple destinations.

Or you could always do a hybrid of the two...

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.


#25 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 09 February 2012 - 01:52 AM

If you're looking at diagrams like the one one wikipedia, my advice is to ignore it and do what makes sense to you.

Yup, looking at that while you were writing this...now looking for eraser...

...tasty soup

You've been to Kazakhstan too 'eh?

I’ll try and get this suggestion, with more detail, in the 2012 beta forum (once I’ve figured out how to download the beta software :rolleyes: ).

Looking forward to it. Does NI only allow beta downloads from USA? Texans never could play nice with foreigners. :P

The controller can also listen in on those same messages...

I think I'm getting how to do that but now I'm looking forward to the example in 2012. It's only 638 MB away...630MB!

#26 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 09 February 2012 - 05:24 AM

if you join the LV 2012 beta program, the beta of 2012 went live today and there's a shipping example in there for exactly this with the AF.

I have searched extensively and cannot find the example anywhere in the 2012 Beta. Could you point me to it please?

#27 todd

todd

    Very Active

  • Members
  • PipPipPip
  • 217 posts
  • Location:Seattle
  • Version:LabVIEW 2011
  • Since:2002

Posted 09 February 2012 - 06:39 AM

I have searched extensively and cannot find the example anywhere in the 2012 Beta. Could you point me to it please?

It's right on the Getting Started Window (new project from template, or so). See the beta forum for an update to the sample project, though. Arg, this doesn't count as talking about the beta, does it?

#28 Aristos Queue

Aristos Queue

    LV R&D: I write C++/# so you don't have to.

  • Premium Member
  • 2,620 posts
  • Location:Austin, TX
  • Version:LabVIEW 2011
  • Since:2000

Posted 09 February 2012 - 02:37 PM

It's right on the Getting Started Window (new project from template, or so). See the beta forum for an update to the sample project, though. Arg, this doesn't count as talking about the beta, does it?

Yeah, it kind of does, but I won't tell the Powers That Be if you don't...

jbjorlie: Read the beta forum for comments from me about this.

#29 PaulL

PaulL

    Extremely Active

  • Premium Member
  • 462 posts
  • Location:Flagstaff AZ
  • Version:LabVIEW 2011
  • Since:1997

Posted 09 February 2012 - 05:35 PM

I actually don't like calling it MVC because I don't think it's an accurate description. It's closer to a Model-View-Mediator architecture, but that's not exactly right either. Depends on your messaging topology. Applications using the observer pattern lean towards a lot of direct point-to-point communication. In these the message source usually sends a copy of the message to each receiver. I prefer a hierarchical messaging topology. In that system the thermocouple sends out a single Temp message to it's owning mediator, which then forwards it to the next mediator, and so on down the line. Copies are only made if a mediator has to forward the message to multiple destinations. Or you could always do a hybrid of the two...

This is somewhat tangential, but the Gang of Four folks (pp. 5-6) consider M-V-C a composite design pattern, where the individual design patterns are Observer, Composite, and Strategy.

#30 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 10 February 2012 - 08:18 PM

In our components the Model publishes its state.

My preference is more along the lines of Paul's "other flavor" MVC implementation. There is no direct communication between the model and view at all; it all goes through the controller. (Instead of a triangle my three components are in a line with the controller in the middle.) The controller is where I put the glue code that translates output messages from one into input messages for the other. I actually don't like calling it MVC because I don't think it's an accurate description. It's closer to a Model-View-Mediator architecture, but that's not exactly right either.

I prefer a hierarchical messaging topology. In that system the thermocouple sends out a single Temp message to it's owning mediator, which then forwards it to the next mediator, and so on down the line. Copies are only made if a mediator has to forward the message to multiple destinations.


Excusing my horrible flowchart design, are we talking about something like this?

Untitleddrawing2.jpg

Edited by jbjorlie, 10 February 2012 - 09:01 PM.


#31 PaulL

PaulL

    Extremely Active

  • Premium Member
  • 462 posts
  • Location:Flagstaff AZ
  • Version:LabVIEW 2011
  • Since:1997

Posted 10 February 2012 - 10:45 PM

Excusing my horrible flowchart design, are we talking about something like this?

Well, Dave and I are advocating different things.
In practice, our project uses a hybrid approach. This is from our presentation last August:
MVC.PNG
Description:
A user clicks a button on the view. The view code handles the button event and publishes a value (a demand). (Note that another view or controller in the application can publish this same demand, if we so design it. This is great for designing a hierarchical system.)
The "Data Listener" for the component subscribes to all relevant demands (really any input data) for that component, and upon receipt of a new demand creates a corresponding Command object (see Command Pattern), which it publishes. Hence the Data Listener is a sort of mediator, I suppose.
The Controller subscribes to Command, and responds accordingly. When there is something to do it invokes methods on the Model.
The Model changes state as appropriate, and publishes updated aspects of its state to appropriately named topics.
The View subscribes to these state topics. When a value change event occurs, it updates the appropriate indicator. (Binding the indicator to the shared variable is another way to accomplish the same thing in the very simplest cases.)
Note that multiple Views can subscribe to the same information.

We have implemented a number of systems now and I think this is really quite elegant.

[Some details: We actually use programmatic access to SVs. Also we right justify and fix the digits for numeric indicators and use proper units. For this and other reasons we use events rather than shared variable binding in most instances.]

#32 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 11 February 2012 - 12:13 AM

In practice, our project uses a hybrid approach.

I assume your "Model" is self sufficient and processes internal events through its own "mediator(s)" thingys? If not, what happens when a change in the process value necessitates some additional actions on behalf of the model? Overheating! Turn heater off, ... Does that go through the VIEW and back down? Maybe I am assigning too much responsibility to the Control and it should not be doing things like running PID loops?

With that in mind, this updated flowchart may be inaccurate but I would appreciate more feedback on this:

Untitleddrawing (3).jpg

#33 Daklu

Daklu

    Bringing the Fu to you

  • Premium Member
  • 1,752 posts
  • Location:Seattle
  • Version:LabVIEW 2009
  • Since:2006

Posted 11 February 2012 - 12:35 AM

Excusing my horrible flowchart design, are we talking about something like this?

Close. What you show is more of a mixed model. A strict hierarchical messaging topology looks more like this. (I don't know what those symbols mean in a flowcharts, but here it just represents one "thing" and multiple "things.")

Capture.PNG

A couple things to note:
1. The "things" on the diagram do not represent individual vis or even classes; they are loops. IMO loops are the fundamental unit of execution.
2. The hierarchy represents "is responsible for," not "is dependent on." A vi containing a sub loop may or may not be on the block diagram of the mediator vi. I think it's easier to start with the responsibility tree matching the dependency tree, but it is not a requirement.
3. The purpose of a mediator loop is strictly message routing. They don't do any file IO, VISA commands, etc. This helps prevent message queues from getting clogged.
4. The messages the mediator loop accepts from and sends to "higher" loops define the public api for all the functionality below it. Mediator loops also handle message routing between its immediate sub loops. (i.e. Messages always go up or down; they don't go sideways.)
5. The diagram shows the controller being responsible for the UI and Model components. In truth any of them can be responsible for the other two--it just depends on your goals. It's probably most common to use the UI as the root.

There's a lot of other little bits of information rattling around in my head... I'd better stop there lest I get too long winded.

...what happens when a change in the process value necessitates some additional actions on behalf of the model? Overheating! Turn heater off, ... Does that go through the VIEW and back down? Maybe I am assigning too much responsibility to the Control and it should not be doing things like running PID loops?

This is just my opinion, but the model should be self sufficient except where user interaction is required. I'd definitely put temperature monitoring and automatic shutdowns in the model.

Certified LabVIEW Architect
Dak's First Law of Problem Solving: If the solution looks simple, I don't know enough about the problem.

Yes, the QSM is flexible. So is Jello. That doesn't make it good construction material.

There are two secrets to success:
Secret #1 - Never tell everything you know.


#34 PaulL

PaulL

    Extremely Active

  • Premium Member
  • 462 posts
  • Location:Flagstaff AZ
  • Version:LabVIEW 2011
  • Since:1997

Posted 11 February 2012 - 01:14 AM

I assume your "Model" is self sufficient and processes internal events through its own "mediator(s)" thingys? If not, what happens when a change in the process value necessitates some additional actions on behalf of the model? Overheating! Turn heater off, ... Does that go through the VIEW and back down? Maybe I am assigning too much responsibility to the Control and it should not be doing things like running PID loops?

OK, the Controller executes Commands, which simply invoke methods on a Context (see Command Pattern). The Context methods (also trivial) delegate their instructions to State methods (see State Pattern) that implement a state machine.
The State methods invoke Model methods directly (OK, via an interface).
The State methods determine which Model methods to call based on:
1) A new external trigger (user interaction, message from another system)
2) An internal trigger (overheatingIsTrue). The Model has a method that calculates that overheatingIsTrue (and will create an error or warning as appropriate) but it does not determine what to do in that circumstance. The state method does. This is actually quite important.

To reiterate, the State methods know what to do but not how to do it. The Model methods just now how to do what they are told.

By the way, we treat an interrupt or other start loop trigger as just another instance of an external trigger (external to the controller thread, but running on the the same hardware in the same application). This simplifies things dramatically.

Within our State methods we have exactly two methods where we wire an error cluster input to a case structure!

[By the way, I view the state machine as part of the controller, not the model. I think the definition of the two is sufficiently ambigous in the literature I have read that you could alternatively define the "model" to encompass what I am calling Context, State, and Model here.]

#35 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 13 February 2012 - 08:44 PM

Great information fellas, I hope I can return the favor somehow someday. Thank you, I had the model looking more like the set of instrument drivers and not the loops that control them. Now it is much more clear how I should be approaching this AND how to name what.

There are many more questions coming but I need to take what I've learned and put it into action first. Also, I'm leaving the Actor Framework to a smaller project in LV2012 and walking the LapDog through this one :yes: It sure is tempting to try and use them all though! Why is it so painful and expensive to be an early adopter? :throwpc:

#36 Steen Schmidt

Steen Schmidt

    Very Active

  • Members
  • PipPipPip
  • 95 posts
  • Location:Denmark
  • Version:LabVIEW 2010
  • Since:1998

Posted 13 February 2012 - 08:55 PM

It's not so much early adoption as it is hours spent up front instead of 10-fold on fixes and more fixes. A well designed application is more or less hitting the ground running, and you can focus on adding functionality or the next application instead of perpetually fixing the old ones.

So the pain you feel is just because you do all the work up front, and the sum of it is much less than if you look back at the work put into a poorly designed application :).

Cheers,
Steen

PS: I hope the "holiday dinner" feeling has faded - for the record I believe the debate about using Shared Variables or not is very much in synch with the topic (if that was the topic you felt sidetracked your thread a bit here). My experience with SVs, which I described here, was a direct response to your "I now see no reason to avoid shared variables for sharing data between vis when only one vi is ever going to write to them" statement. And that experience didn't come cheap. Just for the record. Didn't want to swamp your voice :P.

Edited by Steen Schmidt, 13 February 2012 - 08:56 PM.

CLA & CTA

#37 jbjorlie

jbjorlie

    More Active

  • Members
  • PipPip
  • 31 posts
  • Version:LabVIEW 2011
  • Since:2011

Posted 13 February 2012 - 09:38 PM

A well designed application is more or less hitting the ground running, and you can focus on adding functionality or the next application instead of perpetually fixing the old ones.

Very good quote! If I ever throw that into a presentation I'll give you credit.

As for the holiday dinner, it wasn't so much of getting sidetracked than of many related but distinct conversations going on at once. Not bad, just hard to follow for my experience level. Thanks for all your input, I am glad you came back with some pitfalls of SV's and I am now thinking of messaging all my process values, LED's and whatnot. The result will depend on my skill, I suppose, and if it is too slow or creates too much complexity in message handling I may give your vi registers a try for those needs. The registers are completely self-sufficient, yes? If I remember right, they just drop onto the block diagram without the need for any database or administration type vi's? Do you think they will be highly portable to future LV versions?





Also tagged with one or more of these keywords: lvoop, framework, hmi, messaging