Proyecto Fin de Carrera Ingeniería Informática Control de Tiempo Real estricto en un robot móvil basado en MaRTE OS Francisco Javier Feijoo Cano Director: José Luis Villarroel Salcedo Departamento de Informática e Ingeniería de Sistemas Centro Politécnico Superior Universidad de Zaragoza Diciembre 2007 Mi agradecimiento a la gente del laboratorio de robótica que han hecho posible la realización del presente trabajo en especial a Danilo Tardioli, porque con sus conocimientos y su colaboración, me ayudó a seguir hacia delante en los momentos más difíciles. Agradecer también la desinteresada colaboración de Daniel Sangorrin, que desde la Universidad de Cantabria me prestó su ayuda y su tiempo en diferentes partes del proyecto. Índice general Índice de guras 9 Índice de cuadros 10 1. Introducción 11 1.1. Objetivo y alcance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2. Contexto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.3. Diferentes objetivos de los sistemas operativos . . . . . . . . . . . . . . . . 12 1.3.1. Sistema operativo de propósito general . . . . . . . . . . . . . . . . 12 1.3.2. Sistema operativo de tiempo real . . . . . . . . . . . . . . . . . . . 13 1.3.3. Elección del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.4. Necesidad de control temporal en un robot móvil . . . . . . . . . . . . . . 14 1.5. Estructura de la memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2. El sistema operativo MaRTE OS 16 2.1. Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.2. Trabajando con MaRTE OS . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3. El robot móvil Pioneer 3.1. 3.2. 20 Arquitectura del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.1.1. Sensores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.1.2. Actuadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.1.3. Mecanismo de comunicación . . . . . . . . . . . . . . . . . . . . . . 22 Método de trabajo actual con el robot . . . . . . . . . . . . . . . . . . . . 4. Integración de los sensores en MaRTE 22 24 4.1. Análisis general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 4.2. Diseño arquitectural 24 4.3. 4.4. 4.5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 4.3.1. Microcontrolador y P2OS Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 4.3.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.4.1. Láser SICK LMS Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.4.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Comunicación inalámbrica . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 30 4.6. 4.7. 4.5.1. Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.5.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 GPS Novatel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.6.1. Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.6.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Implementación y pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. Caracterización temporal completa del sistema 33 34 5.1. Medir el tiempo de cómputo en MaRTE . . . . . . . . . . . . . . . . . . . 34 5.2. Dependencia de la línea serie . . . . . . . . . . . . . . . . . . . . . . . . . . 35 6. Pruebas realizadas y resultados 6.1. 37 Navegación autónoma y tiempo real estricto 6.1.1. . . . . . . . . . . . . . . . . . 37 Esquema de tareas y cumplimiento de plazos . . . . . . . . . . . . . 38 6.2. Comunicaciones en tiempo real . . . . . . . . . . . . . . . . . . . . . . . . 41 6.3. Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 7. Conclusiones y trabajos futuros 44 7.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 7.2. Dicultades encontradas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 7.3. Trabajos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Bibliografía 46 A. Fases del proyecto y diagrama de Gantt 48 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 A.2. Diagrama de Gantt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 A.1. Hitos temporales B. Estudio sobre sistemas operativos de tiempo real 50 B.1. Arquitectura de un SO de tiempo real . . . . . . . . . . . . . . . . . . . . . B.1.1. Arquitectura de un SO de propósito general 50 . . . . . . . . . . . . . 50 B.1.2. Clases de tiempo real . . . . . . . . . . . . . . . . . . . . . . . . . . 51 B.1.3. Características de rendimiento . . . . . . . . . . . . . . . . . . . . . 51 B.1.4. Arquitectura de un SO de tiempo real . . . . . . . . . . . . . . . . 52 . . . . . . . . . . . . . . . . . . . . . . . . 55 B.1.5. Rendimiento del sistema B.2. Algunos de los SO de tiempo real más usados . . . . . . . . . . . . . . . . 55 B.2.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 B.2.2. ADEOS (Adaptative Domain Environment Operating Systems ) . . . 56 B.2.3. RTLinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 B.2.4. MaRTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 B.2.5. VxWorks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 C. P2OS: El Sistema Operativo del microcontrolador. C.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.1.1. Especicaciones técnicas . . . . . . . . . . . . . . . . . . . . . . . . C.2. El Sistema Operativo del robot. P2OS . . . . . . . . . . . . . . . . . . . . 64 64 64 65 ÍNDICE GENERAL 7 C.2.1. Conexión Cliente-Servidor . . . . . . . . . . . . . . . . . . . . . . . 65 C.2.2. Comandos de movimiento . . . . . . . . . . . . . . . . . . . . . . . 66 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 C.2.4. Emergencias y paradas . . . . . . . . . . . . . . . . . . . . . . . . . 67 C.2.3. Sonar D. El láser SICK LMS 68 D.1. Información básica sobre el láser . . . . . . . . . . . . . . . . . . . . . . . . 68 D.2. Software. Mecanismo de comunicación . . . . . . . . . . . . . . . . . . . . 69 D.2.1. Esquema de funcionamiento para la comunicación con LMS . . . . . 69 D.2.2. Establecer la comunicación con LMS . . . . . . . . . . . . . . . . . 69 D.2.3. Valores por defecto del LMS . . . . . . . . . . . . . . . . . . . . . . 70 D.2.4. Cambiar la velocidad de transmisión . . . . . . . . . . . . . . . . . 70 . . . . . . . . . . . . . . . . . . . . 71 D.2.5. Cambiar la resolución del LMS D.2.6. Cambiar la unidad de medida en LMS . . . . . . . . . . . . . . . . D.2.7. Empezar con la salida continua de datos desde el LMS 72 . . . . . . . 72 D.2.8. Interpretación de los datos recibidos . . . . . . . . . . . . . . . . . . 73 D.2.9. Detención de la salida continua de datos . . . . . . . . . . . . . . . 74 D.2.10. Formato de la cadena de datos de salida . . . . . . . . . . . . . . . 74 D.2.11. Información del byte de estado (status byte) . . . . . . . . . . . . . 75 E. Trabajando con MaRTE OS 76 E.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 E.2. Creación de nuevos drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 E.3. Arrancar en red con MaRTE OS y el robot . . . . . . . . . . . . . . . . . . 77 E.3.1. Elementos hardware . . . . . . . . . . . . . . . . . . . . . . . . . . 77 E.3.2. Elementos software . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 E.3.3. Conguración del servidor . . . . . . . . . . . . . . . . . . . . . . . 77 E.3.4. Conguración del host . . . . . . . . . . . . . . . . . . . . . . . . . 79 E.3.5. Método de trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 F. Manual de usuario y API F.1. Manual de usuario 80 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . F.2. Funciones en lenguaje C 80 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 F.2.1. P2OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 F.2.2. Láser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 F.2.3. GPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 F.2.4. Comunicación inalámbrica . . . . . . . . . . . . . . . . . . . . . . . 85 F.3. Funciones en lenguaje Ada . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 F.3.1. P2OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 F.3.2. Láser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 F.3.3. GPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 F.3.4. Comunicación inalámbrica . . . . . . . . . . . . . . . . . . . . . . . 88 F.4. Consideración nal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 G. Interfaz de programación entre Ada y C 89 G.1. Visibilidad global de los datos . . . . . . . . . . . . . . . . . . . . . . . . . 90 G.2. Visibilidad global de funciones . . . . . . . . . . . . . . . . . . . . . . . . . 93 G.3. Ejecución del programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 G.3.1. Inicialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 G.3.2. Captura de excepciones . . . . . . . . . . . . . . . . . . . . . . . . . 94 G.4. Interfaz de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Índice de guras 2.1. Arquitectura de MaRTE OS para aplicaciones ADA y C 2.2. Entorno de desarrollo del proyecto. . . . . . . . . . . 18 . . . . . . . . . . . . . . . . . . . . . . 19 3.1. Robot Pioneer 3-AT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2. Los dispositivos más importantes del robot y sus conexiones. . . . . . . . . 21 4.1. Diseño del driver P2OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.2. Esquema de funcionamiento del puerto serie. . . . . . . . . . . . . . . . . . 29 4.3. Doble búfer del láser para minimizar bloqueos. . . . . . . . . . . . . . . . . 30 5.1. Medición del tiempo de cómputo de una función en MaRTE para C y Ada respectivamente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 5.2. Ejemplo de tareas con tiempos en MaRTE. . . . . . . . . . . . . . . . . . . 36 6.1. Algoritmo de navegación adaptado a MaRTE. . . . . . . . . . . . . . . . . 37 6.2. Esquema de las tareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 6.3. Navegación del robot a través de comunicación inalámbrica y control. . . . 42 A.1. Diagrama de Gantt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 D.1. Principio de medida y rango angular de LMS . . . . . . . . . . . . . . . . . 68 D.2. Resumen del funcionamiento de las comunicaciones con LMS . . . . . . . . 69 D.3. Esquema de la inicialización del LMS . . . . . . . . . . . . . . . . . . . . . 70 D.4. Barrido láser en el modo 0 ..180 . . . . . . . . . . . . . . . . . . 71 D.5. Operaciones en la ejecución de un programa con LMS . . . . . . . . . . . . 73 F.1. Funciones para manejar el P20S en C . . . . . . . . . . . . . . . . . . . . . 83 F.2. Funciones para manejar el Láser en C . . . . . . . . . . . . . . . . . . . . . 84 F.3. Funciones para manejar el GPS en C 84 o o y 0..100 o . . . . . . . . . . . . . . . . . . . . . F.4. Funciones para manejar el P20S en Ada . . . . . . . . . . . . . . . . . . . 86 F.5. Funciones para manejar el Láser en Ada . . . . . . . . . . . . . . . . . . . 87 F.6. Funciones para manejar el GPS en Ada . . . . . . . . . . . . . . . . . . . . 87 9 Índice de cuadros 4.1. Opciones de conguración del láser . . . . . . . . . . . . . . . . . . . . . . 28 5.1. Interrupciones generadas por la línea serie. . . . . . . . . . . . . . . . . . . 35 6.1. Información sobre las tareas. . . . . . . . . . . . . . . . . . . . . . . . . . . 39 6.2. Resultados obtenidos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 10 Capítulo 1 Introducción 1.1. Objetivo y alcance El objetivo principal de este proyecto es la implantación del sistema operativo (SO) de tiempo real estricto MaRTE OS en un robot móvil Pioneer 3-AT. Se crearán los controladores (drivers ) de algunos dispositivos del robot. Entre ellos el microcontrolador, el láser, el sistema de comunicación inalámbrico y el GPS. Además se proporcionarán las herramientas necesarias para continuar investigando y poder realizar aplicaciones en este nuevo sistema. MaRTE OS (Minimal Real Time Operating System for Embedded Applications ) [1] es un SO para aplicaciones empotradas basado en un subconjunto del estándar POSIX.13 para tiempo real. Está escrito principalmente en Ada y actualmente está siendo desarrollado en la Universidad de Cantabria. Es totalmente necesario añadir al control de los robots restricciones de tiempo real. Una mala gestión del procesador por parte del SO puede provocar diversos problemas de control en el robot. Con el SO MaRTE pueden realizarse aplicaciones ables bajo un entorno determinista que asegura una planicación correcta de las tareas que componen la aplicación. Para poder realizar comunicaciones en tiempo real se estudiará y portará a MaRTE el protocolo RT-WMP que actualmente se desarrolla en la Universidad de Zaragoza. RT-WMP (Real Time Wireless Multi-hop Protocol ) [7] es un protocolo de comunicación basado en paso de testigo, con la característica principal de soportar transmisiones en tiempo real. Se demostrará el correcto funcionamiento de las herramientas desarrolladas con diferentes aplicaciones y se evaluarán los resultados obtenidos. Además se deberá realizar una caracterización temporal completa del conjunto de funciones disponibles para cada dispositivo. Como valor añadido del proyecto, se han establecido las bases para trabajar con un SO de tiempo real de libre distribución que es capaz de funcionar en diferentes arquitecturas. Esto permite el estudio de diferentes técnicas y protocolos basados en tiempo real que hasta ahora eran difíciles o imposibles de realizar. 11 1.2. Contexto El proyecto se ha llevado a cabo en el grupo de Robótica, Percepción y Tiempo Real del Departamento de Informática e Ingeniería de Sistemas (DIIS). El departamento posee 4 robots móviles Pioneer de la casa constructora ActiveMedia. Hasta ahora los robots sólo tenían instalado un SO Linux de propósito general. Para poder interaccionar con los dispositivos del robot (odometría, láser, GPS, comunicaciones, etc) se trabaja a través de una plataforma cliente/servidor llamada Player/Stage de libre distribución que se ejecuta sobre este SO. Una aplicación que se ejecuta en un SO de estas características no puede controlar qué tarea entra a ocupar el procesador en cada instante haciendo imposible garantizar el cumplimiento de restricciones temporales. La forma de ejecución de las tareas que componen la aplicación no las determina el usuario, sino el SO que tiene otros objetivos diferentes a los de tiempo real. No se garantiza una correcta planicación de las tareas que se ejecutan en el robot, pudiendo provocar comportamientos no especicados en el sistema. 1.3. Diferentes objetivos de los sistemas operativos Los SO proporcionan una plataforma de software encima de la cual otros programas, llamados aplicaciones, puedan funcionar. Las aplicaciones se programan para que funcionen encima de un SO particular, por tanto, la elección del SO determina en gran medida las aplicaciones que se pueden utilizar. En el anexo B se ilustran las características más importantes que diferencian a un SO de propósito general de uno de tiempo real desde un punto de vista técnico. 1.3.1. Sistema operativo de propósito general El objetivo de este tipo de SO es gestionar y administrar ecientemente los recursos hardware del ordenador, permitiendo ejecutar concurrentemente varios programas sin que haya conictos en el acceso de cada uno de ellos a cada uno de los recursos que necesita y sin que ningún programa monopolice un recurso determinado. El SO intentará que la CPU del ordenador realice el mayor rendimiento medio posible. Esto se consigue gracias a un planicador que aprovecha al máximo la capacidad del procesador haciendo evolucionar todos los procesos o tareas alterando su ejecución y modicando dinámicamente la prioridades. El usuario no tiene acceso al control directo del hardware y tampoco puede prever con seguridad el momento en el que una tarea terminará su ejecución, ni el momento en el 1. Introducción 13 que un proceso obtendrá un resultado. Otra de las características de este tipo de SO es que son multitarea, multiaplicación y multiusuario. En una misma máquina pueden estar en ejecución varias tareas, estar en marcha varias aplicaciones y estar registrados varios usuarios al mismo tiempo. 1.3.2. Sistema operativo de tiempo real Un sistema de tiempo real es un sistema de procesamiento de información que debe responder a estímulos de entrada generados externamente en un período nito y especíco. Las respuestas correctas dependen no sólo de los resultados obtenidos sino también del tiempo en que son entregadas. Las fallos por no responder a tiempo son tan malos como un mal resultado. Este tipo de sistemas está formado por dispositivos de E/S, hardware y software de propósito especíco en donde existe una fuerte interacción con el entorno. El entorno cambia con el tiempo y el sistema debe controlar y/o reaccionar ante cada uno de los cambios. Para conseguir un funcionamiento correcto se imponen varias restricciones. Restricciones de tiempos: Cómputo, periodo, plazos. Restricciones de predecibilidad: Implica que debe ser posible demostrar o comprobar a priori que los requerimientos de tiempos se cumplen en cualquier circunstancia. Como consecuencia, la predecibilidad implica: • Una cuidadosa planicación de tareas y recursos. • Cumplimiento predecible de requisitos temporales: determinismo. • Anticipación a fallos, y sus requerimientos temporales. • Consideraciones de sobrecargas: degradación controlada. • Consideraciones de elementos de impredecibilidad. • Dotar al sistema con capacidades de monitorización y control de tiempos (hardware, software, SO, lenguaje, líneas y protocolos de comunicaciones). Restricciones de recursos: una tarea puede requerir acceso a ciertos recursos, además del procesador, como dispositivos de E/S, redes de comunicación, estructuras de datos, archivos y bases de datos. Restricciones de precedencia: una tarea puede requerir resultados de una u otra tarea antes de comenzar su ejecución. A diferencia de los SO de propósito general, los SO de tiempo real son monousuario y monoaplicación. Sólo puede haber un usuario que es el que ejecuta la única aplicación que hay en el sistema. Esta aplicación se encargará de crear las diferentes tareas que controlen el sistema. 1.3.3. Elección del sistema Es evidente que estos dos tipos de SO cubren aplicaciones totalmente diferentes. Un SO de propósito general no está diseñado para controlar un sistema móvil que realiza operaciones con unos requisitos temporales y ha de ser able en todo momento. Por otro lado, tampoco es lógico usar un SO de tiempo real en aplicaciones sin restricciones temporales, que en un SO de propósito general se ejecutan sin problemas. Será necesario usar un SO de tiempo real cuando la aplicación requiera un control estricto, de forma que cuando reciba un dato de entrada sea necesario realizar el procesamiento de dicho dato antes de la recepción de la siguiente entrada. Es posible encontrar sistemas empotrados que basan su funcionamiento en algún tipo de SO de tiempo real realizando multitud de aplicaciones en aviones, trenes, coches, teléfonos móviles, etc. 1.4. Necesidad de control temporal en un robot móvil El robot que se ha usado en el proyecto esta formado por una serie de sensores que recogen información del entorno y actuadores que le permiten realizar movimientos. Cada uno de estos dispositivos envían/reciben datos a una frecuencia diferente. Para poder recoger los datos correctamente será necesario crear una tarea para cada dispositivo que se ejecute a la frecuencia correspondiente. Para que el robot se mueva o realice un trabajo, será necesaria una tarea que se encargue por ejemplo de ejecutar un algoritmo de navegación evitando obstáculos. Además es posible que se desee visualizar en una pantalla lo que el robot está haciendo y para ello se creará otra tarea que muestre los datos deseados. Al tratarse de un sistema móvil, los requisitos temporales se deben respetar siempre. Los algoritmos de control tienen que cumplir unos periodos jos y responder dentro de unos plazos previamente establecidos. En un robot que se mueve a una velocidad de 2 m/s (7.2 km/h) y ejecuta su control cada 100 milisegundos, reaccionar 50 milisegundos más tarde supone reaccionar 10 cm más lejos de lo que se desea. Esto puede provocar un golpe del robot, a una persona o realizar un mal movimiento. Como es lógico, cada tarea del sistema tendrá una prioridad determinada, que será asignada después de realizar un estudio de planicabilidad. La tarea que atiende un sensor tiene más prioridad que la tarea que realiza la navegación. De la misma forma, la tarea de navegación no puede ser interrumpida por la tarea que muestra información en la pantalla. En denitiva no se puede permitir que en un momento determinado el SO decida dar mayor o menor prioridad a una de las tareas, ni expulsar a una tarea del procesador para que entre otra. 1. Introducción 15 Para que todas las tareas empiecen en los momentos determinados y acaben dentro de su plazo correspondiente es necesario disponer de un SO de tiempo real que asegure una ejecución de las tareas de la misma forma que han sido planicadas. 1.5. Estructura de la memoria En el capítulo 2 y 3 se puede ver una introducción al SO MaRTE y al robot utilizado durante el proyecto. En el capítulo 4 se muestra el proceso de desarrollo de cada uno de los drivers, pasando por las fases de análisis, diseño, implementación y pruebas. En el capítulo 5 se explican algunas consideraciones sobre la medición del tiempo en MaRTE y en el capítulo 6 se muestran las aplicaciones realizadas para demostrar el buen funcionamiento del sistema y los resultados que se han obtenido en el proyecto. Para nalizar en el capítulo 7 se pueden ver las conclusiones obtenidas y los trabajos futuros que se plantean como resultado de este proyecto. Además tras la memoria se puede profundizar en los aspectos más importantes que se han planteado consultando los diferentes anexos realizados. Características de SO de tiempo real, manuales de los drivers, arranque en red, API de la aplicación o los hitos más importantes del proyecto son algunos de los temas que se pueden consultar. Capítulo 2 El sistema operativo MaRTE OS MaRTE OS es un SO de tiempo real destinado al desarrollo de aplicaciones empotradas que se ajusta al perl de Sistema de Tiempo Real Mínimo denido en el estándar POSIX.13.1. MaRTE está escrito en lenguaje Ada, con partes en C y en ensamblador, y soporta aplicaciones Ada, C y C++. [2] 2.1. Características Permite ejecutar aplicaciones en máquinas desnudas. Da y controla el acceso a los recursos hardware. Es bastante diferente de un sistema de propósito general como Linux ya que no soporta sistemas de cheros ni tiene una consola de comandos. Sigue el subconjunto mínimo de tiempo real POSIX.13. Dentro de POSIX.13 MaRTE OS gura dentro de la categoría Mínimo, destinada a sistemas empotrados pequeños, en la cual no es necesario ofrecer sistema de cheros ni multiproceso. MaRTE OS no hace uso pues de la MMU de algunas arquitecturas, no usa disco duro sino que se aloja en memoria volátil y tampoco necesita de un terminal. Es lo que se denomina en jerga POSIX como controlador de un Tostador. Funcionalidad del perl mínimo del subconjunto POSIX.13 incluida en MaRTE OS: • Threads: también llamados hilos o hebras. Un thread es una secuencia de instrucciones ejecutada en paralelo con otras secuencias. Los threads son una forma de dividir un programa en varias tareas que se ejecutan de forma concurrente. • Mutexes, variables condicionales, semáforos: estructuras utilizadas para la sincronización de varios threads. • Señales: servicio del núcleo que permite indicar la existencia de un evento. • Relojes y contadores: ofrecen funcionalidad para controlar el tiempo de ejecución de cada thread. • Suspensión de threads, retrasos absolutos y relativos. 16 2. El sistema operativo MaRTE OS • 17 Ficheros de dispositivo y entrada/salida: Permiten tratar los dispositivos desde un punto de vista abstracto como si fueran un chero al que realizar llamadas del tipo open, read, write, ... • Funcionalidad extra: Manejadores de interrupciones hardware, planicación denida por la aplicación. Ofrece concurrencia a nivel de thread (tareas en Ada) pero no a nivel de procesos. En MaRTE OS sólo hay un proceso (que será el encargado de crear los threads -tareas necesarios), y por tanto un único espacio de direcciones de memoria. Utiliza una política de planicación expulsiva con prioridades jas. Estos algoritmos permiten un alto aprovechamiento de la CPU y su implementación es sencilla tal y como dene el estándar POSIX.13.1 permite utilizar políticas de planicación expulsivas como FIFO con prioridades, round-robin o servidor esporádico. Para la sincronización de tareas implementa el protocolo de herencia básica de prioridad y el techo de prioridad inmediato. Todos los servicios tienen una respuesta y latencia temporal acotada, por lo que se puede utilizar para aplicaciones de tiempo real (tanto estricto como no). El espacio de direcciones es compartido por el núcleo y la aplicación con lo cual no se provee la protección de otros sistemas operativos y se debe probar a fondo el sistema nal. La ventaja es que permite una mayor velocidad de ejecución. Es un núcleo monolítico. Un núcleo monolítico se caracteriza porque cuando se está ejecutando una parte de su código no hay otras partes ejecutándose concurrentemente. Permite simplicar su desarrollo y ser muy ecientes en sistemas monoprocesador, aunque es complicado portarlo a sistemas multiprocesador. Está escrito en Ada 95 (salvo algo de código en C y ensamblador) pero ofrece interfaces tanto para aplicaciones Ada como C, o incluso aplicaciones que mezclen threads con tareas Ada. Es portable a diferentes plataformas gracias a una capa de abstracción hardware. Incluyendo microcontroladores, de gran importancia en el mundo de los sistemas empotrados. Actualmente se encuentran implementadas para: • Arquitectura x86 PC (bien en máquinas desnudas o bien en emuladores). El núcleo es compatible con cargadores que usen el protocolo Multiboot. • Arquitectura Linux y LinuxLib, donde MaRTE OS corre dentro de Linux. Principalmente destinada a investigación y enseñanza (no se puede alcanzar requerimientos de tiempo real estricto dentro de un sistema que no lo es, como Linux). • Arquitectura M683XX. No se distribuye actualmente con MaRTE OS debido a que corresponde a una versión antigua que no ha sido actualizada. Es código libre con licencia GNU/GPL. Figura 2.1: Arquitectura de MaRTE OS para aplicaciones ADA y C En la gura 2.1 podemos ver la arquitectura en forma de capas de MaRTE OS para una aplicación escrita en Ada y en C. La principal diferencia entre ambas radica en la capa utilizada para comunicar la aplicación con el resto del sistema. Como puede apreciarse en ambas guras, el núcleo incluye una interfaz abstracta de bajo nivel para acceder al hardware. En ella se dene la visión que del hardware tienen las partes del núcleo que son independientes de la plataforma de ejecución (Ej: x86, PowerPC, ARM, MIPS,...). Esta interfaz constituye la única parte del núcleo que es dependiente del hardware, lo que facilita el portado de MaRTE OS a distintas plataformas. Por otro lado, los gestores de dispositivos (drivers ) también presentarán dependencias respecto al hardware sobre el que se ejecutan. 2.2. Trabajando con MaRTE OS En el anexo E se puede consultar la forma de instalación del sistema, el proceso de creación de nuevos drivers y la conguración necesaria de nuestro entorno de desarrollo para poder arrancar el SO a través de la red. MaRTE es un SO destinado a controlar aplicaciones empotradas en diferentes máquinas y arquitecturas. Por este motivo al desarrollar una aplicación será necesario un ordenador donde el usuario programa y compila (servidor), y otra máquina donde se ejecute el archivo generado en el proceso anterior (host ). Para comenzar con MaRTE OS es muy recomendable el uso de alguna máquina virtual, como por ejemplo Qemu (disponible en http://fabrice.bellard.free.fr/qemu/). De esta forma no hay que traspasar el archivo entre diferentes ordenadores. Para un mayor detalle sobre como utilizar la máquina virtual con MaRTE OS se recomienda leer [3]. En este caso, la máquina host es el robot, y por lo tanto todas las pruebas deberán realizarse sobre esta arquitectura. El entorno en el que se ha desarrollado el proyecto se muestra en la gura 2.2 2. El sistema operativo MaRTE OS with MaRTE_OS; with Text_IO; use Text_IO; Ordenador de desarrollo 19 Robot en ejecución Arranque en red o mprogram en disco procedure robot is begin setSpeed(1.0,0.1); ... end procedure; Compilación Programa ejecutable MaRTE OS Código objeto Enlazado Programa ejecutable Red Red Inicializa el sistema Ejecuta programa del usuario Servidor DHCP + TFTP Figura 2.2: Entorno de desarrollo del proyecto. En el servidor tendremos que tener Linux con los archivos y el compilador de MaRTE instalado. Aquí será donde se programe la aplicación incluyendo las librerías del SO. Al compilar con el compilador de MaRTE se obtiene un chero llamado mprogram que se deberá copiar al robot para ser ejecutado. Para agilizar el proceso, se permitió al robot arrancar en red, descargándose el archivo generado después de compilar. El ordenador host obtiene la dirección de red por medio de un servidor DHCP, y este es el que le indica que archivo debe descargarse para arrancar. La máquina host lo descarga mediante un servidor TFTP instalado en el servidor y comienza la ejecución del SO y la aplicación programada. Esta conguración esta completamente especicada en el apartado 2.3 de [4]. Capítulo 3 El robot móvil Pioneer 3.1. Arquitectura del sistema En la gura 3.1 se puden observar los robots disponibles en el laboratio. Cada uno de estos robots está formado por un ordenador Pentium III a 800MHz, con 250MB de memoria RAM, 40GB de disco duro y una variedad de dispositivos sensores y actuadores. Los sensores permiten obtener información del entorno. Los actuadores sirven para interaccionar con el entorno y dar cierta movilidad al sistema. En la gura 3.2 se muestra una esquema gráco de la arquitectura del sistema donde se detallan los diferentes dispositivos estudiados y sus conexiones. Figura 3.1: Robot Pioneer 3-AT. El láser, el microcontrolador y el GPS se comunican con el robot a través de la línea serie RS232. El microcontrolador tiene conectados varios sensores. Él mismo se comunica con estos sensores gracias a un SO llamado P2OS que lleva incorporado. El ordenador (el robot) se comunica con el micro y sus sensores mediante comandos que el P2OS comprende. La tarjeta inalámbrica es de tipo PCMCIA. El robot no dispone de un conector de este tipo pero si de uno de tipo PCI 104. Para poder usar la tarjeta se ha utilizado un adaptador entre PCMCIA y PCI 104 de 32 bits. 20 3. El robot móvil Pioneer 21 LÁSER ttyS0 GPS ttyS1 MICROCONTROLADOR Odometría Sonar ttyS2 PCI 104 ROBOT ADAPTADOR PCI-PCMCIA PCMCIA LINEA SERIE RS232 TARJETA INALÁMBRICA Motores Brújula P2OS Figura 3.2: Los dispositivos más importantes del robot y sus conexiones. 3.1.1. Sensores Posición relativa: El sensor de odometría es el que informa al robot de la posición en la que se encuentra situado respecto a los movimientos realizados. Básicamente lo que hace es medir el movimiento de las ruedas del robot, calculando la posición en X, en Y y el ángulo que se ha movido. Un sensor tacométrico esta conectado al microcontrolador. Con cada movimiento de las ruedas el sensor envía pulsos al microcontrolador y este los traduce a valores correspondientes al movimiento. Esta medida es aproximada y poco able ya que si una rueda derrapa el sistema de odometría creerá que el robot se ha movido más de lo que realmente se ha movido. Esto provoca que el robot tenga una información acerca de su posición incorrecta. Además, debido a que la odometría es un valor respecto al desplazamiento realizado, el error se va acumulando y cuantos más movimientos se hacen la calidad de la medida empeora. Con el sistema de odometría también se puede saber a que velocidad se realizan los movimientos, tanto translacional como angularmente. Estos valores de velocidad se obtienen derivando el valor de la posición. Posición global: Gracias al dispositivo GPS de la marca Novatel modelo ProPack G2 que lleva incorporado el robot se puede obtener la posición global en la que se encuentra el robot. El error del GPS es de pocos metros y se puede reducir a centímetros si se usa una estación base diferencial. El problema del sistema GPS es que sólo puede usarse en exteriores porque en interiores no recibe la señal de los satélites. Esto obliga a usar la odometría en interiores. Entorno 2D con láser: El robot dispone de un sensor láser de distancias de la marca SICK modelo LMS que es capaz de aportar información sobre lo que el robot tiene delante suyo. Su funcionamiento se basa en un mecanismo de espejo rotatorio, que va dirigiendo un o pulso láser en un recorrido horizontal de hasta 180 . Las medidas se calculan por tiempo de vuelo. Para obtener más información acerca del dispositivo SICK LMS se recomienda consultar el anexo D. Entorno 2D con sonar: También existe la posibilidad de usar los 16 sensores sonar que proporcionan información similar al láser pero más limitada. En vez de utilizar un láser, lanza una onda que luego recoge y se obtiene la distancia al obstáculo. El problema es que las ondas no se transmiten en línea recta como el láser. Esto provoca que en diferentes situaciones el valor que se recoge es erróneo e incluso puede que la onda que recoge un sensor es la que envió otro de los sensores debido a algún rebote. Además en vez de obtener las 360 distancias que puede proporcionar el láser, ofrece tan solo 16. Orientación: Es posible usar una brújula electrónica para conocer de forma precisa la orientación del robot. La brújula es uno más de los sensores que está conectado al microcontrolador. Bumpers : En la parte frontal y trasera del robot están colocados 10 sensores que indican al robot que ha tocado o se ha chocado con algo. Cuando uno de estos sensores se activa, el robot por defecto se para. Este comportamiento es congurable. También está conectado al microcontrolador. 3.1.2. Actuadores Motores: Para realizar movimientos el robot dispone de 2 motores para mover las ruedas de cada lado. Se puede mover en la dirección X, Y con desplazamientos de o translación y 360 angularmente, pero para girar ha de rotar sobre sí mismo derra- pando ya que las ruedas están jas sin poder modicar la dirección. La velocidad o de translación máxima es de 2 metros/segundo y la angular de 360 por segundo. 3.1.3. Mecanismo de comunicación El robot dispone de un conector PCI 104. Gracias a un adaptador que convierte una entrada PCI 104 a una de tipo PCMCIA es posible usar una tarjeta inalámbrica de tipo PCMCIA de la marca Conceptronics. A través de esta tarjeta se puede enviar información del robot a cualquier otra tarjeta inalámbrica utilizando el protocolo 802.11. Además es posible utilizar el protocolo RT-WMP para comunicaciones en tiempo real que se esta desarrollando actualmente en la Universidad de Zaragoza. 3.2. Método de trabajo actual con el robot Actualmente el robot tiene instalado un SO Linux de propósito general. Para controlarlo se utiliza un programa de software libre con licencia GNU llamado Player/Stage. Player se ejecuta sobre el robot proporcionando un interfaz simple y claro para el manejo de sus sensores y actuadores sobre una red IP. Por lo tanto, para poder controlar el robot, se necesita de un programa cliente que acceda por medio de un socket TCP/IP a Player. 3. El robot móvil Pioneer 23 Este cliente puede leer la información que devuelven los sensores, dar órdenes a los actuadores y congurar los dispositivos que monta el robot al vuelo. Entre las principales características de Player cabe mencionar su capacidad para soportar distintos robots y su facilidad para añadir nuevo hardware. Todo esto es posible gracias a su arquitectura modular. Otra de las cosas que se puede destacar de Player es que si un programa de control funciona en su simulador (Stage), generalmente, este funcionará en el robot real sin ningún cambio. El programa es muy cómodo para desarrollar sistemas de navegación y todo tipo de aplicaciones robóticas. Permite realizar un desarrollo rápido usando un entorno integrado como Eclipse. Además no es necesario tener un robot para hacer pruebas ya que se pueden hacer en el simulador. El único problema del simulador es que no tiene en cuenta algunos factores del entorno. Las ruedas del robot no derrapan nunca, la odometría es perfecta y todos los valores de láser están disponibles instantáneamente sin error alguno. Capítulo 4 Integración de los sensores en MaRTE 4.1. Análisis general Actualmente los algoritmos de control desarrollados para el robot (o el simulador del robot) se ejecutan sobre un SO Linux de propósito general. Un algoritmo de navegación bien diseñado no conseguirá mover el robot con la precisión que se desea. Mientras se ejecuta el algoritmo de navegación, el SO realiza diferentes tareas y su planicador dejará ejecutar la navegación si lo cree conveniente. Esto quiere decir que el movimiento del robot está condicionado por la carga y la política de planicación del sistema. En el capítulo 6 se ha demostrado que si se ejecuta una aplicación en Linux para mover el robot y se carga el sistema con otros procesos el robot se mueve de forma descontrolada. Si se ha desarrollado un buen algoritmo de navegación y se necesita un sistema able y robusto se deberá realizar una aplicación en MaRTE similar a la que podemos ver en el apartado 6.1. El ordenador del robot está dedicado únicamente a leer los sensores, procesar los datos (navegación) y mandar comandos a los motores. La planicación se realiza antes de lanzar la aplicación. Un SO como MaRTE y un estudio de planicabilidad garantizan que todas las tareas que forman la aplicación siempre se van a ejecutar dentro de sus plazos. 4.2. Diseño arquitectural En la gura 3.2 se pueden observar los dispositivos que componen el sistema y sus conexiones. Se han desarrollado los diferentes drivers que permiten la interacción del ordenador con: El microcontrolador. Driver de comunicación a través de la línea serie entre microcontrolador y ordenador. El láser. Driver de comunicación a través de la línea serie entre láser y ordenador. El GPS. Driver de comunicación a través de la línea serie entre GPS y ordenador. La tarjeta inalámbrica. Driver de comunicación a través de la conexión PCI 104 con el adaptador PCI/PCMCIA. Y a través de ésta se realiza la comunicación con la tarjeta inalámbrica PCMCIA. 24 4. Integración de los sensores en MaRTE 25 A continuación se explican las fases de análisis, diseño, implementación y pruebas por las que ha evolucionado el proyecto. 4.3. Microcontrolador y P2OS 4.3.1. Análisis Como punto de partida es necesario conocer qué características tiene el microcontrolador y qué tarea de control hay que realizar para que el robot y el micro se comuniquen perfectamente. Para ello se estudió en profundidad el manual disponible en [11] donde se especican las características del micro y se dene desde el sistema de conexión para cada elemento hasta los diferentes comandos que se pueden enviar. En el anexo C hay disponible una versión resumida del manual en castellano. Varios de los sensores están conectados al microcontrolador que a su vez está conectado con el ordenador principal del robot a través de la línea serie RS232. Este micro se comunica mediante el P2OS con los motores, el sistema de odometría, los sensores sonar, la brújula, etc. El P2OS tiene una estructura cliente/servidor. El servidor está en el micro esperando los comandos que el cliente (el ordenador) le va mandando. Se pueden diferenciar dos tipos de paquetes de comunicación entre el micro y el ordenador: Paquetes SIP: Son Paquetes de Información del Servidor que cada 100 ms envía el microcontrolador al ordenador. Este paquete contiene información actualizada sobre todos los dispositivos conectados al micro. Esto signica que cada 100 ms el ordenador tiene actualizada correctamente la información de odometría, sonar, orientación, etc. Paquetes de Comando: Son paquetes diferentes a los anteriores. En este caso van en la dirección contraria, el ordenador envía una orden al micro para que realice un nuevo comando. Por ejemplo modicar el valor de la velocidad, la conguración de un sensor, etc. El driver desarrollado para el micro debe ser capaz de enviarle comandos correctamente, y de recibir la información que el micro envía periódicamente. Es decir, el driver implementa la parte cliente del P2OS. 4.3.2. Diseño El primer paso fue estudiar como estaba implementado el controlador del micro en la plataforma Player que se usa en el robot. En términos generales Player dispone de un nivel de usuario y un nivel hardware que se comunican pasándose mensajes en las dos direcciones. En el nivel hardware se crea un thread por cada dispositivo que se instancia en el robot. Si usamos tres dispositivos (microcontrolador, láser y GPS) se creará un thread para cada uno. Cada thread atiende los datos que se envían/reciben para cada dispositivo y actualiza una serie de variables compartidas entre ambos niveles (datos de posición, velocidad, orientación, etc). Además intercambia mensajes con el nivel superior. El nivel de usuario tiene una visión abstracta del hardware. Es un nuevo proceso que mediante una serie de funciones que componen el API de Player, obtiene los datos compartidos y va generando los diferentes tipos de mensajes que comunican con el nivel hardware. Esta forma de comunicación con los dispositivos es incompatible con las características del tiempo real. El usuario no puede tomar decisiones sobre las prioridades de los diferentes threads que se crean. Todos los threads entran en conicto entre ellos y con los demás procesos del sistema. La alternativa al sistema de Player fue reutilizar una parte del driver que implementaba el cliente del P2OS y rediseñar la forma de creación y comunicación de las diferentes tareas. Las funciones que construyen, envían y reciben comandos para el microcontrolador se mantuvieron modicando algunas llamadas al sistema. Para todas estas funciones que estaban escritas en C, se elaboró una interfaz para poder utilizar toda la exibilidad de las tareas Ada. En el anexo G se puede ver como se realiza la interfaz entre C y Ada, y en el anexo F el conjunto de funciones que el usuario tiene a su disposición. Se proporcionan funciones que interaccionan directamente con el hardware y funciones que obtienen datos compartidos por las tareas. Los dos niveles de Player ahora se convierten en un sólo nivel. El usuario deberá crear las tareas que interaccionan con el hardware y las que se comunican mediante los datos compartidos. Ahora el control total de las tareas la tiene el usuario. Las funciones que realmente interaccionan con el hardware están escritas en C. Como la comunicación entre tareas no se puede implementar con objetos protegidos Ada se implementaron con mutexes de C. En este caso tienen la característica de poder ser inicializados con un protocolo de planicación de techo de prioridad inmediato modicando los atributos del mutex con el valor PTHREAD_PRIO_INHERIT y con la prioridad deseada. En cualquier caso el usuario puede modicarlo para usar cualquiera de los protocolos disponibles. Cuando una tarea quiere acceder a información compartida, debe realizar un bloqueo (función de usuario lockP2os), ejecutar las funciones correspondientes sobre los datos compartidos y volver a liberar el mutex (unlockP2os). El tiempo de cómputo que transcurre desde que se captura el mutex hasta que se libera supone un tiempo de bloqueo para otras tareas que también quieran acceder a los datos. Esta forma de trabajar se ha utilizado también en el láser y en el GPS. En la gura 4.3 se puede ver una explicación gráca para el caso del láser. En la gura 4.1 se muestran las fases y tareas que están involucradas en la comunicación entre el robot y el micro. Cuando encendemos el robot, el micro se queda a 4. Integración de los sensores en MaRTE 27 Ordenador del robot + MaRTE Microcontrolador + Comunicación Servidor P2OS 1 Escucha peticiones del cliente 2 Envía SIP cada 100 ms Cliente P2OS Conexión 2 2' Recibe comandos y actúa SYNC0 SYNC1 SYNC2 Conecta al servidor 1 Dos tareas concurrentes T1 Recibe SIP cada 100 ms y actualiza variable compartida 2' T2 Envía comandos Figura 4.1: Diseño del driver P2OS la espera para recibir (1) una serie de comandos de conexión (comandos SYNC) que el cliente deberá mandar. Cuando el micro tiene un cliente conectado, realiza dos tareas automáticamente. Por un lado (2) envía un paquete SIP al cliente cada 100ms y por otro (2') espera la recepción de comandos del cliente para actuar sobre los motores. En el otro lado, el cliente lo forma el ordenador del robot controlado por MaRTE. Cuando la aplicación comienza manda los comandos de conexión (1) y el siguiente paso es lanzar dos tareas diferentes. La primera tarea (2) realiza la lectura de los paquetes SIP que envía el servidor (esto se hace cada 100ms). La segunda tarea (2') es la encargada de enviar los comandos al robot. En esta segunda tarea será donde se ejecute por ejemplo un algoritmo de navegación. 4.4. Láser SICK LMS 4.4.1. Análisis El láser es el dispositivo que permite al robot obtener información sobre el entorno. Cada cierto tiempo este dispositivo envía al ordenador un conjunto de valores que representan la distancia que separa el sensor de los objetos que hay delante suyo. De forma similar al microcontrolador, el ordenador se comunica con el láser a través de la línea serie intercambiando datos. En el anexo D se detalla en profundidad el funcionamiento del dispositivo y los diferentes comandos que se envían para congurarlo y comenzar la lectura de datos. Hay varias conguraciones posibles para usar el láser. Para realizar la conguración se han de enviar diferentes comandos de una forma determinada. En primer lugar se puede congurar la velocidad de conexión con el dispositivo (9600, 19200 y 38000 bytes por se- Rango angular 0º .. 100º 0º .. 100º 0º .. 100º 0º .. 180º 0º .. 180º Resolución angular 1º 0.5º 0.25º 1º 0.5º Número de puntos 101 201 401 181 361 Cuadro 4.1: Opciones de conguración del láser gundo). Es posible obtener las distancias en un rango de 100 o o de 1 , 0.5 o ó 0.25 o ó 180 o y con una precisión obteniéndose un número de valores de distancias diferente en cada caso. Por último se puede congurar la precisión de las distancias que se recogen en cm o en mm. Las fases de comunicación con el dispositivo son muy simples: 1. Enviar comandos de conguración. 2. Enviar comando Start para empezar a recibir datos de forma continua. 3. Enviar comando Stop y Reset para terminar y dejar el dispositivo con los valores por defecto. Cuantos más puntos se obtengan del láser, se podrá conocer mejor el entorno pero la frecuencia de muestreo será menor. Los diferentes modos de conguración del láser se pueden consultar en la tabla 4.1. Todos los datos se envían a través de la línea serie a una velocidad determinada limitando la capacidad de transmisión. El driver del láser debía ser capaz de implementar la comunicación entre el dispositivo y el robot a la perfección. Además se debían de aportar soluciones para poder usarlo dentro del marco del tiempo real. 4.4.2. Diseño La cantidad de información (bytes) que el sensor manda al robot es muy grande y lo hace a una frecuencia elevada. Esto provoca que se generen un gran número de interrupciones a través de la línea serie. Se estudió la gestión de interrupciones en el puerto serie en MaRTE ya que a tasas de envío altas se perdían interrupciones. Esto es un error grave que había que arreglar y con este objetivo se estudió como estaba implementada la línea serie. Los problemas de la línea serie En la gura 4.2 se pueden observar los elementos más importantes que componen el driver de la línea serie en MaRTE. El problema que planteaba este diseño es que la rutina de interrupción se ejecuta correctamente dependiendo de la velocidad del procesador. El procesador del robot es más lento (800 MHz) que el procesador que había usado la persona que desarrolló este driver y no lo tuvo en consideración. El primer problema 4. Integración de los sensores en MaRTE 29 BUFER DE ENTRADA INT RS232 PROGRAMA DE USUARIO REGISTRO ENTRADA Read Rutina de interrupción REGISTRO SALIDA Serial_port_driver write BUFER DE SALIDA (bloqueante / nobloqueante) Figura 4.2: Esquema de funcionamiento del puerto serie. importante fue que el búfer circular (entrada y salida) tan solo tenía espacio para 1 Byte. Este problema se solucionó modicando la denición del búfer ampliando la capacidad. El segundo problema que hubo que solucionar fue que mientras se estaba atendiendo a una interrupción, llegaban nuevas interrupciones que más tarde no eran atendidas. Para ello se modicó el manejador de la interrupción para que antes de salir comprobara si habían nuevos datos en el registro del RS232. De esta forma se consiguió que la línea serie funcionara con el láser SICK LMS para las velocidades de 9600bps y 19200bps. El problema es que este manejador presenta una condición de carrera y un aumento en la frecuencia de recepción de interrupciones provoca que de nuevo no dé tiempo al driver a atender a todas las interrupciones correctamente. Con la siguiente velocidad posible (38400bps) el driver volvía a fallar. La solución más sencilla es ampliar la velocidad del procesador. Sin embargo en Linux, con la misma velocidad y el mismo procesador todo funciona correctamente. La explicación es que, o bien el código del driver de la línea serie no está tan optimizado como para Linux, o directamente el driver está mal implementado y con velocidades altas no funciona. El desarrollo del driver se realizó siguiendo el manual del dispositivo. Una vez corregida la transmisión de datos a través de la línea serie en MaRTE, se implementaron los diferentes comandos que hay que enviar al láser, así como todas las funciones necesarias para una comunicación correcta entre el ordenador y el dispositivo. El láser tiene unas fases de ejecución determinadas y deja poco margen a la imaginación. La única forma para conseguir que funcione correctamente es traducir a código el manual. Sin embargo, sí que se realizó una modicación adicional para poder usar el láser correctamente en tiempo real. Lectura y reducción de bloqueos Cuando realizamos una lectura del dispositivo láser rellenamos un búfer de distancias de diferente dimensión dependiendo del modo con el que lo hayamos inicializado, y por lo tanto tardaremos más o menos tiempo en leerlo. Por otro lado cuando tenemos una aplica- Tarea utiliza el láser Tarea que atualiza el búfer del láser wait (mutex) Escritura completa variable protegida signal (mutex) valores1 valores2 wait (mutex) Lectura completa variable protegida Estructura con las signal (mutex) medidas del láser duplicada para minimizar bloqueos. Figura 4.3: Doble búfer del láser para minimizar bloqueos. ción y queremos consultar el láser entero iremos leyendo el búfer de elemento en elemento. Puede suceder que cuando usemos el láser desde una tarea leamos el búfer mientras que la tarea que actualiza el mismo búfer también este escribiendo, dejando un dato incoherente. La gura 4.3 muestra la solución que se ha dado a este problema. Para evitar leer un dato incoherente se tiene que proteger el búfer en el que se esta escribiendo/ leyendo en cada momento. Se implementó un objeto protegido mediante un mutex de la misma forma que en el driver del microcontrolador. Además para evitar tener que esperar a que una de las dos operaciones acaben completamente se duplicó el búfer. De esta forma cuando una tarea actualiza el búfer, la tarea que lo lee puede continuar sin bloquearse. Cuando el búfer esté actualizado y la otra tarea ya no esté leyendo (ha liberado el bloqueo) se intercambiarán los vectores y se podrá continuar. En el apartado 6.1 se pueden ver los valores de los bloqueos entre tareas y objetos protegidos para una aplicación típica. 4.5. Comunicación inalámbrica 4.5.1. Análisis Este driver se implementó para poder comunicar el robot con otras máquinas. Para ello MaRTE OS dispone de un controlador para una tarjeta Conceptronics de tipo PCI. Por problemas de tamaño, es imposible instalar una tarjeta de este tipo en el robot. Lo que si se podía hacer es poner un adaptador PCMCIA/PCI que permite instalar una tarjeta Conceptronics de tipo PCMCIA. Debido a que las tarjetas son del mismo fabricante y de modelos muy similares el driver es exactamente el mismo para ambas tarjetas. El problema surgió debido a que no existía en MaRTE el driver para comunicarse con la tarjeta mediante PCMCIA. Desarrolladores de MaRTE OS en la Universidad de Cantabria estudiaron el problema y proporcionaron el driver que solucionaba los problemas anteriores. 4. Integración de los sensores en MaRTE 31 El ojetivo a partir de aquí fue realizar comunicaciones en tiempo real usando las funciones que proporcionaba este driver. El problema es que en un sistema distribuido (con varios robots o máquinas comunicándose), la tarea que monitorea y controla diferentes aspectos del entorno está dividida entre los nodos. Debido a los retardos impredecibles de la comunicación, los diferentes nodos pueden obtener nueva información en distintos instantes, causando que algunos nodos tengan una visión incorrecta del entorno. Estos actuarán inconsistentemente y fuera de control. Por lo tanto en un sistema distribuido de tiempo real se necesita garantizar el tiempo que tarda en enviarse un mensaje para permitir una planicación en tiempo real. En consecuencia cada evento o fase en un protocolo de comunicación debe tener una duración acotada. Sin embargo, los protocolos de comunicación inalámbrica existentes como 802.11 no aportan garantías temporales en transmisiones de red debido a interferencia entre paquetes, retransmisiones y problemas de bloqueos. 4.5.2. Diseño Con el driver de la tarjeta funcionando se disponía de la tecnología suciente para enviar una trama de bytes desde una máquina a otra. Es decir, mediante las funciones send y receive que proporciona el driver era posible enviar datos desde una dirección MAC a otra. La mejor alternativa para poder conseguir una comunicación dentro del marco de tiempo real fue adaptar el protocolo RT-WMP para comunicaciones en tiempo real, que esta siendo desarrollando en la Universidad de Zaragoza a MaRTE OS. El protocolo RT-WMP funciona en tres fases. Fase de arbitrio de la prioridad, fase de autorización de transmisión y fase de transmisión del mensaje. Durante la fase de arbitrio de la prioridad, los nodos se ponen de acuerdo sobre cual de ellos tiene el mensaje de más prioridad en la red en ese momento. Después, en la fase de autorización de transmisión, se envía una autorización para transmitir al nodo que tiene el mensaje de mayor prioridad. Finalmente, en la fase de transmisión del mensaje, éste nodo envía el mensaje al nodo de destino. RT-WMP funciona mediante paso de testigo sobre un conjunto de nodos acotado. Cada nodo tiene su propia cola de mensajes y cada cola de mensajes tiene una prioridad (de 1 a 255 niveles). Cada mensaje tiene una dirección de destino, que es uno de los nodos de la red. Cuando un nodo recibe un token, éste busca en su cola el mensaje con mayor prioridad y, sí el valor de la prioridad del mensaje es mayor que el valor en el correspondiente campo del token, el nodo cambia el valor de la estación con mayor prioridad y el valor de la prioridad del mensaje en el campo del token y lo envía a otro nodo. El último nodo que recibe el toquen comprueba cual es el nodo que tiene el mensaje de mayor prioridad y, por lo tanto, cual es el nodo autorizado a enviar el mensaje. Entonces, manda un mensaje de autorización al nodo que tiene el mensaje de mayor prioridad. Finalmente este mensaje es enviado a través de un camino multi-salto. Cuando el mensaje llega al destino, el bucle se reinicia. Los nodos saben sólo el número de nodos de la red. Cada nodo esta identicado con un número natural entre 0 y N que es su dirección en la red WMP. Las conrmaciones (ACK) son implícitas. Sí el nodo A envía un token al nodo B, y el nodo B lo envía al nodo C, el nodo A interpreta que éste pasa como un reconocimiento implícito de que el token fue recibido correctamente por el nodo B. Todas las capas de bajo nivel del protocolo envían sus tramas mediante broadcast. No hay ltrado y todos los nodos reciben la misma trama, lo cual es obligatorio para que el protocolo funcione correctamente. En [7] se puede obtener más información sobre el funcionamiento de RT-WMP. El protocolo hasta ahora sólo funcionaba en Linux, y está escrito en C y C++. Gracias a la exibilidad y modularidad con la que está implementado, adaptarlo a MaRTE no fue una tarea difícil. En primer lugar se denió la mejor forma de hacer el protocolo multiplataforma. Mediante cheros de denición se puede compilar el código directamente para la plataforma deseada. Para conseguir que funcionara en MaRTE fue necesario adaptar las llamadas al sistema del protocolo (para Linux) a sus equivalentes llamadas para MaRTE. En el capítulo 6 se puede ver una de las aplicaciones realizadas usando comunicaciones inalámbricas. Para este protocolo no se ha realizado un interfaz Ada debido a la escasez de tiempo. El protocolo genera diferentes threads que controla el SO pero no el usuario. En un futuro este interfaz permitirá lanzar el protocolo utilizando tareas de Ada. 4.6. GPS Novatel 4.6.1. Análisis Este dispositivo tiene la misión de leer la posición, que es devuelta en coordenadas geográcas (longitud/latitud). Por lo tanto, también se encarga de pasarlas a coordenadas cartesianas en el sistema UTM (X,Y,h) donde X es positiva hacia el Este de la cuadrícula e Y hacia el Norte y h es el uso o zona UTM (UTM zone). El origen de este sistema de coordenadas es para la X el meridiano central del huso UTM en el que está el robot, y para la Y el ecuador. El problema inherente que trae consigo el uso de UTM es que el robot cambie de huso. Lo que ocurre en este caso es que el origen del sistema de coordenadas para la coordenada X también cambia y por lo tanto también cambiará la idea de posición que tiene el robot. Para evitar esto, se guarda el primer huso UTM de la primera lectura que se ha tomado del GPS y a partir de él se calculan las posiciones en coordenadas UTM. Para más información del sistema GPS y de la proyección UTM ver el anexo H en [10]. 4. Integración de los sensores en MaRTE 33 4.6.2. Diseño La comunicación con el dispositivo GPS se llevó a cabo siguiendo la misma idea que para el microcontrolador. En primer lugar se estudió el manual del dispositivo [12] y cómo estaba implementado el driver para Player. Las funcionalidades básicas que interaccionan a nivel hardware pudieron ser reutilizadas con algunas modicaciones. Para poder permitir un uso de tiempo real correcto también se creó otro objeto protegido mediante mutex exactamente igual que el del microcontrolador. El sistema GPS es de gran utilidad para poder corregir la posición (la odometría) del robot y disponer de una buena localización. El dispositivo envía cada segundo un nuevo dato con las coordenadas de la posición global. 4.7. Implementación y pruebas Esta ha sido la parte más laboriosa del proyecto ya que la implementación de los drivers debía ser a bajo nivel en lenguaje C. Básicamente se tuvo que realizar una traducción de los manuales a dicho lenguaje cumpliendo estrictamente con cada byte enviado y recibido. Además para poder probar cada nuevo avance o mejora era necesario ejecutar el código en el robot, haciendo mucho más pesado el trabajo. Pero es así como debe de realizarse la programación de un sistema empotrado. Cuando se completó la implementación y testeo de las funciones de cada driver en C, se realizó un interfaz entre C y Ada para poder usar dichas funciones desde un programa Ada. Esto posibilita realizar una mejor planicación de las tareas ya que para este tipo de aplicaciones, el lenguaje Ada es sin duda la mejor herramienta de desarrollo. Se puede consultar la conversión entre ambos lenguajes y tipos en el anexo G. Se ha creado por tanto un nuevo conjunto de funciones o API para el desarrollo de aplicaciones robóticas bajo el control de MaRTE OS tanto en Ada como en C disponible en el anexo F. Es importante resaltar que todas las funciones desarrolladas fueron fuertemente testeadas tanto individualmente como en conjunto con diferentes aplicaciones como se puede ver en el capítulo 6. Como resultado nal se dispone de un entorno de control para el robot amplio y robusto. Capítulo 5 Caracterización temporal completa del sistema En un sistema de tiempo real, es completamente necesario denir de forma precisa los tiempos de cómputo de las operaciones que se pueden realizar, así como los periodos de ejecución de las tareas (o sus operaciones) y de los plazos de respuesta si es que existen. Por este motivo, en el momento que se probaron completamente las funciones de los drivers implementados, se midieron los tiempos de cómputo con la máxima precisión posible. 5.1. Medir el tiempo de cómputo en MaRTE Para medir el tiempo de cómputo de una función en MaRTE se han de tomar algunas precauciones. Se puede medir el tiempo inicial y nal de la ejecución de la función y luego restarlos. Pero de esta forma se obtiene el tiempo que está la función en ejecución y no su tiempo de cómputo. Si dicha función no se ejecuta a la máxima prioridad o se suspende en algún momento el planicador de MaRTE es libre de expulsarla mientras se está ejecutando para realizar otras operaciones y más tarde nalizar la primera. Para realizar una medida correcta del cómputo es necesario usar los relojes de ejecución disponibles en MaRTE. En la gura 5.1 se muestra la forma correcta de medir el tiempo de cómputo de una función para los lenguajes C y Ada. De esta forma el tiempo with POSIX; with POSIX_Timers; pragma Elaborate_All (POSIX_Timers); struct timespec ts; //para medir la duracion de la interrupcion procedure medir is CPU_Time_First : POSIX.Timespec := POSIX.To_Timespec (0.0); CPU_Time_Last : POSIX.Timespec := POSIX.To_Timespec (0.0); begin CPU_Time_First := POSIX_Timers.Get_Time(POSIX_Timers.Clock_Task_Cputime_Id); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); double t1=ts.tv_nsec; funcion_a_medir(); funcion_a_medir; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); CPU_Time_Last := POSIX_Timers.Get_Time(POSIX_Timers.Clock_Task_Cputime_Id); double t2=ts.tv_nsec; printf("%.6lf nseconds elapsed\n", t2-t1); put("Tiempo = "); put ((POSIX.To_Duration (CPU_Time_Last) POSIX.To_Duration (CPU_Time_First)) * 1000); put_line("ms."); esc: terminar Figura 5.1: Medición del tiempo de cómputo de una función en MaRTE para C y Ada respectivamente. 34 5. Caracterización temporal completa del sistema Baud rate interrupciones / segundo 9600 1200 19200 2400 38400 4800 Periodo mínimo (inversa) 833.333µs 416.66µs 208.333µs 35 Utilización 0.03240 0.0648 0.1296 Cuadro 5.1: Interrupciones generadas por la línea serie. medido corresponde únicamente al tiempo en el que la función que se desea medir ha estado ocupando el procesador. En el anexo F se puede ver el tiempo de cómputo de las funciones desarrolladas para el microcontrolador, el láser y el GPS. Todos han sido medidos usando los relojes de tiempo de ejecución. Debido a que el driver de la tarjeta inalámbrica estuvo disponible varios meses después de comenzar el proyecto, el tiempo de cómputo de las funciones del protocolo RT-WMP no ha podido ser medido completamente. Aunque las pruebas realizadas para la comunicación inalámbrica funcionan correctamente no se ha podido realizar un estudio de planicabilidad completo. Este trabajo será necesario hacerlo si en el futuro se pretende hacer un uso intensivo de la comunicación inalámbrica en el robot. 5.2. Dependencia de la línea serie Otro de los aspectos importantes de este sistema es que los drivers del P2OS, del láser y del GPS funcionan a través de la línea serie. Cada byte que envían estos dispositivos es capturado por MaRTE a través de una interrupción asociada a la línea serie como se muestra en la gura 4.2. En el momento en el que se instancia un dispositivo, por ejemplo el láser, dicha interrupción se ejecutará cada vez que reciba un byte. Se midió el tiempo de cómputo de la interrupción, resultando ser de 29 microsegundos. La frecuencia a la que se ejecutará dicha interrupción dependerá de la conguración de la línea serie. Para cada dispositivo habrá que tener en cuenta estas interrupciones. Una posibilidad es estimar que en el peor caso existe una tarea periódica de tiempo de ejecución 29 microsegundos y con un periodo igual a la separación mínima entre eventos. Esta separación se obtiene a partir de la velocidad a la que se instancia el dispositivo como se puede ver en la tabla 5.1. Si se instancia el P2OS a 9600 y el láser a 19200, sin hacer ninguna operación más habrá una utilización del procesador del 9.72 % y si además se instancia el GPS (9600) dicha utilización será del 12.96 %. Estos datos son indispensables para poder realizar una planicación correcta de tiempo real. En la gura 5.2 se puede ver la distribución de tareas necesarias para realizar una INT línea serie C=29µs T=833.33µs Rutina de interrupción linea serie Ejemplo de uso del driver P2OS con tareas a 9600bps C = Cómputo T = Periodo Tarea actualiza P2OS Datos P2OS C=620µs T=100ms p2osGetValues Tarea que usa P2OS C=20ms T=300ms lockP2os unlockP2os Valores de ejemplo Figura 5.2: Ejemplo de tareas con tiempos en MaRTE. aplicación en tiempo real cuando se instancia el driver del microcontrolador. Por un lado se puede ver la rutina de interrupción que se ejecuta por haber instanciado el driver del P2OS. Tendremos que crear una tarea para cada dispositivo que funciona a través de la línea serie para tener en cuenta dicha rutina de interrupción. Por otro lado existirá una tarea de actualización de los datos del P2OS que se ejecutará continuamente a la frecuencia a la que se reciben los paquetes de información del micro. Y por último se crearán las tareas necesarias que usen las funciones del driver para realizar una navegación, visualizar datos del micro, etc. Los valores que se muestran para las tareas de manejo de la interrupción y actualización del P2OS corresponden a sus valores reales. Para la otra tarea será necesario medir el tiempo de cómputo (los de la gura son valores de ejemplo). Como se explicó en el apartado 4.4.2, para acceder a las funciones de los objetos protegidos implementados con mutexes es necesario realizar un bloqueo, leer los datos deseados y quitar el bloqueo. Será el usuario el que deba realizar el bloqueo y el desbloqueo correctamente bajo su responsabilidad. Si no se produce el bloqueo el sistema funcionará pero no tendrá un soporte de tiempo real y los datos pueden ser incoherentes. Capítulo 6 Pruebas realizadas y resultados Después de testear a fondo las funciones que se crearon para poder interaccionar con los drivers, se pasó a realizar diferentes aplicaciones para comprobar que todo funcionaba correctamente. 6.1. Navegación autónoma y tiempo real estricto En primer lugar se adaptó un buen algoritmo de navegación para poder usarlo en MaRTE con las funciones que se han implementado en el proyecto. El algoritmo seleccionado usa el láser para obtener información del entorno y el microcontrolador para leer la odometría y actuar sobre los motores. Cuando empieza la ejecución intenta encontrar algún objeto que se encuentre en movimiento usando el láser. En el momento en el que algún objeto se mueve en su rango de visión, comienza a generar nuevos objetivos hacia los que mueve el robot. Para poder estimar estos nuevos objetivos realiza diferentes cálculos matriciales, entre ellos la estimación de la posición del objeto móvil mediante ltros de Kalman [13]. A todo es este proceso se le denomina traking. Además lleva incorporado un sistema de evitación de obstáculos conocido como ND que computa la mejor dirección de movimiento para un vehículo omnidireccional y circular [14]. Este algoritmo realiza gran cantidad de cálculos y por tanto su ejecución ocupa el procesador durante bastante tiempo. El esquema general del algoritmo se puede ver en 6.1 Nuevo objetivo traking Evitación de obstáculos ND Nuevo movimiento Obstáculos (sensores) Robot Figura 6.1: Algoritmo de navegación adaptado a MaRTE. La aplicación está compuesta por varias tareas que interaccionan entre sí modicando y consultando los objetos protegidos (a partir de ahora servidores), generando nuevos 37 movimientos y visualizando algunos datos de interés en una pantalla instalada en el robot. Todo ello bajo el control del tiempo real ofrecido por MaRTE y respaldado por un estudio de tiempos con la política de planicación basada en prioridades estáticas RMS. RMS (Rate Monotonic Scheduling ) establece que la asignación de prioridades más altas a las tareas más frecuentes (periodo más corto) es óptima [5]. Este método de planicación requiere que el plazo de respuesta (tiempo que tiene la tarea para llevar a cabo su trabajo) sea igual al periodo, tal y como sucede en nuestro caso. 6.1.1. Esquema de tareas y cumplimiento de plazos En la gura 6.2 se puede ver el esquema con las tareas, servidores y las diferentes llamadas a los servicios. INT Microcontrolador (9600) C=0.029ms T=0.833ms P=0.833ms Prio HW Rutina de interrupción linea serie Tarea actualiza P2OS C=0.062ms T=100ms P=100ms Prio 22 Tarea de navegación C=50ms T=100ms P=100ms Prio 21 Tarea Visualización Prio 20 C=12ms T=100ms P=100ms INT Láser (19200) C=0.029ms Rutina de T=0.4196ms interrupción P=0.4196ms linea serie Prio HW Prio 22 Servidor P2OS p2osGetValues (B=0.062ms) lockP2os p2osGetXpos p2osGetYpos p2osGetAngle p2osGetXSpeed p2osGetYawSpeed unlockP2os B=0.02186ms Servidor Láser Prio 21 lockLaser laserazo * 361veces GetCounLaser unlockLaser B=1.1226ms Tarea actualiza Láser C=1.867ms T=397.15ms P=397.15ms Prio 19 readLMSValues (B=0.001ms) C = Cómputo T = Periodo P = Plazo B = Bloqueo Figura 6.2: Esquema de las tareas En la tabla 6.1 se se muestra la información sobre las tareas que se usará para realizar 6. Pruebas realizadas y resultados 39 la planicación. Se va a realizar el test de tiempo de nalización y después se calculará la utilización del procesador en esta aplicación.[6] Tarea INT Láser INT Micro Actualiza P2OS Navegación Visualización Actualiza Láser Servidor P2OS Servidor Láser Periodo = Plazo 0.4196 0.833 100 100 200 397.5 Cómputo 0.029 0.029 0.062 50 12 1.867 Bloqueo 0 0 0.02186 1.1226 0.001 0 Techo de prioridad Prioridad HW HW 22 21 20 19 22 21 Cuadro 6.1: Información sobre las tareas. Test de tiempo de nalización En esta aplicación las tareas se comunican entre sí a través de los servidores que guardan los valores correctos del micro y del láser. Para poder realizar una planicación correcta, se debe estudiar cómo se verán afectadas las prioridades de las tareas al usar los servicios (funciones) que ofrecen dichos servidores. Se decidió usar un protocolo de techo de prioridad inmediato, que establece que una tarea que acceda a un recuso hereda inmediatamente el techo de prioridad del servidor. Este protocolo lo proporciona MaRTE y es sencillo de comprender. Para realizar el análisis de cumplimiento de plazos hay que obtener en primer lugar los tiempos de ejecución de peor caso tanto de las tareas como de los diferentes servicios que ofrece cada servidor. Estos son los bloqueos entre tareas ejecutándose con un protocolo de techo de prioridad inmediato: Bloqueo de las rutinas de interrupción: Ambas tareas se ejecutan a prioridad hardware (prioridad establecida por MaRTE). Como se ejecutan a la misma prioridad habrá que tener en cuenta que cualquiera de las dos tareas puede retrasar a la otra. Para tener esto en cuenta cada tarea tendrá como termino de expulsión a la otra. Bloqueo de la tarea que actualiza P2OS: Seleccionamos los servidores de prioridad mayor o igual que la tarea que actualiza p2os. Seleccionamos las tareas de menor prioridad y buscamos el servicio más largo que es llamado por una tarea de menor prioridad en alguno de los servidores anteriores. En este caso la tarea navegación llama a las funciones entre lockP2os y unlockP2os creando un bloqueo de 0.02186ms. Bloqueo de la tarea navegación: De la misma forma calculamos el bloqueo para esta tarea. En este caso el servicio más largo es utilizar las funciones entre lockLaser, unlockLaser, llamado por la tarea visualización. Produce un bloqueo de 1.226ms. Bloqueo de la tarea visualización: Esta tarea es bloqueada durante tan solo 0.001ms por la tarea actualiza láser con el servicio readLMSValues que tan sólo bloquea y desbloquea el mutex para cambiar el valor de la variable que determina el búfer de lectura escritura dentro del driver del láser. Bloqueo de la tarea actualiza láser: No existen tareas de menor prioridad así que la tarea no será bloqueada. A continuación comprobaremos el cumplimiento de plazos de las tareas calculando el trabajo requerido al procesador en los plazos de respuesta de cada tarea. W (Di ) = X Di d e ∗ Cj + Ci + Bi ≤ Di Pj j<i (6.1) Tarea INT láser: W (D0 ) = P j<0 d D0 e ∗ Cj + C0 + B0 = 0,029 + 0,029 + 0 = 0,058 < 0,4196 Pj Tarea INT P2os: W (D1 ) = P j<1 d 0,833 D1 e ∗ Cj + C1 + B1 = d e ∗ 0,029 + 0,029 + 0 = 0,058 < 0,833 Pj 0,4196 Tarea actualiza P2OS: W (D2 ) = P j<2 d 100 100 D2 e∗Cj +C2 +B2 = d e∗0,029+d e∗0,029+0,062+0,0218 = Pj 0,4196 0,833 10,518 < 100 Tarea navegación: D3 100 100 100 e ∗ Cj + C3 + B3 = d e ∗ 0,029 + d e ∗ 0,029 + d e∗ Pj 0,4196 0,833 100 0,062 + 50 + 1,122 = 61,654 < 200 W (D3 ) = P j<3 d Tarea visualización: W (D4 ) = 0,062 + d P j<4 d D4 200 200 200 e ∗ Cj + C4 + B4 = d e ∗ 0,029 + d e ∗ 0,029 + d e∗ Pj 0,4196 0,833 100 200 e ∗ 50 + 12 + 1,867 = 134,191 < 200 100 Tarea actualiza láser: W (D5 ) = P j<5 d D5 397,15 397,15 397,15 e ∗ Cj + C5 + B5 = d e ∗ 0,029 + d e ∗ 0,029 + d e∗ Pj 0,4196 0,833 100 6. Pruebas realizadas y resultados 0,062 + d 41 397,15 397,15 e ∗ 50 + d e ∗ 12 + 1,867 + 0 = 267,873 < 397,15 100 200 Se puede observar que todas las tareas nalizan antes de su plazo de respuesta y por lo tanto el test de nalización se supera sin problemas. Utilización del procesador La utilización del procesador (U) para n tareas con prioridades asignadas en orden de frecuencia, se calcula con la siguiente expresión: U (n) = n X Ci i=1 Pi (6.2) Tras realizar los cálculos correspondientes la utilización total es del 66.83 % para las 6 tareas de la aplicación. El resto del procesador puede ser usado por tareas con menor prioridad sin problemas. 6.2. Comunicaciones en tiempo real Para demostrar que la comunicación inalámbrica del robot funcionaba correctamente se desarrolló la siguiente aplicación. En la gura 6.3 se puede observar un esquema de los elementos que componen la aplicación. Por un lado se dispone del robot iniciado con MaRTE constituyendo un nodo de la red RT-WMP (nodo 0). Cualquier otro ordenador de la sala se puede iniciar con MaRTE (nodo 1) para que haga de estación de control del robot. Se ha realizado una aplicación que permite: Manejar el robot desde la estación de control mediante el teclado. Visualizar en la estación de control los datos más importantes que están disponibles en el robot. Con esta aplicación se pretende poner de maniesto que es posible realizar el control del robot desde un ordenador y mandar los comandos pertinentes al robot. El protocolo sobre el que se ejecuta la aplicación (RT-WMP) es un protocolo determinista que tiene todos los tiempos de envío y recepción acotados. La comunicación es determinista y las aplicaciones que se ejecutan sobre el ordenador y el robot también lo son. Este es sólo un ejemplo sencillo de lo que se puede conseguir utilizando los elementos que se han desarrollado en este proyecto. Se establecen las bases para investigar en aplicaciones multi-agente. Por ejemplo con estos recursos se podrían desarrollar aplicaciones en las que un conjunto de robots comparten información para ampliar o mejorar su conocimiento del entorno. Si uno de los robots dispone de una cámara y obtiene información importante puede compartirla con los robots que estén a su alrededor. Si un equipo de robots están realizando una misión en la cual deben moverse unos cerca de otros y uno de ellos dispone de GPS puede informar Estación de control + + Da órdenes & Visualiza datos ______________________________________________________ | | | *** * ****| Posición * ** * ** * * * * |* | ***** ****| x = 1.454 * ** * ** * * * * |* * | ***** ****| y = 0.321 * *** |***** ******* | * * * * * * * * * * * * * * * * * * * * * * * * |* * | rot = 0.675 | ****** ***** ****| |************* * | *************** **** * * * * * * * * * * * * * * | | Velocidad | * ** * * |************* * **** ** ***** ****| | trans = 0.1 * ** * * |************* * **** ** ***** ****| | * * * * * * * * * * * * * * * * * * * * ** ** |********** Láser | ang = 0.2 | * ** * * |************* * **** ** ***** ****| | Odometría ______________________________________________________ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |* * | Movimiento | | q: + vtrans w: + vrot | | a: - vtrans s: - vrot | | ______________________________________________________ esc: terminar | | Teclado RT-WMP Robot + Ejecuta órdenes & Envía datos Figura 6.3: Navegación del robot a través de comunicación inalámbrica y control. al resto de la posición en la que están. Estos son sólo algunos ejemplos de las posibilidades que ofrece un buen sistema de comunicación, y la importancia de hacerlo con restricciones de tiempo real para aplicaciones de control. 6.3. Resultados Hasta ahora todo el trabajo que se había realizado sobre los robots se había hecho sobre Linux utilizando Player. Los robots ejecutan los nuevos algoritmos que se van desarrollando sin problemas aparentes. Es complicado convencer y demostrar a alguien que este trabajando con los robots como se ha hecho hasta ahora de que trabajar con MaRTE es una opción mucho mejor. El problema es que los robots se usan con la nalidad de comprobar si un tipo de aplicación se ha implementado correctamente y poco más. Los robots hasta ahora no se han usado teniendo en mente conceptos como robustez, determinismo, tolerancia a fallos o rendimiento. Tras este proyecto todos los dispositivos que se han desarrollado funcionan perfectamente en el robot. La persona que desee realizar una aplicación en MaRTE tiene a su disposición un conjunto de funciones prácticamente idénticas a las que proporciona Player para controlar el robot. Existen además otras funciones que se deben conocer y usar para que las tareas funcionen correctamente en tiempo real. Para poder ver en que situaciones MaRTE OS permite controlar mejor al robot que Linux, se realizaron una serie de experimentos. El robot debía moverse en línea recta a una distancia de 4 metros con diferentes niveles de carga en el sistema y a diferentes velocidades. Se desarrolló una aplicación para Linux y otra para MaRTE que realizaban el mismo movimiento. Con esta prueba se pretendía observar si el robot se comportaría igual en SO diferentes. Los resultados se muestran en la tabla 6.2. 6. Pruebas realizadas y resultados 43 Prueba realizada Velocidad Distancia recorrida (cm) Error (%) Linux 0.2 m/s 410 2.5 MaRTE 0.2 m/s 402 0.5 Linux 0.4 m/s 420 5 MaRTE 0.4 m/s 404 1 Linux con carga 0.2 m/s 500 25 MaRTE con carga 0.2 m/s 402 0.5 Cuadro 6.2: Resultados obtenidos. Pruebas sin carga en el sistema En la primera prueba MaRTE únicamente estaba ejecutando las tareas de la aplicación que movía el robot cuatro metros hacia delante. Sin embargo en Linux, al existir otros threads en ejecución, la aplicación que movía al robot no disponía del procesador en los instantes precisos. Cuando el robot llegaba a los cuatro metros, no se paraba y seguía andando un poco más. La aplicación tiene que obtener el procesador para leer el valor de la distancia recorrida, comprobar que es 4 metros y volver a pedir el procesador para decirle al microcontrolador que tiene que parar las ruedas. Todo ese tiempo que transcurre desde que el robot llega al objetivo y el microcontrolador recibe la orden, el robot sigue moviéndose a una velocidad determinada. Cuanto mayor sea la velocidad, mayor será el error que comete. Pruebas con carga en el sistema La siguiente prueba se realizó para demostrar que realmente la carga del sistema estaba provocando los errores que se producían en Linux. Se escribió un pequeño programa llamado computos con un bucle que realizaba muchos cálculos y por tanto requería mucho procesador. Mediante el comando nice -n -10 computos se lanzó en Linux el programa con una prioridad del sistema de -10 (la máxima en este SO es -20). El sistema siguió funcionando y se ejecutó la aplicación que debía mandar al robot a 4 metros. Con el ordenador sobrecargado la aplicación disponía del procesador con mucha menos frecuencia. Esto provocó que desde que llegó a su objetivo hasta que se pararon los motores, pasó mucho más tiempo y por lo tanto se desplazo más distancia. En MaRTE se lanzó la aplicación de la misma forma con otra tarea más que realizaba los mismos calculos que el programa computos. Se le asignó una prioridad menor que a las demás tareas del sistema. El resultado fue el mismo que ejecutar la aplicación sin carga. Esto es debido a que la tarea de menos prioridad no afecta a las demás. En la tabla anterior se pueden observar los errores cometidos en las diferentes pruebas. El robot funciona más o menos bien en Linux cuando no hay sobrecarga, pero si en un momento dado el SO decide realizar otras tareas el robot se ve perjudicado. Esto es un problema muy grave en una aplicación de control. Capítulo 7 Conclusiones y trabajos futuros 7.1. Conclusiones Durante el desarrollo del proyecto se ha estudiado un nuevo SO destinado al control de tiempo real en aplicaciones empotradas. Los robots disponibles en el laboratorio suponen una plataforma de trabajo perfecta para poder comprobar la potencia de un SO de estas características. Se han estudiado diferentes dispositivos y se han programado los drivers que permiten a MaRTE OS comunicarse con ellos. Tras varios meses de trabajo están disponibles diferentes herramientas para trabajar con el robot desde un nuevo punto de vista. Aunque hasta ahora los robots funcionaban más o menos bien, era indispensable disponer de un SO able para poder afrontar nuevas aplicaciones con mayores exigencias. Ahora se dispone de los elementos adecuados para controlar de forma able y determinista los robots. En el capítulo 6 se han visto diferentes aplicaciones que funcionan perfectamente y demuestran que este nuevo sistema cumple los objetivos planteados. Además se ha explicado y demostrado porqué un robot ha de trabajar utilizando un SO de tiempo real como MaRTE. Los resultados ponen de maniesto las limitaciones que tiene un SO de propósito general como Linux. En denitiva un sistema de control para el robot funciona mucho mejor en MaRTE que en Linux. Las herramientas que proporciona este proyecto permiten estudiar mejor diferentes protocolos y sistemas de tiempo real. La posibilidad de estudiar el protocolo de comunicación RT-WMP en un SO de tiempo real permite denir de forma precisa tiempos de funciones, retardos, bloqueos, etc. Este es sólo un ejemplo, pero seguro que en el futuro aparecerán nuevas aplicaciones que utilicen MaRTE. Al haber trabajado con los diferentes dispositivos a tan bajo nivel, se ha podido comprender mejor el funcionamiento del hardware del robot. Conguraciones nuevas no usadas anteriormente o comandos que mejoraban el movimiento han sido sólo algunas de las aportaciones. 44 7. Conclusiones y trabajos futuros 45 7.2. Dicultades encontradas En primer lugar MaRTE es un SO que actualmente está en desarrollo. Pese a que en la página de distribución de la aplicación se aporta mucha documentación, a veces la documentación existente no es suciente para encontrar la solución a los problemas que van surgiendo. Además al tratarse de un SO relativamente nuevo, aparecieron problemas con algunos drivers. La línea serie es el elemento fundamental mediante el cual se conectan varios de los dispositivos del robot. Cuando se afrontó la programación del láser aparecieron errores debido al uso intensivo que éste hace de la línea serie. Encontrar el fallo y solucionarlo retrasó el proyecto más de un mes. Finalmente la solución que se encontró pasó a formar parte de MaRTE OS. El driver PCMCIA para MaRTE tampoco estaba implementado cuando empezó el proyecto, aunque fue posible usarlo unos meses más tarde. Por último, el desarrollo de aplicaciones empotradas es un campo en el que no estaba experimentado. El hecho de programar en un sitio y probarlo en otro (en este caso un robot) supone invertir muchas horas de trabajo para cargar la aplicación, reiniciar el robot, etc. 7.3. Trabajos futuros En el apartado 4.4.2 se explica como se trató de solucionar el problema que presentaba el controlador de la línea serie en MaRTE. Tras varias semanas se pudo solucionar parcialmente consiguiendo usar el láser a una velocidad de 19200bps pero no a la siguiente velocidad de 38400bps. Solucionando este problema, el láser podrá ser usado con todo su potencial. El protocolo de comunicación RT-WMP no dispone de interfaz para poder usarlo desde un programa Ada. La gestión de tareas en Ada es mucho más exible que en C. Sería interesante poder juntar las ventajas de Ada y las posibilidades del protocolo. Hay muchos otros sensores que pueden ser integrados también para MaRTE aumentando así las capacidades del robot. Sería interesante poder usar cámaras desde el punto de vista del tiempo real. Pero lo más importante es que se abre un nuevo campo de investigación para aplicaciones robóticas que hasta ahora no estaba disponible. A partir de ahora ya no sólo se van a poder probar aplicaciones que muevan al robot. Se puede ir más allá y exigir al robot que realice diferentes tareas tal y cómo se ha planicado previamente. El usuario ahora controla totalmente lo que hacen los dispositivos, las tareas y el procesador. Bibliografía [1] Mario Aldea Rivas y Michael González Harbour. MaRTE OS: An Ada Kernel for Real-Time Embedded Applications, 2001. [2] Mario Aldea. Planicación de Tareas en Sistemas Operativos de Tiempo Real Estricto para Aplicaciones Empotradas, 2002. [3] Daniel Sangorrin. Hello MaRTE using an emulator, tutorial para MaRTE, Mayo 2005 [4] Daniel Sangorrin. Gestión de dispositivos de entrada/salida analógica, digital y por el bus serie I2C, proyecto n de carrera, Febrero 2006 [5] Liu, C.L., Layland, J.W.. Scheduling Algorithms for Multiprogramming in a Hard Real- Time Environment, 1973. [6] José Luis Villarroel Salcedo. Sistemas de Tiempo Real, apuntes de la asignatura . [7] Danilo Tardioli y J. L. Villarroel. Real-Time Communications over 802.11: RT-WMP, The Fourth IEEE International Conference on Mobile Ad-hoc and Sensor Systems, 2007. [8] Francisco Guerreira. Entorno para la instalación y utilización de manejadores de dispositivos en MaRTE OS, proyecto n de carrera, Marzo 2003. [9] José Luis Mantecón. Desarrollo de una librería gráca para MaRTE OS, proyecto n de carrera, Diciembre 2003. [10] Óscar García Grasa. Robotización de una aplicación de supervisión agrícola, proyecto n de carrera, Junio 2007 [11] Pioneer3 & Pioneer2 H8-Series http://www.mobilerobots.com. 46 Operation Manual. Disponible en BIBLIOGRAFÍA 47 [12] GPS Novatel Manual, disponible en http://www.novatel.com/. [13] L. Montesano, J. Minguez y L. Montano. Modeling the Static and the Dynamic Parts of the Environment to Improve Sensor-based Navigation. In Proceedings of the International Conference on Robotics and Automation (ICRA), 2005, Barcelona, España . [14] Minguez J,., Montano L. Nearness Diagram Navigation (ND): Collision Avoidance in Troublesome Scenarios. IEEE Transactions on Robotics and Automation. Vol. 20, No. 1, 2004. Apéndice A Fases del proyecto y diagrama de Gantt A.1. Hitos temporales En Diciembre de 2006 comencé a realizar una beca de colaboración en el laboratorio de Robótica, Percepción y Tiempo Real del Departamento de Informática e Ingeniería de Sistemas (DIIS). Durante la beca estudié y realicé diferentes pruebas de la calidad de la señal en comunicaciones inalámbricas. Además comencé a trabajar con los robots y conocer su funcionamiento. En Abril de 2007 decidí realizar este proyecto. El proyecto une los sistemas de tiempo real, los sistemas empotrados, los sistemas operativos y la robótica. Estas fueron algunas de las razones por las que decidí realizar este proyecto. El primer paso fue estudiar a fondo el sistema operativo MaRTE OS (instalación, método de trabajo, cheros, instalación de drivers). El siguiente paso fue conseguir tener un sistema de desarrollo adecuado para trabajar con el robot y arrancar el sistema operativo a través de la red. En Junio comencé a analizar, diseñar, implementar y probar cada uno de los drivers uno por uno. Comencé por el del micro, cuando funcionó completamente pasé al driver del láser y por último el GPS. Durante toda esta fase fueron apareciendo problemas debido a que un elemento importantísimo de MaRTE OS no funcionaba correctamente; la línea serie. Después de muchos quebraderos de cabeza se encontró el problema y se solucionó. En Septiembre la Universidad de Cantabria envió el driver de PCMCIA. Este elemen- to era indispensable para poder integrar la tarjeta inalámbrica en el robot. Se consiguió hacer funcionar la tarjeta y además se adaptó el protocolo RT-WMP al sistema operativo MaRTE. Finalmente en Octubre se realizaron diversas aplicaciones usando todos los recursos generados en el proyecto. Navegación autónoma, navegación remota o visualización en Tiempo Real son algunas de las aplicaciones realizadas. Hay que destacar que desde la elección del proyecto comencé a recopilar documentos y redactar los apartados que componen este proyecto. En la gura A.1 se pueden ver con más detalle todas estas tareas avanzando en el tiempo. 48 A. Fases del proyecto y diagrama de Gantt 49 A.2. Diagrama de Gantt A continuación se muestra la distribución temporal de las tareas más importantes del proyecto. También se puede observar que algunas de ellas fueron realizadas en paralelo. Actividad Dic Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Comienzo lectura documentos calidad señal Documentación Robot+ Player/Stage Realización pruebas robot Conclusiones calidad señal Comienzo del Proyecto Estudio sistema operativo MaRTE Arranque en red MaRTE Estudio P2OS + implementación + test Estudio Láser + implementación + test Estudio GPS + implementación + test Revisión linea serie + corrección driver MaRTE Estudio comunicación inalámbrica + implementación RTWMP en MaRTE + test Aplicaciones de prueba Documentación Figura A.1: Diagrama de Gantt Apéndice B Estudio sobre sistemas operativos de tiempo real B.1. Arquitectura de un SO de tiempo real En este capítulo se van a exponer las características más importantes de un sistema operativo de tiempo real, comparando diferentes aspectos con los sistemas operativos convencionales. Se tratan temas como las clases de tiempo real dependiendo de la precisión que necesitemos, el rendimiento, ventajas y desventajas. Al nal se presenta un resumen de algunos SO de tiempo real existentes. B.1.1. Arquitectura de un SO de propósito general La memoria física de un computador está dividida entre el espacio reservado para los usuarios (user-space ) y el espacio reservado para el kernel (kernel-space ). El kernel multitarea es capaz de manejar múltiples aplicaciones de usuarios que ejecutan en el espacio de usuario haciendo creer a cada uno que dispone de todo el espacio de memoria y de todos los recursos hardware. La comunicación entre los programas en el espacio de usuario y el espacio del kernel se realiza a través de las llamadas al sistema. Estas llamadas típicamente lo que hacen es acceder a recursos físicos compartidos. Todos los accesos a los recursos hardware son controlados por el kernel de modo que los programas de usuario no conozcan los detalles físicos de los dispositivos. Las funcionalidades principales de un SO de propósito general son: Gestión de procesos. Planicación de procesos. Gestión de memoria. Interactuar con el Hardware. Servidor de Ficheros. Servidor de Comunicaciones. La funcionalidad principal y requerida para un sistema operativo de tiempo real es proveer de un nivel de servicio adecuado a las aplicaciones que requieran una respuesta 50 B. Estudio sobre sistemas operativos de tiempo real 51 en un intervalo de tiempo determinado. La característica principal de un sistema operativo de tiempo real es la respuesta ante eventos internos ó externos, tales como interrupciones hardware externas, interrupciones software internas ó interrupciones de reloj internas, es decir los requerimientos temporales. Una de las medidas de rendimiento de un SO de tiempo real es la latencia, ó tiempo desde que ocurre el evento y éste es tratado. La otra medida es el jitter, ó variaciones en el periodo normal de ocurrencia de eventos periódicos. Todos los sistemas operativos tienden a tener una baja latencia y un bajo jitter, pero los sistemas operativos de tiempo real requieren que esos valores estén determinados y que no dependan de la carga del sistema. B.1.2. Clases de tiempo real Un programa ó un sistema operativo es considerado como de tiempo real, si a pesar de las restricciones de tiempo le permiten trabajar y funcionar correctamente. Se distinguen las siguientes clases: Tiempo real estricto (Hard Real Time ): Todas las acciones deben ocurrir dentro del plazo especicado. Tiempo real exible (Soft Real Time ): Se pueden perder plazos de vez en cuando. El valor de la respuesta decrece con el tiempo. Tiempo real rme (Firm Real Time ): Se pueden perder plazos ocasionalmente. Una respuesta tardía no tiene valor. B.1.3. Características de rendimiento El criterio fundamental de evaluación del rendimiento de un sistema operativo de tiempo real es la latencia y el periodo del jitter ante un evento. Un evento es cualquier tipo de interrupción, tanto interna, como externa. Latencia en un evento. Un evento puede ser tanto una interrupción hardware como una interrupción software. La latencia ante una interrupción hardware es el tiempo desde que se produce la interrupción hasta que se ejecuta la primera instrucción de la rutina de tratamiento. Puede haber retrasos debido al acceso al bus. La latencia ante una interrupción software es el tiempo desde que la señal es generada hasta que la primera instrucción de la tarea es ejecutada. Aquí el valor depende únicamente del acceso a los registros del procesador. Periodo del jitter. El periodo del jitter se reere a las variaciones en el tiempo que experimenta una tarea cuando se ejecuta de manera repetitiva. B.1.4. Arquitectura de un SO de tiempo real El objetivo de un sistema operativo de tiempo real es reducir la latencia y el jitter en las interrupciones, tanto internas como externas, al orden de microsegundos. Es decir, la parte fundamental para convertir un sistema operativo de propósito general en un sistema operativo de tiempo real es el manejo de las interrupciones. El procesamiento de interrupciones en el kernel estándar está divido en 2 tareas. Una tarea que se encarga de leer los datos del dispositivo físico y escribirlos en un búfer, es lo que se conoce como manejador de interrupciones, y una tarea que se encarga de pasar los datos del búfer a otro para que sean accesible por el kernel. Con este esquema, cuando el manejador está ejecutando, todas las interrupciones están inhibidas con el siguiente retardo impredecible en el servicio de otras interrupciones que se puedan haber producido y por tanto en los valores de latencia y jitter. Para conseguir reducir la latencia y el jitter se han desarrollado distintas alternativas que modican el kernel de Linux en este aspecto fundamentalmente. Actualmente hay dos corrientes de diseño: Atención prioritaria en el kernel estándar (Preemptable kernel ) Esta metodología modica el kernel en profundidad de forma que los procesos de kernel ejecuten con máxima prioridad de forma que puedan interrumpir a procesos de menor prioridad en el acceso a los recursos que necesiten. Esta metodología implica cambios en los manejadores de interrupciones para que las interrupciones de alta prioridad no sean bloqueadas por el manejador de interrupciones mientras está manejando otra de menor prioridad. El resultado de esta metodología es una latencia y un jitter del orden de 1 milisegundo en un Pentium a 100 Mhz. A partir de la versión 2.5.4 del kernel de Linux se incorpora esta metodología. B. Estudio sobre sistemas operativos de tiempo real 53 Como se puede observar en la gura la tarea de tiempo real está controlada por el planicador del kernel y es una más de las tareas que controla el kernel. Esta tarea hace referencia a los procesos de tiempo real en el espacio de usuario. El planicador sabe que las tareas de tiempo real tiene mayor prioridad que las tareas que no son de tiempo real. Como se puede comprobar esta metodología es adecuada para aplicaciones de audio y vídeo donde el periodo de interrupciones es del orden de 1 milisegundo, pero inadecuado cuando ya hablamos de menos de 1 milisegundo. Benecios y limitaciones de la estrategia de kernel preemptable : Ventajas Desventajas Desarrollo de aplicaciones de tiempo real más fácil El rendimiento no es lo suficientemente bueno para los requerimientos de baja latencia en el rango de microsegundos Protección de memoria disponible El peor caso de latencia de una interrupción es desconocido ya que no es posible testearlo Los programas de tiempo real no pueden quebrar el kernel Cambio fuerte en el código fuente del kernel Acceso completo a los servicios del sistema (TCP/IP,Cada vez que sale una nueva versión del kernel I/O) es necesario un test profundo Threads de POSIX disponibles para las funciones de Para realizar el análisis de funcionamiento son tiempo real necesarios todos los drivers de dispositivos y módulos Soporte de herramientas para facilitar la depuración Rendimiento global del sistema reducido Modicaciones sobre el kernel estándar (Patch ) Existen 4 estrategias de modicación del kernel de Linux para proveer capacidades de tiempo real. Tres de ellas implican añadir un segundo kernel (dual) para manejar las tareas de tiempo real y el cuarto implica modicar directamente el código del kernel para añadir características de tiempo real. Benecios y limitaciones de la estrategia de kernel dual: Ventajas Cambios de contexto y latencia de interrupciones muy bajo (5 - 10 microsegundos) Desventajas Todas las características de tiempo real deben ser implementadas como módulos El kernel estándar de Linux ejecuta como una tarea El desarrollo de aplicaciones de tiempo real es de baja prioridad del microkernel mucho más complicado Capa de abstracción hardware e interrupciones Se debe ser conocedor de Linux en profundidad Garantizada una planificación determinística Interacción entre el kernel y los drivers de los dispositivos Código incorrecto puede provocar el fallo del kernel Más difícil depurar el código Las llamadas al sistemas de Linux no pueden tomar el control y el rendimiento no puede ser garantizado • Micro-kernel Esta estrategia añade un segundo kernel que en realidad es una capa interfaz entre el hardware y el kernel estándar, lo que se llama tradicionalmente HAL Hardware Abstraction Layer . Esta capa, micro-kernel, controla la ejecución de las tareas de tiempo real y ejecuta el kernel estándar como una tarea en background, es decir, el kernel estándar sólo ejecuta cuando no hay tareas de tiempo real pendientes. Una implementación de esta estrategia es ADEOS. Los desarrolladores de este proyecto fueron precisamente los que pusieron el nombre de nano-kernel para diferenciarlo claramente de la estrategia de micro-kernel patentado por Yodaiken. • Extensión con un nuevo kernel de acceso a los recursos (Recurso-kernel ) Esta estrategia añade un kernel de forma que éste proporciona una puerta de acceso a los recursos, tales como al sistema de cheros, al puerto paralelo, etc, tanto para el kernel estándar como para los procesos de usuario. El recurso kernel no sólo captura las interrupciones sino que proporciona un mecanismo donde los programas de usuario pueden requerir, reservar y garantizarse un porcentaje nito de los recursos como pueden ser de CPU, memoria, etc. • Extensiones POSIX de tiempo real añadidas al kernel Esta estrategia consiste en modicar directamente el kernel estándar de Linux para añadir librerías que implementan las extensiones de tiempo real de POSIX. El resultado es un kernel conforme al estándar IEEE 1003.1d. No añade un segundo kernel. B. Estudio sobre sistemas operativos de tiempo real 55 Las modicaciones realizadas al kernel consisten en la implementación de relojes, señales, semáforos, memoria compartida, planicador por prioridades, etc según lo especicado en IEEE 1003.1d. Existen 2 aproximaciones diferentes para esta estrategia: • KURT (The Kansas University Real Time Linux) que únicamente implementa los relojes conforme al estándar IEEE 1003.1d. • TimeSys Linux. Añade al preemptable kernel un planicador de kernel que proporciona una latencia y un jitter menor de 100microsegundos. El parche con el planicador no proporciona una alta resolución en los relojes, que es necesaria para tareas de tiempo real repetitivas. B.1.5. Rendimiento del sistema Si comparamos por ejemplo el kernel estándar con RTLinux podremos observar claramente como existe gran diferencia tanto en la latencia en las interrupciones como en el jitter, siendo mucho menos para el caso de RTLinux y siempre en el orden de 1 a 10 microsegundos para un Pentium a 100Mhz. Si comparamos entre si las distintas estrategias de diseño de un sistema operativo de tiempo real podremos observar que las diferencias no son tan amplias si las comparamos con el kernel estándar. SO estándar Aplicación No Tiempo-Real Latencia/Jitter 100µs a 100ms Linux(>2.5.X) estándar IEEE 1003.1d Soft Real-Time 1ms Hard Real-Time 10 a 100µs Micro-Kernel Hard Real-Time 1 a 10µs RTOS Kernel Hard Real-Time 1 a 10µs B.2. Algunos de los SO de tiempo real más usados B.2.1. Introducción Vamos a realizar una breve descripción de la arquitectura, licencia y entorno para el cual están diseñados los S.O.T.R. que hemos escogido. Algunas de éstos están en continuo desarrollo y otros por el contrario están un poco estancadas ó denitivamente olvidadas, pero que son nombrados porque nacieron con el objetivo de proporcionar una nueva característica ó una nueva losofía de diseño que otros S.O.T.R. no proporcionaban y que otras han seguido posteriormente. Distribución ADEOS RT-Linux MaRTE VxWorks Licencia GNU/GPL Comercial GNU/GPL Comercial B.2.2. ADEOS (Adaptative tems ) Arquitectura Nano-kernel Micro-kernel Extensiones POSIX Micro-kernel Domain Environment Operating Sys- El objetivo de ADEOS es proporcionar un entorno exible para compartir los recursos hardware para múltiples sistemas operativos ó múltiples instancias de un mismo sistema operativo. ADEOS activa múltiples kernels, llamados dominios, que existen simultáneamente sobre el mismo hardware. Ninguno de éstos dominios necesariamente conoce la existencia del resto, pero todos ellos si conocen de la existencia de ADEOS. Un dominio puede ser un SO completo, pero no necesariamente. La licencia de ADEOS es GNU/GPL. La arquitectura de ADEOS es la de kernel dual y más especícamente la llamada Nano-kernel. Dominios y Pipeline. Para permitir que las interrupciones y los eventos del sistema sean repartidos para compartir por los múltiples kernels (normalmente SO completos), ADEOS dene lo que ha llamado abstractamente "dominio". Un dominio es un componente software del kernel base al cuál ADEOS puede noticar: Las interrupciones hardware. Llamadas al sistema de las aplicaciones Linux. Eventos del sistema lanzados por el kernel de Linux. Otros eventos que personalicemos nosotros. Un dominio puede ser accesible como un módulo dinámico del kernel, ó como uno estático formando parte de una imagen del kernel, no produciendo ningún tipo de incidencia en el comportamiento de ADEOS. ADEOS también puede asegurar que los eventos sean disparados en el orden correcto para los distintos dominios denidos, gracias a ello, es posible proporcionar determinismo. Esto nos permite asignar a cada dominio una prioridad estática. El valor de esta prioridad B. Estudio sobre sistemas operativos de tiempo real 57 determina el orden en que los eventos son tratados por los dominios. Todos los dominios son encolados de acuerdo a sus respectivas prioridades, formando un pipeline de forma abstracta, que es el que usa ADEOS para manejar el ujo de eventos desde el más prioritario hacia el menos prioritario. Los eventos de entrada son encauzados a la cabecera del pipeline (dominio más prioritario) y progresan hacia la cola (dominio menos prioritario). El código del kernel de Linux es enteramente el sólo un dominio especial predenido, que es creado por ADEOS en las primeras etapas de carga de Linux. Este dominio inicial normalmente hace referencia al dominio "root "hasta que la infraestructura proporciona lo suciente para cargar el resto de dominios dinámicamente (ej. el módulo cargador del kernel ). Modo de Trabajo. ADEOS controla todas las interrupciones, los traps de la CPU y las excepciones del nivel hardware, ya que reprograma el software del manejador. De hecho, ADEOS actualmente reemplaza los manejadores instalados anteriormente por Linux durante el arranque por los suyos propios para las correspondientes interrupciones y eventos. En la plataforma x86, se hace simplemente cambiando el descriptor de interrupción de la tabla. En cualquier momento dada una CPU con ADEOS activado, un dominio puede estar: Ejecutándose. Interrumpido por un dominio más prioritario durante el procesamiento de una interrupción/ evento de entrada mientras el estaba procesando un evento pendiente. Voluntariamente autosuspendido, después de que todas las interrupciones/eventos hayan sido procesados. Cuando un dominio ha nalizado de procesar una interrupción/evento que ha recibido, llama a un servicio especial de ADEOS (adeos_suspend_domain() ) el cual provoca que se pase la interrupción/ evento al siguiente dominio del pipeline y así sucesivamente, realizándose un ciclo del más prioritario al menos prioritario. Hay que destacar que ADEOS reanuda un dominio sólo si tiene que procesar una interrupción/evento ó si ocurre que ha sido interrumpido por un dominio más prioritario que ha recibido alguna interrupción/ evento para procesar, en otras palabras, no se produce intercambio entre dos dominios a menos que haya trabajo pendiente para alguno de ellos. Cuando una interrupción ocurre en un sistema ocioso, ADEOS despierta al dominio más prioritario interesado en ella y el ciclo de proceso del pipeline comienza de nuevo. ¾Por qué puedes necesitar ADEOS? Porque necesitas controlar determinísticamente el ujo de interrupciones hardware usando una capa software antes de que el kernel de Linux las procese. Este control incluye la interceptación, el enmascarado y/o la priorización de las interrupciones. Porque necesitas monitorizar las llamadas al sistema de Linux, añadiendo más información y sin tener que modicar el código de las llamadas al sistema. Porque quieres un mecanismo para monitorizar los eventos internos que ocurren en el kernel de Linux como pueden ser la planicación de tareas, la creación de procesos ó las señales que capturan las tareas. Implementación de un dominio. El interfaz entre un dominio y ADEOS esta compuesto de: Un descriptor, que es una estructura de datos que describe las propiedades del dominio en el tiempo. Una rutina de entrada al dominio, a la cual ADEOS llama para iniciar un dominio. Esta rutina se encarga de registrar el conjunto de interrupciones/ eventos que va a manejar y a continuación el dominio pasa a ejecutar el bucle ocioso. Enlaces: ADEOS (web ocial distribución) http://www.opersys.com/adeos/ ADEOS (web ocial desarrollo) https://gna.org/projects/adeos/ Documentos: Diseño Adeos: http://gayuba1.datsi..upm.es/ dlopez/cache/doc/adeos.design.pdf Adeos: http://gayuba1.datsi..upm.es/ dlopez/cache/doc/porting.txt RTOS sobre ADEOS: http://gayuba1.datsi..upm.es/ dlopez/cache/doc/rtos.over.adeos.pdf B.2.3. RTLinux RTLinux es un SO de tiempo real que ejecuta Linux como un thread de menos prioridad que las tareas de tiempo real. Con este diseño, las tareas de tiempo real y los manejadores de interrupciones nunca se ven retrasados por operaciones que no son de tiempo real. La primera versión de RTLinux estaba diseñada para ejecutarse en la plataforma x86 y proporcionaba una pequeña API y un pequeño entorno de programación. La versión 2, que fue totalmente reescrita, fue diseñada para el soporte de multiprocesamiento simétrico (SMP) y para ser ejecutada en una amplia variedad de arquitecturas. RTLinux proporciona la capacidad de ejecutar tareas de tiempo real y manejadores de interrupciones en la misma máquina que el Linux estándar. Estas tareas y los manejadores ejecutan cuando se necesitan en detrimento de lo que estuviera ejecutando Linux. El peor caso de tiempo es entre que se detecta la interrupción hardware y el procesador ejecuta la primera instrucción del manejador de la interrupción. Este tiempo es del orden de los 10 microsegundos en la plataforma x86. Actualmente hay 2 versiones de RTLinux: B. Estudio sobre sistemas operativos de tiempo real 59 RTLinux/Open: Disponible bajo la licencia GPL, pero que ya no se trabaja en ella desde 2001. RTLinux/Pro: Distribución comercial. Ambas versiones son distribuidas por la empresa FSMLabs. La arquitectura de diseño de RTLinux se encuentra patentada por FSMLabs. Una versión de la patente se encuentra accesible en el enlace: http://www.fsmlabs.com/products/rtlinuxpro/rtlinux_patent.html. Y en aquí se puede ver que la FSF (Free Software Foundation ) esta de acuerdo en los términos de la patente. http://www.gnu.org/philosophy/rtlinux-patent.html A través de este otro enlace podemos leer una pequeña reexión sobre los efectos de la patente en el desarrollo de aplicaciones en RTLinux: http://www.linuxdevices.com/articles/AT2094189920.html. A partir de aquí la descripción que se hace es sobre RTLinux/Open o RTLinux/GPL. Arquitectura. RTLinux es un pequeño y rápido sistema operativo que sigue el estándar POSIX 1003.13: sistema operativo de tiempo real mínimo. RTLinux añade una capa de abstracción hardware entre el kernel estándar de Linux y el hardware de la máquina. Hay 3 modicaciones principales en el kernel de Linux con el objetivo de que RTLinux tenga el control del hardware de la máquina: Control directo de las interrupciones hardware. Control del reloj hardware e implementación de un reloj virtual para Linux. El control de las interrupciones por parte de Linux es reemplazado por 2 funciones que permiten activar ó desactivar las interrupciones, pero las virtuales. Estas modicaciones del kernel de Linux son complejas aunque no requieren excesivo código, pero si más que RTAI. RTLinux proporciona un entorno de ejecución bajo el kernel de Linux, como consecuencia de esto, las tareas de tiempo real no pueden usar los servicios de Linux. Para disminuir este problema, el sistema de tiempo real se ha divido en dos partes: la capa de tiempo real estricto que ejecuta encima de RTLinux, y la capa de tiempo real exible, que ejecuta como un proceso normal de Linux. Para la comunicación de ambas capas se pueden usar varios mecanismos (FIFO, memoria compartida). La propuesta de 2 capas es un método útil para proporcionar tiempo real estricto mientras se mantienen las características de escritorio de un sistema operativo. La separación del mecanismo del kernel de tiempo real del mecanismo del kernel de Linux de propósito general permite optimizar ambos sistemas de forma independiente. Características. Soporte de múltiples arquitecturas y válida para arquitecturas multiprocesador. Gestión de procesos: Planicación, soporte de threads periódicos, amplio rango de prioridades, creación y borrado de threads, etc. Gestión de memoria: No protección de memoria en el kernel y no asignación de memoria de forma dinámica. Comunicación entre procesos: Semáforos, Mutex, control de inversión de prioridades, memoria compartida y FIFO's. Tiempo y relojes: Resolución de nanosegundos. No relojes de usuario. Facilidades para añadir nuevos relojes hardware. Programación de drivers: Se proporcionan funciones de acceso a dispositivos. No proporciona herramientas de calidad de servicio. Enlaces: Página Ocial (http://www.fsmlabs.com, http://www.rtlinux.com, http://www.rtlinux.org) Repositorio RTLinux GPL: http://www.rtlinux-gpl.org Análisis RTLinux/GPL: http://www.mnis.fr/opensource/ocera/rtos/c1450.html B.2.4. MaRTE Aunque es el sistema operativo tratado en el proyecto y ya se ha hecho una descripción de él, pondremos los aspectos tratados en las secciones anteriores en forma de comparativa. Es un SO mínimo de tiempor real para aplicaciones empotradas, que puede ser usado en diferentes plataformas, incluyendo microcontroladores. Cumple un subconjunto POSIX.13. Ofrece los interfaces POSIX para los lenguajes C y ADA. Permite el desarrollo cruzado de aplicaciones de tiempo real C y ADA. Permite el desarrollo de aplicaciones C-ADA. Arquitectura. La parte central del sistema operativo MaRTE está en su kernel, el cual implementa las funcionalidades básicas del sistema. El kernel tiene una interfaz abstracta de bajo nivel para el acceso al hardware. Esta interfaz encapsula operaciones tales como: manejo de interrupciones, manejo del reloj y del tiempo y cambios de contexto en los threads. El B. Estudio sobre sistemas operativos de tiempo real 61 objetivo de esto es facilitar la migración desde una plataforma a otra, ya que lo único que sería necesario cambiar es la capa de abstracción del hardware. En la parte de arriba del kernel hay una interfaz para aplicaciones POSIX.1 (actualmente funciones Ada con la forma de funciones POSIX.1). Esto proporciona dos importantes ventajas: Aplicaciones C pueden usar el kernel directamente, solo son necesarias un conjunto de cabeceras C. La capa de bajo nivel GNARL está por encima de la interfaz POSIX. Esta capa es para adaptarlo al kernel La distribución GNAT que se ha adaptado para que funcione en el sistema operativo MaRTE es la versión estándar desarrollada para Linux. Características. Apropiado para aplicaciones estáticas con el números de tareas y recursos del sistema conocido en tiempo de compilación. Los servicios tendrán tiempo de respuesta limitados. No está protegido. Multiplataforma. Multilenguaje. Entorno de Desarrollo. El entorno de desarrollo es en un PC con Linux. Y el destino para el que se desarrolla en una máquina x86 desnuda. Ambos sistemas están conectados por medio de una red de área local Ethernet (para aplicaciones de arranque) y un cable seria (para depuración remota). El compilador y el linker están basados en GCC y GNAT. El ciclo de desarrollo de una aplicación es bastante rápido e incluye los siguientes pasos: 1. El destino es arrancado con un disco netboot el cual es generado automáticamente durante la instalación del sistema operativo MaRTE. 2. La aplicación es compilada y enlazada en el ordenador de desarrollo usando los comandos mgnatmake o mgcc. 3. En la máquina destino el programa netboot descarga la aplicación que está en el ordenador de desarrollo a través de la Ethernet y lo ejecuta. 4. La aplicación se ejecuta libremente o es depurada remotamente desde el ordenador de desarrollo. 5. Tan pronto como la aplicación naliza el programa netboot de nuevo toma el control de la máquina destino y un nuevo ciclo puede empezar desde el paso 2. Enlaces. Sitio Ocial. http://marte.unican.es B.2.5. VxWorks Es un componente run-time de la plataforma de desarrollo de sistemas empotrados Tornado II (Windows y UNIX). Hay dos versiones de VxWorks: VxWorks a secas, que es de la que hablaremos aquí. Y VxWorks AE, que está diseñado especialmente para alta disponibilidad con la ayuda distribuida de la mensajería y de la alta tolerancia. Características. Herramientas de desarrollo cruzado host-target: • Compilador, Linkador y Cargador para el sistema target. • Depurador remoto. • Determinación de tiempos de ejecución. • Simulador del sistema sobre el host. Soporte de un gran número de placas comerciales mediante Board Support Packages (más de 200), así como de placas a medida: • Inicialización del HW. • Conguración de interrupciones y temporizadores • Memory mapping, etc. Consta de una interfaz con varias APIs (más de 1800 funciones). Es utilizado en diferentes tipos de aplicaciones: desde automoción (Antilock Braking Systems ) a aplicaciones espaciales (Mars PathFinder ), equipamiento de ocina (impresoras, faxes, etc.) y electrodomésticos (microondas, lavavajillas, etc.). Está adaptado a diferentes arquitecturas de CPU tales como: PowerPC, Intel 80x86, Motorola 68K, Intel 80960, ARM, SPARC, etc... Arquitectura. La arquitectura está basada en microkernel, dicho microkernel lo han llamado wind de unos pocos KB que incluye: Planicador multitarea basado en prioridades y con desplazamiento, el cual consta de 256 prioridades y tiene limitado el número de tareas. Primitivas de sincronización y comunicación entre tareas. B. Estudio sobre sistemas operativos de tiempo real 63 Soporte a interrupciones. Gestión de watchdog timers. Gestión de memoria. Al tener una arquitectura modular, el sistema nal puede ser ampliado con diferentes módulos tales como: sistema de E/S, sistemas de cheros soporte para redes, etc.. Por lo tanto el sistema nal es adaptable a cientos de conguraciones diferentes ya que incluso los diferentes módulos son escalables. Los módulos individuales pueden ser utilizados durante el desarrollo y ser omitidos en el sistema nal. Es compatible con la norma POSIX 1003.1 (llamadas básicas al sistema) y 1003.1b (real-time extensions ). Enlaces. Sitio Ocial de VxWorks: http://www.windriver.com/products/device_technologies/os/vxworks6/ http://dmi.uib.es/ aortiz Apéndice C P2OS: El Sistema Operativo del microcontrolador. C.1. Introducción Para la realización del proyecto se ha usado un robot Pioneer 3-AT, distribuido por la empresa ActivMedia Robotics. Este robot contiene todo tipo de sensores y componentes de navegación que le permiten moverse en un entorno real. Es una plataforma perfecta para una gran variedad de proyectos de investigación. A continuación se resume el contenido de [11], dejando claros los puntos más importantes del manual. Para una especicación más detallada consultar [11]. C.1.1. Especicaciones técnicas Cada robot esta hecho con un cuerpo de aluminio, un sistema de movimiento (dos o cuatro ruedas), motores DC reversibles, electrónica de control del motor y conducción, encoders de movimiento de alta resolución, y baterías de larga duración. Todo ello soportado por un microcontrolador embebido sobre el cual está instalado el sistema operativo P2OS C.2, que distribuye ActivMedia. El robot actualmente presenta las siguientes características hardware: CPU Intel Pentium III 850-MHz con 256 MB memoria RAM. 1 Láser Sick LMS 1 Microcontrolador H8-Series. Controla odometría (posición), giróscopo , sonar y bumpers. 1 GPS Novatel. 1 Tarjeta Wi-Fi Conceptronics PCMCIA para comunicación inalámbrica a través de un adaptador PCI 104. 64 C. P2OS: El Sistema Operativo del microcontrolador. 65 C.2. El Sistema Operativo del robot. P2OS La arquitectura de control del robot es de tipo cliente-servidor. Por un lado está el microcontrolador H8-Series dirigido por el P2OS (servidor) y por otro el PC del robot (cliente) conectados mediante el puerto serie. El servidor se encarga de controlar las operaciones de bajo nivel, como manejar los motores, lanzar el sonar, almacenar los valores del sonar y de la información de las ruedas, y otras muchas cosas. El cliente manda comandos para que el servidor los ejecute. Para comunicarse entre ambos se usan dos tipos de paquetes: Comand packet : Cliente ->Servidor. El cliente manda al servidor paquetes con los comandos que quiere que el microcontrolador ejecute en los dispositivos a los que accede. Por ejemplo, el cliente manda un comando de tipo VEL 2 al servidor. Cuando el P2OS recibe ese comando ordena a los motores correspondientes que se muevan a la velocidad correspondiente. Para ver una descripción completa de los comandos ver [11]. Server Information Packet (SIP) : Servidor ->Cliente . El servidor envía cada 100 ms un paquete llamado SIP con información relativa a los dispositivos que controla. Se obtiene información de la odometría (posición), sonar, batería, bumpers, velocidad, etc. Ambos paquetes son cadenas de bits formadas por cinco elementos principales: una cabecera de dos bytes, un byte con el número de bytes que siguen, el comando o paquete SIP, los parámetros del comando o los datos del paquete SIP, y nalmente, dos bytes de checksum. Cada paquete está limitado a 206 bytes. Los diferentes tipos de paquetes se pueden ver en el manual extenso del microcontrolador ([11]). Por su extensión no se expondrán aquí. C.2.1. Conexión Cliente-Servidor Antes de poder ejecutar ningún control sobre el robot, debe de ejecutarse una aplicación cliente que establezca una conexión con el servidor del robot a través del puerto serie. Después de establecer la conexión el cliente podrá enviar comandos y recibir información del servidor. Cadena de sincronización: Para establecer la conexión el cliente debe enviar tres comandos de sincronización SYNC0, SYNC1 y SYNC2. La secuencia de bytes en hexadecimal que el cliente debe enviar es la siguiente: SYNC0: 0xFA, OxFB, 0x03, 0x00, 0x00, 0x00 SYNC1: 0xFA, OxFB, 0x03, 0x01, 0x00, 0x01 SYNC2: 0xFA, OxFB, 0x03, 0x02, 0x00, 0x02 Autoconguración: Tras el comando SYNC2 el servidor manda al cliente los valores que tiene grabados en su memoria ash sobre el nombre (Nombre del robot en cuestión), clase (Pioneer) y subclase (P2AT8, P2DX, ..) del robot. Con esta información el cliente podrá ajustar los parámetros concretos del robot en su aplicación. Abrir el servidor: OPEN Este es el siguiente comando que tiene que mandar el cliente para que el servidor comience diferentes servicios, como el sonar, los controladores del motor, escuche los comandos del cliente, y comience a transmitir paquetes de información (SIP). Comando en hexadecimal: 0xFA, OxFB, 0x03, 0x01, 0x00, 0x01 Mantener vivo al servidor: PULSE El microcontrolador tiene un watchdog de 2 segundos (parámetro congurable en la ash) que controla de forma segura el robot. Si en un periodo de 2 segundos no llega ningún comando del cliente, esto indicará que el cliente ha perdido el control del robot y este dejará de moverse. En el momento que se reciba un comando el robot volverá a moverse. Si nuestra aplicación tiene periodos en los que el cliente no manda ningún comando al servidor, se deberá mandar frecuentemente (menos de 2 segundos) el comando PULSE para evitar que el watchdog salte. Comando en hexadecimal: 0xFA, OxFB, 0x03, 0x00, 0x00, 0x00 Cerrar el servidor: CLOSE Para cerrar la conexión con el servidor, parando los motores, sonar y demás funciones del servidor. Comando en hexadecimal: 0xFA, OxFB, 0x03, 0x02, 0x00, 0x02 C.2.2. Comandos de movimiento El servidor P2OS que controla el motor acepta comandos de dos tipos. Control directo de las ruedas En este modo, el cliente debe de mandar un comando de translación (VEL) y después otro de rotación (ROTATE). Este modo es mucho más preciso. Control directo del movimiento De esta otra forma, el cliente manda un comando de tipo VEL2 con dos argumentos que indican la velocidad para las ruedas de cada lado del robot. Esto requiere, que C. P2OS: El Sistema Operativo del microcontrolador. 67 el cliente calcule, a partir de la translación y rotación deseadas, los dos valores de los parámetros para componer el comando. El robot establece su posición a partir de las lecturas de los encoders que controlan cada rueda del robot. Mantiene la posición de sus coordenadas internas y las envía en el paquete de información SIP. Los valores devueltos son la posición en x (xpos), en y (ypos) y la dirección (Thpos). Estos valores representan la odometría del robot y sólo son válidos para tratar las variaciones de estos en pequeños movimientos. Se debe a que el movimiento del robot depende del entorno y si una rueda derrapa creerá estar en una posición, pero realmente está en otra. En supercies deslizantes el robot trabaja peor que en supercies rugosas. C.2.3. Sonar Cuando el cliente se conecta al servidor, el P2OS inicia directamente el sonar, mandando la información de este a través de los paquetes de información (SIP). Se puede usar el comando SONAR para habilitar o deshabilitar todos o algunos de los dispositivos sonar. Existen además otros dos comandos POLLING y SONAR_CYCLE. El primero establece la secuencia para lanzar cada uno de los sonar y el segundo para cambiar la frecuencia con la que se lanzan. C.2.4. Emergencias y paradas El robot Pioneer va equipado con sensores de contacto en la parte delantera y trasera. Cuando alguno de los sensores se activa (toca un obstáculo) se produce una parada de emergencia. P2OS permite activar o desactivar dichos sensores con el comando BUMPSTALL. Además se puede congurar en la ash la acción que realizará el sensor al detectar un contacto (por defecto parada de emergencia). Apéndice D El láser SICK LMS D.1. Información básica sobre el láser Nota: Esta es una versión resumida en castellano de las hojas de especicación del fabricante del láser SICK LMS. Si desea información completa y más especica consulte el Manual rápido de LMS en www.sick.es. El Sistema de Medida Láser LMS 200, LMS 220, LMS 211, LMS 221, LMS 291 está basado en el principio de la medida del tiempo-de-vuelo (Radar Láser). Un único pulso láser es enviado fuera y reejado por la supercie de un objeto dentro del rango del sensor. El tiempo transcurrido entre la emisión y la recepción del pulso del láser sirve para calcular la distancia entre el objeto y el LMS. Mediante un espejo rotatorio integrado los pulsos del láser barren un rango en forma de radio en frente de la unidad LMS. Se dene de esta forma un campo o área de detección de dos dimensiones. Los principales benecios de estos principios de medida son: Detección de objetos independientemente del color o la textura que tengan. Detección able de la presencia de objetos. Figura D.1: Principio de medida y rango angular de LMS LMS ofrece solución a una gran cantidad de aplicaciones: Determina el volumen de los objetos (medición de paquetes, palets, contenedores ) Determina la posición de los objetos (palets, contenedores, cintas transportadoras ) Previene la colisión de vehículos 68 D. El láser SICK LMS 69 Controla procesos de atraque (posicionamiento) Clasicación de objetos (detección de vehículos) Automatización de procesos .. y muchas más D.2. Software. Mecanismo de comunicación D.2.1. Esquema de funcionamiento para la comunicación con LMS Figura D.2: Resumen del funcionamiento de las comunicaciones con LMS D.2.2. Establecer la comunicación con LMS Después de encender el láser, el led amarillo y el rojo se encenderán hasta que el proceso de inicialización haya sido completado. Solo cuando el led verde o el rojo esté activo, la unidad estará lista para la comunicación. Además, un mensaje de inicialización es enviado a la velocidad de 9600 bps a través del puerto serie al PC conectado. Mensaje de inicialización en hexadecimal LMS -> PC 02 80 17 00 90 4C 4D 53 32 30 30 3B 33 30 31 30 3633 3B 56 30 32 2E 31 30 20 10 72 D0 Para probar la conexión con el LMS conectado, se recomienda enviar el comando de estado al LMS. El comando de petición de estado para el LMS es: Mensaje en hexadecimal PC -> LMS 02 00 01 00 31 15 12 Mensaje en hexadecimal LMS -> PC C6 02 81 .. REFERENCIA A D.5 Nota: El red rojo activado permanente o temporalmente indica una infracción en alguno de los campos de la memoria interna del LMS. En caso de de que todo funcione correctamente sin infracciones el led verde se mantendrá activo de forma permanente. Figura D.3: Esquema de la inicialización del LMS D.2.3. Valores por defecto del LMS Por defecto, el láser después de inicializarse tiene los siguientes valores: Parámetro Puerto serie Rango angular Resolución angular Unidades de medida Valor C6 02 81 .. REFERENCIA A D.5 8 bits de datos sin paridad 1 bit de stop sin control de flujo 0 .. 180º 0.5º mm Los valores por defecto de la tabla deben ser cambiados con los comandos que se describen más adelante. D.2.4. Cambiar la velocidad de transmisión Tras apagar el LMS, la velocidad de transmisión se resetea a 9600 baud. Para acceder a las mediciones del LMS a mayor velocidad, es necesario cambiar la velocidad a una mayor después de cada inicialización con alguno de los siguientes comandos: D. El láser SICK LMS 71 Velocidad de LMS 9600 baud 19200 baud 19200 baud Nota: Comando PC -> LMS 02 00 02 00 20 42 52 08 02 00 02 00 20 41 51 08 02 00 02 00 20 40 50 08 Respuesta 06 02 81 03 00 06 02 81 03 00 06 02 81 03 00 LMS -> PC A0 00 10 36 1A A0 00 10 36 1A A0 00 10 36 1A Al cambiar la velocidad de transmisión mediante estos comandos la comunica- ción con LMS y PC se interrumpe. Para reanudar de nuevo la comunicación con el LMS, es necesario cambiar a la nueva velocidad en el programa del PC también. D.2.5. Cambiar la resolución del LMS El LMS puede suministrar datos de distancia en los siguientes formatos: o Rango angular: 0 .. 100 o o ó 0 o o .. 180 Resolución angular: 1 , 0.5 , 0.25 o o o (solo para 100 ) Dependiendo de formato seleccionado, serán suministrados los diferentes valores de distancia: Rango angular 0º .. 100º 0º .. 100º 0º .. 100º 0º .. 180º 0º .. 180º Resolución angular 1º 0.5º 0.25º 1º 0.5º Numero de valores 101 201 401 181 361 Los diferentes modos pueden ser seleccionados enviando el correspondiente comando del PC al LMS: Nota: Después de enviar un comando, un paquete de reconocimiento (ACK) y la respuesta del LMS necesita ser recibida en el PC. Cuando se haya recibido la respuesta completa al ACK, la conguración del LMS habrá sido realizada y el siguiente comando podrá ser enviado. Los comandos intermedios serán ignorados. Modo LMS 0º .. 100º -- 1º 0º .. 100º -- 0.5º 0º .. 100º -- 0.25º 0º .. 180º -- 1º 0º .. 180º -- 0.5º Comando PC -> LMS 02 00 05 00 3B 64 00 64 00 1D 0F 02 00 05 00 3B 64 00 32 00 B1 59 02 00 05 00 3B 64 00 19 00 E7 72 02 00 05 00 3B B4 00 64 00 97 49 02 00 05 00 3B B4 00 32 00 3B 1F Respuesta LMS -> PC 06 02 81 07 00 BB 01 64 00 64 00 10 4A 3F 06 02 81 07 00 BB 01 64 00 32 00 10 12 92 06 02 81 07 00 BB 01 64 00 19 00 10 BE C4 06 02 81 07 00 BB 01 B4 00 64 00 10 5EB2 06 02 81 07 00 BB 01 B4 00 32 00 10 06 1F o Figura D.4: Barrido láser en el modo 0 ..180 o y 0..100 o D.2.6. Cambiar la unidad de medida en LMS Dependiendo de la aplicación, el LMS puede ser establecido para medir la distancia en dos unidades. Modo mm mode cm mode Nota: Medida / rango de detección 0 .. 8191 mm = 8.191 metros 0 .. 8191 cm = 81.91 metros La precisión de la medida en cm no es tan alta como en mm. Cambio a mm: Para cambiar a una unidad diferente de medida, es necesario habilitar el Modo conguración del LMS. Seguiremos los siguientes pasos, enviando los comandos correspondientes: Unidad de distancia Comando PC -> LMS Respuesta LMS -> PC 1. Modo configuración 02 00 0A 00 20 00 53 49 43 4B 5F 4C06 02 81 03 00 A0 00 10 36 1A 4D 53 BE C5 2. Cambio a mm 02 00 21 00 77 00 00 00 00 00 00 0106 02 81 23 00 F7 00 00 00 46 0000 00 00 02 02 00 00 00 00 00 00 00 0000 01 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 FC 7E 00 00 00 10 FA EA Cambio a cm: De la misma forma que antes, primero enviaremos el comando para cambiar a Modo conguración y luego el comando apropiado: Unidad de distancia Comando PC -> LMS Respuesta LMS -> PC 1. Modo configuración 02 00 0A 00 20 00 53 49 43 4B 5F 4C06 02 81 03 00 A0 00 10 36 1A 4D 53 BE C5 2. Cambio a cm 02 00 21 00 77 00 00 00 00 00 00 0006 02 81 23 00 F7 00 00 00 46 0000 00 00 02 02 00 00 00 00 00 00 00 000D 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 E8 72 00 00 00 10 D2 F2 Nota: Después de enviar un comando, un paquete de reconocimiento (ACK) y la respuesta del LMS necesita ser recibida en el PC. Cuando se haya recibido la respuesta completa al ACK, la conguración del LMS habrá sido realizada y el siguiente comando podrá ser enviado. Para el cambio entre el modo mm y cm la respuestas del LMS puede tardar hasta 7 segundos. Los comandos intermedios serán ignorados. D.2.7. Empezar con la salida continua de datos desde el LMS Cuando se han establecido correctamente todos los parámetros, el LMS necesita un comando para enviar los datos de las mediciones al PC. A diferencia de las aplicaciones por encuesta, el LMS envía una cadena continua de datos a través del puerto serie. D. El láser SICK LMS Salida de datos continua del LMS Comienzo 73 Comando PC -> LMS Respuesta LMS -> PC 02 00 02 00 20 24 34 08 06 02 81 03 00 A0 00 10 36 1A <output string header> < LMS data > (refer to section D.2.) Nota: Antes de enviar cualquier otro comando de conguración al LMS, la salida continua de datos debe ser parada mediante un comando especial (Ver D.2.9) D.2.8. Interpretación de los datos recibidos Un programa de PC típico para monitorear y procesar tareas necesita realizar las siguientes operaciones. Mientras el programa se encuentra en salida de datos continua, es posible enviar un comando que indique Parar salida continua de datos. Figura D.5: Operaciones en la ejecución de un programa con LMS Para determinar el comienzo de una cadena de datos LMS, es necesario identicar una cabecera especial en la cadena de entrada. La cabecera de salida de la cadena de salida es diferente para cada modo de medida. Rango angular 0º .. 100º 0º .. 100º 0º .. 100º 0º .. 180º 0º .. 180º Resolución angular 1º 0.5º 0.25º 1º 0.5º Número de puntos 101 201 401 181 361 Nota: Aunque hay un carácter STX al inicio de cada cadena de datos, no hay un carácter ETX al nal. La cadena de datos actual debe ser identicada de alguna de las siguiente formas: Reconociendo el inicio de la siguiente cadena de datos Almacenando un número exacto de valores calculados a partir de la información de la longitud en la cabecera de datos de la cadena de salida. D.2.9. Detención de la salida continua de datos Antes de enviar cualquier otro comando de conguración al LMS, la salida continua de datos debe ser parada. Salida de datos continua del LMS Parada Comando PC -> LMS Respuesta LMS -> PC 02 00 02 00 20 25 35 08 06 02 81 03 00 A0 00 10 36 1A D.2.10. Formato de la cadena de datos de salida Una vez hemos comenzado con la salida continua de datos, el LMS nos envía una cadena de datos de un formato determinado. El formato en cuestión se describe en detalle a continuación: STX ADR LenL LenH Low High byte byte Campo STX ADR Len CMD DataLen Data .. Status CRC CMD Data Data Data LenL LenH 0º Low byte Data 0º High byte Data 1º Low byte Data ... Status CRC CRC High 1º (more Low byte High data) byte byte Tamaño del Significado dato (numero de bits) 8 Start byte (STX = 02 hexadecimal) 8 Dirección del suscriptor (en este caso el PC). Normalmente el valor es 81 hexadecimal 16 Longitud total de la cadena de datos LMS. Numero de bytes sin incluir el checksum (CRC = 2 bytes) 8 Byte de comando, en este caso (B0 hexadecimal), que indica salida dontinua de datos 16 Numero de bytes de datos de la medicion (depende del modo en el que este configurado el LMS) n x 16 Datos de las medidas (2 bytes cada uno) de acuerdo con el modo de medida. 8 Byte de estado. Indica errores del sistema, contaminación, etc. 16 CRC checksum D. El láser SICK LMS 75 D.2.11. Información del byte de estado (status byte) Durante la salida continua de datos, el LMS manda un byte de estado al nal de cada cadena de salida de datos. Con una programación adecuada, el byte de estado puede ser monitorizado y evaluado durante la captura de datos. Bit 0 0 1 0 1 0 Bit 1 0 0 1 1 0 Bit 2 0 0 0 0 1 Sin error (este es el estado correcto) Información Warning Error Error fatal Por último el Bit 6 indica valor de medida imposible y el Bit 7 que existe contaminación en la medida láser. Apéndice E Trabajando con MaRTE OS E.1. Instalación La instalación de MaRTE es muy sencilla. En la página web de distribución de MaRTE se puede obtener tanto el compilador de lenguaje Ada GNAT como el archivo comprimido que contiene MaRTE. Siguiendo los pasos que se indican en el archivo README se puede instalar todo correctamente. Además MaRTE contiene diferentes ejemplos para probar que la instalación ha sido realizada correctamente. Como referencia rápida, será necesario: Instalar el compilador GNAT 2005 disponible en su página web. Descargar MaRTE OS de la página mencionada. Instalar MaRTE OS en el ordenador con linux ejecutando el programa minstall (leer el archivo README de MaRTE para ver detalles). Congurar las variables del sistema correctamente para poder ejecutar los programas de compilación mgcc (C) y mgnatmake (Ada). Estos son los pasos básicos para instalar el programa que permite generar el archivo (mprogram) que se ejecutará en la máquina controlada por MaRTE. E.2. Creación de nuevos drivers Aunque en [4] queda totalmente denido el proceso de creación de drivers desde el punto de vista más técnico, a continuación se describe de forma rápida el proceso para añadir un nuevo driver desde el punto de vista de usuario programador de MaRTE. En la carpeta kernel de MaRTE se debe abrir el chero kernel-devices-table.ads y añadir un nuevo dispositivo de forma similar a los dispositivos que ya hay disponibles. El propio chero deja claro lo que hay que hacer. Por defecto están disponibles la entrada (teclado), salida estándar y salida de error (pantalla). Aquí es donde se han añadido las terminales del puerto serie ttyS0, ttyS1 y ttyS2 asociados a los dispositivos láser, P2OS 76 E. Trabajando con MaRTE OS 77 y GPS. Cada vez que se modique este chero hay que compilar el kernel de MaRTE ejecutando el comando mkkernel. Para usar el nuevo driver se procede de la misma forma que en Linux. Se obtiene un descriptor de chero realizando un fd = open(/dev/ttyS0) del nombre del terminal correspondiente. A partir de este momento se pueden usar las funciones write y read sobre el dispositivo de la forma habitual. E.3. Arrancar en red con MaRTE OS y el robot Para conseguir el arranque en red en MaRTE hacen falta diferentes elementos hardware y software. E.3.1. Elementos hardware En primer lugar hace falta un PC normal conectado a la red donde se programará la aplicación. A este ordenador lo llamaremos servidor. Por otro lado hace falta el robot Pioneer, al cual se puede conectar una pantalla para poder ver lo que sucede (más cómodo que la línea gdb de debug ). Se conectará un teclado para poder realizar operaciones y se conectará a la red. A esta máquina la llamaremos host. E.3.2. Elementos software Servidor Se necesitan los siguientes elementos: 1. Tener instalado MaRTE OS correctamente. 2. Un servidor DHCP, por ejemplo instalar con aptitude el servidor dhcpd. 3. Un servidor tftp, de la misma forma que antes instalar el servidor tftp. Host Esta máquina tiene que disponer de linux y del gestor de arranque Grub. Además se tiene que conocer la tarjeta de red que usa y descargar de la página http://romo-matic.net/ el archivo de arranque en red correspondiente. En el caso del robot la tarjeta de red es una Intel eepro100. E.3.3. Conguración del servidor Conguración del servidor dhcp: El archivo de conguración del servidor de direcciones dinámicas se encuentra en /etc/dhcp.conf. En este archivo se deben añadir todos aquellos host que han de arranquen en red. Básicamente se dene cada host con una dirección MAC (única para cada máquina) y se le indica cual será su dirección de red y que archivo ha de descargarse para arrancar. ----------------------------------------------------- dhcpd.conf ..................................................... option subnet-mask 255.255.255.0; default-lease-time 600; max-lease-time 7200; server-name "Nombre-de-servidor"; allow bootp; subnet 155.210.155.0 netmask 255.255.255.0 { } host robot { filename "/tftpdboot/mprogram"; server-name "Nombre-de-servidor"; next-server 155.210.155.36; hardware ethernet 00:04:BF:90:08:72; fixed-address 155.210.155.16; option root-path "/tftpdboot"; } # ......... más máquinas .... ...................................................... En este caso cuando el servidor esté activo, si le llega una petición dhcp desde una máquina con dirección MAC 00:04:BF:90:08:72, este sabrá que es el host robot quien le esta pidiendo una dirección de red. El servidor contestará diciéndole que tiene la IP 155.210.155.16 y que se descargue el chero para arrancar desde /tftpdboot/mprogram. Conguración del servidor TFTP: Este servidor es el que hace posible la transferencia del chero mprogram (resultado de la compilación con MaRTE) a través de la red entre diferentes máquinas. Para compartir un directorio de la máquina en red, hay que editar el chero /etc/inetd.conf, modicando las líneas que aparecen a continuación. #:BOOT: TFTP service is provided primarily for booting. Most sites # run this only on machines acting as "boot servers." tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /tftpdboot De esta forma cuando se arranca el ordenador se comparte con el resto de máquinas el directorio /tftpdboot. Y es aquí donde deberá estar el archivo mprogram, para que el host se lo descargue. E. Trabajando con MaRTE OS 79 E.3.4. Conguración del host En el directorio /boot hay que colocar el archivo de arranque en red y modicar el chero menu.lst del directorio /boot/grub añadiendo la siguiente entrada. # ENTRADA PARA MaRTE OS EN EL MENU GRUB title MaRTE OS root (hd0,1) kernel /boot/mprogram E.3.5. Método de trabajo Antes de empezar a trabajar con MaRTE OS en los robots se han de cumplir los siguientes puntos: 1. Conseguir red. Si estás trabajando desde un ordenador jo de la sala nada más arrancar ya se debería disponer de red. En el caso de usar un portátil se deberá ejecutar un programa proporcionado por el administrador del laboratorio para obtener IP correspondiente. (sudo ./ethUni IP ) 2. Hay que eliminar todos los procesos dhcp y dhcpd que estén corriendo en el sistema, si los hay. Normalmente al arrancar el sistema, también arranca un cliente DHCP que pide una dirección de red automáticamente y el propio servidor DHCPD arranca con una conguración determinada. Para ahorrar funcionamientos incorrectos lo mejor es buscar los procesos que están ejecutándose en el servidor con sudo ps aux | grep dhcp y matarlos con kill -9 "numero proceso". Ahora se lanzará el servidor DHCPD de la siguiente manera sudo dhcpd -f -d, y todo queda listo para empezar a trabajar. 3. Cuando compilamos el programa con MaRTE (mgnatmake en ADA y mgcc en C) el chero mprogram queda en un directorio especicado por el usuario en la instalación. Después de compilar se debe copiar ese chero al directorio compartido con TFTP. La orden usada durante el proyecto es cp /home/usuario/export/mprogram /tftpdboot/. 4. Ahora el servidor está listo para escuchar la petición del host (robot). Sera necesario arrancar el robot, donde aparecerá una lista (GRUB) de los diferentes SO que se pueden arrancar.Se deberá elegir la entrada de MaRTE OS tal como se haya congurado, y listo. Un detalle importante a tener en cuenta es que la primera vez que se arranca el robot conviene hacerlo en linux porque la tarjeta de red queda congurada correctamente. Los posteriores arranques en red (con la tarjeta congurada) son mucho más rápidos, permitiendo desarrollar mejor la aplicación en MaRTE. Apéndice F Manual de usuario y API F.1. Manual de usuario A continuación se recogen los pasos más importantes que hay que seguir para realizar una aplicación en el SO MaRTE usando las funciones implementadas para el robot. Se debe tener instalado el entorno de desarrollo en nuestro ordenador con Linux tal y como se explica en el anexo E. La versión estándar de MaRTE por el momento no ofrece los drivers que se han implementado. Para poder usar los dispositivos del robot se deben de copiar las carpetas que contienen los drivers del robot para MaRTE en los lugares apropiados. Se van a mostrar las partes básicas que componen una aplicación Ada para utilizar el dispositivo del microcontrolador (el proceso es similar para C). 1. Poner las directivas with y use correspondientes al dispositivo y los recursos que se deseen usar. De esta forma estarán disponibles dentro de la aplicación las funciones que hay denidas en los cheros incluidos. En este caso se necesita MaRTE_OS como en cualquier otra aplicación para MaRTE_OS, System para poder asignar prioridades del sistema, text_io y Ada.Real_Time para poder utilizar los temporizadores y nalmente p2os_import para utilizar las funciones del microcontrolador. with with with use with MaRTE_OS; system; text_io, Ada.Real_Time; text_io, Ada.Real_Time; p2os_import; use p2os_import; 2. Crear un procedimiento en el que se denirán las tareas que componen la aplicación. En esta aplicación se crearán tres tareas. La primera tarea se crea automáticamente. Como se explicó en el capítulo 3.2, el hecho de instanciar un dispositivo supone crear una tarea que atiende a las interrupciones con un periodo determinado por la velocidad a la que se instancia el dispositivo. La segunda tarea (actualiza_p2os ) actualizará cada 100 ms el valor del objeto protegido que contiene los datos del micro. La última tarea (movimiento ) será la que se encargue de mover el robot tres metros hacia delante. 80 F. Manual de usuario y API 81 3. Habrá que denir la prioridad de cada tarea de la siguiente forma. La tarea que atiende a la interrupción tiene prioridad hardware y el usuario no la debe indicar. La tarea de actualización se ejecuta cada 100ms por lo que se le asigna más prioridad que a la de movimiento que se ejecuta cada 150ms. Por ejempolo asignamos las prioridades 22 y 19: prioridad_actualizacion: constant System.Any_Priority := 22; prioridad_movimiento : constant System.Any_Priority := 19; 4. Habrá que denir las tareas con las prioridades correspondientes: task actualiza_p2os is pragma Priority (prioridad_actualizacion); end actualiza_p2os; task movimiento is pragma Priority (prioridad_movimiento); end movimiento; 5. Por último se crearán las tareas para que el objeto protegido este actualizado cada 100ms y el robot consiga moverse hasta que la odometría indique que se el valor de la x vale 3 metros. Se puede ver que el robor se va a mover traslacionalmente a 0.2m/s y 0.0rad/s angularmente. task body actualiza_p2os is periodo : constant Time_Span := Milliseconds (100); siguiente : Time; port : C.char_array := "/dev/ttyS0"; var : C.Int; begin --Comienza la incialización del microcontrolador var:=initP2os(port); while true loop --Con esta función se actualiza el objeto protegido p2osGetValues; --Suspension hasta que vuelva a empezar su periodo siguiente := siguiente + periodo; delay until siguiente; end loop; end actualiza_p2os; task body movimiento is periodo : constant Time_Span := Milliseconds (200); siguiente : Time; x: float := 0.0; begin siguiente := clock; while true loop --Obtenemos el valor de X lockP2os; x := float(p2osGetXpos); unlockP2os; --Ordenamos al micro que mueva los motores a 0.2 m/s if x < 3.0 then SetSpeed(0.2,0.0); else SetSpeed(0.0,0.0); end if; --Suspension hasta que vuelva a empezar su periodo siguiente := siguiente + periodo; delay until siguiente; end loop; --Fin de control de movimiento end movimiento; F. Manual de usuario y API 83 F.2. Funciones en lenguaje C A continuación se presenta el conjunto de funciones disponibles para programar los dispositivos en lenguaje C. Para la comunicación inalámbrica no se han documentado las funciones debido que todavía no se ha podido probar correctamente este driver. Se pueden ver las funciones del microcontrolador (P2OS), las del láser y las del GPS. Para todas ellas se muestran y explican los parámetros de entrada de las funciones y el resultado que se obtiene con ellas. Además se puede observar el tiempo de cómputo para cada función. Esto facilita enormemente realizar y analizar aplicaciones para el robot con MaRTE OS. F.2.1. P2OS Función int initP2os(char * port); int p2osShutdown(); void p2osMotorOn(); void p2osMotorOff(); void p2osSonarOn(); void p2osSonarOff(); void p2osGetValues(); int p2osGetLwstall(); int p2osGetRwstall(); unsigned char p2osGetStatus(); unsigned char p2osGetBattery(); unsigned char p2osGetSonarreadings(); unsigned char p2osGetAnalog(); unsigned char p2osGetDigin(); unsigned char p2osGetDigout(); unsigned short p2osGetCompass(); unsigned short p2osGetTimer(); unsigned short p2osGetRawxpos(); unsigned short p2osGetRawypos(); unsigned short p2osGetFrontbumpers(); unsigned short p2osGetRearbumpers(); short p2osGetLvel(); short p2osGetRvel(); short p2osGetControl(); unsigned short p2osGetSonar(int I); float p2osGetXpos(); float p2osGetYpos(); float p2osGetAngle(); int p2osGetX_offset(); int p2osGetY_offset(); int p2osGetAngle_offset(); float p2osGetXSpeed(); float p2osGetYawSpeed(); void PrintP2OS_SIP(); void SetSpeed(float trans, float rot); P2OS Cómputo Funcionamiento 12.97* Inicializa el driver del microcontrolador en el puerto indicado en port. 1.209* Finaliza el driver 0.029 Activa /desactiva los motores 0.029 Activa /desactiva el sonar 0.062 0.00394 Actualiza los valores del SIP. Esta función debe ser periódica (todo el rato en un bucle) Valores del sensor de parada. 0.00402 0.00380 0.00401 0.00394 0.00402 Valor del registro de estado del micro. Nivel de batería Número de valores sonar. Registro analógico del micro. Registro digital del mico. (entrada/salida) 0.00401 0.00394 0.00396 Valor de la brújula digital Timer del micro. Valor de x e y entre un cambio y otro. 0.00401 Valor de los sensores de choque 0.00402 Velocidad a izquierda y derecha 0.00380 0.00401 0.00394 Registro de control Sonar número I del robot Valores de la odometría del robot. 0.00380 Valores de la variación de odometría 0.00402 Valor de la velocidad de translación y rotación del robot 9.355* Muestra la información del paquete SIP 0.029 Establece la velocidad de translación(m/s) y rotación (rad/s) del robot. void lockP2os(); 0.001 Bloquea/desbloquea la lectura/escritura de void unlockP2os(); los valores SIP (soporte Tiempo Real) *Valores de tiempo inicio/fin (No de cómputo) debido a que esas funciones no son importantes para el control de Tiempo Real Figura F.1: Funciones para manejar el P20S en C F.2.2. Láser Las funciones que controlan el dispositivo láser son: LÁSER Función Cómputo (ms) Funcionamiento void connectToLMS (int range_mode, int res_mode, int unit_mode, char * port, int baud_sel) 6.5* Conecta y configura el láser con los parametros: range_mode = {RANGE_100 , RANGE_180} res_mode = {RES_1_DEG, RES_0_5_DEG, RES_0_25_DEG} unit_mode = {MMMODE,CMMODE} port = nombre del dispositivo (p.e “/dev/ttyS0”) baud_sel = {9600,19600,38400} void resetLMS() void stopLMS() 6.8* Reset / parada del dispositivo. Se establece la configuración por defecto. int readLMSValues() BPS 100- 1º 100-0.5º 100-0.25º 180-1º 9600 224.67 19200 112.35 38400 int readLMSValues() 453.318 868.52 397.15 224.67 453.318 198.03 180-0.5º Duración de la actualización del láser. Los valores del láser quedan actualizados para las 776.43 funciones de lectura. 397.15 (no funciona en el robot, límite tecnológico) Modo 100- 1º 100-0.5º 100-0.25º 0.540 10.518 2.070 180-1º 0.952 180-0.5º Actualiza los valores del láser. Tiempo de cómputo real (independiente de la línea 1.867 serie) int laserazo (int i) 0.0031 Devuelve el valor de la distancia del láser número I int GetCountLaser() 0.0036 Número de valores que se han recogido en el último barrido double GetScanResLaser() 0.0035 Devuelve la resolución a la que esta configurado el láser. double GetRangeResLaser() 0.0056 Devuelve el rango en el que está configurado el láser int getStatus () 0.0041 Devuelve el estado de funcionamiento del láser. Los valores se pueden consultar en el anexo D. void lockLaser() void unlockLaser() 0.001 Bloquea/desbloquea la lectura/ escritura del láser. *Valores de tiempo inicio/fin (No de cómputo) debido a que esas funciones no son importantes para el control de Tiempo Real Figura F.2: Funciones para manejar el Láser en C F.2.3. GPS GPS Novatel Cómputo (ms) Funcionamiento 1.053* Inicializa el driver en el dispositivo indicado en el parámetro puerto. int SetupNovatel() 11.15206* Establece los valores del GPS. Operación interna de configuración. int leerSerie() 0.20585 (Periodo Lee los valores de la linea serie. mínimo 1 segundo) void leeGps() 0.033 Actualiza los valores del GPS float gps_X() 0.003599 Valor en X float gps_Y() 0.003599 Valor en Y void ShutdownSerial() 2.31086 Finaliza el dispositivo void lockGPS() 0.001 Bloquea/desbloquea la lectura/escritura del void unlockGPS() GPS *Valores de tiempo inicio/fin (No de cómputo) debido a que esas funciones no son importantes para el control de Tiempo Real Función void initNovatel (char * puerto) Figura F.3: Funciones para manejar el GPS en C F. Manual de usuario y API 85 F.2.4. Comunicación inalámbrica El conjunto de funciones usado para poder realizar una comunicación inalámbrica no ha sido testeado hasta el punto de poder ofrecer un API able. Además para poder realizar la comunicación se usa el driver PCI, el driver PCMCIA (yenta_socket) y el driver de la tarjeta (rt61). Para poder hacerlo funcionar necesitaremos además el código del protocolo RT-WMP. Por ello se ha decido no crear un API. El camino correcto, para poder implementar un protocolo de comunicación será estudiar la aplicación de ejemplo que se incluye con el proyecto. El orden de cada una de las funciones es importante, así como la conguración del sistema. Además este driver todavía no ha sido publicado con la distribución actual de MaRTE y no ha sido revisado por sus distribuidores. F.3. Funciones en lenguaje Ada De la misma forma que para lenguaje C, se presentan las funciones y los datos correspondientes para programar aplicaciones en lenguaje Ada. F.3.1. P2OS P2OS Función Cómputo Funcionamiento function initP2os (port: C.char_array) return C.Int; 12.97* Inicializa el driver del microcontrolador en el puerto indicado en port. function p2osShutdown return C.Int; 1.209* Finaliza el driver procedure p2osMotorOn; 0.029 Activa /desactiva los motores procedure p2osMotorOff; procedure p2osSonarOn; 0.029 Activa /desactiva el sonar procedure p2osSonarOff; procedure p2osGetValues; 0.062 Actualiza los valores del SIP. Esta función debe ser periódica (todo el rato en un bucle) function p2osGetLwstall return C.Int; 0.00394 Valores del sensor de parada. function p2osGetRwstall return C.Int; unction p2osGetStatus return C.unsigned_char; 0.00402 Valor del registro de estado del micro. function p2osGetBattery return C.unsigned_char; 0.00380 Nivel de batería function p2osGetSonarreadings return 0.00401 Número de valores sonar. C.unsigned_char; function p2osGetAnalog return C.unsigned_char; 0.00394 Registro analógico del micro. function p2osGetDigin return C.unsigned_char; 0.00402 Registro digital del mico. function p2osGetDigout return C.unsigned_char; (entrada/salida) function p2osGetCompass return C.unsigned_short; 0.00401 Valor de la brújula digital function p2osGetTimer return C.unsigned_short; 0.00394 Timer del micro. function p2osGetRawxpos return C.unsigned_short; 0.00396 Valor de x e y entre un cambio y function p2osGetRawypos return C.unsigned_short; otro. function p2osGetFrontbumpers return 0.00401 Valor de los sensores de choque C.unsigned_short; function p2osGetRearbumpers return C.unsigned_short; function p2osGetLvel return C.short; 0.00402 Velocidad a izquierda y derecha function p2osGetRvel return C.short; function p2osGetControl return C.short; 0.00380 Registro de control function p2osGetSonar(I: C.Int) return 0.00401 Sonar numero I del robot C.unsigned_short; function p2osGetXpos return C.Double; 0.00394 Valores de la odometría del robot. function p2osGetYpos return C.Double; function p2osGetAngle return C.Double; function p2osGetX_offset return C.Int; 0.00380 Valores de la variación de function p2osGetY_offset return C.Int; odometría function p2osGetAngle_offset return C.Int; function p2osGetXSpeed return C.Double; 0.00402 Valor de la velocidad de translación function p2osGetYawSpeed return C.Double; y rotación del robot procedure PrintP2OS_SIP; 9.355* Muestra la información del paquete SIP procedure SetSpeed(trans: Float; rot: Float); 0.029 Establece la velocidad de translación(m/s) y rotación (rad/s) del robot. procedure lockP2os; 0.001 Bloquea/desbloquea la procedure unlockP2os; lectura/escritura de los valores SIP (soporte Tiempo Real) *Valores de tiempo inicio/fin (No de cómputo) debido a que esas funciones no son importantes para el control de Tiempo Real Figura F.4: Funciones para manejar el P20S en Ada F. Manual de usuario y API 87 F.3.2. Láser LÁSER Función Cómputo (ms) Funcionamiento procedure connectToLMS (range_mode, res_mode, unit_mode: C.Int; port: C.char_array; baud_sel:C.Int); 6.5* Conecta y configura el láser con los parametros: range_mode = {RANGE_100 , RANGE_180} res_mode = {RES_1_DEG, RES_0_5_DEG, RES_0_25_DEG} unit_mode = {MMMODE,CMMODE} port = nombre del dispositivo (p.e “/dev/ttyS0”) baud_sel = {9600,19600,38400} procedure resetLMS; procedure stopLMS; 6.8* Reset / parada del dispositivo. Se establece la configuración por defecto. function readLMSValues return C.Int; BPS 100- 1º 100-0.5º 100-0.25º 180-1º 180-0.5º Duración de la actualización del láser. Los valores del láser quedan actualizados para 224.67 453.318 868.52 397.15 776.43 las funciones de lectura. 19200 112.35 224.67 453.318 198.03 397.15 9600 38400 function readLMSValues return C.Int; (no funciona en el robot, límite tecnológico) Modo 100- 1º 100-0.5º 100-0.25º 180-1º 180-0.5º Actualiza los valores del láser. Tiempo de cómputo real (independiente de la 0.540 10.518 2.070 0.952 1.867 línea serie) function laserazo (i: C.Int) return C.Int; 0.0031 Devuelve el valor de la distancia del láser número I function GetCountLaser return C.Int; 0.0036 Número de valores que se han recogido en el último barrido function GetScanResLaser return C.Double; 0.0035 Devuelve la resolución a la que esta configurado el láser. function GetRangeResLaser return C.Double; 0.0056 Devuelve el rango en el que está configurado el láser int getStatus (); 0.0041 Devuelve el estado de funcionamiento del láser. Los valores se pueden consultar en el anexo D. void lockLaser(); void unlockLaser(); 0.001 Bloquea/desbloquea la lectura/ escritura del láser. *Valores de tiempo inicio/fin (No de cómputo) debido a que esas funciones no son importantes para el control de Tiempo Real Figura F.5: Funciones para manejar el Láser en Ada F.3.3. GPS Función procedure initNovatel(port: C.char_array); function SetupNovatel return C.Int; function leerSerie return C.Int; GPS Novatel Cómputo (ms) 1.053* 11.15206* 0.20585 (Periodo mínimo 1 segundo) 0.033 0.003599 0.003599 2.31086 0.001 procedure leeGps; function gps_X return Float; function gps_Y return Float; procedure ShutdownNovatel; procedure lockGPS; procedure unlockGPS; *Valores de tiempo inicio/fin (No de cómputo) debido a que el control de Tiempo Real Funcionamiento Inicializa el driver en el dispositivo indicado en el parámetro puerto. Establece los valores del GPS. Operación interna de configuración. Lee los valores de la linea serie Actualiza los valores del GPS Valor en X Valor en Y Finaliza el dispositivo Bloquea/desbloquea la lectura/escritura del GPS esas funciones no son importantes para Figura F.6: Funciones para manejar el GPS en Ada F.3.4. Comunicación inalámbrica Como se ha comentado en el apartado para el lenguaje C (F.2.4), este driver no dispone de un API able por el momento. Por lo tanto tampoco se dispone del interfaz para ADA. F.4. Consideración nal Además de los tiempos que se muestran en cada función usada, a la hora de desarrollar una aplicación en tiempo real, será necesario conocer el tiempo de cómputo y periodo de las interrupciones que atienden la línea serie. Esta interrupción es diferente dependiendo de la velocidad a la que se instancie el driver. El tiempo de cómputo de la interrupción es de 29 microsegundos y los periodos de ejecución correspondientes a cada modo (en el peor caso posible) se pueden ver aquí: Baud rate interrupciones / segundo 9600 1200 19200 2400 38400 4800 Periodo mínimo (inversa) 833.333µs 416.66µs 208.333µs Utilización 0.03240 0.0648 0.1296 Apéndice G Interfaz de programación entre Ada y C En este anexo se va a explicar como se puede mezclar Ada con C y C++. Algunas razones para mezclar Ada con C/C++ son las siguientes: Tienes una gran cantidad de código escrito en Ada y quieres hacer desarrollos en el futuro en C/C++. Preeres desarrollar aplicaciones en Ada, pero estás obligado a usar librerías que ya existen en C/C++. Con algunas limitaciones, ambos casos son posibles. En general, una aplicación está compuesta de uno o más elementos visibles globalmente. Estos items tienen un nombre que está asociado o con la dirección del dato o la dirección del punto de entrada de una función. El código fuente que generan estos items se almacena en uno o más cheros fuente en el ordenador de desarrollo. Cada chero fuente está escrito o en Ada o en C/C++ y está procesado por su propio compilador. El proceso de compilación convierte el código fuente al código objeto. El linker combina estos módulos de código objeto en un sólo chero ejecutable. Tanto Ada como C/C++ usan este sistema de compilación y lincado separado. Mientras todas los cheros fuente estén escritos en el mismo lenguaje, el compilador y el linker funcionarán perfectamente. Los problemas aparecen cuando algunos cheros están escritos en Ada y otros en C o en C++. Imaginemos que un programa está compuesto de dos partes. Una parte está escrita en Ada y la otra en C/C++. Nos preguntaremos: 1. ¾Cómo se reere una parte a los datos globales de la otra parte? 2. ¾Cómo una parte crea dinámicamente y subsecuentemente se reere a datos de la otra parte? ¾Cómo se destruyen estos datos? 3. ¾Cómo puede una parte llamar a las funciones de la otra parte?¾Cómo se pasan los argumentos? ¾Cómo se recibe los valores devueltos? 4. ¾Dónde esta el punto de entrada del programa?¾Es un main() en C/C++ o es un procedimiento en la parte Ada? 89 En este capítulo trataremos estas cuestiones. G.1. Visibilidad global de los datos Un dato almacenado estáticamente ocupa una porción de memoria que puede ser determinada en tiempo de lincado. Un chero fuente puede denir estáticamente datos que son visibles a otros cheros fuente o pueden acceder estáticamente a datos denidos en otros cheros fuente. En C/C++, los datos almacenados estáticamente son visibles globalmente si están denidos fuera de una función y no está presente la palabra static. Una función C/C++ puede referirse a los datos que han sido almacenados estáticamente en otro chero fuente declarando el dato con la palabra clave extern. Por ejemplo, la siguiente declaración en C++ crea un dato visible a Ada y se reere a un datos que Ada ha creado: extern struct adastuff FromAda2Cpp; // Import from Ada to C++ struct cppstuff FromCpp2Ada; // Export from C++ to Ada Un ejemplo para C sería el siguiente: extern struct adastuff FromAda2C; // Import from Ada to C struct cstuff FromC2Ada; // Export from C to Ada Lo programas Ada hacen visibles los datos globalmente a C/C++ usando el comando pragma export. Un procedimiento o función Ada puede referirse a un dato que ha sido almacenado estáticamente en un chero fuente C/C++ usando el comando pragma im- port. Algunos ejemplo: pragma import(CPP, CPP_HIS_STUFF, "FromCpp2Ada"); pragma export(CPP, CPP_MY_STUFF, "FromAda2Cpp"); pragma import(C, C_HIS_STUFF, "FromC2Ada"); pragma export(C, C_MY_STUFF, "FromAda2C"); Estos comandos de Ada asocian un nombre local Ada con un nombre global C/C++. Tendremos que tener cuidado con los nombres en Ada ya que permiten poner puntos. Esta característica no esta disponible en C/C++ ya que en este caso indica una estructura, una unión o una clase. Estos pragmas Ada realizan una función importante asociando el nombre interno Ada con el símbolo externo y traduciendo símbolos externos a la forma que es compatible con C/C++. G. Interfaz de programación entre Ada y C 91 Ada y C/C++ pueden compartir cualquier tipo de dato si las representaciones que hace la máquina son binariamente compatibles. El paquete Ada INTERFACES.C es útil para forzar estas correspondencias. La siguiente lista muestra la correspondencia de tipos entre Ada y C++. Tipo Ada Integer Interfaces.C.int Short_Integer Interfaces.C.short Long_Integer Long_Long_Integer Interfaces.C.long Character Interfaces.C.char Interfaces.C.plain_char Interfaces.C.unsigned_char Interfaces.C.signed_char Byte_Integer Short_Short_Integer Interfaces.C.unsigned Interfaces.C.unsigned_short Interfaces.C.unsigned_long Float Interfaces.C.C_float Long_Float Interfaces.C.double Interfaces.C.long_double Interfaces.C.char_array Interfaces.C.wchar_t Tipo C/C++ int int short short long long long char char char unsigned char signed char signed char signed char unsigned int unsigned short unsigned long float float double double double char * wchar_t El tipo puntero Ada (access ) es equivalente al correspondiente tipo puntero C/C++. Ada, C y C++ pueden compartir estructuras, uniones y vectores. Es obligatorio denir en el mismo orden los elementos para en las estructuras para asegurar que si las estructuras tienen el mismo número y tipo de elementos, entonces serán binariamente compatibles. Este es un ejemplo de código Ada accediendo a una estructura de datos C++: Lado en C++ class cpprec // Define the structure { int numitems; float weightofitems; }; cpprec cpp_name; // Declare the shared structure Lado en Ada type adarec is -- Define the structure record itemcount : INTEGER; itemweight : FLOAT; end record; ada_name : adarec; -- Declare the shared structure pragma import(cpp, ada_name, "cpp_name");-- Tie the two names together Ahora, cualquier referencia del código Ada a ada_name.itemcount accederá a la mismo posición de memoria entera vista por C++ como cpp_name.numitems. Si el registro Ada es de tipo tagged, entonces la denición C++ del registro necesita dar espacio para la etiqueta del registro Ada. Una variable que imite el tipo *void se tiene que insertar en la denición de la clase antes del primer elemento. El siguiente código muestra un ejemplo: Lado en C++ class cpprec // Define the structure { void* tagspace; // Allow space for the Ada tag int numitems; float weightofitems; }; cpprec cpp_name; // Declare the shared structure Lado en Ada type adarec is -- Define the structure record itemcount : INTEGER; itemweight : FLOAT; end record; ada_name : adarec; -- Declare the shared structure pragma import(cpp, ada_name, "cpp_name");-- Tie the two names together El código C/C++ no puede acceder directamente a datos globales de un paquete Ada existente desde que los símbolos globales han introducido el carácter punto. En este caso, el programador debe usar un pragma export Ada para cada elemento C/C++ que quiera hacer visible. G. Interfaz de programación entre Ada y C 93 G.2. Visibilidad global de funciones Hay que diferenciar los conceptos de función y procedimiento. Un procedimiento es simplemente una función que no devuelve un valor. En Ada, un subprograma es o un procedimiento o una función. Por otro lado C/C++ solo soporta el concepto de función. Sin embargo, una función C/C++ puede ser declarada devolviendo void ; en este caso, el funcionamiento es el mismo que en un procedimiento Ada. La declaración void simplemente le indica al compilador que no espere un valor de retorno. Hay muchos tipos diferentes de función tanto en Ada como en C/C++. Los siguientes tipos comunes de funciones pueden ser usados en ambos lados. 1. Funciones globales - Ada puede llamar a funciones C/C++ globales y C/C++ puede llamar a funciones globales Ada. 2. Miembros de funciones - Ada puede llamar a miembros de funciones C++. C++ no puede llamar a operaciones Ada. Los subprogramas Ada que no pueden ser accedidos desde C/C++ son las operaciones de planicación y las funciones INITIALIZE, FINALIZE y ADJUST de tipos de control. Todas las funciones C/C++ son accesibles desde Ada, aunque los constructores y destructores de C++ no pueden estar disponibles desde Ada directamente. Como para los datos globales, la directiva Ada pragma export y pragma import asocian la función Ada con la función C/C++. Un ejemplo de Ada llamando a una función C++: Lado en Ada function CPROC(input : in integer) return integer; pragma import(CPP, CPROC, "c_proc"); result : integer; ... result := CPROC(123); -- Put answer in variable "result" Lado en C++ int c_proc(int input) { int tmp; // Accumulate the result here. ... // Do some processing here. return tmp; // Return the result. } Para el caso de funciones, el compilador Ada usa la codicación de nombres de C++ para generar el símbolo global real. El programador debe asegurarse de que los tipos de los argumentos encajen entre la declaración de la función Ada y la función C++. Para argumentos de tipo registro y enumerador, el nombre debe ser exactamente entre la denición Ada y C++. La especicación real del tipo del argumento no es un problema. G.3. Ejecución del programa G.3.1. Inicialización El programa principal puede estar escrito en Ada o en C/C++. En ambos casos, el código de inicialización del sistema de ejecución necesita ejecutarse antes de que el programa principal se comience. Este código de inicialización es capturado automáticamente y de forma transparente cuando el programa está escrito en un único lenguaje. Si mezclamos ambos lenguajes, el código de inicialización del usuario debe llamar explícitamente a la inicialización del sistema de ejecución antes de que los elementos del otro lenguaje sean usados. Si las funciones principales están escritas en Ada y el código Ada referencia elementos C++, entonces el programa principal Ada deberá llamar a la función _main() antes de cualquier referencia a un elemento C/C++. Si las funciones principales están escritas en C/C++, entonces el main() debe llamar a una función llamada adainit antes que se haga referencia a un elemento Ada. Esto debe también llamar a adanal después de la última referencia a todos los elementos Ada. G.3.2. Captura de excepciones Tanto Ada como C++ tienen su propio sistema de captura de excepciones. Mientras un programa se ejecuta, el sistema de ejecución mantiene un pila de llamadas. Por ejemplo, la función main() llama a la función sub1(). La función sub1() llama a la función sub2() y ésta a la función sub3(). Si la función sub3() detecta una condición de excepción, deberá lanzar (o capturar) una excepción. Esta excepción transere el control a sub1() para tratar la excepción. Si esas cuatro funciones estuvieran escritas en el mismo lenguaje, el mecanismo nativo de tratamiento de excepciones funcionaría a la perfección. ¾Esto funcionaría si todas las funciones estuvieran escritas en el mismo lenguaje, menos sub2() que está escrita en un lenguaje diferente? Si en el ejemplo, sub2() estuviera escrita en C++ y se hubiera compilado con la opción -Xnewexchandling, la respuesta sería sí. La captura de excepciones es una posible transferencia de control en la pila de llamadas. Para conseguir esto, el compilador construye tablas que son usadas en tiempo de ejecución por el mecanismo de captura de excepciones. La opción -Xnewexchandling indica al compilador C++ que debe construir una tabla de captura de excepciones compatible con la de Ada. G. Interfaz de programación entre Ada y C 95 Si, en el ejemplo anterior todas las funciones estuvieran en C++ y sub2() en Ada, entonces la respuesta es no. Actualmente no hay un mecanismo para construir tablas de excepciones C++. G.4. Interfaz de funciones Muchos de los problemas para disponer de funciones en ambos sentidos se soluciona escribiendo funciones que actúan de interfaz entre C/C++ y Ada. Una buena manera de hacerlo es establecer un conjunto de funciones para cada clase C++. Este conjunto deberá tener como mínimo un constructor y un destructor de la clase. Todos los otros miembros se pueden acceder directamente. Por ejemplo, podríamos denir una clase C++ llamada MyClass que tiene una función llamada Print. La función MyClass_AdaCreate crea una instancia de un objeto de tipo MyClass y devuelve un puntero a él. Lado en Ada -- Define and import the three canonical interface functions -function MyClass_AdaCreate return MyClass_AdaPtrType; function MyClass_AdaCopy(arg : in MyClass_AdaPtrType) return MyClass_AdaPtrType; procedure MyClass_AdaDelete(arg : in MyClass_AdaPtrType); pragma import (CPP, MyClass_AdaCreate, "MyClass_AdaCreate"); pragma import (CPP, MyClass_AdaCopy, "MyClass_AdaCopy"); pragma import (CPP, MyClass_AdaDelete, "MyClass_AdaDelete"); -- Define the normal member function "Print". Note that the -- name of the first argument MUST be "this". -procedure MyClass_Print(this : in MyClass_AdaPtrType); pragma import (CPP, MyClass_Print, "MyClass::Print"); -- Define the variables -Instance1 : MyClass_AdaPtrType; -- Pointer to 1st object Instance2 : MyClass_AdaPtrType; -- Pointer to 2nd object ... -- Executable code. -Instance1 := MyClass_AdaCreate; -- Create the object Instance2 := MyClass_AdaCopy(Instance1); -- Make a copy MyClass_Print(Instance1); -- Print Instance1 MyClass_Print(Instance2); -- Print Instance2 MyClass_AdaDelete(Instance1); -- Delete Instance1 MyClass_AdaDelete(Instance2); -- Delete Instance2 Lado en C++ // Define the three canonical functions to create, copy, // and delete objects of type MyClass. // MyClass* MyClass_AdaCreate(void) { return new MyClass; // Create a new one on the heap } MyClass* MyClass_AdaCopy(MyClass* src) { return new (*src); // Create a copy on the heap } void MyClass_AdaDelete(MyClass* deletethis) { delete *deletethis; // Delete this object } Es importante jarse en la directiva pragma import. El primer parámetro indica el lenguaje externo, el segundo es el nombre de la función Ada externa. El tercero indica el nombre de la función C++.