.. note::

    ¡Hola! Bienvenido a la comunidad de entusiastas de SunFounder para Raspberry Pi, Arduino y ESP32 en Facebook. Únete a otros apasionados y profundiza en el uso de Raspberry Pi, Arduino y ESP32.

    **¿Por qué unirte?**

    - **Soporte de expertos**: 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 recientes.
    - **Promociones festivas y sorteos**: Participa en sorteos y promociones de temporada.

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

.. _py_pi5_alarm:

3.1.3 Alarma de Reversa
=======================

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

En este proyecto, utilizaremos una pantalla LCD, un zumbador y sensores 
ultrasónicos para crear un sistema de asistencia para reversa. Podemos 
colocarlo en un vehículo a control remoto para simular el proceso real 
de estacionar en reversa dentro de un garaje.

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

En este proyecto, necesitamos los siguientes componentes.

.. image:: ../python_pi5/img/4.1.9_reversing_alarm_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 AL COMPONENTE
..         - ENLACE DE COMPRA

..     *   - :ref:`gpio_extension_board`
..         - |link_gpio_board_buy|
..     *   - :ref:`breadboard`
..         - |link_breadboard_buy|
..     *   - :ref:`wires`
..         - |link_wires_buy|
..     *   - :ref:`resistor`
..         - |link_resistor_buy|
..     *   - :ref:`buzzer`
..         - \-
..     *   - :ref:`transistor`
..         - |link_transistor_buy|
..     *   - :ref:`ultrasonic_sensor`
..         - |link_ultrasonic_buy|
..     *   - :ref:`i2c_lcd1602`
..         - |link_i2clcd1602_buy|

Diagrama esquemático
-------------------------

El sensor ultrasónico detecta la distancia entre él y el obstáculo 
y muestra esa información en el LCD en forma de código. Al mismo tiempo, 
el sensor ultrasónico hace que el zumbador emita un sonido de advertencia 
cuya frecuencia varía según la distancia detectada.

============ ======== ======== ===
T-Board Name physical wiringPi BCM
GPIO23       Pin 16   4        23
GPIO24       Pin 18   5        24
GPIO17       Pin 11   0        17
SDA1         Pin 3             
SCL1         Pin 5             
============ ======== ======== ===

.. image:: ../python_pi5/img/4.1.9_reversing_alarm_schematic.png
   :align: center

Procedimientos experimentales
--------------------------------------

**Paso 1:** Construye el circuito.

.. image:: ../python_pi5/img/4.1.9_reversing_alarm_circuit.png
    :align: center

**Paso 2:** Cambia al directorio del código.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/davinci-kit-for-raspberry-pi/python-pi5

**Paso 3:** Ejecuta el programa.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 3.1.3_ReversingAlarm.py

Mientras el código se ejecuta, el módulo de sensor ultrasónico detecta la 
distancia al obstáculo y luego muestra la información sobre la distancia en 
el LCD1602; además, el zumbador emite un tono de advertencia cuya frecuencia 
cambia según la distancia.

.. note::

    * Si obtienes el error ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, consulta :ref:`i2c_config` para habilitar el I2C.
    * Si aparece el error ``ModuleNotFoundError: No module named 'smbus2'``, ejecuta ``sudo pip3 install smbus2``.
    * Si ves el error ``OSError: [Errno 121] Remote I/O error``, significa que el módulo está mal conectado o está dañado.
    * Si el código y las conexiones son correctos, pero la pantalla LCD aún no muestra contenido, puedes girar el potenciómetro en la parte posterior para aumentar el contraste.


.. warning::

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

**Código**

.. note::
    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes, 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
    import LCD1602
    import time
    from gpiozero import DistanceSensor, Buzzer

    # Inicializar el sensor ultrasónico con pines GPIO
    sensor = DistanceSensor(echo=24, trigger=23)  # Echo en GPIO 24, Trigger en GPIO 23

    # Inicializar el zumbador conectado al pin GPIO 17
    buzzer = Buzzer(17)

    def lcdsetup():
        # Configura la pantalla LCD con la dirección I2C y enciende la luz de fondo
        LCD1602.init(0x27, 1)  # 0x27 es la dirección I2C de la LCD
        LCD1602.clear()  # Limpia la pantalla LCD
        # Muestra mensajes de inicio en la LCD
        LCD1602.write(0, 0, 'Ultrasonic Starting')
        LCD1602.write(1, 1, 'By SunFounder')
        time.sleep(2)  # Espera 2 segundos

    def distance():
        # Calcula y devuelve la distancia medida por el sensor
        dis = sensor.distance * 100  # Convierte la distancia a centímetros
        print('Distance: {:.2f} cm'.format(dis))  # Imprime la distancia con dos decimales
        time.sleep(0.3)  # Espera 0.3 segundos antes de la siguiente medición
        return dis

    def loop():
        # Mide la distancia continuamente y actualiza la LCD y el zumbador
        while True:
            dis = distance()  # Obtiene la distancia actual
            # Muestra la distancia y maneja las alertas según la distancia
            if dis > 400:  # Verifica si la distancia está fuera de rango
                LCD1602.clear()
                LCD1602.write(0, 0, 'Error')
                LCD1602.write(3, 1, 'Out of range')
                time.sleep(0.5)
            else:
                # Muestra la distancia actual en la LCD
                LCD1602.clear()
                LCD1602.write(0, 0, 'Distance is')
                LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                # Ajusta la frecuencia del zumbador según la distancia
                if dis >= 50:
                    time.sleep(0.5)
                elif 20 < dis < 50:
                    # Distancia media: frecuencia media del zumbador
                    for _ in range(2):
                        buzzer.on()
                        time.sleep(0.05)
                        buzzer.off()
                        time.sleep(0.2)
                elif dis <= 20:
                    # Distancia cercana: alta frecuencia del zumbador
                    for _ in range(5):
                        buzzer.on()
                        time.sleep(0.05)
                        buzzer.off()
                        time.sleep(0.05)

    try:
        lcdsetup()  # Configura la pantalla LCD
        loop()      # Inicia el bucle de medición
    except KeyboardInterrupt:
        # Apaga el zumbador y limpia la LCD en caso de interrupción (e.g., Ctrl+C)
        buzzer.off()
    LCD1602.clear()



