Nuestro mundo conectado; explicando las máquinas de estados finitos
Se dice que el hombre/la mujer fue creado a imagen de Dios. De manera similar, hombres y mujeres ahora crean máquinas a nuestra propia imagen. Un ejemplo de esto es la programación , o FSM para abreviar. Los ingenieros y desarrolladores ahora utilizan computadoras para realizar tareas que antes se realizaban manualmente. Por ejemplo, ¿tienes ropa sucia por ahí? – Lo sé. Anteriormente teníamos que enjuagar la ropa en una tina o fregadero, agregar jabón, fregar, enjuagar nuevamente y todo eso para conseguir una camiseta limpia para ir a trabajar o salir por la noche. Ahora tenemos lavadoras para hacer este trabajo por nosotros. Llegamos a este punto con ingenieros que diseñaron miles de productos y dispositivos que ejecutan programas basados en el pensamiento o la acción humana. Esta no es una excepción al aprendizaje automático u otras palabras de moda de la IA de hoy . Se están desarrollando millones de dispositivos y aplicaciones para aumentar la eficiencia y la facilidad de las personas y muchos de estos procesos de ayuda existen gracias a los FSM.
Las máquinas de estados finitos son simplemente un cálculo matemático de una serie de causas con eventos. En relación con nuestro ejemplo de lavadora, el 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 grande. El cálculo de FSM cambia o pasa de un estado a otro en respuesta a entradas externas. Un FSM se define mediante un listado u orden lógico de sus estados; su estado inicial y las condiciones para cada transición, concluyendo con un estado final o final. El FSM es una serie de pensamientos programados por la computadora para ejecutar operaciones basadas en entradas; de la misma manera que el hombre piensa y actúa, también lo hacen nuestras máquinas y las computadoras que las controlan.
Los estados son el ADN del FSM que dicta el comportamiento interno o las interacciones con un entorno, como aceptar entradas o producir salidas que pueden o no causar que el sistema cambie o haga una transición de su estado. El estado se ejecutará específicamente dependiendo de los diferentes condicionales definidos en su FSM. Este concepto es muy importante para los ingenieros eléctricos y de hardware, ya que muchos problemas prácticos como la programación de las lavadoras (cuándo agregar agua o jabón, cuándo centrifugar o descansar) se resuelven fácilmente utilizando FSM en lugar de los paradigmas clásicos de programación secuencial. En otras palabras, un 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 muestran dos ejemplos de FSM que producen una toma de decisiones lógica con menos tiempo y energía necesarios para implementar un programa lógico probado. El FSM es su primer paso hacia la informática perimetral a nivel de dispositivo único en aplicaciones industriales IoT .
Máquina Mealy: en el cálculo de la máquina Mealy, las salidas de cada estado dependen del estado real y sus valores de entrada actuales. Normalmente, con cada cálculo de Mealy, la entrada de un estado da como resultado una única salida a una transición o a un estado final. La lavadora se está llenando de agua; cuando se alcanza el nivel X, detenga el agua.
Máquina Moore: En la máquina 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 de detenerla.
DIAGRAMA DE ESTADO
Cualquier FSM debe describirse antes de ser codificado mediante un diagrama de estado (la forma en que podemos diagramar los pensamientos de la máquina). El siguiente ejemplo muestra el comportamiento de FSM y sus transiciones que (normalmente) se dibujan utilizando burbujas para describir estados y flechas para las transiciones. Además, una nota común al ejecutar un FSM correctamente es tener un estado presente único donde el siguiente estado (futuro) que se ejecutará se pueda identificar 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 de Mealy. Supongamos que la operación comienza en el Estado 1 y luego pasa al Estado 2 una vez que se han cumplido las credenciales de programación. Después de pasar a la Etapa 2, el FSM calcula el estado actual hasta que se cumple un activador 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 dan como resultado datos calculados para su resultado final del proyecto.
Ubidots FSM
Ahora, comencemos a codificar un FSM para enviar datos a Ubidots y brindarle una experiencia de la vida real trabajando con este método de programación. Para nuestro FSM, buscamos identificar y reaccionar ante el requisito inicial. Construiremos una máquina Moore rápida: enviaremos datos de sensores desde nuestro microcontrolador (Espressif ESP8266) cada minuto a Ubidots
Con base en este requisito inicial, hemos optado por implementar dos estados utilizando un modelo de cálculo Moore Machine FSM:
- ESPERE: No haga nada hasta que haya pasado un minuto (siéntese en estado inactivo durante aproximadamente 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 siguiente diagrama de estado ilustra la lógica de programación de nuestro FSM:
De este diagrama se desprende 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 ESPERA, el programa se ejecutará continuamente en ESPERA hasta que el tiempo independiente alcance o supere los 60 segundos. Una vez que se alcance la marca de 60 segundos, el FSM pasará de WAIT a READ_SEND. Después de enviar el valor, el FSM volverá a ESPERA durante un conteo adicional de ~59 segundos antes de volver a calcular la transición.
Codificación
Para que este ejemplo sea un poco más sencillo de entender, veamos un código FSM práctico que se ha dividido en cuatro partes separadas para detallar cada uno de los estados y condicionales de transición. El código completo se puede encontrar en su totalidad aquí.
Parte 1: Definir restricciones
// Incluir bibliotecas #include " Ubidots ESPMQTT.h" // Definir constantes #define TOKEN "...." // Tu Ubidots TOKEN #define WIFINAME "...." //Tu SSID #define WIFIPASS "... ." // Su pase Wifi #define WAIT 0 #define READ_SEND 1 uint8_t fsm_state = WAIT; // Estado inicial int msCount = 0; // valor flotante del contador de tiempo; // 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 requeridas. Es importante tener en cuenta que aquí definimos los dos estados, WAIT y READ_SEND como las constantes dentro de todo el código y definimos el estado actual usando la variable fsm_state. La siguiente parte del código reserva espacio de memoria para el temporizador independiente y el valor que se leerá y el cliente MQTT que se inicializará.
Es importante que no olvides configurar los valores adecuados para tu TOKEN y el nombre y contraseña de tu red WiFi. Si no sabe dónde encontrar su token, consulte el Centro de ayuda Ubidots 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("El mensaje llegó ["); Serial.print(tema); Serie.print("] "); for (int i=0;i < length;i++) { Serial.print((char)payload[i]); } Serie.println(); }
En esta parte del código proporcionamos una devolución de llamada que maneja datos del servidor cuando/si es necesario. Para nuestro FSM, este paso es necesario para compilar correctamente su código. Como se describe en nuestro artículo MQTT , la función de devolución de llamada maneja los cambios de sus variables en Ubidots y es necesario compilar el código y definirlo.
Parte 3 – Funciones principales – Configuración()
// Funciones principales void setup() { // inicializa el pin digital LED_BUILTIN como salida. pinMode(A0, ENTRADA); client.wifiConnection(WIFINAME, WIFIPASS); cliente.begin(devolución de llamada); }
Ahora comencemos con las funciones principales. En nuestra configuración() configuraremos el pin analógico cero como entrada (debe editar el número del PIN dependiendo de 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 número flotante como un valor. Además, inicializamos el cliente WiFi y pasamos la función de devolución de llamada en función de los parámetros de programación previamente definidos.
Parte 4 – Funciones principales – Bucle()
bucle vacío() { switch(fsm_state) { caso ESPERA: if (msCount >= 60000){ msCount = 0; fsm_state = READ_SEND; } romper; caso READ_SEND: valor = analogRead(A0); if(!cliente.conectado()){ cliente.reconectar(); } /* Rutina de envío de datos */ client.add("cosas", valor); cliente. ubidots Publicar("fuente1"); cliente.loop(); fsm_state = ESPERAR; romper; predeterminado: romper; } // Incrementa el contador msCount += 1; retraso(1); }
Una forma popular de implementar FSM en microcontroladores es utilizar la de caja de interruptor . Para nuestro ejemplo, los casos serán nuestros estados y los interruptores serán la variable fsm_state
Veamos con más detalle cómo está diseñado cada estado:
Una forma popular de implementar FSM en microcontroladores es utilizar la de caja de interruptor . Para nuestro ejemplo, los casos de cambio serán nuestros Estados y la programación que provoca una transición representada por la variable fsm_state. Aquí determinaremos READ_SEND vs WAIT donde los valores de 1 o 0 se enviarán respetuosamente para identificar cada etapa del 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:
- ESPERE: Del código de este estado, podemos inferir que no hará nada si el resultado del temporizador independiente almacenado en
msCount
es inferior a 60000 milisegundos; una vez que se alcanza esta condición, el valor defsm_state
cambia y pasamos al siguiente estado, el estado READ_SEND. - READ_SEND: Aquí leemos el valor de nuestro sensor y luego simplemente lo agregamos a una variable llamada "cosas" y publicamos sus datos en un dispositivo llamado "fuente1". Al ejecutar este programa, siempre volveremos al estado ESPERA antes de emitir una segunda salida.
Finalmente, fuera de nuestra estructura de caja de interruptor, 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 te estarás preguntando ¿para qué programar todo esto si podemos utilizar la programación secuencial habitual? Imagina que tienes tres tareas adicionales que realizar dentro de tu rutina:
- Controlar un servomotor mediante PWM
- Mostrar valores en una pantalla LCD
- Para cerrar o abrir una puerta
Al operar múltiples tareas, el FSM permite un almacenamiento mínimo de datos en la memoria local de un dispositivo, además las funciones de estado pueden realizar tareas inmediatas basadas en los valores de entrada y no solo en una única salida. Con FSM puede tomar decisiones más lógicas con menos tiempo y energía necesarios para implementar un programa lógico probado. El valor de FSM es su capacidad para calcular procesos a nivel de dispositivo único: el primer paso en la computación Edge.
Pruebas
Nuestros scripts funcionan como se esperaba, se crea un nuevo dispositivo llamado "fuente1" con una variable llamada "cosas" que recibe y guarda el valor del sensor cada 60 segundos en Ubidots .
Mejoras e ideas
Un FSM se puede implementar de muchas maneras y, a veces, la declaración de cambio de caso puede resultar tediosa de mantener si es necesario gestionar una gran cantidad de estados. Una mejora adicional al código explicado aquí en la Parte 1 sería evitar la espera de 1 milisegundo entre cada caso analizado. Esto se puede realizar usando millis().
Conclusión
El hombre y la mujer han diseñado nuestras computadoras para que funcionen a nuestra propia imagen y las Máquinas de Estados Finitos 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 conocimiento para implementar FSM se vuelvan cada vez más baratos y accesibles, seguiremos viendo computadoras de placa única (SBC) impregnando las fábricas industriales y los talleres. El control de procesos simples con programación FSM en SBC continúa impulsando soluciones conectadas que complementan gateway y los PLC básicos como Dell, Siemens, etc., al mismo tiempo que brindan soluciones locales que ahorran $ 10,000 en costos operativos y de hardware.