La clave de la lógica fuzzy es que trata de comprender los cuantificadores de cualidad para nuestras inferencias (mucho, poco, muy, etc.). También esta lógica hace uso de operaciones sobre conjuntos como la unión, la intersección, diferencia, negación, etc. para llevar a cabo el tratamiento de la información y llegar a un resultado.
En la lógica fuzzy existen dos conjuntos difusos básicos llamados antecedentes (conjunto difuso de entrada) y consecuentes (conjunto difuso de salida). Por otro lado, para cada elemento a tratar existe una función de pertenencia, que indica en qué medida el elemento forma parte de ese conjunto difuso.
En la imagen anterior se puede ver la temperatura, que contiene 3 etiquetas, correspondientes a los trapecios que se aprecian. Cada una de estas etiquetas tienen un rango de valores, donde en ciertos puntos la certeza es máxima (1, donde habría un grado de pertenencia máximo a la etiqueta de frío), es decir, se está seguro de que hace frío (cold) y otros donde empieza a subir la temperatura y según donde esté se puede considerar frío en cierto grado o comenzar a acercarse más a una temperatura más cálida.
Además de lo anteriormente mencionado, la lógica fuzzy hace uso de una serie de reglas heurísticas, del tipo SI (antecedentes) ENTONCES (consecuente). Un ejemplo sería:
- Si hace mucho frío entonces subir mucho la calefacción.
- Si hace poco frío entonces subir un poco la calefacción.
- Si hace mucho calor entonces apagar la calefacción.
Una vez explicado por encima el principio básico de la lógica fuzzy y para llevarla a cabo con Arduino se ha optado por usar la "librería Fuzzy para Arduino y sistemas embebidos", comentada en la entrada de Fusión de sensores. Esta librería es bastante tediosa de usar, pero, una vez conocida la estructura a usar, es bastante fácil de manejar.
A continuación se procede a explicar el uso de esta librería:
Lo primero que hay que hacer es descargar la librería y añadirla en Arduino haciendo uso de la inclusión de librerías de Arduino (simplemente se añade un zip con los ficheros descargados del GitHub del proyecto y en Arduino ir a Programa -> Incluir librería -> Añadir librería .zip). Una vez se añade la librería se incluye esta al programa eligiendo la nueva opción que aparecerá llamada eFLL dentro de la opción de Incluir librería anteriormente mencionada.
A continuación se generaría un objeto de la clase Fuzzy y se generarían las etiquetas correspondientes a cada uno de los conjuntos a definir. En nuestro caso como conjunto de entrada se tendría la luz con dos etiquetas correspondientes a que no existe luz o existe luz, el conjunto de entrada para la distancia con tres etiquetas que serían no existe coche, coche alto y coche bajo. Para el conjunto de salida simplemente tendría dos etiquetas correspondientes a si hay un coche o no.
En el siguiente extracto del programa se ve lo explicado anteriormente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <Fuzzy.h> #include <FuzzyComposition.h> #include <FuzzyInput.h> #include <FuzzyIO.h> #include <FuzzyOutput.h> #include <FuzzyRule.h> #include <FuzzyRuleAntecedent.h> #include <FuzzyRuleConsequent.h> #include <FuzzySet.h> // Paso 1 - Instanciando un objeto de la librería fuzzy Fuzzy* fuzzy = new Fuzzy(); //Paso 2 - Crear etiquetas //Etiquetas luz FuzzySet* noExisteLuz = new FuzzySet(0, 0, 275, 425); FuzzySet* existeLuz = new FuzzySet(275, 425, 800, 800); //Etiquetas distancia FuzzySet* cocheAlto = new FuzzySet(0, 0, 127.5, 142.5); FuzzySet* cocheBajo = new FuzzySet(127.5, 142.5, 155, 165); FuzzySet* noExisteDistancia = new FuzzySet(165, 170, 210, 210); //Etiquetas salida FuzzySet* noExisteCoche = new FuzzySet(0, 0, 0, 0); FuzzySet* existeCoche = new FuzzySet(1, 1, 1, 1); |
Una vez se crean las etiquetas hay que crear los conjuntos de entrada y salida usando esas etiquetas. También se generaría el conjunto de reglas que se usa, como por ejemplo, Si no hay luz y coche alto Entonces existe coche.
Todo ello se ha añadido a una función para hacer uso de esta en el setup. A continuación se ve lo descrito:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | void initFuzzy(){ // Paso 3 - Creando conjunto de entrada de luz FuzzyInput* luz = new FuzzyInput(1);// Como parámetro necesita un ID luz->addFuzzySet(noExisteLuz); // Se añade la etiqueta luz->addFuzzySet(existeLuz); fuzzy->addFuzzyInput(luz); //Igual para la distancia FuzzyInput* distancia = new FuzzyInput(2);// Como parámetro necesita un ID distancia->addFuzzySet(noExisteDistancia); // Se añade la etiqueta distancia->addFuzzySet(cocheBajo); distancia->addFuzzySet(cocheAlto); fuzzy->addFuzzyInput(distancia); // Se añade el conjunto al objeto fuzzy // Paso 4 - Creando conjunto de salida FuzzyOutput* coche = new FuzzyOutput(1);// ID de parámetro coche->addFuzzySet(noExisteCoche); // Añadir etiqueta al conjunto de salida coche->addFuzzySet(existeCoche); fuzzy->addFuzzyOutput(coche); // Añadir el conjunto de salida al objeto fuzzy //Paso 5 - Conjunto de reglas //Consecuentes FuzzyRuleConsequent* thenExisteCoche = new FuzzyRuleConsequent(); //Creación de consecuente thenExisteCoche->addOutput(existeCoche);// Juntando consecuente con salida FuzzyRuleConsequent* thenNoExisteCoche = new FuzzyRuleConsequent(); thenNoExisteCoche->addOutput(noExisteCoche); // Regla 1 - Si existe luz y no existe distancia, existe un coche FuzzyRuleAntecedent* siNoExisteLuzYnoExisteDistancia = new FuzzyRuleAntecedent(); //Creando antecedente siNoExisteLuzYnoExisteDistancia->joinWithAND(noExisteLuz, noExisteDistancia); //Añadiendo etiquetas al antecedente FuzzyRule* fuzzyRule01 = new FuzzyRule(1, siNoExisteLuzYnoExisteDistancia, thenExisteCoche); // Creando la regla fuzzy->addFuzzyRule(fuzzyRule01); // Añadiendo regla al conjunto de reglas // Regla 2 - Si existe luz y coche alto, existe un coche FuzzyRuleAntecedent* siNoExisteLuzYcocheAlto = new FuzzyRuleAntecedent(); siNoExisteLuzYcocheAlto->joinWithAND(noExisteLuz, cocheAlto); FuzzyRule* fuzzyRule02 = new FuzzyRule(2, siNoExisteLuzYcocheAlto, thenExisteCoche); fuzzy->addFuzzyRule(fuzzyRule02); // Regla 3 - Si existe luz y coche bajo, existe un coche FuzzyRuleAntecedent* siNoExisteLuzYcocheBajo = new FuzzyRuleAntecedent(); siNoExisteLuzYcocheBajo->joinWithAND(noExisteLuz, cocheBajo); FuzzyRule* fuzzyRule03 = new FuzzyRule(3, siNoExisteLuzYcocheBajo, thenExisteCoche); fuzzy->addFuzzyRule(fuzzyRule03); // Regla 4 - Si no existe luz y no existe distancia, no existe un coche FuzzyRuleAntecedent* siExisteLuzYnoExisteDistancia = new FuzzyRuleAntecedent(); siExisteLuzYnoExisteDistancia->joinWithAND(existeLuz, noExisteDistancia); FuzzyRule* fuzzyRule04 = new FuzzyRule(4, siExisteLuzYnoExisteDistancia, thenNoExisteCoche); fuzzy->addFuzzyRule(fuzzyRule04); // Regla 5 - Si no existe luz y coche Alto, existe un coche FuzzyRuleAntecedent* siExisteLuzYcocheAlto = new FuzzyRuleAntecedent(); siExisteLuzYcocheAlto->joinWithAND(existeLuz, cocheAlto); FuzzyRule* fuzzyRule05 = new FuzzyRule(5, siExisteLuzYcocheAlto, thenExisteCoche); fuzzy->addFuzzyRule(fuzzyRule05); // Regla 6 - Si no existe luz y coche bajo, no existe un coche FuzzyRuleAntecedent* siExisteLuzYcocheBajo = new FuzzyRuleAntecedent(); siExisteLuzYcocheBajo->joinWithAND(existeLuz, cocheBajo); FuzzyRule* fuzzyRule06 = new FuzzyRule(6, siExisteLuzYcocheBajo, thenNoExisteCoche); fuzzy->addFuzzyRule(fuzzyRule06); } |
Una vez se tiene creada la lógica fuzzy, para hacer uso de esta se usan los métodos que esta librería incluye. Básicamente se trata de darle un valor a cada uno de los conjuntos de entrada, usar la función de fuzzify, ver el grado de emparejamiento si se desea usando el método getPertinence de cada etiqueta y recoger la salida del conjunto de consecuente con deffuzify.
Hay que tener en cuenta que cada conjunto de entrada y salida tiene asociado un identificador para poder llamarlos después.
Todo lo descrito anteriormente se ha plasmado en un método, que recibe como parámetros de entrada la luz y la distancia y devuelve si no hay coche (0) o si lo hay (1) que son los valores correspondientes a las etiquetas del conjunto de salida. Este método es el que se usará en el loop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | int getFuzzyValue(float luz, float distancia){ Serial.println("Datos que llegan: "); Serial.print("Luz: "); Serial.print(luz); Serial.print(" distancia "); Serial.println(distancia); //Paso 7 - Iniciar entradas y fuzzificar fuzzy->setInput(1, luz); fuzzy->setInput(2, distancia); fuzzy->fuzzify(); //Ver pertenencia a cada etiqueta Serial.print("Luz: "); Serial.print("no existe luz: "); Serial.print(noExisteLuz->getPertinence()); Serial.print(", existe luz "); Serial.println(existeLuz->getPertinence()); Serial.print("Distancia: "); Serial.print("No existe distancia: "); Serial.print(noExisteDistancia->getPertinence()); Serial.print(", Coche alto: "); Serial.print(cocheAlto->getPertinence()); Serial.print(", cocheBajo"); Serial.println(cocheBajo->getPertinence()); //Paso 8 - Defuzzificar y coger valor salida int coche = fuzzy->defuzzify(1); Serial.print("Existe coche? "); Serial.println(coche); return coche; } |
Con estos dos métodos de creación y uso del Fuzzy se finalizaría la explicación de esta fase. Habría que mencionar que cada una de las etiquetas hay que darle un valor para generar un trapezoide como se ve con la temperatura. Estos valores se han extraído de la experimentación y se han puesto directamente para ahorrar tiempo,
Plaza arduino con etiquetas fuzzy generadas automáticamente
Me gustaría saber que librería estas utilizando, porque la que tengo no funciona con los void, gracias.
ResponderEliminar