jueves, octubre 16, 2008
Paso 25: No podían faltar los videos
miércoles, julio 23, 2008
Paso 22: Envuelto para regalo
Inicialmente, para los primeros ensayos, contábamos con algunas instrucciones que recibían parámetros de configuración y estado. A medida que el soft crecía en funcionalidad, se debían pasar un mayor número de parámetros o la repetida compilación del programa afectando un conjunto limitado de variables y macros. Ésta dificultad desencadenó la necesidad de emplear una herramienta más versátil y que nos permita armar una interfaz simple con el usuario para la configuración del sistema completo.
El camino nos llevó hasta ncurses y los resultados hasta el momento han sido satisfactorios. Hemos logrado interactuar de manera sencilla con la planta, modificando los parámetros deseados y ejecutando las rutinas principales del sistema.
Una captura de pantalla muestra el aspecto que tiene la interfaz de usuario:
Enfocados sobre los detalles del software, hemos establecido dos ámbitos sobre los que se fundaron todos los componentes empleados.
El primero, definido en el espacio del kernel y con el soporte de RTAI, se trata de un módulo cargable destinado a la ejecución de una tarea de tiempo real denominada Despachador, que Se implementó como una máquina de estados, encargada de establecer el modo de trabajo del sistema. La tarea recibe tres parámetros desde el proceso usuario por medio de un FIFO: Modo, Frecuencia y Comando; destinados al modo de trabajo, frecuencia del PWM y comando de operación, respectivamente.
En detalle podemos decir que la tarea de tiempo real realiza las siguientes operaciones:
- Bucle principal: selecciona la accion a realizar dependiendo del modo de trabajo seleccionado por el usuario.
* Modo Libre: Funciona a lazo abierto y sirve para determinar si comunicación y drivers funcionan correctamente.
* Modo Control: Es el modo principal donde queda definido el sistema de control.
* Modo Calibración: Realizar ajustes de cero y ganancia para posición lineal y angular de los sensores.
* Modo Espera: Queda a la espera de una nueva acción a ejecutar y depende del modo de trabajo seleccionado.
Además, cuenta con las siguientes rutinas:
- Comunicación: módulo que permite la comunicación half-duplex entre la PC y el uC, para todos los modos de trabajo.
- Actuación: Dependiente del motor y determina las referencias, ciclos de trabajo de los pwm y otros datos a determinar.
- Sensado: Destinado a la captura de los pulsos de los encoders e inclinómetro.

En segundo lugar, quedó definido en el espacio de usuario el proceso encargado de realizar la interfaz con el operador. Presenta un menu de configuracion, comandos y visualizacion de datos (posicion, angulo, velocidad, estado de la comunicación, etc). Inicialmente el usuario elige el modo de trabajo deseado (libre, controlador, calibrador), luego la frecuencia de los PWM de una lista de opciones que dispone el uC y finalmente, el menú de comandos. Éste último menú permite por un lado, mediante las teclas 4, 6 y 1 hacer avanzar, retroceder y deterner el puente, por el otro, muestra en pantalla la configuración de trabajo y los datos recibidos desde la planta.


