El 06/05/2013 15:33 p.m., Gilles Chanteperdrix escribió:
On 05/06/2013 09:15 PM, Sebastian Pavez wrote:

El 06/05/2013 14:17 p.m., Gilles Chanteperdrix escribió:
On 05/06/2013 07:14 PM, Sebastian Pavez wrote:

Hi,

I've previously asked a question related to this topic:
http://www.mail-archive.com/[email protected]/msg03134.html

But now I have more specific doubts (I think) and hopefully someone could
help me with this.

Like I said in my other question I have two tasks, one to control a DC
motor and the other one acting like a perturbation. I attached a simplify
code of this program (without the code of the control and other stuff).
When I execute it (the real one) and try 'cat /proc/xenomai/sched' I get:

CPU  PID    CLASS  PRI      TIMEOUT   TIMEBASE   STAT       NAME
    0         0      idle      -1                 -         master
R          ROOT/0
    1         0      idle      -1                 -         master
R          ROOT/1
    2         0      idle      -1                 -         master
R          ROOT/2
    3         0      idle      -1                 -         master
R          ROOT/3
    4         0      idle      -1                 -         master
R          ROOT/4
    5         0      idle      -1                 -         master
R          ROOT/5
    6         0      idle      -1                 -         master
R          ROOT/6
    7         0      idle      -1                 -         master
R          ROOT/7
    0    2339         rt       0                 -         master
X          control
    0    2341         rt       1              23us      master
D          control
    0    2342         rt       2               8us       master
D          control

So, one of my worries is answered, the threads are executed on the same
CPU. When I try cat /proc/xenomai/stat I get:

CPU  PID    MSW        CSW        PF    STAT         %CPU  NAME
    0       0      0          23906158        0     00500080     17.8  ROOT/0
    1       0      0                    0          0     00500080    100.0
ROOT/1
    2       0      0                    0          0     00500080    100.0
ROOT/2
    3       0      0                    0          0     00500080    100.0
ROOT/3
    4       0      0                    0          0     00500080    100.0
ROOT/4
    5       0      0                    0          0     00500080    100.0
ROOT/5
    6       0      0                    0          0     00500080    100.0
ROOT/6
    7       0      0                    0          0     00500080    100.0
ROOT/7
    0  2339      3                    3          0     00b00380       0.0
control
    0  2341      1          10157707        0     00300184     31.7  control
    0  2342      1          10157706        0     00300184     48.6  control
    0       0      0          70802151        0     00000000       1.6
IRQ2312: [timer]
Under Linux, every task has an "affinity" defining on which cpus it may
run, you can set affinity at task creation with some recent glibcs with
pthread_attr_setaffinity_np, or later with pthread_setaffinity or the
older service sched_setaffinity. See the glibc documentation for more
details.

I have 1 MSW, does this mean that the threads are being executed on a
secondary mode? If is so, is there a way to avoid this?
If you want to be informed of the switches to secondary mode, see
pthread_set_mode_np documentation.

I've been trying to increment the execution time of the perturbation thread
(which have the highest priority) and see how the control is degrade
(because my goal is to get practical results related with my professor
simulations) but I get nothing.
I may have misread your code, but it seems to me that in the code you
sent to this list, you do not control the execution time: each thread
keeps suspending itself in its inner loop by calling pthread_wait_np.

In general, however, a Xenomai system where a real-time task consumes a
lot of cpu does tend to crash, it is recommended to let linux run (by
having all your real-time tasks suspended at some point) from time to
time. A safe solution is to let it run at least for its timer tick, so
every millisecond, 4 milliseconds, or 10 milliseconds depending on
CONFIG_HZ value.

The idea after getting this is change the
priority, giving the control thread the highest one, and have system
working ok, in simple words we would like to prove the theory of real time
approach in practice. All this by having the same period for both tasks, I
would like to have a bigger period, something like 1ms, but I'm trying to
get the test to the edge first.

Sometimes when I increment the execution time of the perturbation the
computer hangs up before the control could even fail
That is not normal. What version of Xenomai are you running, what
versino of the I-pipe patch, on what hardware, with what kernel
configuration? If you are running in graphic mode, could you try running
in text mode to see if you get a kernel error? If not, could you enable
the I-pipe and Xenomai debugging options to see if one trigs?

