[Rtai] Strange comedi command behaviour in RTAI

Paolo Mantegazza mantegazza at aero.polimi.it
Wed Dec 2 10:52:41 CET 2009


Jordi Blanch Carles wrote:
> Hello everybody,
> 
> we are having a very strange problem with a comedi command under a RTAI 
> LXRT task.
> 
> We need to use a NI PCI-6229 daq card to make acquisitions 
> asynchronously 2 repeated times on 4 analog channels (comedi comand 
> channels list is as follows: 0,1,2,3,0,1,2,3) until we stop it when we 
> reach certain condition. We configure the board to wake up our task 
> everytime it has finished the acquisition using rt_comedi_data_wread() 
> method.
> 

The only thing I can verify, as soon as I can get my hands onto a board, 
is the use of a scan with repetition, of the type you used above, in 
user space. The outcome can make me aware if there is a bug or a C++ 
specific coding problem. I let you know when I'll do it.

Paolo

> We have created a task using showroom/v3.x/user/comedi/cmd.c as an 
> example. We have modified this example to convert it to a C++ class to 
> use it in our application.
> 
> Everything seemed to work properly until we forced different analog 
> signals to the AI inputs of the daq card. We realized that, although we 
> got some values for each channel at each sample, this values didn't 
> correspond to the value it was supposed to have read the card. Only the 
> first position of the buffer read with rt_comedi_data_wread() has a 
> "real" value corresponding to the voltage forced to the AI pin, the 
> other positions of the buffer have some values that could seem "real" 0 
> volts values but they aren't. Moreover, the 5th position of the buffer 
> should correspond to the second acquisition of channel 0, and the value 
> read is always the same and doesn't follow the same values than the 
> first position of the buffer as it should. If we force an analog signal 
> to the corresponding pin of any other analog channel, nothing changes in 
> the values of the corresponding positions of the buffer.
> 
> We have tried to delete everything else in our code so we only read the 
> buffer returned by the rt_comedi_data_wread() method, but nothing seems 
> to change this strange behaviour. All channels give values oscillating 
> around what should be 0 volts at the analog input pin, so it seems that 
> these values are something that must be read from wherever. We have also 
> tried to force an analog signal to every channel of the board, but 
> nothing changes.
> 
> The examples found in comedilib/demo and showroom/v3.x/user/comedi/cmd.c 
> work properly and we can read analog values for any analog input channel 
> of the board, so we really don't know what else to try to know where is 
> our error and why do we have this strange problem.
> 
> Does anybody have any idea of which could be our problem?
> 
> I attach the complete code of our C++ classes because we don't know 
> where else to search for our error.
> 
> Thank you very much for your help.
> 
> ---GestorAdquisicions.h---
> /*
>  * File:   GestorAdquisicions.h
>  * Author: carlos
>  *
>  * Created on 15 de octubre de 2009, 16:12
>  */
> 
> #ifndef _GESTORADQUISICIONS_H
> #define        _GESTORADQUISICIONS_H
> 
> #include <iostream>
> #include <rtai_comedi.h>
> 
> #include "SensorsEncopim.h"
> #include "Etapa.h"
> 
> #define NSEGONS_EN_1_SEGON                  1000000
> #define KHZ_A_NSEGONS(khz)                  (NSEGONS_EN_1_SEGON / khz)
> #define FREQUENCIA_MAXIMA_TARGA_NS          KHZ_A_NSEGONS(250)
> #define NS_PER_ADQUISICIO(numCanals,khz)    ((NSEGONS_EN_1_SEGON/khz) / 
> numCanals)
> 
> #define NUM_MAXIM_TASQUES                   100
> #define AI_RANGE                            0
> #define RT_STACK                            4000
> #define TIMEOUT                             100000000
> 
> /**
>  *  Clase GestorAdquisicions. Classe encarregada de configurar la targeta
>  *  d'adquisicio per que aquesta funcioni independentment i ens avisi a
>  *  traves d'un trigger cada cop que ha fet una adquisicio.
>  *  Amb aquesta classe els cicles en temps real ja no seran periodics sino
>  *  que s'han de registrar a la classe i cada cop que arribi un trigger
>  *  cridarem els cicles.
>  */
> 
> class GestorAdquisicions : public Etapa {
> private:
>     /** Matriu on guardem les dades de cada escaneig */
>     double** arrayDades;
>     /** Array temporal on recollim les dades per posar-les a la matriu */
>     lsampl_t* arrayTemporalDades;
>     /** Nombre de overscan que volem fer */
>     int overscan;
>     /** Nombre de canals que recollim */
>     int numCanals;
>     /** Nombre de encoders que haurem d'agafar a cada callback */
>     int numEncoders;
>     /** Nombre de sensors digitals */
>     int numSensorsDigitals;
>     /** Array dels valors anteriors dels encoders */
>     double* valorsAnteriorsEncoders;
>     /** Array dels valors actuals dels encoders */
>     double* valorsActualsEncoders;
>     /** Array dels valors dels sensors digitals */
>     lsampl_t* valorsSensorsDigitals;
>     /** Array amb els canals que volem recollir */
>     int* indexCanals;
>     /** Array de sensors Analogics que volem fer servir per tractar les 
> dades recollides
> */
>     SensorDecorator** sensorsAnalogics;
>     /** Array de sensors Digitals que volem fer servir per tractar les 
> dades recollides */
>     SensorDecorator** sensorsDigitals;
>     /** Frequencia del control (sense el overscan) que volem fer servir 
> (KHz) */
>     int frequenciaControl;
>     /** Flag per acabar l'adquisicio en la seguent iteracio */
>     bool fiAdquisicio;
>     /** Flag d'estat de l'adquisicio */
>     bool isAdquirint;
>     /** Instruccions per fer les adquisicions digitals */
>     comedi_insn *insn;
>     /** Puntero para la lista de instrucciones */
>     comedi_insnlist ilist;
> 
>     comedi_t *dev;
>     int subdevAnalogic;
>     int subdevDigital;
>     comedi_cmd cmd;
> 
>     RT_TASK **arrayTasques;
>     RT_TASK *task;
>     int numTasques;
> 
>     void configuraAdquisicio();
> public:
>     GestorAdquisicions() {}
>     GestorAdquisicions(int overscan, int frequenciaControl, 
> SensorDecorator**
> sensorsAnalogics,
>             SensorDecorator** sensorsDigitals, int numCanals, int 
> numEncoders,
>                         int numSensors, comedi_t* dev);
> 
>     ~GestorAdquisicions();
> 
>     int getOverscan() {return this->overscan;}
>     void setOverscan(int overscan) {this->overscan = overscan;}
> 
>     int getNumCanals() {return numCanals + numEncoders + 
> numSensorsDigitals;}
>     void setNumCanals(int numCanals) {this->numCanals = numCanals;}
> 
>     int getFrequenciaControl() {return this->frequenciaControl;}
>     void setFrequenciaControl(int frequenciaControl) 
> {this->frequenciaControl =
> frequenciaControl;}
> 
>     int* getIndexCanals() {return this->indexCanals;}
>     double** getArrayDades() {return this->arrayDades;}
>     double* getDadesCanal(int i) {return this->arrayDades[i];}
>     void getDadesScan(int numScan, double* scan);
> 
> 
>     comedi_t* getDevice() {return this->dev;}
>     void setDevice(comedi_t* dev) {this->dev = dev;}
> 
>     RT_TASK* getTasca(int i) {return this->arrayTasques[i];}
>     void setTasca(int i, RT_TASK* task) {this->arrayTasques[i] = task;}
>     RT_TASK** getArrayTasques() {return this->arrayTasques;}
>     void setArrayTasques(RT_TASK** arrayTasques) {this->arrayTasques = 
> arrayTasques;}
> 
>     double getDadaOverscan(int indexDada, int numOverscan);
>     void arrencaAdquisicio();
>     void aturaAdquisicio();
>     void registraTasca(RT_TASK* tasca);
>     void desregistraTasca(RT_TASK* tasca);
> 
>         virtual void run();
> };
> 
> #endif        /* _GESTORADQUISICIONS_H */
> 
> 
> ---GestorAdquisicions.cpp---
> #include "GestorAdquisicions.h"
> 
> GestorAdquisicions :: GestorAdquisicions(int overscan, int 
> frequenciaControl,
> SensorDecorator** sensorsAnalogics,
>         SensorDecorator** sensorsDigitals, int numCanals, int 
> numEncoders, int
> numSensors, comedi_t* dev) {
>     this->overscan = overscan;
>     this->numCanals = numCanals;
>     this->numEncoders = numEncoders;
>     this->numSensorsDigitals = numSensors - numCanals - numEncoders;
>     this->valorsAnteriorsEncoders = new double[numEncoders];
>     this->valorsActualsEncoders = new double[numEncoders];
>     this->indexCanals = new int[numCanals];
>     this->sensorsAnalogics = sensorsAnalogics;
>         this->sensorsDigitals = sensorsDigitals;
>     this->frequenciaControl = frequenciaControl;
>     this->dev = dev;
>     for (int i = 0; i < numCanals; i++) {
>         //cout << "Sensor " << i << ": " << this->sensorsAnalogics[i] << 
> endl;
>         this->indexCanals[i] = this->sensorsAnalogics[i]->getCanal();
>         cout << "Canal sensor " << i << ": " << 
> this->sensorsAnalogics[i]->getCanal() <<
> endl;
>     }
> 
>     this->arrayDades = new double*[numSensors];
>     this->arrayDades = new double*[numCanals];
>     for (int i = 0; i < numSensors; i++) {
>         this->arrayDades[i] = new double[overscan];
>     }
>     this->arrayTemporalDades = new lsampl_t[overscan * numCanals];
>     this->valorsSensorsDigitals = new lsampl_t[numSensorsDigitals];
>     this->numTasques = 0;
>     this->arrayTasques = new RT_TASK*[NUM_MAXIM_TASQUES];
>     for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>         this->arrayTasques[i] = NULL;
>     }
>     this->insn = new comedi_insn[numSensorsDigitals];
>     this->fiAdquisicio = false;
> }
> 
> GestorAdquisicions :: ~GestorAdquisicions() {
>     delete [] indexCanals;
>     for (int i = 0; i < (numCanals + numEncoders + numSensorsDigitals); 
> i++) {
>         delete arrayDades[i];
>     }
>     delete [] arrayDades;
>     delete [] valorsAnteriorsEncoders;
>     delete [] valorsActualsEncoders;
>     delete [] valorsSensorsDigitals;
>     delete [] arrayTemporalDades;
>     delete [] insn;
> }
> 
> double GestorAdquisicions :: getDadaOverscan(int indexDada, int 
> numOverscan) {
>     return arrayDades[indexDada][numOverscan];
> }
> 
> void GestorAdquisicions :: configuraAdquisicio() {
>     unsigned int chanlist[overscan * numCanals];
>     subdevAnalogic = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AI, 0);
>         cout << "Subdev: " << subdevAnalogic << endl;
>     memset(&cmd, 0, sizeof(cmd));
> 
>     for (int i = 0; i < (overscan * numCanals); i++) {
>         chanlist[i] = CR_PACK(indexCanals[i % numCanals], AI_RANGE, 
> AREF_GROUND);
>                 cout << "Canal " << i << ": " << indexCanals[i % 
> numCanals] << ", chanlist: " <<
> chanlist[i] << endl;
>     }
> 
>     cmd.subdev = subdevAnalogic;
>     cmd.flags = TRIG_RT | TRIG_WAKE_EOS;
> 
>     cmd.start_src = TRIG_NOW;
>     cmd.start_arg = 0;
> 
>     cmd.scan_begin_src = TRIG_TIMER;
>     cmd.scan_begin_arg = KHZ_A_NSEGONS(frequenciaControl);
>     //cmd.scan_begin_arg = 1000000;
>         //cout << "Scan begin: " << KHZ_A_NSEGONS(frequenciaControl) << 
> ", frequenciaControl: "
> << frequenciaControl << endl;
> 
>     cmd.convert_src = TRIG_TIMER;
>     cmd.convert_arg = NS_PER_ADQUISICIO((overscan * numCanals), 
> frequenciaControl);
>     //cmd.convert_arg = 125000;
>         //cout << "Convert: " << NS_PER_ADQUISICIO((overscan * 
> numCanals), frequenciaControl) <<
> ", overscan: " << overscan << ", numCanals: " << numCanals << endl;
> 
>     cmd.scan_end_src = TRIG_COUNT;
>     cmd.scan_end_arg = (overscan * numCanals);
>     //cmd.scan_end_arg = 8;
> 
>     cmd.stop_src = TRIG_NONE;
>     cmd.stop_arg = 0;
> 
>     cmd.chanlist = chanlist;
>     cmd.chanlist_len = (overscan * numCanals);
>     //cmd.chanlist_len = 8;
> 
>     for (int i = 0; i < numCanals; i++) {
>         sensorsAnalogics[i]->inicialitzaSensor(overscan);
>     }
> 
>     // Configurem la llista d'instruccions per fer l'adquisicio dels 
> sensors digitals
>     ilist.n_insns = numSensorsDigitals;
>     ilist.insns = insn;
>     // Configurem cada una de les instruccions per l'adquisicio digital
>     subdevDigital = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_DIO, 0);
>     for (int i = 0; i < numSensorsDigitals; i++) {
>         memset(&insn[i], 0, sizeof(insn[i]));
>         insn[i].insn = INSN_READ;
>         insn[i].n = 1;
>         insn[i].data = &valorsSensorsDigitals[i];
>         insn[i].subdev = subdevDigital;
>         insn[i].chanspec = CR_PACK(sensorsDigitals[i]->getCanal(), 0, 0);
>     }
> }
> 
> void GestorAdquisicions :: run() {
>         //cout << "Anem a arrencar l'adquisisio en un thread nou" << endl;
>     arrencaAdquisicio();
> }
> 
> void GestorAdquisicions :: arrencaAdquisicio() {
>     if (!isAdquirint) {
>         isAdquirint = true;
>         configuraAdquisicio();
> 
>         for (int i = 0; i < numEncoders; i++) {
>             valorsAnteriorsEncoders[i] = sensorsAnalogics[(numCanals + 
> i)]->get();
>         }
> 
>         task = rt_task_init_schmod(nam2num("TASCA_ADQUISICIO"), 1, 0, 0, 
> SCHED_FIFO, 0xF);
>         mlockall(MCL_CURRENT | MCL_FUTURE);
>         rt_make_hard_real_time();
> 
>         rt_comedi_register_callback(dev, subdevAnalogic, COMEDI_CB_EOS, 
> NULL, task);
> 
>         int ret = comedi_command_test(dev, &cmd);
>                 //cout << "Comedi commmand test: " << ret << endl;
>         ret = comedi_command_test(dev, &cmd);
>                 cout << "Comedi commmand test: " << ret << endl;
>         if (ret == 0) {
>             ret = comedi_command(dev, &cmd);
>         } else {
>             cout << "Error en cmd test: " << ret << endl;
>             exit(-1);
>         }
> 
>         long mask = COMEDI_CB_EOS;
>                 int numDadesLlegir = overscan * numCanals;
>                 int cont;
>         while(!fiAdquisicio) {
>             cont = 0;
>             //cout << "Esperem dades: " << numDadesLlegir << endl;
>             ret = rt_comedi_command_data_wread(dev, subdevAnalogic, 
> numDadesLlegir,
> arrayTemporalDades, &mask);
>             //cout << "Llegit dades: " << ret << endl;
>             // Agafem els valors dels encoders
>             for (int i = 0; i < numEncoders; i++) {
>                 valorsActualsEncoders[i] = sensorsAnalogics[(numCanals + 
> i)]->get();
>             }
> 
>             rt_comedi_do_insnlist(dev, &ilist);
> 
>             for (int j = 0; j < overscan; j++) {
>                 // Posem els valors que agafem en la callback a l'array 
> de dades
>                 // passant-los per les operacions dels propis sensors
>                                 //cout << "Agafem les dades, numCanals: 
> " << numCanals << endl;
>                 for (int i = 0; i < numCanals; i++) {
>                                         cout << " Dada " << cont << ": " 
> << arrayTemporalDades[cont];
>                     //sensorsAnalogics[i]->setDada(j, 
> (double)arrayTemporalDades[cont]);
>                     //sensorsAnalogics[i]->setIndexOverscan(j);
>                     //sensorsAnalogics[i]->setDada(j, 
> sensorsAnalogics[i]->get());
>                     //arrayDades[i][j] = sensorsAnalogics[i]->getDada(j);
>                     //arrayDades[i][j] = (double)arrayTemporalDades[cont];
>                     //if (i==0) cout << "GestorAdquisicion::Canal 0 
> Overscan " << j << ",
> dada: " << arrayDades[i][j] << endl;
>                     cont++;
>                     //sensorsAnalogics[i]->setNovaAdquisicio(1);
>                 }
>                 // Agafem els valors dels encoders
>                 for (int i = 0; i < numEncoders; i++) {
>                     if (j == overscan) {
>                         arrayDades[i + numCanals][j] = 
> valorsActualsEncoders[i];
>                         valorsAnteriorsEncoders[i] = 
> valorsActualsEncoders[i];
>                     } else {
>                         arrayDades[i + numCanals][j] = 
> valorsAnteriorsEncoders[i] +
> ((valorsActualsEncoders[i] - valorsAnteriorsEncoders[i]) / overscan);
>                     }
>                 }
>                 // Agafem els valors dels sensors digitals
>                 for (int i = 0; i < numSensorsDigitals; i++) {
>                     arrayDades[i + numCanals + numEncoders][j] =
> (double)valorsSensorsDigitals[i];
>                 }
>             }
>                         cout << endl;
>             for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>                 //cout << "Tasca " << i << ": " << arrayTasques[i] << endl;
>                 if (arrayTasques[i] != NULL) {
>                     //cout << "GestorAdquisicions::Resume de la tasca: " <<
> arrayTasques[i] << endl;
>                     rt_task_resume(arrayTasques[i]);
>                 }
>             }
>         }
>         fiAdquisicio = false;
>     }
> }
> 
> void GestorAdquisicions :: aturaAdquisicio() {
>     cout << "GestorAdquisicions::Aturar adquisicio" << endl;
>     if (isAdquirint) {
>         fiAdquisicio = true;
>         //cout << "GestorAdquisicions::flag fiAdquisicio aixecat, 
> esperem" << endl;
>         while (fiAdquisicio) {
>             rt_sleep(100000);
>         }
>         //cout << "GestorAdquisicions::Adquisicio finalitzada" << endl;
>         isAdquirint = false;
>         comedi_cancel(dev, subdevAnalogic);
>         rt_sleep(100000);
>         //cout << "GestorAdquisicions::Adquisicio aturada" << endl;
>         rt_make_soft_real_time();
>         rt_sleep(100000);
>         rt_task_delete(task);
>         //cout << "GestorAdquisicions::Tasca rt esborrada" << endl;
>     }
> }
> 
> void GestorAdquisicions :: registraTasca(RT_TASK* tasca) {
>     cout << "GestorAdquisicions::Registrem tasca: " << tasca << endl;
>     for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>         if (this->arrayTasques[i] == NULL) {
>             cout << "GestorAdquisicions::Tasca registrada a la posicio " 
> << i << endl;
>             this->arrayTasques[i] = tasca;
>             numTasques++;
>             break;
>         }
>     }
> }
> 
> void GestorAdquisicions :: desregistraTasca(RT_TASK* tasca) {
>     cout << "Desregistrem tasca: " << tasca << endl;
>     for (int i = 0; i < NUM_MAXIM_TASQUES; i++) {
>         if (this->arrayTasques[i] == tasca) {
>             cout << "Tasca desregistrada de la posicio: " << i << endl;
>             this->arrayTasques[i] = NULL;
>             numTasques--;
>             break;
>         }
>     }
> }
> 
> void GestorAdquisicions :: getDadesScan(int numScan, double* scan) {
>     for (int i = 0; i < numCanals; i++) {
>         scan[i] = arrayDades[i][numScan];
>     }
> }
> 
> 
> Jordi Blanch Carles
> Unidad de Ensayo y Control
> 
> ENCOPIM S.L.
> C/. del Parc, 5 (nave 13)
> P.I. Els Pinetons
> E-08291 RIPOLLET (Barcelona)
> Tel: (+34) 935 94 23 47
> Fax: (+34) 935 94 64 15
> 
> ==========================================================
> La información contenida en la presente transmisión es confidencial y su
> uso únicamente está permitido a su(s) destinatario(s). Si Ud. no es la
> persona destinataria de la presente transmisión, rogamos nos lo
> comunique de manera inmediata por teléfono (+34 935 942 347) y destruya
> cualquier copia de la misma (tanto digitales como en papel).
> 
> The information contained in this transmission is confidential and is
> intended only for the use of the addressee(s). If you are not the
> designated recipient of this transmission, please advise us immediately
> by telephone (+34 935 942 347) and destroy any copies (digital and
> paper).
> ======================================================
> _______________________________________________
> Rtai mailing list
> Rtai at rtai.org
> https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai
> 




More information about the Rtai mailing list