Ir al contenido principal

Arduino - MEF - Apertura de puertas automáticas

 

1        Máquina de Estados Finitos – Sistema de Puertas automáticas

1.1     Definición

 

1.2     Estados

1.      Estado Cerrado (totalmente Cerrado)

2.      Estado Abriendo

3.      Estado Abierto (totalmente Abierto)

4.      Estado Cerrando

1.3     Transiciones

a.      De Cerrado a Abriendo: Se solicitó abrir. Puede ser por un botón, por detectar cercanía, por detectar movimiento, o por mensaje de otro dispositivo (serial)

b.     De Abriendo a Abierto: Se llegó hasta el fin, accionamiento del botón “final de carrera”

c.      De Abierto a Cerrando: Se solicita cerrar. Puede ser por un botón, por no detectar cercanía o por no detectar movimiento (y por ende, un tiempo ha transcurrido), o por mensaje de otro dispositivo. Sugiero que deba haber un temporizador.

1.4     Componentes y conexiones

1.      Sensor de Apertura (x1, x2) à Sensor de movimiento (PIR) o de distancia (Ultrasonidos HC-SR04).

2.      Sensor de límite totalmente Abierto (x1) à Botón

3.      Sensor de Cierre (x0) à Temporizador

4.      Sensor de límite totalmente Cerrado (x1) à Botón

5.      Relé para el motor de apertura (x1) à Relé, alternativamente un LED

6.      Relé para el motor de cierre (x1) à Relé, alternativamente un LED

1.5     Implementación

1.5.1    Sensor de un sólo lado

1.      Primero, preparar trucos para programar más fácilmente:

// Trucos de C++

#define ENTER "\n"

 

template<class CualquierTipo> inline Print

&operator << (Print &izq, CualquierTipo der )

{

  izq.print( der ) ;

  return izq ;

}

 

2.      Inicializar librerías. Creo que no necesitamos ninguna, así que saltearemos esta parte.

3.      Generar los pines.

#define PIN_DETECTOR 3

#define PIN_FINAL_ABIERTO 4

#define PIN_FINAL_CERRADO 5

#define PIN_RELE_ABRIR 6

#define PIN_RELE_CERRAR 7

4.      Creación de variables para dispositivos complejos. Como no hay, salteamos.

5.      Creación de variables de medición de sensores

float

  _medicionPersonaCerca = 0

  , _medicionFinalAbierto = 0

  , _medicionFinalCerrado = 0

  ;

6.      Creación de las variables de los estados

float _tiempoEstado = 0.0f ;

int _estado = 0 ;

String _pcDice = "" ;

7.      Definición de los Estados para la máquina

#define ESTADO_CERRADO 0

#define ESTADO_ABRIENDO 1

#define ESTADO_ABIERTO 2

#define ESTADO_CERRANDO 3

8.      Establecemos el setup() básico:

void setup() {

  Serial.begin( 9600 ) ;

  Serial << "arduino:conectado" << ENTER ;

  Serial.setTimeout( 10 ) ;

 

9.      Definimos modos de los pines e inicializamos dispositivos complejos, si los hubiere.

  pinMode( PIN_DETECTOR, INPUT ) ;

  pinMode( PIN_FINAL_CERRADO, INPUT ) ;

  pinMode( PIN_FINAL_ABIERTO, INPUT ) ;

  pinMode( PIN_RELE_ABRIR, OUTPUT ) ;

  pinMode( PIN_RELE_CERRAR, OUTPUT ) ;

10. Habilitamos el primer estado, cerramos la función setup() y comenzamos la loop().

  fnCambiarAEstadoCerrado() ;

}

void loop() {

  _pcDice = "" ;

  if( Serial.available() ) {

    _pcDice = Serial.readString() ;

    _pcDice.trim() ;

  }

11. Armamos la máquina de estados finitos.

  if( _estado == ESTADO_CERRADO )

    fnEstadoCerrado() ;

  else if( _estado == ESTADO_ABRIENDO )

    fnEstadoAbriendo() ;

  else if( _estado == ESTADO_ABIERTO )

    fnEstadoAbierto() ;

  else if( _estado == ESTADO_CERRANDO )

    fnEstadoCerrando() ;

  ;

  delay( 100 ) ;

  _tiempoEstado = _tiempoEstado + 100.00f ;

}

