.. note::

    ¡Hola! Bienvenido a la comunidad de entusiastas de SunFounder Raspberry Pi, Arduino y ESP32 en Facebook. Profundiza en Raspberry Pi, Arduino y ESP32 junto a otros entusiastas.

    **¿Por qué unirte?**

    - **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y adelantos exclusivos.
    - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más nuevos.
    - **Promociones y sorteos festivos**: Participa en sorteos y promociones durante las festividades.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo.

.. _4.1.8_py_pi5:

4.1.5 Bienvenida
======================

Introducción
-------------------

En este proyecto, utilizaremos un sensor PIR para detectar el movimiento de los peatones 
y usaremos servos, LED y un zumbador para simular el funcionamiento de la puerta automática 
de una tienda de conveniencia. Cuando un peatón aparezca dentro del rango de detección del 
PIR, la luz indicadora se encenderá, la puerta se abrirá y el zumbador reproducirá un timbre 
de apertura.



Componentes necesarios
--------------------------

En este proyecto, necesitamos los siguientes componentes.

.. image:: ../python_pi5/img/4.1.8_welcome_list.png
    :width: 800
    :align: center

Es definitivamente conveniente comprar un kit completo, aquí tienes el enlace:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Nombre	
        - ELEMENTOS EN ESTE KIT
        - ENLACE
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

También puedes comprarlos por separado en los enlaces a continuación.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - INTRODUCCIÓN DEL COMPONENTE
        - ENLACE DE COMPRA

    *   - :ref:`cpn_gpio_extension_board`
        - |link_gpio_board_buy|
    *   - :ref:`cpn_breadboard`
        - |link_breadboard_buy|
    *   - :ref:`cpn_wires`
        - |link_wires_buy|
    *   - :ref:`cpn_resistor`
        - |link_resistor_buy|
    *   - :ref:`cpn_led`
        - |link_led_buy|
    *   - :ref:`cpn_pir`
        - \-
    *   - :ref:`cpn_servo`
        - |link_servo_buy|
    *   - :ref:`cpn_buzzer`
        - |link_passive_buzzer_buy|
    *   - :ref:`cpn_transistor`
        - |link_transistor_buy|


Diagrama Esquemático
---------------------------

==================== ====== ======== ===
Nombre de la T-Board física wiringPi BCM
GPIO18               Pin 12 1        18
GPIO17               Pin 11 0        17
GPIO27               Pin 13 2        27
GPIO22               Pin 15 3        22
==================== ====== ======== ===

.. image:: ../python_pi5/img/4.1.8_welcome_schematic.png
   :align: center

Procedimientos Experimentales
--------------------------------

**Paso 1:** Monta el circuito.

.. image:: ../python_pi5/img/4.1.8_welcome_circuit.png
    :align: center

**Paso 2:** Cambia de directorio.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Paso 3:** Ejecuta.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 4.1.8_Welcome_zero.py

Después de ejecutar el código, si el sensor PIR detecta que alguien pasa, 
la puerta se abrirá automáticamente (simulada por el servo), se encenderá 
la luz indicadora y sonará el timbre de la puerta. Una vez que el timbre 
suene, el sistema cerrará automáticamente la puerta y apagará la luz indicadora, 
esperando a que alguien pase de nuevo.

Hay dos potenciómetros en el módulo PIR: uno para ajustar la sensibilidad y otro 
para ajustar la distancia de detección. Para que el módulo PIR funcione mejor, 
debes girar ambos en sentido antihorario hasta el final.

.. image:: ../python_pi5/img/4.1.8_PIR_TTE.png
    :width: 400
    :align: center

.. warning::

    Si recibe el mensaje de error ``RuntimeError: Cannot determine SOC peripheral base address``, consulte :ref:`faq_soc`

**Código**

.. note::
    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes de eso, debes ir a la ruta del código fuente como ``raphael-kit/python-pi5``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto.

.. raw:: html

    <run></run>

