Saltar al contenido
Nivel inicial

Barreras automáticas y conteo de plazas

Montar el servomotor de la barrera en la protoboard

El sistema arranca por la barrera. Vamos a controlar su movimiento con un servomotor: cuando llegue un auto a la entrada, la barrera se levantará con un giro del servo a un ángulo de 90° y luego volverá a bajar a .

Servomotor SG-5010 de color negro con su brazo blanco encastrado en el eje y los tres cables de conexión (marrón, rojo y naranja) saliendo del cuerpo.
El servomotor SG-5010 que mueve la barrera (figura original del proyecto): el brazo encastrado en el eje hace de barrera; los tres cables son alimentación (VCC, GND) y señal.

El servo tiene tres cables: VCC (alimentación, cable rojo o marrón), GND (masa, cable negro o marrón) y señal (cable naranja o amarillo), que es el que se conecta a una salida digital de la placa y le indica el ángulo. Empezamos conectando un servo (la barrera de entrada); en el paso 4 sumamos el segundo, para la salida.

En el Arduino UNO, el cable de señal del servo de entrada va al pin 4 (la constante PIN_SERVO_ENTRADA del código), VCC a 5V y GND a GND.

Ojo con un error del material original: el esquema de 2019 conectaba los servos a los pines 0 y 1. Esos dos pines son los que el UNO usa para comunicarse con la computadora por USB (RX y TX): si se los ocupa con los servos, no se puede cargar el programa ni usar el Monitor Serie, y el servo se mueve de forma errática mientras la placa se comunica. Por eso en esta reedición los servos van a pines libres: la barrera de entrada al 4 y la de salida al 8.

En el ESP32, el cable de señal del servo de entrada va al GPIO 25 (la constante PIN_SERVO_ENTRADA del código). La alimentación del servo conviene tomarla de una fuente de 5 V aparte (los servos consumen más de lo que el ESP32 entrega con comodidad) y unir siempre el GND de esa fuente con el GND del ESP32. Para el ESP32 se usa la librería ESP32Servo, que reemplaza a la Servo.h clásica del UNO.

Programar el movimiento de la barrera

La programación la haremos directamente en el lenguaje de Arduino (C++), con el Arduino IDE en su versión 2.x, que se descarga gratis desde arduino.cc/en/software. Un programa de Arduino se llama sketch y tiene dos bloques: setup(), que se ejecuta una sola vez al encender, y loop(), que se ejecuta repetidamente después. Todo lo que sigue a // es un comentario: no afecta al programa, sirve para que el código sea más fácil de leer.

Para mover el servo alcanza con indicarle el ángulo: en el código, una instrucción lleva la barrera a 90 (levantada) y otra a 0 (baja). Como primera prueba conviene hacer la secuencia completa —subir la barrera, esperar dos segundos, bajarla, esperar dos segundos— y ver el brazo moverse. En este primer nivel usamos delay() para las esperas: es lo más simple y hace que el código se lea igual que su comportamiento (en el nivel avanzado lo cambiaremos, porque el IoT lo exige).

Accionar la barrera con el pulsador de entrada

Ahora sumamos el pulsador de entrada, para que la barrera se accione sola cuando llega un auto. Más adelante lo colocaremos debajo de una plataforma en la entrada: el auto la pisa, el pulsador se presiona y la barrera se levanta.

Un pulsador es un interruptor que normalmente está abierto y, mientras se lo mantiene presionado, cierra el circuito. En esta reedición lo conectamos directo entre el pin y GND, aprovechando la resistencia interna de pull-up del microcontrolador (INPUT_PULLUP): así el pin lee un valor estable en reposo y otro al presionarse, sin necesidad de la resistencia externa de 10 kΩ que usaba el esquema original.

La lógica que programamos es: cuando se presiona el pulsador de entrada, la barrera se abre (servo a 90°); mientras el auto sigue sobre la plataforma esperamos, y una vez que pasó, esperamos tres segundos y bajamos la barrera (servo a 0°).

En el Arduino UNO, el pulsador de entrada va al pin 2 (la constante PIN_PULSADOR_ENTRADA).

En el ESP32, el pulsador de entrada va al GPIO 32 (la constante PIN_PULSADOR_ENTRADA).

Contar los autos: barrera de salida y variable de lugares

