Jump to content

QueueYueue

Members
  • Posts

    68
  • Joined

  • Last visited

  • Days Won

    7

Posts posted by QueueYueue

  1. The following VIs aren't reentrant but should be:

    - JSONtext.lvlib:Format JSON Array Text.vi
    - JSONtext.lvlib:Parsing Error.vi
    - JSONtext.lvlib:Format JSON Object.vi
    - JSONtext.lvlib:Get all Object Items.vi
    - JSONtext.lvlib:Get Array Elements.vi
    - JSONtext.lvlib:Parsing Error in converting to LabVIEW type.vi

  2.  

    On 8/5/2021 at 10:29 AM, drjdpowell said:

    Consider just not including those parameters.  Rather than {"A":123,"B":null,"C":789} just have {"A":123,"C":789}; then "B" will be default.

    Alternately you could put named-Variant values inside your variants (which teh Variant-to-Data node will pass through:

    1090371450_2021-08-0517_26_42-Untitled2BlockDiagramonJSONtext.lvproj_MyComputer_.png.63907e2224240eac829f7dadb8bfa9d8.png

    Variants are quite tricky, as they can serve both as a temporary container for a value, and a value itself.

    This is opposite of what I would expect to see. Fundamentally if I give you a cluster with named items (who cares about the data type), I expect the JSON output to an object with fields matching the names of the clusters. All of this "variants have names" discussion is optimizing of weird LabVIEW shenanigans instead of a primary use case.

     

    On 8/5/2021 at 10:19 AM, Aristos Queue said:

    Allow me to rephrase then.

    Recording an array when passed a NAMED cluster is definitely a bug, regardless of the behavior of the variants.

    +1

  3. Hey, Derek here. Stoked to see GPM came up.

    Couple of things I want to mention.

    1. The current GPM release is still a beta release. If you find bugs or want to request features, add them to the issue tracker. https://gitlab.com/mgi/gpm/gpm
    2. @ShaunR Theres a CLI and a GUI. The CLI will probably be used by CI setups, the GUI will be used by people. Eventually (though not currently) anything that you can do in one you can do in the other.(the "commands" that the CLI and GUI execute are just two different ways of executing the exact same business logic.)
    3. I know it needs to support distributing things like quickdrop plugins. I haven't quite decided how I'd like to do it, but I definitely realize it's something that's needed before a full on release. https://gitlab.com/mgi/gpm/gpm/issues/18
    4. Yeah, @David_L I agree, +1 to the number of package managers sucks. Sorry :/

    Back to the OP's topic:

    One of GPM's goals was to answer this question. If you have code that you want to give out for free, I think it should be trivially easy to do so. Using GPM, you just fill out the meta data, create an account on https://gpackage.io/ and then click publish. Once the command has finished executing you're good to go. It's published on the internet so anyone can download it. Someone who wants to use your code just needs to install it using GPM. If your code depends on other packages they'll be installed at the same time. It should be super easy (let me know if it's not!)

    Additionally, GPM package meta data has all of the fields needed to properly index your stuff and link back to your repo. This makes it easy for people to find your code, and contribute to it as needed.

    Happy to answer any more questions (or argue about design decisions =P)

    • Like 2
  4. I've made some pretty cool changes to Monitored Actor that help expand it's capabilities. The main being the ability to override the UI. This lets you do cool things like create a web based actor monitor, or run the monitor window in the runtime environment. I also added Actor Labels to help you identify running actors.


    Check out our Monitored Actor 2.0 article for more info!

    If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Monitored Actor as well as some other tips for developers of large application (like MGI Solution Explorer, Class Method Browser and Actor Framework Message Maker)

  5. Good news, we've got a major update to the MGI Solution Explorer. You can now create custom solution items, which allows us to do cool thinks like create self extracting zip, or help deploy your solution.

    Check out our MGI Solution Explorer 2.0 article for more info!

    If you're at NI week, be sure to checkout the presentation by Brandon Steele on Thursday (1:30 in room 16B). He'll be covering the Solution Explorer as well as some other tips for developers of large application (like Monitored Actor, Class Method Browser and Actor Framework Message Maker)

  6. LabVIEW might support the dragging from explorer and dropping on a 'Path' control, but it does NOT support the dragging from explorer and dropping on a 'List Box'.

     

    It's possible to use the path control to do what you want, but it's a little hack-ey. You end up making the path control transparent, then only making it visible when the mouse is outside the VI's front panel. See http://digital.ni.com/public.nsf/allkb/81D867F8C6A1376D86257347001BE936

    • Like 1
  7. 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.

  8. 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.

  9. I get what you're saying, and I think it is neither pre-alloc or shared re-entrancy. You want a hybrid.

     

    I think there would be a lot of design decisions to be made with what you're suggesting. I feel like this would end up with new clones being allocated when you didn't expect it, sometimes a new clone wouldn't get allocated when expected, etc. Rather than forcing us to learn there rules (it's already hard enough with two re-entrancy types) it's just not available. You can do this on your own however. You can make all of the somewhat-arbitrary design decisions on your own, just follow drjdpowell's advice from earlier: 

     

    You can work around that.   Have your classes use static preallocate-clone methods, and have a dynamic method that returns a prepared reference to one of these static clones.  You store that reference in your object on creation.  Then use a single call-by-reference in your loop, and all preallocate-clone NI subVIs should work correctly.

     

    — James

     But i'm telling you, you're setting yourself up for confusion and memory leaks. I think my pattern is better.

  10. Zyl,

     

    You're close to understanding it correctly. 

     

    Here's how I think about re-entrancy. Pre-allocate -> VI is allocated during compile time. Shared -> VI is allocated during run time. So.....

     

    Let's assume that you are using a standard dynamic dispatch VI (reentrancy set as 'shared'), what happens the very first time that child VI is called ? I guess that, at the time of executing the VI code, LV allocates the memory needed for this specific child... No ?

     Correct.

     

     

    If LV can do it once in 'shared' mode, why it cannot do it every time you would call a 'pre-allocated' child VI ?

    I don't understand what you mean by this.

     

     

     
    Reentrancy does not concern the way you launch an execution, but how you manage the memory allocated with previous launch.

    Re-entrancy does concern the way you launch an execution AND how you manage the memory allocated with the previous launch.

     

    Shared clones are launched from a clone pool. So when execution needs a clone, it asks the clone pool for one. If there is one available, it gets it. If there isn't one available, the clone pool creates one for you. When you're done you return the clone to the pool. You have no control over which instance you get from the clone pool, it decides. This is why the uninitialized shift registers don't work as expected. You're expecting to get the same clone back every time, but the clone pool manager gives you back the first available clone.

     

    With pre-allocate you're linking to specific instance of the clone. There is no clone pool stuff because you're saying "I know I'll need this here so create it up during compile to save some execution time"

     

    So why can't you pre-allocate a dynamic dispatch VI? Because to pre-allocate you need to link to a specific instance of the VI right? To know the specific instance you need to know the runtime data type of the class coming in, which we don't know. To make pre-allocated work you'd need to allocate (at compile time) memory for every possible VI that could be called. This means that if you had a 2 child classes you'd need to allocate memory for 3 VIs (one for the parent and one for each child). Now what do you do if one of the child VIs calls the parent's implementation? maybe that should be allocated up front? Now what happens if you dynamically load a class in a plug in architecture? You're code would need to be recompiled to add the memory for that new class? See how we're running into all of these weird situations, all of which would required allocating a bunch more memory? Maybe it's possible, but it's not efficient, and it'd possibly introduce a whole slew of other complicated design decisions. So that's why you're not allowed to do it.

  11. Why is that?

    You're in a race-condition. You get shared clones instantiated as needed. That means if you have two objects that both call the same VI, sometimes they'll get the first instantiation of the VI, sometimes they'll get the second. LV decides which. Take a look at the example it illustrates it.

     

    Can’t open the example ‘cause I’m still on 2013, but there is no “casting†required in the method I’m thinking of.

    The VI who's ref you create is going to have a common connector pane across all classes. This means that if you have a child class, the input terminal will have to be of the parent's type. so you'll have to do a cast if you want to access any of the child's data. Either that or you'll have to use "Set control by name" invoke nodes, which I avoid at all costs.

     

    Attached is a 2012 version of my example.

    Pealloc Testing 2012.zip

  12. Ohh man, lots going on here. I made an example using references.

     

    Hi hooovahh,


    Yes I know NI VIs have to be called as preallocated reentrant VIs, that is what I actually do. The "relation" between my shared clone and the NI VI called inside is correctly maintained. My problem comes from the relation between the main VI calling shared clones. My question was more about the architecture of the system.

     

     

    Hi QueueYueue,


    OK that is what I was afraid of. I started a development from scratch so I used to store all my custom code data in the objects. But for the needs of the project, the client asked then to use some NI VIs in shared clones. As you say, I'm double screwed.


    I have tried to store a VI reference in the object, but Labview does not allow to open a shared reentrant VI with a call by reference (which stands to reason since Labview manages clones and not my code).

    gallery_53538_118_10352.png

    Calling NI VIs by reference and storing this references in the object works but I am afraid of the number of references I will need...

    Thanks for your answers, I'm installing last version of LV to see if there is any difference.

     

    Calling NI's VIs by ref is what I'm talking about. There's no difference in newer versions of LabVIEW. The reason you cannot call a dynamic dispatch VI by reference is because a reference points to one VI. Dynamic Dispatch, however, means you don't know what VI you're calling until runtime (and by runtime I mean right before the VI is called). What if you open a reference to  Class A's Implementation of a method, then you wire Class B to the input? They both have the same connector pane. What if you open a reference to the parent's implementation, but then wire in a child? You need to call the Child's method, but you have a reference to the parent's. There's a bunch of situations where you'd be trying to call the wrong implementation on the wrong class, so that's why you get a broken run arrow.

     

    In response to the number of references: Who cares? Store all of the references inside the class data, and then give that class a "cleanup" method. Done. Opening a lot of references is no big deal as long as you close them.

     

    You can work around that.   Have your classes use static preallocate-clone methods, and have a dynamic method that returns a prepared reference to one of these static clones.  You store that reference in your object on creation.  Then use a single call-by-reference in your loop, and all preallocate-clone NI subVIs should work correctly.

     

    — James

    It'll work, but I'm pretty sure you'd have to do some casting to get the control panels to line up. See my posted example for a cleaner (IMO) implementation that's pretty similar to what you're suggesting.

     

    Welcome to LVOOP... this is one of my biggest gripes about using it for certain things.  The work arounds listed above help, but using LVOOP design patterns can make some of the simplest things so heavy.  LIke these guys mentioned before, you can make a new class that contains the shift register data of the NI method you want to use and write a custom method for the action want.  Then include this class in your parent and pass it around in each child.  

     

     

    This sounds like an interesting approach, but lately, LV2013 SP1, i keep getting burned by hacking around the call-by-reference nodes to try and fix issues like this.  There seem to be some weird deep labview crashing bugs that i keep stumbling upon when i do things like this.  

     

    This has almost nothing to do with LVOOP. If you called a pre-allocated VI inside of a shared clones VI in any instance you'd have this problem. This is an advanced feature that needs some extra thought by the programmer.

     

    About the example:

    Open "Test VI.vi" and run it with "Call By Ref?" set to False and run the VI. Notice string 1 and string 2 are changing. They will flip flop based on which instance they happen to get (it's a race!)

     

    Stop the VI by clicking the stop button. Now set "Call By Ref?" to True and run the VI. String 1 and String 2 will now get their own values that stay the same.

     

    Take a look at the code, most of the magic happens in "Test Class.lvclass:Test VI.vi" (note: This is the re-entrant shared clones VI). On first call (for that object) it opens a new ref to the pre-allocated VI, and on subsequent calls it just uses the reference it already has open.
     

    Let me know if you have questions.

    Pealloc Testing.zip

  13. You're right. You can't use un-initialized shift registers like you want inside a shared clone VI. This does mean that if you put any of NI's VIs which use pre-allocated re-entrancy inside your shared clone VI you will be screwed. And since you're forced to use shared clones with Dynamic Dispatch VIs, you're double screwed.

     

    All and all, this means that data that needs to be stored between calls needs to be placed in the object's private data. It will now live on the shift register and the clone will just use the data, instead of storing the data. If you were writing the code from scratch, this would be no big deal, but since you're using NI's code, it becomes a pain. What I ended up doing is writing my own version of NI's VIs (typically started by coping and pasting) that strips out all of the shift registers. I think (I've not tested this way) you could also open a VI reference to the VI, then use a call by reference, and store the reference in the objects private data. I'd have to play around  with this way though.

     

    It's annoying, and honestly, I think that NI should go back and give us a version of their VI's that don't have shift registers in them. Obviously this is a lot of work without much return, so I don't blame NI for not doing it.

     

    And that kids, is why you don't use globals unless you're 100% sure you need them and there's no other way.

  14. I'm working on an automated builder. I'd like to be able to know all of the installed versions of labview on the system. I can use the "Get Installed Software" VI in nisysconfg.lvlib, but that gives me names and ID and stuff, and what I really need is executable paths and VI Server ports.

     

    Anyone have ideas? What good is this ID GUID-looking value?

  15. Two things:

    1. Webservices changed a lot in between LV2012 and LV2013. I think you're looking at a tutorial for LV2012, but you're working in LV2013. That's why you're not seeing the webservice option in the build specs.

     

    2. It sounds like you'd like to consume a webservice from labview. The tutorial you're looking is for hosting web services in labview. To consume restuful webservices in labview you should be using the HTTP Client

  16. I have an application that records video and DAQ data at the same time. The user clicks the record button, then does their stuff, then clicks the stop button.

     

    Now I want to generate an output AVI that displays the graph data side by side with the recorded video. (I have the DAQ data in a TDMS and the video saved in a temp AVI). My problem is, how do I get an image of the graph?

     

    Here are the solutions I've come up with:

    1. Have a graph control in a separate VI. Set the graph to the DAQ output, then use the "Get Image" invoke node to get an image

    Pros: Looks great. Easy

    Cons: Heavily uses the UI thread.

     

    2. Have a graph control in a separate VI. Set the graph to the DAQ output, then use the "Export Image" invoke node to get an image

    Pros: Slightly faster than option 1. Easy

    Cons: Heavily uses the UI thread, Doesn't look particularly great (but not bad). Only slightly faster than option 1

     

    3. Use the Picture plot toolkit

    Pros: Does not use the UI thread

    Cons: Looks terrible. A lot of work to get looking decent. Looks like no one at NI has looked at these in a long time (they use deprecated subvis).  VIs aren't reentrant so cannot parallelize.

     

    Here's what I want:
    A decent looking plotting package that I can run in a paralleized for loop.

     

    I'm currently using option 1, and it takes forever to generate the video (2x-3x the length of the video @ 15 FPS). I can't paralellize it because it uses the UI thread. It also noticeably affects the program when running in the background.

     

    Does anyone know of another LabVIEW way to accomplish this? My only other idea would be using the .NET, which would step up the difficulty significantly, but maybe get me the performance I need.

  17. If you want to go the NI route....

     

    I've recently been dealing with the headache that is Vision related licensing. Here is what I understand it to be. The terminology is VERY confusing, so you'll have to deal with me.

     

    IMAQ VIs - These are VIs used to get images/video off of NI cameras. These are free to use (development and runtime), but again, they only work with NI hardware.

     

    IMAQdx VIs - These are VIs used to get images/video off of ALL other cameras. Your webcam falls into this category. This requires the Vision Acquisition Software (VAS) license to develop AND Deploy. These cost money

     

    Other IMAQ VIs - some of these VIs are free to use without any license (such as IMAQ Create), others are not (such as  ImageToImage). The licensed VIs require the Vision Development Module to use in Dev mode, and the Vision Development Module Runtime Engine (I like the way they got development and runtime in the same title) to use in Runtime mode. These both cost money. I don't know of a good list that says X vi needs a license and Y vi doesn't.

     

    There are times when you buy one license and get another for free, but I don't stand of chance of figuring out what's what. It's best to call NI support or talk to your local sales guy for help.

     

    http://digital.ni.com/public.nsf/allkb/F1699570F78FECBB86256B5200665134

     

    tldr (for the NI route); There is no free way to get images from a webcam into labview.

     

    The non-NI route....

     

    I've gotten images from a webcam into labview using non-NI code. OpenCV is a popular one, but I've never used it. Basically my strategy was "how would a C# programmer access a webcam". I found some code on the internet that I was able to modify into a C# DLL that I could call from labview. I did this a few years ago at another company, so I can't give you and example or much more info.

     

    I'd describe this as a pretty advanced task, and not something that I'd recommend to someone who was new to labview, unless they had a good amount of C# experience. The only reason I did it was because we needed to put webcams on 100+ machines, so that means it would have cost $50000+ in licensing. I was able to put something together that did our super small set of tasks in about a week or two. If you're only doing this for 1 machine, just pay NI.

  18. QueueYueue, I fully agree with your first point, but this construction is impossible as I explained before. A root class cannot create a DVR to a child class. Hence my call for a Dynamic Dispatch DVR terminal type, which I'll file shortly.

     

    Yes you can. You just have to use a template method pattern

     

    AQ has written a lot of good info here about why you can't (and wont be able to in the near future) have dynamic dispatch DVR terminals http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Have-Dynamic-Dispatching-terminals-accept-Data-Value-references/idi-p/1054410

    ParentChild DVR.zip

×
×
  • Create New...

Important Information

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