Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

NI USB-6251 with PyDAQmx, buffer size limit issue

Solved!
Go to solution

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!

0 Kudos
Message 1 of 5
(3,110 Views)
Solution
Accepted by topic author JackIverson

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:


@JackIverson 
read = 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

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 2 of 5
(3,099 Views)

You can also try to use nidaqmx instead of pydaqmx https://nidaqmx-python.readthedocs.io/en/latest/ which was created internally at NI.

0 Kudos
Message 3 of 5
(3,095 Views)

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.

0 Kudos
Message 4 of 5
(3,091 Views)

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. 

0 Kudos
Message 5 of 5
(3,078 Views)