Con una sola barrera no alcanza para llevar la cuenta. Sumamos la barrera de salida con su propio servo y su propio pulsador, iguales a los de la entrada, y una variable que guarde cuántos lugares quedan libres.

Consideramos que el estacionamiento tiene 8 plazas. La variable lugares arranca en 8. Cada vez que un auto entra, hay un lugar menos: el programa resta 1. Cada vez que un auto sale, hay un lugar más: suma 1. Así, en todo momento, lugares refleja los espacios disponibles.

En el Arduino UNO, la barrera de salida usa el servo en el pin 8 (PIN_SERVO_SALIDA) y el pulsador de salida en el pin 3 (PIN_PULSADOR_SALIDA).

En el ESP32, la barrera de salida usa el servo en el GPIO 26 (PIN_SERVO_SALIDA) y el pulsador de salida en el GPIO 33 (PIN_PULSADOR_SALIDA).

Indicar la ocupación con dos LED e impedir el ingreso si está lleno

Falta que el sistema avise si hay lugar. Agregamos dos LED: uno verde que se enciende cuando hay al menos una plaza libre y uno rojo que se enciende cuando están todas ocupadas. Cada LED tiene polaridad —la pata larga es la positiva y va al pin de la placa— y una resistencia de 220 Ω en serie que limita la corriente.

Esquema de conexión del nivel inicial: placa Arduino UNO con un LED verde (HAY LUGAR) al pin 9 y un LED rojo (NO HAY LUGAR) al pin 8, dos pulsadores (ENTRADA y SALIDA) y dos servomotores (ENTRADA y SALIDA) cuyos cables de señal llegan a la placa; la alimentación se reparte por las líneas de la protoboard.
Circuito completo del nivel inicial (figura original del proyecto): dos servos para las barreras, dos pulsadores y los LED verde (hay lugar) y rojo (completo). En esta reedición los servos NO van a los pines 0 y 1 como muestra el original, sino a pines libres (4 y 8).

En el Arduino UNO, el LED verde («hay lugar») va al pin 9 (PIN_LED_VERDE) y el rojo («completo») al pin 13 (PIN_LED_ROJO). Como el pin 8 ya lo usa el servo de salida, el LED rojo se lleva a un pin de salida libre. Recordá que los pines se reasignan según lo que ya tengas ocupado; lo que manda son las constantes del código, no un número fijo.

En el ESP32, el LED verde va al GPIO 27 (PIN_LED_VERDE) y el rojo al GPIO 14 (PIN_LED_ROJO), dos GPIO de salida libres.

La última pieza de la lógica es impedir el ingreso cuando no hay lugar: para abrir la barrera de entrada no alcanza con que el pulsador esté presionado, también tiene que haber al menos una plaza disponible (lugares mayor que 0). La barrera de salida, en cambio, siempre puede abrirse.

Este es el programa completo del nivel inicial: las dos barreras, el conteo con lugares y los dos LED.

Ver el código completo · barrera-pulsadores.ino
barrera-pulsadores.ino Arduino UNO
// Estacionamiento automatizado — Nivel Inicial (Arduino UNO).
//
// Maqueta a escala de un estacionamiento de 8 plazas con DOS barreras:
//   - Barrera de ENTRADA: un pulsador la abre (servo a 90) SOLO si quedan
//     lugares; al pasar el auto, se cierra y se resta un lugar.
//   - Barrera de SALIDA: un pulsador la abre; al salir el auto, se cierra y
//     se suma un lugar.
// Dos LED indican de un vistazo la ocupacion, como pide la situacion-problema
// de Juana:  VERDE = hay lugar,  ROJO = estacionamiento completo.
//
// Plataforma: Arduino UNO. Proyecto de BAJA TENSION (servos 5 V, LED,
// pulsadores): no hay 220 V ni agua, no lleva advertencias electricas.
//
// Nivel inicial: se permite delay() (fiel a la progresion del original).
//
// Basado en: Fragmentos de codigo del Nivel Inicial (Pasos 2, 4 y 5) —
// Estacionamiento Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// CORRECCION DE BUG CRITICO (ver README):
//   El original ataba servoEntrada al pin 0 y servoSalida al pin 1. Los pines
//   0 y 1 del UNO son el RX/TX del USB/serial de programacion: usarlos para
//   los servos ROMPE la carga del sketch y el Monitor Serie. Se remapean a
//   los pines 4 (entrada) y 8 (salida), que estan libres.

