From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Dynamic Signal Acquisition

cancel
Showing results for 
Search instead for 
Did you mean: 

Help with Basic Configuration of Parameters for NIDAQmx

Hey all,

 

I'm struggling to get data from my DAQ at the rate I expect. I've read through the scattered documentation I've been able to find, but it does not behave as I expect.

 

I simply want to have a loop that continually reads the latest sample from the DAQ and publishes it (using the robot operating system). Unfortunatelly, I'm seeing delays on the order of many seconds between when events occur and when they show up from the DAQ. I suspect that events are stacking up in the buffer faster than I'm reading them. How should I deal with this?

 

	// Timing parameters
	char clockSource[] = "OnboardClock";

	// Data read parameters
	#define	bufferSize (uInt32)1
	float64 data[bufferSize * channelCount];
	// how many points to read per channel
	int32 pointsToRead = bufferSize;
	int32 pointsRead;
	// timeout in seconds... should be even smaller than 1.0s
	float64 timeout = 10.0;
	int32 totalRead = 0;
	bool isHigh = false;

	adc_msgs::ADCSignal adc;

	DAQmxErrChk(DAQmxBaseCreateTask("", &taskHandle));
	DAQmxErrChk(
			DAQmxBaseCreateAIVoltageChan(taskHandle, channels.c_str(),"",DAQmx_Val_Cfg_Default,min,max,DAQmx_Val_Volts,NULL));
		
	// The sampleRate used here determines how fast samples are read on the hardware side into its internal buffer
	DAQmxErrChk(
			DAQmxBaseCfgSampClkTiming(taskHandle, clockSource, sampleRate, DAQmx_Val_Rising, DAQmx_Val_ContSamps, 1));
	DAQmxErrChk(DAQmxBaseCfgInputBuffer(taskHandle, 200000));
	DAQmxErrChk(DAQmxBaseStartTask(taskHandle));
	


	while (ros::ok()) {
		DAQmxErrChk(
				DAQmxBaseReadAnalogF64(taskHandle,pointsToRead,timeout,DAQmx_Val_GroupByScanNumber,data,bufferSize*channelCount,&pointsRead,NULL));
				
		adc.header.stamp = ros::Time::now();
		adc.signal.clear();
		if (meta != NULL){
			//ROS_INFO('Meta: %s', meta->data.c_str());
			adc.meta = meta->data.c_str();
		}
	
		for (int i = 0; i < channelCount; ++i) {
			float32 val = (float32) data[i];
			adc.signal.push_back(val);
			
// here for debugging if (i==0) { if (!isHigh && val > 1.0) { isHigh = true; printf("going high\n"); } if (isHigh && val < 1.0) { isHigh = false; printf("going low\n"); } } } pub.publish(adc); ros::spinOnce();
// this ensures we sleep for the appropriate amount of time so that the loop rate is
// sampleRate loop_rate.sleep(); }

 

0 Kudos
Message 1 of 8
(7,030 Views)

Hello,

 

I would like to assist you with this question. What specific hardware are you using?

Warm Regards,

Josh
0 Kudos
Message 2 of 8
(7,006 Views)

Thanks!

 

NI - USB 6216

0 Kudos
Message 3 of 8
(7,004 Views)

Thank you for the response. 

 

Have you tried changing how many samples per channel you are reading?

 

Setting the samples per channel to read at one-fourth to one-half of the buffer size is recommended.

 

Needless to say, do not set the number of samples per channel to read too high because you will wait for the number of samples per channel in the buffer to equal the number of samples per channel to read. The time spent waiting for samples to fill the buffer could be spent emptying the buffer.

 

 

Warm Regards,

Josh
0 Kudos
Message 4 of 8
(6,997 Views)

I think maybe I have a misunderstanding of how this should work.

 

Say I want to sample at 1kHz, so I need to get a value every 1ms. Can my while loop not just grab the latest value from the channel? Ideally, I think it would make sense if I used a higher sampleRate than the actual rate at which I want data, say 2kHz, and a buffer that only stored one sample, so that the buffer always contained the latest value. Everything I've tried to get this kind of behavior hasn't worked.

 

Regarding your suggestion:

If I use this buffered system, won't I end up getting burst behavior? So, as you propose I would try to read in 250 samples on each iteration. So that means in one second I would end up burst publishing 250 samples 4 times.

Is that the kind of behavior I should expect from this sort of system? Is there no way to do a non-blocking call when reading?

 

I've tried to do an on demand loop, but when I do that the best I can get is about 300Hz on my system. This is very surprising to me as audio recording devices, which work over USB, sample above 44kHz, with low latency. Are they in fact working in a bursting fasion as well or are the devices just designed better?

0 Kudos
Message 5 of 8
(6,995 Views)

If you would like to replace stored data in the queue, you will want to enqueue the date at opposite end (ie front of queue). This will prioritize the last element added to the queue. With a smaller queue, you will run the risk of overflow that could cause an error. 

 

From a software timing standpoint, your software (especially while loops with for loops inside) could be causing a delay in your data acquiring. This can also be compounded with other software running on your computer. All of these can affect the speed of your data processing.

Warm Regards,

Josh
0 Kudos
Message 6 of 8
(6,976 Views)

I had a look at your attached image, but I'm not using LabView. Do you know if those sorts of queing operations are available in the C API? I haven't come across anything like that.

0 Kudos
Message 7 of 8
(6,972 Views)

I will consult with my colleagues regarding LIFO in C. In the meantime, have you loked at these two articles? The example assistant may be of particular interest for you.

 

Text Based NI-DAQmx Examples 

 

Getting Started with Text Based DAQmx

Warm Regards,

Josh
0 Kudos
Message 8 of 8
(6,960 Views)