Nuestro mundo conectado; explicando las máquinas de estados finitos

José García
· 8 minutos de lectura
Enviar por correo electrónico

Se dice que el hombre y la mujer fueron creados a imagen y semejanza de Dios. De manera similar, ahora creamos máquinas a nuestra propia imagen. Un ejemplo de esto es la programación, o FSM por sus siglas en inglés. Ingenieros y desarrolladores ahora usan computadoras para realizar tareas que antes se hacían manualmente. Por ejemplo, ¿tienes ropa sucia por ahí? Yo sí. Antes teníamos que enjuagar la ropa en una tina o lavabo, agregar jabón, frotar, enjuagar de nuevo, etc., para tener una camiseta limpia para ir al trabajo o salir por la noche. Ahora tenemos lavadoras que hacen este trabajo por nosotros. Hemos llegado a este punto gracias a que los ingenieros han diseñado miles de productos y dispositivos que ejecutan programas basados ​​en el pensamiento o la acción humana. Esto no es una excepción al machine learning u otros términos de moda de la IA. Millones de dispositivos y aplicaciones se están desarrollando para aumentar la eficiencia y facilitar la vida de hombres y mujeres, y muchos de estos procesos de ayuda existen gracias a las FSM.

Las máquinas de estados finitos (FSM) son simplemente un cálculo matemático de una serie de causas y eventos. En relación con nuestro ejemplo de la lavadora, la FSM determina cuándo iniciar el ciclo de enjuague, cuándo centrifugar y cuándo detenerse por completo. Para comprender mejor una máquina de estados finitos (FSM), primero debemos definir el concepto de "estado". Un estado es una pieza única de información dentro de un programa computacional más amplio. El cálculo de la FSM cambia o transita de un estado a otro en respuesta a entradas externas. Una FSM se define mediante una lista u orden lógico de sus estados: su estado inicial y las condiciones para cada transición, culminando con un estado final. La FSM es una serie de pensamientos programados por la computadora para ejecutar operaciones basadas en entradas; de la misma manera que el ser humano piensa y actúa, también lo hacen nuestras máquinas y las computadoras que las controlan.

Los estados son el ADN de la FSM, que dicta el comportamiento interno o las interacciones con el entorno, como la aceptación de entradas o la producción de salidas, lo que puede o no provocar que el sistema cambie o cambie de estado. El estado se ejecuta específicamente en función de las diferentes condiciones definidas en la FSM. Este concepto es fundamental para los ingenieros de hardware y eléctricos, ya que muchos problemas prácticos, como la programación de lavadoras (cuándo añadir agua o jabón, cuándo centrifugar o cuándo parar), se resuelven fácilmente con la FSM en lugar de los paradigmas clásicos de programación secuencial. En otras palabras, una FSM es una solución más "eléctrica y electrónica" para resolver un problema de hardware que la programación secuencial.

A continuación, se presentan dos ejemplos de FSM que permiten una toma de decisiones lógica con menos tiempo y energía para implementar un programa lógico probado. El FSM es el primer paso hacia la computación Edge a nivel de dispositivo único en aplicaciones industriales IoT .

Máquina de Mealy: En el cálculo de la máquina de Mealy, las salidas de cada estado dependen del estado actual y de sus valores de entrada. Normalmente, en cada cálculo de Mealy, la entrada de un estado produce una única salida que conduce a una transición o a un estado final. Por ejemplo, la lavadora se está llenando de agua; cuando se alcanza el nivel X, se detiene el suministro de agua.

Máquina de Moore: En la máquina de Moore, las salidas de cada estado dependen del estado real y normalmente se basan en sistemas secuenciales sincronizados. La lavadora gira después de 4 minutos. Detenga la máquina.

DIAGRAMA DE ESTADOS

Cualquier FSM debe describirse antes de codificarse mediante un diagrama de estados, de la misma manera que diagramamos el pensamiento de la máquina. El siguiente ejemplo muestra el comportamiento de la FSM y sus transiciones, que se dibujan (normalmente) mediante burbujas para describir los estados y flechas para las transiciones. Además, una nota común al ejecutar una FSM correctamente es tener un estado presente único donde el siguiente estado (futuro) que se ejecutará pueda identificarse fácilmente mediante las credenciales de programación del estado.

