PROYECTO #07

Sistema de Acceso
con Servo

Avanzado
⏱ 75 minutos

Una barrera automatizada que se abre con un pulsador y se cierra de emergencia si el sensor de choque detecta un impacto. Aprende maquinas de estados y control de servo.

Servo SG90
Pulsador
Sensor Choque
Pantalla OLED
Maquina de estados

Materiales

Estos son los componentes necesarios para este proyecto. Haz clic en cada uno para ir a su guia completa.

Servo SG90
x1 unidad
Pulsador
x1 unidad
Sensor de Choque
x1 unidad (microswitch)
Pantalla OLED
x1 unidad (128x64)
🔭
micro:bit v2
x1 + placa expansion
Cables macho-macho
x8 aprox.

Conexion

Conecta cada componente a la placa de expansion del micro:bit siguiendo esta tabla. Usa colores de cable diferentes para no confundirte.

Pin Componente Cable sugerido
P0
Pulsador — Signal
Entrada digital
Azul
P1
Servo SG90 — Signal (PWM)
Salida PWM — cable naranja del servo
Naranja
P2
Sensor Choque — Signal
Entrada digital microswitch
Rojo
P19 (SCL)
OLED — CLK
Bus I2C — reloj
Blanco
P20 (SDA)
OLED — DA
Bus I2C — datos
Morado
V / G
Todos los componentes
Alimentacion 3.3V — masa
/
CERRADO
inicio / espera
ABRIENDO
servo 0°→90°
ABIERTO
espera 5s
CERRANDO
servo 90°→0°
⚡ Desde cualquier estado: EMERGENCIA → servo a 0° → CERRADO
EMERGENCIA
1
Conecta el Pulsador a P0
Signal (azul) a P0, V (rojo) a 3.3V, G (negro) a GND. El pulsador es la entrada principal para abrir la barrera.
2
Conecta el Servo SG90 a P1
El servo tiene 3 cables: naranja (signal) a P1, rojo (V) al rail de 5V o 3.3V, marron/negro (G) a GND. IMPORTANTE: el servo necesita entre 4.5V y 5V para funcionar bien — usa la alimentacion de la placa, no los 3.3V del micro:bit directamente.
3
Conecta el Sensor de Choque a P2
Signal a P2, V a 3.3V, G a GND. Asegurate de que el sensor esta en posicion NO (Normalmente Abierto). Con el microswitch en reposo, P2 lee 0. Cuando hay impacto, lee 1.
4
Conecta la Pantalla OLED (I2C)
CLK al pin P19 (SCL), DA al pin P20 (SDA), V a 3.3V, G a GND. La OLED usa el bus I2C compartido — no requiere pines de datos adicionales.
5
Verifica antes de encender
Comprueba que ningun cable toca un pin incorrecto. El servo en posicion incorrecta puede sobrecargar el micro:bit. Verifica la posicion inicial de la barrera: el servo deberia apuntar hacia abajo (0° = barrera cerrada).

Programacion

Codigo completo con comentarios detallados. Elige tu entorno y copia el codigo en tu editor. Recuerda instalar la extension OLED en MakeCode antes de programar.

JavaScript — MakeCode
// Sistema de acceso con servo y máquina de estados
// Estados: CERRADO, ABRIENDO, ABIERTO, CERRANDO, EMERGENCIA

// Constantes de estado
let CERRADO = 0
let ABRIENDO = 1
let ABIERTO = 2
let CERRANDO = 3
let EMERGENCIA = 4

let estado = CERRADO
let tiempoAbierto = 5000  // ms que permanece abierto

// Inicializar
OLED.init(128, 64)
pins.servoWritePin(AnalogPin.P1, 0)  // Barrera cerrada

function actualizarOLED() {
    OLED.clear()
    OLED.writeString("=== ACCESO ===")
    if (estado == CERRADO) {
        OLED.writeString("ESTADO: Cerrado")
        OLED.writeString("Pulsa A para abrir")
    } else if (estado == ABRIENDO) {
        OLED.writeString("ESTADO: Abriendo...")
    } else if (estado == ABIERTO) {
        OLED.writeString("ESTADO: ABIERTO")
        OLED.writeString("Cierra en 5s")
    } else if (estado == CERRANDO) {
        OLED.writeString("ESTADO: Cerrando...")
    } else if (estado == EMERGENCIA) {
        OLED.writeString("!!! EMERGENCIA !!!")
        OLED.writeString("Impacto detectado")
    }
}