12. Pensemos en cada estado. En el estado cerrado, estaremos esperando a que un usuario se acerque a un lado de la puerta (y/o al otro), o de la computadora venga algún mensaje adecuado.

void fnEstadoCerrado() {

  _medicionPersonaCerca = digitalRead( PIN_DETECTOR ) ;

  if( _medicionPersonaCerca == HIGH ) {

    return fnCambiarAEstadoAbriendo() ;

  }

  if( _pcDice == "abrir" ) {

    return fnCambiarAEstadoAbriendo() ;

  }

}

13. Estado abriendo. Tenemos que esperar a que la puerte llegue a su destino.

void fnEstadoAbriendo() {

  _medicionFinalAbierto = digitalRead(PIN_FINAL_ABIERTO);

  if( _medicionFinalAbierto == HIGH ) {

    return fnCambiarAEstadoAbierto() ;

  }

}

14. Estado abierto. Esperamos a que pase el tiempo, o a que de la computadora venga un mensaje.

void fnEstadoAbierto() {

  if( _tiempoEstado >= 3000 ) {

    return fnCambiarAEstadoCerrando() ;

  }

  if( _pcDice == "cerrar" ) {

    return fnCambiarAEstadoCerrando() ;

  }

}

15. Estado cerrando, como el estado abriendo, deberemos esperar a que llegue a su destino.

void fnEstadoCerrando() {

  _medicionFinalCerrado = digitalRead(PIN_FINAL_CERRADO);

  if( _medicionFinalCerrado == HIGH ) {

    return fnCambiarAEstadoCerrado() ;

  }

}

16. Ahora pensemos en las transiciones. Son todas parecidas, al menos en este proyecto. En las transiciones deberemos:

a.      Cambiar el estado.

b.     Reinicializar el tiempo.

c.      Avisar el cambio a la PC.

d.     Activar o desactivar actuadores

void fnCambiarAEstadoAbriendo() {

  _estado = ESTADO_ABRIENDO ;

  _tiempoEstado = 0.00f ;

  Serial << "estado:" << ESTADO_ABRIENDO << ENTER ;

  Serial << "Abriendo puertas" << ENTER ;

  digitalWrite( PIN_RELE_ABRIR, HIGH ) ;

}

void fnCambiarAEstadoAbierto() {

  _estado = ESTADO_ABIERTO ;

  _tiempoEstado = 0.00f ;

  Serial << "estado:" << ESTADO_ABIERTO << ENTER ;

  Serial << "Puertas abiertas" << ENTER ;

  digitalWrite( PIN_RELE_ABRIR, LOW ) ;

}

void fnCambiarAEstadoCerrando() {

  _estado = ESTADO_CERRANDO ;

  _tiempoEstado = 0.00f ;

  Serial << "estado:" << ESTADO_CERRANDO << ENTER ;

  Serial << "Cerrando puertas" << ENTER ;

  digitalWrite( PIN_RELE_CERRAR, HIGH ) ;

}

void fnCambiarAEstadoCerrado() {

  _estado = ESTADO_CERRADO ;

  _tiempoEstado = 0.00f ;

  Serial << "estado:" << ESTADO_CERRADO << ENTER ;

  Serial << "Puertas cerradas" << ENTER ;

  digitalWrite( PIN_RELE_CERRAR, LOW ) ;

}

 

 

1.5.2    Sensor de 2 lados

Variamos al proyecto para tener 2 detectores de presencia o movimiento.

Del punto 3, agregamos la definición del PIN_DETECTOR2

#define PIN_DETECTOR2 8

Del punto 5, agregamos la variable de su medición, antes del punto y coma.

float

  // …

  , _medicionDetector2 = 0

  ;

Redefinimos al estado cerrado para detectar a la persona con el segundo detector.

