# class mrpt::hwdrivers::CNationalInstrumentsDAQ¶

An interface to read from data acquisition boards compatible with National Instruments “DAQmx Base” or “DAQmx”.

Refer to DAQmx Base C API reference online to learn more on the concepts of “channels”, “tasks” (which in this MRPT class are mapped to independent grabbing threads), etc. If both DAQmx and DAQmxBase are installed in the system, DAQmx will be used. This class API isolate the user from the usage of one or another specific library.

This class can be used as a sensor from the application “rawlog-grabber”, or directly as a C++ class from a user program. Refer to the example: [MRPT]/samples/NIDAQ_test

Samples will be returned inside mrpt::obs::CObservationRawDAQ in “packets” of a predefined number of samples, which can be changed by the user through the “samplesPerChannelToRead” parameter of each task.

For multichannels tasks, samples will be interleaved. For example, the readings from successive timesteps for 4 ADC channels will be available in the ADC vector inside mrpt::obs::CObservationRawDAQ in this order:

• A0[0] A1[0] A2[0] A3[0] A0[1] A1[1] A2[1] A3[1] A0[2] A1[2] A2[2] A3[2] …

The sensor label (field “m_sensorLabel”) of each grabbed observation will be the concatenation of this class sensor label, a dot (“.”) and the task label (default=”task###”, with ### the task index).

 PARAMETERS IN THE ".INI"-LIKE CONFIGURATION STRINGS:
-------------------------------------------------------
[supplied_section_name]
; (Parameters below follow NIs DAQmx API notation)

; Channels, separated by commas if more than one.
;  - "ao": Analog outputs
;  - "di": Digital inputs
;  - "do": Digital inputs
;  - "ci_period",
;    "ci_count_edges", "ci_pulse_width",
;    "ci_lin_encoder", "ci_ang_encoder" : Counters & encoders (WARNING: NI
says "a task can include only one counter input channel")
;  - "co_pulses": Output digital pulses (WARNING: NI says "a task can include
only one counter output channel")
;
task0.channels = ai  //, ao, di, do, ci_ang_encoder
mrpt::obs::CObservation sensor label (default: task number)
task0.samplesPerSecond = 1000 // Samples per second. Continuous (infinite)
sampling is assumed.
once from each channel. ;task0.bufferSamplesPerChannel = 200000 // Increase
if you have errors about " Onboard device memory overflow.(...)"

task0.ai.physicalChannelCount = 5  // *IMPORTANT* This must be the total
number of channels listed in "physicalChannel" (e.g. 4 for "Dev1/ai0:3")
task0.ai.terminalConfig  = DAQmx_Val_Cfg_Default | DAQmx_Val_RSE |
DAQmx_Val_NRSE | DAQmx_Val_Diff   // One of these strings

; Analog output channel params.
task0.ao.physicalChannelCount = 4  // *IMPORTANT* This must be the total
number of channels listed in "physicalChannel" (e.g. 1 for "Dev1/ao0")

; Digital input channel params.

; Digital input channel params.

; Counter: period of a digital signal
task0.ci_period.minVal   = 0   // The minimum value, in units, that you
expect to measure. task0.ci_period.maxVal   = 0   // The minimum value, in
units, that you expect to measure. task0.ci_period.units    =
DAQmx_Val_Seconds | DAQmx_Val_Ticks  // One of these strings
task0.ci_period.edge     = DAQmx_Val_Rising | DAQmx_Val_Falling // One of
these strings
task0.ci_period.measTime = 0   // NI says: "Always pass 0 for this
parameter." task0.ci_period.divisor  = 1   // NI says: "Always pass 1 for
this parameter."

; Counter: count the number of rising or falling edges of a digital signal
task0.ci_count_edges.edge           = DAQmx_Val_Rising | DAQmx_Val_Falling //
One of these strings
task0.ci_count_edges.initialCount   = 0    // The value from which to start
counting
| DAQmx_Val_ExtControlled  // One of these strings

; Counter:  measure the width of a digital pulse
task0.ci_pulse_width.minVal       = 0   // The minimum value, in units, that
you expect to measure.
task0.ci_pulse_width.maxVal       = 0   // The minimum value, in units, that
you expect to measure.
task0.ci_pulse_width.units        = DAQmx_Val_Seconds | DAQmx_Val_Ticks  //
One of these strings
task0.ci_pulse_width.startingEdge = DAQmx_Val_Rising | DAQmx_Val_Falling //
One of these strings

; Counter:  uses a linear encoder to measure linear position
task0.ci_lin_encoder.decodingType = DAQmx_Val_X1 | DAQmx_Val_X2 |
DAQmx_Val_X4 | DAQmx_Val_TwoPulseCounting // One of these strings
task0.ci_lin_encoder.ZidxEnable   = false | true | 0 | 1    //  enable z
indexing?
task0.ci_lin_encoder.ZidxVal      = 0 // The value, in units, to which to
reset the measurement when signal Z is high and signal A and signal B are at
the states you specify with ZidxPhase.
DAQmx_Val_AHighBLow | DAQmx_Val_ALowBHigh | DAQmx_Val_ALowBLow  // One of
these strings task0.ci_lin_encoder.units        = DAQmx_Val_Meters |
DAQmx_Val_Inches | DAQmx_Val_Ticks  // One of these strings
task0.ci_lin_encoder.distPerPulse = 0.1  // The distance measured for each
pulse the encoder generates. Specify this value in units.
task0.ci_lin_encoder.initialPos   = 0.0 // The position of the encoder when
the measurement begins. This value is in units.

; Counter:  uses an angular encoder to measure angular position
task0.ci_ang_encoder.decodingType = DAQmx_Val_X1 | DAQmx_Val_X2 |
DAQmx_Val_X4 | DAQmx_Val_TwoPulseCounting // One of these strings
task0.ci_ang_encoder.ZidxEnable   = 0 | 1 | false | true  //  enable z
indexing
task0.ci_ang_encoder.ZidxVal      = 0 // The value, in units, to which to
reset the measurement when signal Z is high and signal A and signal B are at
the states you specify with ZidxPhase.
DAQmx_Val_AHighBLow | DAQmx_Val_ALowBHigh | DAQmx_Val_ALowBLow  // One of
these strings task0.ci_ang_encoder.units        = DAQmx_Val_Degrees |
DAQmx_Val_Radians | DAQmx_Val_Ticks  // One of these strings
task0.ci_ang_encoder.pulsesPerRev = 512  // The number of pulses the encoder
generates per revolution.
task0.ci_ang_encoder.initialAngle = 0.0 // The position of the encoder when
the measurement begins. This value is in units.

; Output digital pulses:
task0.co_pulses.initialDelay      = 0  // The amount of time in seconds to
wait before generating the first pulse.
task0.co_pulses.freq              = 100 // The frequency of the pulses to
generate (Hertz)
task0.co_pulses.dutyCycle         = 0.5  // The width of the pulse divided by
the pulse period.

This class requires compiling MRPT with support for “NI DAQmx” or “NI DAQmx Base”. While compiling MRPT, check the “MRPT_HAS_NI_DAQmx”/”MRPT_HAS_NI_DAQmxBASE” option and correctly set the new variables to the library include directory and library file.

As of 2013, NI seems not to support compiling 64bit programs, so you can must build MRPT for 32bits if you need this class.

#include <mrpt/hwdrivers/CNationalInstrumentsDAQ.h>

class CNationalInstrumentsDAQ:
public mrpt::system::COutputLogger,
public mrpt::hwdrivers::CGenericSensor
{
public:
// structs

//
fields

//
methods

virtual void initialize();
void stop();
virtual void doProcess();

size_t nSamplesPerChannel,
const double* volt_values,
double timeout,
bool groupedByChannel
);

bool checkDAQIsWorking() const;
};

## Inherited Members¶

public:
// structs

struct TMsg;

//
methods

CGenericSensor& operator = (const CGenericSensor&);
virtual void doProcess() = 0;

## Fields¶

std::vector<TaskDescription> task_definitions

Publicly accessible vector with the list of tasks to be launched upon call to CNationalInstrumentsDAQ::initialize().

Changing these while running will have no effects.

## Methods¶

virtual void initialize()

void stop()

It is automatically called at destruction.

virtual void doProcess()

This method will be invoked at a minimum rate of “process_rate” (Hz)

Parameters:

 This method must throw an exception with a descriptive message if some critical error is found.
void readFromDAQ(std::vector<mrpt::obs::CObservationRawDAQ::Ptr>& outObservations, bool& hardwareError)

It returns a maximum number of one observation object per running grabber threads, that is, per each DAQmx “task”. This method MUST BE CALLED in a timely fashion by the user to allow the proccessing of incoming data. It can be run in a different thread safely. This is internally called when using the alternative CGenericSensor::doProcess() interface. No observations may be returned if there are not samples enough yet from any task.

void writeAnalogOutputTask(
size_t nSamplesPerChannel,
const double* volt_values,
double timeout,
bool groupedByChannel
)

Set voltage outputs to all the outputs in an AOUT task For the meaning of parameters, refere to NI DAQmx docs for DAQmxBaseWriteAnalogF64()

The number of samples in volt_values must match the number of channels in the task when it was initiated.

void writeDigitalOutputTask(size_t task_index, bool line_value, double timeout)

Changes the boolean state of one digital output line.

For the meaning of parameters, refere to NI DAQmx docs for DAQmxBaseWriteAnalogF64() The number of samples in volt_values must match the number of channels in the task when it was initiated.

bool checkDAQIsWorking() const

Returns true if initialize() was called and at least one task is running.

Returns true if initialize() was called successfully.