Hi Gilles,

Thanks for your answer. About the execution time issue I'll explain better:
- How I see the code works:
      - I set the period of each thread 'control' and 'pert1'
      - After the initialization of variables and DAQ card the code
inside 'while(1)' is executed periodically
      - I determined the time take it by this 'while(1)' via direct
measure (activating a signal before the code and disbling it after, and
measuring the width of the 'pulse')
      - I get something like 18us for the control thread. So In the pert1
thread I use a 'for' loop inside the while(1), when I increment the
interations number I get a higher execution time
- What I'm trying to test:
      - For the same period for both tasks and the higher priority for
the pert1 thread I incremente the number of iterations inside the for loop
      - I expect, with a execution time of pert1 over 35us, to see a
malfunctioning in the DC motor following the reference (via some signals
I get in the oscillo) because the control will not have
        enough time to be executed properly before the next period in
wich the pert1 thread will resume his execution ... (is this correct?)
      - All this is done to confirm the results obtained in simulation

Now, what I'm doing (the structure of my code) is in order with the
results I would like to test? or I'm misinterpreting something. I would
like to clarify this in order to know if the problems are about the
theory or the implementation ... or, sadly, both.

I do not see all this in the code you sent to the list, what I see is
two threads which sleep on pthread_wait_np and do nothing else. So,
execution time virtually 0. You can use rt_timer_spin to simulate some
load. Some point you may have missed too, is that Xenomai timer runs in
one-shot mode by default, which means the thread periods will not elapse
at the same time, except if you synchronize them by using the first
argument of pthread_make_periodic_np.

In general, however, a Xenomai system where a real-time task consumes a
lot of cpu does tend to crash, it is recommended to let linux run (by
having all your real-time tasks suspended at some point) from time to
time. A safe solution is to let it run at least for its timer tick, so
every millisecond, 4 milliseconds, or 10 milliseconds depending on
CONFIG_HZ value.

How could I do this?

Arrange for every thread to not run more than the time of the period
corresponding to CONFIG_HZ.

That is not normal. What version of Xenomai are you running, what
versino of the I-pipe patch, on what hardware, with what kernel
configuration? If you are running in graphic mode, could you try running
in text mode to see if you get a kernel error? If not, could you enable
the I-pipe and Xenomai debugging options to see if one trigs?

I have xenomai-2.6.1 with kernel 3.2.32. The ipipe is
ipipe-core-3.2.21-x86-1.patch

Xenomai 2.6.1 is not the latest stable release, xenomai 2.6.2.1 is, and
the ipipe patch for linux 3.2.21 is known to have some issues, better
upgrading to 3.4 or 3.5.

I have a Intel core i7 @ 3.4GHZ

It does not seem like a good idea to run a 32 bits kernel on such a
processor.

I'm working in graphic mode, is there another way of seeing the kernel
error without working on text mode? (newbie in linux too)

Yes, newer drivers (nouveau, intel), are able to display oops text on
graphic mode, but I am not sure it really works when the I-pipe is in
the mix, so, starting in text mode is really the easy way out. Simply do
not start the X server.

How could I enable debugging options? Should I have to configure the
kernel again?

Yes. The debug options are in the "Real-time" menu, and the "kernel
hacking" menu. But please a 3.4 or 3.5 kernel before doing that.


Thanks once again Gilles,

I do not see all this in the code you sent to the list, what I see is
two threads which sleep on pthread_wait_np and do nothing else. So,
execution time virtually 0. You can use rt_timer_spin to simulate some
load. Some point you may have missed too, is that Xenomai timer runs in
one-shot mode by default, which means the thread periods will not elapse
at the same time, except if you synchronize them by using the first
argument of pthread_make_periodic_np.

Sorry for that, I now attached the code ... It's quite raw at the moment but it does what is suppose to, control the DC motor.

Arrange for every thread to not run more than the time of the period
corresponding to CONFIG_HZ.

