LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

AI-CI synchronization and saving data sequentially

This is what I want to achieve with the attached VI:

 

1. Read AI (from a load sensor) and CI (from a quadrature encoder) signals synchronously.
2. The program starts with the 'FOR LOOPS?' boolean set to FALSE. In this state, store the synchronized data on-demand (using the STORE button) and perform other actions (to be added later).
3. Once the 'FOR LOOPS?' is set to TRUE, the sequence structure inside runs for every iteration of the outer FOR loop and saves the synchronized AI and CI data to a separate file. The sequence structure has three frames with a wait period for each.

 

What I need help with:

1. Is the synchronization part addressed correctly?

2. Local variables are not updated inside the FOR loop. How else could I pass the correct set of data to save it into a file at intervals dictated by the wait periods in the sequence structure?

 

I am using the following hardware: 

NI cDAQ 9178

NI 9202 AI module

NI 9401 DIO module

NI 9361 CI module

 

Thanks,

lza

Download All
0 Kudos
Message 1 of 11
(294 Views)

1. Is the synchronization part addressed correctly?

Looks correct.

 

2. Local variables are not updated inside the FOR loop. How else could I pass the correct set of data to save it into a file at intervals dictated by the wait periods in the sequence structure?

Use Producer/Consumer Architecture and pass it to a parallel loop for logging.

-------------------------------------------------------
Control Lead | Intelline Inc
0 Kudos
Message 2 of 11
(247 Views)

I have updated the While loop so that the analog input is read based on the requirements of each state of the case structure (snippets attached). However, I am afraid I cannot do the same to the CI. The CI task is coupled with the motor rotation to measure its rpm and shaft angle. It is also fed to the PID controller to maintain the speed of the motor which needs to be running at all times (unless the While loop is stopped).

 

I can now save the AI signal as desired, but not the CI data. Any help or guidance is appreciated.

 

Thanks,

lza

Download All
0 Kudos
Message 3 of 11
(245 Views)

Again, I recommend using Producer/Consumer architecture to log data in another loop so that it does not block your main control loop.

-------------------------------------------------------
Control Lead | Intelline Inc
0 Kudos
Message 4 of 11
(237 Views)

I'll echo ZYOng's suggestion to use a producer/consumer approach to isolate your DAQ operations from your other program logic.  Several additional comments, no particular order:

 

1. Agree that AI / CI sync is correct -- CI "borrows" the AI sample clock, dataflow sequencing assures that CI starts before AI.   CO sequencing is unclear.  If CO is used to control motor speed, you may need to allow some startup time between starting CO and starting to perform PID control.

 

2. Your vi as a whole is unnecessarily messy & cluttered.  This makes interpretation more difficult and time-consuming, frankly too much for me to spend a lot of time on details.

 

3. Your CI data handling seems awfully suspect.  You read multiple samples but only use the very first one.  (You also read multiple channels from a 1-channel task then extract only the first one). 

    You then use a pt-by-pt median filter that operates over multiple loop iterations.  Why not perform a simple median on the full array of samples you just read?   And that's just an example of what seems suspect, there are many other likely better things to do with that array of samples than to take a simple median.

 

4. I see no scaling for the CI data.  Your task will read an angular position but you then want to perform PID with reference to a target RPM.  You're going to need to do some scaling and a derivative to get from angle to RPM.  And you may need some further scaling before passing the PID result to your CO task as a new frequency.

 

5. You probably need to spend some time simply *thinking* and writing down rules for how your app should behave under different conditions.  You will likely find that you should also make use of a state machine in your consumer loop.

    If some of those states include long "wasted time" delays, you need to give careful thought to the implications for the data the producer loop wants to keep delivering.  If the consumer gets stuck in a "Wait 10000 msec" node, data will build up in the producer / consumer queue.  By the time the consumer gets unstuck, it'll start working on data that's stale by at least 10000 msec. 

    There are multiple ways to deal with such a situation, and no single universal answer that's best across all kinds of apps.  You need to spend time thinking about what *YOUR* app needs to do.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy coming to an end (finally!). Permanent license pricing remains WIP. Tread carefully.
Message 5 of 11
(212 Views)

@ Kevin: I am using two channels in one task: one for the motor's rpm and the other for the shaft angle. I feed rpm from there to the PID controller. I have replaced the pt-by-pt median with a simple mean.

 

