Grupo HotPlug
El Proyecto:
Introducción: El proyecto Butiá trata de ampliar las capacidades sensoriales y de actuación de la computadora XO del proyecto OLPC en una plataforma robótica móvil, simple y económica que permita a alumnos de instituciones educativas , en coordinación con docentes e inspectores de Enseñanza Secundaria, interiorizarse con la programación del comportamiento de robots. Se utiliza una Placa entrada/salida donde se conecta un Shield con 9 conectores de 9 pines genéricos para motores, sensores y actuadores para la interactividad con el ambiente que pueden controlarse fácilmente desde cualquier lenguaje de programación con soporte de conexiones TCP/IP.
Estos dispositivos se conectan a la placa entrada/salida a través del Shield. Al encender el la Placa entrada/salida, ésta revisa cada conector para ver si algo está conectado. Cada sensor y actuador tiene uno o más puentes en sus conectores (ver en la foto) que respetan los valores de una tabla (enlazar la tabla acá) uniéndo a partir de 2 pines, uno tierra y otro positivo, otros pines, para que la placa entrada/salida identifique lo que se conectó e informe a la computadora que hay conectado en cada conector a travéz de su conexión por el puerto USB.
A cada sensor y actuador le corresponde un valor (un número entero) entre los que podemos encontrar:
Sensor de distancia | 10 | |
Sensor de temperatura | 11 | |
Sensor de luz | 12 | |
Sensor de grises | 13 | |
Sensor botón | 30 | |
Sensor contacto | 31 | |
Sensor Tilt | 32 | |
Sensor de vibración | 33 | |
Sensor magnético | 34 | |
Actuador Led | 53 | |
Parlante | 10 | |
Sensor potenciómetro | 21 | |
Desconocido | 15 | izda}
Hasta el momento para que el robot funcione correctamente con todos los sensores y actuadores que se conecten, éstos deben estar conectados antes de el encendido para que cuando la Placa entrada/salida revise los conectores los encuentre. La idea es que esto suceda cada cierto tiempo durante la ejecución del programa .
Contenido
Integrantes:
Tema elegido:Firmware + Software : soporte HotPlug.
Motivación:
Objetivos:Que la actualización de los módulos de usuario y drivers del Butiá sea "on the fly" es decir, dinámico. Se desea que durante la ejecución del Bobot-Server, podamos conectar y tener disponible para su uso sensores o actuadores.
El FirmwareConsta de 11 archivos, "PnP", "ax12.h", "ax12.cpp", "comunicacion", "conector.cpp", "conector.h", "info", "modulos", "perifericos", "servicios" y el principal "butia_mega_firmware_0_2" donde se levantan los otros 10 (describir brevemente cada archivo). El lenguaje utilizado es similar al C. Para este trabajo modificamos los archivos "butia_mega_firmware_0_2", "modulos" y "PnP".
- USB4all (enlazar) - Arduino Mega 03 (enlazar) Uso de la placa desde la terminalEn un entonrno de Linux, lo primero.....
Uso de la placa desde el compiladorSe desea que durante la ejecución del Bobot-Server, podamos conectar y tener disponible para su uso sensores o actuadores.
Desarrollo del problema:Se detalla a continuación un breve resumen de las etapas por las que pasó nuestro trabajo:
for (k=0; k<NUM_CONNECTORS; k++)
{
if (conector[k].get_type() != 0)
{add_module(k) };
}
api.hot_plug = {}
api.hot_plug.parameters = {} -- no se envian parámetros
api.hot_plug.returns = {} --nos devuelve el estado de los conectores
api.hot_plug.call = function ()
device:send(HOT_PLUG) --envío el código de operación
end
if (time_act-time_last2 >= 5000) { // cada 20ms llamamos a la sample(). Ojo porque esto afecta al "cuentapasos"
// explora los conectores
for (byte f=0; f<NUM_CONNECTORS; f++) {
byte tipoOld = conector[f].get_type();
byte subtipoOld = conector[f].get_subtype();
conector[f].update_config ();
// conecte algo donde no habia nada, o cambie lo que estaba conectado
if (conector[f].get_type() != 0 &&
(conector[f].get_type() != tipoOld || conector[f].get_subtype() != subtipoOld))
{
//primero borrar el viejo en la lista de handlers si es que
//el viejo no era el tipo 0 (el caso q no hay nada)
add_module(f);
}else if (conector[f].get_type() == 0 && //desconecte algo
(conector[f].get_type() != tipoOld || conector[f].get_subtype() != subtipoOld))){
//borrar el modulo que se acaba de desconectar
} // si hay algo en el conector, agrega 1 módulo PnP para él
}
time_last2 = time_act;
}
Este código realiza las siguientes acciones: 1)Recorremos los conectores, y guardamos su tipo y sub-tipo anteriores. 2)Si no había un conector en la lista de handlers y además, los tipos y sub-tipos son distintos, agregamos el conector llamando a add_module(f); de PnP.pde 3)Sino, debemos borrar del handler el módulo que acabamos de desconectar. Debemos implementar esta función, a la que llamaremos remove_module.
void remove_module (byte num_conector) {
int i=8; //Comenzamos a recorrer desde el 8 ya que desde el 8 se comienzan a agregar los nuevos conectores.
while ( (i< num_modules) && (handler[i].num_conector != num_conector) ) //Buscamos el conector con "num_conector" en el arreglo.
i++;
if (i< num_modules) //El conector con "num_conector" no es el ultimo.
{
//Hacemos el intercambio, dejando en la posicion i, al conector que se encontraba en la ultima posicion (num_modules).
strcpy (handler[i].nombre, handler[num_modules].nombre);
handler[i].funcion = handler[num_modules].funcion;
handler[i].num_conector = handler[num_modules].num_conector;
}
num_modules--;
}
Es decir, si conectamos dos sensores del tipo X y listamos los sensores conectados (usando LIST), obviamente veremos conectados: X, X1. Al desconectar uno veremos también un comportamiento correcto. Pero, al conectar nuevamente el sensor, y listar apreciaremos: X, X2.
1) Crear una nueva estructura (un array de bytes), llamada instancias, en la cual guardaremos las instancias de cada conector, mapeandolos según los siguientes criterios: byte globaltype = 10*conector[num_conector].get_type() + conector[num_conector].get_subtype(); En cada lugar del array, correspondiente a alguno de estos valores, guardaremos la cantidad de instancias de ese sensor. SENSOR_DISTANCIA 10 SENSOR_TEMPERATURA 11 SENSOR_LUZ 12 SENSOR_GRISES 13 SENSOR_BOTON 30 SENSOR_CONTACTO 31 SENSOR_TILT 32 SENSOR_VIBRACION 33 SENSOR_MAGNETICO 34 ACTUADOR_LED 53 MAX_CALLBACKS 10 SENSOR_POTE 21 UNKNOWN 15 El objetivo primordial de esta estructura es tener en una variable global el numero de instancias, para poder actualizarlo en el procedimiento remove_module, ya que antes estas variables solo se podían modificar en get_config al agregar un nuevo sensor. 2) Modificamos la estructura H, agregándole un nuevo campo, instancia, que guardará a qué instancia de ese sensor corresponde el dispositivo ubicado en ese lugar del handler. De esta forma podremos acceder al valor de instacias totales para cada tipo de conector (buscando en el array instancias) y a su vez, al valor particular de cada sensor (que corresponde con la nomenclatura de su nombre). Es importante destacar, que cuando existe sólo un sensor conectado, en el array instancias habrá un 1, mientras que el valor de instancia en el handler será 0. 3)Una vez hecho esto, tenemos que actualizar distintas partes del código, para incluir las nuevas estructuras. En particular, hicimos cambios relevantes en los procedimientos get_config, add_module y remove_module. Pruebas realizadas:Hemos realizado pruebas en las distintas etapas de nuestro trabajo. Incluimos algunas de ellas.
Los desconectamos, llamamos a nuestra operación y al INIT. Sin embargo, al usar el comando LIST, los sensores y el botón siguen apareciendo, lo cual nos hace pensar que la placa no fue reseteada
void Conector::update_config () {
byte id = digitalRead (pin_id0) + 2*digitalRead (pin_id1);
switch (id) {
case 3: // NADA
pinMode (pin_dig0, INPUT);
pinMode (pin_dig1, INPUT);
type = 0;
subtype = 0;
break;
case 2: // sensor analógico
pinMode (pin_dig0, INPUT);
pinMode (pin_dig1, INPUT);
digitalWrite (pin_dig0, HIGH); // activa los pull-ups
digitalWrite (pin_dig1, HIGH); // activa los pull-ups
type = 1;
subtype = digitalRead (pin_dig0) + 2*digitalRead (pin_dig1);
break;
case 1: // sensor analógico c/pin de control
pinMode (pin_dig0, OUTPUT);
pinMode (pin_dig1, INPUT);
digitalWrite (pin_dig1, HIGH); // activa los pull-ups
type = 2;
subtype = digitalRead (pin_dig1);
break;
case 0: // sensor o actuador digital
{
int analog_id = analogRead (pin_analog);
byte i;
for (i=0; i<NUM_VALORES; i++) {
if (abs(analog_id-values[i]) <= TOLERANCIA) {break;}
}
switch (i) {
case 0: case 1: case 2: case 3: case 4:
pinMode (pin_dig0, INPUT);
pinMode (pin_dig1, INPUT);
type = 3; // sensor digital
subtype = i;
break;
case 5: case 6: case 7: case 8:
pinMode (pin_dig0, OUTPUT);
pinMode (pin_dig1, INPUT);
type = 4;
subtype = i-5;
break;
case 9: case 10: case 11: case 12:
pinMode (pin_dig0, OUTPUT);
pinMode (pin_dig1, OUTPUT);
type = 5; // sensor digital c/pin de control
subtype = i-9;
break;
case NUM_VALORES: // si la red de resistencias no coincide con ningun valor, se deja en modo manual
pinMode (pin_dig0, INPUT);
pinMode (pin_dig1, INPUT);
type = 0;
subtype = 0;
break;
}
}
}
Serial.print("conector ");
Serial.print(f,DEC);
Serial.print(" tipo= ");
Serial.print(conector[f].get_type(), DEC);
Serial.print(" subtipo= ");
Serial.println(conector[f].get_subtype(), DEC);
En base a estas pruebas decidimos eliminar el FOR original del modulo butiá (tal como se detalla en la sesión anterior.)
Conclusiones:
Presentación de nuestro trabajo:Para ver la presentación de nuestro proyecto:
Trabajo a futuro:
Referencia: |