🤖 Level 4 – Mobile Robotics

Project 4.5: "PIR Motion Alarm"

 

What you’ll learn

  • Goal 1: Detect motion using a PIR sensor as a digital input pin.
  • Goal 2: Trigger visual and audible alarms with onboard LED and MIDI music blocks.
  • Goal 3: Adjust activation time (how long the alarm stays active) with simple timing.
  • Goal 4: Run continuous monitoring without freezing the loop.
  • Goal 5: Send notification messages via Bluetooth when motion is detected.

Blocks glossary

  • InOut → machine.Pin(pin, machine.Pin.IN): Configura un pin como entrada digital para leer el PIR.
  • InOut → machine.Pin(pin, machine.Pin.OUT), .value(v): Controla el LED u otros actuadores visuales.
  • external actuador → music.MIDI(pin): Crea salida de audio; midi.play(...) y midi.pitch_time(freq, ms) para alarma.
  • bluetooth → ble_peripheral.BLESimplePeripheral(name): Envía mensajes de notificación.
  • serial port → print(…): Registra eventos en el monitor serial.
  • control → while True: / if: / time.sleep_ms(ms): Estructura el bucle y los tiempos de activación.

What you need

Part How many? Pin connection (R32)
D1 R32 1 USB cable
PIR motion sensor 1 Signal → Pin 26, VCC 5V, GND
LED (onboard or external) 1 Onboard LED → Pin 13 (example)
Buzzer (audio via MIDI pin) 1 Signal → Pin 26 (example MIDI)
Bluetooth (built‑in) 1 Internal
  • Share GND between the R32 and the PIR sensor.
  • Place the PIR facing the area to monitor; avoid direct sunlight for reliability.

Before you start

  • Connect the PIR signal to Pin 26, LED to Pin 13 if external (or use onboard LED), and buzzer to the chosen MIDI pin (example 26).
  • Open the serial monitor to see printed logs.
  • Quick test:
print("Ready!")  # Confirmar que el sistema está listo en el monitor serial

Microprojects 1–5

Microproject 4.5.1 – Basic motion detection

import machine                                     # Bloque: importar librería de pines
import time                                        # Bloque: importar tiempo para pausas
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: configurar pin 26 como entrada para PIR
print("[PIR] Entrada en pin 26 lista")             # Bloque: confirmar configuración en serial
state = pir.value()                                # Bloque: leer estado actual (0 sin movimiento, 1 movimiento)
print("[PIR] Estado inicial:", state)              # Bloque: mostrar lectura inicial
time.sleep_ms(300)                                 # Bloque: pequeña pausa para estabilidad del sensor
state = pir.value()                                # Bloque: leer nuevamente para confirmar
print("[PIR] Estado tras pausa:", state)           # Bloque: mostrar segunda lectura

Reflection: Confirmaste que el PIR entrega 0/1 y que la lectura es estable con una pequeña pausa.
Challenge: Imprime “MOTION” cuando sea 1 y “CLEAR” cuando sea 0.


Microproject 4.5.2 – Visual and audible alarm

import machine                                     # Bloque: importar pines para LED
import music                                       # Bloque: importar módulo de música MIDI
import time                                        # Bloque: importar tiempo
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: PIR en pin 26 como entrada
led = machine.Pin(13, machine.Pin.OUT)             # Bloque: LED en pin 13 como salida (visual)
midi = music.MIDI(26)                              # Bloque: salida MIDI en pin 26 (audio del buzzer)
print("[Alarm] PIR=26 LED=13 MIDI=26")             # Bloque: confirmar conexiones
if pir.value() == 1:                               # Bloque: si hay movimiento
    led.value(1)                                   # Bloque: encender LED (alarma visual)
    midi.play(midi.DADADADUM)                      # Bloque: reproducir patrón musical de alarma
    print("[Alarm] Movimiento detectado!")         # Bloque: log de evento
else:                                              # Bloque: si no hay movimiento
    led.value(0)                                   # Bloque: apagar LED (sin alarma)
    print("[Alarm] Área despejada")                # Bloque: log de estado

Reflection: Conectaste la detección a una alarma visual y sonora inmediata.
Challenge: Si detección es 1, añade también un pitido corto: midi.pitch_time(880, 300).


Microproject 4.5.3 – Adjustable activation time

