Hi Gilles,
Sorry for the mess :-) I hope this is more clear:
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.
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.
Regarding the first argument of pthread_make_periodic_np, I use
pthread_self() to assign to the calling thread, wht do you precisely
mean with "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.
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's 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