Jump to content

smithd

Members
  • Content Count

    763
  • Joined

  • Last visited

  • Days Won

    42

Posts posted by smithd

  1. Quote

    JSONtext VIs

    The Flatten/Unflatten String palette includes a link to install JSONtext VIs for programmingJSON in LabVIEW. On the Flatten/Unflatten String palette, click Install JSONtext Add-on toinstall the JSONtext add-on from the JKI VI Package Manager (VIPM). The JSONtext VIsappear on the Addons»JSONtext palette.

    [Special thanks to Dr. James David Powell, author of the JSONtext add-on.]

    https://www.ni.com/pdf/manuals/371780r.pdf

    yay! 🎉

    too bad nxg breaks the code

    • Like 1
  2. The term you are looking for is a cluster, equivalent to a C struct more or less.

    You create a type definition like this: https://zone.ni.com/reference/en-XX/help/371361R-01/lvhowto/creating_type_defs/

    once you are in the control editor for the type definition, what you want to do is drop down a cluster control.

    ctrl+f for "clusters" on this document for a video: https://www.ni.com/getting-started/labview-basics/data-structures

    or in tutorial form: https://www.ni.com/tutorial/7571/en/

     

    Depending on where you're at, you may have access to NI online training, or other resources found on this page: https://labviewwiki.org/wiki/Training

  3. On 5/8/2019 at 12:15 PM, Neil Pate said:

    There is no need for the timed loop as the DAQ itself has a timing source. Just use a regular loop and ask the DAQ for a certain number of samples. This will accurately fix the loop rate.

    Also, to get up and running just try using a regular queue. Although you need to be a bit more careful on RT there is no good reason they will not work unless you really need to get every last ounce of performance from the system. I have never been a fan of shared variables, too much "magic" going on behind the scenes for my liking.

    To go further, the timed loop is the not the right choice, and the RT FIFO has a negative performance impact on this application.

    The data source (daqmx) is nondeterministic, the data client (tdms) is nondeterministic, so using an RT FIFO as I understand it will result in performing a memory copy on every iteration to copy from the (newly allocated and thus non-deterministic) daqmx buffer to the preallocated RT FIFO buffer. In contrast a normal queue (again as I understand) will simply shuffle around a pointer to the buffer provided by daqmx*. No allocation past the one performed by daqmx and a minor one to allocate the queue structure.

    By using a timed loop you're forcing everything to run in a single thread, so if you add any additional code later into the daqmx loop, it would have to run in series with the daqmx api reads. You're also telling the RT OS that the HIGHEST priority loop/thread in your entire codebase is something which immediately hits an asynchronous call and waits for that call to return.

    *I think technically its passing around a struct with an inline timestamp and dt, and then a variant pointer and an array pointer, but you get the idea.

     

    On 5/8/2019 at 9:12 AM, luiz.felipe said:

    2.2- The number points in the waveform read in the timed loop keeps oscillating, depending on the sampling rate. Is it normal?

    4- Should the logging loop run faster than the timed loop or at the same rate?

    2.2: you can make it fixed by passing in a samples to read per channel input on the daqmx read VI. The default is -1, which tells the driver to return whatever is available but don't wait for new data.

    4 By definition the two loops have to run at the same rate...on average. As shown (a kind of producer-consumer implementation), you really want the daqmx loop to be driving the logger loop, which is easy to do with a fifo or queue -- you pass in -1 for the timeout, and as data arrives the bottom loop will run. As you have it, the tdms loop is simply running every 5 ms.

    Instead of a queue or shared variable, you can also use channel wires which are intended to make data communication a bit more user friendly. They even have an RT FIFO option if you ever do need that: https://www.ni.com/product-documentation/53423/en/

  4. 17 hours ago, SteveSun said:

    I want to implement a function as follows: first set the Max and Min voltage values, then set the number of steps in the middle of the Max and Min steps and the dwell time of each step, and finally set the total number of cycles
    The problem is: the value of each step must be output separately, there is a problem here, please help, thank you! 

    What are you trying to output to? A graph? A daq card?

    If its in one of the pictures, only 2 came through on my end, the rest show up as blank squares.

  5. 13 hours ago, rscott9399 said:

    Hi all

    Trying to use a network published variable to control the event structure of something in an RT loop of a rio project. 

    When i try and add an event, it wont let me have access to that variable.

    Any ideas?

    Maybe create a local variable?

    Generally RT code doesn't have a UI, and as mentioned you have to use a special add-on to use events with shared variables. The usual equivalent is to use a messaging tool to handle communication and generate events in your RT code. I personally use HTTP and/or websockets since its free and there are many clients out there. I believe there is a tcp handler for drjdp's messenger lib (https://sine.ni.com/nips/cds/view/p/lang/en/nid/213091), actor framework has a networking addon, and for quick and dirty, AMC (https://www.ni.com/example/31091/en/) works.

     

    To put it another way, where you might use a UI event (queue) structure on a windows machine, you would typically use asynchronous I/O (eg tcp, udp, serial) to feed a queue on the rt system.

  6. 51 minutes ago, RogerSaele said:

    There is no support for fixed-point numbers.

    there is hardly support in labview itself ;)

    In reality this is a pretty easy fix to do on your own branch of the code. Inside here:

    https://bitbucket.org/drjdpowell/jsontext/src/default/Variant to JSON Text.vi

    and here: https://bitbucket.org/drjdpowell/jsontext/src/default/JSON text to Variant.vi

    If you look for every case structure using the type enum, find the case for "extended precision" and then add "Fixed Point" to the same case. Numeric variants automatically coerce so it should work as simple as that. (I suggest extended because of the different variations of fixed point, potentially using 64 bits in a more efficient manner than say a 64 bit double. You will still possibly lose precision)

  7. I re-read your (rscott) post and it occurred to me you might be missing something more fundamental wrt labview applications. I don't claim that this code is good or bad, but it can serve as a reasonable example for this conversation: https://forums.ni.com/t5/Example-Program-Drafts/LabVIEW-Real-Time-Sample-Template-Embedded-UI/ta-p/3511679?profile.language=en

     

    Note that there is some UI code, but theres also a deterministic control loop and various monitoring loops.This is typical and in fact kind of on the low side. This is why message oriented frameworks like actor framework or drjdp's messenger library or delacor's dqmh are fairly popular as they provide some of the plumbing and structure common to many applications.

    178281_RT_Main_-_Separator_Monitor_and_Displayd.png.e3453f857b4d966f65c181c95b0ef914.png

  8. to convert this into c-style:

    while(1) {

    pathwire=pathin

    waitforinput(timeout=forever)

    pathout=pathwire

    }

     

    you didnt 'hose the rest of the system' but your loop will stop because you told it to wait for input. You generally have many many many loops in a labview program. You can change this loop to a polling style by setting timeout to something besides forever.

    also note that the order of operations in the loop is not specified. I wrote one possibility.

  9. This is a good guide to look through: https://www.ni.com/en-us/shop/compactrio/compactrio-developers-guide.html

    Mark mostly covered it, the way I'd think about it:

    Default -> run on host

    Does my code protect human beings -> generally don't use NI products* and don't even touch the application unless you know what you're doing (*exception is maybe the SIL module but even then I'd want an experienced safety person consulting)

    To move to the compactRIO you want one or both of these to be true:

    • Does my code need to run 24/7 headlessly
    • Does my code need to operate in a moderately precise (~100 usec) time frame

    To push the code from RT down to FPGA you want one of these to be true:

    • Does my code protect a mechanical system (eg look for voltage to go past limit, open relay)
    • Does my code need to close a loop in a precise (>25 ns variation) time frame (eg motor control)
    • Does my code analyze a large amount of data that my RT CPU is unable to keep up with, AND
      • Does my code analyze data in such a way that otherwise wasted time (eg time between samples of an ADC chip) can be effectively utilized (eg performing a filtering operation on each sample)
      • Does my code analyze data in such a way that a large amount of data can be compressed to a small amount of data (eg integrate a curve after a trigger, or find peak and valley of a waveform)

    The reason that last one is an AND is that if you can't pretty easily pick up the slack on the FPGA by seriously reducing the data rate or doing a lot of work in otherwise 'idle' time, its probably cheaper to just buy better hardware. Theres a limit to this of course, but...

  10. 6 hours ago, Dataflow_G said:

    I mostly post these over on Twitter, but here's some LabVIEW memes I've made:

    LabVIEW Style Checklist:
    "Size the block diagram window no larger than the screen size."

    Me:

    ultrawide.jpg.82c7492316fad3440083cb9890b58eac.jpg

    I'm not bothered by the size of that guy, I'm bothered that everything is serially executing :(

  11. In the compiler doc here (https://www.ni.com/tutorial/11472/en/) theres mention of a yieldIfNeeded block which is inserted into loops which allows for coordination with the rest of the runtime. If you just have the one while loop, you are still having to check against the runtime engine if you should keep running or if you need to pause and let other code run. Its not just a simple jump.

    tl;dr I dont think there is any way to do this with a regular loop. A timed loop may work. The overhead should be minimal compared to any actual code you wish to run in the loop, and if that isn't true labview is probably not the tool for the job.

    • Thanks 1
  12. On 4/3/2019 at 12:03 PM, cjcilino said:

    I'm also

    You're also what?!

     

    11 hours ago, cjcilino said:

    And Cirrus Logic is not affiliated with NI. I'm not sure why my profile reads "NI"... hmmm.... I'll see if i can get that squared away.

    Make sure your lavag email is not @ni.com and then pm Michael. He can fixit.

  13. My vague understanding is that labview exes are basically special zip files with an executable header tacked on with the instruction to load the labview runtime. The runtime then takes over and loads the code. This obviously changes with the fast file format, but the general concept is probably about the same.

    Point being, the exe is still a separate OS process, it just happens to immediately load up a copy of the lvruntime dll which can be shared.

    • Thanks 1
  14.  

    Thanks guys,

    I've been having intermittent lockup of dll.  This dll is not safe to call from more than one thread at a time, and I had put in protection to prevent that, but I noticed the lockup occurred in two different LabVIEW instances at the same time.  My protection, unfortunately, is confined to a single instance of LabVIEW, and thus couldn't stop this.

    I don't know the exact details, but it looks like you could use a system-wide mutex:

    https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createmutexa

    I'm assuming linux has something similar.

     

    Or since its long-running, another option would be to do whole thing where you make a "blah.lock" file somewhere, like what git does. But thats clearly iffy.

  15. I don't know for sure (maybe @Rolf Kalbermatter does) but looking at this KB (https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019L5JSAU&l=en-US)

    indicates that its basically calling win32 LoadLibrary, and the help for that (https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibrarya) seems to indicate there can only be one (per process):

     

    If the specified module is a DLL that is not already loaded for the calling process, the system calls the DLL's DllMain function with the DLL_PROCESS_ATTACH value. If DllMain returns TRUE, LoadLibrary returns a handle to the module. If DllMain returns FALSE, the system unloads the DLL from the process address space and LoadLibrary returns NULL. It is not safe to call LoadLibrary from DllMain. For more information, see the Remarks section in DllMain.

    Module handles are not global or inheritable. A call to LoadLibrary by one process does not produce a handle that another process can use — for example, in calling GetProcAddress. The other process must make its own call to LoadLibrary for the module before calling GetProcAddress.

     

  16.  

    I've just written two XControls. (First time in about 6 years). They seem to be ok but some of the ways they work can be a bit unintuitive.

    Coincidentally I just wrote a couple as well. I agree they seem OK for simple things, but the whole question of when and how they wake up makes them less usable. The main reason I want an Xcontrol is that a lot of things are combined controls+indicators. For example I have an indicator with the current value and the setpoint and some other stuff, and a control for the setpoint -- but you can't bind to user events, so you have to pick a proper 'direction' for the control and use a property for the other way and you end up having to marshal data around anyway. I don't hate them as much as I once did, but I don't like them.

    I think the q guy had it right, basically just grouping control references together and using standard functions to manipulate the group as one: https://sine.ni.com/nips/cds/view/p/lang/en/nid/214228

     

×
×
  • Create New...

Important Information

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