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] ; 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:
[MRPT]/samples/NIDAQ_test
Sample .ini files for rawlog-grabber in [MRPT]/share/mrpt/config_files/rawlog-grabber/
NI DAQmx C reference: http://others-help.mrpt.org/ni-daqmx_c_reference_help/
NI DAQmx Base 3.x C reference: http://others-help.mrpt.org/ni-daqmx_base_3.x_c_function_reference/
Go to http://ni.com and download the “DAQmx Base” package for your OS. Install following NI’s instructions. As of 2013, the latest version is 3.7.
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 struct TInfoPerTask; struct TaskDescription; // fields std::vector<TaskDescription> task_definitions; // construction CNationalInstrumentsDAQ(); // methods virtual void initialize(); void stop(); virtual void doProcess(); void readFromDAQ(std::vector<mrpt::obs::CObservationRawDAQ::Ptr>& outObservations, bool& hardwareError); void writeAnalogOutputTask( size_t task_index, size_t nSamplesPerChannel, const double* volt_values, double timeout, bool groupedByChannel ); void writeDigitalOutputTask(size_t task_index, bool line_value, double timeout); 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.
Construction
CNationalInstrumentsDAQ()
Constructor.
Methods
virtual void initialize()
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()
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)
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()
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.