Class CNationalInstrumentsDAQ

Nested Relationships

Nested Types

Inheritance Relationships

Base Types

Class Documentation

class CNationalInstrumentsDAQ : public mrpt::system::COutputLogger, public mrpt::hwdrivers::CGenericSensor

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]/mrpt_examples_cpp/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]
; Number of tasks (each will run in a thread). Task indices are 0-based.
; (Parameters below follow NIs DAQmx API notation)
num_tasks  = 1

; Channels, separated by commas if more than one.
;  - "ai": Analog inputs
;  - "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
;task0.taskLabel= MY_LABEL     // Optional textual label to build the
mrpt::obs::CObservation sensor label (default: task number)
task0.samplesPerSecond = 1000 // Samples per second. Continuous (infinite)
sampling is assumed.
task0.samplesPerChannelToRead = 1000  // The number of samples to grab at
once from each channel. ;task0.bufferSamplesPerChannel = 200000 // Increase
if you have errors about " Onboard device memory overflow.(...)"

; Analog input channel params.
task0.ai.physicalChannel = Dev1/ai0:3, Dev1/ai6
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
task0.ai.minVal          = -10.0    // Volts
task0.ai.maxVal          =  10.0    // Volts

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

; Digital input channel params.
task0.di.line           = Dev1/port1/line0

; Digital input channel params.
task0.do.line           = Dev1/port1/line2

; Counter: period of a digital signal
task0.ci_period.counter  = Dev1/ctr0
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.counter        = Dev1/ctr0
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
task0.ci_count_edges.countDirection = DAQmx_Val_CountUp | DAQmx_Val_CountDown
| DAQmx_Val_ExtControlled  // One of these strings

; Counter:  measure the width of a digital pulse
task0.ci_pulse_width.counter      = Dev1/ctr0
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.counter      = Dev1/ctr0
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.
task0.ci_lin_encoder.ZidxPhase    = DAQmx_Val_AHighBHigh |
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.counter      = Dev1/ctr0
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.
task0.ci_ang_encoder.ZidxPhase    = DAQmx_Val_AHighBHigh |
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.
task0.ci_ang_encoder.decimate     = 1   // Grab 1 out of N readings

; Output digital pulses:
task0.co_pulses.counter           = Dev1/ctr1
task0.co_pulses.idleState         = DAQmx_Val_High | DAQmx_Val_Low
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.

See also:

Public Functions

CNationalInstrumentsDAQ()

Constructor

~CNationalInstrumentsDAQ() override

Destructor

virtual void initialize() override

Setup and launch the DAQ tasks, in parallel threads. Access to grabbed data with CNationalInstrumentsDAQ::readFromDAQ() or the standard CGenericSensor::doProcess()

void stop()

Stop the grabbing threads for DAQ tasks. It is automatically called at destruction.

virtual void doProcess() override

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

Throws:

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)

Receives data from the DAQ thread(s). 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 task_index, 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()

Note

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()

Note

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.

Public Members

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.

Protected Functions

virtual void loadConfig_sensorSpecific(const mrpt::config::CConfigFileBase &configSource, const std::string &iniSection) override

See the class documentation at the top for expected parameters

struct TaskDescription

Each of the tasks to create in CNationalInstrumentsDAQ::initialize(). Refer to the docs on config file formats of mrpt::hwdrivers::CNationalInstrumentsDAQ to learn on the meaning of each field. Also, see National Instruments’ DAQmx API docs online.

Public Functions

TaskDescription()

Public Members

bool has_ai = {false}
bool has_ao = {false}
bool has_di = {false}
bool has_do = {false}
bool has_ci_period = {false}
bool has_ci_count_edges = {false}
bool has_ci_pulse_width = {false}
bool has_ci_lin_encoder = {false}
bool has_ci_ang_encoder = {false}
bool has_co_pulses = {false}
double samplesPerSecond = {1000.0}

Sample clock config: samples per second. Continuous (infinite) sampling is assumed.

std::string sampleClkSource

Sample clock source: may be empty (default value) for some channels.

uint32_t bufferSamplesPerChannel = {200000}

(Default=0) From NI’s docs: The number of samples the buffer can hold for each channel in the task. Zero indicates no buffer should be allocated. Use a buffer size of 0 to perform a hardware-timed operation without using a buffer.

uint32_t samplesPerChannelToRead = {1000}

(Default=1000) The number of samples to grab at once from each channel.

std::string taskLabel

(Default=”task###”)

struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ai_t ai
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ao_t ao
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_di_t di
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_do_t douts
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_period_t ci_period

Counter: period of a digital signal

struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_count_edges_t ci_count_edges
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_pulse_width_t ci_pulse_width
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_lin_encoder_t ci_lin_encoder
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_ang_encoder_t ci_ang_encoder
struct mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_co_pulses_t co_pulses
struct desc_ai_t

Analog inputs

Public Functions

desc_ai_t() = default

Public Members

std::string physicalChannel
std::string terminalConfig = {"DAQmx_Val_NRSE"}
double minVal = {-10}
double maxVal = {10}
unsigned int physicalChannelCount = {0}

IMPORTANT This must be the total number of channels listed in “physicalChannel” (e.g. 4 for “Dev1/ai0:3”)

struct desc_ao_t

Analog outputs

Public Functions

desc_ao_t() = default

Public Members

std::string physicalChannel
unsigned int physicalChannelCount = {0}

IMPORTANT This must be the total number of channels listed in “physicalChannel” (e.g. 1 for “Dev1/ao0”)

double minVal = {-10}
double maxVal = {10}
struct desc_ci_ang_encoder_t

Counter: uses an angular encoder to measure angular position

Public Functions

desc_ci_ang_encoder_t() = default

Public Members

std::string counter
std::string decodingType
std::string ZidxPhase
std::string units
bool ZidxEnable = {false}
double ZidxVal = {0}
int pulsesPerRev = {512}
double initialAngle = {0}
int decimate = {1}
int decimate_cnt = {0}
struct desc_ci_count_edges_t

Counter: period of a digital signal

Public Functions

desc_ci_count_edges_t() = default

Public Members

std::string counter
std::string edge
std::string countDirection = {"DAQmx_Val_CountUp"}
int initialCount = {0}
struct desc_ci_lin_encoder_t

Counter: uses a linear encoder to measure linear position

Public Functions

desc_ci_lin_encoder_t() = default

Public Members

std::string counter
std::string decodingType
std::string ZidxPhase
std::string units
bool ZidxEnable = {false}
double ZidxVal = {0}
double distPerPulse = {0.1}
double initialPos = {0}
struct desc_ci_period_t

Public Functions

desc_ci_period_t() = default

Public Members

std::string counter
std::string units
std::string edge
double minVal = {0}
double maxVal = {0}
double measTime = {0}
int divisor = {1}
struct desc_ci_pulse_width_t

Counter: measure the width of a digital pulse

Public Functions

desc_ci_pulse_width_t() = default

Public Members

std::string counter
std::string units
std::string startingEdge
double minVal = {0}
double maxVal = {0}
struct desc_co_pulses_t

Output counter: digital pulses output

Public Functions

desc_co_pulses_t() = default

Public Members

std::string counter
std::string idleState = {"DAQmx_Val_Low"}
double initialDelay = {0}
double freq = {1000}
double dutyCycle = {0.5}
struct desc_di_t

Digital inputs (di)

Public Members

std::string line

The digital line (for example “Dev1/port0/line1”)

struct desc_do_t

Digital outs (do)

Public Members

std::string line

The digital line (for example “Dev1/port0/line1”)