Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Binding AIChannel data to a form control (gauge/meter/tank) in realtime

I am using .NET 2003 with Measurement Studio 7.1, preferably coding in C#. For hardware I am reading the conditioned (0 to 10V) output of a load cell and two strain gauges through a 6062E DAQ card.

I would like to bind gauge and meter form controls (not ActiveX) to the data on the AI channels in realtime. As far as I can tell, however, the only way to get AI channel data is through the method demonstrated in the ContAcqVoltageSamples_IntClk example. i.e. You have to create a virtual channel, create an AnalogMultiChannelReader, register a callback then call BeginReadMultiSample.
This gives you an array of doubles with some specified number of samples. I have tried reading one sample at a time but the system overwrites the buffer too fast for this, and obviously an array of 100+ values doesn't map to a gauge value. I would like to simply take the current virtual channel value and bind it to a WindowsForms.Meter.Value but I see absolutely no property or data object that provides the voltage reading from the AIChannel object.

How can I map my realtime data to a form control for display? This seems like it should be a common task in MStudio but I can find no example code or documentation of any sort on it.

Thank you for you help,

~J

PS Sorry for the crosspost from the hardware forum, I'm not sure how this got submitted to that forum by mistake.
0 Kudos
Message 1 of 5
(4,011 Views)
Hello

From what I understand, you have a continuous acq. running and you want to be able to bind the incoming data to a guage or a meter?
If you are getting array data returned, it won't make much sense to bind it to a meter to a guage ( as you mentioned). How would you decide which datapoint should be displayed from the buffer? Even if you displayed each data point one by one, that won't make much sense to the user who will just see alot of numbers changing very quickly. Are you trying to display the data in a table format?

Data like this would make more sense if you were to chart it on the .NET graph using PlotYAppend since you can easily see the data trends this way.

The .NET UI controls cannot be bound directly to an AIChannel object, since they are not aware of that object. The only way to get the data from an aquisition is to create a reader object using the Task stream and then using the appropriate Read method. Use the Begin/End Reads to read the data asynchronously. Use the Read methods to do a synchronous read. Once you acquire the data, just plot the buffer to the graph to display it.

I hope this helps. Let me know if I missed anything. If you could describe the application some more, perhaps I can provide a better solution.
Bilal Durrani
NI
0 Kudos
Message 2 of 5
(3,981 Views)
Thank you for your response, it at least made clear the fact that I cannot directly bind AIChannel data to a gauge or meter control.

I'm designing a VI, essentially, to monitor and log sensor data from a hydraulic system. This includes 2 pressure gauges, a load cell, a flow meter and a tachometer (which will be a digital input from an RS232 connection). All the analog sensor signals are filtered (4 Hz lowpass) and amplified to be in the 0 to 10V range. I would like to be able to simultaneously graph the data to show change over time, on the order of the last 5 to 10 seconds, as well as using the gauge and meter controls to indicate the realtime values for each sensor.
In addition the user should be able to select which sensors are active (turn on/off data reading) and also which sensor values to display in the graph window.

The solution I'm currently trying is to use the method demonstrated in the ContAcqVoltageSamples_IntClk example to use an AnalogMultiChannelReader object and callback to perform a BeginReadMultiSample and plot the data. At the same time in a different thread I am using a different AnalogMultiChannelReader object to do a ReadSingleSample and set the meter controls to that data.

Since the channel readers are threadsafe I assume this will not cause a conflict with the buffer and I am hoping this will provide a very near realtime snapshot of the system.

I have attached my code, it's pretty rough, but at this point I think I may be on the right track. However if you could take a quick look at it and tell me if there is a better way to do this it would be most appreciated.

~J

Also in the code I've attached, the start/stop buttons can be pressed once but if you attempt to start again there is an exception thrown on daqmxTask.Start() saying "the specified operation cannot be performed while the task is running". I don't understand why this is happening if the daqmxTask.Stop() has been successfully executed beforehand. Any thoughts?
0 Kudos
Message 3 of 5
(3,974 Views)
One thing to look out for would be how you manipulate the UI controls in the BeginVIDataRead method. You will run into problems if you try and access UI controls in a thread other than the one it was created in. BeginInvoke, EndInvoke, Invoke, InvokeRequired, and CreateGraphics are the only members of the UI controls that are thread safe.
The reason why the example does not do this for the graph control in the AnalogInCallback method is because we specify the synchronizing object of the analogInReader to be the form itself.

analogInReader.SynchronizingObject = this;

This ensures that the callback will occur in the same thread as the form itself. Check out the Help topic "Asynchronously Reading and Writing with the NI-DAQmx .NET Class Library" for more information. The DAQmx .NET API help is integrated into the Visual Studio 2003 Help.

What might be happening is that the async callback in the user control might not have completed by the time you call start again. The documentation for Task.Stop states

If an asynchronous read or write on the task is in progress, Stop does not return until the data from the pending read or write has been transferred to or from the task buffer. Stop does not wait for read or write asynchronous callback methods to finish, however.

The usercontrol sets up the task and async callbacks for you. You don't have to configure the timing and callbacks for a task that is returned to you by the user control. If you look at the code for the user control, its already doing that for you. This code is in the DAQmxTask1.cs. This code is autogenerated for you when you use the DAQ Assistant to generate the configuration code for you.

The DAQmx shipping example sets up the async callsbacks explicitly because its not done anywhere else. If you want to follow the pattern that the examples are using, I would recommend just using the configured tasks returned to you by the DAQmxTask1 class and then setting up the asyc callbacks yourself. Because it looks like you basically recreate the same code that is already present in the usercontrol inside your BeginVIDataRead method. When you call this.daQmxUserControl11.Start(), you start up the async callbacks in the user control.

So you can try using either the usercontrol to return the data to you, or use the configured task and then follow the pattern that the examples use.But I think the problem might be happening because of the multiple BeginReads that are being called on the same task. The daqmxUsercontrol stop might only be stopping one of the reads but not the ones that you started up.

I hope this helps. Let me know if missed anything or if something was not clear.
Bilal Durrani
NI
Message 4 of 5
(3,953 Views)
If all you want is to get access to the acquired data in the user control, you can register your own DataReadyHandler with the usercontrol. This will return the data to you that you can process as needed and calling stop on the user control will make sure it stops the async callbacks in the user control in a clean fashion.
Like this:

daQmxUserControl11.DataReady +=new MeasurementStudio1.DAQmxUserControl1.TaskEventHandler(daQmxUserControl11_DataReady);
.
.
.
private void daQmxUserControl11_DataReady(object sender, MeasurementStudio1.DAQmxUserControl1.TaskEventArgs args)
{
double[,] data = args.GetData();
}
Bilal Durrani
NI
0 Kudos
Message 5 of 5
(3,949 Views)