scieee AI-readable full text Open interactive document viewer

Desarrollo de plataforma hardware y software de una unidad de control electrónico para el motor del vehículo FOX

Marín Cortés, Pablo

Abstract

El presente Trabajo Fin de Máster recoge los avances realizados en el proyecto cuyo objetivo es el diseño de una nueva unidad de control electrónica del vehículo FOX, desarrollado en el seno del Departamento de Ingeniería de Sistemas y Automática con la colaboración del Departamento de Ingeniería Aeroespacial y Mecánica de Fluidos, ambos pertenecientes a la Escuela Técnica Superior de Ingeniería de la Universidad de Sevilla. El estudio parte de las conclusiones del Trabajo Fin de Grado "Estudio Preliminar del Diseño de una Nueva Unidad de Control Electrónico del Motor del Vehículo FOX" [1]. Estructuralmente, es posible dividirlo en varios bloques: de un lado, la recepción y puesta a punto del equipo adquirido, incluyendo las pruebas funcionales necesarias para la validación de sus características; la integración del bus de datos CAN (Controller Area Network) en el computador principal, incluyendo pruebas de comunicación con un microcontrolador externo; por último se propone un montaje experimental que emplea todos los elementos estudiados por separado que constituye el paso inmediatamente anterior a la migración del código de los controladores implantados en el vehículo FOX y a la sustitución de su unidad de control electrónico. Bajo los capítulos en los que toman forma los anteriores bloques, también se adjuntan anexos que complementan los desarrollos presentados, y que ayudan a reproducirlos si así se requiriera.

Full text