#if defined(ESP32)
  #include <ESP32Servo.h>
#else
  #include <Servo.h>
#endif

// --- Capacidad del estacionamiento ---
const int CAPACIDAD = 8;

// --- Pines de las barreras (servos) — REMAPEADOS (bug del original) ---
const int PIN_SERVO_ENTRADA = 4;  // original: pin 0 (RX) = BUG, rompe el USB
const int PIN_SERVO_SALIDA  = 8;  // original: pin 1 (TX) = BUG, rompe el USB

// --- Pines de los pulsadores ---
// El original usa resistencias de 10K como PULLDOWN (estan en los insumos):
// el pulsador lee HIGH cuando se presiona y LOW en reposo.
const int PIN_PULSADOR_ENTRADA = 2;
const int PIN_PULSADOR_SALIDA  = 3;

// --- Pines de los LED de estado ---
// Estos dos LED existen SOLO en el nivel inicial. En el nivel intermedio se
// reemplazan por el display de 7 segmentos (que reutiliza estos pines).
const int PIN_LED_VERDE = 9;   // encendido = hay lugares disponibles
const int PIN_LED_ROJO  = 13;  // encendido = estacionamiento completo

// --- Angulos de la barrera ---
const int ANGULO_ABIERTA = 90;
const int ANGULO_CERRADA = 0;

// Tiempo (ms) que se espera, tras liberar el pulsador, a que el auto termine
// de cruzar antes de bajar la barrera.
const unsigned long TIEMPO_PASO_MS = 3000;

// Lugares disponibles. Arranca vacio: 8 lugares libres.
int lugares = CAPACIDAD;

Servo servoEntrada;
Servo servoSalida;

void setup() {
  pinMode(PIN_PULSADOR_ENTRADA, INPUT);
  pinMode(PIN_PULSADOR_SALIDA, INPUT);
  pinMode(PIN_LED_VERDE, OUTPUT);
  pinMode(PIN_LED_ROJO, OUTPUT);

  servoEntrada.attach(PIN_SERVO_ENTRADA);
  servoSalida.attach(PIN_SERVO_SALIDA);
  // Ambas barreras arrancan bajas (cerradas).
  servoEntrada.write(ANGULO_CERRADA);
  servoSalida.write(ANGULO_CERRADA);
}

void loop() {
  // --- ENTRADA: solo se abre si hay al menos un lugar libre ---
  if (digitalRead(PIN_PULSADOR_ENTRADA) == HIGH && lugares >= 1) {
    servoEntrada.write(ANGULO_ABIERTA);
    // Mientras el auto sigue sobre el pulsador, esperamos.
    while (digitalRead(PIN_PULSADOR_ENTRADA) == HIGH) {
    }
    delay(TIEMPO_PASO_MS);
    servoEntrada.write(ANGULO_CERRADA);
    lugares = lugares - 1;  // entro un auto: un lugar menos
  }

  // --- SALIDA: solo tiene sentido si hay algun auto adentro (lugares < 8) ---
  // El guard (lugares < CAPACIDAD) evita que el contador supere la capacidad.
  if (digitalRead(PIN_PULSADOR_SALIDA) == HIGH && lugares < CAPACIDAD) {
    servoSalida.write(ANGULO_ABIERTA);
    while (digitalRead(PIN_PULSADOR_SALIDA) == HIGH) {
    }
    delay(TIEMPO_PASO_MS);
    servoSalida.write(ANGULO_CERRADA);
    lugares = lugares + 1;  // salio un auto: un lugar mas
  }

  // --- LED de estado ---
  if (lugares > 0) {
    digitalWrite(PIN_LED_VERDE, HIGH);
    digitalWrite(PIN_LED_ROJO, LOW);
  } else {
    digitalWrite(PIN_LED_VERDE, LOW);
    digitalWrite(PIN_LED_ROJO, HIGH);
  }
}
barrera-pulsadores.ino ESP32
// Estacionamiento automatizado — Nivel Inicial (ESP32 DevKit v1).
//
// Maqueta a escala de un estacionamiento de 8 plazas con DOS barreras:
//   - Barrera de ENTRADA: un pulsador la abre (servo a 90) SOLO si quedan
//     lugares; al pasar el auto, se cierra y se resta un lugar.
//   - Barrera de SALIDA: un pulsador la abre; al salir el auto, se cierra y
//     se suma un lugar.
// Dos LED indican la ocupacion:  VERDE = hay lugar,  ROJO = completo.
//
// Plataforma: ESP32 (DevKit v1). Servo con la libreria ESP32Servo (la Servo.h
// clasica no funciona en ESP32). Proyecto de BAJA TENSION: sin 220 V ni agua.
// Nota electrica: el ESP32 trabaja a 3,3 V; los servos se alimentan desde 5 V
// con GND comun con la placa.
//
// Nivel inicial: se permite delay() (fiel a la progresion del original).
//
// Basado en: Fragmentos de codigo del Nivel Inicial (Pasos 2, 4 y 5) —
// Estacionamiento Automatizado, Saberes Digitales (INET/EDUCAR 2019).
// Los servos van a GPIO seguros del contrato (25/26); no aplica el bug de los
// pines 0/1 del UNO, pero la eleccion de GPIO evita strapping pins.