En el diagrama anterior, ilustramos un proceso completo de la Máquina de Estados Finitos Mealy. Supongamos que la operación comienza en el Estado 1 y pasa al Estado 2 una vez que se cumplen los requisitos de programación. Tras la transición a la Etapa 2, la FSM calcula el estado actual hasta que se cumple un disparador para pasar al Estado 3 o al Estado 4. Tenga en cuenta que, en este diagrama, el Estado 3 y la Etapa 4 son estados finales que generan datos calculados para el resultado final de su proyecto.

FSM Ubidots

Ahora, comencemos a programar una máquina de estados finitos (FSM) para enviar datos a Ubidots y brindarles una experiencia práctica con este método de programación. Para nuestra FSM, buscamos identificar y responder al requisito inicial. Construiremos una máquina de Moore rápida:enviaremos datos de sensores desde nuestro microcontrolador (Espressif ESP8266) cada minuto a Ubidots

En base a este requerimiento inicial, hemos optado por implementar dos estados utilizando un modelo de cálculo FSM de Máquina de Moore:

  • ESPERAR: No hacer nada hasta que haya transcurrido un minuto (permanecer en estado inactivo durante ~59 segundos).
  • READ_SEND: Lee la entrada analógica del microcontrolador donde está conectado el sensor y envía el resultado a Ubidots usando MQTT en la marca de 60 segundos.

El diagrama de estados a continuación ilustra la lógica de programación de nuestro FSM:

Este diagrama muestra claramente que la transición de WAIT a READ_SEND depende exclusivamente de si el valor del tiempo independiente es mayor o menor que 60 segundos. A partir del siguiente estado de WAIT, el programa se ejecutará continuamente en WAIT hasta que el tiempo independiente alcance o supere los 60 segundos. Una vez alcanzados los 60 segundos, la FSM pasará de WAIT a READ_SEND. Tras enviar el valor, la FSM volverá a WAIT durante unos 59 segundos adicionales antes de volver a calcular la transición.

Codificación

Para que este ejemplo sea más fácil de entender, veamos un código práctico de máquina de estados finitos (FSM) dividido en cuatro partes que detallan cada uno de los estados y las condiciones de transición. El código completo se puede encontrar aquí.

Parte 1 – Definir restricciones

// Incluir bibliotecas #include "UbidotsESPMQTT.h" // Definir constantes #define TOKEN "...." // Su TOKEN Ubidots #define WIFINAME "...." // Su SSID #define WIFIPASS "...." // Su contraseña Wifi #define WAIT 0 #define READ_SEND 1 uint8_t fsm_state = WAIT; // Estado inicial int msCount = 0; // contador de tiempo float value; // espacio de memoria para el valor a leer Ubidots client(TOKEN);

Esta primera parte del código no es muy interesante, ya que simplemente importamos la biblioteca MQTT para enviar datos a Ubidots y completamos algunas definiciones necesarias. Es importante destacar que aquí definimos los dos estados, WAIT y READ_SEND, como constantes dentro del código, y el estado actual se define mediante la variable fsm_state. La siguiente parte del código reserva espacio de memoria para el temporizador independiente, el valor a leer y la inicialización del cliente MQTT.

Es importante que no olvides configurar los valores correctos para tu token, así como para el nombre y la contraseña de tu red wifi. Si no sabes dónde encontrar tu token, consulta el Ubidots Centro de Ayuda para obtener más consejos y trucos.

Parte 2 – Devolución de llamada

// Funciones auxiliares void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Mensaje llegado ["); Serial.print(topic); Serial.print("] "); for (int i=0;i < length;i++) { Serial.print((char)payload[i]); } Serial.println(); }

En esta parte del código, proporcionamos una función de devolución de llamada que gestiona los datos del servidor cuando es necesario. Para nuestra FSM, este paso es necesario para compilar correctamente el código. Como se describe en nuestro artículo sobre MQTT, la función de devolución de llamada gestiona los cambios de las variables en Ubidots y es necesaria para compilar el código y tenerlo definido.

Parte 3 – Funciones principales – Setup()

// Funciones principales void setup() { // inicializa el pin digital LED_BUILTIN como salida. pinMode(A0, INPUT); client.wifiConnection(WIFINAME, WIFIPASS); client.begin(callback); }