This mean, don't set a period more than 4ms for each thread? (I have a configuration of 250hz) I tried to start in text mode by changing "quite splash" to "quite splash text" in the grub ... I only get a black screen at the start.

One more question, the results I get with 'cat /proc/xenomai/stat' and 'cat /proc/xenomai/sched' prove that the threads are being executed in a rel-time mode?
or there's something "weird" about them? or That'n not enough info?

Best regards,
Seba. P.
-------------- next part --------------
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/io.h>
#include <math.h>
#include <time.h>
#include <sched.h>

// Llamada al archivo de cabecera de los threads de POSIX
#include <pthread.h>

// Llamada al archivo de cabecera que contiene los registros de la tarjeta
#include "REG_PCI1711.h"

// Definición de la dirección base de la tarjeta PCI-1711U
#define PCI_BASE_ADRESS_1711 0xc000

// Se definen los periodos para las dos tareas #define PERIOD 50000 //1000000 #define PERIOD2 50000

// Estructura de datos necesarias para la creación de los threads
pthread_t thread_control;
pthread_t thread_pert1;

// Estructura de datos necesarias para la asignación de prioridades
struct sched_param p_control;
struct sched_param p_pert1;

void * control(void *arg){
unsigned int valor,datos,y,d,beta,N,re;
unsigned long overruns_r;
int out,in,o,outpos;                       // Variables para el control
double t,w,grados,g,m;
float ref,Vtaco,Vpot,err,ctr,ctrpos;
float err0=0.0;
float Vtaco0=0.0;
float Vpot0=0.0;
float ref0=0.0;
float a=0.0737;                     // Constantes del PI para velocidad a=Kp  ; 
 b=ti
float b=0.0487;
int posicion = 0;                   // Selección de control, 1 = posición ; 0 
= velocidad
double referencia=20.2;            // Referencia control de posicion en grado
float x,r,gref;
float h;
float P,I,D, Ppos, Dpos;
float kp=2.88;     // 2.88                    // Constantes del PD para posicion
float td=0.024;   // 0.024
float Dold=0.0;
float Doldpos=0.0;
float Iold=0.0;

// Estructura para el manejo temporal
struct timespec now,period;
int dummy;
w=1.8; // 2rad/s

// Se setean los valores para llevar un conteo del tiempo transcurrido
// Esto se hace según el reloj CLOCK_REALTIME
      period.tv_sec=0;
      period.tv_nsec=PERIOD;

      clock_gettime     ( CLOCK_REALTIME, &now);
      now.tv_nsec=now.tv_nsec+PERIOD;

// Se marca el thread como uno periodico y se verifica si no se produce algun 
error
      dummy=pthread_make_periodic_np (pthread_self(), &now,&period);
      switch(dummy){
case 0 : break; case ESRCH: printf("thread is invalid \n"); pthread_exit ((void *)-1); break; case ETIMEDOUT : printf("the start time has already passed\n"); pthread_exit ((void *)-1); break; default : printf(" output value not defined \n"); pthread_exit ((void *)-1); }

// Se fija la referencia interna de la tarjeta para la salida análoga 0 y 1 en 
10[V]
outw(5,PCI_BASE_ADRESS_1711 + PCI171x_DAREF);
// Se selecciona el modo del funcionamiento de la tarjeta y se limpia la
// información que pueda quedar en el buffer. Se inicializa el conversor A/D
  outw(Control_CNT0|Control_SW, PCI_BASE_ADRESS_1711+PCI171x_CONTROL);
  outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRFIFO);
  outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRINT);

  outw(1, PCI_BASE_ADRESS_1711+PCI171x_CONTROL);
  outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRFIFO);
  outb(0, PCI_BASE_ADRESS_1711+PCI171x_CLRINT);

// Se selecciona la ganancia del amplificador, así como el canal de entrada, 
AI0
  outw(0, PCI_BASE_ADRESS_1711+PCI171x_RANGE);