#if defined(ESP32)
  #include <ESP32Servo.h>
#else
  #include <Servo.h>
#endif

// --- Capacidad del estacionamiento ---
const int CAPACIDAD = 8;

// --- Pines de las barreras (servos) — GPIO del contrato ---
const int PIN_SERVO_ENTRADA = 25;
const int PIN_SERVO_SALIDA  = 26;

// --- Pines de los pulsadores (con resistencia de 10K como pulldown) ---
const int PIN_PULSADOR_ENTRADA = 32;
const int PIN_PULSADOR_SALIDA  = 33;

// --- Pines de los LED de estado (solo en el nivel inicial) ---
// GPIO libres y seguros; en intermedio el display reemplaza a los LED.
const int PIN_LED_VERDE = 27;  // encendido = hay lugares disponibles
const int PIN_LED_ROJO  = 14;  // encendido = estacionamiento completo

// --- Angulos de la barrera ---
const int ANGULO_ABIERTA = 90;
const int ANGULO_CERRADA = 0;

// Espera (ms) a que el auto cruce antes de bajar la barrera.
const unsigned long TIEMPO_PASO_MS = 3000;

// Lugares disponibles. Arranca vacio: 8 lugares libres.
int lugares = CAPACIDAD;

Servo servoEntrada;
Servo servoSalida;

void setup() {
  pinMode(PIN_PULSADOR_ENTRADA, INPUT);
  pinMode(PIN_PULSADOR_SALIDA, INPUT);
  pinMode(PIN_LED_VERDE, OUTPUT);
  pinMode(PIN_LED_ROJO, OUTPUT);

  servoEntrada.attach(PIN_SERVO_ENTRADA);
  servoSalida.attach(PIN_SERVO_SALIDA);
  servoEntrada.write(ANGULO_CERRADA);
  servoSalida.write(ANGULO_CERRADA);
}

void loop() {
  // --- ENTRADA: solo se abre si hay al menos un lugar libre ---
  if (digitalRead(PIN_PULSADOR_ENTRADA) == HIGH && lugares >= 1) {
    servoEntrada.write(ANGULO_ABIERTA);
    while (digitalRead(PIN_PULSADOR_ENTRADA) == HIGH) {
    }
    delay(TIEMPO_PASO_MS);
    servoEntrada.write(ANGULO_CERRADA);
    lugares = lugares - 1;
  }

  // --- SALIDA: guard (lugares < CAPACIDAD) evita superar la capacidad ---
  if (digitalRead(PIN_PULSADOR_SALIDA) == HIGH && lugares < CAPACIDAD) {
    servoSalida.write(ANGULO_ABIERTA);
    while (digitalRead(PIN_PULSADOR_SALIDA) == HIGH) {
    }
    delay(TIEMPO_PASO_MS);
    servoSalida.write(ANGULO_CERRADA);
    lugares = lugares + 1;
  }

  // --- LED de estado ---
  if (lugares > 0) {
    digitalWrite(PIN_LED_VERDE, HIGH);
    digitalWrite(PIN_LED_ROJO, LOW);
  } else {
    digitalWrite(PIN_LED_VERDE, LOW);
    digitalWrite(PIN_LED_ROJO, HIGH);
  }
}
Estacionamiento del nivel inicial: los pulsadores de entrada y salida mueven las barreras y actualizan la variable lugares (arranca en 8); el LED verde indica que hay lugar y el rojo que está completo. La barrera de entrada solo se abre si quedan plazas.