Comencemos con las funciones principales. En nuestra configuración (setup()), estableceremos el pin analógico cero como entrada (debe modificar el número del PIN según la conexión física de su sensor) para poder usar el ADC que permite al sensor leer los datos del entorno y representar un valor de coma flotante. Además, inicializamos el cliente WiFi y pasamos la función de devolución de llamada según los parámetros de programación definidos previamente.

Parte 4 – Funciones principales – Loop()

void loop() { switch(fsm_state) { case WAIT: if (msCount >= 60000){ msCount = 0; fsm_state = READ_SEND; } break; case READ_SEND: value = analogRead(A0); if(!client.connected()){ client.reconnect(); } /* Rutina para enviar datos */ client.add("stuff", value);ubidotsPublish("source1"); client.loop(); fsm_state = WAIT; break; default: break; } // Incrementa el contador msCount += 1; delay(1); }

Una forma popular de implementar máquinas de estados finitos (FSM) en microcontroladores es mediante la switch-case . En nuestro ejemplo, los casos serán nuestros estados y los interruptores serán la fsm_state . Veamos con más detalle cómo se diseña cada estado:

Una forma popular de implementar la FSM en microcontroladores es mediante lade casos de conmutación . En nuestro ejemplo, los casos de conmutación serán nuestros estados y la programación que provoca una transición, representada por la variable fsm_state. Aquí determinaremos READ_SEND y WAIT, donde se enviarán valores de 1 o 0 respectivamente para identificar cada etapa de la FSM y la transición entre operaciones según el temporizador independiente de 60 segundos.

Veamos con más detalle cómo está diseñado cada estado:

  • ESPERA: Del código de este estado, podemos inferir que no hará nada si el resultado del temporizador independiente almacenado en msCount es menor a 60000 milisegundos; una vez que se alcanza esta condición, el valor de fsm_state cambia y pasamos al siguiente estado, el estado READ_SEND.
  • READ_SEND: Aquí leemos el valor de nuestro sensor y lo añadimos a una variable llamada "stuff" y publicamos sus datos en un dispositivo llamado "source1". Al ejecutar este programa, siempre volvemos al estado WAIT antes de emitir una segunda salida.

Finalmente, a partir de nuestra estructura de caso de conmutación, incrementamos el valor de nuestro temporizador y tenemos un retraso muy pequeño de 1 milisegundo para que el tiempo sea consistente con nuestro contador.

Llegados a este punto, quizá te preguntes por qué programar todo esto si podemos usar la programación secuencial habitual. Imagina que tienes tres tareas adicionales que realizar en tu rutina:

  1. Controlar un servomotor mediante PWM
  2. Mostrar valores en una pantalla LCD
  3. Cerrar o abrir una puerta

Al ejecutar múltiples tareas, la FSM permite un almacenamiento mínimo de datos en la memoria local del dispositivo, además de que las funciones de estado pueden realizar tareas inmediatas basadas en los valores de entrada y no solo en una única salida. Con FSM, se puede tomar decisiones más lógicas con menos tiempo y energía para implementar un programa con una lógica probada. El valor de la FSM reside en su capacidad para computar procesos a nivel de dispositivo único: el primer paso en la computación Edge .

Pruebas

Nuestros scripts funcionan como se espera, se crea un nuevo dispositivo llamado “source1” con una variable llamada “stuff” que recibe y guarda el valor del sensor cada 60 segundos en Ubidots.

Mejoras e ideas

Una FSM se puede implementar de muchas maneras, y a veces la instrucción switch-case puede ser tediosa de mantener si se necesita gestionar una gran cantidad de estados. Una mejora adicional al código explicado en la Parte 1 sería evitar la espera de 1 milisegundo entre cada caso analizado. Esto se puede lograr mediante millis().

Conclusión

El ser humano ha diseñado nuestros ordenadores para que funcionen a su imagen y semejanza, y las máquinas de estados finitos (FSM) son la programación que permite a las máquinas realizar tareas y brindar a los humanos una valiosa asistencia y seguridad en nuestra vida diaria. A medida que la tecnología y el conocimientoedge implementar FSM se vuelven más económicos y accesibles, seguiremos viendo los ordenadores de placa única (SBC) se extienden por las fábricas y los talleres industriales. El control de procesos sencillos mediante la programación FSM en SBC impulsa soluciones conectadas que complementan gatewayy los PLC de marcas como Dell, Siemens, etc., a la vez que proporciona soluciones locales que ahorran $en costes de hardware y operativos.