From: Sebastian Pavez <sebastian.pavez.t@gmail.com>
To: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Cc: Xenomai <xenomai@xenomai.org>
Subject: Re: [Xenomai] Doubts about priorities with periodic tasks (Posix Skin)
Date: Mon, 06 May 2013 17:12:32 -0400 [thread overview]
Message-ID: <51881CC0.5060300@gmail.com> (raw)
In-Reply-To: <5188059C.9030106@xenomai.org>
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/xenomai@xenomai.org/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);
}
next prev parent reply other threads:[~2013-05-06 21:12 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-06 17:14 [Xenomai] Doubts about priorities with periodic tasks (Posix Skin) Sebastian Pavez
2013-05-06 18:17 ` Gilles Chanteperdrix
2013-05-06 19:15 ` Sebastian Pavez
2013-05-06 19:33 ` Gilles Chanteperdrix
2013-05-06 21:12 ` Sebastian Pavez [this message]
2013-05-07 11:29 ` Gilles Chanteperdrix
2013-05-07 12:36 ` Sebastian Pavez
2013-05-08 13:19 ` Gilles Chanteperdrix
2013-05-08 18:39 ` Sebastian Pavez
2013-05-08 18:49 ` Gilles Chanteperdrix
2013-05-08 18:50 ` Gilles Chanteperdrix
2013-05-08 19:42 ` Sebastian Pavez
2013-05-08 20:05 ` Gilles Chanteperdrix
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51881CC0.5060300@gmail.com \
--to=sebastian.pavez.t@gmail.com \
--cc=gilles.chanteperdrix@xenomai.org \
--cc=xenomai@xenomai.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.