viernes, mayo 30, 2008
Paso 21: Ejemplos de aplicación - RTAI
En éste caso, presentamos un ejemplo de una tarea de tiempo real, ejecutada como parte de un módulo del kernel, y un proceso usuario que muestra datos en pantalla. La tarea se encarga de muestrear cada 50 useg, las entradas discretas de la placa adquisidora. En el puerto, está conectado un encoder incremental de cuadratura y el algoritmo implementado determina si se debe incrementar o decrementar un pulso en el acumulador.
A continuación, se detallan los archivos empleados con algunos comentarios incluidos en el código.
Makefile
-------------------------------------------------------------------
-------------------------------------------------------------------
obj-m := ktest_encoder.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
EXTRA_CFLAGS := -I/usr/realtime/include -I/usr/include/ -ffast-math -mhard-float
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
gcc -o utest_encoder utest_encoder.c
.runinfo
-------------------------------------------------------------------
-------------------------------------------------------------------
latency:ksched+fifos:push ktest_encoder;./utest_encoder;popall:control_c
ktest_encoder.c
-------------------------------------------------------------------
/*
Archivo: ktest_encoder.c
COPYRIGHT (C) 2007-2008 Elias S. Fliger (elias.s.f@gmail.com)
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
*/
/*----------------------------------------------------------
Descripción:
Se ejecuta 1 tarea denominada ENCODER.
Lee los canales A y B (chA y chB) y almacena los valores actuales
y anteriores del encoder en los vectores A y B para incrementar
o decrementar la variable x que especifica la posicion angular del motor.
----------------------------------------------------------*/
/* includes*/
#include <linux>
#include <linux>
#include <asm.h>
#include <math.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>
/* defines*/
#define TICK_PERIOD 50000 //50 useg de periodo
#define TASK_PRIORITY 0
#define STACK_SIZE 10000
#define FIFO 0
#define BASEPORT 0x300 //Dirección Base de la placa adquisidora
/* globals */
static RT_TASK rt_task3;
/********************************************************
* FUNCION: encoder
*
* Descripcion: Tarea de lectura del encoder.
*
* Esta rutina lee los canales IN0 e IN1 (pin31 y 30) como canales A y B, respectivamente.
* Compara el estado de cada canal cada 50 useg ya que no posee interrupciones y
* luego incrementa o decrementa el acumulador de pulsos.
*********************************************************/
static void encoder(int t)
{
unsigned char chA=0, chB=0, entrada=0; //canales A y B , mas la mascara del puerto de entradas discretas
unsigned int A[2] = {0,0}; //Vector para comparar el valor actual y anterior del canal A
unsigned int B[2] = {0,0}; //Idem
int x=0; //Acumulador de pulsos
entrada=inb( BASEPORT);
chA = entrada & 0x01; //Lee IN 0 - Pin 31
chB = entrada & 0x02; //Lee IN 1 - Pin 30
A[0] = ( unsigned int )chA; //Inicializa canales de entrada
B[0] = ( unsigned int )chB;
rtf_reset(FIFO);
while(1)
{
entrada=inb( BASEPORT);
chA = entrada & 0x01;
chB = entrada & 0x02;
chB = chB/2;
A[1] = ( unsigned int )chA;
B[1] = ( unsigned int )chB;
if((A[1] & B[1])) //Ejecutar solo si A[1] = B[1] = 1
{
if( ((A[1]^A[0]) | (B[1]^B[0])) ) //si hubo cambio de estado para A o B, Incr o Decr
{
if((A[1]^B[0])) x++; // Si A[1] xor B[0] = 1 incrementa
else
{
if(x>0) x--; // De otra forma decrementa
else x=0;
}
}
}
A[0]=A[1]; //Actualiza valores
B[0]=B[1];
rtf_put(FIFO, &x, sizeof(x)); //Coloca en el FIFO para Proceso usuario
rt_task_wait_period();
}
}
/********************************************************
* FUNCION: init_module
*
* Descripcion: Inicializa el modulo.
*
* Inicializa tarea de tiempo real, establece modo periódico,
* crea FIFO e inicia temporizador.
*********************************************************/
int init_module(void)
{
RTIME tick_period;
rt_set_periodic_mode();
rt_task_init(&rt_task3, encoder, 1, STACK_SIZE, TASK_PRIORITY, 0, 0);
//tarea, funcion,valor inicial, tamaño stack, prioridad, usa FPU, usa Signal Handler.
rtf_create(FIFO, 10);
tick_period = start_rt_timer(nano2count(TICK_PERIOD));
rt_task_make_periodic(&rt_task3, rt_get_time() + tick_period, tick_period);
return 0;
}
/********************************************************
* FUNCION: cleanup_module
*
* Descripcion: Libera el modulo.
*
* Detiene temporizador, destruye FIFO y elimina tarea de tiempo real.
*********************************************************/
void cleanup_module(void)
{
stop_rt_timer();
rt_busy_sleep(10000000);
//recomendado
rtf_destroy(FIFO);
rt_task_delete(&rt_task3);
return;
}
MODULE_AUTHOR("Elias S. Fliger,");
MODULE_DESCRIPTION("Proyecto BORA - RT test encoder - UNQ");
MODULE_LICENSE("GPL");
-------------------------------------------------------------------
utest_encoder.c
-------------------------------------------------------------------
/*
Archivo: utest_encoder.c
COPYRIGHT (C) 2007-2008 Elias S. Fliger (elias.s.f@gmail.com)
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
*/
/*----------------------------------------------------------
Descripción:
El proceso solo recibe el valor del acumulador de pulsos
obtenido en el modulo ktest_encoder y lo muestra en pantalla.
Ejecutar ./utest_encoder
----------------------------------------------------------*/
/* includes*/
#include
#include
#include
#include
#include
#include
#include
#include
/* defines*/
#define BASEPORT 0x300
//direccion base de la placa de adquisicion
static int end;
static void endme(int dummy)
{
end=1;
}
int main(int argc, char * argv[])
{
int fifo;
int Contador;
if ((fifo = open("/dev/rtf0", O_RDONLY))
-------------------------------------------------------------------
jueves, mayo 10, 2007
Paso 13: Sobre el control, los controladores y lo controlado
En el comentario anterior (Paso 12), hicimos una reseña de los tres sistemas operativos de tiempo real que teníamos a disposición y cuál terminamos adoptando. A continuación, damos un breve repaso por los distintos temas que abarcamos hasta la fecha.
Tiempo Real
La búsqueda fue orientándonos a una herramienta de código abierto u open source, de tiempo real, con buena y accesible documentación, etc. Hasta que dimos con RTAI (Interface de Aplicación de Tiempo Real) y comenzamos a investigarlo y experimentar exhaustivamente, con algunos muy buenos resultados.
Dado que contamos con escasa (nula) experiencia con Linux, buscamos versiones booteables o LiveCDs que incluyan RTAI para evitar la recompilación del kernel y aprender comandos básicos de Linux evitando su instalación definitiva en la máquina.
Una de las mejores versiones que encontramos fue una distribución Knoppix 5.0 con RTAI 3.4 y kernel 2.6.17, que incluye la biblioteca Comedi y varios ejemplos de aplicación. Ésta se puede encontrar en PmWiki y en http://www-lar.deis.unibo.it/people/gpalli/files/rtai_knoppix.iso
Cuando cumplimos unas cuantas horas de vuelo, probando y errando, instalamos el sistema operativo y comenzamos el desarrollo del control, o los primeros esbozos.
Un esquema de la arquitectura de control se puede ver a continuación, donde una computadora realizará el control propiamente dicho, mientras la otra captura las imágenes de video y envía, por el puerto serial, la posición estimada de los objetos bajo la plataforma.

Placa Adquisidora
El control por sí mismo no tiene sentido si carece de comunicación con el exterior. Para ello es necesario la placa adquisidora, que se encarga de obtener la señal de los sensores y enviar órdenes a los actuadores, para que la acción tenga efecto.
En nuestro caso, nos conformamos con una placa adquisidora de origen nacional, marca microAXIAL, modelo ADQ12-B.
Entre sus características, podemos contar con:
- Conversor de 12 bits.
- 16 canales desbalanceados y 8 diferenciales, 10 useg de conversión.
- 8 salidas y 5 entradas digitales.
- Contador de 16 bits y Pacer de 32 bits.
- 2 entradas de interrupciones enmascarables.
Lamentablemente, los recursos disponibles impiden tener un driver para ésta placa que sea compatible con RTAI, por lo que habrá que diseñar uno a partir de la biblioteca ofrecida por Comedi (Linux Control and Measurement Device Interface).
Aun así y a fin de evitar semejante embrollo, desarrollamos todos los ejemplos iniciales con la dirección de memoria del puerto a la que apunta la placa, a través de las funciones outb() e inb().
Programación
La mejor forma que encontramos para aproximarnos a la estrategia de control final, fue desmenuzando las diferentes tareas a ejecutar por el controlador en:
Salidas Discretas: PWM y pulsos.
Entradas Analógicas: Posición angular.
Entradas Discretas: Encoders.
Control.
Comunicación.
Hasta el momento, los resultados obtenidos con RTAI nos permiten tener, cómodamente, un período de interrupciones de 100 useg (10 KHz), aunque puede ser reducido aún más.
Otras pruebas en las que funcionaron tres tareas de tiempo real en un mismo módulo, arrojaron un tiempo mínimo de interrupciones de 40 useg (25 Khz).
Ahora podemos enfocarnos en el diseño definitivo del control mientras terminamos de construir los carros que van montados sobre la estructura y que conforman la planta, o el sistema, a controlar.