07-11-2018 09:53 AM
I am trying to use a NI USB-6251 to collect an analog waveform using the PyDAQmx package (outlined here: https://pythonhosted.org/PyDAQmx/). Due to my lack of prior experience with this type of work, I am trying to implement an oversimplified script, calling as few internal functions as possible, to collect a waveform from one channel on the device. My code is as follows:
from PyDAQmx import * import numpy from ctypes import * # Example from https://pythonhosted.org/PyDAQmx/usage.html to develop understanding # Declaration of variable passed by reference taskHandle = TaskHandle() read = int32() data = numpy.zeros((100,), dtype=numpy.float64) try: #DAQmx Configure Code DAQmxCreateTask(b'', byref(taskHandle)) DAQmxCreateAIVoltageChan(taskHandle, #Handle of task to associate voltage channel b'Dev1/ai0', #Name of physical channel to be used (Device 1, Analog Input 0) b'', #Name to associate with newly associated channel DAQmx_Val_Cfg_Default, #Configuration of channel -1.5, #Minimum expected measurement (in units) 1.5, #Maximum expected measurement (in units) DAQmx_Val_Volts, #Defines units, in this case Volts None) #Nume of custom scale to apply, must be null if "units" set to Volts DAQmxCfgSampClkTiming(taskHandle, #Handle of task to associate sampling info b'', #Source terminal of samp clock. To use device internal clock, use NULL 100000.0, #Sampling rate in samples/sec/channel DAQmx_Val_Rising, #Specifies clock edge to acquire samples DAQmx_Val_FiniteSamps, #Defines continuous or finite operation of task 100) #Number of samples to acquire #DAQmx Start Code DAQmxStartTask(taskHandle) #DAQmx Read Code DAQmxReadAnalogF64(taskHandle, #Handle of task whose data will be read 100, #Number of samples per channel to read 10.0, #Timeout limit in seconds DAQmx_Val_GroupByChannel, #Specifies whether samples are interleaved data, #Size of the array into which samples are read bool32(True), #Reserved for future use, pass NULL byref(read), #Array to read samples into None) #Actual number of samples read from each channel (in this example, don't care) print ("Acquired %d points"%read.value) csvbuffer = [] for i in read: csvbuffer.append(i) with open('csvbuffer', 'wt') as fout: csvout = csv.writer(fout) csvout.writerow(csvbuffer) except DAQError as err: print ("DAQmx Error: %s"%err) finally: if taskHandle: # DAQmx Stop code DAQmxStopTask(taskHandle) DAQmxClearTask(taskHandle)
Running the above code generates the following error related to buffer size:
DAQmx Error: Buffer is too small to fit read data. Buffer Length: 1 Required Buffer Size in Samples: 100 Task Name: _unnamedTask<1> Status Code: -200229 in function DAQmxReadAnalogF64
To my knowledge, the buffer is supposed to be automatically generated and modified to hold the number of samples outlined by the used functions, which in this case is 100, but could be anything. Is there something that I am obviously doing wrong? I copied this script wholesale from the PyDAQmx website as an "easy example," so I'm shocked that I've had so much trouble with it.
Thanks in advance for any help you can provide!
Solved! Go to Solution.
07-11-2018 11:06 AM
I don't really speak python, but the some things in the read call arguments, their comments, and the variable declarations/initialization look a little suspicious to me. I'll excerpt the stuff I mean:
@JackIversonread = int32() data = numpy.zeros((100,), dtype=numpy.float64) DAQmxReadAnalogF64(taskHandle, #Handle of task whose data will be read 100, #Number of samples per channel to read 10.0, #Timeout limit in seconds DAQmx_Val_GroupByChannel, #Specifies whether samples are interleaved data, #Size of the array into which samples are read bool32(True), #Reserved for future use, pass NULL byref(read), #Array to read samples into None) #Actual number of samples read from each channel (in this example, don't care)
Starting with the 'data' argument, it isn't clear that the arguments, comments, and variables really match up. The 'data' variable appears to be initialized as an array of 64-bit floats set to 0 value. But the argument comment expects an array size parameter. The 'read' variable has a comment that the argument should be the array to read samples into. But the variable declaration doesn't look right to me (though again, I don't speak python). The other arguments 'bool32(True)' and 'None' also don't seem to correspond well to the comments about what's expected.
That's about all I can speculate about. The other DAQmx function calls looked sensible, assuming the comments were properly aligned to the argument lists.
-Kevin P
07-11-2018 11:19 AM
You can also try to use nidaqmx instead of pydaqmx https://nidaqmx-python.readthedocs.io/en/latest/ which was created internally at NI.
07-11-2018 11:36 AM
Thanks for the advice, Kevin! I'm not super Python-literate either. My supervisor on this project prefers Python, and sees it as our best option for creating modular tests to be controlled by a single test executive. I agree with your take on the conflict between my argument datatypes and the descriptions for each argument in my comments. Weirdly enough, the function will only run properly if I use these weird variable types. As written above, the script returns errors provided by the hardware, but when modified in any way the errors become ArgumentErrors generated by the compiler itself.
I am strongly considering switching to NI-DAQmx, as that was where I started on this project, but the main purpose of PyDAQmx is to allow me to avoid using ctypes variable types and cluttering up the scripts I'm writing. I hoped that PyDAQmx would hide that complexity and allow me to work at a higher level, but that is starting to look like more work than it's worth.
07-11-2018 01:12 PM
I don't think I understand your preference for PyDAQmx...can you elaborate?
https://github.com/ni/nidaqmx-python/blob/master/nidaqmx_examples/ai_voltage_sw_timed.py is an example for nidaqmx which returns multiple sw-timed samples. Seems pretty clean to me.