basic.forever(function () {
    // Leer sensores
    let botonPulsado = pins.digitalReadPin(DigitalPin.P0)
    let choquePulsado = pins.digitalReadPin(DigitalPin.P2)

    // Detectar emergencia desde cualquier estado
    if (choquePulsado == 1 && estado != EMERGENCIA) {
        estado = EMERGENCIA
        pins.servoWritePin(AnalogPin.P1, 0)  // Cerrar inmediatamente
        actualizarOLED()
        basic.pause(3000)
        estado = CERRADO
    }

    // Máquina de estados
    if (estado == CERRADO) {
        actualizarOLED()
        if (botonPulsado == 1) {
            estado = ABRIENDO
        }
    } else if (estado == ABRIENDO) {
        actualizarOLED()
        pins.servoWritePin(AnalogPin.P1, 90)  // Abrir barrera
        basic.pause(500)
        estado = ABIERTO
    } else if (estado == ABIERTO) {
        actualizarOLED()
        basic.pause(tiempoAbierto)  // Permanecer abierto
        estado = CERRANDO
    } else if (estado == CERRANDO) {
        actualizarOLED()
        pins.servoWritePin(AnalogPin.P1, 0)  // Cerrar barrera
        basic.pause(500)
        estado = CERRADO
    }

    basic.pause(100)
})
MicroPython
from microbit import *
import ssd1306

oled = ssd1306.SSD1306_I2C(128, 64, i2c)

# Estados
CERRADO = 0
ABRIENDO = 1
ABIERTO = 2
CERRANDO = 3
EMERGENCIA = 4

estado = CERRADO
TIEMPO_ABIERTO = 5000  # ms

def mover_servo(angulo):
    # Convertir ángulo (0-180) a PWM (0-1023)
    # 0° = 26, 90° = 77, 180° = 128 (aproximado)
    pwm = int(26 + (angulo / 180) * 102)
    pin1.write_analog(pwm)

def actualizar_oled():
    oled.fill(0)
    oled.text("=== ACCESO ===", 0, 0)
    if estado == CERRADO:
        oled.text("Cerrado", 0, 20)
        oled.text("Pulsa boton", 0, 36)
    elif estado == ABRIENDO:
        oled.text("Abriendo...", 0, 20)
    elif estado == ABIERTO:
        oled.text("ABIERTO", 0, 20)
        oled.text("Cierra en 5s", 0, 36)
    elif estado == CERRANDO:
        oled.text("Cerrando...", 0, 20)
    elif estado == EMERGENCIA:
        oled.text("!EMERGENCIA!", 0, 20)
        oled.text("Impacto!", 0, 36)
    oled.show()

# Posición inicial: cerrado
mover_servo(0)

while True:
    boton = pin0.read_digital()
    choque = pin2.read_digital()

    # Emergencia
    if choque == 1 and estado != EMERGENCIA:
        estado = EMERGENCIA
        mover_servo(0)
        actualizar_oled()
        sleep(3000)
        estado = CERRADO

    # Máquina de estados
    if estado == CERRADO:
        actualizar_oled()
        if boton == 1:
            estado = ABRIENDO
    elif estado == ABRIENDO:
        actualizar_oled()
        mover_servo(90)
        sleep(500)
        estado = ABIERTO
    elif estado == ABIERTO:
        actualizar_oled()
        sleep(TIEMPO_ABIERTO)
        estado = CERRANDO
    elif estado == CERRANDO:
        actualizar_oled()
        mover_servo(0)
        sleep(500)
        estado = CERRADO

    sleep(100)
Concepto clave — Maquina de estados

En lugar de un montón de if anidados, usamos una variable de estado que solo puede tener un valor a la vez. Cada ciclo del loop comprueba en que estado estamos y que hacer. La emergencia tiene prioridad absoluta — se comprueba ANTES de la maquina de estados. Esto hace el codigo predecible y facil de ampliar.


Pruebalo

Comprueba cada punto para confirmar que el sistema funciona correctamente. Si algo falla, revisa la seccion de problemas.