.. code-block:: python

   #!/usr/bin/env python3

   from gpiozero import LED, MotionSensor, Servo, TonalBuzzer
   import time

   # Configuración de pines GPIO para LED, sensor de movimiento (PIR) y zumbador
   ledPin = LED(6)
   pirPin = MotionSensor(21)
   buzPin = TonalBuzzer(27)

   # Factor de corrección de ancho de pulso del motor servo y cálculo
   myCorrection = 0.45
   maxPW = (2.0 + myCorrection) / 1000  # Ancho de pulso máximo
   minPW = (1.0 - myCorrection) / 1000  # Ancho de pulso mínimo

   # Inicializar servo con anchos de pulso personalizados
   servoPin = Servo(25, min_pulse_width=minPW, max_pulse_width=maxPW)

   # Melodía musical para el zumbador, con notas y duraciones
   tune = [('C#4', 0.2), ('D4', 0.2), (None, 0.2),
           ('Eb4', 0.2), ('E4', 0.2), (None, 0.6),
           ('F#4', 0.2), ('G4', 0.2), (None, 0.6),
           ('Eb4', 0.2), ('E4', 0.2), (None, 0.2),
           ('F#4', 0.2), ('G4', 0.2), (None, 0.2),
           ('C4', 0.2), ('B4', 0.2), (None, 0.2),
           ('F#4', 0.2), ('G4', 0.2), (None, 0.2),
           ('B4', 0.2), ('Bb4', 0.5), (None, 0.6),
           ('A4', 0.2), ('G4', 0.2), ('E4', 0.2), 
           ('D4', 0.2), ('E4', 0.2)]

   def setAngle(angle):
       """
       Move the servo to a specified angle.
       :param angle: Angle in degrees (0-180).
       """
       value = float(angle / 180)  # Convertir ángulo a valor de servo
       servoPin.value = value      # Establecer posición del servo
       time.sleep(0.001)           # Breve pausa para el movimiento del servo

   def doorbell():
       """
       Play a musical tune using the buzzer.
       """
       for note, duration in tune:
           buzPin.play(note)       # Reproducir la nota
           time.sleep(float(duration))  # Duración de la nota
       buzPin.stop()               # Detener el zumbador después de la melodía

   def closedoor():
       # Apaga el LED y mueve el servo para cerrar la puerta
       ledPin.off()
       for i in range(180, -1, -1):
           setAngle(i)             # Mover servo de 180 a 0 grados
           time.sleep(0.001)       # Breve pausa para movimiento suave
       time.sleep(1)               # Esperar después de cerrar la puerta

   def opendoor():
       # Encender LED, abrir puerta (mover servo), reproducir melodía, cerrar puerta
       ledPin.on()
       for i in range(0, 181):
           setAngle(i)             # Mover servo de 0 a 180 grados
           time.sleep(0.001)       # Breve pausa para movimiento suave
       time.sleep(1)               # Esperar antes de reproducir la melodía
       doorbell()                  # Reproducir la melodía del timbre
       closedoor()                 # Cerrar la puerta después de la melodía

   def loop():
       # Bucle principal para verificar movimiento y operar la puerta
       while True:
           if pirPin.motion_detected:
               opendoor()               # Abrir puerta si se detecta movimiento
           time.sleep(0.1)              # Breve pausa en el bucle

   try:
       loop()
   except KeyboardInterrupt:
       # Limpiar GPIO al interrumpir el usuario (por ejemplo, Ctrl+C)
       buzPin.stop()
       ledPin.off()


**Explicación del Código**

#. El script comienza importando los módulos necesarios. La biblioteca ``gpiozero`` se utiliza para interactuar con el LED, el sensor de movimiento, el motor servo y el zumbador tonal. El módulo ``time`` se utiliza para funciones relacionadas con el tiempo.

   .. code-block:: python

       #!/usr/bin/env python3
       from gpiozero import LED, MotionSensor, Servo, TonalBuzzer
       import time

#. Inicializa el LED, el sensor de movimiento PIR y el zumbador tonal en sus respectivos pines GPIO.

   .. code-block:: python

       # Configuración de pines GPIO para LED, sensor de movimiento (PIR) y zumbador
       ledPin = LED(6)
       pirPin = MotionSensor(21)
       buzPin = TonalBuzzer(27)

#. Calcula los anchos de pulso máximos y mínimos para el motor servo, incorporando un factor de corrección para un ajuste fino.

   .. code-block:: python

       # Factor de corrección de ancho de pulso del motor servo y cálculo
       myCorrection = 0.45
       maxPW = (2.0 + myCorrection) / 1000  # Ancho de pulso máximo
       minPW = (1.0 - myCorrection) / 1000  # Ancho de pulso mínimo