Podés ver el comportamiento —los autos entrando y saliendo, el conteo y los LED cambiando— en el simulador, antes de armar el circuito real:

Simulación del comportamiento

La misma máquina de estados del firmware, portada a TypeScript, maneja el comportamiento del dispositivo. No se ejecuta el binario real: la ejecución del .hex con avr8js está en el roadmap.

Simulación lista. Presioná «Iniciar» para arrancar la secuencia.

Para subir el código a la placa, conectala a la computadora con el cable USB, elegí en el Arduino IDE 2.x la placa y el puerto (en el IDE 2.x se eligen juntos en el menú desplegable de la barra superior) y apretá el botón Subir (la flecha →). Al terminar, aparece el mensaje de carga completada en la barra inferior.

Para el Arduino UNO: usá el cable USB tipo B, elegí la placa Arduino UNO y el puerto que se agregó al conectarla (en Windows es un puerto COM numerado; en Linux suele llamarse /dev/ttyACM0 o similar). Como ahora los servos están en los pines 4 y 8 (y no en el 0/1), la carga funciona sin desconectar nada.

Para el ESP32 hay dos pasos previos que se hacen una sola vez: instalar el soporte de placas ESP32 desde el gestor de placas del IDE (buscá “esp32” e instalá el paquete de Espressif) y la librería ESP32Servo desde el gestor de bibliotecas. Después elegí la placa ESP32 Dev Module y el puerto correspondiente. Si al subir el IDE queda esperando en “Connecting…”, mantené apretado el botón BOOT de la placa hasta que empiece la carga.

Armar la maqueta del estacionamiento

Con el circuito probado sobre la protoboard, podemos pasar a la maqueta. Una vez que las conexiones funcionan, se puede prescindir de la protoboard soldando cada componente con un cable a la placa y ubicando cada pieza en su lugar dentro de la maqueta.

Para diseñar la planta del estacionamiento con los estudiantes hay que tener en cuenta la ubicación de los dos servomotores con sus barreras (entrada y salida, en calles distintas), la de los dos pulsadores bajo sus plataformas basculantes, la de los LED y la distribución de las 8 plazas.

Esta parte es de fabricación. Los brazos de las barreras y los soportes de los servos (piezas impresas en 3D) y la planta del estacionamiento (corte láser en MDF 3 mm) forman parte de los paquetes de fabricación del proyecto, que se descargan desde su ficha. Mientras tanto, la maqueta puede construirse con materiales simples: una base de cartón o madera con las plazas dibujadas, palitos o cartulina para las barreras encastradas en el brazo del servo y pequeñas plataformas de cartón sobre cada pulsador.

Cierre del nivel

Al terminar este nivel, el estacionamiento de Juana ya se gestiona solo: las barreras se levantan al llegar un auto, el sistema lleva la cuenta de las plazas con la variable lugares y los LED avisan si hay lugar o si está completo, bloqueando la entrada cuando no quedan espacios. Además, corregiste el error del original que conectaba los servos a los pines del USB. Pero los LED solo dicen “hay / no hay” lugar: no cuántos. En el nivel intermedio vamos a agregar un display de 7 segmentos para ver en pantalla el número exacto de plazas libres.

Evidencia de cierre

Al terminar este nivel, esto tiene que estar funcionando:

  • El circuito está montado en la protoboard: dos servomotores (barreras de entrada y de salida), dos pulsadores y los LED verde y rojo, con los servos conectados a pines libres (no a los pines 0 y 1 del USB).
  • Sabés subir un programa desde el Arduino IDE 2.x: elegir la placa, elegir el puerto y verificar que quedó cargado.
  • Al presionar el pulsador de entrada la barrera se levanta (servo a 90°), espera y vuelve a bajar (0°), y el programa descuenta un lugar; el pulsador de salida hace lo inverso y suma un lugar.
  • El LED verde queda encendido mientras hay plazas libres y el rojo cuando el estacionamiento está completo; con el estacionamiento lleno, la barrera de entrada no se abre.
  • La maqueta del estacionamiento está armada con sus 8 plazas, las dos barreras, los pulsadores y los LED.