Table of Contents
Nokia Qt es de lo mejorcito para hacer aplicaciones multiplataforma en C++. De la misma manera, COMEDI es lo más adecuado para hacer adquisición de datos en Linux.
El objetivo de esta página es mostrar un primer ejemplo de programa para Qt que emplee COMEDI. El ejemplo es sencillo, y se basa en el miniproyecto de la asignatura Informática Industrial.
Digamos que esta página complementa a la equivalente de "Usando National Instruments NIDAQmx con Qt".
Se propone ir a la introducción a COMEDI para poner a punto COMEDI y emplear un simple puerto paralelo de impresora para hacer las pruebas.
Como muchas bibliotecas, para usar COMEDI en Qt basta con informar de dónde están las cabeceras y las bibliotecas.
En las últimas versiones de Linux, COMEDI ya es parte del kernel principal, así que es facilísimo.
Para adaptar el proyecto hay que modificar el archivo de proyecto Qt (.pro) añadiendo la configuracíon para COMEDI. Para ser más generales, se ha aprovechado para ilustrar la capacidad multiplataforma de Qt. El siguiente fragmento hay que añadirlo al .pro y está pensado para que se use una tarjeta de National Instruments con NiDAQmx para Windows y las bibliotecas COMEDI en Linux.
# configuración para *nix (por ejemplo, Linux), etc. con COMEDI unix { #usamos un módulo de proceso distinto en Linux SOURCES += proceso_comedi.cpp # anydimos la ruta para localizar la cabecera de la tarjeta (no hace falta en Linux modernos) #INCLUDEPATH += "/usr/include" # anydimos la ruta de busqueda de las bibliotecas (opcion -L) (no hace falta en Linux modernos) #LIBS += -L"/usr/lib" # anydimos la biblioteca "libcomedi.so*" quitando partes del nombre del archivo, (opcion -l) LIBS += -lcomedi } # configuración para Windows usando una tarjeta de National Instruments win32 { #usamos un módulo de proceso distinto en windows SOURCES += proceso_nidaqmx.cpp # anydimos la ruta para localizar la cabecera de la tarjeta INCLUDEPATH += "C:/Archivos de programa/National Instruments/NI-DAQ/DAQmx ANSI C Dev/include" # anydimos la ruta de busqueda de las bibliotecas (opcion -L) LIBS += -L"C:/Archivos de programa/National Instruments/NI-DAQ/DAQmx ANSI C Dev/lib/msvc" # anydimos la biblioteca "NIDAQmx.lib" quitando partes del nombre del archivo, (opcion -l) LIBS += -lNIDAQmx }
Ya está.
Siguiendo el ejemplo de la asignatura, se ha adaptado el módulo de
proceso (proceso.cpp
) a COMEDI. El siguiente listado
es un ejemplo de manejo de una válvula digital conectada al puerto de
impresora del ordenador.
/** @file proceso_comedi.cpp @brief Modulo interfaz con el proceso. Version para Linux y COMEDI Este modulo es una prueba de COMEDI y LINUX. La salida digital para la valvula corresponde a los pines 20 y 2 del puerto de impresora. @author Angel Perles @date May 2011 */ // Los parámetros del módulo que queramos que sean fácilmente configurables // deben ir con DEFINES y similares al principio del listado #define FICHERO_TARJETA "/dev/comedi0" // dispositivo comedi con la tarjeta #define VALVULA_SUBDEVICE 0 //subdispositivo a usar #define VALVULA_CHANNEL 0 // canal del subdispositivo // fin parámetros "fácilmente configurables al principio del módulo" ---------- #include <stdio.h> #include <stdlib.h> #include <comedilib.h> /* incluir cabecera de comedi */ #include "proceso.h" comedi_t *device; /* dispositivo DAQ para comedi */ // prototipos de funciones que no se quieren en la cabecera ------------------- void proceso_Error(const char *mensaje); void daqtst(int codigo_error,int linea); // para comprobar las llamadas /**********************************************************************************************/ /** @brief Preparacion del hardware de adquisicion de datos Esta funcion hay que llamarla antes de usar cualquier otra, y solo llamarla una vez */ void proceso_Inicializar(void) { // abrir el dispositivo comedi */ device = comedi_open(FICHERO_TARJETA); if (device == NULL) { comedi_perror("Fallo abriendo"/**/FICHERO_TARJETA); exit(1); // la fastidiamos } // preparar dispositivo de salida digital "valvula" daqtst(comedi_dio_config(device,VALVULA_SUBDEVICE,VALVULA_CHANNEL,COMEDI_OUTPUT),__LINE__); } /**********************************************************************************************/ /** @brief Manejar la salida digital de la valvula @param estado valor deseado para la valvula {VALVULA_ABIERTA, VALVULA_CERRADA} Ejemplo @verbatim proceso_EscribirActuadorValvula(VALVULA_ABIERTA); @endverbatim */ void proceso_EscribirActuadorValvula(Testado_valvula estado) { // establecer el bit, 0=VALVULA CERRADA, 1=VALVULA ABIERTA if (estado==VALVULA_ABIERTA) { daqtst(comedi_dio_write(device,VALVULA_SUBDEVICE,VALVULA_CHANNEL,1),__LINE__); } else { daqtst(comedi_dio_write(device,VALVULA_SUBDEVICE,VALVULA_CHANNEL,0),__LINE__); } } /**********************************************************************************************/ /** @brief Finalizar el modulo de proceso Esta funcion deberia llamarse antes de salir de la aplicacion para llevar el sistema a un estado seguro */ void proceso_Finalizar(void) { proceso_EscribirActuadorValvula(VALVULA_CERRADA); } /** @brief Función que comprueba el valor devuelto por las llamadas a las funciones de la tarjeta */ void daqtst(int codigo_error,int linea) { char msg[2000]; if (codigo_error < 0) { // ha habido un fallo sprintf(msg,"Error llamando a la biblioteca COMEDI\nLínea: %d\nRazón: %s\n",linea,comedi_strerror(comedi_errno())); proceso_Error(msg); } } /**********************************************************************************************/ /** @brief Informar de un error y terminar el programa */ void proceso_Error(const char *mensaje) { //ShowMessage(mensaje); puts(mensaje); exit(1); // forzar la salida del programa a las bravas } // Fin archivo ----------------------------------------------------------------
Desde una ventana de Qt se puede llamar a las funciones del módulo de proceso para probar si todo funciona. Por ejemplo, la siguiente figura muestra el aspecto de la ventana del proyecto desarrollado aquí.
A los slots asociados a las señales de los botones se han asociado
las llamadas a las funciones proceso_Inicializar()
y
proceso_EscribirEstadoValvula()
. El siguiente listado
corresponde a la implementación de la ventana.
#include "mainwindow.h" #include "ui_mainwindow.h" #include "proceso.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_btInicializar_clicked() { proceso_Inicializar(); ui->btAbrirValvula->setEnabled(true); ui->btCerrarValvula->setEnabled(true); } void MainWindow::on_btAbrirValvula_clicked() { proceso_EscribirActuadorValvula(VALVULA_ABIERTA); } void MainWindow::on_btCerrarValvula_clicked() { proceso_EscribirActuadorValvula(VALVULA_CERRADA); }
Recordar que este ejemplo está pensado para probar con el puerto paralelo de impresora de un PC. Lo más sencillo será usar un tester entre los pines 20 y 2 del conector DB-25.
La siguiente figura muestra el aspecto de una aplicación hecha en un ratito que aplica lo dicho aquí.
Se ha conectado la placa que se emplea en prácticas de ESO/DSO al puerto paralelo y se ha empleado COMEDI para leer y escribir la señales de la placa.
Aquí va un vídeo, y en la sección de descargas está el código.