#. Inicializa el motor servo en el pin GPIO 25 con los anchos de pulso personalizados para una posición precisa.

   .. code-block:: python

       # Inicializar servo con anchos de pulso personalizados
       servoPin = Servo(25, min_pulse_width=minPW, max_pulse_width=maxPW)

#. La melodía se define como una secuencia de notas (frecuencia) y duraciones (segundos).

   .. code-block:: python

       # Melodía musical para el zumbador, con notas y duraciones
       tune = [('C#4', 0.2), ('D4', 0.2), (None, 0.2),
               ('Eb4', 0.2), ('E4', 0.2), (None, 0.6),
               ('F#4', 0.2), ('G4', 0.2), (None, 0.6),
               ('Eb4', 0.2), ('E4', 0.2), (None, 0.2),
               ('F#4', 0.2), ('G4', 0.2), (None, 0.2),
               ('C4', 0.2), ('B4', 0.2), (None, 0.2),
               ('F#4', 0.2), ('G4', 0.2), (None, 0.2),
               ('B4', 0.2), ('Bb4', 0.5), (None, 0.6),
               ('A4', 0.2), ('G4', 0.2), ('E4', 0.2), 
               ('D4', 0.2), ('E4', 0.2)]

#. Función para mover el servo a un ángulo especificado. Convierte el ángulo a un valor entre 0 y 1 para el servo.

   .. code-block:: python

       def setAngle(angle):
           """
           Move the servo to a specified angle.
           :param angle: Angle in degrees (0-180).
           """
           value = float(angle / 180)  # Convertir ángulo a valor de servo
           servoPin.value = value      # Establecer posición del servo
           time.sleep(0.001)           # Breve pausa para el movimiento del servo

#. Función para reproducir una melodía musical utilizando el zumbador. Itera a través de la lista ``tune``, reproduciendo cada nota por su duración especificada.

   .. code-block:: python

       def doorbell():
           """
           Play a musical tune using the buzzer.
           """
           for note, duration in tune:
               buzPin.play(note)       # Reproducir la nota
               time.sleep(float(duration))  # Duración de la nota
           buzPin.stop()               # Detener zumbador después de la melodía

#. Funciones para abrir y cerrar la puerta utilizando el motor servo. La función ``opendoor`` enciende el LED, abre la puerta, reproduce la melodía y luego cierra la puerta.

   .. code-block:: python

       def closedoor():
           # Apaga el LED y mueve el servo para cerrar la puerta
           ledPin.off()
           for i in range(180, -1, -1):
               setAngle(i)             # Mover servo de 180 a 0 grados
               time.sleep(0.001)       # Breve pausa para movimiento suave
           time.sleep(1)               # Esperar después de cerrar la puerta

       def opendoor():
           # Encender LED, abrir puerta (mover servo), reproducir melodía, cerrar puerta
           ledPin.on()
           for i in range(0, 181):
               setAngle(i)             # Mover servo de 0 a 180 grados
               time.sleep(0.001)       # Breve pausa para movimiento suave
           time.sleep(1)               # Esperar antes de reproducir la melodía
           doorbell()                  # Reproducir la melodía del timbre
           closedoor()                 # Cerrar la puerta después de la melodía

#. Bucle principal que verifica constantemente la detección de movimiento. Cuando se detecta movimiento, se activa la función ``opendoor``.

   .. code-block:: python

       def loop():
           # Bucle principal para verificar movimiento y operar la puerta
           while True:
               if pirPin.motion_detected:
                   opendoor()               # Abrir puerta si se detecta movimiento
               time.sleep(0.1)              # Breve pausa en el bucle

#. Ejecuta el bucle principal y asegura que el script se pueda detener con un comando de teclado (Ctrl+C), apagando el zumbador y el LED para una salida limpia.

   .. code-block:: python

       try:
           loop()
       except KeyboardInterrupt:
           # Limpiar GPIO al interrumpir el usuario (por ejemplo, Ctrl+C)
           buzPin.stop()
           ledPin.off()