Proyecto Fin de Carrera Ingeniería de Telecomunicación Formato de Publicación de la Escuela Técnica Superior de Ingeniería Autor: F. Javier Payán Somet Tutor: Juan José Murillo Fuentes Dep. Teoría de la Señal y Comunicaciones Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2013 Trabajo Fin de Máster Máster Universitario en Ingeniería Aeronáutica Desarrollo de Plataforma Hardware y Software de una Unidad de Control Electrónico para el Motor del Vehículo FOX Autor: Pablo Marín Cortés Tutor: Francisco Gavilán Jiménez Departamento de Ingeniería Aeroespacial y Mecánica de Fluidos Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2018 Trabajo Fin de Máster Máster Universitario en Ingeniería Aeronáutica Desarrollo de Plataforma Hardware y Software de una Unidad de Control Electrónico para el Motor del Vehículo FOX Autor: Pablo Marín Cortés Tutor: Francisco Gavilán Jiménez Departamento de Ingeniería Aeroespacial y Mecánica de Fluidos Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2018 Trabajo Fin de Máster: Desarrollo de Plataforma Hardware y Software de una Unidad de Control Electrónico para el Motor del Vehículo FOX Autor: Pablo Marín Cortés Tutor: Francisco Gavilán Jiménez El tribunal nombrado para juzgar el trabajo arriba indicado, compuesto por los siguientes profesores: Presidente: Vocal/es: Secretario: acuerdan otorgarle la calificación de: El Secretario del Tribunal Fecha: Agradecimientos Me gustaría agradecer a mis padres, mi hermana y toda mi familia por el apoyo y la comprensión que me han brindado a lo largo de mi periodo de estudios en la Escuela. Asimismo, mi más sincero agradecimiento a todos mis amigos y compañeros de clase, que han estado siempre ahí para sacarme una sonrisa cuando más lo necesitaba. Esta sección de agradecimientos no estaría de ninguna manera completa sin alabar la dedicación demostrada por Francisco Gavilán en la realización de este proyecto, siendo de inestimable ayuda para llegar a las conclusiones que en él se presentan. Merecen también mi agradecimiento los miembros directivos del FCCL, por la oportunidad brindada para trabajar con el FOX: Carlos Bordons y Miguel Ángel Ridao. Mis agradecimientos también a Juan José Márquez por su tiempo y capacidad para prestar una mano cuando fue necesario. I Resumen El presente Trabajo Fin de Máster recoge los avances realizados en el proyecto cuyo objetivo es el diseño de una nueva unidad de control electrónica del vehículo FOX, desarrollado en el seno del Departamento de Ingeniería de Sistemas y Automática con la colaboración del Departamento de Ingeniería Aeroespacial y Mecánica de Fluidos, ambos pertenecientes a la Escuela Técnica Superior de Ingeniería de la Universidad de Sevilla. El estudio parte de las conclusiones del Trabajo Fin de Grado "Estudio Preliminar del Diseño de una Nueva Unidad de Control Electrónico del Motor del Vehículo FOX" [ 1 ]. Estructuralmente, es posible dividirlo en varios bloques: de un lado, la recepción y puesta a punto del equipo adquirido, incluyendo las pruebas funcionales necesarias para la validación de sus características; la integración del bus de datos CAN (Controller Area Network) en el computador principal, incluyendo pruebas de comunicación con un microcontrolador externo; por último se propone un montaje experimental que emplea todos los elementos estudiados por separado que constituye el paso inmediatamente anterior a la migración del código de los controladores implantados en el vehículo FOX y a la sustitución de su unidad de control electrónico. Bajo los capítulos en los que toman forma los anteriores bloques, también se adjuntan anexos que complementan los desarrollos presentados, y que ayudan a reproducirlos si así se requiriera. III 2Capítulo 1. Introducción en microrredes (definidas como el conjunto de cargas, generadores y sistemas de almacenamiento que puede ser gestionado de manera coordinada para operar de forma aislada o conectada a la red eléctrica). Se considera especialmente la problemática de la interconexión entre vehículos eléctricos y microrredes, así como el problema de cambio de topología por la conexión/desconexión de cualquier sistema de generación, almacenamiento o carga. El proyecto pretende desarrollar entre los años 2017 y 2020 distintas estrategias de control en el marco del Control Predictivo para gestionar de manera eficiente la operación de estos sistemas, abordando la reconfigurabilidad tanto en lo referente a los componentes de una microrred, como a microrredes interconectadas. Los sistemas de control también considerarán criterios que incluyan los factores que afectan a la degradación de los sistemas de almacenamiento, con objeto de dotarlos de una mayor durabilidad. En el ámbito directo de aplicación del presente trabajo, el FOX consiste en un vehículo de competición biplaza adaptado (véase la figura 1.1b) para servir de plataforma de estudio en cuanto a la integración de los vehículos eléctricos y las microrredes anteriormente mencionadas. Las fuentes de energía del mismo pueden ser baterías convencionales o pilas de hidrógeno, clasificándolo como un vehículo eléctrico (EV) híbrido entre un BEV (Battery Electric Vehicle) y un FCEV(Fuel Cell Electric Vehicle). La planta motriz del FOX consiste en cuatro motores de corriente continua sin escobillas (brushless) situados de forma que cada neumático puede ser accionado de manera independiente. La necesidad de un sistema de control automático se justifica por varias razones, entre las que se incluyen lo complicado gobernar la trayectoria del vehículo mediante la actuación directa de cada motor, la gestión de las baterías y la pila de hidrógeno y la seguridad de los ocupantes, así como para la gestión de los datos útiles para la consecución del proyecto. En cuanto a los elementos de control, el vehículo dispone de volante y pedales compuestos por potenciómetros lineales, así como de una unidad integrada de GPS y medidas inerciales. Toda la información es presentada al conductor a través de una pantalla HMI (Human Machine Interface). Es posible encontrar una representación del sistema completo en la figura 1.3. La unidad de control electrónico del vehículo se encuentra situada tras el asiento del conductor, contenida en un chasis metálico refrigerado que presenta los conectores necesarios para servir de interfaz con todos los elementos del vehículo. Está compuesta por módulos con factor de forma PC/104, un estándar en computadores industriales embarcados, apilados entre sí y conectados con el resto de elementos mediante una red de bus CAN, cuya aplicación resulta un estándar en el mundo automovilístico desde los años 90. El software implementado, como ya se expuso en [ 1 ], consiste en la versión 6.3.2 de QNX, un sistema operativo privativo empleado principalmente en sistemas embarcados. 1.2 Estado inicial del proyecto Varios fueron los objetivos conseguidos al finalizar el proyecto presentado en [ 1 ]; por un lado se documentaron aspectos relacionados con el proyecto FOX necesarios para revisar el sistema de la ECU y por otro se llevó a cabo la implementación de un sistema operativo en tiempo real (RT) basado en Linux para soportar un entorno exigente en cuanto a tiempos de ejecución, puesto que como se discutió, el control automático preciso y determinista del vehículo depende en gran medida de su robustez. Ello quedó justificado al constatarse que el sistema operativo basado en QNX instalado en el vehículo presenta algunos problemas de corrupción de datos difíciles de predecir que ponen en peligro el desempeño seguro y fiable del controlador, sumado a las características favorables del SO elegido (código libre, extensiva documentación, posibilidad de crear un SO a medida... etc.) Como se describió en [ 1 , Sección 4.4.1], la dificultad añadida de la idea residió en la necesidad de que el vehículo se encontrara operativo el mayor tiempo posible para la realización de pruebas periódicas en vivo del software controlador, lo cual imposibilitó trabajar directamente sobre los elementos que componen la ECU. Con ello, el desarrollo se realizó en un equipo cedido por el departamento de Ingeniería Aeroespacial y Mecánica de Fluidos de la Escuela Técnica Superior de Ingeniería de la Universidad de Sevilla. Asimismo, este departamento fue el encargado de proporcionar parte de los materiales adicionales necesarios para llevar las pruebas a cabo. 1.2 Estado inicial del proyecto 3 Figura 1.3 Esquema general de las conexiones del vehículo. Figura 1.4 Equipo de pruebas empleado en [1]. Los resultados de caracterización del desempeño del sistema que se desarrolló, si bien resultaron prometedoras, pusieron de manifiesto las deficiencias en cuanto al rendimiento de la placa principal de pruebas, lo cual motivó la conclusión de que las capacidades del hardware empleado resultaban insuficientes para demostrar el determinismo del sistema. En la figura 1.5 se puede apreciar la pantalla shell en la que quedaron reflejados los resultados. A la vista de las cifras obtenidas, se propusieron una serie de dispositivos que reunían los requisitos 4Capítulo 1. Introducción Figura 1.5 Resultados de latencia. suficientes como para servir de base a la instalación, llevando a la conclusión de que era posible mejorarlas con un equipo basado en hardware actualizado y con mayores prestaciones. Con todo ello, el principal objeto del proyecto queda marcado por el desarrollo de un sistema de control electrónico determinista que funcione a una frecuencia conjunta de adquisición de datos y procesamiento de la señal que se ha demostrado suficiente para el control del vehículo. Esta frecuencia queda fijada en 50 Hz (tiempo total de 20 ms entre procesamientos sucesivos). Otro de los campos que quedaron fuera del alcance de [ 1 ] fue el estudio de la comunicación a través de bus CAN que existe en el vehículo, la cual juega un papel fundamental para conseguir el desempeño deseado. 1.3 Objetivos del TFM Una vez se ha puesto en contexto el avance realizado en el proyecto de modernización de la ECU, los objetivos concretos marcados para este Trabajo Fin de Máster son entonces los siguientes: • En primer lugar, la instalación de un SO con capacidades en tiempo real para este nuevo dispositivo, comprobando su desempeño de manera similar a la llevada a cabo en [ 1 , Sección 6.6], que se tratará en el capítulo 2. • Como se ha comentado, y puesto que el sistema se comunica con los elementos de control del vehículo a través de bus CAN (Controller Area Network), el segundo objetivo consiste en añadir esta capacidad de comunicación mediante un módulo PC/104 externo (Capítulo 4) y comprobar que el sistema de comunicaciones resultante demuestra las prestaciones suficientes para la aplicación de control que se está considerando. • Por último se propone la implementación de un programa de prueba que se ejecute en tiempo real y que, en caso de demostrar que su funcionamiento resulte determinista y estricto en cuanto a tiempos de ejecución, pueda servir de base para la migración de los programas QNX de los controladores del vehículo FOX, y con ello constituir el bloque fundamental de su Unidad de Control Electrónico. De esta manera comienza el estudio con la descripción del nuevo equipo. 2 Recepción del nuevo equipo Basándose en las conclusiones expuestas en el Trabajo de Fin de Grado Estudio preliminar de una nueva unidad de control del motor para el vehículo FOX, el Fuel Cell Control Lab de la Universidad de Sevilla [ 1 ] adquiere el siguiente equipo: •Computador embarcado con factor de forma PC/104 modelo PCM-3365 de la empresa Advantech •Módulo PC/104 de alimentación modelo PCM-3910 •Tarjeta SATA con 64 Gb de capacidad Transcend MSA370 Se dispone del siguiente material en el laboratorio: •Fuente ATX de 350W •Ventilador de 12V •Monitor •USB de 64Gb •Teclado USB Además, el laboratorio cuenta con el material electrónico necesario para algunas de las pruebas que se realizarán en capítulos sucesivos. 2.1 PCM-3365 Se trata de un Single Board Computer desarrollado por la empresa Advantech y lanzado al mercado a mediados del año 2016. Este elemento constituye el verdadero corazón de la unidad de control electrónico del FOX; su misión principal consiste en recibir información relativa al estado de los sensores repartidos por el vehículo, procesarla y enviar la correspondiente señal de control a los motores para conseguir el comportamiento esperado del mismo. Entre otras características que se pueden encontrar en el datasheet [3], destacan: Tabla 2.1 Características de la tarjeta PCM3365. Procesador Intel Celeron N2930 con velocidad de 1.83 GHz y cuatro núcleos Memoria RAM 8 GB DDR3L Conexión Ethernet RS-232/422/485 desde el conector COM 1, 2 RS-232 desde los conectores COM2/3. USB 6 puertos (versión 2.0) Puertos de expansión Mini PCIe 1 x (Full-size), expansión PC/104 y PCI-104. Fuente de alimentación AT/ATX y soporte para alimentación con módulo PC/104. Tensión de alimentación 5V±5% A partir de estos datos, junto con los correspondientes al modelo de SBC actualmente implantado en la ECU [ 1 , Sección 2.2.2], es posible predecir en líneas generales que el sistema resultante presentará unas características que superarán a las entregadas por el primero. 5 6Capítulo 2. Recepción del nuevo equipo Figura 2.1 SBC PCM-3365. Figura 2.2 Fuente PCM-3910. 2.2 PCM-3910 Para proporcionar la alimentación necesaria en el vehículo se dispuso asimismo de un módulo con factor de forma PC/104, modelo PCM-3910 también de Advantech, que consiste en un convertidor DC/DC con las siguientes características (véase [4]): Tabla 2.2 Características de la tarjeta PCM3910. Potencia nominal 50 W Rango de tensión de alimentación 10 a 24 VDC ±5% Protección Polaridad inversa. 5 VDC @ 10A 12 VDC @ 2A -5 VDC @ 0.4A Salidas -12 VDC @ 0.4A Los datos relativos a los consumos de potencia eléctrica recogidos en la tabla 2.2 son de utilidad para los cálculos presentados en el apéndice A, donde se prueba el funcionamiento de este elemento. En cuanto a los conectores disponibles, conviene notar que dispone de una tornillera de entrada etiquetada como CN1 (input) y de puertos de expansión PCI/104 e ISA. La conexión a través de cualquiera de ellos proporciona a la PCM-3365 los voltajes necesarios para su funcionamiento (+5 VDC, +12 VDC y +5 VSB). 2.3 Montajes experimentales propuestos 7 2.3 Montajes experimentales propuestos En este punto conviene describir los dos montajes experimentales que se pretenden llevar a cabo. El primero de ellos consiste en un banco de desarrollo con el objeto de la puesta a punto del equipo, en el que la alimentación del mismo se realiza a través de una fuente ATX convencional, y cuya interfaz gráfica de usuario consiste en una pantalla de ordenador. En el segundo se cambia el módulo de alimentación para adecuarlo a las baterías del vehículo, y la interfaz gráfica es la pantalla integrada del HMI (Human Machine Interface). Los diagramas de bloques de ambos se recogen en la figura 2.3 (a) Montaje experimental . (b) Instalación en el vehículo . Figura 2.3 Bloques funcionales. En el caso del montaje en el vehículo, tal y como se discutió en [ 1 ], es necesario convertir las señales analógicas procedentes de los pedales y motores en señales digitales que serán transmitidas a la ECU vía bus CAN como entrada para los controladores; de manera inversa, la salida de control en formato digital será convertida a analógica y alimentada a los motores. La conversión analógica/digital y viceversa se realiza mediante los mismos módulos PC/104 de los que dispone actualmente el vehículo: Advantech PCM-3718HO para las entradas analógicas y E/S digitales y Ruby MM-1612 para las salidas analógicas. 8Capítulo 2. Recepción del nuevo equipo (a) Espaciadores incluidos . (b) Instalados en el equipo . Figura 2.4 Montaje de los espaciadores hexagonales. 2.4 Hardware Una vez recogidas las principales características del nuevo material adquirido, se procedió a implantar al nuevo equipo para tener un sistema base sobre el que trabajar. El objeto de esta sección es documentar el proceso llevado a cabo en este sentido. En primer lugar se instalaron los espaciadores hexagonales que se proporcionan con la placa PCM-3365 (figura 2.4) con el objeto de separarla de la mesa de trabajo favoreciendo así la ventilación de la misma y evitando cualquier cortocircuito accidental con el espacio de trabajo. La tarjeta SATA se montó en la ranura situada en la parte inferior del equipo, asegurándola mediante el tornillo incluido al efecto. En la figura 2.5 puede apreciarse con detalle el emplazamiento de los principales componentes de la parte inferior de la placa. A continuación, y haciendo uso de los manuales del PCM-3365 que se incluyen con el mismo, se identificaron todos los conectores, véase la figura 2.6. Para el montaje del banco de pruebas se decidió no utilizar el módulo PCM-3910, empleando en su lugar una fuente ATX. Según el manual la alimentación principal del sistema se hace mediante el conector 2.4 Hardware 9 Figura 2.5 Vista inferior de la placa donde se pueden apreciar las ranuras para la tarjeta SATA y para el módulo de memoria RAM. (a) Vista superior . (b) Vista inferior . Figura 2.6 Conectores [3]. CN1. Además es necesaria la conexión de CN2 (ATX power in) usando el cable de alimentación ATX que viene incluido. En efecto, la consulta del manual (figura 2.7) indica que los pines de este conector son los responsables de mandar la señal de activación a la fuente. Asimismo se conectó un teclado USB, para lo cual se insertó el adaptador correspondiente en cualquiera de los conectores CN13, CN16 y CN17. Por último se conectó la pantalla en CN7 (conector VGA) (figura 2.8). 10 Capítulo 2. Recepción del nuevo equipo (a) Información sobre CN2 del manual [3]. (b) Cable para ATX . Figura 2.7 Conexión de la fuente ATX. (a) Cable adaptador USB . (b) Cable adaptador VGA . Figura 2.8 Conexiones restantes . 3 Instalación y parcheado del sistema operativo basado en Linux Como se estudió detalladamente en [ 1 , Sección 5], un sistema operativo en tiempo real es aquel que garantiza la ejecución de los distintas operaciones que realice dentro de unos márgenes de tiempo lo más deterministas posible, traduciéndose todo ello en una ejecución fiable y predecible. A modo de recordatorio, un sistema operativo en tiempo real se puede clasificar según el grado en el que se aseguren estos tiempos destinados a la ejecución de operaciones críticas: se habla de un sistema operativo de tiempo real estricto cuando se conocen con exactitud, y de tipo soft o no estricto cuando importa más la continuidad de la ejecución de las operaciones que el tiempo que éstas disponen para hacerlo. En este sentido, un sistema operativo como Linux puede considerarse que no dispone de capacidades en tiempo real estricto. No obstante, existen algunas técnicas de bajo nivel que permiten gestionar las interrupciones del sistema operativo al nivel de su núcleo, permitiendo clasificar el resultante como de tiempo real estricto. En [ 1 ] se decidió emplear el conocido como parche RT Linux. Entre otras muchas funcionalidades destinadas a garantizar el comportamiento deseado destaca la inclusión de dos nuevos schedulers o programadores de tareas en tiempo real: FIFO (First In First Out) y Round Robin, que son la base para la programación de hilos POSIX, como se estudiará más adelante. Habiendo introducido el contexto de los sistema, la primera tarea en cuanto a software consistió en instalar el sistema operativo y aplicar la versión del parche que añade funcionalidades de tiempo real estricto al mismo. Tal y como se estudió en [ 1 , Sección 5.22], se optó por basar la ECU en un SO Linux en su distribución Slackware. Se realizó una búsqueda en la página kernel.org para conocer el último lanzamiento del parche RT que coincide con la versión de su kernel , que resulta ser la 3.10.17 en el momento en que se escribe este trabajo. Esto restringe la versión más actualizada de slackware que es posible instalar en el sistema a la 14.1, lanzada en 2013 si se quiere emplear este tipo de método para obtener un sistema con capacidades RT. Figura 3.1 Logotipo de Slackware. De esta forma, a modo de resumen, se deben descargar los siguientes archivos: •Disco de instalación de Slackware 14.1 •Código fuente del Kernel 3.10.17 •Parche de tiempo real para dicha versión •Programas de prueba RT tests 11 18 Capítulo 3. Instalación y parcheado del sistema operativo basado en Linux Código 3.7 lilo.conf. ... image = /boot/vmlinuz-custom-3.10.17 #Nuevo bloque para incluir la imagen del # kernel parcheado root = /dev/sda2 # Linux-rt label = Realtime read-only # Linux bootable partition config ends Para aplicar los cambios se escribe lilo en el terminal. La opción que se acaba de introducir aparece marcada con un asterisco si el proceso se ha realizado satisfactoriamente. La última comprobación para saber si se ha compilado correctamente el kernel es ejecutar el comando uname una vez se arranque el sistema equipado con el mismo. Código 3.8 Comprobación. root@darkstar:~ # uname -r 3.10.17-rt12-realtime 3.4 Pruebas de rendimiento Por último se realizarán los mismos tests de rendimiento empleados para caracterizar el sistema que los empleados en [1, Sección 6.6]. El primero de ellos es cyclictest, que se encarga de medir los tiempos de latencia creando procesos y midiendo el tiempo entre interrupciones, y que supone el principal instrumento para conocer el determinismo del sistema. Asimismo, para proveer un entorno de carga exigente se empleó el programa hackbench, que se ejecuta en paralelo a la ejecución del código de control y la medición de latencias. Su funcionamiento es simple pero efectivo; envía un número de paquetes en forma de hilos a través del procesador (o procesadores en el caso de tratarse de un sistema de varios núcleos), de un tamaño determinado, siendo ambos parámetros introducidos por el usuario. Un mayor tamaño se traduce en una carga más grande, que junto con el número de paquetes determina el tiempo durante el cual el sistema permanecerá cargado. 3.4.1 Paquete rt-tests-1.3 Se trata de la versión más reciente que incluye todas las herramientas necesarias para poner a prueba el sistema. Se pueden conseguir en https:// www.kernel.org/ pub/ linux/ utils/ rt-tests/ . Para la compilación es necesario disponer de las librerías NUMA (Non Uniform Memory Acess) y algunos paquetes de desarrollador, que se descargan de www.gnu.org/ software/ . A continuación se facilita una lista de todas los paquetes y versiones que se han utilizado: •numactl 2.0.12 •Autoconf 2.69 •Automake 1.16 •libtool 2.4 •m4 1.4 Todas las instrucciones que hacen referencia a cada paquete se encuentran recogidas en el archivo INSTALL correspondiente. Nótese que las versiones empleadas son distintas que en [1, Sección 6.6.1]. 3.4 Pruebas de rendimiento 19 Figura 3.11 Histograma de latencias de los núcleos. 3.4.2 Perfil de carga Los parámetros y características del ensayo con hackbench ycyclictest son los siguientes: •Prioridad de ejecución del hilo de 99% •Tiempo del ensayo aproximadamente de 24h •Un hilo por CPU •Tiempo entre hilos de 1000µs A diferencia de [ 1 ], en el presente trabajo no era posible disponer fácilmente de varias terminales mediante las que ejecutar al mismo tiempo hackbench ycyclictest. La manera de solucionarlo es ejecutar el primero con los parámetros anteriores y enviarlo al segundo plano. Esto se realiza con la combinación de teclas CTRL+Z para detener el proceso y a continuación escribiendo en la terminal bg para ponerlo en segundo plano, dejando la terminal libre para poder ejecutar cualquier otro programa al mismo tiempo. Para recuperarlo desde este estado basta con escribir fg. Código 3.9 Ejecución de las pruebas. root@rtlinux:~ # cd /usr/src/TFM/rt-tests-1.3 root@rtlinux:/usr/src/TFM/rt-tests-1.3 # hackbench -s1000 -l1000000 #Presionamos CTRL+Z tras ejecutar esta línea. root@rtlinux:/usr/src/TFM/rt-tests-1.3 # bg #Se manda al background root@rtlinux:/usr/src/TFM/rt-tests-1.3 # cyclictest -t -p99 -i1000 3.4.3 Resultados de las pruebas A continuación, en la figura 3.11, se presenta la distribución de latencias conseguida con las condiciones de prueba descritas en las anteriores secciones. Para obtener el gráfico se le indicó a cyclictest que escribiera un fichero de texto con todos los datos y éstos se procesaron con un script de MATLAB, que puede encontrarse en el anexo B. El gráfico anterior permite ver una tendencia clara de latencias alrededor de los 10µs . Este resultado es unas diez veces mejor que el obtenido con el equipo original con el que se realizaron las primeras pruebas de caracterización de un sistema en tiempo real (del orden de 500 µs , [ 1 , Sección 6.6.3]), poniendo de manifiesto 20 Capítulo 3. Instalación y parcheado del sistema operativo basado en Linux Figura 3.12 Segunda prueba de rendimiento. la relevancia del uso de un hardware ysoftware actualizados y con buenas prestaciones en la construcción de un sistema con capacidades en tiempo real. En cuanto al peor escenario, en esta primera prueba se obtuvieron 34 µs , también muy por debajo de la cifra de 1048 µs obtenida con el primer montaje experimental. Para validar estos datos se realizó una segunda prueba con los mismos parámetros de carga que en la tabla 3.4.2, pero limitando la latencia máxima representada en el histograma a 60 µs . Los resultados se recogen en la figura 3.12. Al igual que en el anterior caso, las latencias están distribuidas alrededor de 10 µs , y la más desfavorable se mantiene en el orden, aumentando ligeramente hasta 48 µs Un comportamiento que se puede observar que el núcleo número 4 presenta un peor rendimiento que el resto, puesto que el número de bucles con latencias mayores es superior al del resto. Estos resultados resultan más que satisfactorios para implementar una unidad de control electrónico que presente una frecuencia de muestreo típica de 50 Hz (2ms entre muestreos consecutivos), dejando un margen muy amplio para el procesado de la señal de control. Mediante estas pruebas queda demostrada la idoneidad del sistema adquirido para servir como unidad de control electrónico para el vehículo FOX y para presentar el comportamiento determinista necesario para asegurar un nivel de seguridad suficiente para su correcto funcionamiento, a falta de validar experimentalmente estas afirmaciones. Estos aspectos se estudian en las posteriores secciones. 4 Controller Area Network (CAN) El siguiente componente de la unidad de control electrónico a estudiar es el bus datos CAN (Controller Area Network). Éste se emplea para hacer posible la comunicación entre la ECU y otros dispositivos que proporcionan el control automático del vehículo, como el supervisor. La manera de implementarlo en el sistema que se ha considerado hasta ahora, formado por la tarjeta principal PCM-3365, es mediante una placa controladora adicional compatible. La opción comercial elegida es el módulo con factor de forma PC/104 PCM-3680I de Advantech, que será estudiada en la sección 4.2. La verificación del correcto funcionamiento de este sistema de comunicación en la ECU sugirió varias ideas y situaciones. Se planteó la posibilidad de establecer una conexión a través de bus CAN entre la ECU y una tarjeta microcontroladora externa, la Mbed LPC1768 de ARM, estudiada en la sección 4.3, como una manera fiable de confirmar que la comunicación se produce correctamente entre varias capas físicas independientes. Las situaciones consideradas por tanto incluyen la conexión en ambos sentidos de los dos dispositivos considerados y entre sus canales disponibles, en la que se intercambian los papeles de transmisor y receptor. Los dispositivos disponibles para esta fase fueron: •Tarjeta CAN PC/104 de Advantech, modelo PCM-3680I •Microcontrolador Mbed de ARM, modelo LPC 1768 Los conocimientos necesarios previos a la descripción más detallada de los dispositivos y sus métodos de interconexión a través de bus CAN son esencialmente los relacionados con la capa física del protocolo, que se describe a continuación en la sección 4.1. 4.1 Nociones sobre la capa física del protocolo CAN La capa física CAN es aquella que en la representación del modelo OSI (Open System Interconection) se encuentra en el nivel más bajo del protocolo (véase la figura 4.1). Algunas de sus características se encuentran recogidas en el estándar ISO 11898 junto a la capa de datos. Más concretamente, el ISO-11898-2 especifica las subcapas PMA (Physical Medium Attachement)y MDI (Medium Dependent Interface) de la capa física. Los aspectos relacionados con la señalización física (PS, Physical Signaling) se encuentran definidos por la especificación CAN. El diseñador del sistema de comunicaciones puede elegir cualquier transmisor/receptor y medio de transporte de la información mientras que se cumplan los requisitos de PS. En este contexto, la Organización Internacional de Estandarización (ISO) ha definido un estándar que incluye la especificación CAN junto con la de la capa física (ISO 11898). Éste fue originalmente creado para las intercomunicaciones de alta velocidad para vehículos a través de CAN. En la figura 4.2 se representa un controlador CAN completo definido por la especificación dehardware. 4.1.1 MCP2551 El MCP2551 es un circuito integrado en un paquete Dual-In-line Package (DIP) de 8 pines que implementa un transceptor CAN de manera compacta. El datasheet de este componente resulta fácil de encontrar online, y es necesario para conocer el pinout a la hora de incluirlo en un circuito. La manera de reconocer los pines 21 22 Capítulo 4. Controller Area Network (CAN) Figura 4.1 Modelo OSI del protocolo CAN [8]. Figura 4.2 Modelo de hardware CAN. Figura 4.3 pinout del MCP2551. 4.1 Nociones sobre la capa física del protocolo CAN 23 Tabla 4.1 Tabla de pinout. Pin Etiqueta Descripción 1 TXD Entrada de transmisión de datos 2Vss Tierra 3VDD Tensión de alimentación 4 RXD Salida de recepción de datos 5RsEntrada de control de pendiente 6 CANH E/S de nivel alto CAN 7 CANL E/S de nivel bajo CAN 8VREF Salida de referencia de voltaje Figura 4.4 Niveles lógicos CAN. sobre el paquete físico es notar la marca de referencia en la parte superior del mismo. El primer pin a la izquierda de ella recibe el número 1, y los consecuentes pines se suceden en orden ascendente en sentido antihorario, tal y como se muestra en la figura 4.3 En la tabla 4.1 se encuentra la descripción de cada uno de los pines del MCP2551. Las características principales listadas en el datasheet correspondiente [9] se presentan a continuación. •Soporta velocidades de hasta 1Mbps. • Cumple con los requerimientos de la normativa ISO-11898 relativos a la capa física del protocolo CAN •Válido para sistemas de 12V y 24V. •Pendiente controlada de manera externa para reducir interferencias electromagnéticas (EMI). •Detección de falta de tierra- 4.1.2 Niveles lógicos Los niveles lógicos se dividen en recesivo y dominante. El estándar ISO-11898 define un voltaje diferencial para representar estos estados, tal y como se muestra en la figura 4.4 En el estado recesivo (1 lógico en la entrada TXD del MCP2551) el voltaje diferencial entre CANH y CANL es menor que el umbral mínimo (<0.5V en la entrada del receptor o <1.5V en la salida del transmisor, tal y como se aprecia en la figura 4.5); en el estado dominante (0 lógico) el voltaje diferencial en CANH y CANL es mayor que el umbral mínimo. Un bit dominante sobreescribe a un bit recesivo en el bus para conseguir un arbitraje no destructivo mediante bits. Como puede observarse en la anterior figura, cuando el voltaje diferencial de la salida se encuentra entre 1.5V y 3V se considera un nivel lógico dominante, mientras que el estado será recesivo cuando se encuentre entre -0.5V y 0.05V. Del mismo modo, en el caso de la entrada se aprecia que el rango se extiende desde los 0.9V a los 5V para el 1 lógico y entre los -1V y 0.5V para el 0 lógico. 24 Capítulo 4. Controller Area Network (CAN) Figura 4.5 Umbrales para el voltaje diferencial de transmisor y receptor en estados recesivo y dominante. Tabla 4.2 Características de la tarjeta PCM-3680I . Velocidad de transmisión Hasta 1 Mbps Frecuencia del controlador 16 MHz Protección Aislamiento óptico Leds indicadores Uno por puerto Temperatura Amplio rango de operación Sistemas operativos soportados WinXP/Vista/7 y Linux (32 y 64 bits) WinCE 5.0/6.0 4.1.3 Conectores Aunque el estándar ISO-11898-2 no especifica qué tipo de conectores han de emplearse, sí se indica que aquellos que se empleen deben cumplir con los requisitos eléctricos de la especificación. Asimismo, se requieren resistencias de terminación de un valor nominal de 120Ω en cada extremo del bus con el objeto de evitar "rebotes" de la señal como consecuencia de un desajuste de impedancias. 4.2 PCM-3680I Este módulo es el encargado de añadir físicamente la capacidad de comunicación mediante bus CAN al sistema. Se trata de una tarjeta con factor de forma PC/104 con dos canales de bus de datos CAN independientes. Sus principales características son las reflejadas en la tabla 4.2 [10]. Asimismo, este módulo dispone de un puerto PCI/104 para conectar a la computadora PCM-3365. 4.2.1 Instalación de drivers Con el objeto de gestionar la red de comunicación es necesario instalar los controladores o drivers del dispositivo PCM-3680I. Junto a la misma se incluye un disco de instalación, pero tras consultar su documentación se llegó a la conclusión de que los drivers solo son válidos para versiones del kernel 2.6.x.x. Por tanto, fue necesario acudir al sitio web de Advantech para encontrar los controladores más recientes. Respecto a las versiones soportadas, se encontró la información recogida en la tabla de la figura 4.7; como es posible observar, las pruebas realizadas por los desarrolladores de estos controladores emplearon versiones del Kernel similares a la que se implementó en el anterior capítulo (recuérdese que era la 3.10.17). Además, en el apartado relativo a soporte se indica que son válidos para versiones 2.6.33 y posteriores, lo cual concuerda con la instalada. 4.2 PCM-3680I 25 Figura 4.6 Módulo CAN PCM-3680. Figura 4.7 Soporte de las versiones del Kernel. En https:// www.advantech.com/ products se encuentra el repositorio con los drivers más recientes. Los archivos de los que es necesario disponer son un archivo comprimido CAN cards (PCI-1680_MIC-3680_PCM- 3680I)_advSocketCAN_V1.0.0.0.tar.gz y el documento de texto con la información relativa a la instalación. Cabe comentar que para facilitar el manejo del archivo en el sistema de archivos de Linux es posible autocompletar el nombre del mismo escribiendo los primeros caracteres y pulsando la tecla TAB. Código 4.1 Extracción de drivers. root@rtlinux:~ # cd /usr/src/TFM root@rtlinux:/usr/src/TFM # tar -zxvf CAN cards (PCI-1680\_MIC-3680\_\textit{PCM -3680I})\_advSocketCAN\_V1.0.0.0.tar.gz root@rtlinux:/usr/src/TFM # cd advSocketCAN_V1.0.0.0/\textit{drivers} root@rtlinux:/usr/src/TFM # make #Se compilarán los archivos advsocketcan.ko y advcan_sja1000.ko root@rtlinux:/usr/src/TFM # make install #Con este comando se instalan los \ textit{drivers} El siguiente aspecto a considerar fue que estos drivers se cargaran automáticamente durante el arranque del equipo. Para ello es necesario modificar el fichero encargado de hacerlo, esto es, rc.modules-3.10.17-smp del directorio /etc/rc.d empleando cualquier editor de texto de Linux. Para más información sobre el uso de vim (Vi IMproved) se recomienda la consulta de [ 1 ]. Sin embargo, la versión 14.1 de Slackware incluye nano, que posee más funcionalidades, por lo que se empleará a lo largo de todo el presente proyecto. 26 Capítulo 4. Controller Area Network (CAN) Figura 4.8 Carga de drivers. Código 4.2 Carga automática de drivers. root@rtlinux:~ # cd /etc/rc.d root@rtlinux:/etc/rc.d # nano rc.modules-3.10.17-smp Los nombres de los módulos adicionales a cargar se encuentran descritos en el archivo de texto que se proporciona con los drivers. El aspecto del fichero tras la modificación debería ser el que aparece en la figura 4.8 (téngase en cuenta que sólo se muestra el fragmento modificado). Para futuras referencias se transcribe el contenido del fichero considerado en el código 4.3, que como puede observarse en la figura 4.8 se decidió insertar justo al principio de todos los módulos ya incluidos: Código 4.3 Inclusión de drivers CAN. ### Can driver: # \textit{drivers} de la tarjeta CAN de ADVANTECH /sbin/modprobe lp /sbin/modprobe can /sbin/modprobe can_dev /sbin/modprobe can_raw /sbin/modprobe advcan_sja1000 /sbin/modprobe advsocketcan No hay que olvidar reiniciar el equipo tras la modificación de estos archivos para que los scripts se ejecuten. La primera manera de comprobar que la operación ha sido llevada a cabo con éxito es que durante la carga del sistema operativo aparecerá momentáneamente un gráfico compuesto por caracteres ASCII en el que se da la bienvenida a los drivers de la tarjeta CAN y se comprueban ambos canales disponibles. La segunda consiste en ejecutar el comando ip link list en el terminal. Esta orden ( ip ) junto con el sufijo ( link ) muestra las interfaces de la capa de enlace de datos del sistema, esto es, aquella que recibe las peticiones de la capa de red y hace uso de los servicios de la capa física por donde se transmite la información. Con los nuevos drivers incluidos deben aparecer dos nuevas interfaces, can0 y can1 , correspondientes a los dos canales CAN de los que se dispone. Además, por defecto estas interfaces estarán desactivadas. Todos estos aspectos 4.2 PCM-3680I 27 Figura 4.9 Lista de enlaces de datos. Figura 4.10 CAN activado. aparecen en el terminal tal y como se indica en la figura 4.9, donde se puede comprobar el estado DOWN en la línea de cada interfaz CAN. Este es el estado en el que ambos enlaces se encontrarían cada vez que se arranque el sistema. Con el objeto de evitar esto se realizó un script que se ejecuta en el arranque y que los activa con los parámetros recomendados en la documentación de los drivers. La manera de llevar a cabo esto es añadir las siguientes líneas al archivo rc.local: Código 4.4 Modificación en el fichero rc.local. ip link set can0 up type can bitrate 125000 ip link set can1 up type can bitrate 125000 Con ello lo que se está haciendo es activar cada una de las interfaces (can0 y can1) y asignándoles una velocidad de 125000 bits por segundo. Ejecutando de nuevo ip link list se obtiene por pantalla el contenido de la figura 4.10. Con esto finaliza el proceso de instalación de los drivers de la tarjeta PCM-3680I. Una de las formas más sencillas posibles de comprobar la interfaz CAN consiste en intercomunicar los dos canales disponibles. 4.2.2 Comunicación entre canales El árbol o tree de directorios del código fuente de los drivers contiene una carpeta de ejemplos (advSocket- CAN_V1.0.0.0/examples) donde se encuentra un fichero mediante el que es posible probar el desempeño de las comunicaciones CAN de la tarjeta PCM-3680I. En el apartado 5 de la documentación incluida con los drivers, véase [ 11 ], se encuentra la línea de comandos necesaria para compilar los scripts de lectura y escritura de mensajes en el bus, que simplemente consiste en emplear el comando make en el directorio advSocketCAN_V1.0.0.0/examples. 34 Capítulo 4. Controller Area Network (CAN) (a) Administrador de dispositivos . (b) Ventana principal de Putty . Figura 4.18 Visualización a través de terminal. Código 4.7 Programa de prueba. 1 #include "mbed.h" 2 3 int main() { 4 while(1) { 5 printf("hola mundo"); 6 break; 7 } 8 } Si se compila el programa tal y como se explicó en la sección 4.3, se copia el archivo .bin en la carpeta del dispositivo, se abre un terminal en Putty y se pulsa el botón reset de la placa, el terminal debe reflejar la frase "hola mundo", como se puede apreciar en la figura 4.19. Un primer problema que se observó en el terminal de Putty fue la incorrecta alineación de las sucesivas líneas de salida del programa. Esto se puede arreglar en la pestaña de opciones Terminal, tal y como se muestra en la figura 4.20a Para facilitar el trabajo, es posible almacenar todas las opciones que se han ido introduciendo (nomre del 4.3 Mbed LPC1768 35 Figura 4.19 Mensaje de prueba en el terminal. (a) "Fix" del terminal. (b) Guardar sesión . Figura 4.20 Mejoras de Putty. puerto serie y opción para alinear terminal) en un perfil que se puede cargar automáticamente al inicio de Putty (obsérvese la figura 4.20b) De esta manera se podrá tener una visión inmediata sobre la salida de la transmisión y la recepción de la LPC-1768 a través de la pantalla del PC del laboratorio, aspecto clave para la evaluación de la validez de la prueba. A continuación se analiza el código de ejemplo de intercomunicación de los canales propuesto en [13]. Código 4.8 Programa de prueba para comunicación CAN. 1 #include "mbed.h" 2 3 Ticker ticker; 4 DigitalOut led1(LED1); 5 DigitalOut led2(LED2); 6 CAN can1(p9, p10); 7 CAN can2(p30, p29); 8 char counter = 0; 9 10 void send() { 11 printf("send()\n"); 12 if(can1.write(CANMessage(1337, &counter, 1))) { 13 printf("wloop()\n"); 14 counter++; 15 printf("Message sent: %d\n", counter); 36 Capítulo 4. Controller Area Network (CAN) Figura 4.21 Salida del programa de intercomunicación del LPC-1768. 16 } 17 led1 = !led1; 18 } 19 20 int main() { 21 printf("main()\n"); 22 ticker.attach(&send, 1); 23 CANMessage msg; 24 while(1) { 25 printf("loop()\n"); 26 if(can2.read(msg)) { 27 printf("Message received: %d\n", msg.data[0]); 28 led2 = !led2; 29 } 30 wait(0.2); 31 } 32 } En primer lugar se define un Ticker, que consiste en una interfaz para establecer una interrupción recurrente que llame a una función con una determinada frecuencia. A continuación se asignan las salidas que se emplean en la prueba; dos leds indicadores y las dos interfaces CAN. Asimismo se asigna el valor 0 a un contador necesario para la función send(). Ésta imprime por pantalla una línea cada vez que se ejecuta, y si se envía correctamente el mensaje CAN (con las siguientes características: identificador 1337, dirección señalada por la variable counter como contenido y longitud de 1 bit)al bus mediante la función CANMessage el contador se incrementa y notifica el éxito de al operación, cambiado de estado el led 1. Para la función principal se especifica que el Ticker produzca una interrupción para mandar un mensaje cada segundo, para crear después otro en blanco que será en el que se almacenen los sucesivos enviados por send(). Por último y de manera cíclica, si se tiene éxito leyendo con can2.read, se notifica y se cambia de estado el segundo led, produciéndose entonces una espera de 0.2s. Con ello debe apreciarse un parpadeo sucesivo de los dos leds indicadores; el del canal 1 para la escritura y el del 2 para lectura. Esto se comprobó sin problemas, lo cual indica el correcto funcionamiento de la prueba y garantiza que se es capaz de leer y escribir en el bus de datos mediante la LPC-1768. Además, haciendo uso de la comunicación puerto serie, se pudo comprobar la correcta ejecución del programa, tal y como se muestra en la figura 4.21 4.4 Comunicación entre dispositivos 37 Figura 4.22 Diagrama de conexión entre placas. Figura 4.23 Pinout del conector DB9. 4.4 Comunicación entre dispositivos Una vez probado cada uno por separado, se procedió a conectarlos entre ellos para comprobar las capacidades conjuntas del bus CAN y el sistema operativo en tiempo real implementado para la ECU. El esquema de conexión se muestra en la figura 4.22 Conviene hacer referencia al pinout del conector DB9 que comunica ambos dispositivos. En [ 10 ] se detallan las asignaciones de cada uno de ellos, que para una referencia rápida se encuentran en la figura 4.23. Es importante tener en cuenta si la terminación es macho o hembra para realizar las conexiones correctamente. Por otra parte, no es necesario conectar un jumper al terminal de tierra. Nótese también que se ha omitido del circuito uno de los trasceptores MCP-2551, puesto que este componente ya se encuentra implementado en la placa PCM-3680I. Mediante este esquema de conexión se está en condiciones para comenzar con los dos casos que se consideraron. En las siguientes secciones se analiza el bus con la ECU como receptor (RX), siendo la LPC-1768 el elemento complementario. 4.4.1 Prueba de funcionamiento El programa para escribir en el bus CAN mediante la Mbed LPC1768 se obtuvo de [ 16 ], y se adjunta a continuación en el código 4.9: 38 Capítulo 4. Controller Area Network (CAN) Código 4.9 Programa para escribir en el bus CAN. 1 #include "mbed.h" 2 3 DigitalOut led1(LED1); 4 CAN can1(p30, p29); 5 char counter = 0; 6 int main() { 7 can1.frequency(125000); 8 printf("send... "); 9 while(1) { 10 if (can1.write(CANMessage(1, &counter, 1))) { 11 printf("Message sent: %d\n", counter); 12 counter++; 13 led1=!led1; 14 }else{ 15 can1.reset(); 16 } 17 wait(1); 18 } 19 } El funcionamiento del programa consiste en utilizar el canal que se establece entre los pines 29 y 30 de la Mbed para escribir un mensaje CAN cada segundo, en el se envía un contador en el campo de datos y se imprime por pantalla tanto el contenido del mensaje como el estado de la comunicación, además de emplear un led como indicador luminoso de cada transmisión. En la línea 10 se evalúa mediante un bucle if el éxito de la transmisión, reseteando el bus si no se produce. Es de vital importancia para la comunicación que tanto RX y TX se encuentren a la misma frecuencia. En este caso hay que recordar que, según lo introducido en el código 4.4, el bus CAN transfiere los datos a 125000 bits por segundo. La manera de seleccionar la frecuencia CAN en la LPC1768 es mediante la asignación del atributo frequency al objeto can , línea 7. Si se omite este paso la comunicación no será posible en ningún sentido, corriéndose el riesgo de bloquear el sistema operativo. En el caso de la Unidad de Control Electrónico, formada por la PCM-3365 e integrada en el bus mediante el módulo PCM-3680I, basta con utilizar el programa de ejemplo de lectura CAN para recibir la información. Las únicas modificaciones que se introdujeron fueron la eliminación de los caracteres "0x" que preceden a los bits contenido del mensaje (puesto que el programa de escritura de ejemplo envía números en formato hexadecimal) y de todos los mensajes que imprimen por pantalla el contenido salvo uno, puesto que el mensaje que se pretende enviar tiene una longitud de un bit. Además, por simplicidad, se omite la impresión del DLC o longitud en bits del mensaje. El resultado que se debe visualizar en el shell del PCM-3365 puede deducirse del análisis del código de lectura de ejemplo, detallado a continuación con las modificaciones realizadas. Código 4.10 Programa de ejemplo readCAN. 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <net/if.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <sys/ioctl.h> 9 10 #include <linux/can.h> 4.4 Comunicación entre dispositivos 39 11 #include <linux/can/raw.h> 12 #include <linux/can/error.h> 13 #include <fcntl.h> 14 15 int main(int argc,char **argv) 16 { 17 int s,i; 18 int nbytes; 19 struct sockaddr_can addr; 20 struct can_frame frame; 21 struct ifreq ifr; 22 char ifname = argv[1]; 23 int setflag,getflag,ret =0; 24 if (argc != 2) 25 { 26 printf("usage: readCAN <CAN interface> \n"); 27 printf("ex. readCAN can0\n"); 28 return 0; 29 } 30 if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { 31 perror("Error while opening socket"); 32 return -1; 33 } 34 35 strcpy(ifr.ifr_name, ifname); 36 ioctl(s, SIOCGIFINDEX, &ifr); 37 38 39 addr.can_family = AF_CAN; 40 addr.can_ifindex = ifr.ifr_ifindex; 41 42 if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 43 perror("Error in socket bind"); 44 return -2; 45 } 46 47 48 setflag = setflag|O_NONBLOCK; 49 ret = fcntl(s,F_SETFL,setflag); 50 getflag = fcntl(s,F_GETFL,0); 51 52 can_err_mask_t err_mask = CAN_ERR_TX_TIMEOUT |CAN_ERR_BUSOFF; 53 ret = setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof( err_mask)); 54 if (ret!=0) 55 printf("setsockopt fail \n"); 56 57 printf("using %s to read\n", ifname); 58 59 while(1) 60 { 61 nbytes = read(s, &frame, sizeof(frame)); 62 if (nbytes > 0) 63 { 64 if (frame.can_id & CAN_ERR_FLAG) 65 printf("error frame\n"); 66 else 40 Capítulo 4. Controller Area Network (CAN) (a) Shell de la LPC-1768 .(b) Shell del PCM-3365 . Figura 4.24 Salidas por pantalla de la primera prueba. 67 { 68 printf("\nID=%d \n",frame.can_id); 69 for (i =0;i$<$frame.can\_dlc;i++) 70 { 71 printf("data[%d]=%d \n",i,frame.data[i]); 72 } 73 } 74 75 } 76 } 77 78 79 return 0; 80 } En la línea 68 se saca por pantalla el identificador del mensaje, mientras que en la 71 se imprime el contenido del mismo. La salida por pantalla va aumentando de línea con la frecuencia que se ha introducido en el código de escritura del bus en la LPC-1768, tal y como se muestra en la figura 4.24. A continuación se procedió a someter a carga al sistema mientras se realizaba la comunicación, ejecutando la herramienta hackbench con los parámetros que se emplearon en la prueba del SO (sección 3.4.2). Además, se presionó el botón reset de la LPC-1768 de manera aleatoria para comprobar la robustez en cuanto a ejecución del programa de lectura en la ECU ante interrupciones imprevistas. Los resultados fueron idénticos a los expuestos en la sección 3.4, lo cual resulta prometedor en la búsqueda del comportamiento determinista del sistema. Así concluye este capítulo, habiéndose acondicionado un sistema de comunicaciones basado en el estándar CAN que resulta de aplicación directa en el ámbito del vehículo FOX. En el siguiente capítulo se empleará esta red junto con los demás dispositivos para realizar una prueba global de comportamiento de la unidad de control electrónico. 5 Montaje experimental y código de ejemplo para controlador de motor eléctrico En este capítulo se emplean todos los conocimientos que se han ido desarrollando en las secciones anteriores como base para realizar un montaje experimental que sirva para demostrar que mediante el hardware y el software escogidos es posible disponer de un sistema de control electrónico del motor para el vehículo FOX que presente las características de determinismo que se fijaron como objetivo del presente proyecto. Se comenzará introduciendo algunas nociones características de un código embarcado basado en Linux, describiendo funciones específicas de este tipo de sistemas operativos cuyas capacidades de tiempo real se añadieron mediante el procedimiento descrito en la sección 3.3, introduciendo a continuación el alcance de la prueba y sus componentes, finalizando por último con el código que se propone para la construcción del demostrador de concepto de unidad de control electrónica. Este análisis incluye la metodología empleada para llevar a cabo la tarea de control mediante código, con las elecciones realizadas y los problemas y soluciones halladas en el proceso de programación. 5.1 Procesos e hilos En la presente sección se pretende exponer los elementos de programación más útiles para realizar la tarea del control electrónico del vehículo: procesos e hilos. La información presentada bajo estas líneas puede ampliarse consultando [17]. Tradicionalmente, un proceso UNIX correspondía a una instancia de un programa en ejecución, más precisamente a un espacio de dirección (space adress) y un conjunto de recursos dedicados a ejecutar el programa. Esta definición se vio formalizada por POSIX. El término hilo proviene del concepto de un hilo individual de ejecución, esto es, un camino "lineal" a través del código. POSIX define un hilo como los recursos necesarios para representar ese único camino de ejecución. Históricamente siempre ha existido el concepto de proceso en los sistemas operativos UNIX. Cada proceso posee una serie de recursos asociados, incluyendo un espacio de dirección, registros de la CPU, un identificador o ID, una serie de descriptores de archivo abierto, un identificador de usuario, una pila o stack, ...etc. Mientras que éste es un buen modelo, sólo permite un camino secuencial de ejecución. Para conseguir algún grado de concurrencia en este modelo, es necesario crear múltiples procesos, que a menudo requieren algún tipo de comunicación entre procesos, que suele resultar cara y pesada en el contexto del tiempo de computación. A finales de los años 80, el concepto de varios hilos de control se hizo popular en la comunidad de UNIX. La idea fundamental era crear un conjunto limitado de los recursos de un proceso y hacer varios juegos del mismo, permitiendo de esta manera la concurrencia dentro de un único proceso. Los recursos que se eligieron fueron los mínimos necesarios para representar un único estado de ejecución. Éste consistía principalmente en los registros de la CPU y la pila o stack. Cada juego se llamó entonces un "hilo". Esto permitió la concurrencia dentro de una aplicación sin necesidad de un mecanismo de comunicación entre hilos. Es importante notar que este modelo conservaba el concepto de proceso único, extendiendo la definición para incluir múltiples 41 42 Capítulo 5. Montaje experimental y código de ejemplo para controlador de motor eléctrico hilos dentro de este proceso. Figura 5.1 Esquema de procesos e hilos. En esta época existieron muy pocas implementaciones experimentales de hilos, y ninguna de ellas en producción. Estaba claro, sin embargo, que resolvía una necesidad creciente, especialmente con el desarrollo de máquinas UNIX con procesador múltiple en el horizonte. También durante este período la estandarización POSIX se encontraba poco desarrollada. Existía un gran impulso por crear un conjunto común de APIs que pudieran garantizarse para todas las implementaciones de UNIX. Algunos investigadores desarrollaron una API que implantaba el modelo multihilo y proponía incluirlo en el estándar POSIX. Se aceptó en forma de borrador bajo el epígrafe de extensiones de tiempo real. Aunque había poca experiencia en el mundo real con hilos, la intención era proveer un marco de trabajo común antes de que aparecieran múltiples implementaciones que competirían entre sí. En los siguientes años, la API para hilos de POSIX (conocida como pthreads) ha pasado por numerosas revisiones y se incorporó al estándar en 1996. La mayoría, si no todas las implementaciones de UNIX incuyen una biblioteca de pthread, y hay muchas aplicaciones que las usan. 5.2 Montaje experimental del demostrador de concepto Una vez presentado el método de programación se procede a diseñar un código de ejemplo que sirva como unidad de control electrónico para un pequeño motor eléctrico como demostrador de concepto. El montaje experimental respondió a los siguientes requisitos: • La idea general consiste en emplear el LPC 1768 como tarjeta de adquisición y escritura de señales tanto analógicas como digitales, comunicándose a través de bus CAN con el conjunto PCM-3375 y PCM-3680I, que actúa como el núcleo de la unidad de control electrónica. •El motor y su velocidad de giro se representan mediante un servomotor Futaba S3003, descrito en la siguiente sección. • El control de revoluciones del motor se realiza mediante un potenciómetro lineal a modo de acelerador. Esta decisión resulta realista si se tiene en cuenta lo expuesto en [ 1 ], donde se aprecia que en el vehículo FOX el acelerador está compuesto esencialmente por un potenciómetro. 5.3 Programación del controlador 43 5.3 Programación del controlador En líneas generales, el código principal de la ECU se programó mediante un hilo de ejecución POSIX, descrito en la primera sección del presente capítulo, asignando una alta prioridad para el scheduler. 5.3.1 Pthreads (POSIX threads) La herramienta que se empleó en la programación consiste en hilos que cumplen con las especificaciones del estándar POSIX. En primer lugar se presentan las funciones y la sintaxis de pthread. Es posible encontrar información más detallada de cada una de ellas en los manuales de Linux Pthread_create Permite crear un hilo POSIX. La sintaxis de esta función es la siguiente: 1 int pthread_create(pthread_t * thread, 2 const pthread_attr_t *attr, 3 void *(*start_routine) (void *), 4 void *arg); • El primer argumento de la función es un puntero a una variable de tipo pthread_t que indica el identificador del hilo. • El segundo argumento es un puntero a un puntero a una variable de tipo const pthread_attr_t con los atributos para la creación del hilo. •A continuación se introduce un puntero a la función principal del hilo desde la cual se creará. •Por último se encuentran los argumentos a la función del hilo. Pthread_join Recoge el retorno del hilo cuando éste termina. Para ello el mismo debe ser de tipo joinable. 1 int pthread_join(pthread_t thread, 2 void **retval); •El primer argumento de entrada indica el identificador del hilo al que aplica esta función •El segundo es un doble puntero vacío que apunta a la variable donde se almacena el retorno del hilo. Pthread_exit Esta función termina el hilo desde la que se llama. 1 void pthread_exit(void *retval); El argumento de la función especifica el retorno que el hilo devolverá para pthread_join. Pthread_cancel La función pthread_cancel() manda una petición de cancelación al hilo desde la que se llama. Si el hilo reacciona o no, y cuándo ocurre la cancelación depende de dos atributos bajo el control de este hilo: su estado y tipo de cancelabilidad. El estado de cancelabilidad de un hilo, determinado por pthread_setcancelstate(), puede ser activado (por defecto para hilos nuevos) o desactivado. Si el estado de cancelabilidad es desactivado, entonces cualquier petición de cancelación permanece en cola hasta que al hilo se le atribuya el estado activado. Si por el contrario un hilo tiene el estado activado, el tipo de cancelabilidad determina cuándo ésta ocurre. El tipo de cancelabilidad, determinado por pthread_setcanceltype, puede ser asíncrono (asynchronous) o diferido (deferred) (por defecto). La cancelabilidad asíncrona quiere decir que el hilo puede ser cancelado en 50 Capítulo 5. Montaje experimental y código de ejemplo para controlador de motor eléctrico Esta función intenta leer un número count de bytes del file descriptor fd en el buffer especificado por la variable de entrada buf. En el caso de que el campo de expiración del file descriptor se encuentre vacío esta función se bloquea, tal y como se especifica en la documentación de la función timerfd_create() [ 22 ]. Este comportamiento es el que permite la periodicidad en la ejecución del hilo con el periodo especificado en make_periodic. Además, en esta función se almacena el número de ciclos de periodo especificado que se ha excedido el tiempo de ejecución del código del hilo, lo cual resulta idóneo para caracterizar el comportamiento del sistema. Función del hilo del controlador Se encuentra en primer lugar, ocupando desde la línea 74 hasta la 177 del código C.1. En la figura 5.6 se presenta el diagrama de flujo de la misma. Anteriormente se ha creado una variable de tipo pthread_t que corresponde al identificador del hilo (h1). Las acciones principales que realiza el programa controlador son la lectura del bus CAN de los mensajes con bit identificador adecuado, generación de la señal de control y escritura de un mensaje CAN con la señal, que será leída por el actuador correspondiente (LPC1768). Para la lectura CAN se comienza con un bloque de comprobaciones, tal y como se puede encontrar en [ 11 ]. Es importante notar que la interfaz CAN que se emplea para la comunicación (can0 o can1) debe incluirse en la variable ifname, y que debe coincidir con aquella a la que está conectado el cable DB9 descrito en 4.4. Tras comprobar que no se ha producido ningún error, se entra en un bucle principal que lee continuamente los mensajes con identificador 1 (los que se deben leer), dejando 2 para los que se escriben. A partir de la línea 142 se encuentra una serie de bucles if que evalúan la posición del potenciómetro y asignan las variables de encendido para los LEDs, que llegarán a la LPC 1768 a través de los mensajes CAN con id = 2. Para el control del servomotor que representa la salida de la unidad de control electrónico se emplea el comando de la línea 166, en la que el dato del mensaje proveniente de la mbed LPC-1768, que contiene la posición del potenciómetro, se adjunta en el quinto byte del mensaje de salida, con identificador 2, para que se modifique la señal de control del servo. En la línea 171 se encuentra una llamada a la función usleep() que sirve de stopping point para la función pthread_cancel. Por último se llama a pthread_exit para salir del bucle y que devuelva un valor vacío (NULL). Función del hilo secundario Con el objeto de comprobar las funcionalidades de pthread_cancel y de establecer un entorno de prueba realista, el código C.1 implementa una parada de emergencia que funciona mediante entrada por pantalla. Un bucle while comprueba periódicamente el valor de una bandera, que cambia de estado en el momento en que se introduce el carácter de parada (que en este caso se eligió 5). Cuando se sale del bucle se realiza una llamada a pthread_exit para terminar el hilo 2. Función principal (main) Desde esta función se crean los hilos, se les asigna prioridad y scheduling policy y se evalúa el estado de los mismos en cuanto se terminan de ejecutar (por parada de emergencia). En cualquier caso, una salida forzada del programa principal (con la combinación de teclas CTRL+C ) en el terminal bash acaba también con cualquier hilo que se haya creado a través de la misma. Este comportamiento puede cambiarse mediante algunos parámetros de las funciones de pthread, pero se decidió dejarlo por seguridad durante las pruebas. El diagrama de flujo se presenta en la figura 5.7 En primer lugar se crean las variables para almacenar la scheduling policy de los dos hilos, y su prioridad. En este ejemplo de prueba se decidió emplear valores bajos para no comprometer el correcto funcionamiento del equipo en caso de producirse un error a la hora de programar. En el caso de la policy FIFO, el valor máximo es de 99. El primer hilo en crearse es el del programa del controlador, tras lo cual se asigna la policy y la prioridad. Se procede de igual manera para el segundo bucle. Se emplea pthread_join para comprobar que los dos hilos han finalizado y poder continuar con la ejecución de la función principal. Por último se incluye código para imprimir por pantalla tanto la policy como la prioridad de ambos hilos, así como el éxito a la hora de finalizarlos. Este bloque se ejecutará unicamente cuando se realice una parada de emergencia del controlador según lo anteriormente dispuesto. 5.4 Caracterización del comportamiento 51 Figura 5.8 Diagrama de flujo del código en la Mbed LPC1768. Código de la tarjeta de adquisición de datos y actuadora (Mbed LPC1768) El código implementado en la tarjeta Mbed LPC1768 queda recogido en el código C.2 del apéndice C. Éste se compiló de la manera descrita en 4.3.1 en la tarjeta Mbed LPC1768. A continuación se explican los principales aspectos que presenta, adjuntándose el diagrama de flujo de la figura 5.8 para su mejor seguimiento. En primer lugar, se inicializan todas las entradas y salidas del microcontrolador, esto es: •Salidas digitales para los LEDs de a bordo. •Salida de tipo PWM para la señal de control del servo. •Entrada analógica para la posición del potenciómetro. Además, en la línea 19 se inicializa la interfaz CAN para permitir la comunicación entre dispositivos. Todas las anteriores acciones han de realizarse respetando el pinout de la Mbed LPC-1768, presentado en la figura 4.12b. la función principal comienza con la asignación de la frecuencia para la señal PWM de control del servo. Es importante su declaración antes del bucle while de la línea 28, puesto que de manera contraria no se produce un comportamiento correcto del dispositivo. Otro de los aspectos más importantes del código es la asignación de la frecuencia de transmisión de datos a través del bus CAN, presentada en la línea 30. Una vez leídos los mensajes procedentes de la ECU se procede a realizar la actuación de control sobre los dos tipos de elementos configurados para ello: de un lado, un patrón de luces LED y de otro el servomotor descrito en la figura 5.2. 5.4 Caracterización del comportamiento Cyclictest yHackbench Con objeto de asegurar el comportamiento determinista de todo el sistema, se realizaron todas las pruebas de idéntica manera a como se expone en la sección 3.4.2. 52 Capítulo 5. Montaje experimental y código de ejemplo para controlador de motor eléctrico Un problema que surgió a la hora de proceder fue que la parada de la función principal con objeto de transferirla a segundo plano (tómese el código 3.9 como referencia) termina con los hilos que se están ejecutando a partir dela misma (main), dejando al sistema sin controlador. Para solucionarlo se hizo uso del comando shell "nohup, del inglés no hung up), cuya sintaxis para pasar la ejecución del controlador a segundo plano dejando libre el shell se presenta a continuación en el código 5.3 Código 5.3 Comandos shell para ejecutar el programa del controlador en segundo plano. 1 root@rtlinux:~ # gcc -pthread -o programa programa.c && nohup ./programa>/dev/ null 2>&1 & En esta línea de comando shell, en primer lugar se compila el código programa.c, adjuntando la librería pthread, para a continuación ejecutar el programa directamente en el background (las dos operaciones se ejecutan secuencialmente empleando el operador && ). Esto libera el terminal para poder ejecutar el perfil de carga con hackbench y monitorizar la latencia con cyclictest. Nótese la sintaxis de la parte del comando que comienza con nohup; lo que se consigue con ella es redirigir la salida que se crea mediante este comando a /dev/null, esto es, eliminándola por completo. En caso de no realizar este ajuste se creará un fichero de salida que irá incrementando su tamaño a medida que avanza el tiempo de ejecución del programa, llegando a llenar efectivamente toda la memoria de la partición principal, dejando inservible el computador. Respecto a la latencia, seguidamente en la figura 5.9 se presenta el histograma obtenido de la ejecución del programa del controlador con un perfil de carga. Figura 5.9 Histograma de latencias del montaje completo. Se observa que los resultados en cuanto a la latencia son ligeramente superiores que en el caso contemplado en la sección de caracterización del comportamiento del sistema sin ejecutar el controlador (secc. 3.4). No obstante, la máxima latencia medida por cyclictest es de 71 µ s, muy por debajo de los 500 µ s obtenidos en [ 1 , Sección 6.6.3]. Nótese también cómo la distribución del histograma se traslada hacia latencias superiores comparado con el de las figuras 3.11 y 3.12. Este hecho puede interpretarse como indicativo de la carga que el montaje experimental supone en el sistema de control electrónico. Medición del tiempo entre paquetes recibidos La primera concepción del código principal de la unidad de control electrónica (código C.1) no consideraba la posibilidad de que la ejecución se realizara de manera periódica, sino que sirvió para comprobar que el programa respondía a estímulos externos en tiempo real. No obstante, tal y como efectivamente se ha presentado en dicho código y se ha explicado en detalle en la anterior sección, fue necesario estudiar un 5.4 Caracterización del comportamiento 53 Figura 5.10 Diagrama de flujo de los dos dispositivos durante la prueba. método para que se forzara al sistema a trabajar de manera periódica, de forma que se cumplieran los objetivos de velocidad de procesamiento. Esta filosofía de programación periódica permite tener la certeza de que el sistema se comporta de manera determinista en cuanto a tiempos de ejecución, lo cual constituye el objetivo más fundamental del presente proyecto más allá de la velocidad efectiva del sistema. Para terminar de confirmar este comportamiento, se realizó una prueba que consistió en medir el tiempo entre que se reciben dos mensajes consecutivos en la Mbed LPC1768, obteniendo de esta manera una idea de la latencia del sistema global (bus CAN, y unidad de control principal PCM-3365). Para ello se emplearon varias herramientas de programación y de generación de archivos en el lenguaje C++. Se creó un código de prueba previa implementación en el programa principal de la ECU en la tarjeta Mbed LPC1768, recogido en el código C.3 del apéndice C. El objeto de este programa no es otro que el de medir los tiempos entre recepción de paquetes a través del bus CAN. El primer paso consistió en averiguar cómo obtener el tiempo de ejecución dentro de una función en el lenguaje mbed. Para ello es posible emplear uno de los timers de los que dispone, que proporciona en segundos el tiempo entre llamadas. Su uso consiste en la declaración previa a la ejecución de la función principal de una variable de tipo timer (línea 17 del código C.3). Ya dentro de la función principal se invoca a t.start() para comenzar el timer y a t.stop() para detenerlo. El siguiente problema consiste en realizar las medidas únicamente cuando se reciba un mensaje nuevo a través del bus CAN, como queda reflejado en la figura 5.10. La documentación del API del bus CAN proporcionada por Mbed [ 23 ] indica que la clase CAN posee una función atributo llamada attach(), que permite crear una interrupción cuando se produce uno de los siguientes eventos del bus [24]: •CAN::RxIrq para nuevo mensaje recibido •CAN::TxIrq para un nuevo mensaje transmitido o abortado •CAN::EwIrq para una advertencia de error •CAN::DoIrq para sobreescritura de datos •CAN::WuIrq para estado de wake up •CAN::EpIrq para error pasivo •CAN::AlIrq para proceso de arbitraje perdido •CAN::BeIrq para error del bus 54 Capítulo 5. Montaje experimental y código de ejemplo para controlador de motor eléctrico Para la aplicación que se pretende llevar a cabo, la primera de ellas resulta idónea, puesto que en virtud de la documentación, es posible lanzar una función cada vez que se produzca este estado en el bus, esto es, que se reciba un nuevo mensaje. Basta entonces con programar dicha función con la parada, lectura y puesta a cero del timer anteriormente descrito. El problema que surgió de esta implementación responde a la naturaleza de las interrupciones que se generan con can.attach(), que son de tipo ISR (Interruption Service Routine). Estas interrupciones presentan la particularidad, entre otras, de que no pueden implementar funciones de entrada/salida con buffer, tales como printf() ofprintf() para interrupciones con un tiempo similar al de vaciado de tal buffer sin que presenten fallos en la ejecución. Dichos tiempos son del orden de 1 ms. Este comportamiento se apreció en el hecho de que periodos entre transmisión de paquetes mediante la PCM-3680I cada vez más bajos empezaban a arrojar unos valores de tiempo transcurrido por pantalla inconsistentes, llegando a quedar en el entorno de decenas de microsegundos cuando se fijaba el periodo en cualquier valor por debajo de 5ms. Esto puede resolverse de varias formas, tal cual se recoge en [ 25 ]. No obstante, en [ 26 ] se proporciona una solución sencilla que consiste en la creación de una variable de tipo booleano que cambia a estado verdadero cada vez que se produce la interrupción. Esta variable se evalúa continuamente en la función principal, y si resulta ser verdadera, imprime por pantalla el valor de la lectura del timer que se ha almacenado en la línea 33 del código C.3. El almacenamiento de los tiempos se terminó realizando de forma similar a la llevada a cabo en la sección 4.3.2: la salida por pantalla del script presentado en el código C.3 se visualiza mediante el programa Putty, proporcionando al mismo la opción de guardar todas las líneas de salida en un archivo con extensión .log . A partir de las medidas es posible crear un histograma y representarlo de forma similar a la presentada en el apéndice B.2. Para facilitar el uso futuro se guardó la sesión al igual que en la sección 4.3.2, incluyendo todas las opciones correspondientes a la sesión del fix del terminal. En la figura 5.11 se presentan las principales opciones para llevar a cabo este último paso. El código que se ejecuta en la ECU aparece recogido en el código C.4, empleado para para enviar mensajes CAN de manera periódica, siendo el tiempo entre ellos (periodo) y su número total dos variables que se pueden modificar a voluntad. El funcionamiento del programa es idéntico al expuesto en el apartado del código C.1, con la creación de un timer que genera un file descriptor que bloquea la ejecución del hilo hasta que no se lee mediante la función wait_period(). En este caso, sin embargo, no se leen mensajes CAN ni se procesa su contenido, sino que simplemente se mandan a una tasa conocida. La diferencia principal de este código frente al C.1 es, como se ha comentado, la capacidad de controlar el número de mensajes CAN que se envían y el periodo de transmisión. Para finalizar este apartado se adjuntan distintos gráficos en los que se presenta la información obtenida de esta última prueba de caracterización. Éstas se han obtenido fijando un periodo de 20ms (50 Hz), y un total de 100000 mensajes, lo cual sugiere un tiempo total aproximado de ejecución de 30 min. Al igual que en las demás pruebas, se ejecuta simultáneamente en segundo plano el programa de carga hackbench con el perfil habitual (véase el código 3.4.2). En la gráfica 5.12 se puede apreciar el histograma de los tiempos de ejecución. Los intervalos en los que se produce el conteo tienen un ancho de 1µs , y responden a una distribución similar a una de tipo normal. La tendencia que se observa es que se cumple el periodo establecido de 20 ms, con algún tiempo de margen en el sentido más favorable. Asimismo, en la figura 5.13 se puede observar un detalle de la distribución completa de tiempos de ejecución (gráfica mensaje frente a tiempo de distancia con el anterior). Puede comprobarse la aleatoriedad de tiempos, aunque en límites razonables alrededor del periodo fijado. El hecho de que no se muestre para 5.4 Caracterización del comportamiento 55 Figura 5.11 Opciones para crear un log file en Putty. Figura 5.12 Histograma de tiempos entre mensajes. 56 Capítulo 5. Montaje experimental y código de ejemplo para controlador de motor eléctrico Figura 5.13 Distribución parcial de tiempos de ejecución. todos los mensajes responde a la densidad de información que ello supondría. Con esta sección de estudio de comportamiento, con los resultados favorables obtenidos, se alcanzan los objetivos que se marcaron para la realización de este proyecto. En la siguiente sección se recapitulan y analizan los resultados obtenidos durante el mismo. 6 Conclusiones y trabajo futuro En este último capítulo se recogen los resultados principales del estudio llevado a cabo en este trabajo, y se valora si son adecuados o no para cumplir con los objetivos planteados al comienzo del proyecto. 6.1 Recapitulación y conclusiones Mediante lo estudiado en los capítulos del bloque uno se ha conseguido poner a punto el computador PCM-3365. Esto ha incluido el hardware necesario (sección 2.4), así como todo el software para el sistema operativo Slackware de Linux, y su adaptación para operar bajo condiciones de tiempo real estricto. Las pruebas llevadas a cabo en la sección 3.4, en condiciones de carga relativamente exigentes comparadas con las que experimenta la unidad de control electrónico en el vehículo FOX muestran la idoneidad del sistema para su uso en dicha aplicación. En cuanto al segundo bloque, se consiguió instalar con éxito una tarjeta de bus CAN (PCM-3680I) en el PCM-3365, junto con sus drivers correspondientes. El uso de un microcontrolador externo con capacidad de comunicación CAN (LPC-1768) ha resultado de utilidad en un doble propósito; de un lado, entender el funcionamiento a bajo nivel del protocolo, mediante el uso del circuito integrado del transceptor CAN MCP2551, y por otro, comprobar la comunicación entre dos dispositivos distintos. El último bloque integró todos los anteriores dispositivos probados junto con otro nuevo, un elemento sobre el que actuar como es un servomotor. Ello ha servido para introducir la generación de una señal PWM y el uso de las entradas analógicas de un microcontrolador genérico. Varias han sido las pruebas realizadas en este contexto; de un lado se implementó un montaje experimental en la sección 5.2 cuyos resultados controlando un servomotor fueron satisfactorios; de otro, se realizaron la caracterización del sistema completo como en la sección 3.4 y un seguimiento exhaustivo de los tiempos de ejecución a través del bus CAN, demostrando un comportamiento periódico (véase la sección 5.3.3), con el periodo establecido en los objetivos de la sección 1.3, y asegurando un éxito de transmisión absoluto de los mensajes incluso con cargas severas. Con todo ello es posible concluir que se está en condiciones de migrar el código de los controladores que se encuentran actualmente implantados en el vehículo al nuevo sistema, y realizar pruebas de caracterización de su funcionamiento mientras se ejecutan dichos códigos. Este planteamiento se desarrolla a continuación en la sección dedicada a trabajo futuro. 6.2 Trabajo futuro 6.2.1 Pruebas de funcionamiento El carácter experimental del sistema estudiado en el presente trabajo, si bien posee unas características que resultan bastantes prometedoras como se acaba de comentar, hace desaconsejable la instalación directa en 57 58 Capítulo 6. Conclusiones y trabajo futuro (a) Primera propuesta . (b) Segunda propuesta . Figura 6.1 Esquemas de pruebas propuestos. el vehículo para pruebas en vivo, debido a la situación de riesgo que podría suponer para el piloto y sus alrededores la pérdida efectiva de control del mismo. La línea de acción más adecuada consistiría en realizar un banco de pruebas externo ubicado en el laboratorio del FCCL, de manera que se pudiera conocer la respuesta del sistema a los datos recogidos de los distintos sensores en la unidad de control electrónico y observar la acción de control sobre los actuadores del vehículo, en este caso los motores. Este tipo de pruebas reciben en el contexto de la validación de conceptos operacionales en ATM (Air Traffic Management)[ 27 ] el nombre de Pruebas en modo sombra, y suponen el nivel de desarrollo del proyecto más alto sin realizar pruebas "en vivo", en las que el vehículo sería directamente controlado por el nuevo sistema. Para llevar a cabo dichas pruebas, se plantean dos métodos hipotéticos. Los esquemas de los mismos se presentan en la figura 6.1: • El primero consistiría en emplazar el nuevo sistema en el interior del vehículo, conectando las entradas de los sensores, y programándolo de manera que las acciones de control se guardaran en un fichero para poderlo consultar a posteriori. • El segundo consistiría en guardar la señal de actuación y los tiempos de ejecución de la misma durante el funcionamiento del vehículo en un fichero que podría alimentar al banco de pruebas externo para comprobar el correcto funcionamiento Apéndice A Prueba de funcionamiento de PCM-3910 En el presente anexo se describe de forma breve la manera de probar el funcionamiento del sistema de control del vehículo sin emplear una fuente de alimentación ATX, construyendo para ello un pequeño convertidor AC/DC de 18V para simular las baterías. La elección de este nivel particular de voltaje se eligió por conveniencia, y se puede modificar sin más que cambiar un único componente del circuito propuesto. Como se ha comentado, el esquema de conexión es parecido al expuesto en la figura 2.3b del capítulo 2, sólo que en lugar de las baterías se conecta la salida de este circuito: Figura A.1 Esquema con convertidor. El tipo de fuente que se construyó es del tipo lineal regulada, en las que no existe tratamiento digital de la tensión para su conversión. La desventaja de este tipo de circuitos es su baja eficiencia frente a las modernas fuentes conmutadas (SMPS, Switched Mode Power Supply), que utilizan modulación de pulsos (PWM). Ello se hace patente en el tamaño de los componentes necesarios y en las pérdidas por calor en algunos de sus componentes. No obstante, su construcción es sencilla si se tienen en cuenta algunos aspectos que se tratan a continuación. A.1 Consideraciones de diseño En primer lugar se recurrió al datasheet de la PCM-3910, en el que se encontró que la tensión de entrada admisible se encuentra entre 10VDC y 24VDC. Los bloques básicos del circuito son transformador, rectificador, filtro y regulador El transformador elegido dispone de una entrada de 230VAC y una salida de 24VAC (figura A.2a). Para convertir este nivel a corriente continua es necesario un rectificador, compuesto por cuatro diodos (puente de onda completa). La tensión que se obtiene tras este componente presenta un fuerte rizado, para lo cual se añadió un filtro consistente en un condensador de una capacidad adecuada. Es importante notar que en la rectificación en un puente de onda completa se cumple la siguiente relación sin carga a la salida: Vout (DC)≃√2Vin(AC)(A.1) 59 66 Capítulo C. Códigos del demostrador de concepto 144 frame2.data[1] = 0; 145 frame2.data[2] = 0; 146 frame2.data[3] = 0; 147 } 148 else if(frame.data[0]>25 && frame.data[0]<=50){ 149 frame2.data[0] = 0; 150 frame2.data[1] = 1; 151 frame2.data[2] = 0; 152 frame2.data[3] = 0; 153 } 154 else if(frame.data[0]>50 && frame.data[0]<=75){ 155 frame2.data[0] = 0; 156 frame2.data[1] = 0; 157 frame2.data[2] = 1; 158 frame2.data[3] = 0; 159 } 160 else{ 161 frame2.data[0] = 0; 162 frame2.data[1] = 0; 163 frame2.data[2] = 0; 164 frame2.data[3] = 1; 165 } 166 frame2.data[4] = frame.data[0]; //se lee directamente la posición del 167 //potenciómetro de los mensajes enviados por la mbed y se le devuelven 168 //sin modificar a través del bus CAN 169 nbytes2 = write(s, &frame2, sizeof(struct can_frame)); 170 } 171 usleep(100); //Esta función es un stopping point para pthread_cancel. 172 173 wait_period(&info); //Función para esperar el periodo de ejecución 174 175 } //*FIN DEL BUCLE PRINCIPAL*// 176 pthread_exit(NULL); 177 } //*FIN DE LA FUNCIÓN DEL HILO 1*// 178 179 180 181 void* fun_hilo2(){ 182 //Esta función interrumpe a la función 1. Es una parada de emergencia 183 //printf("Modo de parada activado \n"); 184 int j; 185 int flag = 0; 186 while(flag == 0){ 187 scanf(" %d",&j); 188 if (j==(int)5){ 189 flag = 1; 190 printf("\n !!!!!!!!!!!! PARADA DE EMERGENCIA !!!!!!!!!!!!!!\n"); 191 pthread_cancel(h1); //cierra el hilo principal 192 pthread_exit(NULL); //terminar hilo 193 } else{ 194 printf("Orden no reconocida"); 195 } 196 } 197 198 199 200 } C.1 Unidad de Control Electrónico (PCM3365 yPCM-3680I)67 201 202 // NOTA: Typecasting = pasar de un tipo a otro; 203 // La sintaxis es (newvartype)name 204 205 206 207 int main(){ //Función principal 208 //*INICIO DE LA FUNCIÓN PRINCIPAL*// 209 210 int policy1; 211 int policy2; 212 213 struct sched_param params1; 214 struct sched_param params2; 215 216 params1.sched_priority = 30; 217 params2.sched_priority = 40; 218 219 220 pthread_create(&h1, NULL, fun_hilo1, NULL); //funcion de llamada del hilo. Se necesitan 221 //cuatro argumentos: La direccion del hilo, los atributos del mismo, la direccion de la funcion del hilo y los 222 // parametros de entrada. 223 224 if(pthread_setschedparam(h1, SCHED_FIFO, ¶ms1)!=0){ 225 printf("SIN ÉXITO AL CAMBIAR LA POLICY 1 /n"); 226 } 227 228 int ret1 = pthread_getschedparam(h1, &policy1, ¶ms1); 229 230 231 232 pthread_create(&h2, NULL, fun_hilo2, NULL); //Creamos el hilo de parada de emergencia. 233 234 if(pthread_setschedparam(h2, SCHED_FIFO, ¶ms2)!=0){ 235 printf("SIN ÉXITO AL CAMBIAR LA POLICY 2 /n"); 236 } 237 238 int ret2 = pthread_getschedparam(h2, &policy2, ¶ms2); 239 /**/ 240 241 242 243 int comp1 = pthread_join(h1,NULL); //Funcion que indica si el hilo 1 ha terminado y devuelve si se quiere el estado de cierre. 244 int comp2 = pthread_join(h2,NULL); //Funcion que indica si el hilo 1 ha terminado y devuelve si se quiere el estado de cierre. 245 246 //COMPROBACIONES PARA EL HILO 1 247 if(comp1==0){ 248 printf("\n\n\n---- COMPROBACIONES----\n\n"); 249 printf("\n hilo 1 terminado \n"); 250 } 251 else{ 252 printf("Fallo en terminar el hilo 1"); 68 Capítulo C. Códigos del demostrador de concepto 253 } 254 255 if (policy1!=SCHED_FIFO){ 256 printf("NO FUNCIONA LA POLICY 1\n"); 257 printf("%d \n",(int)policy1); 258 } 259 else{ 260 printf("POLICY 1 SCHED_FIFO \n"); 261 } 262 printf("la prioridad del hilo 1 es %d \n",params1.sched_priority); 263 264 //COMPROBACIONES PARA EL HILO 2 265 266 267 if(comp2==0){ 268 printf("hilo 2 terminado \n"); 269 } 270 else{ 271 printf("Fallo en terminar el hilo 2"); 272 } 273 274 if (policy1!=SCHED_FIFO){ 275 printf("NO FUNCIONA LA POLICY 2\n"); 276 printf("%d \n",(int)policy1); 277 } 278 else{ 279 printf("POLICY 2 SCHED_FIFO \n"); 280 } 281 printf("la prioridad del hilo 2 es %d \n",params2.sched_priority); 282 /**/ 283 284 } C.2 Código de la tarjeta de adquisición de datos y actuadora (Mbed LPC1768) Código C.2 Código de ejemplo para la tarjeta LPC-1768. 1 #include "mbed.h" 2 3 //Este programa toma la posición de un potenciómetro, la manda a la ECU a travé s del bus CAN y escribe el nivel que ésta devuelve en los LEDs indicadores de la mbed, divididos en cuatro regiones. Además, permite el control de un servomotor mediante PWM. 4 5 // Inicialización de los LEDs 6 DigitalOut led_low(LED1); //LED que se enciende en el primer cuarto del potenci ómetro 7 DigitalOut led_mid_low(LED2); //Segundo cuarto del potenciómetro 8 DigitalOut led_mid_high(LED3); //Tercer cuarto del potenciómetro 9 DigitalOut led_high(LED4); //Último cuarto del potenciómetro 10 11 //Inicilización de la señal de control del servo 12 PwmOut servo(p21); 13 C.2 Código de la tarjeta de adquisición de datos y actuadora (Mbed LPC1768)69 14 //Inicialización de la entrada analógica para el potenciómetro 15 AnalogIn pot(p20); 16 char pot_c; 17 18 //Inicialización de la interfaz CAN 19 CAN can1(p30, p29); 20 21 //Inicialización de variable para guardar mensaje que se lee 22 CANMessage leido; 23 24 25 int main() { 26 27 servo.period(0.020); //Frecuencia de la señal PWM para el servo (20ms) 28 while(1) { 29 30 can1.frequency(250000); //Frecuencia del bus CAN 31 32 //Se crea un mensaje CAN con identificador 1 para escribir en el bus la 33 //posición del potenciómetro. 34 35 pot_c = floor(pot*100); 36 37 if(can1.write(CANMessage(1, &pot_c, 1))){ 38 printf("\n"); 39 t.start(); 40 } 41 42 //Ahora se lee el bus para ejecutar la orden de la ECU, sólo se necesita 43 //leer los mensajes con identificador 2 44 45 can1.read(leido); 46 47 if (leido.id == 2){ 48 //printf("He leido un mensaje con id=2"); 49 t.stop(); 50 printf("\n %f",(float)t); 51 52 led_low = leido.data[0]; 53 led_mid_low = leido.data[1]; 54 led_mid_high = leido.data[2]; 55 led_high = leido.data[3]; 56 57 float pw = 0.002*leido.data[4]/100+0.0003; 58 //printf("%f",pw); 59 servo.pulsewidth(pw); 60 } 61 } 62 } 70 Capítulo C. Códigos del demostrador de concepto C.3 Medición del tiempo entre paquetes recibidos Código C.3 Código de ejemplo para medir tiempos entre recepción mediante la tarjeta LPC-1768. 1 #include "mbed.h" 2 #include <fstream> 3 #include <iostream> 4 5 using namespace std; 6 7 volatile float tiempo; 8 9 volatile bool imprime = false; 10 11 //Inicialización de la interfaz CAN 12 CAN can1(p30, p29); 13 14 //Inicialización de variable para guardar mensaje que se lee 15 CANMessage leido; 16 17 //Inicialización del timer 18 Timer t; 19 20 //Bandera de salidad del bucle principal 21 int flag =0; 22 23 //Función de la interrupción 24 void inter(){ 25 26 can1.read(leido); 27 if(leido.id==2){ 28 flag=1; 29 } 30 31 t.stop(); 32 33 tiempo = t.read(); 34 imprime = true; 35 t.reset(); 36 t.start(); 37 38 } 39 40 41 //Inicio de la función principal 42 int main() { 43 44 cout<<"funcion principal"<<endl; 45 can1.frequency(250000); 46 can1.attach(&inter); 47 48 t.start(); 49 50 while(flag==0){ 51 C.3 Medición del tiempo entre paquetes recibidos 71 52 if (imprime){ 53 imprime=false; 54 cout << tiempo << endl; 55 } 56 } 57 58 cout << "fuera del bucle" <<endl; 59 cout<<"programa terminado"<<endl; 60 } Código C.4 Código de ejemplo para enviar mensajes CAN de manera periódica mediante el montaje PCM- 3365 yPCM-3680I. 1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 #include <sched.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <net/if.h> 9 #include <sys/types.h> 10 #include <sys/socket.h> 11 #include <sys/ioctl.h> 12 #include <linux/can.h> 13 #include <linux/can/raw.h> 14 #include <linux/can/error.h> 15 #include <fcntl.h> 16 #include <sys/time.h> 17 #include <sys/timerfd.h> 18 19 int periodo = 20000; //periodo en us 20 int bucles = 10000; 21 struct periodic_info { 22 int timer_fd; 23 unsigned long long n_perdidas; 24 }; 25 26 static int make_periodic(unsigned int period, struct periodic_info *info) 27 { 28 int ret; 29 unsigned int ns; 30 unsigned int sec; 31 int fd; 32 struct itimerspec itval; 33 34 //Crear el timer 35 fd = timerfd_create(CLOCK_MONOTONIC, 0); 36 info->n_perdidas = 0; 37 info->timer_fd = fd; 38 if (fd == -1) 39 return fd; 40 41 //Hacer el timer periódico 42 sec = period / 1000000; 43 ns = (period - (sec * 1000000)) * 1000; 72 Capítulo C. Códigos del demostrador de concepto 44 itval.it_interval.tv_sec = sec; 45 itval.it_interval.tv_nsec = ns; 46 itval.it_value.tv_sec = sec; 47 itval.it_value.tv_nsec = ns; 48 ret = timerfd_settime(fd, 0, &itval, NULL); 49 return ret; 50 } 51 52 static void wait_period(struct periodic_info *info) 53 { 54 unsigned long long perdidas; 55 int ret; 56 57 ret = read(info->timer_fd, &perdidas, sizeof(missed)); 58 // read se para si no ha pasado del tiempo del timer 59 } 60 61 info->n_perdidas += perdidas; 62 if(perdidas>1){ 63 printf("Perdidas = %llc\n",perdidas); 64 } 65 } 66 67 static int thread_1_count = 0; 68 69 static void *thread_1(void *arg) // FUNCIÓN DEL HILO 70 { 71 struct periodic_info info; 72 73 printf("Comienzo del hilo 1 \n"); 74 75 //Comprobaciones para bus CAN 76 77 int s,i; 78 int nbytes; 79 struct sockaddr_can addr; 80 struct can_frame frame; 81 struct ifreq ifr; 82 char *ifname = "can0"; 83 84 int setflag,getflag,ret =0; 85 if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0){ 86 perror("Error while opening socket"); 87 return (void*)-1; 88 } 89 90 strcpy(ifr.ifr_name, ifname); 91 ioctl(s, SIOCGIFINDEX, &ifr); 92 93 94 addr.can_family = AF_CAN; 95 addr.can_ifindex = ifr.ifr_ifindex; 96 97 if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){ 98 perror("Error in socket bind"); 99 return (void*)-2; 100 } C.3 Medición del tiempo entre paquetes recibidos 73 101 102 103 setflag = setflag|O_NONBLOCK; 104 ret = fcntl(s,F_SETFL,setflag); 105 getflag = fcntl(s,F_GETFL,0); 106 107 can_err_mask_t err_mask = CAN_ERR_TX_TIMEOUT |CAN_ERR_BUSOFF; 108 ret = setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask )); 109 110 make_periodic(periodo, &info); 111 112 // Fin de comprobaciones para bus CAN 113 114 while (thread_1_count<bucles) { //Función principal del hilo 115 116 frame.can_id = 1; 117 frame.can_dlc = 1; 118 119 frame.data[0] = 1; 120 121 nbytes = write(s, &frame, sizeof(struct can_frame)); 122 123 printf("%d\n",thread_1_count); 124 thread_1_count++; 125 126 wait_period(&info); 127 } 128 frame.can_id = 2; //Al final del bucle mandamos un mensaje con id=2 para parar el código 129 // de la mbed LPC-1768 130 131 frame.can_dlc = 1; 132 133 frame.data[0] = 1; 134 135 nbytes = write(s, &frame, sizeof(struct can_frame)); 136 137 return NULL; 138 } 139 140 141 int main() //FUNCIÓN PRINCIPAL 142 { 143 printf("Comprobación de la peridicidad de pthreads\n"); 144 145 pthread_t t_1; 146 147 int policy; 148 struct sched_param params; 149 150 params.sched_priority = 80; 151 152 153 pthread_create(&t_1, NULL, thread_1, NULL); 154 155 if(pthread_setschedparam(t_1, SCHED_FIFO, ¶ms)!=0){ 74 Capítulo C. Códigos del demostrador de concepto 156 printf("SIN ÉXITO AL CAMBIAR LA POLICY /n"); 157 } 158 159 160 int ret = pthread_getschedparam(t_1, &policy, ¶ms); 161 162 sleep(10); 163 164 int comp = pthread_join(t_1,NULL); 165 166 167 //COMPROBACIONES PARA EL HILO 168 if(comp==0){ 169 printf("\n\n\n---- COMPROBACIONES----\n\n"); 170 printf("\n hilo terminado \n"); 171 } 172 else{ 173 printf("Fallo en terminar el hilo"); 174 } 175 176 if (policy!=SCHED_FIFO){ 177 printf("NO FUNCIONA LA POLICY\n"); 178 printf("%d \n",(int)policy); 179 } 180 else{ 181 printf("POLICY SCHED_FIFO \n"); 182 } 183 printf("la prioridad del hilo es %d \n",params.sched_priority); 184 185 186 return 0; 187 } Índice de Figuras 1.1. Vehículo FOX 1 1.2. Entidades promotoras del proyecto CONFIGURA 1 1.3. Esquema general de las conexiones del vehículo 3 1.4. Equipo de pruebas empleado en [1] 3 1.5. Resultados de latencia 4 2.1. SBC PCM-3365 6 2.2. Fuente PCM-3910 6 2.3. Bloques funcionales 7 2.4. Espaciadores 8 2.5. Vista inferior de la placa donde se pueden apreciar las ranuras para la tarjeta SATA y para el módulo de memoria RAM 9 2.6. Conectores 9 2.7. Conexión de la fuente ATX 10 2.8. Conexiones restantes 10 3.1. Logotipo de Slackware 11 3.2. Ventanas de UNetbootin y Rufus 12 3.3. Pinout de CN10 [3] 13 3.4. Pantalla de inicio 13 3.5. Ventanas de instalación 14 3.6. Particiones necesarias 14 3.7. Opciones de instalación 15 3.8. Partición objetivo 15 3.9. Opción USB 15 3.10. ventana de menuconfig 17 3.11. Histograma de latencias de los núcleos 19 3.12. Segunda prueba de rendimiento 20 4.1. Modelo OSI del protocolo CAN [8] 22 4.2. Modelo de hardware CAN 22 4.3. pinout del MCP2551 22 4.4. Niveles lógicos CAN 23 4.5. Voltaje diferencial 24 4.6. Módulo CAN PCM-3680 25 4.7. Soporte de las versiones del Kernel 25 4.8. Carga de drivers 26 4.9. lista de enlaces de datos 27 4.10. CAN activado 27 4.11. Resultado de la comunicación CAN 29 4.12. Detalles del microcontrolador 30 75 82 Bibliografía [21] Developing the pulse width modulation tool (pwmt) for two timer mechanism technique in microcontrollers - scientific figure on researchgate. https:// www.researchgate.net/ figure/ PWM-signal-with-its-two- basic-time-periods_fig4_271437313. [22] Linux man pages. Documentación de la función timerfd_create.man7.org/ linux/ man-pages/ man2/ timerfd_create.2.html, Consultado en 2019. [23] Mbed ARM . Documentación la API del bus CAN. https:// os.mbed.com/ docs/ mbed-os/ v5.14/ apis/ can.html, Consultado en 2019. [24] Mbed ARM . Documentación las funciones miembro de la clase CAN: can.attach(). https:// os.mbed.com/ docs/ mbed-os/ v5.14/ mbed-os-api-doxy/ classmbed_1_1_c_a_n.html# a554dccfc95f8e864de7be65a4a793e98, Consultado en 2019. [25] Jan Jongboom. Simplify your code with mbed-events.https:// os.mbed.com/ blog/ entry/ Simplify-your- code-with-mbed-events/ , Consultado en 2019. [26] Mbed ARM. Foros de preguntas . Explicación relativa a los problemas en el uso de funciones como printf() con interrupciones ISR . https:// os.mbed.com/ questions/68656/ Add-interrupt-into-queue/ , Consultado en 2019. [27] Alfonso Valenzuela Romero. Apuntes de la asignatura Tráfico Aéreo Avanzado del Máster Universitario en Ingeniería Aeronáutica de la Universidad de Sevilla. Tema 6. Validación de Conceptos Operacionales en ATM. Sección 6.4.2. Pág. 97. , Consultado en 2019.