**Explicación del Código**

#. Este script utiliza varias bibliotecas para su funcionamiento. La biblioteca ``LCD1602`` gestiona la pantalla LCD, mientras que ``time`` proporciona funciones relacionadas con el tiempo. La biblioteca ``gpiozero`` es esencial para las interacciones con los pines GPIO en la Raspberry Pi, especialmente para operar el DistanceSensor y el Buzzer.

   .. code-block:: python

       #!/usr/bin/env python3
       import LCD1602
       import time
       from gpiozero import DistanceSensor, Buzzer

#. El sensor ultrasónico se configura con sus pines de eco y disparo conectados a los pines GPIO 24 y 23, respectivamente. Además, un zumbador está conectado al pin GPIO 17.

   .. code-block:: python

       # Inicializar el sensor ultrasónico con los pines GPIO
       sensor = DistanceSensor(echo=24, trigger=23)  # Echo en GPIO 24, Trigger en GPIO 23

       # Inicializar el zumbador conectado al pin GPIO 17
       buzzer = Buzzer(17)

#. La inicialización de la pantalla LCD incluye limpiarla y mostrar un mensaje de inicio.

   .. code-block:: python

       def lcdsetup():
           # Configura la pantalla LCD con la dirección I2C y enciende la luz de fondo
           LCD1602.init(0x27, 1)  # 0x27 es la dirección I2C de la LCD
           LCD1602.clear()  # Limpia la pantalla LCD
           # Muestra mensajes de inicio en la LCD
           LCD1602.write(0, 0, 'Iniciando Ultrasonico')
           LCD1602.write(1, 1, 'By SunFounder')
           time.sleep(2)  # Espera 2 segundos

#. La función ``distance`` calcula la distancia medida por el sensor ultrasónico y la muestra, devolviendo el valor en centímetros.

   .. code-block:: python

       def distance():
           # Calcula y devuelve la distancia medida por el sensor
           dis = sensor.distance * 100  # Convierte la distancia a centímetros
           print('Distance: {:.2f} cm'.format(dis))  # Imprime la distancia con dos decimales
           time.sleep(0.3)  # Espera 0.3 segundos antes de la siguiente medición
           return dis

#. El bucle principal mide continuamente la distancia, actualizando tanto la LCD como el zumbador. Maneja diferentes rangos de distancia con acciones específicas, como mostrar mensajes de error o variar las frecuencias del zumbador según la distancia medida.

   .. code-block:: python

       def loop():
           # Mide la distancia continuamente y actualiza la LCD y el zumbador
           while True:
               dis = distance()  # Obtiene la distancia actual
               # Muestra la distancia y maneja las alertas según la distancia
               if dis > 400:  # Verifica si la distancia está fuera de rango
                   LCD1602.clear()
                   LCD1602.write(0, 0, 'Error')
                   LCD1602.write(3, 1, 'Out of range')
                   time.sleep(0.5)
               else:
                   # Muestra la distancia actual en la LCD
                   LCD1602.clear()
                   LCD1602.write(0, 0, 'Distance is')
                   LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                   # Ajusta la frecuencia del zumbador según la distancia
                   if dis >= 50:
                       time.sleep(0.5)
                   elif 20 < dis < 50:
                       # Distancia media: frecuencia media del zumbador
                       for _ in range(2):
                           buzzer.on()
                           time.sleep(0.05)
                           buzzer.off()
                           time.sleep(0.2)
                   elif dis <= 20:
                       # Distancia cercana: alta frecuencia del zumbador
                       for _ in range(5):
                           buzzer.on()
                           time.sleep(0.05)
                           buzzer.off()
                           time.sleep(0.05)

#. Al ejecutarse, el script configura la LCD e ingresa al bucle principal. Puede ser interrumpido con un comando de teclado (Ctrl+C), lo que apaga el zumbador y limpia la pantalla LCD.

   .. code-block:: python

       try:
           lcdsetup()  # Configura la pantalla LCD
           loop()      # Inicia el bucle de medición
       except KeyboardInterrupt:
           # Apaga el zumbador y limpia la LCD en caso de interrupción del usuario (e.g., Ctrl+C)
           buzzer.off()
           LCD1602.clear()
