UNIVERSIDAD CARLOS III ESCUELA POLITÉCNICA Dto. Sistemas Automáticos Proyecto Fin de Grado DISEÑO DE APLICACIÓN PARA MÓVIL MEDIANTE PLATAFORMA ARDUINO ADK Autor: Javier Aldana Corchón Tutor: Fernando García Fernández Título: Diseño de Aplicación para Móvil mediante Plataforma Arduino ADK Autor: Javier Aldana Corchón Director: Fernando García Fernández TRIBUNAL Presidente: Vocal: Secretario: Realizado el acto de defensa y lectura del Proyecto Fin de Grado el día__ de_____ de 2014 en Leganés, en la Escuela Politécnica Superior de la Universidad Carlos III de Madrid, acuerda otorgarle la CALIFICACIÓN de: VOCAL SECRETARIO PRESIDENTE Resumen Este trabajo tiene como objetivo demostrar cómo un teléfono móvil Android puede controlar las funcionalidades de un robot seguidor de línea. Para ello, el dispositivo formará parte del Hardware del robot. Gracias a esto, y siempre a través de software libre, el número de sus elementos aumentará sustancialmente, así como su capacidad para realizar tareas mucho más complejas añadiendo otras funcionalidades al robot. Para ello, se sustituirá la placa controladora del robot por el conocido Arduino ADK, y se desarrollará una aplicación que se comunique con el Arduino a través de un cable USB. Desde esta aplicación se podrá mover el robot en dos modos distintos: en modo siguelíneas y en modo manual, este último utilizando el acelerómetro del móvil y pudiendo modificar la velocidad del robot. En cualquiera de los dos modos, será posible visualizar los datos de los sensores del robot. Gracias a esto se conseguirán varias mejoras. Por una lado, el robot podrá adquirir otras funcionalidades, como la opción de ser dirigido manualmente además de seguir una línea, o la de poder visualizar los datos reales de los sensores que tiene robot. Por otra parte, la aplicación desarrollada podrá utilizarse como base en proyectos futuros para incorporar otras funcionalidades, hacer al robot más inteligente, utilizar otros elementos del teléfono o agregar otros sensores. Abstract The objective of this study is to demonstrate how an Android mobile phone can control the functionalities of a line follower robot. For this, the device is going to be part of the robot hardware. As a result the elements will increase substantially and it is having the ability to do more complex tasks. Also, the robot is going to have others functions, always through free software. The robot controller board is replaced by Arduino ADK, and an application will be developed to communicate with the Arduino through a USB cable. The robot will be moved in two different modes: in Siguelíneas mode and manual mode, the latest is using the phone's accelerometer. In either case, you may view the data from the sensors of the robot. Thanks to these improvements, we will get some improvements. On the one hand, the robot may get other functionalities, such as the option to be control manually and follow a line, or being able to view the actual data from sensors. Moreover, the developed application may be used as according to future projects to incorporate other functionalities, as do the robot more intelligent, use other elements of the phone or add sensors to the robot. Índice Índice general Introducción ................................................................................................................................ 10 1.1 Objetivo del Proyecto ........................................................................................................ 12 1.2 Estado del Arte .................................................................................................................. 14 1.2.1 Robótica ..................................................................................................................... 14 1.2.2 Accessory Development Kit( ADK) .......................................................................... 22 Elementos del Sistema ................................................................................................................ 29 2.1 Sensores y actuadores........................................................................................................ 31 2.2 Arduino Mega ADK .......................................................................................................... 37 2.3 Smartphone Android ......................................................................................................... 40 Diseño del Sistema ...................................................................................................................... 42 3.1 Software de Arduino ......................................................................................................... 44 3.1.1 Entorno de Arduino .................................................................................................... 44 3.1.2 Desarrollo del programa ............................................................................................. 46 3.2 Software de Android ......................................................................................................... 58 3.2.1 Entorno de Eclipse + SDK ......................................................................................... 58 3.2.2 Desarrollo de la aplicación ......................................................................................... 64 Pruebas y evaluación ................................................................................................................... 83 4.1 Descripción del entorno de pruebas .................................................................................. 83 4.2 Pruebas realizadas durante el desarrollo del proyecto....................................................... 86 4.3 Pruebas unitarias ............................................................................................................... 87 4.4 Compatibilidad plataformas Android ................................................................................ 89 Conclusiones y líneas futuras ...................................................................................................... 90 5.1 Conclusiones ..................................................................................................................... 90 5.2 Mejoras futuras.................................................................................................................. 91 Presupuesto ................................................................................................................................. 92 Anexos......................................................................................................................................... 95 8.1 ANEXO I: Datasheet Arduino .......................................................................................... 95 8.2 ANEXO II: Códigos deArduino y Android ...................................................................... 97 Bibliografía ............................................................................................................................... 134 6 Índice Índice de figuras Figura 1. Estructura de la aplicación ........................................................................................... 13 Figura 2. Tecnologías aplicadas .................................................................................................. 14 Figura 3. Ciencias y tecnologías en la robótica ........................................................................... 15 Figura 4. Elementos de un robot siguelíneas............................................................................... 20 Figura 5. Hardware ADK de Android ......................................................................................... 22 Figura 6. Arquitectura de Android .............................................................................................. 23 Figura 7. ARduino ADK ............................................................................................................. 27 Figura 8. Comunicación Accesorio- dispositivo Android ........................................................... 28 Figura 9. Esquema con los elementos del antiguo Sistema ........................................................ 29 Figura 10. Incorporación del hardware del ADK ....................................................................... 30 Figura 11. Funcionamiento CNY70 ............................................................................................ 31 Figura 12. Estados posibles ......................................................................................................... 32 Figura 13. Esquema del HC- SR04 ............................................................................................. 32 Figura 14. Diagrama de las señales del HC- SR04 ..................................................................... 33 Figura 15. Sistema de acondicionamiento................................................................................... 35 Figura 16. Señales PWM............................................................................................................. 36 Figura 17. Esquema Arduino ADK ............................................................................................. 39 Figura 18. Esquema de un dispositivo móvil .............................................................................. 40 Figura 19. Selección de la tarjeta ADK....................................................................................... 44 Figura 20. Entorno Arduino ........................................................................................................ 45 Figura 21. Monitor Serie ............................................................................................................. 46 Figura 22. Ciclo de vida de un sketch ......................................................................................... 47 Figura 23. Estructura del programa ............................................................................................. 49 Figura 24. Flujograma del programa en Arduino ........................................................................ 50 Figura 25. Contenido del mensaje ............................................................................................... 52 Figura 26. entorno Eclipse .......................................................................................................... 59 Figura 27. Máquina virtual de Android (AVD) .......................................................................... 60 Figura 28. Creación gráfica de archivos.xml .............................................................................. 61 Figura 29. Estructura de un proyecto en Eclipse ......................................................................... 62 Figura 30. Bibliotecas de Android .............................................................................................. 64 Figura 31. Esquema general de la aplicación .............................................................................. 65 Figura 32. representación de un Relative Layout ........................................................................ 66 Figura 33. Ciclo de vida de una actividad ................................................................................... 68 Figura 34. Clase Actividad Principal .......................................................................................... 69 Figura 35. Flujograma de la Actividad Principal ........................................................................ 70 Figura 36. Ciclo de vida de un Bound Service ............................................................................ 71 Figura 37. Diagrama de counicación en un Bound Service utilizando la clase Messenger ........ 72 Figura 38. Librerías utiizadas en el desarrollo del software........................................................ 74 7 Índice Figura 39. Elementos del Servicio .............................................................................................. 75 Figura 40. Diagrama de la Clase Servicio ................................................................................... 77 Figura 41. Apariencia de la Actividad Cliente ............................................................................ 80 Figura 42. Diagrama de la Clase Cliente..................................................................................... 81 Figura 43. Entorno de pruebas .................................................................................................... 83 Figura 44. Ordenador portátil ...................................................................................................... 84 Figura 45. Aplicación Demokit ................................................................................................... 86 Figura 46. Impresión de los datos del sensor de ultrasonidos en el monitor serie ...................... 88 8 Índice Índice de tablas Tabla 1. Ciencias y tecnologías en ............................................................................................... 16 Tabla 2. Clasificación según su estructura .................................................................................. 18 Tabla 3. Clasificación según generación ..................................................................................... 19 Tabla 4. Estados en el sistema seguidor de línea ........................................................................ 21 Tabla 5. Bibliotecas de Android.................................................................................................. 24 Tabla 6. Entorno de ejecución de Android.................................................................................. 25 Tabla 7. Bibliotecas JAVA.......................................................................................................... 26 Tabla 8. Funcionamiento CNY70 ............................................................................................... 31 Tabla 9. Características HC- SR04 ............................................................................................. 34 Tabla 10. Sensor LDR ................................................................................................................. 34 Tabla 11. Servomotor Futaba S3003 ........................................................................................... 35 Tabla 12. Interruptor RL6 ........................................................................................................... 37 Tabla 13. Puertos necesarios ....................................................................................................... 38 Tabla 14. Especificaciones Arduino............................................................................................ 39 Tabla 15. Especificaciones Huawei Y300................................................................................... 41 Tabla 16. Protocolo del mensaje ................................................................................................. 52 Tabla 17. Protocolo del mensaje ................................................................................................. 58 Tabla 18. Carpetas de un proyecto en Android ........................................................................... 63 Tabla 19. Métodos de una actividad............................................................................................ 69 Tabla 20. Características del Huawei Ascend Y300 ................................................................... 84 Tabla 21. Características del Smartphone BQ Aquaris 5.7 ......................................................... 85 Tabla 22. Robot del laboratorio................................................................................................... 85 Tabla 23. Fases de la memoria .................................................................................................... 92 Tabla 24. Coste mano de obra ..................................................................................................... 93 Tabla 25. Coste de material ......................................................................................................... 93 Tabla 26. Coste total ................................................................................................................... 94 9 Introducción Capítulo 1 Introducción El término robótica fue acuñado por Isaac Asimov para describir la tecnología de los robots. Procede de las palabras checas robota ( trabajo forzado) y robotnik (sirviente) y fueron usadas por primera vez en 1921 por el escritor checo Karel Capek, en la obra de teatro Rossum’s Universal Robot (R.U.R.), en la que se hacía referencia a un humanoide mecánico. Se entiende por robótica como la rama de la tecnología que se dedica al diseño, operación, construcción, disposición estructural, manufactura y aplicación de los robots. La historia de la robótica va unida a la construcción de “artefactos” que trataban de materializar el deseo humano de crear seres a su semejanza y que hicieran algunos trabajos por ellos. Los robots han tenido una evolución norme. Los primeros surgieron en el siglo I a. C, y eran máquinas de vapor o artefactos de fuego. En la actualidad, existen robots que disponen de alta tecnología y con numerosas funcionalidades, llegando a existir robots humanoides que caminan de forma bípeda y son capaces de interactuar con personas. Esta evolución y expansión del mundo de la robótica es debido a que se hace uso de muchas ciencias y áreas multidisciplinares de la tecnología que también han tenido una gran evolución y que, si además, se combinan unas con otras, la evolución es todavía más notable. Actualmente vivimos en una época donde está ocurriendo una revolución tecnológica, sobre todo en tecnologías de la información, y éstas también se están empezando a aplicar en robótica. Un ejemplo de esto es combinar la tecnología que posee un robot con la de un Smartphone. Los teléfonos móviles han pasado de ser dispositivos de comunicación por voz a distancia a convertirse en ordenadores potentes con interfaz gráfica, sensores, actuadores y varios tipos de conectividad. Parece muy interesante incorporar un Smartphone en robots. Es una forma relativamente barata de transformar un robot que realiza tareas sencillas en uno mucho más inteligente, aumentar sus funcionalidades, comunicarlo a otros dispositivos con conexión inalámbrica o conectarlo directamente a Internet. Algunas empresas líderes tecnológicas invierten en I+ D sobre tema. Un claro ejemplo es Google, que ha desarrollado una plataforma para comunicar por medio de la interfaz 10 Introducción USB dispositivos móviles Android con Arduino , una placa controladora muy utilizada en robótica. En este proyecto se utiliza esta plataforma para controlar un robot seguidor de línea y añadirle algunas funcionalidades. 11 Introducción 1.1 Objetivo del Proyecto El presente proyecto se mueve el mundo de la robótica y la informática. Se pretende controlar un robot seguidor de línea con un teléfono Android. El sistema debe de ser: De bajo consumo. Relativamente barato. Hará uso de software libre. Uso de hardware conocido y asequible. Funcionamiento autónomo. Además: El sistema deberá leer datos de los siguientes sensores incorporados en el robot, e imprimirlos por pantalla. Sensor de ultrasonidos. Sensores de contacto izquierdo y derecho. Sensor de iluminación. El robot debe tener dos modos de funcionamiento: Un modo manual, en el que se puede mover el robot con el acelerómetro del móvil. Un modo siguelíneas, en el que el robot se mueva siguiendo una línea negra sobre un fondo blanco. En cualquiera de los dos modos en los que opere el robot, deberá pararse si choca con algún obstáculo. Básicamente el del sistema consiste en desarrollar un programa que se cargará en la placa Arduino y una aplicación desarrollada en Android, que debe de tener la siguiente estructura: Una pantalla principal que de la opción de elegir los dos modos de funcionamiento: “Modo Manual” y “Modo Siguelíneas”. 12 Introducción Una pantalla por cada modo de funcionamiento, que sea capaz de sacar por pantalla los datos de cada sensor y ordenar al robot que se mueva en el modo correspondiente. En la siguiente figura se muestra un esquema general de cómo debe ser la estructura de la aplicación Pantalla principal Modo Manual Pantalla Modo Manual Modo Siguelíneas Pantalla Modo Siguelíneas Activar Modo Manual Activar Modo Siguelíneas Datos de los sensores Datos de los sensores Figura 1. Estructura de la aplicación 13 Introducción 1.2 Estado del Arte En este apartado se analiza el contexto en el que está enmarcado el Trabajo de fin de Grado. Estas son las tecnologías de las que se hará uso en este proyecto: Robótica Arduino Trabajo de Fin de Grado Android Figura 2. Tecnologías aplicadas Se explica el concepto de Robótica, entrando más en detalle en el robot seguidor de líneas. A continuación se hablará del ADK (Accessory Development Kit), plataforma para desarrolladores con el objetivo de comunicar via USB un arduino Mega ADK y un teléfono Android. 1.2.1 Robótica Hay ciertas dificultades a la hora de definir qué es un robot. Las definiciones son muy dispersas: “Es un dispositivo reprogramable y multifuncional diseñado para mover materiales, piezas, herramientas o dispositivos especializados a través de movimientos programados” Robot Institute of América, 1979. 14 Introducción “Un dispositivo automático que realiza funciones que normalmente se consideran, son o deberían ser realizadas por humanos” Diccionario Webster. “Máquina o ingenio electrónico programable, capaz de manipular objetos y realizar operaciones antes reservadas sólo a las personas” Diccionario de la Real academia La robótica es la rama de la tecnología que se dedica al diseño, construcción, operación, disposición estructural, manufacturación y manipulación de los robots. En robótica se combinan varias áreas de conocimiento: Mecánica Física Electrónica Ingeniería de control Inteligencia artificial Informática Figura 3. Ciencias y tecnologías en la robótica 15 Introducción Disciplina Definición Aplicaciones en un robot Estudia el movimiento, el reposo de los cuerpos y su evolución en el tiempo debido a la acción de fuerzas. • Diseño de todo lo que está relacionado con la parte física del robot, como sus eslabones, articulaciones y actuadores (parte física). Sistemas cuyo funcionamiento se basa en el control de flujo de electrones • Sensores. • Actuadores (parte electrónica). • Microprocesador. • Sistema de almacenamiento de datos (ROM, RAM, memoria Flash..). • Conversores A/D y D/A. Mecánica Electrónica Informática Inteligencia artificial Ingeniería de control Estudia métodos, procesos y • Programación del microprocesador técnicas con el fin de procesar y en lenguajes de programación como transmitir información y datos C, C++, Java… en forma digital. Área multidisciplinar que, ayudada de la lógica, informática y la filosofía estudia entidades capaces de razonar por sí mismas imitando la inteligencia humana. • Algoritmos genéticos. • Redes neuronales artificiales. • Algoritmos de lógica análogos al pensamiento humano. • Búsqueda del estado deseado sobre todos los estados posibles, según las acciones posibles. Se basa en el uso de reguladores para el control de máquinas y procesos reduciendo la necesidad de intervención humana. • Automatización industrial. • Control y regulación de cualquier magnitud física. • Domótica. Tabla 1. Ciencias y tecnologías en 16 Introducción Disciplina Física • Definición Aplicaciones en un robot Ciencia que estudia el comportamiento y las propiedades de la materia y la energía, así como el tiempo y el espacio, y las interacciones entre estos cuatro elementos. Engloba a todas las disciplinas anteriores. • Aparte de las aplicaciones anteriores, existen otros usos de la física en robótica como imitar a la naturaleza en algún aspecto, como en forma, movimiento, dinamismo, comportamiento, etc. Clasificación de los robots. Para la clasificar un robot se atiende principalmente a dos criterios: arquitectura y evolución. En base a su arquitectura se pueden dividir en: Tipo Poliarticulados Móviles Descripción Son sedentarios y están estructurados para mover sus elementos terminales en un determinado espacio de trabajo con un número limitado de grados de libertad (manipuladores y algunos robots industriales). Tienen una gran capacidad de desplazamiento, basados en carros o plataformas y dotados de un sistema locomotor de tipo rodante. Siguen su camino por telemando o guiándose por la información recibida de su entorno a través de sus sensores. 17 Ejemplo Introducción Tipo Androides Ejemplo Descripción Intentan reproducir total o parcialmente la forma y el comportamiento cinemático del ser humano. Uno de los aspectos más complejos de estos robots es la locomoción bípeda (controlar dinámicamente el movimiento y mantener elequilibrio del robot). Imitan en forma y movimiento de diversos seres vivos. Zoomórficos Híbridos Industriales Seguridad y espacio De servicios Aquellos de difícil clasificación cuya estructura se sitúa en combinación con alguna de las anteriores (un carro móvil con un brazo, robot personal antropomorfo, etc). Son artilugios mecánicos y electrónicos destinados a realizar de forma automática determinados procesos de fabricación o manipulación. Relativos al uso de robots en tierra, mar y aire en misiones de seguridad civil o militar así como su uso en misiones espaciales. Sistemas aplicados en los dominios de la vida: entornos domésticos y de ocio, en salud y rehabilitación, en servicios profesionales y en ambientes peligrosos; que reproducen acciones de ayuda a los humanos. Tabla 2. Clasificación según su estructura 18 Introducción Si atendemos a su evolución se clasifican de la siguiente manera: Generación 1ª generación 2ª generación 3ª generación 4ª generación 5ª generación Descripción Sistema de control basado en “paradas fijas” mecánicamente (mecanismos de relojería que mueven las cajas musicales o los juguetes de cuerda). El movimiento se controla a través de una secuencia numérica almacenada en disco o cinta magnética (industria automotriz). Utilizan las computadoras para su control y tienen cierta percepción de su entorno a través del uso de sensores. Con esta generación se inicia la era de los robots inteligentes y aparecen los lenguajes de programación. Robots altamente inteligentes con más y mejores extensiones sensoriales, para entender sus acciones y captar el mundo que los rodea. Incorporan conceptos “modélicos” de conducta. Actualmente se encuentran en desarrollo. Basarán su acción principalmente en modelos conductuales establecidos. Tabla 3. Clasificación según generación • Robot siguelíneas Como ya se comentó en la introducción, en este proyecto se utiliza un robot seguidor de líneas, al cual se le modificará parte del hardware y el software para el objetivo del proyecto. A continuación se describe qué función tienen estos robots, su estructura y los elementos que los componen. Los robots seguidores de línea, como su propio nombre indica, tienen la misión de seguir una línea, normalmente de color negra, sobre un tablero blanco. Son robots muy sencillos, y por este motivo su mayor utilización es en la introducción y aprendizaje en el mundo de la robótica. Se podría decir que son el “hola mundo” en esta disciplina. Estos robots pueden variar mucho en funcionalidad. Pueden seguir únicamente una línea o hacer tareas más complejas como salir de un laberinto, detectar objetos, medir magnitudes en su entorno, etc. También suelen variar en su estructura. Existen múltiples diferencias en la forma, en el número de ruedas, tipos de sensores y actuadores, diferentes placas controladoras…..pero todos tienen en común unas partes básicas: 19 Introducción Tarjeta de control Fuente de energía Sensores Motores Ruedas Figura 4. Elementos de un robot siguelíneas Si se tiene en cuenta la clasificación expuesta anteriormente, un robot seguidor de línea pertenecería al grupo de los móviles, y de 3ª generación, debido a poseer cierta percepción del entorno gracias a disponer de sensores y una unidad computacional que controla sus actuadores (los motores de las ruedas principalmente). Sistema seguidor de línea La parte más característica de un robot seguidor de línea es el sistema de detección de línea compuesto por el sensor de infrarrojos. Es la esencia de este robot, lo que le diferencia del resto de todos ellos. Aunque se volverá a comentar más adelante, continuación se expone la idea de cómo funciona este sistema. Por una parte está el procesamiento de la información del microcontrolador y cómo actúa en consecuencia. El funcionamiento consta básicamente de cuatro órdenes: 20 Introducción Estado Los dos sensores están sobre la línea El sensor de la derecha ha salido de la línea. Respuesta El robot acanza con las dos ruedas El robot gira a la izquierda. Esto se consigue moviendo la rueda derecha y parando la izquierda. El sensor de la izquierda ha salido de la línea. Hay que girar a la derecha moviendo la rueda izquierda y manteniendo la derecha parada. Ambas ruedas permanecen paradas. Los dos sensores están fuera de la línea. Tabla 4. Estados en el sistema seguidor de línea La otra parte del sistema tiene que ver con el circuito electrónico capaz de detectar la línea. El sensor de infrarrojos es el más utilizado por su sencillez y precio. Como ejemplo, en este proyecto se ha utilizado un sensor CNY70, compuesto por un Led de infrarrojos (IR) y un fototransistor. Para detectar la línea negra se utilizan dos sensores de este tipo. El led emite rediación infrarroja, y el fototransistor es sensible a ella. Si está sobre el color blanco, la radiación se refleja llegando a ser percibida por el fototransitor. Si, por el contrario, se está sobre la línea negra, se absorbe la radiación. Utilizando dos sensores se consiguen los cuatro estados posibles. Una vez que se ha introducido el concepto de robótica y se ha explicado con más detalle qué es un robot siguelíneas, se explicará la tecnología que se añadirá al robot, el ADK de Android. 21 Introducción 1.2.2 Accessory Development Kit( ADK) El ADK consiste en la implementación y desarrollo de código fuente y hardware para facilitar la construcción de accesorios Android. Algunos de estos accesorios pueden ser estaciones de conexión para audio, máquinas de ejercicio, estaciones meteorológicas o cualquier otro dispositivo de hardware externo que se suma a la funcionalidad de Android. Se trata de comunicar un teléfono Android con una placa Arduino. Existen dos versiones: El ADK 2011 y la actualización ADK 212. La principal diferencia entre las dos versiones es que en el ADK 2011 contiene librerías para la comunicación a través de un USB host, y en el ADK 2012 se añaden librerías para comunicarse por medio de Bluetooth. En este proyecto el teléfono irá colocado en el robot y no es necesaria una comunicación inalámbrica, así que se utilizará el ADK 2011. Figura 5. Hardware ADK de Android Este kit de desarrollo tiene un gran potencial en el mundo de la robótica debido a sus numerosas ventajas y posibles aplicaciones, en las que se profundizará más adelante. A continuación se explican los componentes del ADK. • Dispositivo Android Android es una pila de software desarrollada para dispositivos móviles que incluye un sistema operativo, middleware y aplicaciones de usuario. 22 Introducción Fue adquirido por Google en 2005 y es la primera aparición de Google en el mercado de la telefonía móvil. Todas las aplicaciones de Android se programan en lenguaje JAVA y son ejecutadas en una máquina virtual llamada Dalvik. El núcleo de Android es el Linux 2.6. Android es un software libre. El objetivo es mejorar el desarrollo de aplicaciones consiguiendo que funcione en cualquier dispositivo móvil, y que cualquier usuario tenga la opción de contribuir en el desarrollo o en la resolución de problemas. Arquitectura A continuación se explicará cómo está constituida la pila de Android. Cada una de las capas utiliza los servicios de las capas anteriores y ofrece los suyos propios a las capas superiores. Figura 6. Arquitectura de Android 23 Introducción El núcleo de Android es un kernel (núcleo) de Linux versión 2.6. Proporciona una capa de abstracción que tiene que acceder a las aplicaciones. Para cada elemento hardware existe un driver. Esto permite utilizar cualquier elemento del teléfono. En la siguiente capa se encuentran las bibliotecas. Están escritas en C++ y compiladas para la arquitectura hardware de cada teléfono, tarea realizada por cada fabricante. El objetivo es dar funcionalidad a las aplicaciones para tareas que se repiten con frecuencia, evitando tener que codificarlas y garantizando que se llevan a cabo de la forma más eficiente. Las bibliotecas son las siguientes: LIBRARIES Biblioteca Gestor de superficies (surface Manager) OpenGL/SL y SGL. Librerias graficas 3D y 2D Bibliotecas multimedia Descripción Compone imágenes que se muestran posteriormente en las capas gráficas 2D y 3D de tal forma que facilita la superposición de elementos, transparencias, animaciones, etc. Las aplicaciones pueden combinar gráficos en 2 y 3 dimensiones. Permiten tratar el contenido multimedia animaciones,etc). ( videos, audio, Motor web utilizado por el navegador. Webkit. Protocolo para comunicarse de forma segura. -SSL( Secure Sockets Layer). Freetype. SQLite. Permite trabajar con fuentes tipográficas. Motor de bases de datos relacionales, disponible para todas las aplicaciones. Incluye las cabeceras y funciones del lenguaje C. Biblioteca C de sistema(libc). Tabla 5. Bibliotecas de Android 24 Introducción En el mismo nivel se encuentra el entorno de ejecución. Aquí se encuentran librerías con clases de JAVA y la máquina virtual Dalvik. ANDROID RUNTIME Biblioteca Dalvik Descripción Diseñada para ejecutar aplicaciones que son propias de dispositivos móviles y no de JAVA. Transforman en .dex donde los comprime para una mayor optimización. JAVA Tabla 6. Entorno de ejecución de Android Las aplicaciones se ejecutan en su propia instancia, evitando así interferencias entre ellas, y tienen acceso a todas las bibliotecas y al kernel. En el siguiente nivel se encuentra las bibliotecas de JAVA que acceden a los recursos a través de la máquina virtual Dalvik. Se enumeran algunas de ellas a continuación: APPLICATION FRAMEWORK Biblioteca Descripción Controla el ciclo de vida de las aplicaciones de Android. Administrador de actividades (Activity Manager). Gestiona las ventanas de las aplicaciones y utiliza la librería Surface Administrador de ventanas Manager. (Windows Manager). Proveedor de contenidos (Content Provider). Proporciona servicios para notificar al usuario cuando requiera su atención, como activar vibrador, sonidos de alerta, etc. Administrador de notificaciones (Notification Manager) Proporciona servicios para notificar al usuario cuando requiera su atención, como activar vibrador, sonidos de alerta, etc. Administrador de paquetes (Package Manager) Las aplicaciones se distribuyen en paquetes (archivos .apk) que contienen todos los demás archivos necesarios para una aplicación determinada. Esta biblioteca permite obtener información sobre estos paquetes. 25 Introducción Bibliotecas Administrador de telefonía (Telephone Manager) Administrador de recursos (Resource Manager) Administrador de ubicaciones (Location Manager) Administrador de sensores (sensor Manager) Descripción Las aplicaciones se distribuyen en paquetes (archivos .apk) que contienen todos los demás archivos necesarios para una aplicación determinada. Esta biblioteca permite obtener información sobre estos paquetes. Proporciona acceso a todos los elementos propios de una aplicación que se incluyen directamente en el código. Determina la posición geográfica (GPS, mapas, etc). Gestiona el acelerómetro, giróscopo,sensor de presión, etc). Gestiona el sensor de la cámara. Cámara Multimedia. Permite reproducir y visualizar video, audio e imágenes. Tabla 7. Bibliotecas JAVA Por último, en la capa superior están las aplicaciones. Se encuentran tanto las que tiene Android como las que añada el usuario posteriormente. Para desarrollar aplicaciones en Android se utiliza el Android Software Development Kit (SDK de Android). Básicamente es el entorno de desarrollo Eclipse ( IDE para desarrollar programas en Lenguaje JAVA) al que se le han añadido las herramientas de desarrollo necesarias para desarrollar una aplicación en Android. Estas herramientas son: • • • • ADT plugin. Herramientas del SDK de Android. Herramientas de plataforma de Android. Android Virtual Device (AVD). Un emulador virtual del sistema operativo de Android para poder ejecutar las aplicaciones sin usar el dispositivo. 26 Introducción • Placa Arduino ADK Es una plataforma de hardware y software libre desarrollada para hacer más fácil el diseño de la parte electrónica en proyectos multidisciplinares. Está basada en un microcontrolador, un puerto USB host por donde se comunicará con el dispositivo Android, y un entorno de desarrollo llamado Arduino IDE. El hardware consiste en un micronotrolador Atmel AVR y puertos de entrada y salida. A continuación se muestra un esquema de la placa: Pines de señal PWM Pines de comunicación Serie Conector PC E/S digitales USB HOST Conector DC Pines de alimentación E/S analógicas Microcontrolador Atmega2560 Figura 7. ARduino ADK El entorno de desarrollo se llama Arduino IDE, hace uso del lenguaje C/ C++ y además existen unas librerías como herramientas de desarrollo: Librería USB Host Shield Es una librería que proporciona la lógica para que la tarjeta USB actúe como USB host. Esto permite al Arduino iniciar la comunicación con otros dispositivos USB. 27 Introducción Librería Android Accessory. Esta librería define cómo enumerar el bus, encontrar un dispositivo Android conectado compatible con el modo accesorio y cómo configurar la comunicación del dispositivo. Librerías útiles para la funcionalidad del ADK Librería CapSense. Contiene clases funciones para facilitar el uso de sensores capacitivos. Librería I2C/ TWI. Protocolo para la comunicación mediante cable I2C. Librería Servo. Contiene clases y funciones para facilitar el uso de servomotores en Arduino. Librería SPI. Permite la comunicación con dispositivos SPI, actuando el Arduino como maestro en la comunicación. Librería Wire. Permite comunicarse con dispositivos I2C/ TWI. Existen dos formas de comunicación entre la placa Arduino y el dispositivo móvil: el modo Host y el modo Accessorio. Figura 8. Comunicación Accesorio- dispositivo Android En el modo Host el dispositivo Android actúa como anfitrión en la comunicación. Esto significa que el dispositivo es el que comprueba continuamente si hay un accesorio conectado, y el accesorio sólo responde si el dispositivo le hace una petición. También proporciona alimentación a la placa Arduino. Sin embargo, en el modo Accesorio pasa lo contrario, es la placa Arduino la que actúa como anfitrión en la comunicación y la que proporciona alimentación al teléfono. En este proyecto se hará uso del ADK en modo accesorio. 28 Elementos del Sistema Capítulo 2 Elementos del Sistema En el presente capítulo se identificarán los distintos elementos hardware que componen el sistema. En la siguiente figura se muestra un esquemático muy general de estos componentes: Sensor de contacto izquierdo Sensor de contacto derecho Sensor de ultrasonidos Sensor CNY70 izquierdo Sensor CNY70 derecho E/S E/S MICROCONTROLADOR E/S Motor rueda izquierda Motor rueda derecha POWER Sensor iluminación Batería Figura 9. Esquema con los elementos del antiguo Sistema Al incorporar la plataforma ADK de Google, la placa controladora del robot es sustituida por un Arduino ADK conectado vía USB a un dispositivo Android: 29 Elementos del Sistema Sensor de contacto izquierdo Sensor de ultrasonidos Sensor de contacto derecho Sensor CNY70 izquierdo Sensor CNY70 derecho Motor rueda izquierda Motor rueda derecha Sensor iluminación Batería Figura 10. Incorporación del hardware del ADK 30 Elementos del Sistema A continuación se describen todos los componentes representados en el esquema anterior: 2.1 Sensores y actuadores Sensor detector de línea CNY70 Para detectar si el robot está sobre la línea negra se utilizan dos sensores CNY70. Apariencia Esquema eléctrico acondicionamiento con El led IR emite luz infrarroja (longitud de onda que va desde 0.7 hasta 1000 micrómetros). Si el fototransistor recibe esa radiación se comporta como una fuente de corriente y en la patilla “E” hay 5V . La puerta NOT conectada en serie hace que el estado final sean 0V. Si por el contrario,el fototransistor no recibe la radiación infrarroja se comportará como un circuito abierto, en la patilla “E” hay 0V y la tensión a la salida de la puerta NOT son 5V. La patilla “E” de cada sensor irá conectada a una entrada digital del Arduino. Tabla 8. Funcionamiento CNY70 Color blanco Fototransistor Led IR Figura 11. Funcionamiento CNY70 31 Elementos del Sistema Si se tiene en cuenta que el color blanco refleja radiación y el negro la absorbe, se deduce que cuando el sensor se encuentra sobre el color blanco, el circuito presenta una salida de 0V, y cuando está sobre la línea negra la salida es de 5V. Así se consiguen los dos niveles lógicos. Utilizando dos sensores contiguos podemos obtener cuatro estados posibles. Figura 12. Estados posibles Sensor de ultrasonidos HC- SR04 Figura 13. Esquema del HC- SR04 Con este sensor el robot puede conocer a la distancia que se encuentra de otros objetos. 32 Elementos del Sistema El sensor dispone de cuatro patillas: • • • Vcc y GND. Se corresponden a las patillas de alimentación. Trigger. Señal de disparo. Conectada a una salida digital del Arduino. Echo. Señal de rebote. Conectada a una entrada digital. Este sensor tiene un emisor de ondas de ultrasonidos y un receptor de las mismas. Calcula el tiempo que hay entre la emisión y la recepción de la onda. La velocidad del sonido, al ser constante y con un valor conocido (340 m/s) es posible calcular la distancia mediante esta fórmula: Distancia= tiempo* velocidad del sonido/2. A continuación se muestra un diagrama del tiempo de cómo debe de ser el tiempo de disparo para que el sensor funcione correctamente: Figura 14. Diagrama de las señales del HC- SR04 En el programa de arduino se ha hecho de esta manera: delayMicroseconds(10);//tiempo de activación de disparo mínimo del trigger del HC-SR04 según fabricante digitalWrite(trigger,LOW); duracion_microsegundos = pulseIn(echo,HIGH,timeOut); value= conversion(duracion_microsegundos);// función para convertir tiempo en distancia 33 Elementos del Sistema A continuación se muestra una tabla con las principales características: Voltaje de operación Corrriente de operación Frecuencia de emisión Rango máximo Rango mínimo Ángulo de medida Trigger input signal Echo output signal Dimensiones 5 V DC 15 mA 40 KHz 70 cm 2 cm 15 º 10 microsegundos, señal TTL Input TTL 45*20*15 mm Tabla 9. Características HC- SR04 Fotorresistor. Light Dependent Resistor (LDR) Es una Resistencia que varía su valor en función de los fotones que inciden en su superficie. Su respuesta espectral se encuentra en el visible, alrededor de los 550 nm, y no es lineal. Símbolo Apariencia Tabla 10. Sensor LDR 34 Respuesta espectral Elementos del Sistema Conexionado: Figura 15. Sistema de acondicionamiento La salida Vout se conecta a un pin analógico del Arduino configurado como entrada. Servomotores Futaba S3003 Especificaciones Voltaje: [4.8, 6] V Corriente máxima: 8 mA Apariencia Conexionado Tabla 11. Servomotor Futaba S3003 Estos servos se emplean para mover las ruedas del robot. Básicamente están formados por un motor eléctrico, una caja reductora y un circuito de control y están diseñados para girar en un ángulo máximo de 180º. En la siguiente figura se explica cómo se consigue: 35 Elementos del Sistema Figura 16. Señales PWM Un potenciómetro está sujeto al eje de giro sel servo. De esta forma el circuito de control sabe en qué posición está en cada momento. La posición deseada se le da al eje por medio de una señal PWM o de ancho de pulso, que consiste en enviar una señal con un período constante y un pulso que varía en función del ángulo girado. En este proyecto se pretende que el robot se mueva a distintas velocidades, así que ha habido que “trucar” los servos para que, por un lado, giren 360 º y, por otro, que se pueda controlar la velocidad en lugar de la posición. El procedimiento consiste en liberar el potenciómetro del eje de giro y colocarlo en el valor medio de su rango de valores, que correspondería q tener el servo con un ángulo de 90 º. Haciendo esto se consigue que el motor gire en varios sentidos. Además, existe un pequeño rango de ángulo, en torno al punto medio en el que el servo tiene una respuesta aproximadamente lineal. En el programa de Arduino se expandirá esta pequeña zona de funcionamiento lineal para el rango de datos del acelerómetro. Así se consigue que la velocidad de giro varíe en función del ángulo del dato del acelerómetro. El Arduino posee pines específicos para mandar señales PWM y además proporciona la librería Servo que simplifica mucho el código necesario para mover el servo. 36 Elementos del Sistema Sensor de contacto. Interruptor de fin de carrera RL6 Especificaciones Conexionado Apariencia Señal de medida Voltaje máx: 250 V GND Corriente máxima: 16 A VCC GND VCC Señal de control Tabla 12. Interruptor RL6 El robot dispone de dos interruptores, uno a cada lado, para detectar posibles colisiones contra obstáculos. El modo de funcionamiento es muy sencillo. Si el interruptor está presionado, en la patilla de medida habrá 5 V. En caso contrario no habrá tensión. En el Arduino se conectará en una de sus entradas digitales. Para evitar que haya un cortocircuito cuando esté presionado, se conecta una resistencia en serie entre la patilla de medida y la patilla de GND. 2.2 Arduino Mega ADK En el apartado de “1.1 Objetivos del Proyecto” se comentó que el sistema debería ser barato, de bajo consumo, hacer uso de software libre y tener un hardware bastante conocido donde hubiera mucha información en la red para facilitar el desarrollo de mejoras futuras. El dispositivo más conocido que cumple estos requisitos es Arduino. Arduino es una plataforma para desarrollo de productos electrónicos, sobre todo para construir prototipos. Arduino cuenta con una gran variedad de modelos con distintas características, así como “shields” de ampliación para añadir elementos de comunicación y otras funcionalidades. En este proyecto se utiliza uno de los modelos, el Arduino ADK. 37 Elementos del Sistema Estos dispositivos son relativamente baratos (a partir de 20 euros, dependiendo del modelo). Son de bajo consumo. Pueden ser alimentados por USB, por puerto Jack de 2.1 mm o por los pines Vin y GND, y la placa trabaja a 5V. Si lo alimentamos con Jack, la tensión de alimentación deberá ser de entre 7V y 12V aunque pueden operar con alimentaciones de entre 6V y 20V. Si lo alimentamos a menos de 7V, su pin de potencia para alimentar otros dispositivos podría entregar menos de 5V y si lo hacemos con más de 12V, la placa podría sufrir daños. Es software libre. La página oficial de Arduino (http://www.arduino.cc/) se puede descargar el IDE de Arduino de forma gratuita para desarrollar programas, además de utilizar bibliotecas creadas por Arduino u otras que sube la gente a la web. El hardware también es libre ya que te dan la opción de descargarte los planos de la placa para imprimirla, incluso mejorarla. El sistema requiere unos requisitos mínimos que debe cumplir la placa. A continuación se enumeran: Puertos E/S Entradas Analógicas salidas Total pines 1 para el sensor LDR 1 Dgitales 2 para los interruptores 1 para el “echo” del sensor HC- SR04 2 señales PWM para los servos 1 para el “trigger” del sensor HC- SR04 6 Tabla 13. Puertos necesarios Además deberá tener un puerto USB HOST, un pin de alimentación de 5 V y un pin de GND. Puerto de alimentación Jack 2.1 mm Si el robot es autónomo debe de portar una batería que alimente todos sus componentes. El arduino ADK cumple con todos estos requisitos además de aportar otras características: 38 Elementos del Sistema Especificaciones Microcontroller Input Voltage (recommended) Input Voltage (limits) Digital I/O Pins Analog Input Pins DC Current per I/O Pin DC Current for 3.3V Pin Flash Memory SRAM EEPROM ATmega2560 5V 7- 12 V 54 (of which 15 provide PWM output) 16 40 mA 50 mA 6 KB of which 8 KB used by bootloader 8 KB 4 KB Clock Speed USB Host Chip 16 MHz MAX3421E Tabla 14. Especificaciones Arduino Pines de señal PWM Pines de comunicación Serie E/S digitales Conector PC USB HOST Conector Jack 2.1 mm Pines de alimentación E/S analógicas Microcontrolador Atmega2560 Figura 17. Esquema Arduino ADK 39 Elementos del Sistema 2.3 Smartphone Android Los robots son sistemas electrónicos móviles que requieren requisitos serios como el tamaño, el peso, la adaptabilidad al escenario, la robustez y, sobre todo, la alimentación. La mejor solución que cubre todas estas necesidades es utilizar un teléfono móvil. En esta figura se muestran los elementos que se incorpora un dispositivo móvil en el robot : Figura 18. Esquema de un dispositivo móvil Si además el teléfono tiene un sistema operativo Android se cubren las necesidades anteriormente citadas, como el bajo consumo y el software libre. En este proyecto se ha utilizado el Smartphone Huawei Ascend Y 300, del que se detallan algunas características: 40 Elementos del Sistema Modelo Sistema operativo Banda Dimensiones Pantalla Batería Memoria interna Memoria de expansión Conectividad Cámara Peso Procesador Otros Especificaciones Huawei Ascend Y 300 Android 4.1 (Jelly Bean) UMTS: 900/2100 - EDGE: 850/900/1800/1900 - HSDPA DL 7.2Mbps / UL 5.76Mbps 124,5 x 63,8 x 11,2mm 4,0" TFT-LCD WVGA. Resolución: 800x480. 16M Colores. CORNING® GORILLA® GLASS 2 Li-ion 1950 mAh ROM: 4GB, RAM: 512MB MicroSD hasta 32GB Bluetooth 2.1 A2DP, Wi-Fi 802.11 b/g/n, USB 2.0 High-Speed 5 MP AF, Cámara frontal: 0,3MP FF 130g con batería Qualcomm MSM8225. 1,0 GHz Doble Nucleo GPS/AGPS , Emotion UI 1.0, Sensor de próximidad, Sensor de luz de ambiente, arranque en 5 segundos, carga rápida, DLNA Tabla 15. Especificaciones Huawei Y300 41 Diseño del Sistema Capítulo 3 Diseño del Sistema En el presente capítulo se describe el desarrollo del Sistema, que principalmente es todo desarrollo software. En la figura de la siguiente página podemos ver una idea general de todo el sistema, tanto del Hardware como del Software. 42 Diseño del Sistema Sensor de contacto izquierdo Sensor de ultrasonidos Sensor de contacto derecho Sensor CNY70 izquierdo Sensor iluminación Programa Arduino Comunicación USB Motor rueda izquierda Sensor CNY70 derecho Motor rueda derecha Batería App Android 43 Diseño del Sistema El desarrollo del software en ADK tiene dos partes bien diferenciadas: la programación en Arduino y la aplicación en Android. 3.1 Software de Arduino El programa en Arduino, también llamado “sketch”, usa el lenguaje de programación C/C++ además de incorporar sus propias librerías, las cuales contienen clases y métodos para la activación y usos de los puertos del chip. 3.1.1 Entorno de Arduino El IDE de Arduino es un entorno de desarrollo libre que se puede descargar de forma gratuita en la web www.arduino.cc. Además , para este proyecto es necesario descargar e incluir en la carpeta libraries las siguientes carpetas: USB_Host_Shield. Librerías correspondientes a los Drivers de la placa controladora. Todo Hardware siempre tiene unos drives para que sea reconocido por el sistema operativo. AndroidAccessory. Librerías que contienen las clases y métodos para la comunicación con el dispositivo Android. Otro aspecto importante es seleccionar la tarjeta en la que cargaremos el programa. Se hace de la siguiente manera: Figura 19. Selección de la tarjeta ADK 44 Diseño del Sistema Una vez hecho esto, se pasará a mostrar los diferentes elementos que componen el IDE de Arduino: Verificar código. Si hay fallos se indicará en cuadro de mensajes Cargar el sketch en el Arduino Crea un sketch nuevo Abrir un sketch Abre el monitor serie que muestra los datos por pantalla enviados desde Arduino. También permite enviarle datos Guardar el sketch Cuadro de mensajes. Aquí se muestran los errores de programación, warnings, modificaciones… SKETCH Número de línea donde se encuentra el cursor Puerto del Arduino en el que se cargará el sketch Figura 20. Entorno Arduino 45 Diseño del Sistema El monitor serie se puede ver en la siguiente figura: Figura 21. Monitor Serie 3.1.2 Desarrollo del programa Para programar en Arduino hay que tener en cuenta varias partes: En primer lugar, se han de incluir las librerías que se van a utilizar: A continuación es buena costumbre dar un nombre a los pines que se van a usar. Es fácil cometer el error de equivocarse con el número del pin. 46 Diseño del Sistema En esta zona también se declaran variables que se usarán en el programa como variables globales, constantes o instancias de clases. He aquí algunos ejemplos: - Ahora se pasa a explicar el ciclo de ejecución del programa. Tiene dos funciones principales y obligatorias: Figura 22. Ciclo de vida de un sketch La función setup(). Se ejecuta siempre que se enciende el Arduino o se reinicia. En esta función : En este proyecto el Arduino intercambiará datos con el teléfono, así que es necesario indicar a la velocidad que se transmitirán esos datos de la siguiente manera: 47 Diseño del Sistema Es posible dar valores iniciales a variables u objetos que requieran una asignación de pines: Además de haber declarado los pines, es necesario indicar si los pines son de entrada/ salida. La función loop(). Se repite cíclicamente. Aquí va escrito el cuerpo del programa, lo que hace, y se ejecuta repetidamente de forma indefinida. En el siguiente apartado se muestra la estructura y se explica cómo funciona el código que hay en esta función. Después de esta función, se pueden implementar otras funciones que se requieran en el programa y que son llamadas en la función loop(). Como ejemplo, la siguiente función tiene que ver con el sensor de ultrasonidos. La función toma como parámetro el tiempo que mide el ultrasonidos y devuelve una distancia. 48 Diseño del Sistema Software de Arduino En este apartado se explicará el software desarrollado en la rutina principal o loop, el cual se ejecutará de forma indefinida una vez se cargue a la placa de Arduino. En la estructura del programa hay tres partes diferenciadas, y que siguen este orden: Establecer conexión con el dispositivo Leer el mensaje del dispositivo, y según el contenido de éste, mover el robot en uno de los dos modos Leer las entradas de los sensores y enviar la información en un mensaje al dispositivo Figura 23. Estructura del programa A continuación se muestra el flujograma que explica cómo se comporta el código del programa y se entrará en detalle en las partes del código más características: 49 Diseño del Sistema Figura 24. Flujograma del programa en Arduino 50 Diseño del Sistema • Detección de dispositivos conectados Es lo primero que se encuentra en la rutina principal. El loop comienza con una llamada a la función AndroidAccessory::isConnected() para comprobar si hay un dispositivo conectado. Si lo hay, actualiza los flujos de entrada y salida entre el dispositivo y Arduino. Si no detecta ningún dispositivo conectado continua comprobándolo hasta que haya uno conectado. Esta sentencia se traduce en código de esta manera: Para usar la función isConnected() hay que crear un objeto global de la clase AndroidAccessory: En la rutina principal llamamos a la función de esta manera: • Lectura del mensaje Una vez que ya está establecida la comunicación hay que leer el mensaje que envía la aplicación Android, en el caso de que exista. Para comprobar si se ha recibido un mensaje se utiliza otra función de la clase AndroidAccessory. Con la función read() se lee el flujo de entrada. Si no hay un mensaje entrante la función devuelve un 0. Si existe un mensaje lo guarda en msg, un vector de 6 Bytes, donde posteriormente el programa interpretará esa información. En el siguiente punto se explica qué significado tienen los mensajes para el programa. 51 Diseño del Sistema • Protocolo de mensajes Eje del acelerómetro [0] [1] Dato Modo de operación Como se ha dicho anteriormente, la información proveniente de la aplicación se guarda en un vector de tipo Byte con 6 posiciones. La información que guarda y va actualizando el vector en cada ciclo es la siguiente: [2] [3] [4] [5] Figura 25. Contenido del mensaje Posición [0] [1] De [2] a [5] Descripción Posee el modo de operación del robot. Dato 0x7. Modo Manual. Especifica si el dato es la inclinación correspondiente al eje y o al eje x del teléfono. Sólo es necesario si estamos en Modo manual. El dato medido por el acelerómetro en cualquiera de los dos ejes. Sólo es necesario si estamos en Modo Manual. 0x1. El dato es la inclinación del eje X. 0x2. El dato es la inclinación del eje Y. Tabla 16. Protocolo del mensaje 52 0x1. Modo Siguelíneas. Diseño del Sistema Aclaración. El dato del acelerómetro está almacenado en 4 Bytes. Esto es porque el acelerómetro mide datos analógicos y los convierte a un valor digital de entero. Si se almacena ese número directamente en una variable de tipo Byte sólo se guardan los 8 primeros bits, perdiendo la información de los bits restantes. El resultado de esta operación es que se obtiene un número totalmente erróneo, distinto a la medida real. Para solucionar este problema se utiliza la técnica de bit-shifting, en la que se representa el dato en su forma binaria y se almacena en 4 Bytes. Supongamos que se quiere almacenar el número 300. Su representación binaria es 00000000 00000000 00000001 00101100. La idea es almacenar esta información en 4 bytes, de tal manera que en la posición [2] haya almacenado el 00000000, en la [3] el 00000000, en la [4] el 00000001 y en la 5 el 00101100. En programación esto se puede seguir usando la siguiente sentencia: De este modo se envían los datos correctamente sin perder información. Para realizar la operación inversa, es decir, convertir la información de los 4 Bytes en un valor entero, se utiliza el método bitwise AND, y la forma de hacerlo en programación es la siguiente: Esta operaciones son utilizadas tanto en el código de la aplicación como en el de Arduino cuando hay una medida analógica que se quiere enviar, como los datos del acelerómetro, las medidas del sensor de ultrasonidos o del de iluminación. • Decisiones del programa Dependiendo del mensaje que se reciba, se ejecutará una parte el programa u otra y, por consiguiente, el robot actuará de diferentes maneras. 53 Diseño del Sistema - Si por ejemplo, el primer valor del vector es el 0x7, se ejecuta la parte del código correspondiente para mover el robot manualmente. Esto es con los datos del acelerómetro. En este caso es importante la información de la siguiente posición del vector, ya que si es 0x1 el dato corresponderá a la inclinación del eje X del teléfono, y si es 0x2, la del eje Y. El resto de las posiciones contienen el dato. Véase esto traducido a código. Según lo explicado anteriormente, este sería el caso del dato de la inclinación del eje X, cuyos valores máximo y mínimo son 100 y -100. Este dato se convierte a tipo entero por el método de bitwise AND, y se realiza una conversión de rango por medio de la función map() para que los valores estén en el rango donde el servo cambia de velocidad. Las variables rueda_der y rueda_izq son las velocidades finales con las que se moverán los servos. Se realiza la misma operación para el caso del eje Y. Pero en este caso hay que añadir el siguiente código para que el robot gire en una dirección u otra, esta vez con velocidad constante: 54 Diseño del Sistema Finalmente se mueven los servos mediante esta sentencia: Nótese que el programa está escrito en este orden. En cada vuelta del loop() sólo se recibe el dato del eje X, el dato del eje Y o ninguno de los dos. Si se mueven los servos al final del código expuesto el robot se moverá con fluidez y más continuidad porque se hacen todas las operaciones antes. Si movemos los servos en otra parte de este código o más de una vez el robot se móvera con menos realismo, incluso se puede saturar la aplicación. - Si, por el contrario, el primer valor del vector corresponde al 0x1, el programa ejecutará el código del Modo Siguelíneas, saltándose el código anterior y despreciando el resto de la información del vector. El código del Modo Siguelíneas es muy sencillo. Se hace una lectura digital de los sensores de infrarrojos y esos datos se someten a los cuatro casos posibles, ya explicados en el bloque 2 de la memoria ( Estado del arte). Según estas posibilidades el robot se moverá para que los sensores estén siempre dentro de la línea negra. 55 Diseño del Sistema • Lectura de sensores y envío de mensajes Es la última parte del programa. Por los pines del arduino se leen las medidas de los sensores de contacto (derecho e izquierdo), ultrasonidos e iluminación; pero no de cualquier manera, sino de la más eficiente para no colapsar el programa. Existen dos tipos de medidas: - Digitales. Correspondientes a los sensores de contacto. El código es el siguiente: Primero se hace una medida digital con la función digitalRead() en la que se actualiza el estado del sensor de contacto. Después se modifica una variable booleana según el estado actual para detener el robot o no, se compara el estado actual con el anterior, y finalmente se manda el mensaje usando la función write() del Accessory. De este modo, y si se hace una medición al inicio del programa, cuando el teléfono reciba el mensaje tendrá la información para saber si el sensor está activado o desactivado. Es mejor enviar el mensaje justo después de la medición porque el Arduino tiene que mandar menos información en cada mensaje y la aplicación tiene menos datos en cola. Aún así, sólo envía 2 Bytes, uno para identificar qué sensor es y otro con el valor lógico de ‘0’ o ‘1’. 56 Diseño del Sistema - Analógicas. Es la información de los sensores de ultrasonidos e iluminación. Estos sensores sí que tienen que enviar números enteros que ocupan más. El Arduino tarda en leer una entrada analógica unos 100 microsegundos. Eso significa que como mucho puede hacer 10,000 medidas en un segundo, pero como hay tres sensores más y también tiene que enviar la información de datos enteros al final enviará bastantes menos. Por este motivo, y aprovechando que los sensores de iluminación y ultrasonidos no requieren una respuesta en frecuencia alta se utiliza la sentencia switch ( count ++ %10). Utilizando esto se reduce la frecuencia de lecturas analógicas a la mitad porque en cada vuelta sólo realiza la lectura de uno de los sensores que están dentro del switch. El código se muestra a continuación: 57 Diseño del Sistema Como se aprecia en el código, el protocolo de mensajes es el siguiente: Posición Descripción Identificación del sensor. [0] Dato del sensor. Dato 0x5. Sensor de iluminación. 0x7. Sensor de ultrasonidos. El dato tiene 16 bits. De [1] a [2] Tabla 17. Protocolo del mensaje Por último, llama a la función delay() para que transcurran unos microsegundos ( 5 en este caso) después de cada vuelta para no colapsar la comunicación con el dispositivo. 3.2 Software de Android El desarrollo de la aplicación tiene bastante más complicidad que el sketch de Arduino. Entre otras cosas, porque la aplicación se ejecuta en un sistema operativo. Requisitos de software Para desarrollar aplicaciones en Android es necesario instalar el Java Development Kit( JDK) y el ADT Bundle. Este último es un paquete que contiene el entorno de desarrollo Eclipse con las herramientas del Software Development Kit (SDK) para poder desarrollar las aplicaciones, incluso ejecutarlas en una máquina virtual de Android. 3.2.1 Entorno de Eclipse + SDK Las aplicaciones en Android se escriben en JAVA, lenguaje de programación orientado a objetos de desarrollo totalmente libre. 58 Diseño del Sistema A continuación se presenta la apariencia con los elementos que componen el entorno Eclipse: Barra de herramientas Editor de archivos Estructura de Elementos Ventana de Breakpoints y De la aplicación depuración de errores Ventana de ejecución Figura 26. entorno Eclipse • Barra de herramientas Las herramientas más significativas son: SDK Manager. Esta herramienta permite descargar paquetes que contienen herramientas, APIS y drivers necesarios para desarrollar una aplicación en en una versión de Android. AVD Manager. Es una máquina virtual del sistema operativo Android para poder cargar y ejecutar las aplicaciones que se desarrollen. Es una alternativa a cargar la aplicación directamente en el teléfono. A continuación se muestra la apariencia de la máquina virtual de Android: 59 Diseño del Sistema Figura 27. Máquina virtual de Android (AVD) Debug. Comprueba si la aplicación tiene errores. Si es así, abre la ventana de breakpoints y depuración de errores. En caso de no tener errores carga la aplicación al teléfono a través de USB, y si no existe un dispositivo aconectado abre el AVD Manager para cargarla en la máquina virtual. Hace exactamente lo mismo que Debug, pero además ejecuta la aplicación. • Editor de archivos En esta parte es donde se escribe y modifica el código de la aplicación, ya sea el de los archivos.java o el de los archivos.xml. Aunque más adelante se explicarán estos archivos con mayor profundidad, se adelanta que los archivos.java sólo se pueden modificar cambiando el código, mientras que los archivos.xml pueden ser modificados cambiando el código o de forma gráfica. A continuación se muestra la imagen de la ventana para modificar un archivo.xml de forma gráfica. 60 Diseño del Sistema Figura 28. Creación gráfica de archivos.xml • Ventana de Breakpoints y depuración de errores En programación se obtienen todo tipo de errores constantemente. Si el código es corto es fácil encontrarlos, pero en caso contrario puede ser muy tedioso. Los breakpoints sirven para ejecutar el código de la aplicación poco a poco para encontrar los errores de forma más sencilla y rápida. • Ventana de ejecución Es una ventana donde se ve el proceso de ejecución de la aplicación en tiempo real. Las pestañas más usadas normalmente son la Consola y el LogCat, muy útiles para reconocimiento de errores. • Estructura de elementos de la aplicación Está formado por el código fuente escrito en java, un código descriptor (AndroidManifiest.xml) y los recursos. El código fuente necesita y hace uso de los recursos de la aplicación para desarrollar un programa Android completo. 61 Diseño del Sistema A continuación se muestra una imagen de la estructura del proyecto y una tabla explicando que contiene cada carpeta: Figura 29. Estructura de un proyecto en Eclipse 62 Diseño del Sistema Tabla 18. Carpetas de un proyecto en Android Además, para desarrollar aplicaciones de ADK está la carpeta xml. Esta carpeta no se crea por defecto cuando creas un proyecto nuevo. Es necesario crearla aparte y ubicarla dentro de la carpeta res. Dentro de esta carpeta hay q crear un fichero.xml llamado accessory_filter, cuyo código es el siguiente: 63 Diseño del Sistema Este recurso hay que registrarlo en el AndroidManifiest.xml para que lo reconozca la aplicación. Si no se hace exactamente de esta forma se generarán errores cuando se depure la aplicación. 3.2.2 Desarrollo de la aplicación Antes de profundizar en el código fuente y otros elementos de la estructura es necesario explicar algunos conceptos básicos relacionados con la programación en Android. Para desarrollar una aplicación se hace uso de bibliotecas con superclases. Figura 30. Bibliotecas de Android Los elementos más básicos que se pueden encontrar en una aplicación son: • • Activity. Es cada pantalla de la aplicación. Puede contener texto, botones, entradas de texto, etc. Las actividades pueden realizar multitud de funciones, interactuar entre ellas o con otros elementos, como los servicios. Service. Un servicio ejecuta procesos sin necesidad de ninguna interacción, no tiene entorno gráfico. • BroadcastReceiver. Es un componente que recibe y maneja peticiones que pueden ser enviadas al sistema u otras aplicaciones. Puede reaccionar en situaciones de batería baja, incluso usado para abrir otra aplicación. • ContentProvider. El proveedor de contenidos es usado para compartir datos entre multitud de aplicaciones. Un ejemplo sería el proovedor de contenidos de los contactos del teléfono, usado por muchas aplicaciones como whta´s App. 64 Diseño del Sistema La aplicación está compuesta por un servicio, una actividad principal, una actividad para el Modo Manual y otra actividad para el Modo siguelíneas. En la siguiente figura se puede ver un esquema general de cómo es la aplicación y las acciones que realiza. Servicio • Establece la comunicación via USB con el arduino ADK . • Recibe información de los sensores del ADK. • Envía información del acelerómetro al ADK. Actividad principal •Ejecutar el servicio Actividad Modo Manual •Utilizar el servicio. • Parar el servicio. •Abrir actividad Modo Manual. • Abrir actividad Modo Siguelíneas. • Dejar de utilizar el servicio. Actividad Modo Siguelíneas • Utilizar servicio. el •Dejar de utilizar el servicio. Las actividades utilizan el servicio para : • Recibir la información de los sensores y sacarlos por pantalla. • Enviar información al servicio con el modo de funcionamiento. Figura 31. Esquema general de la aplicación 65 Diseño del Sistema 3.2.2.1 Actividad principal Representa la primera pantalla que aparece cuando se ejecuta la aplicación. La programación de la actividad tiene dos partes diferenciadas: Programación del entorno gráfico La programación del entorno gráfico está escrita en lenguaje xml y el archivo está dentro de la carpeta Layout. Cada actividad tendrá su propio Layout en esta carpeta. Todos los elementos necesarios para construir la parte gráfica están contenidos en la clase View Group. A continuación se describen los elementos: Relative Layout Botones Figura 32. representación de un Relative Layout Layout. Es la estructura donde se construye la interfaz gráfica. Existen distintos tipos, como el Relative Layout, en el que se 66 Diseño del Sistema pueden colocar los objetos con total libertad, sin ningún orden o restricción obligatoria. Todo Layout tiene unos parámetros, como el tamaño y la identificación. Botones. Su uso es realizar acciones cuando son presionados. Sus principales parámetros son el tamaño, el texto , la identificación . El código que crea este entorno gráfico es el siguiente: En el código fuente se identifica a este botón por este nombre Parámetros de la forma y alineación con el Layout El código de los otros tres botones es igual Código fuente El código fuente está escrito en lenguaje JAVA, y cada actividad es una clase que está dentro de la carpeta src. Para entender el código es importante conocer el ciclo de vida que tiene una actividad en Android. Ciclo de vida de una actividad Una actividad es una clase que puede contener variables y los métodos que se quiera, pero tiene que tener unos métodos estipulados y obligatorios para que se ejecute correctamente la actividad. Cuando se lanza una actividad el Sistema siempre busca y lee estos métodos en el mismo orden y sigue siempre el siguiente esquema: 67 Diseño del Sistema Figura 33. Ciclo de vida de una actividad 68 Diseño del Sistema A continuación se hace una descripción de estos métodos: Método onCreate() Descripción Es llamada cuando la actividad es creada por primera vez. Aquí se crean las vistas, variables estáticas y todo inicialización. onRestart() El Sistema la llama después de que la actividad ha sido parada. onStart() Llamada siempre antes de que la actividad sea visible por el usuario. OnResume() Correspondiente a las tareas que haga la aplicación cuando esté interactuando con el usuario. onPause() Llamada cuando el Sistema tiene otra actividad en primer plano (con el método onResume()) y esta deja de visualizarse parcialmente. En esta función pausa todo lo que se estaba haciendo en la función onResume(). Tabla 19. Métodos de una actividad No es imprescindible que una actividad tenga todos estos métodos. En la actividad principal de la aplicación sólo están implementados el onCreate() y el onDestroy(). El Sistema llama al primero de éstos cuando la aplicación es lanzada y después busca los siguientes métodos. Si no los encuentra, se queda ejecutando el código de onCreate() hasta que la actividad sea destruida. Diagrama de la clase Actividad Principal Una vez explicado el ciclo de vida se presenta la Clase de la Actividad Principal: Figura 34. Clase Actividad Principal 69 Diseño del Sistema Nota aclaratoria: Un callback es un objeto perteneciente a una clase determinada que tiene unas funciones obligatorias, diseñado así por Android. Para la programación de los botones se utiliza un callback que tiene una única función llamada onClick(), y el Sistema ejecuta el código que hay en esta función cada vez que el botón es pulsado. La forma de programar esto es escribir el callback y después llamarlo en el método onCreated() para que se ejecute cada vez que se pulse. He aquí un ejemplo de cómo se implementa: Callback de un botón: Llamada en onCreate(): En este caso cuando se pulsa el botón se llama a la función startService(), que comienza que ejecuta el servicio. Flujograma de la Actividad Principal Figura 35. Flujograma de la Actividad Principal 70 Diseño del Sistema 3.2.2.2 Servicio La funcionalidad del Servicio en esta aplicación es: 1. Establecer comunicación con el Arduino ADK. 2. Enviar información del acelerómetro y del modo de funcionamiento al ADK. 3. Recibir información del ADK con los datos de los sensores. 4. Comunicarse con las actividades para saber el modo de funcionamiento y enviar los datos de los sensores a las actividades. Estas tareas se podrían hacer con una actividad. El problema es que el teléfono irá acoplado en el robot, y si no se interactúa con la actividad ésta será destruida por el sistema tarde o temprano, eliminándose la comunicación entre el teléfono y el ADK. Un servicio es un componente de una aplicación que realiza procesos sin necesidad de que el usuario interactúe con él, no tienen interfaz gráfica, y se ejecuta en el Background, así que es mucho menos probable que el Sistema acabe destruyéndolo ya que los servicios son mucho más prioritarios que las actividades a la hora de eliminar procesos. Existen servicios con estructuras y funcionalidades diferentes. En esta aplicación se usará un Bound Service . Su función es ser el servidor de la una interfaz de comunicación servidor/ cliente. Los clientes, tales como actividades, se pueden unir al servicio, hacer peticiones, respuestas, intercambio de datos y desunirse cuando acabe el proceso. El servicio se ejecuta mientras que haya alguna actividad usándolo, en caso contrario el Sistema destruirá el servicio. A continuación se muestra el ciclo de vida completo de un Bound Service: Figura 36. Ciclo de vida de un Bound Service 71 Diseño del Sistema Además, el servicio usará con las actividades un protocolo de comunicación vía Messenger. Este protocolo se explica a continuación: Comunicación con las actividades Figura 37. Diagrama de counicación en un Bound Service utilizando la clase Messenger Tanto el servicio como las actividades que se unan a él pertenecen a la misma aplicación, no forman parte de aplicaciones diferentes. En la aplicación, las actividades que se unen al servicio son Modo Manual y Modo Siguelíneas y el proceso es exactamente igual para cada una de ellas. Siguiendo el sentido del esquema se explica el proceso a continuación: 1. Un Intent es una petición que un elemento de una aplicación manda a otro para comunicarse con él. La actividad manda un Intent al Servicio a través de la función bindService(), la cual opera de forma muy similar a startService(), explicada en la Actividad Principal. 2. El servicio se inicia si no se había inicado antes. 3. El servicio contiene la función onBind(), la clase Messenger y la clase IncomingHandler. La función onBind() recibe el Intent proveniente de la actividad y crea un objeto de la clase Messenger. 72 Diseño del Sistema 4. La función onBind() envía a la actividad un objeto de la clase IBinder, la cual contiene elementos de identificación del servicio y para el establecimiento de la comunicación. 5. . En la actividad, la función onServiceConnected(): • Recibe el objeto IBinder. • Crea un objeto Messenger con la información del IBinder. Ahora la actividad y el servicio ya pueden comunicarse por medio de sus dos clases Messenger. • Crea un mensaje con la variable de registro. • El Messenger envía el mensaje con la función send(). 6. El Messenger del servicio recibe el mensaje de registro y se lo pasa a la clase IncomingHandler. 7. La clase IncomingHandler maneja los mensajes provenientes de la actividad. Registra como cliente a la actividad y la añade a un array de la clase Client. Con esta esta clase se mandan mensajes con los datos de los sensores a la actividad, la cual también tiene una clase IncomingHandler para recibir los datos y sacarlos por pantalla. Comunicación con la placa Arduino La comunicación USB es una comunicación asíncrona a través de un cable que tiene cuatro líneas: dos para la alimentación, una para enviar datos y otra para recibir datos. En el caso del ADK, tiene un protocolo de comunicación en el que el Arduino es el maestro ( manda peticiones de conexión ) y el dispositivo Android el esclavo ( sólo puede responder a peticiones de conexión). Además la alimentación la proporciona el Arduino. Los teléfonos Android no están preparados para que se conecten dispositivos con USB host. Usb Accessory es una librería que permite que estos dispositivos puedan conectarse al teléfono. Por otro lado, la clase que permite acceder al estado del USB y comunicarse con dispositivos se llama Usb Manager. 73 Diseño del Sistema Android Accessory Android Usb Manager USB Host C/ C++ Usb Host Shield Android Accessory Se utilizarán estos dos elementos para establecer la comunicación entre el Arduino y el teléfono. Figura 38. Librerías utiizadas en el desarrollo del software La aplicación debe seguir las siguientes pasos siguiendo este orden: 1. Detectar accesorios (como Arduino) que quieren conectarse al USB del teléfono y elegir el accesorio con que realmente se quiera establecer conexión. 2. Pide al usuario permiso para comunicarse con el accesorio, si no lo ha obtenido. 3. Intercambia datos con el accesorio a través de una interfaz. A continuación se expone un esquema general con los elementos de la aplicación que están relacionados con la comunicación del accesorio: 74 Diseño del Sistema SISTEMA ANDROID Notificación cuando un evento en USB ocurre Registro para el evento de USB BROADCAST RegisterAccessory() NTENTI FILTER DESCRIPTOR THREAT Y RUNNABLE OpenAccessory() INPUT STREAM OUTPUT STREAM Figura 39. Elementos del Servicio Establecimiento de conexión. Función RegisterAccessory() Un Broadcast Receiver es un elemento de Android capaz de percibir distintos eventos que ocurren en el teléfono, como una llamada entrante, batería baja, redes de conexión disponibles, etc. El intento de conexión de un elemento externo al teléfono a través de USB también es un evento. La aplicación utiliza un Broadcast Receiver para saber cuándo se están intentando conectar al USB. Para eso manda al sistema un registro especificando que le avise sólo de eventos que ocurran en el USB. El sistema le enviará todos los eventos que ocurran, pero sólo hay que establecer conexión con el Arduino del robot. Un Intent Filter es un 75 A P L I C A C I Ó N RECEIVER Diseño del Sistema elemento que filtra todos los intentos de conexión de accesorios y registra el que responde a la identificación del Arduino del robot. El código de identificación es el recurso accessory_filter.xml, ubicado en la carpeta res de la aplicación. Comunicación con el accesorio. Función OpenAccesory() Una vez que el servicio reconoce el accesorio con el que se quiere conectar, crea un File Descriptor con los permisos necesarios para la comunicación. Este archivo se pasará por referencia a la clase File Input Stream, la cual es capaz de acceder al buffer de la comunicación y leer los mensajes. La aplicación está continuamente recibiendo mensajes a la vez que hace otros procesos, como mostrar la pantalla, comunicarse con las actividades, etc. Todas estas tareas por defecto se realizan en el UI Thread (Proceso de ejecución de interfaz de usuario), también llamado Thread principal. Si se hacen todas estas tareas en un solo proceso probablemente la aplicación acabe bloqueándose. Para solucionar este problema se utiliza la clase Threat. Esta clase es capaz de crear un proceso de ejecución paralelo al principal. La idea es realizar tareas por separado, como la comunicación con el Arduino, y que el UI Thread solamente imprima los datos de los sensores. De este modo se evita que se colapse. Todo el código que queremos que se ejecute en el hilo paralelo estará en un Runnable. El Sistema buscará este elemento cuando iniciemos un Thread en la función openAccessory(). Por otro lado se utiliza la clase Output Stream para enviar los datos del acelerómetro al Arduino. 76 Diseño del Sistema Una vez explicado la comunicación del servicio con las actividades y con el accesorio se muestra la clase Servicio y su diagrama de flujo: Diagrama de la Clase Servicio Figura 40. Diagrama de la Clase Servicio 77 Diseño del Sistema Flujograma de la Clase Servicio 78 Diseño del Sistema 79 Diseño del Sistema 3.2.2.3 Actividad Cliente Esta actividad muestra por pantalla los datos de los sensores. Está compuesta por un botón para utilizar el servicio llamado “Bind to Service” u otro para dejar de utilizarlo que se llama “Unbind from Service”. Cuando se une al servicio establece comunicación (ya explicado cuando se describió el servicio), envía al servicio su variable de identificación y recibe los datos de los sensores para imprimirlos por pantalla. Sólo se podrá unir al servicio si este se ha iniciado en la actividad principal. Las actividades Modo Siguelíneas y Modo Manual son actividades cliente. Esta es la apariencia de la actividad escrita en lenguaje xml: Botón para utilizar el servicio Botón para dejar de utilizar el servicio Datos de los sensores de contacto Dato del sensor de iluminación Dato del sensor de ultrasonidos Datos del acelerómetro (inclinación en el eje X y en el eje Y del teléfono) Figura 41. Apariencia de la Actividad Cliente A continuación se muestra la clase Cliente: 80 Diseño del Sistema Diagrama de la Clase cliente Figura 42. Diagrama de la Clase Cliente 81 Diseño del Sistema Flujograma de la Clase Cliente 82 Pruebas y evaluación Capítulo 4 Pruebas y evaluación En este capítulo se describen las pruebas que se han hecho al sistema, con las cuales se aseguran que los requisitos especificados se han cumplido. Se describe el entorno de pruebas, y a continuación se detallan las mismas. 4.1 Descripción del entorno de pruebas El entorno de pruebas consta de un ordenador personal, el robot con el Arduino ADK incorporado y dos Smartphones. A continuación se muestra una imagen del mismo y se describen sus elementos: Figura 43. Entorno de pruebas 83 Pruebas y evaluación • Ordenador personal. Sony Vaio VGN- NW21 Figura 44. Ordenador portátil El ordenador es un componente esencial en las pruebas. Es utilizado para: • Cargar la aplicación al Smartphone con el entorno Eclipse. Cargar el programa de Arduino en la placa ADK . Proporcionar alimentación a la placa Arduino ADK durante las pruebas. Smartphones Se utilizan dos Smartphones para realizar las pruebas: un Huawei Ascend Y 300 y un BQ Aquaris 5. A continuación se hace una breve descripción de sus características. Huawei Huawei Ascend Y300 Características Descripción Apariencia Android OS, SO v4.1 (Jelly Bean) Dual-core 1 GHz CPU Cortex-A5 2.0 Versión USB Se utiliza en todas las pruebas a lo largo del desarrollo de la aplicación. Además irá incorporado en el robot. Tabla 20. Características del Huawei Ascend Y300 84 Pruebas y evaluación BQ Aquaris 5.7 Características SO Descripción Apariencia Android 4.2 Jelly Bean Quad Core CPU Cortex A7 7 up to 1.5 GHz 2.0 Versión USB Sólo es utilizado para estudiar la compatibilidad con otras plataformas. Tabla 21. Características del Smartphone BQ Aquaris 5.7 • Robot utilizado Componentes Placa Arduino ADK Placa Protoboard Sensor de ultrasonidos Sensor de iluminación Apariencia Sensor de contacto Sensor detector de línea Tabla 22. Robot del laboratorio 85 Pruebas y evaluación 4.2 Pruebas realizadas durante el desarrollo del proyecto Cuando se desarrolla software, buscar programas que sirvan de ejemplo o desarrollar la aplicación por partes es primordial para verificar que se va por buen camino hacia la solución final. A continuación se describen una serie de pruebas que se hicieron, por orden cronológico, desde el inicio hasta el resultado final del sistema: Se descargó y probró la aplicación “Demokit” desarrollada por Google para el ADK y disponible en Play Store. Esta aplicación es capaz de leer sensores y realizar acciones como encender leds o servomotores. Figura 45. Aplicación Demokit Se desarrolló el “hola mundo” del ADK. Fue importante para conocer el entorno de Eclipse, cómo cargar los programas y la estructura básica de una aplicación con el ADK. La prueba consistía en encender un diodo Led con el teléfono. 86 Pruebas y evaluación A la aplicación anterior se le fueron añadiendo sensores . En las pruebas la aplicación se bloqueaba. No era capaz de enviar y recibir información al mismo tiempo. Hubo que modificar la estructuración de la aplicación y del programa de Arduino. Una vez realizada la prueba del éxito del punto anterior, se desarrolló una aplicación orientada a la solución final. Las pruebas ayudaron a que el robot se moviera correctamente, pudiendo modificar su velocidad y recibiendo los datos de los sensores. Parecía que la solución final estaba muy cerca. Sin embargo, al probar la aplicación en el robot sucedió que funcionaba correctamente sólo durante un período de tiempo . Esto es debido a que la aplicación estaba compuesta por un única actividad, y cuando en una actividad no ha interacción con un usuario a través de la pantalla el Sistema acaba destruyéndola. Esto suponía una limitación enorme, que se solucionó dando un giro completo a la estructura de toda la aplicación, utilizando un “Bound Service”. Se hicieron pruebas básicas con el ADK utilizando un “Bound Service” como si se estuviera en la primera fase de desarrollo. Fue una fase complicada. No había información sobre la utilización del ADK con servicios en Android. Parece ser que ésta ha sido la primera vez. Desarrollo y pruebas de la aplicación final. A pesar de la falta de información y la incertidumbre que se crea, el sistema acabó funcionando con éxito. Se comprobó que era posible utilizar el ADK con este tipo de servicio y se superó la limitación surgida. 4.3 Pruebas unitarias Las pruebas unitarias son la forma de comprobar el correcto funcionamiento de cada módulo que conforma el código aisladamente. Esto asegura que cada uno de los componentes trabaja como es debido por separado. 87 Pruebas y evaluación Pruebas en Arduino. Pruebas tales como la verificación de que se reciben los datos de los sensores correctamente, o que el robot se detiene cuando se activa un sensor de contacto. Un ejemplo concreto es la comprobación de que el sensores de ultrasonidos funciona correctamente. Para esto se imprimen los valores que recibe el Arduino por el monitor serie: Figura 46. Impresión de los datos del sensor de ultrasonidos en el monitor serie Pruebas en el teléfono. Las principales pruebas que se pueden hacer son las siguientes: Cargar la aplicación al teléfono. Cuando surgen errores en este paso, generalmente es debido a un problema de versión de Android o errores relacionado con la programación del entorno gráfico (archivos xml). Iniciar servicio y comprobarlo en el gestor de aplicaciones del dispositivo. En el menú de ajustes Gestor de aplicaciones aplicaciones ejecutándose, se puede comprobar si el servicio se está ejecutando. Otra forma de comprobarlo es eligiendo un modo y unirse al servicio. Si está iniciado se imprirán los valores del acelerómetro ( está así programado). 88 Pruebas y evaluación 4.4 Compatibilidad plataformas Android La aplicación se ha desarrollado para una versión de Android 4.1 (Jelly Bean). Teóricamente esta aplicación ADK puede ser cargada y ejecutada correctamente en cualquier dispositivo con una versión Android igual o superior. Para comprobarlo, se ha cargado la aplicación en el Smartphone BQ Aquaris 5.7, con una versión de Android superior, la 4.2. Efectivamente la aplicación se carga y ejecuta correctamente, hasta el momento en que se conecta al Arduino. La aplicación empieza a recibir datos y enseguida se bloquea. De esta experiencia se puede concluir que una aplicación, desarrollada con el ADK, y para una versión de Android en concreto, no es compatible con todos los dispositivos con versiones iguales o superiores. 89 Conclusiones y líneas futuras Capítulo 5 Conclusiones y líneas futuras En este capítulo, como autor del proyecto, expresaré mis conclusiones sobre el mismo, así como posibles mejoras que se podrían implementar en proyectos futuros. 5.1 Conclusiones Tras el desarrollo del proyecto se deben de sacar algunas conclusiones. La respuesta final del sistema está en consonancia con los objetivos marcados desde el principio, llevando a cabo todas las tareas planificadas para la consecución del mismo. El sistema es capaz de controlar el robot mediante dos modos de funcionamiento. Uno manual, en el que se puede mover el robot en cualquier dirección y con velocidades distintas (utilizando el acelerómetro del móvil), y otro que consiste en que el robot es capaz de seguir una línea oscura sobre un fondo claro. Otra funcionalidad que se ha añadido al robot es que sea capaz de pararse si choca contra un obstáculo y a su vez se active el vibrador del teléfono como modo de alarma. Además, el sistema puede leer los datos de los sensores de contacto, ultrasonidos e iluminación integrados en el robot, y mostrarlos por pantalla en la aplicación. Conclusions After the project it is necessary to explain the conclusions. The result is linked with the principle's objectives, thanks to tasks have been planned to get the aims. The system is able to control the robot with two modes. One is the manual mode; you can move the robot with the accelerometer of the phone. The other way consist on the robot is able to follow a dark line on a light background Also, it is reading data from the contact sensors, ultrasonic and light sensor, and it is be able to display them on screen in the application. 90 Conclusiones y líneas futuras 5.2 Mejoras futuras En este proyecto se podrían hacer algunas mejoras. Por un lado, que la aplicación funcionara correctamente con todas las versiones de Android. En teoría, y según las opciones que te da Eclipse para crear un proyecto nuevo, la aplicación debería funcionar a partir de la versión de Android 3.1 en adelante, cosa que no es así en la práctica. Una mejora sería hacer una aplicación que englobara todas las versiones, tanto las anteriores a la versión 3.1 como las posteriores. Añadir funcionalidades puede ser otro tema interesante. El teléfono móvil tiene, una unidad de procesamiento potente, varios sensores, una interfaz gráfica y varias posibilidades de conectividad. El caso es aumentar esas funcionalidades utilizando los elementos que tiene el teléfono. Como ejemplo, se podría dotar al robot de visión artificial. Consistiría en añadir una actividad que procesara las imágenes de la cámara del teléfono con el fin de detectar obstáculos o un objeto en concreto. Otro ejemplo es utilizar las comunicaciones disponibles en el teléfono. Se podría comunicar el dispositivo móvil incorporado en el robot con otro teléfono a través de Wifi o bluetooth. De esta manera el robot se controlaría de forma inalámbrica. Otra opción es contratar una tarifa de datos en el teléfono y conectarlo a Internet. De esta manera se puede controlar el robot desde prácticamente cualquier lugar del mundo. 91 Presupuesto Capítulo 6 Presupuesto En este capítulo, a la hora de calcular el presupuesto se tendrá en cuenta el coste del material utilizado y el tiempo empleado en las distintas fases del TFG. Fases/ Tareas. Coste personal 1. Fase de documentación I. II. III. IV. V. Estudio de cómo fucniona el ADK de Google, instalar software y lebrerías necesarias (10 h). Estudio del Arduino y del IDE de programación (15 h). Búsqueda de información y tutoriales de Arduino (30 h). Estudio de Android y de su entorno de programación Eclipse (20 h). Búsqueda de información y tutoriales de Android (30 h). 2. Fase de desarrollo del sistema propuesto I. II. III. IV. Elaboración y pruebas de programas básicos(20 h). Estudio del desarrollo de un servicio en Android (20 h). Desarrollo del software definitivo del Arduino y la aplicación en Android (60 h). Pruebas y correcciones del sistema(50 h). 3. Fase de elaboración de la memoria I. II. Redacción de la memoria(80 h). Corrección y maquetación(5 h). Fases Documentación Desarrollo del sistema propuesto Elaboración de la memoria TOTAL Horas 75 150 85 310 Tabla 23. Fases de la memoria 92 Presupuesto Estimando que el ingeniero encargado del desarrollo del proyecto gane 45 €/ h, el coste personal es el siguiente: PERSONAL COSTE(€/h) HORAS TRABAJADAS Ingeniero 45 310 13.950 TOTAL Tabla 24. Coste mano de obra Coste de materiales Todo el software desarrollado en el TFG es “open source”, no es necesario realizar el pago de ninguna licencia, y el alumnos disponía de un ordenador con “Microdoft office”. Software utilizado en el TFG Microsoft Office 2010 Arduino 1.0.5 Eclipse con herramientas SDK A continuación se muestra el coste del material que se ha empleado en el proyecto. COSTE DE MATERIAL Cantidad Coste unitario(€) 1 44 1 120 Descripción Arduino ADK Rev 3 Smartphone Huawei Ascend Y300 Coste total de material Importe total(€) 44.00 120 164 Tabla 25. Coste de material 93 Presupuesto Coste del proyecto RESUMEN PRESUPUESTO Descripción Importe total (€) 13.950 Coste personal 164 Coste de material 2.963,94 Impuestos (IVA 21 %) 17.080,94 Total presupuesto Tabla 26. Coste total “El presupuesto total del presente proyecto asciende a la cantidad de DIECISIETE MIL OCHENTA EUROS CON NOVENTA Y CUATRO CENTIMOS DE EURO” Leganés, 22 de septiembre de 2014 El ingeniero proyectista Fdo. Javier Aldana Corchón 94 Anexos Capítulo 7 Anexos 8.1 ANEXO I: Datasheet Arduino 95 Anexos 96 Anexos 8.2 ANEXO II: Códigos deArduino y Android Código de Arduino /////LIBRERÍAS////// #include <Wire.h> #include <Max3421e.h> #include <Usb.h> #include <AndroidAccessory.h> #include<Servo.h> //////VARIABLES////// #define LIGHT_SENSOR A1 #define SERVO1 3 #define SERVO2 2 #define BUTTON1 A4 #define BUTTON2 A5 Servo servos[2]; //sensor de ultrasonidos const int trigger = 8; const int echo = 7; const unsigned long timeOut = 5884;//Tiempo de espera máximo (para 100cm). Cálculo: timeOut = ((distancia máxima(cm)/0.017)+1 float distancia_centimetros; // 97 Anexos unsigned long duracion_microsegundos; byte b1,b2; //variables globales para los servos int posInDegrees_x; int posInDegrees_y; int rueda_der; int rueda_izq; //variables globales para los CNY70 int iriPin= 10; int irdPin= 11; int irderecho,irizquierdo; //uint16_t val,val2; //float value; boolean contact; AndroidAccessory acc("uPhyca", "HelloADK", "DemoKit Arduino Board", "1.0", "http://www.android.com", "0000000012345678"); void setup(); void loop(); 98 Anexos //////FUNCIONES IMPLEMENTADAS////// void init_buttons(){ pinMode(BUTTON1,INPUT); pinMode(BUTTON2,INPUT); //digitalWrite(BUTTON_1,HIGH); b1=digitalRead(BUTTON1); b2=digitalRead(BUTTON2); } void init_pins(){ pinMode(iriPin,INPUT); pinMode(irdPin,INPUT); } //////INICIALIZACIÓN////// void setup() { Serial.begin(115200); // 115200 bits por segundo Serial.print("\r\nStart"); servos[0].attach(SERVO1); servos[0].write(90); servos[1].attach(SERVO2); servos[1].write(90); contact=false; 99 Anexos pinMode(trigger,OUTPUT); pinMode(echo,INPUT); init_buttons(); init_pins(); acc.powerOn(); } //////RUTINA PRINCIPAL////// void loop() { byte msg[3]; static byte count = 0; byte b,c; if (acc.isConnected()) { uint16_t val,val2; float value; int len = acc.read(msg, sizeof(msg), 1); if (len > 0) { if(contact){ 100 Anexos servos[0].write(90); servos[1].write(90); } if(!contact ){ if(msg[0]==0x7){ if(msg[1]==0x1){ posInDegrees_x=((msg[2] & 0xFF) << 24) +((msg[3] & 0xFF) << 16) +((msg[4] & 0xFF) << 8) +((msg[5] & 0xFF)); rueda_der=map(posInDegrees_x,-100,100,78,102); rueda_izq=map(posInDegrees_x,-100,100,102,78); } if(msg[1]==0x2){ posInDegrees_y=((msg[2] & 0xFF) << 24) +((msg[3] & 0xFF) << 16) +((msg[4] & 0xFF) << 8) +((msg[5] & 0xFF)); posInDegrees_y=map(posInDegrees_y,-100,100,78,102); 101 Anexos } //así giro el robot hacia la derecha if(posInDegrees_y <= 80){ //paro rueda derecha rueda_der=78; //rueda izquierda al máximo rueda_izq=90; } //giro el robot hacia la izquierda if(posInDegrees_y >= 92){ //paro rueda izquierda rueda_izq= 102; //rueda derecha al máximo rueda_der=90; } servos[0].write(rueda_der); servos[1].write(rueda_izq); } if(msg[0]==0x1){ 102 Anexos irderecho=digitalRead(irdPin); irizquierdo=digitalRead(iriPin); if(irderecho==0 && irizquierdo==0){ rueda_der=78; rueda_izq=102; } if(irderecho==1 && irizquierdo==1){ rueda_der=90; rueda_izq=90; } if(irderecho==0 && irizquierdo==1){ rueda_der=90; rueda_izq=102; } if(irderecho==1 && irizquierdo==0){ rueda_der=78; rueda_izq=90; } servos[0].write(rueda_der); servos[1].write(rueda_izq); } } 103 Anexos contact=false; } b = digitalRead(BUTTON1); //Serial.println(b); if(b==0){ contact=true; } if (b != b1) { msg[0] = 0x6; msg[1] = b ? 0 : 1; acc.write(msg, 3); b1 = b; } c= digitalRead(BUTTON2); if(c==0){ contact=true; } if(c!=b2){ msg[0]=0x9; msg[1]=c ? 0: 1; 104 Anexos acc.write(msg,3); b2=c; } switch (count++ % 0x10) { case 0: val = analogRead(LIGHT_SENSOR); msg[0] = 0x5; msg[1] = val >> 8; msg[2] = val & 0xff; acc.write(msg, 3); break; case 0x4: //digitalWrite(trigger,LOW); //delayMicroseconds(3);//en principio estas dos lineas no hacen falta, pero las ponemos por seguridad digitalWrite(trigger,HIGH); delayMicroseconds(10);//tiempo de activación de disparo mínimo del trigger del HC-SR04 según fabricante digitalWrite(trigger,LOW); duracion_microsegundos = pulseIn(echo,HIGH,timeOut); value= conversion(duracion_microsegundos); //hago un cast, convierto value de float a uint16_t val2=( uint16_t) value; 105 Anexos //Serial.println(val2); msg[0]=0x7; msg[1]=val2>> 8; msg[2]=val2 & 0xff; acc.write(msg,3); break; } } else{ servos[0].write(90); servos[1].write(90); delay(5); } } /////IMPLEMENTACIÓN DE FUNCIONES////// float conversion(unsigned long duracion){ float distancia; distancia = duracion/58.2;// vel_sonido = 340 m/s = 0.034 cm/us --> dist(cm)=(t/2)*0.034=t*0.017 return distancia; } 106 Anexos Código de la aplicaión en Android Código fuente escrito en JAVA La clase MyService import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; public class MyService extends Service implements Runnable{ private static final String TAG = "HelloLED"; private static final String ACTION_USB_PERMISSION = "com.uphyca.android.app.helloled.action.USB_PERMISSION"; private PendingIntent mPermissionIntent; private boolean mPermissionRequestPending; private UsbManager mUsbManager; private UsbAccessory mAccessory; ParcelFileDescriptor mFileDescriptor; FileInputStream mInputStream; FileOutputStream mOutputStream; 107 Anexos private static boolean isRunning = false; private static final byte COMMAND_SERVO = 0x7; private static final byte SERVO_ID_1 = 0x1; private static final byte SERVO_ID_2=0x2; private static final byte COMMAND_CONTACT=0x3; private SensorManager sensorManager; private Sensor accelerometer; boolean servo=false; boolean siguelineas=false; byte contact; boolean crash=false; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent){ String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)){ synchronized (this){ UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)){ openAccessory(accessory); }else{ Log.d(TAG, "permission denied for accessory " + accessory); } mPermissionRequestPending = false; } }else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)){ UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (accessory != null && accessory.equals(mAccessory)){ closeAccessory(); } } } }; private int composeInt(byte hi, byte lo) { int val = (int) hi & 0xff; val *= 256; val += (int) lo & 0xff; return val; } ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients. 108 Anexos int mValue = 0; // Holds last value set by a client. static final int MSG_REGISTER_CLIENT = 1; static final int MSG_UNREGISTER_CLIENT = 2; static final int MSG_SET_BYTE_VALUE = 3; static final int MSG_SERVO_1=4; static final int MSG_SERVO_2=5; static final int MSG_LIGHT=6; static final int MSG_ULTRASONIC=7; static final int MSG_RIGHT_CONTACT=8; static final int MSG_LEFT_CONTACT=9; static final int MSG_REGISTER_CLIENT2=10; static final int MSG_UNREGISTER_CLIENT2=11; static final int MSG_CONTACT_VALUE=12; //6. Recibe el mensaje del client, y el mensaje lo manda al incomingHandler , para que haga // con el lo que le de la gana final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. // 4. Cuando presiono el botón "bind to the service, se manda una peticion a través de un intent a //esta función, onbin(). Esta devuelve una referencia a mMessenger y un dispath callback a la funcion //onServiceConnected() en el ServiceConnection para establecer la comunicacion a traves de un Ibinder // con el client que se conecte al Service. @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } //7.una vez que hemos recibido el mensaje del Client con esta clase decidimos qué hacemos con él. class IncomingHandler extends Handler { // Handler of incoming messages from clients. @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); servo=true; break; case MSG_REGISTER_CLIENT2: mClients.add(msg.replyTo); siguelineas=true; break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); servo=false; break; case MSG_UNREGISTER_CLIENT2: mClients.remove(msg.replyTo); siguelineas=false; break; 109 Anexos default: super.handleMessage(msg); } } } @Override public void onCreate() { super.onCreate(); Log.i("MyService", "Service Started."); mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); registerReceiver(mUsbReceiver, filter); sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //sendCommand(siguelineas); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("MyService", "Received start id " + startId + ": " + intent); sensorManager.registerListener(sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_GAME); //sendCommand(siguelineas); if (mInputStream != null && mOutputStream != null){ return -1 ; 110 Anexos } UsbAccessory[] accessories = mUsbManager.getAccessoryList(); UsbAccessory accessory = (accessories == null ? null : accessories[0]); if (accessory != null){ if (mUsbManager.hasPermission(accessory)){ openAccessory(accessory); }else{ synchronized (mUsbReceiver) { if (!mPermissionRequestPending){ mUsbManager.requestPermission(accessory, mPermissionIntent); mPermissionRequestPending = true; } } } }else{ Log.d(TAG, "mAccessory is null"); } //sendCommand(siguelineas); return START_STICKY; // run until explicitly stopped. } @Override public void onDestroy() { closeAccessory(); sensorManager.unregisterListener(sensorEventListener); unregisterReceiver(mUsbReceiver); super.onDestroy(); } private void openAccessory(UsbAccessory accessory){ mFileDescriptor = mUsbManager.openAccessory(accessory); if (mFileDescriptor != null){ mAccessory = accessory; FileDescriptor fd = mFileDescriptor.getFileDescriptor(); mInputStream = new FileInputStream(fd); mOutputStream = new FileOutputStream(fd); Thread thread = new Thread(null, this, "DemoKit"); thread.start(); Log.d(TAG, "accessory opened"); //enableControls(true); 111 Anexos }else{ Log.d(TAG, "accessory open fail"); } } private void closeAccessory(){ //enableControls(false); try{ if (mFileDescriptor != null){ mFileDescriptor.close(); } }catch (IOException e){ }finally{ mFileDescriptor = null; mAccessory = null; } } private static final int MESSAGE_LIGHT = 3; private static final int MESSAGE_ULTRASONIC = 4; private static final int MESSAGE_RIGHT_CONTACT=5; private static final int MESSAGE_LEFT_CONTACT=6; protected class LightMsg { private int light; public LightMsg(int light) { this.light = light; } public int getLight() { return light; } } protected class UltrasonicMsg{ private int ultrasonic; public UltrasonicMsg(int ultrasonic){ this.ultrasonic=ultrasonic; } public int getUltrasonic(){ return ultrasonic; } } protected class LeftContactMsg{ private byte value; public LeftContactMsg(byte value){ this.value = value; } public byte getValue(){ return value; 112 Anexos } } protected class RightContactMsg{ private byte value; public RightContactMsg(byte value){ this.value= value; } public byte getValue(){ return value; } } @Override public void run(){ int ret = 0; byte[] buffer = new byte[16384]; int i; while (ret >= 0){ try{ ret = mInputStream.read(buffer); }catch(IOException e){ break; } i = 0; while (i < ret){ int len = ret - i; switch (buffer[i]){ case 0x5: if (len >= 3) { Message m = Message.obtain(mHandler, MESSAGE_LIGHT); m.obj = new LightMsg(composeInt(buffer[i + 1], buffer[i + 2])); mHandler.sendMessage(m); } i += 3; break; case 0x7: if(len >= 3){ Message m=Message.obtain(mHandler, MESSAGE_ULTRASONIC); m.obj = new UltrasonicMsg(composeInt(buffer[i + 1], 113 Anexos buffer[i + 2])); mHandler.sendMessage(m); } i += 3; break; case 0x8: if(len >= 3){ Message m=Message.obtain(mHandler, MESSAGE_LEFT_CONTACT); m.obj = new LeftContactMsg(buffer[i +1]); mHandler.sendMessage(m); } i += 3; break; case 0x6: if(len >= 3){ Message m=Message.obtain(mHandler, MESSAGE_RIGHT_CONTACT); m.obj = new RightContactMsg(buffer[i + 1]); mHandler.sendMessage(m); } i += 3; break; case 0x9: if(len >= 3){ Message m=Message.obtain(mHandler, MESSAGE_LEFT_CONTACT); m.obj = new LeftContactMsg(buffer[i + 1]); mHandler.sendMessage(m); } i += 3; break; default: Log.d(TAG, "unknown msg: " + buffer[i]); i = len; break; } } } } private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg){ switch (msg.what){ case MESSAGE_LIGHT: 114 Anexos LightMsg l = (LightMsg) msg.obj; //handleLightMessage(MSG_LIGHT,l.light); handleLightMessage(MSG_LIGHT,l.getLight()); break; case MESSAGE_ULTRASONIC: UltrasonicMsg u = (UltrasonicMsg) msg.obj; //handleLightMessage(MSG_LIGHT,l.light); handleUltrasonicMessage(MSG_ULTRASONIC,u.getUltrasonic()); break; case MESSAGE_LEFT_CONTACT: LeftContactMsg left = (LeftContactMsg) msg.obj; handleContactMessage(MSG_LEFT_CONTACT,left.getValue()); break; case MESSAGE_RIGHT_CONTACT: RightContactMsg right = (RightContactMsg) msg.obj; handleContactMessage(MSG_RIGHT_CONTACT,right.getValue()); break; } } }; private void handleLightMessage(int ID,int value){ for (int i=mClients.size()-1; i>=0; i--) { try { // Send data as an Integer mClients.get(i).send(Message.obtain(null, ID, value, 0)); } catch (RemoteException e) { // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop. mClients.remove(i); } } } private void handleUltrasonicMessage(int ID,int value){ for (int i=mClients.size()-1; i>=0; i--) { try { // Send data as an Integer mClients.get(i).send(Message.obtain(null, ID, value, 0)); 115 Anexos } catch (RemoteException e) { // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop. mClients.remove(i); } } } private void handleContactMessage(int ID, byte value){ for(int i=mClients.size()-1; i>=0; i--){ try{ //send data as a byte Bundle b= new Bundle(); b.putByte("b1", value); Message msg=Message.obtain(null, ID); msg.setData(b); mClients.get(i).send(msg); }catch (RemoteException e){ mClients.remove(i); } } } public static boolean isRunning() { return isRunning; } private final SensorEventListener sensorEventListener = new SensorEventListener(){ int x_acceleration; int y_acceleration; @Override public void onAccuracyChanged(Sensor sensor, int accuracy){ } @Override public void onSensorChanged(SensorEvent event){ x_acceleration = (int)(-event.values[0] * 10); y_acceleration=(int)(-event.values[1]*10); //mandar el mensaje al arduino del valor del servo moveServoCommand(SERVO_ID_1, x_acceleration); moveServoCommand(SERVO_ID_2, y_acceleration); 116 Anexos //sendCommand(siguelineas); //aqi hay q poner el codigo para mandar los valores a la actividad handleMessageServo(MSG_SERVO_1,x_acceleration); handleMessageServo(MSG_SERVO_2,y_acceleration); } }; public void moveServoCommand(byte target, int value){ byte[] buffer = new byte[6]; if(servo){ buffer[0] = COMMAND_SERVO; }else if(siguelineas){ buffer[0]=0x1; } buffer[1] = target; buffer[2] = (byte) (value >> 24); buffer[3] = (byte) (value >> 16); buffer[4] = (byte) (value >> 8); buffer[5] = (byte) value; if (mOutputStream != null){ try{ mOutputStream.write(buffer); }catch(IOException e){ Log.e(TAG, "write failed", e); } } } private void handleMessageServo(int ID,int value_servo){ for (int i=mClients.size()-1; i>=0; i--) { try { // Send data as an Integer mClients.get(i).send(Message.obtain(null, ID, value_servo, 0)); } catch (RemoteException e) { // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop. mClients.remove(i); } } } 117 Anexos } La clase MainActivity import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { Button btnStart, btnStop, btnManual, btnLine; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //reconocimiento de los botones con el xml btnStart = (Button)findViewById(R.id.start_service); btnStop=(Button)findViewById(R.id.stop_service); btnManual=(Button)findViewById(R.id.manual_mode); btnLine=(Button)findViewById(R.id.line_mode); //Invoco a los callbacks de los botones btnStart.setOnClickListener(btnStartListener); btnStop.setOnClickListener(btnStopListener); btnManual.setOnClickListener(btnManualListener); btnLine.setOnClickListener(btnLineListener); } private OnClickListener btnStartListener = new OnClickListener() { public void onClick(View v){ startService(new Intent(MainActivity.this, MyService.class)); } }; private OnClickListener btnStopListener = new OnClickListener() { public void onClick(View v){ stopService(new Intent(MainActivity.this, MyService.class)); } }; private OnClickListener btnManualListener= new OnClickListener(){ public void onClick(View v){ 118 Anexos //startActivity(new Intent(MainActivity.this, ManualActivity.class)); startActivity(new Intent(MainActivity.this, LineActivity.class)); } }; private OnClickListener btnLineListener= new OnClickListener(){ public void onClick(View v){ //startActivity(new Intent(MainActivity.this, LineActivity.class)); startActivity(new Intent(MainActivity.this, ManualActivity.class)); } }; @Override public void onDestroy(){ //stopService(new Intent(MainActivity.this, MyService.class)); super.onDestroy(); } } La clase ManualActivity import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.Vibrator; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class ManualActivity extends Activity { Button btnBind, btnUnbind; TextView textRightContact, textLeftContact, textLight, textUltrasonic, textServo_x, textServo_y; Messenger mService = null; boolean mIsBound; 119 Anexos private Vibrator vibrator; private boolean isVibrating=false; //lo utilizo para comunicarme con el Service. Aqui recibo lo que el service me manda. final Messenger mMessenger = new Messenger(new IncomingHandler()); class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyService.MSG_LIGHT: //String light_value=Integer.toString(msg.getData().getInt("int1")); textLight.setText("Iluminación: "+ msg.arg1); break; case MyService.MSG_ULTRASONIC: textUltrasonic.setText("ultrasonidos: " + msg.arg1); break; case MyService.MSG_SERVO_1: textServo_x.setText("Eje x : " + msg.arg1); break; case MyService.MSG_SERVO_2: textServo_y.setText("Eje y : " + msg.arg1); break; case MyService.MSG_LEFT_CONTACT: ContactMsg LeftContact=new ContactMsg( msg.getData().getByte("b1")); textLeftContact.setText(LeftContact.isPressed()); LeftContact.isVibrate(); //sendMessageToService(LeftContact.value); break; case MyService.MSG_RIGHT_CONTACT: //byte RightContactValue=msg.getData().getByte("b1"); ContactMsg RightContact= new ContactMsg(msg.getData().getByte("b1")); textRightContact.setText(RightContact.isPressed()); RightContact.isVibrate(); //sendMessageToService(RightContact.value); break; default: super.handleMessage(msg); } } } private ServiceConnection mConnection = new ServiceConnection() { //5. Crea un Messenger y despues se lo asigna a un messenger para que lo envie al service 120 Anexos public void onServiceConnected(ComponentName className, IBinder service) { // mService es de tipo Messenger, para mandar mensajes al servicio mService = new Messenger(service); // textStatus.setText("Attached."); try { Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; //aqui mando el mensaje al Service. el mMessenger del servicio recibirá este mensaje mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even do anything with it } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been unexpectedly disconnected process crashed. mService = null; //textStatus.setText("Disconnected."); } }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_manual); btnBind=(Button)findViewById(R.id.btnBind); btnUnbind=(Button)findViewById(R.id.btnUnbind); textRightContact=(TextView)findViewById(R.id.right_contact); textLeftContact=(TextView)findViewById(R.id.left_contact); textLight=(TextView)findViewById(R.id.light_text); textUltrasonic=(TextView)findViewById(R.id.ultrasonic_text); textServo_x=(TextView)findViewById(R.id.x_text); textServo_y=(TextView)findViewById(R.id.y_text); vibrator = ((Vibrator) getSystemService(VIBRATOR_SERVICE)); // 3. Llamo a la funcion setOnclickListener() y le paso como referencia la función del paso 2. btnBind.setOnClickListener(btnBindListener); btnUnbind.setOnClickListener(btnUnbindListener); CheckIfServiceIsRunning(); } private void CheckIfServiceIsRunning() { //If the service is running when the activity starts, we want to automatically bind to it. if (MyService.isRunning()) { doBindService(); } } 121 Anexos // 1. este callback se ejecuta cuando presiono el boton "bind to the Service". esta funcion la llamaré // en onCreate(). private OnClickListener btnBindListener = new OnClickListener() { public void onClick(View v){ doBindService(); } }; private OnClickListener btnUnbindListener = new OnClickListener() { public void onClick(View v){ doUnbindService(); } }; // 2. esta funcion la utilizo para unirme al servicio. Además pongo una variable a "true" void doBindService() { bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; //textStatus.setText("Binding."); } void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with it, then now is the time to unregister. if (mService != null) { try { Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service has crashed. } } // Detach our existing connection. unbindService(mConnection); mIsBound = false; //textStatus.setText("Unbinding."); } } /* private void sendMessageToService(byte value) { if (mIsBound) { if (mService != null) { try { Bundle b = new Bundle(); b.putByte("b1",value); Message msg = Message.obtain(null,MyService.MSG_CONTACT_VALUE) ; msg.setData(b); //mClients.get(i).send(msg); //Message msg = Message.obtain(null, MyService.MSG_CONTACT_VALUE, value, 0); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { } } } } */ 122 Anexos @Override protected void onDestroy() { super.onDestroy(); try { doUnbindService(); stopVibrate(); } catch (Throwable t) { Log.e("MainActivity", "Failed to unbind from the service", t); } } protected class ContactMsg{ private byte value; String pressed="choque"; String not_pressed="No hay contacto"; public ContactMsg(byte value){ this.value = value; } public String isPressed(){ if(value == 1){ return pressed; }else{ return not_pressed; } } public void isVibrate(){ if(value == 1){ startVibrate(); }else{ stopVibrate(); } } } /* protected class LeftContactMsg{ private byte value; String pressed="choque"; String not_pressed="No hay contacto"; public LeftContactMsg(byte value){ this.value = value; } public String isPressed(){ if(value == 1){ return pressed; }else{ return not_pressed; } } public void isVibrate(){ if(value == 1){ startVibrate(); }else{ 123 Anexos stopVibrate(); } } } */ public void stopVibrate(){ if(vibrator!=null && isVibrating){ isVibrating=false; vibrator.cancel(); } } public void startVibrate(){ if(vibrator!=null && !isVibrating){ isVibrating=true; vibrator.vibrate(new long[]{0,100,250},0); } } } La clase LineActivity import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.Vibrator; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class LineActivity extends Activity { Button btnBind, btnUnbind; TextView textRightContact, textLeftContact, textLight, textUltrasonic, textServo_x, textServo_y; Messenger mService = null; boolean mIsBound; private Vibrator vibrator; private boolean isVibrating=false; 124 Anexos //lo utilizo para comunicarme con el Service. Aqui recibo lo que el service me manda. final Messenger mMessenger = new Messenger(new IncomingHandler()); class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MyService.MSG_LIGHT: //String light_value=Integer.toString(msg.getData().getInt("int1")); textLight.setText("Iluminación: "+ msg.arg1); break; case MyService.MSG_ULTRASONIC: textUltrasonic.setText("ultrasonidos: " + msg.arg1); break; case MyService.MSG_SERVO_1: textServo_x.setText("Eje x : " + msg.arg1); break; case MyService.MSG_SERVO_2: textServo_y.setText("Eje y : " + msg.arg1); break; case MyService.MSG_LEFT_CONTACT: LeftContactMsg LeftContact=new LeftContactMsg( msg.getData().getByte("b1")); textLeftContact.setText(LeftContact.isPressed()); LeftContact.isVibrate(); break; case MyService.MSG_RIGHT_CONTACT: //byte RightContactValue=msg.getData().getByte("b1"); RightContactMsg RightContact= new RightContactMsg(msg.getData().getByte("b1")); textRightContact.setText(RightContact.isPressed()); RightContact.isVibrate(); break; default: super.handleMessage(msg); } } } private ServiceConnection mConnection = new ServiceConnection() { //5. Crea un Messenger y despues se lo asigna a un messenger para que lo envie al service public void onServiceConnected(ComponentName className, IBinder service) { // mService es de tipo Messenger, para mandar mensajes al servicio mService = new Messenger(service); // textStatus.setText("Attached."); try { 125 Anexos Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT2); msg.replyTo = mMessenger; //aqui mando el mensaje al Service. el mMessenger del servicio recibirá este mensaje mService.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even do anything with it } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been unexpectedly disconnected process crashed. mService = null; //textStatus.setText("Disconnected."); } }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_line); btnBind=(Button)findViewById(R.id.btnBind); btnUnbind=(Button)findViewById(R.id.btnUnbind); textRightContact=(TextView)findViewById(R.id.right_contact); textLeftContact=(TextView)findViewById(R.id.left_contact); textLight=(TextView)findViewById(R.id.light_text); textUltrasonic=(TextView)findViewById(R.id.ultrasonic_text); textServo_x=(TextView)findViewById(R.id.x_text); textServo_y=(TextView)findViewById(R.id.y_text); vibrator = ((Vibrator) getSystemService(VIBRATOR_SERVICE)); // 3. Llamo a la funcion setOnclickListener() y le paso como referencia la función del paso 2. btnBind.setOnClickListener(btnBindListener); btnUnbind.setOnClickListener(btnUnbindListener); CheckIfServiceIsRunning(); } private void CheckIfServiceIsRunning() { //If the service is running when the activity starts, we want to automatically bind to it. if (MyService.isRunning()) { doBindService(); } } // 1. este callback se ejecuta cuando presiono el boton "bind to the Service". esta funcion la llamaré // en onCreate(). private OnClickListener btnBindListener = new OnClickListener() { public void onClick(View v){ doBindService(); } }; 126 Anexos private OnClickListener btnUnbindListener = new OnClickListener() { public void onClick(View v){ doUnbindService(); } }; // 2. esta funcion la utilizo para unirme al servicio. Además pongo una variable a "true" void doBindService() { bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; //textStatus.setText("Binding."); } void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with it, then now is the time to unregister. if (mService != null) { try { Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT2); msg.replyTo = mMessenger; mService.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service has crashed. } } // Detach our existing connection. unbindService(mConnection); mIsBound = false; //textStatus.setText("Unbinding."); } } @Override protected void onDestroy() { super.onDestroy(); try { doUnbindService(); stopVibrate(); } catch (Throwable t) { Log.e("MainActivity", "Failed to unbind from the service", t); } } protected class RightContactMsg{ private byte value; String pressed="choque"; String not_pressed="no hay contacto"; public RightContactMsg(byte value){ this.value = value; } public String isPressed(){ if(value == 1){ return pressed; }else{ return not_pressed; } } public void isVibrate(){ 127 Anexos if(value == 1){ startVibrate(); }else{ stopVibrate(); } } } protected class LeftContactMsg{ private byte value; String pressed="Hay contacto"; String not_pressed="No hay contacto"; public LeftContactMsg(byte value){ this.value = value; } public String isPressed(){ if(value == 1){ return pressed; }else{ return not_pressed; } } public void isVibrate(){ if(value == 1){ startVibrate(); }else{ stopVibrate(); } } } public void stopVibrate(){ if(vibrator!=null && isVibrating){ isVibrating=false; vibrator.cancel(); } } public void startVibrate(){ if(vibrator!=null && !isVibrating){ isVibrating=true; vibrator.vibrate(new long[]{0,100,250},0); } } } Archivos.xml de la parte gráfica de las actividades 128 Anexos Activity_line.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btnBind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:text="Bind to Service" /> <Button android:id="@+id/btnUnbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_below="@+id/btnBind" android:layout_marginTop="30dp" android:text="Unbind from Service" /> <TextView android:id="@+id/left_contact" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/btnUnbind" android:layout_marginTop="56dp" android:text="left" /> <TextView android:id="@+id/light_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="light" /> <TextView android:id="@+id/ultrasonic_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/light_text" android:layout_centerHorizontal="true" android:layout_marginTop="46dp" android:text="ultrasonic" /> <TextView 129 Anexos android:id="@+id/x_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/y_text" android:layout_alignBottom="@+id/y_text" android:layout_alignParentLeft="true" android:text="eje x" /> <TextView android:id="@+id/y_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="42dp" android:layout_toLeftOf="@+id/right_contact" android:text="eje y" /> <TextView android:id="@+id/right_contact" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/left_contact" android:layout_alignBottom="@+id/left_contact" android:layout_alignParentRight="true" android:layout_marginRight="26dp" android:text="right" /> </RelativeLayout> Activity_manual.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btnBind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:text="Bind to Service" /> <Button android:id="@+id/btnUnbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" 130 Anexos android:layout_alignParentRight="true" android:layout_below="@+id/btnBind" android:layout_marginTop="30dp" android:text="Unbind from Service" /> <TextView android:id="@+id/left_contact" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/btnUnbind" android:layout_marginTop="56dp" android:text="left" /> <TextView android:id="@+id/light_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="light" /> <TextView android:id="@+id/ultrasonic_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/light_text" android:layout_centerHorizontal="true" android:layout_marginTop="46dp" android:text="ultrasonic" /> <TextView android:id="@+id/x_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/y_text" android:layout_alignBottom="@+id/y_text" android:layout_alignParentLeft="true" android:text="eje x" /> <TextView android:id="@+id/y_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="42dp" android:layout_toLeftOf="@+id/right_contact" android:text="eje y" /> <TextView android:id="@+id/right_contact" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/left_contact" android:layout_alignBottom="@+id/left_contact" android:layout_alignParentRight="true" android:layout_marginRight="26dp" android:text="right" /> 131 Anexos </RelativeLayout> Activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="fill_parent" android:gravity="top" > <Button android:id="@+id/start_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginTop="31dp" android:text="start Service" /> <Button android:id="@+id/stop_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/start_service" android:layout_marginTop="48dp" android:text="Stop Service" /> <Button android:id="@+id/line_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:text="Modo manual" /> <Button android:id="@+id/manual_mode" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/line_mode" android:layout_marginTop="60dp" android:text="Modo siguelíneas" /> </RelativeLayout> AndroidManifiest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.adk_app" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="12" 132 Anexos android:targetSdkVersion="16" /> <uses-feature android:name="android.hardware.usb.accessory" /> <uses-feature android:name="android.hardware.sensor.accelerometrer"/> <uses-permission android:name="android.permission.VIBRATE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> <service android:name="com.example.adk_app.MyService"> </service> <activity android:name="com.example.adk_app.ManualActivity" android:screenOrientation="portrait"> </activity> <activity android:name="com.example.adk_app.LineActivity" android:screenOrientation="portrait"> </activity> </application> </manifest> 133 Bibliografía Capítulo 8 Bibliografía [1] Javier García Galón. “Aprenda JAVA como si estuviera en primero”. Tecnun. Campus tecnológico de la universidad de Navarra. Enero 2000. [2] Mario Bohmer. “Begining Android ADK with Arduino”. Technology in Action. [3] Wikipedia. http://es.wikipedia.org/wiki/Rob%C3%B3tica. [4] Arduino official website. http://www.arduino.cc/. [5] Foro Arduino. http://forum.arduino.cc/. [6] Android developers official Website. http://developer.android.com/index.html. [7] Foro de programación. http://stackoverflow.com/. [8] Sitio Web donde se aloja código. https://github.com/. [9] Documentación sobre el ADK. http://www.elecfreaks.com/wiki/index.php?title=ADK. [10] Arduteka. http://www.arduteka.com/. [11] Documentación sobre un BoundService. http://www.javacodegeeks.com/. [12] Tutorial sobre Bound Services utilizano Messenger. https://www.coursera.org/courses?search=android. 134 Bibliografía [13] Tutorial sobre Bound Services. http://developer.xamarin.com/guides/android/application_fundamentals/s ervices/part_2_-_bound_services/ [14] Drivers del SmartPhone Huawei Ascend Y300. http://singledrivers.blogspot.com.es/2014/01/huawei-ascend-y300-usbdriver-for.html. [15] Tutoriales de Android. http://www.vogella.com/tutorials/android.html. [16] Tutorial sobre Bound Services. http://www.techotopia.com/index.php/Android_Local_Bound_Services_ %E2%80%93_A_Worked_Example#Understanding_Bound_Services [17] Tutorial sobre Servicios en Android. http://androideity.com/2011/11/08/creando-un-servicio-propio-enandroid/. [18] Web para descargar libros de Arduino. http://ebookbrowsee.net/an/android-arduino#.VB9_H_l_vX5. [19] Código de Demokit, aplicación de Google. https://code.google.com/p/android-sourcebrowsing/source/browse/?repo=device--google--accessory-demokit&name=jb-mr1.1-dev#git%2Fapp [20] Tutorial sobre el sensor CNY70. http://www.comohacerturobot.com/Taller/taller-sensorOptico.htm [21] Jorge Agudo Martín. “Cronotermostato inteligente con transmisión vía radio”. TFG. Septiembre 2013. 135
© Copyright 2024