while(1) {

if(posicion == 1){ // Control de posicion, lectura desde la entrada AI1
  outb(1, PCI_BASE_ADRESS_1711+PCI171x_MUX_sta);  // Empezar en el canal AI0
outb(1, PCI_BASE_ADRESS_1711+PCI171x_MUX_sto); // Terminar en el canal AI0

                clock_gettime(CLOCK_REALTIME,&now);     // Variacion de la 
referencia en el tiempo
                t=(double)now.tv_nsec*1.0E-9+(double)now.tv_sec;
                r=(double)2+(double)2*sin( w*t);                
               if(r<2){
                grados=referencia;
                }
                if(r>2){
                grados=referencia+18.09;
                }

// Conversion de grados en tension
if((0<=grados)&&(grados<160)){
gref=grados*0.0553-0.1255;
// printf("x: %f[V]  ", x);
}
if((215<grados)&&(grados<360)){
gref=grados*0.0555-20.161;
}

// Zona muerta del potenciometro
if((160<=grados)&&(grados<=215)){
gref=-0.1255;
}

// Conversion de la tension para la salida de la tarjeta considerando la etapa 
de adaptacion de niveles
if((-10<=gref)&&(gref<0)){
in=(gref+10)/0.00488;
}
if((0<=gref)&&(gref<=10)){
in=gref/0.00244;
}

// Limitacion del valor de la salida
if(in<0){
in=0;
}else if(in>4095){
in=4095;
}

// Se saca la señal de referencia por la salida DA0
outw(in,PCI_BASE_ADRESS_1711 + PCI171x_DA0);

// Lectura de la salida
valor=1;
//Comenzar el proceso de conversión
   outw(0, PCI_BASE_ADRESS_1711+PCI171x_SOFTTRG);

   while (valor) {
// Verificar si la conversión ha finalizado
   valor=(inb(PCI_BASE_ADRESS_1711+PCI171x_STATUS) & Status_FE);
                }
// Leer los datos
   datos=inw(PCI_BASE_ADRESS_1711+PCI171x_AD_DATA); // Obtener datos de la cola
   d=datos&0x0fff;

// Transformacion en tension de la lectura
Vpot=d*0.002442;
Vpot=(Vpot-5)*2;

// COnversion de la tension en grados
if((-0.1255<=Vpot)&&(Vpot<8.68)){
g=(Vtaco+0.1255)/0.0553;
}
if((-8.25<Vpot)&&(Vpot<-0.1255)){
g=(Vpot+20.161)/0.0555;
}

// Algoritmo del PD para control de posición
beta=1;
N=10;
h=PERIOD*0.000000001;
Ppos=kp*(beta*gref-Vpot);
Dpos=td/(N*h+td)*Dold + N*kp*td/(N*h+td)*(Vpot0-Vpot);
ctrpos = Ppos + Dpos;
Doldpos = Dpos;
Vpot0 = Vpot;

// Limitacion en tension de la señal de control
if(ctrpos>10){
ctrpos=10;
}
if(ctrpos<-10){
ctrpos=-10;
}

// Conversion de la señal de control para ser escrita en la tarjeta
if((-10<=ctrpos)&&(ctrpos<0)){
outpos=(ctrpos+10)/0.00488;
}
if((0<=ctrpos)&&(ctrpos<=10)){
outpos=ctrpos/0.00488+2046;
}

// Limitacion de la salida
if(outpos<0){
outpos=0;
}else if(outpos>4095){
outpos=4095;
}

// Se saca la señal de control por la salida analoga DA1 y se aplica al puente 
H del motor
outw(outpos,PCI_BASE_ADRESS_1711 + PCI171x_DA1);


}else if(posicion == 0){ // Control de velocidad, lectura desde la entrada AI0
  outb(0, PCI_BASE_ADRESS_1711+PCI171x_MUX_sta);  // Empezar en el canal AI0
outb(0, PCI_BASE_ADRESS_1711+PCI171x_MUX_sto); // Terminar en el canal AI0
                clock_gettime(CLOCK_REALTIME,&now);     // Variacion de la 
referencia en el tiempo
                t=(double)now.tv_nsec*1.0E-9+(double)now.tv_sec;
                x=(double)2+(double)2*sin( w*t);
                if(x<2){
                x=0.5;
                }
                if(x>2){
                x=1.5;
                }
                if((0<=x)&&(x<=10)){  // Conversion de la tension en valores de 
la tarjeta
               in=x/0.00244;
               }
               outw(in,PCI_BASE_ADRESS_1711 + PCI171x_DA0); // Se saca la 
referencia por el canal DA0

// Lectura de la salida
valor=1;
//Comenzar el proceso de conversión
   outw(0, PCI_BASE_ADRESS_1711+PCI171x_SOFTTRG);

   while (valor) {
// Verificar si la conversión ha finalizado
   valor=(inb(PCI_BASE_ADRESS_1711+PCI171x_STATUS) & Status_FE);
                }
// Leer los datos
   datos=inw(PCI_BASE_ADRESS_1711+PCI171x_AD_DATA); // Obtener datos de la cola
   y=datos&0x0fff;

// Transformacion en tension de la lectura
Vtaco=y*0.00244;
Vtaco=(Vtaco-5)*2;

// Algoritmo del PI para control de velocidad
beta=1;
N=10;
h=PERIOD*0.000000001;
P=a*(beta*x-Vtaco);
I=Iold;
ctr = P+I;
Iold = Iold + a*h/b*(x-Vtaco);
Vtaco0 = Vtaco;

// Limitacion en tension de la señal de control
if(ctr>10){
ctr=10;
}
if(ctr<-10){
ctr=-10;
}

// Conversion de la señal de control para ser escrita en la tarjeta
if((-10<=ctr)&&(ctr<0)){
out=(ctr+10)/0.00488;
}
if((0<=ctr)&&(ctr<=10)){
out=ctr/0.00488+2046;
}

// Limitacion de la salida
if(out<0){
out=0;
}else if(out>4095){
out=4095;
}

// Se saca la señal de control por la salida analoga DA1 y se aplica al puente 
H del motor
    outw(out,PCI_BASE_ADRESS_1711 + PCI171x_DA1);

}

// Pausar la ejecución hasta el próximo periodo
 pthread_wait_np (&overruns_r);
}

