Diferencia entre revisiones de «Grupo HotPlug»

De Proyecto Butiá
Saltar a: navegación, buscar
Línea 11: Línea 11:
  
  
[[Archivo:IMG_3876.JPG|Shield|250px|marco]]
+
[[Archivo:IMG_3876.JPG|Shield|250px|tumb]]
[[Archivo:IMG_3879.JPG|Shield|150px|marco]]
+
[[Archivo:IMG_3879.JPG|Shield|150px|tumb]]
[[Archivo:IMG_3872.JPG|250px|Sensores y boton, en el conector se pueden observar los puentes de pin a pin|marco]]
+
[[Archivo:IMG_3872.JPG|250px|Sensores y boton, en el conector se pueden observar los puentes de pin a pin|marco|tumb]]
  
  

Revisión del 16:17 22 feb 2012

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:


tumb tumb

tumb


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


Estos valores se pueden encontrar en el firmware con el que trabaja la Placa. Un firmware especial para el funcionamiento de este robot desarrollado en la Facultad de Ingeniería de la Universidad de la República que se puede descargar y modificar. (colocar sitio aquí) Nuestro trabajo se concentra en mayor parte a este nivel.

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 .


Integrantes:

Placa Arduino + Shield con 9 conectores disponibles
  • Juan La Cruz
  • Sofía Maiolo
  • Mathias Battistella


Tema elegido:

Firmware + Software : soporte HotPlug.


Motivación:

  • Nuestra principal motivación fue el poder realizar un proyecto que mejoraría el labor cotidiano con el Butiá y que permitiría un uso aún más sencillo del mismo.
  • Por otro lado, nos interesó la idea de trabajar en varios niveles (firmware, bobot, tortugarte) y poder comprender mejor como se relacionan.



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 Firmware

Consta 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".


Algunas de las placas entrada/salida utilizadas son:

- USB4all (enlazar) - Arduino Mega 03 (enlazar)

Uso de la placa desde el navegador

Uso de la placa desde la terminal

En un entonrno de Linux, lo primero.....


[centrado][/centrado]

Uso de la placa desde el compilador

Se 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:

  • En primer lugar modificamos el código del módulo butia, incluido en el archivo modulos.pde, para incluir una nueva operación que actualice los dispositivos conectados al Butiá. Esta nueva operacion consta de un for, donde se recorren los conectores, revisando su estado. Anexamos el código añadido


for (k=0; k<NUM_CONNECTORS; k++)
{ 
   if (conector[k].get_type() != 0) 
        {add_module(k) }; 
}
  • Al anexar esta nueva operación, debemos modificar también los drivers, incluidos en la carpeta bobot. Cambiamos, en particular, el archivo butia.lua, para poder invocar a la nueva función, que llamamos get_hot_plug. Incluimos el código:


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
  • Luego de realizar varias pruebas (detalladas en la próxima sesión) decidimos cambiar el enfoque y optamos por quitar el FOR agregado inicialmente en el módulo butiá. Lo sustituimos por el siguiente código incluido en el archivo butia_firmware_mega_0_2.pde:


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.


  • Para implementar remove_module, exploramos el handler, buscando el módulo a borrar y lo sustituimos por el módulo que se encuentra en la última posición ocupada del handler. Actualizamos, también, la cantidad de módulos. Incluimos la primera versión de nuestro código:
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--;
  
}
  • Luego de probar el firmware con estas modificaciones, comprobamos que se detecta correctamente cuando se conecta/desconecta un sensor. Sin embargo, cuando conectamos/desconectamos sensores del mismo tipo, los nombres asignados no se actualizan.

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.

  • Para solucionar este problema, relacionado con la cantidad de instancias de cada conector del handler, optamos por:

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.

  • En primer instancia, probamos nuestra implementación conectando un boton y un sensor de distancia. Hacemos un LIST y los reconoce bien.

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

Vista desde la Terminal de Linux



Vista desde un explorador



Placa Arduino


Probando y consultando con docentes, nos dimos cuenta de que faltaba actualizar el tipo de los conectores, antes de hacer la recorrida en el for. Para ello, usamos una función implementada en conector.cpp, llamada update_config (). Incluimos el código de dicha función.

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;   
      }  
    }
  }



Probando4.png
  • Usamos ./lua bobot-server.lua DEBUG en la Terminal para ver más información.
  • Probando con "Serial monitor" el FOR original de tal forma que repita cada 5 seg sin el init que aparece antes del codigo. Se puede ver el Print indicado mostrando correctamente la lista de dispositivos conectados. Para ello agregamos en butia.lua, linea 35: Print ("tipo leido",devolver); (devolver integer)
 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.)

  • Haciendo para cada conector update_config: "conector[f].update_config (); funionó, se probó con un boton y un sensor y verificó que el codigo los reconocía correctamente desde Serial Monitor. Pero probando con: ./lua bobot-server.lua DEBUG (Terminal) no funcionó, ahora el sensor de grises no aparece como unknown, sino como "grises", pero se repite como antes.
  • Luego de agregar las nuevas estructuras, volvimos a repetir las pruebas y sin embargo, el problema no se solucionó.

Conclusiones:

  • Hasta este momento hemos logrado que se detecte correctamente cuando se conecta/desconecta un sensor. Sin embargo, a pesar de todos los cambios hechos, no hemos podido solucionar el problema de la nomenclatura de los conectores.
  • El proyecto nos motivó mucho, ya que nos permitió utilizar herramientas que ya teníamos y observar de una forma mucho más práctica a la cual estamos acostumbrados, los cambios introducidos en el código.
  • Nuestra idea es culminar el proyecto, tratando de solucionar el problema antes explicado.


Presentación de nuestro trabajo:

Para ver la presentación de nuestro proyecto:

Presentación HotPlug


Trabajo a futuro:

  • Creemos que los cambios introducidos deberían permitirnos completar nuestro proyecto solucionando los problemas ahora existentes. Nuestro trabajo a futuro se centrará en identificar qué estamos haciendo mal, para poder cumplir íntegramente los objetivos planteados.
  • Por otro lado, también evaluamos la posibilidad de incluir un "botón refresh" dentro del Tortugarte, para permitir al usuario, actualizar los sensores cuando lo desee.


Referencia:

HotPlug sorceforge

Wiki de Lua

Articulo wikipedia Arduino

Web Arduino