Main MRPT website > C++ reference for MRPT 1.4.0
CNationalInstrumentsDAQ.h
Go to the documentation of this file.
1/* +---------------------------------------------------------------------------+
2 | Mobile Robot Programming Toolkit (MRPT) |
3 | http://www.mrpt.org/ |
4 | |
5 | Copyright (c) 2005-2016, Individual contributors, see AUTHORS file |
6 | See: http://www.mrpt.org/Authors - All rights reserved. |
7 | Released under BSD License. See details in http://www.mrpt.org/License |
8 +---------------------------------------------------------------------------+ */
9
10#ifndef CNationalInstrumentsDAQ_H
11#define CNationalInstrumentsDAQ_H
12
16#include <mrpt/synch/CPipe.h>
17#include <mrpt/system/threads.h>
18#include <list>
19
20namespace mrpt
21{
22 namespace hwdrivers
23 {
24 /** An interface to read from data acquisition boards compatible with National Instruments "DAQmx Base" or "DAQmx".
25 * Refer to DAQmx Base C API reference online to learn more on the concepts of "channels", "tasks" (which in this MRPT class
26 * are mapped to independent grabbing threads), etc.
27 * 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.
28 *
29 * This class can be used as a sensor from the application "rawlog-grabber", or directly as a C++ class from a user program.
30 * Refer to the example: [MRPT]/samples/NIDAQ_test
31 *
32 * Samples will be returned inside mrpt::obs::CObservationRawDAQ in "packets" of a predefined number of samples, which can
33 * be changed by the user through the "samplesPerChannelToRead" parameter of each task.
34 *
35 * For multichannels tasks, samples will be **interleaved**. For example, the readings from succesive timesteps for 4 ADC channels
36 * will be available in the ADC vector inside mrpt::obs::CObservationRawDAQ in this order:
37 *
38 * - A0[0] A1[0] A2[0] A3[0] A0[1] A1[1] A2[1] A3[1] A0[2] A1[2] A2[2] A3[2] ...
39 *
40 * The sensor label (field "m_sensorLabel") of each grabbed observation will be the concatenation of this class sensor label,
41 * a dot (".") and the task label (default="task###", with ### the task index).
42 *
43 * \code
44 * PARAMETERS IN THE ".INI"-LIKE CONFIGURATION STRINGS:
45 * -------------------------------------------------------
46 * [supplied_section_name]
47 * ; Number of tasks (each will run in a thread). Task indices are 0-based.
48 * ; (Parameters below follow NIs DAQmx API notation)
49 * num_tasks = 1
50 *
51 * ; Channels, separated by commas if more than one.
52 * ; - "ai": Analog inputs
53 * ; - "ao": Analog outputs
54 * ; - "di": Digital inputs
55 * ; - "do": Digital inputs
56 * ; - "ci_period",
57 * ; "ci_count_edges", "ci_pulse_width",
58 * ; "ci_lin_encoder", "ci_ang_encoder" : Counters & encoders (WARNING: NI says "a task can include only one counter input channel")
59 * ; - "co_pulses": Output digital pulses (WARNING: NI says "a task can include only one counter output channel")
60 * ;
61 * task0.channels = ai //, ao, di, do, ci_ang_encoder
62 * ;task0.taskLabel= MY_LABEL // Optional textual label to build the mrpt::obs::CObservation sensor label (default: task number)
63 * task0.samplesPerSecond = 1000 // Samples per second. Continuous (infinite) sampling is assumed.
64 * task0.samplesPerChannelToRead = 1000 // The number of samples to grab at once from each channel.
65 * ;task0.bufferSamplesPerChannel = 200000 // Increase if you have errors about " Onboard device memory overflow.(...)"
66 *
67 * ; Analog input channel params.
68 * task0.ai.physicalChannel = Dev1/ai0:3, Dev1/ai6
69 * task0.ai.physicalChannelCount = 5 // *IMPORTANT* This must be the total number of channels listed in "physicalChannel" (e.g. 4 for "Dev1/ai0:3")
70 * task0.ai.terminalConfig = DAQmx_Val_Cfg_Default | DAQmx_Val_RSE | DAQmx_Val_NRSE | DAQmx_Val_Diff // One of these strings
71 * task0.ai.minVal = -10.0 // Volts
72 * task0.ai.maxVal = 10.0 // Volts
73 *
74 * ; Analog output channel params.
75 * task0.ao.physicalChannel = Dev1/ao0, Dev1/ao2:4
76 * task0.ao.physicalChannelCount = 4 // *IMPORTANT* This must be the total number of channels listed in "physicalChannel" (e.g. 1 for "Dev1/ao0")
77 * task0.ao.minVal = -10.0 // Volts
78 * task0.ao.maxVal = 10.0 // Volts
79 *
80 * ; Digital input channel params.
81 * task0.di.line = Dev1/port1/line0
82 *
83 * ; Digital input channel params.
84 * task0.do.line = Dev1/port1/line2
85 *
86 * ; Counter: period of a digital signal
87 * task0.ci_period.counter = Dev1/ctr0
88 * task0.ci_period.minVal = 0 // The minimum value, in units, that you expect to measure.
89 * task0.ci_period.maxVal = 0 // The minimum value, in units, that you expect to measure.
90 * task0.ci_period.units = DAQmx_Val_Seconds | DAQmx_Val_Ticks // One of these strings
91 * task0.ci_period.edge = DAQmx_Val_Rising | DAQmx_Val_Falling // One of these strings
92 * task0.ci_period.measTime = 0 // NI says: "Always pass 0 for this parameter."
93 * task0.ci_period.divisor = 1 // NI says: "Always pass 1 for this parameter."
94 *
95 * ; Counter: count the number of rising or falling edges of a digital signal
96 * task0.ci_count_edges.counter = Dev1/ctr0
97 * task0.ci_count_edges.edge = DAQmx_Val_Rising | DAQmx_Val_Falling // One of these strings
98 * task0.ci_count_edges.initialCount = 0 // The value from which to start counting
99 * task0.ci_count_edges.countDirection = DAQmx_Val_CountUp | DAQmx_Val_CountDown | DAQmx_Val_ExtControlled // One of these strings
100 *
101 * ; Counter: measure the width of a digital pulse
102 * task0.ci_pulse_width.counter = Dev1/ctr0
103 * task0.ci_pulse_width.minVal = 0 // The minimum value, in units, that you expect to measure.
104 * task0.ci_pulse_width.maxVal = 0 // The minimum value, in units, that you expect to measure.
105 * task0.ci_pulse_width.units = DAQmx_Val_Seconds | DAQmx_Val_Ticks // One of these strings
106 * task0.ci_pulse_width.startingEdge = DAQmx_Val_Rising | DAQmx_Val_Falling // One of these strings
107 *
108 * ; Counter: uses a linear encoder to measure linear position
109 * task0.ci_lin_encoder.counter = Dev1/ctr0
110 * task0.ci_lin_encoder.decodingType = DAQmx_Val_X1 | DAQmx_Val_X2 | DAQmx_Val_X4 | DAQmx_Val_TwoPulseCounting // One of these strings
111 * task0.ci_lin_encoder.ZidxEnable = false | true | 0 | 1 // enable z indexing?
112 * 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.
113 * task0.ci_lin_encoder.ZidxPhase = DAQmx_Val_AHighBHigh | DAQmx_Val_AHighBLow | DAQmx_Val_ALowBHigh | DAQmx_Val_ALowBLow // One of these strings
114 * task0.ci_lin_encoder.units = DAQmx_Val_Meters | DAQmx_Val_Inches | DAQmx_Val_Ticks // One of these strings
115 * task0.ci_lin_encoder.distPerPulse = 0.1 // The distance measured for each pulse the encoder generates. Specify this value in units.
116 * task0.ci_lin_encoder.initialPos = 0.0 // The position of the encoder when the measurement begins. This value is in units.
117 *
118 * ; Counter: uses an angular encoder to measure angular position
119 * task0.ci_ang_encoder.counter = Dev1/ctr0
120 * task0.ci_ang_encoder.decodingType = DAQmx_Val_X1 | DAQmx_Val_X2 | DAQmx_Val_X4 | DAQmx_Val_TwoPulseCounting // One of these strings
121 * task0.ci_ang_encoder.ZidxEnable = 0 | 1 | false | true // enable z indexing
122 * 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.
123 * task0.ci_ang_encoder.ZidxPhase = DAQmx_Val_AHighBHigh | DAQmx_Val_AHighBLow | DAQmx_Val_ALowBHigh | DAQmx_Val_ALowBLow // One of these strings
124 * task0.ci_ang_encoder.units = DAQmx_Val_Degrees | DAQmx_Val_Radians | DAQmx_Val_Ticks // One of these strings
125 * task0.ci_ang_encoder.pulsesPerRev = 512 // The number of pulses the encoder generates per revolution.
126 * task0.ci_ang_encoder.initialAngle = 0.0 // The position of the encoder when the measurement begins. This value is in units.
127 * task0.ci_ang_encoder.decimate = 1 // Grab 1 out of N readings
128 *
129 * ; Output digital pulses:
130 * task0.co_pulses.counter = Dev1/ctr1
131 * task0.co_pulses.idleState = DAQmx_Val_High | DAQmx_Val_Low
132 * task0.co_pulses.initialDelay = 0 // The amount of time in seconds to wait before generating the first pulse.
133 * task0.co_pulses.freq = 100 // The frequency of the pulses to generate (Hertz)
134 * task0.co_pulses.dutyCycle = 0.5 // The width of the pulse divided by the pulse period.
135 * \endcode
136 *
137 * See also:
138 * - [MRPT]/samples/NIDAQ_test
139 * - Sample .ini files for rawlog-grabber in [MRPT]/share/mrpt/config_files/rawlog-grabber/
140 * - NI DAQmx C reference: http://others-help.mrpt.org/ni-daqmx_c_reference_help/
141 * - NI DAQmx Base 3.x C reference: http://others-help.mrpt.org/ni-daqmx_base_3.x_c_function_reference/
142 *
143 * DAQmx Base Installation
144 * ------------------------
145 * Go to http://ni.com and download the "DAQmx Base" package for your OS. Install following NI's instructions.
146 * As of 2013, the latest version is 3.7.
147 *
148 * \note This class requires compiling MRPT with support for "NI DAQmx" or "NI DAQmx Base". While compiling MRPT,
149 * check the "MRPT_HAS_NI_DAQmx"/"MRPT_HAS_NI_DAQmxBASE" option and correctly set the new variables to
150 * the library include directory and library file.
151 *
152 * \note As of 2013, NI seems not to support compiling 64bit programs, so you can must build MRPT for 32bits if you need this class.
153 *
154 * \ingroup mrpt_hwdrivers_grp
155 */
157 {
159 public:
160 /** Constructor */
162
163 /** Destructor */
165
166 /** Setup and launch the DAQ tasks, in parallel threads.
167 * Access to grabbed data with CNationalInstrumentsDAQ::readFromDAQ() or the standard CGenericSensor::doProcess() */
168 virtual void initialize();
169
170 /** Stop the grabbing threads for DAQ tasks. It is automatically called at destruction. */
171 void stop();
172
173 // See docs in parent class
174 void doProcess();
175
176 /** 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".
177 * 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.
178 * This is internally called when using the alternative CGenericSensor::doProcess() interface.
179 * No observations may be returned if there are not samples enough yet from any task.
180 */
182 std::vector<mrpt::obs::CObservationRawDAQPtr> &outObservations,
183 bool & hardwareError );
184
185 /** Set voltage outputs to all the outputs in an AOUT task
186 * For the meaning of parameters, refere to NI DAQmx docs for DAQmxBaseWriteAnalogF64()
187 * \note The number of samples in \a volt_values must match the number of channels in the task when it was initiated.
188 */
189 void writeAnalogOutputTask(size_t task_index, size_t nSamplesPerChannel, const double * volt_values, double timeout, bool groupedByChannel);
190
191 /** Changes the boolean state of one digital output line.
192 * For the meaning of parameters, refere to NI DAQmx docs for DAQmxBaseWriteAnalogF64()
193 * \note The number of samples in \a volt_values must match the number of channels in the task when it was initiated.
194 */
195 void writeDigitalOutputTask(size_t task_index, bool line_value, double timeout);
196
197 /** Returns true if initialize() was called and at least one task is running. */
198 bool checkDAQIsWorking() const;
199
200
201 /** Each of the tasks to create in CNationalInstrumentsDAQ::initialize().
202 * Refer to the docs on config file formats of mrpt::hwdrivers::CNationalInstrumentsDAQ to learn on the meaning
203 * of each field. Also, see National Instruments' DAQmx API docs online.
204 */
206 {
208
209 bool has_ai, has_ao, has_di, has_do;
210 bool has_ci_period, has_ci_count_edges,has_ci_pulse_width,has_ci_lin_encoder,has_ci_ang_encoder, has_co_pulses;
211
212
213 double samplesPerSecond; //!< Sample clock config: samples per second. Continuous (infinite) sampling is assumed.
214 std::string sampleClkSource; //!< Sample clock source: may be empty (default value) for some channels.
215 uint32_t bufferSamplesPerChannel; //!< (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.
216 uint32_t samplesPerChannelToRead; //!< (Default=1000) The number of samples to grab at once from each channel.
217 std::string taskLabel; //!< (Default="task###")
218
220 {
221 desc_ai_t() : terminalConfig("DAQmx_Val_NRSE"),minVal(-10), maxVal(10),physicalChannelCount(0) { }
222
223 std::string physicalChannel, terminalConfig;
224 double minVal, maxVal;
225 unsigned int physicalChannelCount; //!< *IMPORTANT* This must be the total number of channels listed in "physicalChannel" (e.g. 4 for "Dev1/ai0:3")
226 }
227 ai; //!< Analog inputs
228
230 {
231 desc_ao_t() : physicalChannelCount(0),minVal(-10), maxVal(10) { }
232
233 std::string physicalChannel;
234 unsigned int physicalChannelCount; //!< *IMPORTANT* This must be the total number of channels listed in "physicalChannel" (e.g. 1 for "Dev1/ao0")
235 double minVal, maxVal;
236 }
237 ao; //!< Analog outputs
238
240 {
241 std::string line; //!< The digital line (for example "Dev1/port0/line1")
242 }
243 di; //!< Digital inputs (di)
244
246 {
247 std::string line; //!< The digital line (for example "Dev1/port0/line1")
248 }
249 douts; //!< Digital outs (do)
250
252 {
253 desc_ci_period_t() : minVal(0),maxVal(0),measTime(0),divisor(1) { }
254
255 std::string counter, units, edge;
256 double minVal,maxVal;
257 double measTime;
259 }
260 ci_period; //!< Counter: period of a digital signal
261
263 {
264 desc_ci_count_edges_t() : countDirection("DAQmx_Val_CountUp"),initialCount(0) { }
265
266 std::string counter, edge, countDirection;
268 }
269 ci_count_edges; //!< Counter: period of a digital signal
270
272 {
273 desc_ci_pulse_width_t() : minVal(0),maxVal(0) { }
274
275 std::string counter, units, startingEdge;
276 double minVal,maxVal;
277 }
278 ci_pulse_width; //!< Counter: measure the width of a digital pulse
279
281 {
282 desc_ci_lin_encoder_t() : ZidxEnable(false),ZidxVal(0),distPerPulse(0.1),initialPos(0) { }
283
284 std::string counter, decodingType, ZidxPhase,units;
286 double ZidxVal;
289 }
290 ci_lin_encoder; //!< Counter: uses a linear encoder to measure linear position
291
293 {
294 desc_ci_ang_encoder_t() : ZidxEnable(false),ZidxVal(0),pulsesPerRev(512),initialAngle(0),decimate(1),decimate_cnt(0) { }
295
296 std::string counter, decodingType, ZidxPhase,units;
298 double ZidxVal;
301 int decimate, decimate_cnt;
302 }
303 ci_ang_encoder; //!< Counter: uses an angular encoder to measure angular position
304
306 {
307 desc_co_pulses_t() : idleState("DAQmx_Val_Low"),initialDelay(0),freq(1000),dutyCycle(0.5) { }
308
309 std::string counter, idleState;
310 double initialDelay,freq,dutyCycle;
311 }
312 co_pulses; //!< Output counter: digital pulses output
313
314 }; // end of TaskDescription
315
316 /** Publicly accessible vector with the list of tasks to be launched upon call to CNationalInstrumentsDAQ::initialize().
317 * Changing these while running will have no effects.
318 */
319 std::vector<TaskDescription> task_definitions;
320
321 protected:
322 /** See the class documentation at the top for expected parameters */
324 const mrpt::utils::CConfigFileBase &configSource,
325 const std::string &iniSection );
326
327 private:
328 std::vector<mrpt::obs::CObservationRawDAQPtr> m_nextObservations; //!< A buffer for doProcess
329
331 {
333 TInfoPerTask(const TInfoPerTask &o); //!< Copy ctor (needed for the auto_ptr semantics)
334
337 std::auto_ptr<mrpt::synch::CPipeReadEndPoint> read_pipe;
338 std::auto_ptr<mrpt::synch::CPipeWriteEndPoint> write_pipe;
339 bool must_close, is_closed;
341
342 TaskDescription task; //!< A copy of the original task description that generated this thread.
343 };
344
345 std::list<TInfoPerTask> m_running_tasks;
346
347 /** Method to be executed in each parallel thread. */
349
350 }; // end class
351
352 } // end namespace
353} // end namespace
354
355#endif
#define DEFINE_GENERIC_SENSOR(class_name)
This declaration must be inserted in all CGenericSensor classes definition, within the class declarat...
A generic interface for a wide-variety of sensors designed to be used in the application RawLogGrabbe...
An interface to read from data acquisition boards compatible with National Instruments "DAQmx Base" o...
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,...
void readFromDAQ(std::vector< mrpt::obs::CObservationRawDAQPtr > &outObservations, bool &hardwareError)
Receives data from the DAQ thread(s).
std::vector< mrpt::obs::CObservationRawDAQPtr > m_nextObservations
A buffer for doProcess.
void writeDigitalOutputTask(size_t task_index, bool line_value, double timeout)
Changes the boolean state of one digital output line.
void doProcess()
This method will be invoked at a minimum rate of "process_rate" (Hz)
virtual ~CNationalInstrumentsDAQ()
Destructor.
virtual void initialize()
Setup and launch the DAQ tasks, in parallel threads.
bool checkDAQIsWorking() const
Returns true if initialize() was called and at least one task is running.
void grabbing_thread(TInfoPerTask &ipt)
Method to be executed in each parallel thread.
void stop()
Stop the grabbing threads for DAQ tasks.
std::vector< TaskDescription > task_definitions
Publicly accessible vector with the list of tasks to be launched upon call to CNationalInstrumentsDAQ...
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
See the class documentation at the top for expected parameters.
This class acts exactly as an int (or long) variable, but with atomic increment and decrement operato...
Definition atomic_incr.h:27
This class allows loading and storing values and vectors of different types from a configuration text...
This base class provides a common printf-like method to send debug information to std::cout,...
#define HWDRIVERS_IMPEXP
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
unsigned long uint32_t
Definition pstdint.h:216
std::auto_ptr< mrpt::synch::CPipeReadEndPoint > read_pipe
std::auto_ptr< mrpt::synch::CPipeWriteEndPoint > write_pipe
TInfoPerTask(const TInfoPerTask &o)
Copy ctor (needed for the auto_ptr semantics)
TaskDescription task
A copy of the original task description that generated this thread.
unsigned int physicalChannelCount
IMPORTANT This must be the total number of channels listed in "physicalChannel" (e....
unsigned int physicalChannelCount
IMPORTANT This must be the total number of channels listed in "physicalChannel" (e....
std::string line
The digital line (for example "Dev1/port0/line1")
std::string line
The digital line (for example "Dev1/port0/line1")
Each of the tasks to create in CNationalInstrumentsDAQ::initialize().
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_count_edges_t ci_count_edges
Counter: period of a digital signal.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ao_t ao
Analog outputs.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_di_t di
Digital inputs (di)
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_do_t douts
Digital outs (do)
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_ang_encoder_t ci_ang_encoder
Counter: uses an angular encoder to measure angular position.
double samplesPerSecond
Sample clock config: samples per second. Continuous (infinite) sampling is assumed.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_period_t ci_period
Counter: period of a digital signal.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_co_pulses_t co_pulses
Output counter: digital pulses output.
uint32_t samplesPerChannelToRead
(Default=1000) The number of samples to grab at once from each channel.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_pulse_width_t ci_pulse_width
Counter: measure the width of a digital pulse.
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ai_t ai
Analog inputs.
uint32_t bufferSamplesPerChannel
(Default=0) From NI's docs: The number of samples the buffer can hold for each channel in the task....
struct HWDRIVERS_IMPEXP mrpt::hwdrivers::CNationalInstrumentsDAQ::TaskDescription::desc_ci_lin_encoder_t ci_lin_encoder
Counter: uses a linear encoder to measure linear position.
std::string sampleClkSource
Sample clock source: may be empty (default value) for some channels.
This structure contains the information needed to interface the threads API on each platform:
Definition threads.h:26



Page generated by Doxygen 1.9.7 for MRPT 1.4.0 SVN: at Tue Jun 13 13:45:58 UTC 2023