Combinando Nokia Qt y COMEDI


Noviembre 2011


Table of Contents

1. Introducción
2. Poniendo a punto COMEDI
3. Preparando el proyecto Qt
4. Un módulo de proceso que usa COMEDI
5. Probando el módulo desde una ventana
6. Un ejemplo más bonito
7. Descargas

1. Introducción

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".

2. Poniendo a punto COMEDI

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.

3. Preparando el proyecto Qt

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á.

4. Un módulo de proceso que usa COMEDI

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


5. Probando el módulo desde una ventana

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í.

Figure 1. Ventana de la aplicación

Ventana de la aplicación

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.

6. Un ejemplo más bonito

La siguiente figura muestra el aspecto de una aplicación hecha en un ratito que aplica lo dicho aquí.

Figure 2. Qt y COMEDI usando la placa de 7 segmentos.

Qt y COMEDI usando la placa de 7 segmentos.

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.

7. Descargas

Bajarse el ejemplo para Nokia Qt 4.xxx.

Bajarse el ejemplo de la placa de 7 segmentos.