Jump to content

todd

Members
  • Posts

    335
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by todd

  1. At bottom is the probe results, showing (to my interpretation) a simple array of strings as input and the anomalous cluster of single-string arrays as output.

    It is a cluster of strings, not of string arrays. The names of the cluster elements are derived from the indices of the input array - "[0]" is the name of the first string array element. With context help open, hover the wiring tool over the output of Array To Cluster to see its type.

  2. ... your asking if a message logger could automatically be attached inside the "Create" methods, thus making logging of all messages automatic while hiding this fact in the top-level diagram. Correct?

    Yes. I believe you were asking for a different kind of comment, but it's all I have :)

    One could easily create a "Create and auto-log" VI that does exactly this, encapsulating the currently existing functions, and setting up a logger that records all messages to the created Messengers. Personally, I wouldn't use this, as I don't actually want all messages logged except when I'm debugging, and when I am logging I want this fact to be very clear from the top-level VI. What is logged and where isn't something that should be hidden, IMO.

    Ok. I like to put the debugging/logging code in each component (each one for me tends to be just different enough). And I can select debugging capability separately in each component, depending on what I'm looking for.

  3. ... the instrument would be a class, but it would also have other (unrelated) classes "inside" of it, right? So inside some of the methods for the instrument class, I would need to call methods of another class for communication (with children for tcp/ip, modbus, serial or whatever is appropriate for the instrument)?

    ...

    I might just pick my poison and start traveling down a path and see where it leads.

    ...

    The masochist in me wants to pick the ACTOR framework just because it seems very complicated and feature rich. :)

    I'm not much ahead of you on the LVOOP curve, but my take is that you need to code something up and see what happens. A "simulated" instrument class may help during early development. Actor Framework or daklu's create.vi and execute.vi loop are very good starting points for encapsulation. I have custom instruments with different evolving capabilities, and I'm having success (so far) grouping their classes all together in create.vi as private data in the instrument's class.

    Unfortunately, there is quite a bit of work to set up simple proof of concepts in LVOOP.. or rather, it seems that way now since everything is new to me still.

    It's not that much work, after you get used to it.

  4. All of the examples run, here. The only comment I have is somewhat superficial and simplistic (meaning not entirely thought through): since the logger display is called by reference based on a relative path, couldn't it somehow be included in the Create.vi of CommandMessenger[A,B]? Then, instead of the observer being CC'd in the Controller, the Messenger's "Receive" could send the copy. I'm thinking only of keeping the top level VI's diagram simple.

  5. Here is most of the state of my noodling with this. Some obvious stuff is left out (gracefully stopping some loops; low-level VISA and other comm methods; proprietary stuff).

    main.vi is the top-level VI. Some goals (maybe I should have written these BEFORE coding - just kidding, I knew this would be an iterative approach):

    - Provide simple access to instruments in test VIs, as in "Test 1.vi"

    - Allow one-time selection of instrument "descriptor" data from the top-level (hide the controls and use INI files for production code), as in main.vi. In fact, such an INI file would eliminate the notifiers in main. But I need to be able to choose them for now.

    - Provide a live front-panel for each instrument, as in Execute.vi

    - Allow simulated instruments with live front-panels and with APIs, as in Execute.vi

    - All instruments must support immediate response data, as in Version.vi

    - Some instruments must support streaming data with multiple versions of data manipulation, as in Execute.vi and "Read and Queue Bytes.vi". Kind of. My current real app does dynamic dispatch of Execute.vi, but does not have some aspects properly abstracted - such as the comm method (serial vs dll - each with their own versions) and data parsing.

    It still "feels" as if I haven't got the traditional kind of OO philosophy, but if I can just find the right place to override methods and encapsulate data, I'll be in flexibility heaven.

    It also feels as if the controls and indicators on Execute.vi could all be private class data.

    Sample Project.zip

  6. I'm still swimming here, so here's the standard disclaimer: beware my imprecise and disorganized statements below!

    I'm finally beginning to understand this thread, and I have a question that relates to Steven's about multiple "execute" slave loops that handle the same type of instrument: Why not use non-classed VIs for create, execute and destroy and make them reentrant? Is classing "create" and "execute" just a handy way to bundle up the input queue, output queue, object, and mediator's queue? Oh, perhaps this:

    -When using multiple slaves, I don't have to worry at all about accidentally sending a message to the wrong loop. The slave object can only be wired to it's own methods. Again, a mistake here is a compiler error instead of a runtime error, saving me a bunch of time down the road.

    I made an API (set of VIs) that basically just send/receive messages to/from the slave's input/output queues. If the APIs are methods of a class, they have to match the object (bundle of queues) sent to them. I don't like having the instrument's object available in the mediator loop, though.

  7. You slipped a couple posts in there... I guess I'm getting too long-winded.

    Or I'm being too impatient :)

    I agree the other terms don't quite fit. Sometimes people just call them threads, but that creates confusion between LV threads, OS threads, and CPU threads. Besides that it doesn't relay any information about the intent of the loop. Instrument loop is as good as anything... at least for this thread. :blink:

    They are both "actors"/"active objects"/"slaves"/whatever.

    Actor Slave Object Loop: ASOL - everyone has one! Ha! (Nothing like sophomoric humor.)

    When the app starts your instrument loops start running. The tests are top-level vis that are dynamically launched when users request it. You pass the instrument loop's input and output queues to the tests so they each can communicate with the instrument loop.

    I'm just now "internalizing" that an output queue is actually required. I just have to massage my existing data queues to output data the same way as an immediate measurement.

    You also plan on creating other top level vis to simulate instruments and stuff. Did I get that right?

    Exactly - but just a single top level VI to control the simulated instruments.

    Potential problems: First, each message on a queue can only be dequeued once. How are you going to get messages from each instrument to all the top level vis that want the information? You have to create copies somewhere along the line. You can make the instrument loop observable and have other loops register their own input queues with it. Or you can have the instrument loop send all it's messages to another loop (mediator,) which in turn creates copies and sends them to the receivers. I prefer to split the functionality and keep each loop's responsibilities separate and distinct.

    I strive to make things as simple as I can. That said, I consider my current confusion a result of being mid-way through a programmer's continuous learning process that you mentioned in another thread, once.

    Second, the idea of injecting an instrument's queues into a top level vi so the vi can simulate the instrument seems backwards to me. Isn't that why you have a Digitizer Simulated class? Subclass your simulated instruments directly from the instrument they're simulating.

    And that is exactly the type of simple answer that I've missed. I shall do it this way.

    I have a simulated Stage object I use. When the creator executes it launches a front panel allowing me to manipulate encoder feedback and see how the app responds. It's great since most of my dev work is done away from the hardware. Better yet, switching between simulated and real hardware is as easy as replacing the class creator.

    Exactly my intent. I use an enum to choose the class that gets created.

    Third, I'm curious how you are preventing tests from interfering with each other. If tests a, b, and c all send messages to instrument 1, are you running the risk of having the tests issue conflicting commands?

    A second comment I have is about running multiple "Tests" in parallel, which I get the impression you're trying to do. If that is the case, it may be a good idea to add the ability for a Test to "lock" an instrument so that it can't be simultaneously used by other Tests, to prevent potentially dangerous conflicts.

    At the moment, if an instrument is being used in one test, any other test that tries to use that instrument will throw an error. This is not entirely built out, but I consider it my responsibility to understand the complexities required to support this kind of flexibility.

    I see.... would you be at 'F' in Everett? I spent several years writing test software to support hardware development activties. It's a challanging environment. Speed tends to take priority over everything else and it's hard to convince managers of the long-term benefit of good code.

    PM about my location (with which you are familiar, according to local NI folks) is forthcoming. I live near 'F', though. So far, the development cycles have been beneficial in that I have time (and my manager gives me leave, as long as stuff works when needed) to iterate the test architecture - with the help of experts, here.

    I would suggest that, whatever design for a parallel process you decide on, use the same one for both "Instruments" and "Tests". They are both "actors"/"active objects"/"slaves"/whatever.

    ...

    Settle on one design that works for both and perfect it.

    This is an intriguing concept, and I have been wondering how soon I would have to try to instantiate a class of test the same way as an instrument actor.

    For example, I've been developing a design I call "Parallel Process". I have a parent class that contains the "Launch" (Create) VI that dynamically launches a VI, sets it up with a command messenger (message queue) and wraps that queue inside the parent object. All my... let's standardize and call them "actors"... inherit from this class (I have a few templates that I copy from). As each actor is standardized, each is created by the same parent "Launch.vi", and once that VI is debugged I never have to worry about the details of dynamic launching. And the child actor classes are very simple; generally with no additional private data items, no additional methods or overrides, and only one VI (the one that is dynamically launched) copied from a template. The complicated stuff is all in the parent class. Note that once you have the basics of a VI dynamically launched and running in parallel, sitting behind a command queue, you have all the ability to customize it. Your "Create Test.vi" could (after launching) send your Test a message containing a cluster of "Instrument" proxy objects (ie. objects that contain the command queues of your instruments). Your "Create InstrumentA.vi could send messages containing the information needed to configure InstrumentA.

    Excellent! This will be by next peak to ascend.

    Regardless of what design you go with, try to get complicated stuff like dynamic launching and messaging standardized into clean reusable components (such as in a reuse library or a parent class) so that you can deal with the complexity once and then not have to worry about again.

    This is an excellent method, and one toward which I've iterated towards over the last two months of my re-immersion into LabVIEW.

    Thank you both!

  8. Ahh - it's nice to be able to follow 99% of your post! (Not sucking up - just happy that I'm getting it.)

    By the way, thanks for your time.

    Broadly speaking there are two ways of sharing a resource among parallel processes

    I finally understood this last week - helped along by Evil AQ. My next hurdle was/is making it happen, and sharing the interface with a few other VIs.

    The loop's error out is wired to ReleaseQueue for sequencing.

    That makes sense. I've used an error cluster constant just inside the while-loop for that sequencing.

    Errors are in a SR because the Dequeue method looks for errors on its error in terminal. When it finds one, instead of dequeuing the next message it packages up the error in an ErrorMessage object and spits it out in a "QueueErrorIn" message.

    Ah! I missed that. I like it! I used to put a dequeue timeout case that just checked for errors on the SR.

    Overall my approach to error handling in slaves may be a little different than what is common. I don't terminate the loop on errors.

    I've just been throwing in Simple Error Handler.vi, during development. I like the possibility of logging errors after deployment, though.

    The thing that immediately jumps out at me is you'e wired a MessageQueue constant into the Digitizer Execution Loop. That won't work. You have to use the Create method. I realize you probably did that so you could run the vi, but I wanted to make sure the requirement was clear.

    Yes, quite clear. I was coding out loud. I'm not yet unhappy with the two-way notification shown in post #16 above.

    Your simulated and custom Digitizer classes inherit from the abstract Digitizer Base class. In general I have discovered abstract base classes tend to get in the way unless you have very specific and well defined reasons for using them. I make better progress by starting with a concrete class. I'd just use the Custom Digitizer class and subclass the Simulated Digitizer from it. Others probably have different opinions.

    Later on if you need other digitizer classes with very similar behaviors you can make them subclasses of the Custom Digitizer as well. If the other digitizers implement different behaviors you can then subclass them all from a common parent, or create a separate class hierarchy and delegate to the digitizer classes. (I usually like delegation better.)

    The instruments I use can vary wildly (in many ways) over their development cycle, and I need to support each version. The abstract class helps me flesh out the simplest methods to expose, and to drop the simulated one in place so I can write tests before the instrument arrives, or before announced functionality is added to the real metal. I didn't really plan it that way, but I'm happy with it, so far. (I haven't seen delegation - time to study.)

    Regarding where to put the Create and Execute vis, creating a DigitizerSlave class too early can slow down development because you're shuffling back and forth between the two block diagrams to make sure all your message names and message types stay synched up. I usually start the slave loop on the same block diagram as the master and push it down into a slave class if the need arises. (Though dynamically launching the execution loop does qualify as "need.")

    I usually start loops that way, too, just to see what inputs they need when they're sub-VIed (before I have a standard for the current project). I have enough screen real estate to have them all open, and I have several existing loop objects that I will massage into the new message standard.

    Thanks, again!

  9. It sounds complicated

    "If I can't explain it simply, I don't understand it well enough."

    There is a communication reference (often a queue) that allows communication with a loop (on diagram or in a subVI). This loop contains information about, and methods to act on, a real-world instrument.

    Yes! What is that kind of loop called? I call it the Instrument Loop. "Driver" almost works, except that term tends to be reserved for the lowest-level functions. "Actor" almost works, given AQ's definition of it as state data in a module - however, the loop itself is more like his Actor Core.vi instead of the Actor.vi which spawns it. "API" almost works, because the messages handled by that loop (which are, again, the ONLY way to act on the real-world instrument) are the only messages allowed - except the API is actually the set of VIs that wrap possible messages. In my code so far, the Instrument Loop carries an instrument's class in a shift register. The instrument's class provides the inherited methods (such as "Take a Measurement" and "Set Scan Rate") that call some level of the instrument's driver.

    Now, there is more than one place to use a LVOOP class in the above design, and more than one thing that can be referred to as "the instrument class". The place I think your using is the latter part: the information about, and methods to act on, the real-world instrument. That's a perfectly good place to use a class, the most obvious place, and useful for various reasons, but I would never want to use that class as "the instrument" in the higher-level code. The entire structure is "the instrument", and the communication reference out front is a "reference to the instrument".

    Please pardon my lack of clarity, and thank you for taking the time to correctly suss things out. One note that is beside the point: I do make the Instrument Loop VI a method in a class, because several of the real-world instruments require loops that are parallel to the Instrument Loop (similar to the Image Display Loop in daklu's image here: http://lavag.org/topic/15089-dequeue-element-timeout-state-control/page__view__findpost__p__90891). Also, each Instrument Loop has a "Show" message so it's front panel can be brought up - so the Instrument Loop also has a paraller User Event structure loop (which only uses the available Instrument Loop message API. But I still consider those parallel loops part of the Instrument Loop functionality.

    If you look at my designs, the LVOOP classes with instrument names are actually just wrappers of a communication reference (or references). And these are effectively by-reference objects; they can be easily passed around and used in multiple places (no problem with branched wires). They serve as a proxy for, and encapsulate, the entire structure of communication, loop, data/methods, and real-world hardware. To interact with the "instrument", I send a message to this proxy object (or call a class method that sends a predefined message), which passes the message to the loop, which performs the appropriate action on the internal data or communicates with the real-world instrument.

    If I have second, by-value class for the instrument data and methods, it is accessed only internal to the loop, and never "passed across BD lines". If your trying to pass this by-value object between different loops, that sounds like a rather complicated and troublesome thing to do.

    I've only been back on these forums for the last few months, and have been looking at every VI I can find - ramping up on inheritance. Now that the terminology is better defined - at least in this thread - (Instrument Loop is the only place to communicate with a real-world instrument; API is the set of messages that can be sent to the Instrument Loop), I can be clear about the problem:

    Think about the one-panel VIs many people start with: open a VISA session, initialize an instrument, take several measurements, save data to file, close the VISA session. Now imagine a top-level VI like the one in Daklu's post mentioned above. Add a button to the front panel called "Run Test 1". The User Event structure tells the Mediator Loop to run a one-panel VI (invoke node, do not wait for completion). I want to send the by-reference message queues to the one-panel VI so it has access to the real-world instruments via the Instrument Loop's API. I also want the by-reference message queues to be available to another top-level VI so messages can be injected (typically used for simulating instruments that are not present, or that don't have fine-enough controls for checking the test's logic).

  10. Named queues, on the other hand.... *shudder* ... Or you can create it internally as part of the constructor and wire it to an output terminal on the creator.

    Yeah, named queues haven't bit me, yet - but I've been making single application instances, so far. I like it the idea of sending a slave queue out - trying it now with non-OOP Create + Execute. Baby steps.

    Pfft... see? You're already using slaves. ... Then instead of using a USR for maintaining state you store it as private class data.

    Yes, exactly! Just have to figure out how to transport their control across BD lines. I'm picturing having the Execute method hold the class (with its private data) in a shift register - example below.

    You already have a queue going from the robot loops to your controller. Why don't you just send it as a message?

    Because I haven't figured out how to send all instruments' classes into invoked test VIs - although now I'll try bundling up all their message queues and passing them in. I like this idea because it allows me to send that bundle to the simulator loop, too!

    There's a common perception LapDog.Messaging is really complicated that I don't quite understand.

    It's not difficult, now that I've used it. It's just a matter of taking the time to build up an app - starting from your example. Little extra for filling in error handling, etc. I'm still at the point where I'm trying to figure out why you wired a loop's error out to the error in of ReleaseQueue.vi, and why errors are in SRs.

    Here's my initial attempt. I used LapDog - just to keep your attention. :) I haven't yet figured out where to put the Create and Execute VIs (not yet classed, as mentioned above). Perhaps a "dispatcher" loop at the top-level that receives Create-required information and spawns Execute loop VIs - don't know, yet.

    post-107-0-30169700-1319250849_thumb.png

    Sample Project.zip

  11. Here's what I've been mostly using - except that the two lower while loops are in subVIs, and they each have Init or Open cases that store an instrument class in a USR. Also, I name the queues and create a helper VI for each queue/loop that obtains the named queue and enqueues elements.

    One problem I'd like to solve is the most useful way to return data (haven't wrapped my head around lapdog or anything, yet). Sometimes I put it in a "global" data AE in a parallel loop in the instrument's handler VI. Also needed is a cleaner (more debuggable) method of talking to the instruments' queues inside test VIs and from the simulator (a separate loop at the top level that listens to another set of buttons and sliders - so the water-spraying can be tested without first setting fire to the city).

    Another problem is "instantiating" multiple instances of an instrument's loop without duplicating code. I've "classed" the instrument loop (several of the same kinds of instruments behave differently), but that pushes the instrument class creation into the top-level loop, which I don't like. I'd like to create the object in the top-level and send it as the variant to the instrument loop, except the instrument loop is a method of the class...

    post-107-0-01805700-1319228328_thumb.png

    Robot Usage.vi

  12. I'd love to see what he did.

    It was really slick. He could identify all instruments on several different busses/comm methods (including custom), show them all to the user, and allow them to select names for them all. Saved the config to a file for later automation. He's in Lynnwood.

    Well-named and well-segregated sub vis are your friend. :thumbup1:

    Then I have made a lot of friends! :)

    Okay, time to put some nodes where my mouth is. I know I've seen many discussions about this on LAVA (duplicate class wires make a new copy of the object), but I'm not ramped up, yet. All I can come up with is that I need a SINGLE VI that can access the specific instrument's class. Not there, yet.

    post-107-0-73527500-1319225821_thumb.png

    Personally, I usually find it worthwhile to give each instrument a VI running in parallel that handles all communication with it.

    ...

    Think of this as a higher-level driver for the instrument, which the rest of the program manipulates.

    You can use a class to represent or proxy for each subsystem or instrument; this class would mainly contain the communication method to the parallel-running VI. Daklu's "Slave loop" is an example. You can either write API methods for this class (as Daklu does) or send "messages" to this object (which I've been experimenting with recently).

    Yes! This is what I've converged upon. But I have resorted to using named queues with the "standard" string+variant to handle all of the instruments' handles/actors/slaves. I'm searching for a method that, for lack of a better term, "feels better than" passing commands via named queues. For example, some instruments have a method that gathers streamed data and adds it to an AE. Other instruments just have simple read/write access. Just haven't unified them, yet - not for the sake of unification for its own sake, but for ease of use of the reusable API.

  13. Have you found an example anywhere?

    No. For the last few applications, I managed to keep the code modular enough that refactoring was basically painless - but I can see a ceiling to the scalability. Reading the discussions, here, of everyone's design patterns has helped immensely. If you have time, create a bunch of classes with fake instruments and do trial-and-error. If you have money, follow Daklu's advice.

    I could not find suitable examples, either. The hardware abstraction examples are wonderful for teaching inheritance. I get the feeling that people who use LabVIEW to develop applications have their own methods, and that people who use it develop one-panel data-grabbing VIs are overwhelmed by (and don't need) complex examples. A few experts have shown me their code, and it seems to me that it is more complicated than it needs to be - lots of upcasting and downcasting, etc. One gentleman has a base class called Instrument from which all other instrument classes inherit. This allows him a huge amount of flexibility, but it is hard for me to keep it all in my head. (What's the G equivalent of the old Linux book's quote: "400 lines of code is all most people can keep in their head at once"? 400 VIs? 400 classes?)

    My plan of attack, at the moment, is a single cluster of Somethings that can be accessed by name in any test (and in an emulator). Each Something is an Action Engine class, and includes an instrument class in its private data. Create the single cluster at the top-level and pass it around to the tests. Perhaps this is easier to do with some of the messaging systems mentioned on LAVA, but I'm not there, yet.

    Plenty of words from me, but no code, this time. A VI's worth 400 lines.

    • Like 1
  14. This is exactly the kind of problem I've been trying to solve. I really like using classes, since the instruments must sometimes be swapped out. But I can't quite figure out where to keep the class wires so that they're available to the tests AND to some other processes (simulation, for example). Some are kept in AEs, which makes it easier to access them from tests with a set of AE wrapper VIs. Now I'm trying to instantiate an AE class in order to create multiple AEs - but that brings back the original problem of where to keep that class wire.

×
×
  • Create New...

Important Information

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