import machine                                     # Bloque: importar pines
import music                                       # Bloque: importar música
import time                                        # Bloque: importar tiempo
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: PIR en pin 26 (entrada)
led = machine.Pin(13, machine.Pin.OUT)             # Bloque: LED en pin 13 (salida)
midi = music.MIDI(26)                              # Bloque: MIDI en pin 26 (buzzer)
ACTIVATION_MS = 3000                               # Bloque: duración de la alarma en milisegundos
if pir.value() == 1:                               # Bloque: si hay movimiento
    led.value(1)                                   # Bloque: encender LED
    midi.pitch_time(660, 300)                      # Bloque: pitido de inicio
    print("[Alarm] Activada por", ACTIVATION_MS, "ms")  # Bloque: log de activación
    time.sleep_ms(ACTIVATION_MS)                   # Bloque: mantener alarma activa por el tiempo definido
    led.value(0)                                   # Bloque: apagar LED tras la duración
    print("[Alarm] Desactivada")                   # Bloque: log de fin de alarma
else:                                              # Bloque: si no hay movimiento
    led.value(0)                                   # Bloque: asegurar LED apagado
    print("[Alarm] Sin movimiento")                # Bloque: log de estado

Reflection: Aprendiste a controlar cuánto tiempo permanece activa la alarma después de detectar.
Challenge: Cambia ACTIVATION_MS a 1000/5000 y observa la diferencia en reacción y duración.


Microproject 4.5.4 – Continuous monitoring mode

import machine                                     # Bloque: importar pines
import time                                        # Bloque: importar tiempo
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: PIR en pin 26 entrada
led = machine.Pin(13, machine.Pin.OUT)             # Bloque: LED en pin 13 salida
print("[Monitor] Iniciando vigilancia continua")   # Bloque: log de arranque
while True:                                        # Bloque: bucle infinito
    if pir.value() == 1:                           # Bloque: si detecta movimiento
        led.value(1)                               # Bloque: encender LED
        print("[Monitor] Movimiento!")             # Bloque: log de evento
        time.sleep_ms(300)                         # Bloque: breve pausa para no saturar
    else:                                          # Bloque: si no detecta movimiento
        led.value(0)                               # Bloque: apagar LED
        time.sleep_ms(150)                         # Bloque: pausa más corta para ahorrar energía

Reflection: Mantienes una vigilancia estable sin inundar el serial ni bloquear el sistema.
Challenge: Agrega un “heartbeat” cada 2 s: imprime “[Monitor] OK” periódicamente.


Microproject 4.5.5 – Integration with notification system

import machine                                     # Bloque: importar pines
import ble_peripheral                              # Bloque: importar periférico Bluetooth
import time                                        # Bloque: importar tiempo
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: PIR en pin 26 entrada
ble_p = ble_peripheral.BLESimplePeripheral("PIR-R32")  # Bloque: crear periférico BLE con nombre
print("[Notify] BLE 'PIR-R32' listo")              # Bloque: confirmar BLE
while True:                                        # Bloque: bucle continuo
    if pir.value() == 1:                           # Bloque: si hay movimiento
        ble_p.send("EVENT:MOTION")                 # Bloque: enviar notificación al teléfono/PC
        print("[Notify] EVENT:MOTION")             # Bloque: reflejar en serial
        time.sleep_ms(500)                         # Bloque: pausa para evitar spam
    else:                                          # Bloque: si no hay movimiento
        time.sleep_ms(200)                         # Bloque: pequeña pausa de vigilancia

Reflection: Tu sistema ahora avisa por Bluetooth cuando detecta movimiento.
Challenge: Envía también “EVENT:CLEAR” tras 2 segundos sin detección.


Main project

PIR motion alarm with visual/audio alerts, adjustable timing, continuous monitoring, and Bluetooth notifications

  • Detection: PIR como entrada digital en Pin 26.
  • Alarms: LED y buzzer con bloques oficiales.
  • Timing: Activación ajustable para duración de la alarma.
  • Monitoring: Bucle continuo que no bloquea.
  • Notifications: Mensajes BLE al teléfono/PC en cada evento.