Al encender: la pantalla OLED muestra "ESTADO: Cerrado" y el servo esta en 0° (barrera hacia abajo).
Al pulsar el pulsador: la pantalla cambia a "ESTADO: Abriendo..." y el servo gira hasta 90° (barrera levantada).
Estado ABIERTO: la pantalla muestra "ESTADO: ABIERTO / Cierra en 5s" durante 5 segundos.
Cierre automatico: pasados 5 segundos, el servo vuelve a 0° solo y la pantalla muestra "Cerrado".
Emergencia: al presionar el sensor de choque en cualquier momento, el servo va a 0° y la pantalla muestra "!!! EMERGENCIA !!! / Impacto detectado" durante 3 segundos. Luego vuelve a CERRADO.
Emergencia durante ABIERTO: si el sensor de choque se activa mientras la barrera esta abierta, cierra inmediatamente sin esperar los 5 segundos.

Actividades

Cuatro retos progresivos para ampliar el proyecto. No hay solucion unica — experimenta y prueba tus ideas.

🎯
Reto 1 — Modificar
Cambia el tiempo de apertura
Modifica tiempoAbierto a 10000 (10 segundos) y observa el comportamiento. Luego prueba con 2000 (2 segundos). ¿Que valor te parece mas realista para una barrera de parking?
🎯
Reto 2 — Ampliar
Boton de cierre manual
Añade un segundo pulsador en P3 que funcione como "boton de cierre de emergencia". Cuando se pulsa en el estado ABIERTO, cierra la barrera inmediatamente sin esperar los 5 segundos. Pista: añade la lectura de P3 dentro del bloque estado == ABIERTO.
🎯
Reto 3 — Avanzado
Contrasena de 3 pulsaciones
La barrera solo se abre si se pulsa el boton A del micro:bit 3 veces seguidas en menos de 2 segundos. Necesitaras un contador de pulsaciones, un timestamp y resetear el contador si pasa demasiado tiempo entre pulsaciones.
🎯
Reto 4 — Indicadores
LEDs de estado
Añade un LED rojo (P4) que parpadee durante la emergencia a 5Hz (100ms on, 100ms off) y un LED verde (P5) que permanezca encendido solo cuando la barrera esta en estado ABIERTO. Ambos apagados en cualquier otro estado.

Problemas comunes

Si algo no funciona como esperas, revisa estos casos. La mayoria de los problemas tienen una causa sencilla.

"El servo hace ruido pero no se mueve bien o tiembla constantemente"
El servo SG90 necesita entre 4.5V y 5V para funcionar correctamente. Si lo conectas directamente a 3.3V del micro:bit, puede vibrar o no llegar a los extremos de posicion. Asegurate de conectar el cable rojo del servo a la alimentacion de la placa de expansion (rail de 5V), no a los pines V del micro:bit.
"La maquina de estados se queda 'colgada' en ABRIENDO o ABIERTO"
Cada bloque de estado debe terminar asignando el siguiente estado. Si el codigo se queda en ABRIENDO para siempre, revisa que tienes estado = ABIERTO al final del bloque de ABRIENDO. Sin esa linea, el estado nunca cambia y el loop repite el mismo bloque infinitamente.
"El sensor de choque dispara la emergencia solo, sin tocar nada"
El microswitch puede estar conectado en posicion NC (Normalmente Cerrado) en vez de NO (Normalmente Abierto). En ese caso, el pin lee 1 en reposo y 0 cuando se pulsa — al reves de lo esperado. Prueba a cambiar choque == 1 por choque == 0 en la condicion de emergencia.
"La pantalla OLED no se actualiza o parece congelada con textos superpuestos"
Es imprescindible llamar a OLED.clear() (MakeCode) o oled.fill(0) (MicroPython) ANTES de escribir nuevo texto. Sin limpiar la pantalla, los caracteres se superponen y es imposible leer. En MakeCode, usa OLED.clear() como primera linea de la funcion actualizarOLED.

Mas alla

Ideas para convertir este proyecto en algo mas complejo. Son punto de partida — investiga como implementarlas.

🔒
Contrasena numerica
Usa los botones A y B del micro:bit para introducir una combinacion secreta (ej. A, A, B) antes de que la barrera se abra.
👥
Contador de accesos
Lleva la cuenta de cuantas veces se ha abierto la barrera en la OLED. Resetea con el boton B del micro:bit.
Control horario
Usa el sensor de luz para detectar si es "de noche" y bloquear la apertura — la barrera solo se abre de dia.
🔔
Alarma de emergencia
Conecta un buzzer pasivo a P4 y haz que suene una melodia de alarma durante el estado de emergencia.