DAQ - mahilab/MEL GitHub Wiki

At the heart of the MEL library is the DAQ framework, which abstracts low level access to various devices into easy-to-use and flexible C++ Daq classes. At present, MEL provides interfaces for the following DAQs with plans to integrate more in the near future.

DAQ Header Operating System(s)
Quanser Q8-USB <MEL/Daq/Quanser/Q8Usb.hpp> Windows
Quanser Q2-USB <MEL/Daq/Quanser/Q2Usb.hpp> Windows
NI myRIO <MEL/Daq/NI/MyRio/MyRio.hpp> NI Linux Real-Time

A Daq object can created and opened in the following way:

MyRio myrio;
if (!myrio.open())
    return 1;  // the device did not open, fail-fast

Once a DAQ is open, it can be enabled:

myrio.enable()

The distinction between open() and enable() is that open() simply initializes communication between the software and hardware drivers, while enable() sets the device to its initial state (e.g. setting initial digital or analog outputs to 0 V or some other values).

Modules

Each Daq contains a number of Modules. A Module can be thought of as a bus or bank of same-type I/O channels. MEL currently implements the following Module types:

Module Description Physical Units C++ Type
AnalogInput Channels which read analog voltages V Voltage (aka double)
AnalogOutput Channels which write analog voltages V Voltage (aka double)
DigitalInput Channels which read TTL logic levels TTL Logic enum
DigitalOutput Channels which write TTL logic levels TTL Logic enum
DigitalInputOutput Channels which can read or write TTL logic levels TTL Logic enum
Encoder A quadrature encoder input counts int

Modules are contained within Daqs as member variables, and may be organized in different ways to match the physical hardware configuration. For example, the Modules on Q8Usb are accessed directly through the class itself (e.g. q8.AO, q8.DI, q8.encoder, etc.), while MyRio provides an intermediate abstraction for each connector interface (e.g. myrio.mxpA.DO, myrio.mspC.encoder, myrio.mxpB.AI).

Channels

Each Module contains a number of Module::Channels. Channels can be retrieved in two ways:

Encoder::Channel     enc1 = myrio.mspC.encoder[1];        // bracket operator overload
AnalogOutput::Channel ao0 = myrio.mspC.AO.get_channel(0); // member function

The current value on Channels of Input type Modules can be retrieved like so:

int counts;
counts = enc1.get_value();                  // with a channel variable, or ...
counts = myrio.mspC.encoder[1].get_value(); // with the Module, or ...
counts = myrio.mspC.encoder[1];             // automatic conversion

Likewise, the current value on Channels of Output type Modules can be set like so:

double voltage = 5.0;
ao0.set_value(voltage);              // with a channel variable, or ...
myrio.mspC.AO[0].set_value(voltage); // with the Module, or ...
myrio.mspC.AO[0] = voltage;          // automatic conversion

Updating Modules and Channels

Setting or getting the current value on a Module only sets or gets the buffered value stored in memory. To synchronize this value with the real-world, you must explicitly update inputs and outputs. You can do this at three levels: the Daq level, the Module level, or the Channel level. Here are a few examples:

myrio.update_input();       // updates all inputs on each myRIO connector
myrio.update_output();      // updates all outputs on each myRIO connector
myrio.mspA.update_input();  // updates all input modules on connector A
myrio.mxpB.AO.update();     // updates all channels on AO module of connector B
myrio.mspC.AI[1].update();  // updates only analog input channel 1 on connector C

You are encouraged to call functions which update DAQs or Modules together over per-Channel updates. Usually these functions will use a more efficient read/write operation from the underlying device API.

Relevant Examples

Example Description
ex_q2usb.cpp General overview of Q2-USB usage
ex_q8usb.cpp General overview of Q8-USB usage
ex_q8usb_loopback.cpp Performs loopback on all analog and digital Q8-USB channels
ex_mryio.cpp General overview of myRIO usage