void fnEstadoCerrado() {

  _medicionPersonaCerca =

    digitalRead( PIN_DETECTOR )

    + digitalRead( PIN_DETECTOR2 )

  ;

  if( _medicionPersonaCerca ) {

    return fnCambiarAEstadoAbriendo() ;

  }

  if( _pcDice == "abrir" ) {

    return fnCambiarAEstadoAbriendo() ;

  }

}

 

1.6     Mejoras

Como en muchos estados las condiciones dispararían al mismo cambio de estado, podríamos juntarlas todas en mi mismo IF() con el operador lógico || (or), cuestión que si ocurre una posibilidad o la otra, igual se cumpliría. Incluso, ni hace falta utilizar la expresión return; esto se utilizaría en contextos en que no queremos que continuara otra regla.

void fnEstadoCerrado() {

  _medicionPersonaCerca =

    digitalRead( PIN_DETECTOR )

    + digitalRead( PIN_DETECTOR2 )

  ;

  if(

    _medicionPersonaCerca

    || _pcDice == "abrir"

  ) {

    fnCambiarAEstadoAbriendo() ;

  }

}

 

 

n   

Comentarios

Entradas populares de este blog

Probando ChatGPT - Mapa conceptual con Mermaid

 Había conversado con ChatGPT acerca de cuidado de las plantas e hidroponía. Luego de unos días me di cuenta que quizás también podría saber acerca de crear Mapas conceptuales. Salió lo siguiente; le falta un concepto para crear correctamente mapas conceptuales (la relación entre los conceptos), pero podría ser algo para ayudarnos a corregir mejor. El texto original era el que cito a continuación, pero le agregué explícitamente que me armara un "mapa conceptual" utilizando el lenguaje Mermaid, un lenguaje descriptivo que permite construir gráficos diversos, entre ellos Mapas conceptuales, generando un archivo SVG. ``` Hacé un mapa conceptual en lenguaje Mermaid con el siguiente texto, redactado anteriormente: "La hidroponía es un método de cultivo que se utiliza para cultivar plantas sin suelo utilizando una solución nutriente y agua. Algunas plantas pueden cultivarse con éxito mediante hidroponía, mientras que otras necesitan el suelo para crecer y prosperar. De las pl...

Conectar a Servidor Node.JS desde VB6 o VBA

El presente código sirve tanto para Visual Basic 6.0 (sí, todavía sirve, todavía sirve!) como para Visual Basic para Aplicaciones (Excel o VBA). ' Si estamos en Visual Basic para Aplicaciones agregar la referencia ' WinHTTP, en el menú Herramientas, Referencias, Microsoft WinHTTP Services Function Solicitar( _ ByVal URLBase As String _ , Optional ByVal Puerto As Integer = 80 _ , Optional ByVal Seccion As String = "" _ , Optional ByVal Metodo As String = "GET" _ ) As String On Error GoTo solucion #If VBA6 Then Dim objXML As New WinHttpRequest #ElseIf Win32 Then Dim objXML As Object Set objXML = CreateObject("MSXML2.ServerXMLHTTP") #End If objXML.Open Metodo, URLBase & ":" & Puerto & "/" & Seccion, False objXML.send If (objXML.Status = 404) Then Solicitar = "404 Error" Else Solicitar = objXML.responseText End If Se...

Cómo implementar el Perceptrón en JavaScript (inteligencia artificial)

El presente post es acerca de cómo implementar el algoritmo de Inteligencia Artificial llamado Perceptrón (red neuronal formada por una sola neurona) en JavaScript. Está portado del Python a través del ejemplo y explicación de I am Pablo - Programando una red neuronal simple . El código acá presente no está optimizado, pero está realizado de tal manera que cualquiera que deba intentar aprenderlo lo pueda realizar (notar los nombres de las variables, constantes y funciones utilizadas). // Constructor de la clase Perceptron() var Perceptron = function Clase ( cantDatos , capacidadAprendizaje = 0.1 ) {    this.cantEntradas = cantDatos ;      this.capacidadAprendizaje = capacidadAprendizaje ;    this.pesos = [] ;    for ( var cadaDato = 0 ; cadaDato < cantDatos ; cadaDato ++ )       this.pesos.push ( Math.random () ) ; // Inicializar pesos al azar (0..1) } // Habi...