@ ZYOng: I have attached a VI that uses producer-consumer loops to read and save the AI/CI data respectively. The issue that I am trying to address now (apart from maybe the improper use of channel wires) is to save the data from AI and CI not continuously but at certain instances while the program is running. These instances are dictated by the sequence structure inside a case structure. How do I ensure that the AI and CI samples are read and saved simultaneously? More details inside the block diagram...

 

Thanks,

lza

0 Kudos
Message 6 of 11
(167 Views)

Sorry for the prior oversight about the multi-channel CI task.  Your device is one of the very few NI has ever offered that supports multi-channel CI.

 

I'm going to reiterate step #5 from my prior post.   You probably need some state-machine-like logic over on the consumer loop side that will manage the decisions about manual saves vs programmatically-controlled sequences.  It will likely help to work this out with paper and pencil first, the various program states, the logic that determines when to change states, when to disallow interruptions, etc.  Make sure it's very clear in your mind *before* you start implementing in code.  Coding first often leaves you stuck in a kind of dead end and tempts you to try to get out of it with short cuts that are often bad ideas.

 

Generally, I would remove all file operations out of the producer loop -- they belong in a consumer.  I'd also get rid of all the msec delay timers in the producer loop and let your DAQmx Read calls control your producer loop timing (# samples / sample rate = loop time).  Generally, the producer loop just just be your DAQ and PID stuff, along with any possible logic about enabling / disabling the motor & PID.  Just read data and send it to the consumer, nothing much else.

    You can do yourself a further favor if you always read the same # samples from AI and CI and then bundle the data into a single cluster (be sure to turn it into a typedef!), and write that cluster of always-correlated data to your channel wire.

 

Over on the consumer side, your state logic can decide when the incoming data can be ignored, when it needs to be saved immediately, when you need to react to a user's request to manually save.

 

Again, keep the producer lean.  Just do the DAQ work there, no complicated state logic, no forced timer delays.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy coming to an end (finally!). Permanent license pricing remains WIP. Tread carefully.
0 Kudos
Message 7 of 11
(128 Views)

Thank you @Kevin.

 

I will work on having a state machine on the consumer side. I have a question though: consider AI data read continuously inside the producer loop and sent to the consumer. The program runs for some time, waits for certain conditions to be met, and then becomes ready to save the current data. Wouldn't the stream channel output the first samples that it had stored and not the current ones (FIFO, I guess...)? Do I need to apply the logic for 'when to send the data' on the producer side, or is there a way to handle this on the consumer end as well?

 

lza

0 Kudos
Message 8 of 11
(117 Views)

There's not really a single right way to decide how to split up logic -- whether to enable / disable  sending on the producer side or whether to process / discard on the consumer side.

 

I've developed the habit (and it has worked out well) to keep my DAQ loops as simple as possible because that helps prevent DAQ timing & buffering errors which can be catastrophic in a particular test run.  Usually my DAQ loop just captures data and dispatches it up to a "main brain" loop.  It doesn't need to know what the rest of the app is doing, or whether it even wants the data right now.  It's job is simply to capture and send, capture and send.  I try to defer app-specific decision logic to the consumer.

 

To avoid having the consumer loop operate on stale data, you would need the consumer loop to be constructed to regularly read data from the stream channel, keeping up with the DAQ producer loop that sends it.  The consumer might often ignore & discard that data, but the act of reading it prevents the buildup of a backlog of stale data.

 

The consumer loop needs a shift register that maintains info about its operating state.  It needs logic that knows when and how to change those operating state parameters and descriptors.  As it reads data delivered by the DAQ loop, it consults its state info to decide what to do with it.

 

You may have a case where you don't want your consumer getting stuck *waiting* for data from the producer.  If so, it might make sense for your stream reader to have a short timeout and then you have code to handle the often-expected timeout condition.

 

I realize these aren't complete explanations, just a few tips that I hope help to point you in a useful direction and give you some terms you can search and learn more about.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy coming to an end (finally!). Permanent license pricing remains WIP. Tread carefully.
0 Kudos
Message 9 of 11
(95 Views)

In the attached zip file, I have thrown a stepper motor control (DO and CO) into the mix. Based on the status of the motor, a message is sent to the producer loop to start sending AI/CI data to the consumer loop via a channel wire.

 

Is this a reasonable approach?

 

Thanks,

lza

 

0 Kudos
Message 10 of 11
(38 Views)