Jump to content

Mike Le

Members
  • Posts

    180
  • Joined

  • Last visited

  • Days Won

    6

Posts posted by Mike Le

  1. Last month I ran into a problem building an application with LabVIEW claiming a certain VI was "broken."

     

    The VI wasn't broken, but in one of its subVIs there was a FOR loop with a conditional indexing tunnel. When I replaced this with the old-style of conditional indexing (shift register, case register, build array) the program was able to build.

     

    Today I ran into the same problem, where adding a conditional indexing tunnel caused a build to fail with the same error.

     

    I remember running into LabVIEW crash problems when conditional indexing was first introduced, but I was told it would be fixed for 2013. Is this not the case? Does anyone know if a "real" or "complete" fix has gone in for 2014?

  2. Kind of a strange situation.

     

    There are two parts: the streaming data and displaying the data.

     

    The streaming data is picked up from multiple sources. Some "black box" software outputs the data as a waveform array, with absolute timestamp data. The absolute timestamp data is important, because the multiple sources produce data at different times, and the timestamp tells us how the data is aligned.

     

    If you throw the timestamped data on a Waveform Chart, it plots perfectly and everything lines up.

     

    Now, the enduser has a request. He wants to be able to pause and resume streaming. But he wants different runs to be right next to each other, with no gaps. This is a quick, handy way to do an instant side-by-side comparison of two short data runs.

     

    If you just throw the timestamped data onto the chart, then gaps show up whenever you pause. If you paused streaming for 10 seconds, then the gap is 10 seconds long. The pause could be several minutes.

     

    So I need to get rid of these gaps in acquisition. I'm struggling with a good way to do that, because the timestamp data is critical in aligning the disparate hardware sources, so I can't just discard it.

     

    All the ideas I have are elaborate and involved, requiring shifting all the timestamp data by the length of the pause... but even that's not perfect, because sometimes the data sources will start up several seconds apart. So I think I'd have to look at the trigger time of each signal and check for a >1sec (approx.) delta, then shift that signal back by that amount every time. But then all the subsequent streaming data would also have to be shifted by that same delta...

     

    Has anyone had to do anything like this before, or have suggestions for a plan of attack?

     

    Thanks guys.

  3. When both UI and process code need to be aware of some state, e.g. "Move Slowly" option is flagged by the user. Either the process requests that state before obeying a command to move, or that state is copied into the process whenever the user modifies the flag. Which is better and why?

     

    Whenever possible, I forward changes as they happen, to any state machines that need to know that data. Whenever I've gone down the "request data and wait for reply" path, it's led to more complex messaging. I could definitely be overlooking an elegant implementation of that, but "forward changes on the fly" has worked well for me, and I don't (yet) have a compelling reason to change it.

     

     

    When I change the state of a control, I can either copy its state into a variable in the control loop, or I can maintain references to the controls and read it from the control loop as necessary. I have been doing the former, but I would like to do the latter as it would mean having one less copy of the data. Are there any gotchas I should be aware of?

     

    I also did the former for a long time but in some more recent applications, have switched to the latter. There's increased polling time for using property nodes, but none of my UIs have needed to be "ultra-responsive," so that hasn't been a problem for me.

     

     

    Finally, when a control only has a single purpose, i.e. its state will not be read in more than one control loop action, is it best practise to read the control directly in the control loop, rather than seperate it into the event structure and either use a reference to read it, or copy its state.

     

    My instinct tends to be to leave things open-ended and flexible.

     

    There have been a few times where I've been 100% certain that I wouldn't need to do X or Y with a UI, only to find out months or years later that the end-user wants not only X and Y, but also some Z I'd never considered.

     

    So if I have some control I think will only be used in one action, I'd probably still treat it like other controls that are used in multiple places. It's minimal extra work and makes it easier to use later if I end up needing it in other spots.

     

    Just my two cents, I barely know what I'm doing.

  4. The other day I was having trouble tracking down a hanging Actor. Debug Actor Framework let me shut them all down but it wouldn't tell me what Actor was still left hanging. That took a little more digging.

     

    I realized this was a problem I was running into a lot, so I decided to add some simple tracking code to our department's Parent Actor Template. Maybe this'll be useful to someone else, or give someone else some ideas. It's just something I whipped together quickly so it isn't thoroughly vetted or anything.

     

    Basically, it's a dialog that tells you (1) what Actors you've launched, (2) what Actors you've shut down, and (3) what Actors are still running.

     

    iDtz1ux.png

     

    CBU4g6r.png

     

    The tracker dialog is contained in a single VI, which is called in Pre-Launch Init and Stop Core overrides. The call is inside a conditional disable structure, with the condition "ACTORDEBUG==True". To enable the tracker, you set that conditional token in your Project Properties.

     

    I tried to keep the code simple and straightforward, it looks like this:

     

    hTJafkX.png

     

    The call to "Get LVOOP Name" is slow, but performance isn't a big concern for me as I only spin up a couple dozen Actors at once.

     

    The lvclass is attached, for 2012 and 2013. To use the tracker, change your actor inheritance to inherit from the Actor with Tracker class.

     

    Try it out and let me know what you think. The code depends on the OpenG toolkits.

     

    And I imagine a lot of other people have created their own versions of this and other handy debugging actor tools. I'd love to see what others in the community have come up with.

     

    Mike

    • Like 1
  5. Just a warning about using ACBR nodes, as this was an issue I was bit by recently. It sometimes causes project hanging problems.

     

    http://digital.ni.com/public.nsf/allkb/2EE8B4884922F2E686257D580053BDB1

     

    The Knowledge Base article says it primarily affects 2013 and 2014, but I suspect that's because the bug is most apparent when using AF, and Launch Actor was modified in 2013.

     

    I don't think that guarantees the bug wouldn't appear in older versions if you started using ACBR nodes in different ways, just that mostly AF users have noticed the bug. You PROBABLY won't ever see this problem arise, but if you do, the ACBR node is a good place to check for problems.

  6. AQ breaks down the issue here and offers a few solutions. The bug affects those using 2013, 2013SP1, and 2014. It's supposed to be patched by 2014SP1.

     

    There's more detail in the linked thread, but here's what it boils down to in terms of "work-arounds" in the meantime:

     

     

    You have a top-level VI that launches your top actor. That launcher VI quits, leaving the top-actor running, and then the top actor goes off and does its thing, including spawning additional actors.

     

    I believe that the entire problem goes away if you can somehow leave your top-level VI running. As long as the launcher VI stays running, the VI refnum allocated inside Launch Actor stays valid and we do not have to open a second reference to Actor.vi. Avoiding that second reference seems to be critical.

     

    Alternatively, if there is enough of a time gap between the launcher VI quitting and the first call to Launch Nested Actor.vi, that seems to help. I cannot guarantee that, but it seems to be the case looking at the C++ code. I have not actually tried in G to empirically test this theory.

     

    If neither of those works, then you can go back to the 2012 version of Launch Actor.vi and see how the block diagram worked back then. The "close the reference on every call to Launch Actor" is less efficient and subject to root loop pause, as noted earlier in this discussion, but it completely dodges this bug (because it basically forces there to be no overlap of the refnums).

  7. A link to the conversation on why the AF uses the pool-of-clones ref in the way it does.  Don’t change things until you know what “root loop synchronization†means.  I use the same method in non-AF code and haven’t had any issues, so there must be something else involved in the library-locking problem.

     

    Thanks for the info. I was a bit concerned as we made these changes because the NI rep I was speaking to was definitely NOT an Actor Framework expert... he didn't know what it was before we had the conversation. He pulled the suggestions from a similar CAR and it patched my problem, but I got the feeling I didn't get a "tear off the warranty" explanation I SHOULD have gotten.

  8. Okay, I UNMARKED my old post as the solution, because the problem came back this week. A mass compile didn't resolve it like before.

     

    I went back and forth with NI about this. We started poking around Launch Actor.vi, based on another CAR they had that sounded similar.

     

    The change we ultimately made was to remove the 2-iteration for loop that tries to reopen the VI if there's an error on the first try. We also explicitly close the VI reference to the Actor. There's a comment in the original Launch Actor that reads:

     

     

    We deliberately leak the opened VI reference in order to achieve better performance. We open it once, and then leave the reference open to so that we only depend upon LabVIEW's root loop synchronization on the first call. LabVIEW auto closes the reference when the VI goes idle.

     

    I guess that means that LabVIEW was failing to auto-close that reference? I've definitely noticed that the libraries are now SLOW to unlock after code executes. There's several seconds where the project is responsive but the libraries remain locked, then I get a busy cursor for a second, and then the libraries unlock.

     

    But they DO unlock, and I can keep working on the code without having to task-kill LabVIEW, so I guess that's a success.

  9. Hey folks,

     

    So after my recent debacles with project corruption, I started working on some tools to help sniff out problems in my repo.

     

    One thing I'm trying to do is parse any and all URL tags in lvclass, lvlib, and lvproj files. As I find them, I look to see if these tags are pointing to a file that actually exists on-disk.

     

    I'm running into some problems parsing these tags.

     

    For example, I'm parsing a class called "Setting Element.lvclass". I come across this tag:

     

    <Item Name="Pseudo Array - Remove Row.vi" Type="VI" URL="../Pseudo Array - Remove Row.vi">

     

    Based on this, I would expect the method "Pseudo Array - Remove Row.vi" to be one level up in the folder hierarchy from the folder where "Setting Element.lvclass" is located. Instead, it's in the SAME directory as "Setting Element.lvclass."

     

    To me, that would be indicated with URL="./Pseudo Array - Remove Row.vi". In other words, there's one more "." than I would expect: I think of "./" as meaning "current directory" and "../" as meaning "parent directory."

     

    So what's going on? Do I have my "./" and "../" mixed up? Or is LabVIEW using a different internal logic when assigning these URL tags?

     

    Thanks.

  10. Hey folks,

     

    After a two year hiatus, we're bringing back the User Group Meetings for the San Diego area.

     

    We secured a venue and a little funding from NI for pizza and beer. We're hoping the rest of you will bring a little LabVIEW knowledge!

     

    You can check out our official thread on the dark side. Details below.

     

    09/17/2014 | 06:00pm-08:00pm
     
    Ansir Innovation Center
    4685 Convoy St. #210
    San Diego, CA 92111
     
    Light food and drinks will be provided. Please park on the street.
     
    We'll have two short presentations, followed by open-ended discussion and networking.
     
    Presentation Topics:
    • Base 64 Encoding and Optimization, by Ivan Gagne (CLD). Explaining base 64 and demoing a few optimization techniques for For Loops, string manipulation, etc.
    • Class-Based Implementation of a Hardware API, by Tom Fantasia (CLA). Breakdown of the challenges of implementing an in-house hardware interface, and how a class-based architecture was used to overhaul a previously task-oriented solution.

    Hope to see some of you there! If you can make it out, please reply to this thread so we can get a headcount.

     

    EDIT:

     

    We're going to try to live stream the meeting, so if you can't make it in-person, tune in here:

     

    https://plus.google.com/events/ckt7o8j0eimdbgg0lqtnqlh0if8

     

    It's our first meeting, and our first time trying to stream, so apologies in advance for any technical difficulties!

  11. I would definitely like the last 2-3 days of my productivity back.

     

    I also feel like I'm a magnet for problems like this. I run into bizarre behavior far more often than my coworkers. It feels like I must have some awful coding habits or something that's leading to this. Or maybe I'm in a dysfunctional relationship with LabVIEW and am trying to make excuses for it?

  12. Okay, I think I've solved this problem.

     

    I stepped through the code until the crash occurred, which led me to this accessor:

     

    iryJGfz.png

     

    Originally, the "Test Cases" reference was not inside the "Refs" cluster. I moved into the "Refs" cluster. The bundle by name SEEMED like it had updated automatically, as you'd expect. But it was crashing every time it reached this accessor.

     

    I deleted the "bundle by name" and replaced it with a new "bundle by name" node. The wiring's exactly the same otherwise. The code no longer crashes.

     

    Somehow the "bundle" node had become corrupt, maybe pointing to the old data location? I don't know. I would never have thought to look for a show-stopping, IDE crash in a bundle node.

  13. It was down to a full path of the class in an lvlib instead of a relative one. It may also have had the same in the class itself for a couple of methods; like I said, it is a bit fuzzy Once I manually edited the full path to a relative one, the problem went away. Might be worth seeing if you have something similar. It's easy to spot using a text editor

     

    Good news: this fixed the Mass Compile problem. I checked for the obsolete relative path in all my lvlibs, lvclasses, and lvproj files. I finally found it in an lvproj file. I fixed it and the Mass Compile no longer searches in the wrong spot.

     

    Bad news: this did not resolve the bizarre "total IDE crash" behavior.

  14. A few weeks ago, I noticed that I'd messed up when saving a child class. Somehow, the lvclass file was located in the same directory as its parent.

     

    I used the LabVIEW "move on disk" right-click operation to move the class to its correct directory.

     

    I thought nothing of it until some weird project behavior started cropping up. I thought I'd resolved it last week. Hell, it could be a totally unrelated problem! But some very strange behavior came up today.

     

    I was updating another class's private data to include a few arrays. When I finished that operation, trying to dynamically load one of that class's children led to a catastrophic, no-error crash of the IDE. The IDE just disappears and LabVIEW.exe shuts down. When I reopen LabVIEW, it gives no indication that it shut down improperly on the last execution.

     

    Reverting to be backed, checking the run-time behavior, and then reimplementing the change confirms that changing the class data is the source of the problem.

     

    This class is NOT the same class as the lvclass file I moved a few weeks ago. However, one of its child classes does call the moved class.

     

    I tried running a Mass Compile and here's where it gets weird:

     

    During the Mass Compile, it starts searching for the moved class in the OLD file location. If I point it to the correct location on-disk (by clicking "Browse"), then when the Mass Compile completes, it states:

     

    Could not load (C:\Workspaces\V12000\Analysis and Plotting Tool\Plotting Legend\Plotting Legend - Graphing Actor.lvclass) because (C:\Workspaces\V12000\Analysis and Plotting Tool\Plotting Legend - Graphing Actor\Plotting Legend - Graphing Actor.lvclass) in memory

     

     

    What's weird is that nothing but a Mass Compile will reveal this outdated file location pointer. Executing the code is fine, the project shows no Missing or Incorrectly Claimed items. If I do a snapshot of the folder I'm mass-compiling in a brand new project, then at no point does LabVIEW ask me to (1) resolve a conflict between two file locations or (2) locate a missing file.

     

    If I perform a Move On Disk operation BACK to the original (incorrect) location, then the Mass Compile completes without errors.

     

    I can Save All and the Mass Compile completes without errors. With everything that calls the class in memory (in fact, with my entire workspace in memory) I then do a "Move on Disk" operation to where the class SHOULD be. I Save All and perform another Mass Compile, which returns the identical "searching" behavior as previously; something is STILL expecting the class to be in its old location.

     

    I've tried clearing the compiled object cache and deleting the mutation histories of all the classes in the Mass Compiled directory. I also tried clearing the mutation histories in several folders that might also be called as a result of dependencies. Nothing's fixed it.

     

    Has anyone seen anything like this? I'll probably open a support ticket with NI tomorrow.

  15. Lately I've limited myself to using classes mainly as fancy clusters b/c of these issues.  Maybe its a lack of understanding on my part but it seems to be more hassle than its worth in a lot of cases.  

     

    I still use OO for its design features. If you're not going to use inheritance, dynamic dispatch, etc. then what're you using the classes for?

     

    If you want to switch off classes because of the corruption/IDE problems, I'm wholly sympathetic to that. But are you getting enough added value from simply using classes "as fancy clusters" to justify the added corruption/IDE issues?

     

    That sounds like the worst of both worlds; opening yourself up to hard-to-track problems with very little of the benefit.

  16.  

     

    What I want to do now is remove the enum, and make it a class. (it is my understanding that have type-defined controls inside a class can lead to some weirdness).

     

    I saw that in the thread about decoupling messages when using Actors. What I'm wondering is: does making it a class improve things at all? It seems like you'd have the same dependency problems, plus potential class library corruption problems.

     

    I use OO for all my big projects, but more and more, I find myself battling the IDE and mysterious class corruption issues.

     

    I'm not sure if switching from a typedef to composition improves things. I do it all the time, but I also use typedefs in the class private data, and I'm not convinced that one is worse than the other. (Though I'm open to being persuaded otherwise.)

×
×
  • Create New...

Important Information

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