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...