// Señala el termino del thread
pthread_exit ((void *)0);
}


void * pert1(void *arg){
unsigned int valor,lect,lt;
int i,j,k;
double u;
unsigned long overruns_r;
struct timespec now,period;
int dummy;

      period.tv_sec=0;                //Inicializo los contadores del tiempo 
transcurrido
      period.tv_nsec=PERIOD2;          // en 0.001 seg
      clock_gettime     ( CLOCK_REALTIME, &now);
      now.tv_nsec=now.tv_nsec+PERIOD2;
      dummy=pthread_make_periodic_np (pthread_self(), &now,&period);
      switch(dummy){
case 0 : break; case ESRCH: printf("thread is invalid \n"); pthread_exit ((void *)-1); break; case ETIMEDOUT : printf("the start time has already passed\n"); pthread_exit ((void *)-1); break; default : printf(" output value not defined \n"); pthread_exit ((void *)-1); }

  while (1) {

        for(i=0;i<210;i++){
//        for(j=0;j<100;j++){
       k++;
        u=sin((double)k);
//        }
   }

   pthread_wait_np (&overruns_r);
        }
pthread_exit ((void *)0);
}

int main(int argc, char* argv[]){

// Reserva de memoria y permiso para acceso a la tarjeta
   mlockall(MCL_CURRENT|MCL_FUTURE);
ioperm(PCI_BASE_ADRESS_1711,50,2); // Crea el thread "control" y se le asigna su prioridad pthread_create (&thread_pert1, NULL, pert1, 0);
   p_pert1.sched_priority = 1;
pthread_setschedparam (thread_pert1, SCHED_FIFO, &p_pert1); // Crea el thread "control" y se le asigna su prioridad pthread_create (&thread_control, NULL, control, 0);
   p_control.sched_priority = 2;
pthread_setschedparam (thread_control, SCHED_FIFO, &p_control);
// Coordina el termino de la ejecución de los threads
   pthread_join   (thread_control,NULL);
   pthread_join   (thread_pert1,NULL);

   return(0);
}
_______________________________________________
Xenomai mailing list
[email protected]
http://www.xenomai.org/mailman/listinfo/xenomai

Reply via email to