import machine                                     # Bloque: importar pines y hardware
import music                                       # Bloque: importar módulo de música MIDI
import ble_peripheral                              # Bloque: importar periférico Bluetooth
import time                                        # Bloque: importar tiempo
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: PIR en pin 26 como entrada
led = machine.Pin(13, machine.Pin.OUT)             # Bloque: LED en pin 13 como salida
midi = music.MIDI(26)                              # Bloque: salida MIDI en pin 26 (buzzer)
ble_p = ble_peripheral.BLESimplePeripheral("PIR-R32")  # Bloque: periférico BLE con nombre
print("[Main] PIR=26 LED=13 MIDI=26 BLE=PIR-R32")  # Bloque: resumen de conexiones
ACTIVATION_MS = 3000                               # Bloque: duración de alarma en ms (ajustable)
while True:                                        # Bloque: bucle principal
    if pir.value() == 1:                           # Bloque: si el PIR detecta movimiento
        led.value(1)                               # Bloque: encender LED (alarma visual)
        midi.pitch_time(880, 300)                  # Bloque: pitido corto de alarma
        ble_p.send("EVENT:MOTION")                 # Bloque: enviar notificación Bluetooth
        print("[Main] Motion! Alarm for", ACTIVATION_MS, "ms")  # Bloque: log detallado
        time.sleep_ms(ACTIVATION_MS)               # Bloque: mantener alarma durante ACTIVATION_MS
        led.value(0)                               # Bloque: apagar LED tras periodo de activación
        print("[Main] Alarm cleared")              # Bloque: log de fin de alarma
        time.sleep_ms(300)                         # Bloque: breve pausa para evitar reactivación inmediata
    else:                                          # Bloque: si no hay movimiento
        led.value(0)                               # Bloque: asegurar LED apagado
        time.sleep_ms(150)                         # Bloque: cadencia de vigilancia ligera

External explanation

Este proyecto usa solo bloques oficiales: el PIR como entrada digital, LED como salida, MIDI para sonido y BLE para notificaciones. La duración de la alarma se controla con pausas temporales, y el monitoreo continuo evita saturar el sistema. Los logs por serial explican cada estado para que el estudiante nunca se pierda.


Story time

Tu robot se convierte en un guardián amable: cuando alguien pasa, enciende su luz, emite un pitido y te avisa. Cuando todo vuelve a estar tranquilo, respira y sigue vigilando en silencio.


Debugging (2)

Debugging 4.5.A – False detections

# Usa una pequeña pausa de confirmación antes de activar la alarma
import time                                        # Bloque: importar tiempo
# Ejemplo de confirmación:
# if pir.value() == 1:
#     time.sleep_ms(200)                           # Bloque: esperar 200 ms
#     if pir.value() == 1:                         # Bloque: segunda verificación
#         # activar alarma                          # Bloque: solo si persiste
print("[Debug] Doble verificación aplicada")       # Bloque: informar en serial

Debugging 4.5.B – It does not detect movement

# Revisa alimentación y orientación del PIR
# Asegura que el pin esté correctamente configurado como entrada
import machine                                     # Bloque: importar pines
pir = machine.Pin(26, machine.Pin.IN)              # Bloque: configurar entrada
print("[Debug] PIR en 26, prueba lectura:", pir.value())  # Bloque: lectura de prueba
# Ubica el PIR sin luz directa del sol y con campo visual despejado

Final checklist

  • El PIR lee 0/1 correctamente en el pin 26.
  • La alarma visual (LED) y sonora (MIDI) se activan ante movimiento.
  • La duración de activación se ajusta con una variable en milisegundos.
  • El monitoreo continuo mantiene el sistema estable.
  • Las notificaciones BLE se envían cuando hay movimiento.

Extras

  • Student tip: Ajusta ACTIVATION_MS para diferentes escenarios (puerta vs pasillo).
  • Instructor tip: Pide a los alumnos que diseñen mensajes BLE claros (EVENT:MOTION, EVENT:CLEAR).
  • Glossary:
    • PIR: Sensor de infrarrojo pasivo que detecta cambios en movimiento/calor.
    • MIDI: Bloques de música para emitir tonos y patrones.
    • BLE: Bluetooth de baja energía para notificaciones.
  • Mini tips:
    • Evita colocar el PIR frente a ventanas soleadas.
    • Usa pausas cortas tras la alarma para evitar activaciones encadenadas.
    • Mantén los mensajes de BLE breves para que sean fáciles de leer.
On this page