04-29-2016 07:30 AM
Hi all,
I have made a state machine design (as described here) to organise three (mutually exclusive) processes/states: idle, calibration measurement, and continuous measurement. The calibration should be done prior to the measurement because the result of the calibration is used in the measurement. The data input is a camera that should run at all times, also in the Idle mode.
The problem however is that calibration state and continuous measurement (should) have a different method of data acquisition. The measurement is continuous and frames are processed real-time. For the calibration an N number of frames should be accumulated and subsequently processed (basically create a background image).
In the state machine as I have it now (see images attached) I have the vision acquisition outside of the state machine in order to have a live view at all times. The problem now is that the inner loop in the calibration state (the loop that should accumulate the frame) obviously accumulates only the first frame N times, it doesn't poll for any new frames during this state.
I could of course solve this by having an if/else statement in the calibration mode to first accumulate the images (if i < N, accumulate frame in buffer and continue), but I am not convinced that having a lot of nested loops is the most elegant way to do this.
This also made me thinking, is the state machine as I built it here at all the best way to manage these two processes/acquisition modes? Or are there better ways to do this?
Input and feedback is highly appreciated!
Note: I know the for-loop as programmed now in the Calibration state is wrong with the shift registers. That was a test before I realised the flaw was in the nesting of the state machine altogether.
Solved! Go to Solution.
04-29-2016 08:00 AM
Please do not attach pictures, but instead post executable code, either as VIs (easiest) or as LabVIEW Snippets (which will become VIs when dragged into a Block Diagram). If you have more than three attachments, compress their folder and attach the ZIP file.
I was once describing a system similar to yours, and one of my students, who was a Computer Science major, said "That's not a State Machine!". I had a situation similar to yours, where I had an acquisition process that ran continually and a "Stateful" routine that did various things with the data (in your case, using it for Calibration, waiting until "Go", Acquiring, etc.).
I realized he was correct. I'd "inverted" the model, having the Acquisition always running and "driving" the timing, and doing an appropriate "Action" on each data set, where the Action could (and did) vary depending on other conditions. So I renamed my State Machine to "Action Engine", and everyone was happy.
So I won't bother looking at your code (a brief glance showed me I'd only be frustrated by the limited view), but will give you a suggestion for an alternative architecture.
You (ideally) want two parallel loops. One loop simply acquires data (images) at some rate. For each Image, it signals the other loop that it is time to do an "Action" on the acquired data (use a Queue or Notifier to do this). You want the Action Engine to run independently of the Acquisition Loop, just in case a particular Action takes, say, 1.2 Sample Times to complete -- you don't want to "miss" any samples!.
The Action Engine loop does a single Action, appropriate at the time, on the newly-acquired Data. If you are in the Calibration "State", the Action will be "Add to Calibration". When you have accumulated enough data to actually do the Calibration, set the next Action to (for example) "Wait for Start Signal". When you get the Start Signal, change the Action to "Acquire, Process, and Save Data". And so on.
As it happens, I didn't do my code exactly this way, but this was the general idea -- the Acquisition Loop was "king", it ran the clock and drove the "State Machine/Action Engine" to "do the right thing, appropriate at the time" with the data. See if that type of model makes sense in your situation.
Bob Schor
04-29-2016 08:14 AM
Fair point, my apologies. I can't edit the first post anymore, so attached here the VI's (including custom subVI).
Your suggestion sounds like a good idea though, thanks. I will look into how to make a queued parallel loop.
04-29-2016 10:44 AM
I agree with Bob, your best bet is going to be using a parallel loop. I often give each instrument a loop of its own.
You may be able to get your program running now the way you want... but eventually you will want to add some functionality that is very hard to implement right now, but would be easy with a less coupled architecture.
Also, do not get in the habit of leaving terminals unwired and using local variables instead. Local variables are slightly slower, and it is very easy to make multiple places where a variable is written (though it looks like you have not 🙂 ). If you are not careful, two pieces of code will be writing different values to the same local variable and you will have a race condition.
05-02-2016 07:16 AM
Great, thanks for the input! I already expected that my layout was wrong when I couldn't easily debug/add my feature. I am all for modularity so I will change the loops.
@Gregory wrote:
[...]
Also, do not get in the habit of leaving terminals unwired and using local variables instead. Local variables are slightly slower, and it is very easy to make multiple places where a variable is written (though it looks like you have not 🙂 ). If you are not careful, two pieces of code will be writing different values to the same local variable and you will have a race condition.
Thanks for the tip, I will look into that as well. My background is mainly in MATLAB and similar code-based programming so I am used to working with variables. LabView requires a slightly different approach, I need to get used to that still.
05-02-2016 08:56 AM
LabVIEW has "variables" as well -- they are usually implemented as a set of parallel wires running near the top of a While Loop connecting pairs of Shift Registers. If you look at the State Machine example Project that ships with LabVIEW, the "variables" are all contained in the Cluster that is running in the wire between the Shift Registers at the top of the loop. I admit to a fondness for individual "variables", so I typically have 5-8 closely-spaced parallel wires (with a label on the left edge naming them, e.g. "State", "Path", "Delay", "# Samples", "Frequency", etc.).
Bob Schor
05-03-2016 06:29 AM
Thanks again for the input.
I'm trying to restructure the code but I'm still a bit confused how to do it.
I need to create parallel loops: one for data acquisition, one for processing. The action of the latter loop depends on the user input. If I'm correct the architecture would look something like in this example: http://www.viewpointusa.com/resource/view/newsletters/communicating-between-parallel-loops/
In that example, one loop controls the action selection and the other loop contains the appropriate action.
If I understand correctly then, my first loop should contain the vision acquisition (it's inherently embedded in a while-loop) and the "action selection", and a second while-loop with the actions?
As for the image accumulation, I should make separate actions for image accumulation and processing? The accumulation has a counter with it as well to count the number of images and that is reset after the processing.
05-04-2016 08:02 AM
Okay, it seems that the loops for Vision Acquisition need some extra attention.
I have rearranged the architecture into parallel while loops, but the information is not passed on between the loops. Even more, the parallel while loops other than the Vision Acquisition are not executed at all.
To find the problem I have constructed a minimal working example (see attached) of two parallel while loops; one with Vision Acquisition and the second displays an incrementing number. If I highlight the execution, it is clear that the first loop is only repeated and the second one is never executed!
I haven't found a solution for this yet, so any input on it is appreciated.
05-04-2016 08:33 AM
Addition:
I have attempted to work with queues as demonstrated [url=http://www.viewpointusa.com/resource/view/newsletters/communicating-between-parallel-loops/]here[/ur... and [url=http://stackoverflow.com/questions/9984375/labview-is-overwriting-captured-images-in-a-queue]here[/u... unfortunately unsuccesfully.
05-04-2016 10:29 AM
Sorry to spam again, but I've managed to get the camera acquisition and communication working using a queue.The trick was that there can be only one queue channel and no other communication wires between the loops.
Thinking about how to handle both the image data from the camera and the different processing actions, I think I know how to do it - bit I'm not sure if it's correct. It actually is very similar to the first architecture I had, except that the image acquisition is moved to a seperate while-loop.
Schematically depicted, it would look like below. Is this way of thinking correct? (Before I redesign everything again)
+===============+ -queue----@-------Insert--@---Release queue | # GrabImg-^ # | # # | # # | +===============+ | | +====================+ | # #===== event ====+ + | # # #=== case ===+ + + \ @ # # img queue + + + -action---@ @ @ + + + # # #============+ + + # #================+ + +====================+