U NIVERSIDAD NACIONAL DE T UCUMÁN - FACULTAD DE C IENCIAS E XACTAS Y T ECNOLOGÍA D EPARTAMENTO DE E LECTRICIDAD , E LECTRÓNICA Y C OMPUTACIÓN I NGENIERÍA EN C OMPUTACIÓN J UNIO 2016 Trabajo de Graduación D ESARROLLO DE UN FRAMEWORK EN LENGUAJE C PARA CONTROLADORES DIFUSOS R EVISIÓN 1 autor Franco Javier S ALINAS M ENDOZA CX1416301 tutor Ing. Esteban VOLENTINI co-tutor Dr. Adrián W ILL Agradecimientos A Leandro Gutierrez, quien trabajó conmigo en los inicios de este proyecto, y a mis tutores, Esteban Volentini y Adrián Will, quienes me acompañaron durante todo el desarrollo. 1 Dedicatorias Dedico este trabajo a mis padres, por su esfuerzo a lo largo de estos años, a mi abuela por su afecto incondicional, y a Lucía, quien me inspiró para seguir adelante. 2 Prólogo A lo largo de este trabajo de graduación se describen los procesos de diseño, implementación y prueba de µFuzzy: un framework de lógica difusa pensado especialmente para sistemas embebidos. A su vez, se presentan dos ejemplos de aplicación sobre un robot móvil autónomo terrestre. 3 Índice general 1. Introducción 1.1. Motivación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 6 7 2. Conceptos de lógica difusa 2.1. Conceptos básicos . . . . . . . . . . . . . . . . . 2.1.1. Estructura de un sistema difuso . . . . . 2.1.2. Funciones de membresía . . . . . . . . . 2.1.3. Parámetros de los sistemas difusos . . . . 2.2. Construcción de un sistema difuso . . . . . . . . 2.2.1. Elección de las variables del sistema . . . 2.2.2. Definición de las reglas . . . . . . . . . . 2.2.3. Definición de las funciones de membresía 2.3. Proceso de inferencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 9 10 10 10 11 11 11 3. Diseño 3.1. Aspectos generales . . . . . . . . . . . . . . . . 3.1.1. Necesidad de un formato propio . . . . . 3.1.2. Visión general . . . . . . . . . . . . . . 3.2. µFuzzy . . . . . . . . . . . . . . . . . . . . . . 3.2.1. Elección del lenguaje de desarrollo . . . 3.2.2. Consideraciones respecto al lenguaje . . 3.2.3. Utilización de aritmética de punto fijo . . 3.2.4. Limitaciones debidas al uso de punto fijo. 3.2.5. Características soportadas . . . . . . . . 3.3. cfsconvert . . . . . . . . . . . . . . . . . . . . . 3.3.1. Características generales . . . . . . . . . 3.3.2. Elección del lenguaje de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 14 14 14 15 15 15 16 16 17 18 18 18 . . . . . . 20 20 20 20 21 21 23 4. Aplicación 4.1. Introducción . . . . . . . . . . . . . . . . . 4.2. Control de lazo cerrado para los motores . . 4.2.1. Estudio de los motores . . . . . . . 4.2.2. Estructura del controlador . . . . . 4.2.3. Diseño del sistema de control difuso 4.3. Seguimiento de pared . . . . . . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Desarrollo de un framework en lenguaje C para controladores difusos 5. Resultados 5.1. Framework . . . . . . . . . . . . 5.1.1. Calidad del código fuente 5.1.2. Pruebas . . . . . . . . . . 5.1.3. Integración a la CIAA . . 5.2. Aplicaciones . . . . . . . . . . . 5.2.1. Control de velocidad . . . 5.2.2. Seguimiento de pared . . . 5.3. Conclusiones y trabajos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anexos A. API de µFuzzy A.1. Tipos de dato . . A.2. Funciones . . . . A.3. Macros . . . . . A.4. Códigos de error 26 26 26 26 28 28 28 29 29 34 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 35 35 39 39 B. Manual de cfsconvert 41 C. Especificación del formato CFS 42 D. Cálculo de los coeficientes de Sugeno-Takagi 46 ÍNDICE GENERAL 5 Desarrollo de un framework en lenguaje C para controladores difusos Capítulo 1 Introducción 1.1. Motivación Desde su formulación en 1965, la lógica difusa se ha utilizado con éxito en inumerables aplicaciones tales como sistemas de predicción de clima, reconocimiento de patrones faciales, automatización industrial y robótica [7], aunque sin dudas, sus aplicaciones más destacadas pertenecen al campo de los sistemas de control. El ejemplo más representativo es el sistema utilizado en el metro de Sendai, Japón. El mismo se encuentra operativo desde 1988 y su desempeño supera tanto a opeararios como a sistemas de control convencionales [5]. Por otro lado, desde hace más de cuatro décadas, la cantidad de transistores en los circuitos integrados aumenta tal como lo establece la ley de Moore, y como consecuencia, su costo se reduce [1]. En el año 1997 Intel lanzó el microprocesador Pentium II 233 a un precio de mercado de US$636. Dos décadas más tarde, en febrero de 2016, la fundación Raspberry PI lanzó la Raspberry PI 3 Model B, una Placa de Tamaño Reducido (SBC) de performance comparable al procesador de Intel a un precio casi 20 veces menor. Por su parte, en el segmento de los sistemas embebidos de bajo costo, un microcontrolador con núcleo ARM Cortex-M0 puede adquirirse por centavos de dólar. Esto permite aplicaciones embebidas cada vez más complejas y abre la puerta a incorporar software e inteligencia artificial a dispositivos que hoy no los tienen, por una fracción mínima de su coste de producción. En el marco del proyecto de investigación del CIUNT, Inteligencia Artificial y Aplicaciones a Robótica, surgió la necesidad de implementar sistemas de control complejos, y la lógica difusa se eligió como herramienta para llevarlos a cabo. Hoy existen diversas librerías de lógica difusa libres y gratuitas tales como fuzzylite, Free Fuzzy Logic Library (FFLL), o Embedded Fuzzy Logic Library (eFLL), sin embargo solo esta última está pensada para sistemas embebidos, lo cual resulta un requisito indispensable para las necesidades del proyecto. Aún asi, esta librería tiene fuertes limitaciones. En primer lugar, utiliza operaciones con punto flotante, lo cual repercute fuertemente en la performance en microcontroladores sin Unidad de Punto Flotante (FPU). En segundo lugar, reserva memoria dinámicamente, lo que la hace inadecuada para Sistemas Operativos en Tiempo Real (RTOSs). Finalmente, no permite realizar ajustes al sistema sin recompilar, lo cual impacta negativamente en el flujo de trabajo. Esto plantea la necesidad de crear una nueva librería, liviana y flexible, que sea capaz de ejecutarse en la gama más económica de los microcontroladores. CAPÍTULO 1. INTRODUCCIÓN 6 Desarrollo de un framework en lenguaje C para controladores difusos 1.2. Objetivos El objetivo central de este proyecto es desarrollar un framework de lógica difusa, capaz de funcionar en microcontroladores de bajo costo independientemente de su arquitectura, y compatible con las herramientas más difundidas de lógica difusa de la actualidad. Dado el potencial de este framework para ser utilizado en aplicaciones industriales en las que la seguridad es prioritaria, se plantea como una meta adicional someterlo a exhaustivas pruebas de funcionamiento. Finalmente, el framework será aplicado en un robot para resolución de laberintos[3] desarrollado en el marco de otro trabajo de graduación. Este robot posee dos microcontroladores: uno para interactuar con los sensores y actuadores, y otro para ejecutar algoritmos de alto nivel y tomas de decisiones. µFuzzy se utilizará en el primero para efectuar control de lazo cerrado sobre las velocidades de los motores, mientras que en el segundo servirá para generar un comportamiento de wall follower. CAPÍTULO 1. INTRODUCCIÓN 7 Desarrollo de un framework en lenguaje C para controladores difusos Capítulo 2 Conceptos de lógica difusa 2.1. Conceptos básicos En la lógica booleana o binaria, esencial para la electrónica digital y la programación de computadoras, cada proposición o variable puede tomar uno de dos valores de verdad: verdadero o falso. Por ejemplo, París está en Francia es una proposición verdadera y Los perros son peces es una proposición falsa. Sin embargo ciertas situaciones no pueden ser modeladas con precisión usando lógica booleana. Considérese la proposición Juan es alto y supóngase que Juan mide 1.75 m. No puede decirse a ciencia cierta si la proposición es verdadera o falsa porque no existe una definición nítida del concepto de altura. Dicho de otro modo, no existe una altura umbral que sirva para clasificar a las personas como altas o bajas. En cambio, tenemos una noción de altura mucho más vaga, dependiente del contexto y cargada de subjetividad. La lógica difusa, que puede entenderse como una extensión de la lógica binaria, modela estas situaciones imprecisas o ambiguas típicas del razonamiento humano, permitiendo que las proposiciones en lugar de ser absolutamente verdaderas o absolutamente falsas puedan tener un cierto grado de verdad. 2.1.1. Estructura de un sistema difuso La Fig. 2.1 ilustra la estructura básica de un sistema de inferencia basado en lógica difusa. Fundamentalmente, está compuesto por un conjunto de reglas, que permiten obtener el valor de ciertas variables de salida a partir de una serie de variables de entrada. Estas reglas, al igual que las de la lógica proposicional, están conformadas por un antecedente y un consecuente. Sin embargo, en la lógica difusa, el valor de verdad de las proposiciones se representa con un número real en el intervalo [0, 1]. Por ejemplo, una proposición con un valor de verdad de 0.8 puede entenderse como razonablemente cierta, mientras que un grado de verdad 0 indica que la misma es absolutamente falsa. Otra diferencia respecto a la lógica clásica, es que las variables involucradas en el proceso de inferencia no son numéricas ni booleanas, sino que son variables lingüísticas. Por ejemplo, si un sistema utiliza la variable temperatura, entonces la misma tomaría valores tales como alta, baja o muybaja, en lugar de valores numéricos expresados en grados. No obstante, si dicho sistema necesitara una medición de la temperatura para funcionar, probablemente la obtendría de un sensor cuya lectura sí sea numérica. Por esta razón, el primer paso en el proceso de inferencia difusa consiste en convertir valores numéricos a valores difusos. Este paso recibe el nombre de fuzzificación. Análogamente, el último paso consiste en realizar el proceso inverso, y se lo conoce como defuzzificación. CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 8 Desarrollo de un framework en lenguaje C para controladores difusos Figura 2.1: Estructura de un sistema de inferencia basado en lógica difusa 2.1.2. Funciones de membresía Antes de poder efectuar la fuzzificación, es necesario dar un sentido a cada uno de los términos lingüísticos utilizados en el sistema. Para el ejemplo anterior, esto implica que se debe definir qué significa que la temperatura sea alta, baja o muy baja. Cabe destacar que el significado de estos conceptos depende de cada sistema particular; lo que para un horno puede ser una temperatura muy baja, para una heladera podría resultar extremadamente alta. Matemáticamente, cada término lingüístico puede entenderse como un conjunto, pero en el que la pertenencia al mismo no es booleana sino difusa. Para cierto sistema, una temperatura de 10 ◦C puede pertenecer en gran medida al conjunto de las temperaturas bajas, en menor medida al conjunto de las temperaturas muy bajas, y no pertenecer en absoluto al conjunto de las temperaturas altas. Estos conjuntos difusos se definen utilizando una función de pertenencia o membresía, que asigna a cada elemento del universo de discurso (en este caso el conjunto de temperaturas posibles), un valor en el intervalo [0, 1] que representa el grado de pertenencia de dicho elemento al conjunto. Por ejemplo, para la variable temperatura podrían definirse las funciones de membresía que se muestran en la Fig. 2.2. Figura 2.2: Funciones de membresía CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 9 Desarrollo de un framework en lenguaje C para controladores difusos 2.1.3. Parámetros de los sistemas difusos En la lógica clásica, los operadores utilizados para la conjunción o la disyunción se definen mediante tablas de verdad. Esto es posible ya que operan sobre valores booleanos y solo pueden ocurrir unas pocas combinaciones de entrada. En cambio, en la lógica difusa las proposiciones pueden tomar cualquier valor en el intervalo [0, 1], por lo que los operadores deben definirse como funciones. El operador conjuntivo puede escogerse de un conjunto de funciones denominadas Tnormas, entre las cuales la más habitual es la función mínimo. Análogamente, el disyuntivo se elige de la familia de S-normas, y la elección más habitual es la función máximo. A su vez, existen diferentes métodos de inferencia, entre los cuales probablemente los más difundidos son el método de Mamdani y el de Sugeno-Takagi. La principal diferencia entre estos métodos es que en el método de Sugeno, los consecuentes de las reglas no utilizan variables lingüísticas, sino que son una constante, o bien una combinación lineal de las entradas. Así, una regla de un sistema basado en el método de Sugeno tiene la forma: SI temperatura es alta Y humedad es baja ENTONCES y = aT + bh + c Donde T y h son los valores numéricos de la temperatura y la humedad respectivamente, a, b y c son constantes, y y es la variable de salida. En la práctica, la ventaja del método de Mamdani es que, ya que los consecuentes utilizan variables lingüísticas, la definición de las reglas resulta más intuitiva. Por su parte, el método de SugenoTakagi, es más eficiente, ya que al utilizar variables numéricas en los consecuentes, el proceso de defuzzificación suele requerir menos operaciones. Otro parámetro que debe definirse es qué método se utilizará para la defuzzificación, es decir, de qué manera se convertirán los conjuntos difusos producto del proceso de inferencia, a valores numéricos. Para el método de Mamdani, el más habitual es el centro de gravedad, mientras que para Sugeno-Takagi suele utilizarse la media ponderada. 2.2. Construcción de un sistema difuso Supóngase que se desea desarrollar un sistema para controlar el nivel de agua en un tanque. El líquido ingresa al mismo a través de una cañería, cuyo caudal puede controlarse mediante una electroválvula. El fluído abandona el tanque a un ritmo variable que depende de un factor externo y no puede controlarse. A su vez, el sistema cuenta con un sensor que mide el nivel del tanque, y otro que mide la presión de agua en la cañería de alimentación. La apertura de la válvula puede ajustarse entre 0 mm2 y 100 mm2 . El nivel de agua óptimo es 1 m. En este caso, se desarrollará un sistema difuso basado en el método de Mamdani, dado que el planteamiento del mismo resulta mucho más intuitivo que con el método de Sugeno. Asimismo, para simplificar la explicación del proceso de inferencia, se utilizarán las funciones mínimo y máximo para la conjunción y la disyunción respectivamente. Como defuzzificador se utilizará el centro de gravedad. 2.2.1. Elección de las variables del sistema La construcción del sistema comienza con la elección de las variables de entada y salida. Se trata de una elección y no una identificación, porque además de la opción trivial de elegir la lectura de los sensores como variables de entrada, podría elegirse el error de los mismos respecto a un punto de referencia; incluso podrían adicionarse variables de entrada tales como las derivadas o las integrales de las lecturas respecto del tiempo. Como salida, por ejemplo, podría elegirse la apertura CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 10 Desarrollo de un framework en lenguaje C para controladores difusos de la válvula, o bien la corrección en la apertura respecto a un modelo ideal. Existen varios criterios para decidir, por ejemplo: si la lectura de los sensores tuviera altos niveles de ruido probablemente la derivada no podría utilizarse; si puede tolerarse cierto corrimiento en el valor de referencia o setpoint puede omitirse la integral; si el valor de referencia es variable posiblemente sea mejor utilizar el error en las lectura del nivel y no el nivel como variable de entrada. En este caso, por cuestiones de simplicidad, se utilizarán sólo las lecturas de los sensores como entradas, y la apertura de la válvula como salida. 2.2.2. Definición de las reglas Las reglas se definen en base al conocimiento de un experto o al estudio del comportamiento del sistema. En este caso, se utilizarán las siguientes: 1. SI nivel es alto ENTONCES apertura es nula 2. SI nivel es normal Y presion es baja ENTONCES apertura es grande 3. SI nivel es normal Y presion es normal ENTONCES apertura es media 4. SI nivel es normal Y presion es alta ENTONCES apertura es chica 5. SI nivel es bajo Y presion es baja ENTONCES apertura es máxima 6. SI nivel es bajo Y presion es normal ENTONCES apertura es grande 7. SI nivel es bajo Y presion es alta ENTONCES apertura es media Puede observarse que en la primera regla, la variable presion no interviene. Esto implica que siempre que el nivel sea alto, la apertura será nula, independientemente del valor de la presión. 2.2.3. Definición de las funciones de membresía Las funciones de membresía, al igual que las reglas, se obtienen a partir de un estudio del sistema. En este caso, se definieron como se ilustra en la Fig. 2.3. Como puede observarse, si el nivel del agua es menor a 80 cm entonces se lo considera absolutamente bajo. A partir de este punto, el nivel comienza a aproximarse a un nivel normal. Un nivel de 1 m es absolutamente normal, pero para alturas mayores comienza a ser alto. Si la altura es mayor a 120 cm entonces el nivel es absolutamente alto. En cuanto a la presión, la misma se considera baja si es inferior 300 kPa, normal si es aproximadamente 500 kPa, y absolutamente alta si supera los 700 kPa. Finalmente, para la apertura de la válvula se definen las etiquetas lingüísticas nula, chica, media, grande, y maxima, que corresponden a aperturas de aproximadamente 0 %, 25 %, 50 %, 75 %, y 100 %. 2.3. Proceso de inferencia Para el ejemplo dado en la sección anterior, se explicará gráficamente el proceso de inferencia cuando el nivel medido es de 105 cm y que la presión es de 400 kPa. El primer paso consiste en la obtención del grado de verdad de cada uno de los antecedentes de las reglas, para el valor actual de las variables de entradas. Como se muestra en la Fig. 2.4, los valores de verdad se obtienen evaluando la función de membresía asociada al término lingüístico que aparece en la proposición. Puede observarse que, por ejemplo, la proposición nivel = alto tiene un grado de verdad de 0.25, y como esa es la única proposición en el antecedente de la primera CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 11 Desarrollo de un framework en lenguaje C para controladores difusos (b) Presión en la cañería (a) Nivel del agua (c) Apertura de la válvula Figura 2.3: Funciones de membresia para las variables del sistema regla, 0.25 también es el peso o valor de verdad del antecedente. A su vez, para la segunda regla, los valores de verdad de las proposiciones nivel = normal y presion = baja son 0.75 y 0.50. En este caso, como se utiliza la función mínimo para la conjunción, el grado de verdad del antecedente resulta ser 0.50. La tabla 2.1 muestra los grados de verdad de los antecedentes de cada regla. regla grado de verdad 1 0.25 2 0.50 3 0.50 4 0.00 5 0.00 6 0.00 7 0.00 Cuadro 2.1: Grados de verdad de los antecedentes de las reglas. Una vez que se conocen los pesos de los antecedentes de cada regla, se procede a truncar las funciones de membresía del correspondiente consecuente, siempre que el valor que tome la función excede el peso del antecedente. El resultado de esta operación se muestra en la Fig. 2.5a. Como puede observarse, las únicas funciones de pertenencia que tienen peso son las correspondientes a las aperturas media, grande y nula, siendo la última la menos relevante. Luego, como se ilustra en la Fig. 2.5b, las funciones de membresía se combinan tomando en cada punto el valor máximo entre ellas para formar un conjunto difuso. Finalmente, se utiliza el método de defuzzificación, que en este caso es el centro de gravedad, para obtener el valor numérico de la variable de salida. En este caso, el cálculo del centro de gravedad da como resultado una apertura CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 12 Desarrollo de un framework en lenguaje C para controladores difusos (b) Presión en la cañería (a) Nivel de agua Figura 2.4: Evaluación de las funciones de membresía de entrada (a) Pesos de cada función de membresía (b) Conjunto difuso de salida y defuzzificación Figura 2.5: Obtención del valor de la variable de salida del 40 %, que representa la salida del sistema difuso. CAPÍTULO 2. CONCEPTOS DE LÓGICA DIFUSA 13 Desarrollo de un framework en lenguaje C para controladores difusos Capítulo 3 Diseño 3.1. Aspectos generales 3.1.1. Necesidad de un formato propio En la actualidad existen diversos formatos utilizados para definir sistemas difusos tales como el Fuzzy Inference System (FIS) de MATLAB, el FuzzyLite Language (FLL) de fuzzylite o el Fuzzy Control Language (FCL). Sin embargo, estos formatos no son los más adecuados para ser utilizados en microcontroladores de bajo costo, dado que estan basados en texto y el análisis de estos archivos produce una demanda de recursos computacionales que puede ser evitada. Una alternativa a esto es incorporar la definición del sistema difuso, es decir cantidad de entradas, salidas, reglas, etc., al momento de la compilación. No obstante, esta solución requiere recompilar cada vez que se haga un ajuste al sistema y se debe observar que, en la práctica, quien realiza dichos ajustes es un experto en lógica difusa y no necesariamente un programador experimentado. La alternativa por la que finalmente se optó es definir un formato binario propio, denominado Compact Fuzzy System (CFS), que pueda ser incorporado en tiempo de compilación o tiempo de ejecución. Esta solución es flexible y notablemente más eficiente que usar archivos de texto. 3.1.2. Visión general El framework está compuesto por dos módulos. El módulo principal, µFuzzy, es una librería de lógica difusa pensada para ser utilizada en sistemas embebidos. Su principal objetivo es permitir la implantación de sistemas de control difusos y sistemas expertos difusos en microcontroladores de bajo costo con cantidades limitadas de memoria y baja velocidad de procesamiento. La librería no constituye una herramienta para el diseño de sistemas basados en lógica difusa, sino para su implementación. El módulo secundario, cfsconvert, es un software de escritorio que permite convertir los formatos de archivos difundidos de descripción de sistemas difusos, como ser el formato FIS, al formato CFS de µFuzzy. Antes de entrar en los detalles del diseño de cada módulo, es necesario comprender cómo éstos interactúan entre sí y cómo se integrarían a una aplicación que haga uso del framework (ver Fig. 3.1). Supóngase que se desea implementar un sistema de control para un aire acondicionado usando µFuzzy. En primer lugar, el modelador estudiará el problema, definirá cuáles son las entradas y salidas del sistema, las reglas que rigen su comportamiento y otros parámetros que hacen al proceso de inferencia difusa. Esta información debe plasmada ser por el modelador en un archivo FIS, FLL o FCL. Por otro lado, el implantador desarrollará el software que se instalará en el aire acondicionado utilizando la librería µFuzzy. Finalmente, deberá cargar el archivo creado por el modelador CAPÍTULO 3. DISEÑO 14 Desarrollo de un framework en lenguaje C para controladores difusos en la aplicación de escritorio cfsconvert para convertirlo a formato CFS e incorporarlo al software desarrollado. Figura 3.1: Módulos de µFuzzy 3.2. µFuzzy 3.2.1. Elección del lenguaje de desarrollo Al desarrollar software para microcontroladores la elección del lenguaje de programación se ve limitada por diversos factores. En primer lugar se descartaron los lenguajes interpretados tales como Python dada la imposibilidad de instalar un intérprete en microcontroladores de bajo costo, e incluso por la incompatibilidad de dichos intérpretes con ciertas arquitecturas de procesadores típicas de los sistemas embebidos. Por las mismas razones resulta inviable la instalación de una máquina virtual que permita ejecutar código escrito en Java o similares. En segundo lugar, debió dejarse de lado la posibilidad de usar lenguaje ensamblador ya que desarrollar software multiplataforma implicaría reescribirlo para cada Arquitectura del Set de Instrucciones (ISA) con la que se desea compatibilidad. Las dos opciones más firmes fueron los lenguajes C y C++, favorecidas por la existencia de compiladores para todas las familias de microcontroladores populares en el mercado, pero finalmente se eligió el lenguaje C por razones de performance. 3.2.2. Consideraciones respecto al lenguaje El lenguaje C cuenta con varios estándares publicados desde su creación los cuales no fueron totalmente implementados por todos los compiladores. Características incluidas en C99 (ISO/IEC 9899:199) tales como funciones inline o la posibilidad de declarar variables en cualquier lugar del cuerpo de las funciones no están disponibles en muchos compiladores actualmente, por lo que se optó por escribir código compatible con ANSI C. Además, muchos de los microcontroladores con los que se busca compatibilidad no cuentan con un Sistema Operativo (OS), lo que implica que características tales como administración dinámica de memoria y E/S provistas por las librerías estándar del lenguaje a través del OS no están disponibles. Para maximizar la compatibilidad se decidió no hacer uso de dichas librerías. Asimismo, es frecuente encontrar microcontroladores sin soporte para aritmética con punto flotante. Por esta razón µFuzzy utiliza operaciones con punto fijo. CAPÍTULO 3. DISEÑO 15 Desarrollo de un framework en lenguaje C para controladores difusos 3.2.3. Utilización de aritmética de punto fijo La aritmética de punto fijo se implementa con variables enteras destinando algunos bits para la parte entera y los restantes para la parte fraccionaria. La adición y la sustración se efectúan tal como se hace con enteros, pero no sucede lo mismo con el producto y el cociente. Si se utilizan n bits para la parte fraccionaria, después de un producto debe realizarse un desplazamiento de n bits hacia la derecha sobre el resultado para obtener el valor correcto. En el caso del cociente, el desplazamiento debe realizarse antes de dividir y hacia la izquierda. Cuando se utilizan enteros, el rango de valores que pueden representarse con una variable de 32 bits habitualmente excede las necesidades de las aplicaciones, y resulta poco frecuente necesitar variables de 64 bits o más. En cambio, si se trabaja con punto fijo y por ejemplo se destinan 16 bits para la parte entera y 16 bits para la fraccionaria, el valor máximo representable es 32535. Además debe tenerse en cuenta que al multiplicar o al dividir, por la forma en la que se efectúan estas operaciones, los valores intermedios son varios ordenes de magnitud mayores al resultado. Como consecuencia, el uso de variables de 64 bits para almacenar estos valores intermedios puede ser necesario y acarrea dos problemas: performance y compatibilidad. Es que para las arquitecturas a las que µFuzzy está destinada las operaciones de 64 bits son naturalmente más lentas y de hecho, algunos compiladores para estas arquitecturas ni siquiera soportan variables de 64 bits. Al momento de elegir la cantidad de bits para las variables de punto fijo, es necesario analizar el proceso de inferencia difusa. En este proceso, los números que intervienen provienen de las variables de entrada y salida, y en particular las funciones de membresía definidas para estas. El dominio de estas funciones de membresía corresponde al de la variable para la que se definieron, mientras que su rango (que representa un grado de pertenencia) es [0,1]. El dominio depende de la aplicación y dentro de una misma aplicación puede haber variables con dominios muy diferentes entre sí. Por consiguiente, la elección del tamaño de la parte entera y fraccional se convierte en una decisión de compromiso; si se usan pocos para la parte entera se limita el valor máximo representable, mientras que si se usan pocos para la parte fraccionaria se limita la precisión. Esa decisión puede evitarse si las variables y sus respectivas funciones de membresía se someten a un proceso de normalización tal y como se muestra en la Fig. 3.2. Como se puedo observar, las variables de entrada son normalizadas al intervalo [0,1] antes del proceso de inferencia. Luego del proceso, se obtiene un resultado también dentro del intervalo [0,1]. Finalmente, este resultado se convierte a su valor real. De esta manera, la parte entera puede ser pequeña y todos los bits restantes pueden usarse para la parte fraccionaria. En vista de lo expuesto se decidió utilizar variables de 16 bits, con 2 bits para la parte real y 14 para la parte fraccionaria, las cuales permiten representar valores en el intervalo [-2, 2) con incrementos de 2−14 . La ventaja de usar variables de 16 bits es que los valores intermedios caben en variables de 32 bits, que pueden utilizarse en todas las arquitecturas. Se requiere el bit de signo porque cuando se usa el método de Sugeno-Takagi, los coeficientes de los consecuentes de las reglas pueden ser negativos. 3.2.4. Limitaciones debidas al uso de punto fijo. Al margen de las pérdidas de precisión, existen otras límitaciones relacionadas con el uso de aritmética de punto fijo. En primer lugar, el rango de las variables de entrada y salida debe estar bien definido de modo que sea posible efectuar la normalización. Todos los formatos compatibles con µFuzzy tienen campos destinados para esos efectos, sin embargo, en el caso de los sistemas basados en el método de Sugeno-Takagi, el rango de las variables de salida es opcional. Para poder convertirlos a formato CFS y utilizarlos con µFuzzy esa información debe ser provista. Dicho de otro modo, si el rango de una variable de salida no se especifica en el archivo que describe al sistema CAPÍTULO 3. DISEÑO 16 Desarrollo de un framework en lenguaje C para controladores difusos Figura 3.2: Proceso de inferencia con variables normalizadas difuso, entonces ese archivo no es compatible con el framework. Otra limitación aparece cuando se analizan los coeficientes utilizados en los consecuentes de las reglas de los sistemas de Sugeno-Takagi. El valor de estos coeficientes debe modificarse de manera acorde a la normalización de las variables de entrada y de salida, para no alterar el comportamiento del sistema. En algunos casos, el nuevo valor de los coeficientes no pertenece al intervalo representable [-2, 2). Cuando eso sucede, la solución es sobredimensionar el rango de las variables de salida en forma proporcional al exceso en el valor del coeficiente, de modo que tras la normalización, los coeficientes sean representables. Dicho de otro modo, si el rango original de una variable de salida es [0, 100] y uno de los coeficientes luego de la normalización resulta 3, entonces redefiniendo ese rango como [0, 200] el valor del coeficiente será 1.5 y podrá representarse. El proceso de normalización de coeficientes se explica en el anexo D. 3.2.5. Características soportadas Los sistemas de inferencia difusos cuentan con una gran cantidad de parámetros que pueden ser ajustados para lograr el comportamiento deseado. La Tabla 3.1 expone las características soportadas por µFuzzy. Las funciones de mebresía de µFuzzy ofrecen flexibilidad y eficiencia. Las funciones de pertenencia trapezoidales, que también pueden ser utilizadas como triangulares o rectangulares, optimizan el uso de memoria y son procesadas rápidamente. Por otro lado, las tabuladas, permiten representar funciones arbitrarias y, aunque demandan más memoria que las anteriores, el tamaño de las tablas es configurable. Ambos tipos de funciones de membresía pueden coexistir e incluso, los tamaños de las tablas pueden configurarse independientemente para cada una. A su vez, µFuzzy permite configurar independientemente métodos de inferencia, operadores de activación, operadores de agregación y defuzzificadores para cada variable de salida. Es decir que un controlador podría calcular el valor de una variable de salida utilizando el método de Sugeno y otras usando el método de Mamdani. CAPÍTULO 3. DISEÑO 17 Desarrollo de un framework en lenguaje C para controladores difusos Métodos de inferencia Funciones de membresía T-normas S-normas Métodos de defuzzificación Conectivos lógicos Sugeno Mamdani trapezoidal tabulada mínimo producto algebraico diferencia acotada producto drástico producto de Einstein producto de Hamacher máximo suma algebraica suma acotada suma drástica suma de Einstein suma de Hamacher centroide media ponderada conjunción disyunción negación Cuadro 3.1: Características soportadas por µFuzzy 3.3. cfsconvert 3.3.1. Características generales cfsconvert es un conversor de archivos FIS a formato CFS. Para agilizar el desarrollo de esta aplicación se la diseño como una herramienta por línea de comandos. Si bien el uso de este tipo de herramientas puede resultar poco intuitivo, cfsconvert ofrece funcionalidad Drag & Drop a fin de simplificar la tarea del usuario final. A su vez, al funcionar por línea de comandos, cfsconvert puede integrarse a cadenas de herramientas automatizadas. El conversor genera dos tipos de salidas: código fuente C con los datos en formato CFS incrustados, o un archivo binario que puede ser interpretado por la librería. En el primer caso, el sistema difuso se define en tiempo de compilación, es decir que para realizar ajustes el software debe ser recompilado. Esta opción es la más adecuada para proyectos simples, en los que recompilar no represente un esfuerzo significativo. En el segundo caso, en cambio, el archivo binario generado puede cargarse dinámicamente. Esto permite por ejemplo cargar el archivo CFS en una tarjeta SD o transferirlo a través de una red. La elección dependerá de cuál de las dos opciones se integre mejor al flujo de trabajo del proyecto. 3.3.2. Elección del lenguaje de desarrollo La elección del lenguaje de desarrollo pudo efectuarse con mayor libertad que en el caso de µFuzzy, dado que el conversor es una aplicación de escritorio y su performance es un elemento secundario. Aunque podrían haberse escogido lenguajes ágiles tales como Python o Lua, finalmente se optó por C++. El factor clave a la hora de decidir fue que la librería fuzzylite es gratuita, de código CAPÍTULO 3. DISEÑO 18 Desarrollo de un framework en lenguaje C para controladores difusos abierto y provee funciones para leer archivos FIS. Es decir que haciendo uso de fuzzylite sólo es necesario crear las funciones para exportar a formato CFS y programar la interfaz de comandos. CAPÍTULO 3. DISEÑO 19 Desarrollo de un framework en lenguaje C para controladores difusos Capítulo 4 Aplicación 4.1. Introducción A lo largo de este capítulo se describe una aplicación de µFuzzy en un robot móvil autónomo terrestre pensado para resolver laberintos. En esta aplicación el framework se emplea a dos niveles: en primer lugar se utiliza para efectuar control de lazo cerrado sobre la velocidad de las ruedas, y en segundo lugar para que el robot avance siguiendo una pared lateral (wall-following). El robot consiste en una versión modificada del presentado en Robot para Laberintos[3]. Posee una placa principal, basada en un microcontrolador MC9S08JM32 de 8 bits que opera a una frecuencia de bus de 24 MHz y cuenta con 2 KB de memoria RAM y 32 KB de memoria flash. Se desplaza usando motores de corriente continua que le permiten alcanzar velocidades de hasta 360 mm/s, y cuenta con encoders incrementales de 30 pulsos por revolución en cada rueda. A su vez, dispone de tres sensores ultrasónicos de distancia: uno frontal y dos laterales a 90o del primero. Además posee una interfaz Arduino compatible que le permite comunicarse con una placa secundaria a través del puerto serie y delegarle la toma de decisiones. En esta aplicación se usa para ese propósito una FRDM-KL25Z, una placa de desarrollo basada en un microcontrolador de 32 bits con núcleo Cortex-M0+ que trabaja a 48 MHz, y que cuenta con 16 KB de memoria RAM y 128 KB de memoria flash. 4.2. Control de lazo cerrado para los motores 4.2.1. Estudio de los motores Como se mencionó anteriormente el robot cuenta con dos motores de corriente continua, los cuales se controlan mediante Modulación por Ancho de Pulsos (PWM). El primer paso en el diseño del controlador fue obtener la relación entre el ciclo de trabajo ρ y la velocidad del robot v, la cual se muestra en la Fig. 4.1. En el intervalo [80, 380] la curva puede aproximarse mediante una función cuadrática, mientras que las velocidades inferiores a 80 mm/s no pueden lograrse. Por otro lado, la Fig. 4.2 muestra la velocidad en función del tiempo para un ciclo de trabajo dado, partiendo desde el reposo. Se puede observar que aunque el ciclo de trabajo se mantenga constante, la respuesta tiene una cantidad considerable de ruido. Esto se debe a que el cálculo de la velocidad se realiza tomando el tiempo entre pasos del encoder, y en el robot utilizado ese tiempo no puede ser medido con más precisión ya que encoders están conectados a entradas analógicas. Esto implica que los pasos deben ser detectados por software muestreando la señal, pero la frecuencia de muestreo (que determina el error de la medición) está fuertemente limitada por las capacidades del CAPÍTULO 4. APLICACIÓN 20 Desarrollo de un framework en lenguaje C para controladores difusos Figura 4.1: Ciclo de trabajo en función de la velocidad procesador. 4.2.2. Estructura del controlador En base a los datos obtenidos, se desarrolló el modelo de controlador que se muestra en la Fig. 4.3. El mismo está basasdo en un controlador PI, en el cual la parte derivada se omite dado que el ruido en la señal no permite utilizarla. Toma como entradas la velocidad de referencia o setpoint vr , el error e en la velocidad respecto al setpoint, y la integral de este error ie . A partir de la vr se calcula un ciclo de trabajo aproximado ρ0 utilizando la función cuadrática que se obtuvo anteriormente. A su vez, las tres variables de entrada son sometidas al proceso de inferencia mediante lógica difusa para obtener como salida ρc , que constituye una corrección a la primera aproximación. El ciclo de trabajo ρ que finalmente se aplica al motor es la suma de estos dos factores. Usando los encoders, se mide la velocidad va y se la utiliza para realimentar el controlador. 4.2.3. Diseño del sistema de control difuso El sistema de control difuso tiene como objetivo solventar las limitaciones de un controlador PI con ganancias constantes. Emplea el método de inferencia de Takagi-Sugeno, ya que resulta notablemente más eficiente que el método de Mamdani[4], y con este mismo criterio, utiliza los operadores máximo y mínimo para implementar la unión y la intersección difusas respectivamente. El sistema utiliza tres reglas: SI e no es chico ENTONCES ρc = kp0 e SI e es chico Y vr es baja ENTONCES ρc = kp1 e + ki1 ie CAPÍTULO 4. APLICACIÓN 21 Desarrollo de un framework en lenguaje C para controladores difusos Figura 4.2: Velocidad del robot en función del tiempo para un ciclo de trabajo del 80 % SI e es chico Y vr no es baja ENTONCES ρc = kp2 e + ki2 ie La primera diferencia entre el sistema difuso y el controlador PI es que el primero define las ganancias en función del setpoint, tal como puede apreciarse en la segunda y tercera regla. Para velocidades bajas las ganancias son menores, ya que la pendiente de la curva del ciclo de trabajo en función de la velocidad es menor. Asimismo, para velocidades altas se utilizan ganancias mayores. Los valores constantes kp1 y kp2 corresponden aproximadamente a la pendiente de la curva para velocidades bajas y altas respectivamente. Por otro lado, se encontraron grandes dificultades a la hora de definir las ganancias del término integral, especialmente para velocidades elevadas. Esto se debe a que en las pruebas, en las que se partió del reposo, el robot tardaba un tiempo considerable en vencer la inercia y durante ese tiempo, la integral se acumulaba. Ganancias bajas del termino integral conducían a tiempos de convergencia altos, mientras que ganancias altas implicaban mayor overshoot. Por este motivo se utiliza la primera regla, la cual establece que se la parte integral se use solo cuando la velocidad medida se encuentre próxima al setpoint, es decir cuando el error sea pequeño. Cuando el error es grande, se utiliza solamente la parte proporcional. Esto permite asignar un valor alto a kp0 para aproximarse rápidamente al valor deseado sin perder estabilidad, y a su vez, permite que ki1 y ki2 relativamente altas sin el overshoot que habitualmente esto implica. Las funciones de membresía utilizadas se muestran en la Fig. 4.4. Como puede observarse se utiliza sólo una para la velocidad de referencia y el error, mientras que para la integral no se usa ninguna. Esta última variable se usa sólamente en el cálculo de los consecuentes. El rango de la velocidad de referencia se limita al intervalo [80,400], porque velocidades menores que 80 no son posibles. Asimismo, el rango del error del error se limita al intervalo [-50, 50] y si el error excede ese intervalo entonces se trunca. CAPÍTULO 4. APLICACIÓN 22 Desarrollo de un framework en lenguaje C para controladores difusos Figura 4.3: Proceso de control (a) Velocidad de referencia (b) Error en la velocidad Figura 4.4: Funciones de membresía para las variables de entrada 4.3. Seguimiento de pared El objetivo de este controlador es que el robot avance manteniendo constante la distancia a una pared lateral valiéndose de un único sensor ultrasónico. En este caso, para disminuir la carga de tareas en la placa principal, el programa se ejecuta en la placa de toma de decisiones. La Fig. 4.5 muestra el esquema de funcionamiento de este controlador. Las entradas son la distancia da a la pared, y la derivada de esta distancia respecto al tiempo d0a . Las salidas son la velocidad v y la velocidad angular ω que deben aplicarse al robot para corregir su dirección. Esta aplicación, al igual que la anterior, utiliza el método de Takagi-Sugeno y los operadores máximo y mínimo para implementar las operaciones difusas. El diseño de las reglas y las funciones de membresía se basa en la geometría del problema. Este sistema dista de ser lineal ya que la distancia leída por el sensor no es proporcional a la distancia del robot a la pared, sino que esta afectada por la orientación del robot. Es decir que un cambio brusco en la lectura del sensor no implica que el robot se haya alejado o acercado a la pared, sino que puede deberse a un cambio en su orientación. A su vez, cuanto más lejos se encuentra el robot de la pared más sensible es a los cambios de orientación. A partir de este análisis se plantearon 3 reglas para controlar la velocidad angular: CAPÍTULO 4. APLICACIÓN 23 Desarrollo de un framework en lenguaje C para controladores difusos Figura 4.5: Proceso de control SI da es pequeña Y d0a no es grande positiva ENTONCES ω es lineal SI da no es pequeña Y d0a no es grande positiva ENTONCES ω es lineal suave SI d0a es grande positiva ENTONCES ω es nula La primera regla emula el comportamiento de un controlador PD y actúa en la operación normal del robot, es decir cuando se encuentra cerca de la pared y aproximadamente alineado con ésta. La segunda se activa cuando la distancia del robot a la pared es grande y se similar a la primera pero con menor ganancia. Finalmente, la última actúa cuando se detecta que la distancia a la pared crece bruscamente, es decir que el robot está girando alejándose de la pared. El propósito de esta regla es que el sistema no salga de la zona estable. Para el control de la velocidad se utilizan dos reglas independientes de las anterirores: SI da es muy pequeña Y d0a es grande negativa ENTONCES v es nula SI da no es muy pequeña O d0a no es grande negativa ENTONCES v es constante Cuando el robot se encuentra muy próximo a la pared y continúa aproximándose a ésta, la velocidad tangencial debe hacerse nula para evitar una colisión. En otro caso, avanza con velocidad constante. Las funciones de membresía definidas para este controlador se presentan en la Fig. 4.6. CAPÍTULO 4. APLICACIÓN 24 Desarrollo de un framework en lenguaje C para controladores difusos (a) Lectura del sensor (b) Derivada de la lectura Figura 4.6: Funciones de membresía para las variables de entrada CAPÍTULO 4. APLICACIÓN 25 Desarrollo de un framework en lenguaje C para controladores difusos Capítulo 5 Resultados 5.1. Framework 5.1.1. Calidad del código fuente µFuzzy se desarrolló siguiendo el estándar de código fuente propusto en [2] y fue íntegramente documentada usando doxygen, una herramienta para generar documentación a partir de comentarios en el código fuente. La densidad de comentarios de la librería es del 92 %, lo que significa que prácticamente se escribió una línea de comentario por cada línea de código. Por otro lado, la librería fue sometida a exhaustivas pruebas de funcionamiento. Tanto es así que la cantidad de líneas de código escritas para las pruebas unitarias es casi el doble que las escritas para la librería propiamente dicha. Estas estadísticas, generadas con la herramienta CLOC, se muestran en la Tabla 5.1. Librería Pruebas unitarias Total archivos 29 13 42 comentarios 1405 424 1829 líneas de código 1528 2608 4136 Cuadro 5.1: Estadísticas del código fuente 5.1.2. Pruebas Para realizar las pruebas unitarias se utilizó Ceedling, un conjunto de herramientas y librerías para desarrollo basado en pruebas en lenguaje C. Se escribieron pruebas unitarias para todas las funciones externas de µFuzzy, y se logró una cobertura del 100 % de las líneas de código. Es decir que cada línea de código de la librería es ejecutada por al menos una función de prueba, o en otras palabras, que cada posible camino de ejecución fue probado. Adicionalmente, se diseñó un software para realizar pruebas funcionales automáticas, que procesa un conjunto de archivos FIS con µFuzzy y fuzzylite, y compara los resultados. Este programa prueba n combinaciones de entrada uniformemente distribuidas para cada controlador, y calcula para todas las combinaciones el error normalizado e definido como: e= |(oµ − of )| (omax − omin ) (5.1) Donde oµ es el valor calculado por µFuzzy, of es el valor calculado por fuzzylite, y omax y omin son el máximo y el mínimo valor que puede tomar la variable de salida respectivamente. Como CAPÍTULO 5. RESULTADOS 26 Desarrollo de un framework en lenguaje C para controladores difusos resultado, presenta el error máximo emax y el error promedio ē. Cabe destacar que este software prueba tanto µFuzzy como cfsconvert ya que todos los archivos son convertidos de formato FIS a CFS como parte del procedimiento. Se realizaron pruebas funcionales sobre un conjunto de archivos FIS tomados de los ejemplos distribuidos con MATLAB R2014a. Se utilizaron todos los ejemplos exceptuando dos, por hacer uso de características incompatibles con cfsconvert: constantes simbólicas y funciones personalizadas. Para los controladores basados en el método de Sugeno, fue necesario redefinir los rangos de las variables de salida, tal como se explica en 3.2.4. Se probaron 100000 combinaciones de entrada para cada variable de salida de cada controlador, y los resultados utilizando tablas para las funciones de membresía de 512 y 4096 entradas se muestran en las Fig.5.1 y 5.2 respectivamente. Figura 5.1: Errores con tablas de 512 entradas Como puede observarse en la Fig.5.1, en general, el error máximo se ubica debajo del 0.5 % mientras que el medio no supera el 0.1 %. En el caso más desfavorable (fpeaks) se obtuvo un error significativamente mayor. La diferencia se debe a la forma en la que está construido ese sistema. Utiliza el método de Sugeno y tiene definidas 16 reglas con dos variables de entrada y una de salida. Cada una de las variables de entrada tiene cuatro funciones de membresía gausianas, las cuales acarrean el error propio de la tabulación. Por otro lado, en este caso, los coeficientes utilizados en los consecuentes de las reglas tienen magnitudes muy diferentes entre sí, por lo que el error debido al uso de aritmética de punto fijo impacta directamente sobre los resultados. Finalmente, utiliza como operador de conjunción el producto algebráico, lo cual ocasiona pérdidas de precisión que no ocurrirían si se utilizara por ejemplo el mínimo como operador. En la Fig. 5.2 se muestran los resultados de las pruebas cuando se aumenta la cantidad de entradas en las tablas de las funciones de membresía a 4096. En general, tanto errores máximos como medios se ubican debajo del 0.05 %. Con esta configuración, el error máximo de fpeaks se CAPÍTULO 5. RESULTADOS 27 Desarrollo de un framework en lenguaje C para controladores difusos Figura 5.2: Errores con tablas de 4096 entradas redujo a la cuarta parte, y el error medio a menos de la mitad. El caso más desfavorable pasó a ser tank2, y su error máximo es idéntico al obtenido con la configuración anterior porque este sistema utiliza sólo funciones de membresía trapezoidales las cuales no se tabulan. La razón por la cual presenta un error máximo grande comparado con el resto es que utiliza los operadores algebráicos para la conjunción y la disyunción, y se pierde precisión tal y como ocurre con fpeaks. 5.1.3. Integración a la CIAA La Computadora Industrial Abierta Argentina (CIAA) es una plataforma electrónica libre y gratuita desarrollada colaborativamente en Argentina con el apoyo de universidades y empresas de todo el país. Se distribuye con un RTOS y un conjunto de módulos orientados a aplicaciones industriales, todos ellos desarrollados específicamente para esta plataforma y siguiendo estrictas normas de calidad. Por la potencial aplicabilidad de µFuzzy a la industria, se propuso a los responsables del proyecto CIAA incluirlo como módulo, y como fruto de los esfuerzos realizados en pos de la confiabilidad y mantenibilidad del framework, la propuesta fue aceptada. Esto significa que las futuras versiones del firmware de la CIAA incluirán una copia de µFuzzy lista para usarse. 5.2. Aplicaciones 5.2.1. Control de velocidad Para evaluar la respuesta del controlador se midió la velocidad del robot en función del tiempo para distintos setpoints partiendo desde el reposo. Los resultados de los 7 casos de prueba, que corresponden a velocidades entre 80 mm/s y 360 mm/s con incrementos de 40 mm/s, se presentan CAPÍTULO 5. RESULTADOS 28 Desarrollo de un framework en lenguaje C para controladores difusos en la Fig. 5.3a. Como puede observarse, en todos los casos la velocidad converge al valor deseado. Cuanto más bajo es el setpoint más rápida es la convergencia, y en ningún caso se observa overshoot. En el caso más desfavorable en término de tiempo de convergencia, es decir cuando la velocidad deseada es de 360 mm/s, no pueden lograrse mejores resultados dado que para llegar a esa velocidad se utiliza un ciclo de trabajo del 100 %. La Fig. 5.3b muestra una comparación de las respuestas usando el controlador difuso y usando control de lazo abierto, para una velocidad de referencia de 240 mm/s. Puede observarse que usando control de lazo cerrado la velocidad converge al valor deseado en menos de 400 ms, mientras que usando control de lazo abierto la velocidad nunca llega al setpoint y se estabiliza en 1 segundo aproximadamente. 5.2.2. Seguimiento de pared Para el caso de este controlador, dada la imposibilidad de medir la distancia del robot a la pared, lo que se evaluó fue la lectura del sensor ultrasónico en función del tiempo. Nótese que la lectura del sensor está influenciada por la orientación del robot, es decir que la distancia medida no corresponde a la distancia a la pared excepto cuando el robot avanza de forma paralela a la misma. El controlador fue probado para 4 condiciones inciales y una distancia objetivo de 47 mm. La Fig. 5.4 muestra los resultados para un ángulo incial nulo, y dos distancias iniciales diferentes. En ambos casos hay overshoot en la lectura del sensor, aunque el overshoot en la distancia real del robot a la pared es considerablemente menor. El tiempo de convergencia a la distancia objetivo es de aproximadamente 4 segundos en los dos casos. El comportamiento del controlador también fue evaluado para ángulos iniciales distintos de 0. Las Fig. 5.5 y 5.6 muestran los resultados para ángulos iniciales de -22o (acercándose a la pared) y 45o (alejándose de la pared). Ángulos mayores a 45o no son viables dado que en esos casos el sensor no es capaz de detectar las ondas reflejadas por la pared, por lo tanto la distancia no se puede medir. Ángulos menores a -22o con distancias iniciales pequeñas no pudieron lograrse con este controlador, dado que se requiere un tiempo de respuesta muy rápido y que la distancia real a la pared es mucho menor que la medida. 5.3. Conclusiones y trabajos futuros A lo largo de este trabajo de graduación se expuso los procesos de diseño, desarrollo y prueba de µFuzzy. El funcionamiento del framework fue validado satisfactoriamente usándolo en un robot móvil, para dos propositos diferentes en dos microcontroladores de bajo costo de arquitecturas totalmente distintas entre sí. A futuro, se planea mejorar la librería ampliando la gama de métodos de defuzzificación y dando permitiendo asignar pesos a cada regla. Esta última característica es importante porque otorgaría total compatibilidad con Sistemas de Inferencia Adaptativos de Inferencia Neuro-Difusa (ANFIS). En vista de los resultados, puede afirmarse que µFuzzy constituye una herramienta confiable y potente, que puede utilizarse en aplicaciones reales y complejas, y en entornos extremadamente limitados en términos de recursos procesamiento. CAPÍTULO 5. RESULTADOS 29 Desarrollo de un framework en lenguaje C para controladores difusos (a) v(t) para distintos setpoints (b) Control de lazo abierto vs control de lazo cerrado Figura 5.3: Respuesta en velocidad usando control difuso CAPÍTULO 5. RESULTADOS 30 Desarrollo de un framework en lenguaje C para controladores difusos (a) Distancia inicial de 20 mm (b) Distancia inicial de Figura 5.4: Lectura del sensor en función del tiempo con ángulo inicial nulo CAPÍTULO 5. RESULTADOS 31 Desarrollo de un framework en lenguaje C para controladores difusos Figura 5.5: Ángulo inicial de -22o Figura 5.6: Ángulo incial de 45o CAPÍTULO 5. RESULTADOS 32 Bibliografía [1] David M Byrne, Stephen D Oliner, and Daniel E Sichel. How fast are semiconductor prices falling? Technical report, National Bureau of Economic Research, 2015. [2] Jerry Doland and Jon Valett. C style guide. 1994. [3] Martin Izquierdo and Gabriel A Parodi. Robot para resolución de laberintos. Tesis, Universidad Nacional de Tucumán, Tucumán, Argentina, 2015. [4] Javad J Jassbi, SH Alavi, Paulo JA Serra, and Rita Almeida Ribeiro. Transformation of a mamdani fis to first order sugeno fis. In FUZZ-IEEE, pages 1–6, 2007. [5] Bart Kosko and Satoru Isaka. Fuzzy logic. Scientific American, 269(1):62–7, 1993. [6] Timothy J Ross. Fuzzy logic with engineering applications. John Wiley & Sons, 2009. [7] Harpreet Singh, Madan M Gupta, and Thomas et al. Meitzler. Real-life applications of fuzzy logic. Advances in Fuzzy Systems, 2013. 33 Anexos 34 Desarrollo de un framework en lenguaje C para controladores difusos Anexo A API de µFuzzy A.1. Tipos de dato uF_controller_dt Objeto que contiene la información de un controlador. Son creados por la función uF_ufuzInit. uF_fixed_point_dt Tipo de dato numérico representado en punto fijo. Pueden utilizarse las funciones uF_fixpToInt, uF_fixpFromInt, uF_fixpToLongInt y uF_fixpFromLongInt para convertir entre este formato y tipos conocidos. uF_error_dt Tipo de dato para representar códigos de error. A.2. Funciones uF_ufuzInit Crea un nuevo controlador a partir de un bloque de datos con formato CFS. prototipo uF_controller_dt* uF_ufuzInit(uint8_t *controller_data, uint32_t data_size); parámetros controller_data Referencia al bloque de memoria que contiene la estructura CFS. data_size Tamaño del bloque. valor de retorno En caso de éxito, devuelve un puntero a un controlador inicializado. En caso contrario devuelve 0, y el código de error puede obtenerse llamando a uF_ufuzError. uF_ufuzClear Libera los recursos utilizados por un controlador. En la implementación actual, sin reserva dinámica de memoria, esta función no efectúa ninguna acción. ANEXO A. API DE µFUZZY 35 Desarrollo de un framework en lenguaje C para controladores difusos prototipo uF_ufuzClear(uF_controller_dt *controller); parámetros controller Puntero al controlador devuelto por uF_ufuzInit. uF_ufuzProcess Calcula la salida del controlador. prototipo uF_error_dt uF_ufuzProcess(uF_controller_dt *controller, uF_fixed_point_dt *inputs, int inputs_size, uF_fixed_point_dt *outputs, int outputs_size); parámetros controller Puntero al controlador devuelto por uF_ufuzInit. inputs Arreglo con los valores de las variables de entrada expresados en punto fijo. Pueden utilizarse las funciones uF_fixpFromInt y uF_fixpFromLong para obtener valores en punto fijo a partir de los tipos int y long respectivamente. inputs_size Tamaño del arreglo de entrada. Debe coincidir con la cantidad de variables de entrada del controlador. outputs Arreglo para devolver las salidas del controlador. Pueden utilizarse las funciones uF_fixpToInt y uF_fixpToLongInt para convertir estos valores a los tipos int y long respectivamente. outputs_size Tamaño del arreglo de salida. Debe coincidir con la cantidad de variables de salida del controlador. valor de retorno Devuelve el código de error si hubiera uno. En caso contrario devuelve uF_ERROR_NONE. uF_ufuzError Devuelve el código del último error registrado para un controlador en particular. Una llamada a esta función también limpia el registro de errores para dicho controlador. prototipo uF_error_dt uF_ufuzError(uF_controller_dt *controller); parámetros controller Puntero al controlador devuelto por uF_ufuzInit. ANEXO A. API DE µFUZZY 36 Desarrollo de un framework en lenguaje C para controladores difusos valor de retorno Si controller no es nulo, devuelve el último código de error producido sobre ese controlador. En caso contrario, devuelve el último error global. Esto es útil, cuando uF_ufuzInit devuelve un puntero nulo. uF_fixpFromInt Convierte un número entero perteneciente al intervalo [range_min, range_max], a un valor de punto fijo normalizado. prototipo uF_fixed_point_dt uF_fixpFromInt(short i, short range_min, short range_max); parámetros i Número a convertir. range_min Valor mínimo que puede tomar la variable a convertir. range_max Valor máximo que puede tomar la variable a convertir. valor de retorno Devuelve el valor convertido a punto fijo. uF_fixpFromLongInt Convierte un número entero perteneciente al intervalo [range_min, range_max], a un valor de punto fijo normalizado. prototipo uF_fixed_point_dt uF_fixpFromLongInt(long i, long range_min, long range_max); parámetros i Número a convertir. range_min Valor mínimo que puede tomar la variable a convertir. range_max Valor máximo que puede tomar la variable a convertir. valor de retorno Devuelve el valor convertido a punto fijo. uF_fixpToInt Convierte un número en punto fijo, a un entero en el intervalo [range_min, range_max]. ANEXO A. API DE µFUZZY 37 Desarrollo de un framework en lenguaje C para controladores difusos prototipo short uF_fixpToInt(uF_fixed_point_dt fp, short range_min, short range_max); parámetros fp Número a convertir. range_min Valor mínimo que puede tomar la variable a convertir. range_max Valor máximo que puede tomar la variable a convertir. valor de retorno Devuelve el valor convertido a entero. uF_fixpToLongInt Convierte un número en punto fijo, a un entero en el intervalo [range_min, range_max]. prototipo short long uF_fixpToLongInt(uF_fixed_point_dt fp, long range_min, long range_max); parámetros fp Número a convertir. range_min Valor mínimo que puede tomar la variable a convertir. range_max Valor máximo que puede tomar la variable a convertir. valor de retorno Devuelve el valor convertido a entero. uF_poolSpace Devuelve el espacio disponible en el pool de memoria. prototipo uint_fast32_t uF_poolSpace(void); valor de retorno La cantidad de bytes disponibles. ANEXO A. API DE µFUZZY 38 Desarrollo de un framework en lenguaje C para controladores difusos A.3. Macros uF_POOL_SIZE Tamaño en bytes del pool de memoria. El valor por defecto es 1024. uF_NO_INT64 Si se define, la librería no hace uso de enteros de 64 bits para las operaciones internas. Por defecto no esta definido. Esta opción es util para compiladores sin soporte para enteros de 64 bits. A.4. Códigos de error uF_ERROR_NONE Ningún error. uF_ERROR_UNKNOWN Error desconocido. uF_ERROR_NULL_CFS_DATA La función de inicialización fue llamada con un puntero nulo. uF_ERROR_MEMORY_POOL_TOO_SMALL No hay suficiente espacio en el pool de memoria. uF_POOL_SIZE debe ser redefinido con un valor mayor. uF_ERROR_INPUT_ARRAY_TOO_SMALL El arreglo de valores de entrada pasado como argumento a uF_ufuzProcess no tiene suficientes elementos. Debe tener tantos elementos como variables de entrada tenga el sistema. uF_ERROR_OUTPUT_ARRAY_TOO_SMALL El arreglo de valores de salida pasado como argumento a uF_ufuzProcess no tiene suficientes elementos. Debe tener tantos elementos como variables de salida tenga el sistema. uF_ERROR_DATA_SIGNATURE El bloque de datos pasado como argumento a uF_ufuzInit tiene una firma inválida. El puntero al bloque o los datos del mismo son inválidos. uF_ERROR_RESERVED_FIELD_NOT_ZERO Los campos reservados en el bloque CFS deben ser cero. uF_ERROR_UNKNOWN_AND_OPERATOR El operador and en el bloque CFS no es válido. uF_ERROR_UNKNOWN_OR_OPERATOR El operador or en el bloque CFS no es válido. uF_ERROR_NO_INPUT_VARIABLES El controlador definido en el bloque CFS no tiene variables de entrada. uF_ERROR_NO_OUTPUT_VARIABLES El controlador definido en el bloque CFS no tiene variables de salida. uF_ERROR_UNKNOWN_ACTIVATION_OPERATOR El operador de activación definido para una variable de salida en el bloque CFS no es válido. ANEXO A. API DE µFUZZY 39 Desarrollo de un framework en lenguaje C para controladores difusos uF_ERROR_TABLE_INDEX_SIZE_TOO_BIG El tamaño del índice de una función de membresía tabulada en el bloque de datos CFS es demasiado grande. uF_ERROR_SENSOR_RESERVED_FIELD_NOT_ZERO Uno de los campos reservados de una variable de entrada en el bloque CFS no es cero. uF_ERROR_UNKNOWN_INFERENCE_METHOD El método de inferencia definido para una variable de salida en el bloque CFS no es válido. uF_ERROR_UNKNOWN_AGGREGATION_OPERATOR El operador de agregación definido para una variable de salida en el bloque CFS no es válido. uF_ERROR_UNKNOWN_DEFUZZIFICATION_METHOD El método de defuzzificación definido para una variable de salida en el bloque CFS no es válido. uF_ERROR_INVALID_TABLE_PARAMETERS Uno de los grados de verdad que definen una función de membresía tabulada no pertenence al intervalo [0, 1]. uF_ERROR_INVALID_TRAPEZOID_PARAMETERS Uno de los puntos que definen una función de membresía trapezoidal no pertenence al intervalo [0, 1]. uF_ERROR_MEM_FUNC_RESERVED_FIELD_NOT_ZERO Uno de los campos reservados de una función de membresiía en el bloque CFS no es cero. uF_ERROR_UNKNOWN_MEM_FUNC_TYPE Una de las funciones de membresía definidas en el bloque CFS tiene tipo inválido. uF_ERROR_READER_OVERFLOW La función de inicialización intentó leer más allá de los límites del bloque CFS. Los datos del bloque están dañados. uF_ERROR_TOO_MANY_DEFUZZIFICATION_STEPS El campo del bloque CFS que define la cantidad de pasos en el proceso de defuzzificación tiene un valor mayor al permitido. uF_ERROR_UNKNOWN_LOGICAL_CONNECTIVE Una de las reglas del bloque CFS tiene un conectivo lógico inválido. uF_ERROR_INVALID_MEMBERSHIP_FUNCTION_ID Una de las reglas del bloque CFS hace referencia a una función de membresía inexistente. uF_ERROR_CONTROLLER_NOT_INITIALIZED El controlador no fue inicializado antes de llamar a la función de procesamiento. uF_ERROR_PADDING_NOT_ZERO Uno de los campos de relleno en el bloque CFS no es cero. ANEXO A. API DE µFUZZY 40 Desarrollo de un framework en lenguaje C para controladores difusos Anexo B Manual de cfsconvert Descripción cfsconvert es una herramienta por línea de comandos para convertir archivos FIS a formato CFS. Utilización cfsconvert [-d dsteps] [-s tsize] [-c] [-b] [-t] SOURCE [DESTINATION] -d dsteps Logaritmo en base dos del número de pasos a realizar en el proceso de defuzzificación. El valor por defecto es 8, que corresponde a 256 pasos. -s tsize Logaritmo en base dos del número de entradas en las funciones de membresía tabuladas. El valor por defecto es 8, que corresponde a 256 entradas por tabla. -c El conversor entrega como salida código fuente C. Esta opción es apropiada para integrar el conversor en un toolchain. -b El conversor entrega como salida un archivo binario con la estructura CFS. -t El conversor entrega como salida un archivo de texto con la estructura CFS definida como un struct en C. SOURCE Ruta al archivo FIS a convertir. DESTINATION Nombre del archivo o los archivos de salida sin extensión. Si DESTINATION se omite, entonces los archivos de salida tienen el mismo nombre que el archivo FIS, pero diferente extensión. Si no se especifica ninguno de los parámetros -c, -b o -t, entonces el conversor entrega un archivo de texto. ANEXO B. MANUAL DE CFSCONVERT 41 Desarrollo de un framework en lenguaje C para controladores difusos Anexo C Especificación del formato CFS Estructura 8 bytes x bytes cabecera variable de entrada 1 ... y bytes z bytes variable de entrada n variable de salida 1 w bytes ... variable de salida m Cabecera byte 0 byte 1 byte 2 byte 3 1 'C' 'F' 'S' RES:=0 2 AND_OP OR_OP INPUT_NUM OUTPUT_NUM RES Campo reservado. Debe valer 0. AND_OP Identificador del operador conjuntivo. OR_OP Identificador del operador disyuntivo. INPUT_NUM Cantidad de variables de entrada. OUTPUT_NUM Cantidad de variables de salida. ANEXO C. ESPECIFICACIÓN DEL FORMATO CFS 42 Desarrollo de un framework en lenguaje C para controladores difusos Variables de entrada 1 byte 1 byte x bytes y bytes MF_NUM RES:=0 función de membresía 1 ... función de membresía n MF_NUM Cantidad de funciones de membresía para esta variable. RES Campo reservado. Debe valer 0. Funciones de membresía trapezoidales 1 byte 0 byte 1 MF_TYPE:=0 RES:=0 2 X1 3 X3 byte 2 byte 3 X0 X2 MF_TYPE Tipo de función de membresía. 0 para trapezoidales. RES Campo reservado. Debe valer 0. X0 Coordenada x del primer punto del trapezoide. La coordenada y es 0. X1 Coordenada x del segundo punto del trapezoide. La coordenada y es 1. X2 Coordenada x del tercer punto del trapezoide. La coordenada y es 1. X3 Coordenada x del cuarto punto del trapezoide. La coordenada y es 0. Funciones de membresía tabuladas 1 byte 0 byte 1 MF_TYPE:=1 INDEX_SIZE byte 2 byte 3 Y0 ... m MF_TYPE Yn Tipo de función de membresía. 1 para tabuladas. ANEXO C. ESPECIFICACIÓN DEL FORMATO CFS 43 Desarrollo de un framework en lenguaje C para controladores difusos INDEX_SIZE Tamaño del índice de la tabla. La cantidad de elementos en la tabla es 2i , donde i es el tamaño del índice. Y0 Coordenada y del primer punto de la tabla. Yn Coordenada y del último punto de la tabla. Variables de salida calculadas por Mamdani 1 byte 1 byte x bytes INF_TYPE:=0 MF_NUM función de membresía 1 ... y bytes z bytes función de membresía n parámetros Mamdani INF_TYPE Método de inferencia. 0 para Mamdani. MF_NUM Cantidad de funciones de membresía para esta variable. Parámetros Mamdani 1 byte 1 byte 1 byte 1 byte 1 byte 1 byte n bytes ACT_OP AGG_OP DEFUZ STEPS RES:=0 RULE_NUM regla 1 n bytes ... regla n ACT_OP Identificador del operador de activación. AGG_OP Identificador del operador de agregación. DEFUZ Identificador del método de defuzzificación. STEPS Logaritmo en base 2 de la cantidad de pasos a realizar en el proceso de defuzzificación. Se realizan 2d pasos, donde d=STEPS. RES Campo reservado. Debe valer 0. RULE_NUM Cantidad de reglas para calcular esta variable. Reglas Mamdani 1 byte 1 byte CON MF1 ... 1 byte 1 byte 1 byte MFn OMF [PAD] ANEXO C. ESPECIFICACIÓN DEL FORMATO CFS 44 Desarrollo de un framework en lenguaje C para controladores difusos CON Identificador del conectivo lógico de la regla. MF1 Identificador de la función de membresía de la variable de entrada 1. MFn Identificador de la función de membresía de la variable de entrada n. OMF Identificador de la función de membresía de la variable de salida. [PAD] Padding para alinear la regla a 16 bits si es necesario. Variables de salida calculadas por Sugeno 1 byte 1 byte x bytes INF_TYPE:=1 RULE_NUM regla 1 y bytes ... regla n INF_TYPE Método de inferencia. 1 para Sugeno. RULE_NUM Cantidad de funciones de reglas para calcular esta variable. Reglas Sugeno 1 byte 1 byte CON MF1 ... 1 byte 1 byte 2 bytes 2 bytes MFn [PAD] C0 C1 2 bytes ... CON Identificador del conectivo lógico de la regla. MF1 Identificador de la función de membresía de la variable de entrada 1. MFn Identificador de la función de membresía de la variable de entrada n. [PAD] Padding para alinear la regla a 16 bits si es necesario. C0 Término independiente del consecuente en formato big-endian. C1 Coeficiente de la variable 1 en formato big-endian. Cn Coeficiente de la variable n en formato big-endian. ANEXO C. ESPECIFICACIÓN DEL FORMATO CFS Cn 45 Anexo D Cálculo de los coeficientes de Sugeno-Takagi Considérese un sistema basado en el métdo de Sugeno-Takagi con n variables de entrada. Los consecuentes de las reglas de este sistema tienen la forma: y= n X ai xi + a0 (D.1) i=1 Donde se utilizan los símbolos x para las entradas, y para las salidas y a para los coeficientes. Si ymax e ymin son los valores máximo y mínimo que puede tomar y, entonces la variable normalizada y 0 puede obtenerse como: n y0 = X ai a0 − ymin y − ymin = xi + ymax − ymin ymax − ymin ymax − ymin (D.2) i=1 Renombrando los coeficientes se obtiene: n X y0 = bi xi + b0 (D.3) i=1 Por otro lado, las entradas del sistema no serán las variables xi , sino las variables normalizadas x0i , las cuales pueden definirse como: x0i = xi − ximin ximax − ximin (D.4) Donde ximax e ximin son los valores máximo y mínimo que puede tomar la variable xi . Despejando xi y reemplazando en la ecuación D.7 se obtiene: 0 y = n X bi [x0i (ximax − ximin ) + ximin ] + b0 (D.5) i=1 Reordenando resulta: 0 y = n X bi (ximax − ximin )x0i i=1 + n X i=1 46 bi ximin + b0 (D.6) Desarrollo de un framework en lenguaje C para controladores difusos Finalmente, esta ecuación puede escribirse como: 0 y = n X ci x0i + c0 (D.7) i=1 Donde: ci = bi (ximax − ximin ) = ai c0 = n X i=1 ximax − ximin , i = 1..n ymax − ymin Pn bi ximin + b0 = + a0 − ymin ymax − ymin i=1 ai ximin ANEXO D. CÁLCULO DE LOS COEFICIENTES DE SUGENO-TAKAGI (D.8) (D.9) 47