.. note::

    ¡Hola, bienvenido a la comunidad de entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook! Sumérgete más en Raspberry Pi, Arduino y ESP32 con otros entusiastas.

    **¿Por qué unirte?**

    - **Soporte Experto**: Resuelve problemas post-venta y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y Comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Preestrenos Exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y avances.
    - **Descuentos Especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones y Sorteos Festivos**: Participa en sorteos y promociones de temporada.

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

.. _4.1.9_py_pi5:

4.1.6 Alarma de Reversa
======================================

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

En este proyecto, usaremos una pantalla LCD, un zumbador y sensores ultrasónicos 
para crear un sistema de asistencia de reversa. Podemos colocarlo en un vehículo 
controlado a distancia para simular el proceso real de reversa de un automóvil en el 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í está el enlace: 

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

    *   - Nombre	
        - ARTÍCULOS EN ESTE KIT
        - ENLACE
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

También puedes comprarlos por separado desde 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_buzzer`
        - \-
    *   - :ref:`cpn_transistor`
        - |link_transistor_buy|
    *   - :ref:`cpn_ultrasonic_sensor`
        - |link_ultrasonic_buy|
    *   - :ref:`cpn_i2c_lcd`
        - |link_i2clcd1602_buy|

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

El sensor ultrasónico detecta la distancia entre él y el obstáculo, la cual se 
mostrará en la pantalla LCD en forma de código. Al mismo tiempo, el sensor ultrasónico 
hace que el zumbador emita un sonido de advertencia de diferente frecuencia según el 
valor de la distancia.

============== ====== ======== ===
Nombre T-Board física 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 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.9_ReversingAlarm_zero.py

A medida que se ejecuta el código, el módulo del 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 
con la distancia.

.. note::

    * Si obtienes el error ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, necesitas referirte a :ref:`i2c_config` para habilitar el I2C.
    * Si obtienes el error ``ModuleNotFoundError: No module named 'smbus2'``, por favor ejecuta ``sudo pip3 install smbus2``.
    * Si aparece 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 el cableado están bien, pero la pantalla LCD aún no muestra contenido, puedes girar el potenciómetro en la parte trasera para aumentar el contraste.

.. 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, necesitas 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)  # El pin Echo es GPIO 24, el pin Trigger es GPIO 23

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

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

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

    def loop():
        # Medir continuamente la distancia y actualizar la pantalla LCD y el zumbador
        while True:
            dis = distance()  # Obtener la distancia actual
            # Mostrar la distancia y manejar las alertas basadas en la distancia
            if dis > 400:  # Comprobar 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:
                # Mostrar la distancia actual en la pantalla LCD
                LCD1602.clear()
                LCD1602.write(0, 0, 'Distance is')
                LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                # Ajustar 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()  # Configurar la pantalla LCD
        loop()      # Iniciar el bucle de medición
    except KeyboardInterrupt:
        # Apagar el zumbador y limpiar la pantalla LCD en caso de interrupción del usuario (por ejemplo, Ctrl+C)
        buzzer.off()
    LCD1602.clear()



**Explicación del Código**

#. Este script utiliza varias bibliotecas para su funcionalidad. 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 de Raspberry Pi, particularmente 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 pines GPIO
       sensor = DistanceSensor(echo=24, trigger=23)  # El pin Echo es GPIO 24, el pin Trigger es GPIO 23

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

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

   .. code-block:: python

       def lcdsetup():
           # Inicializar la pantalla LCD con dirección I2C y habilitar la luz de fondo
           LCD1602.init(0x27, 1)  # 0x27 es la dirección I2C de la pantalla LCD
           LCD1602.clear()  # Limpiar la pantalla LCD
           # Mostrar mensajes de inicio en la pantalla LCD
           LCD1602.write(0, 0, 'Ultrasonic Starting')
           LCD1602.write(1, 1, 'By SunFounder')
           time.sleep(2)  # Esperar 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():
           # Calcular y devolver la distancia medida por el sensor
           dis = sensor.distance * 100  # Convertir distancia a centímetros
           print('Distance: {:.2f} cm'.format(dis))  # Imprimir distancia con dos decimales
           time.sleep(0.3)  # Esperar 0.3 segundos antes de la siguiente medición
           return dis

#. El bucle principal mide continuamente la distancia, actualizando tanto la pantalla 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():
           # Medir continuamente la distancia y actualizar la pantalla LCD y el zumbador
           while True:
               dis = distance()  # Obtener la distancia actual
               # Mostrar la distancia y manejar las alertas basadas en la distancia
               if dis > 400:  # Comprobar 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:
                   # Mostrar la distancia actual en la pantalla LCD
                   LCD1602.clear()
                   LCD1602.write(0, 0, 'Distance is')
                   LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                   # Ajustar 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 pantalla LCD y entra en el bucle principal. Puede ser interrumpido con un comando de teclado (Ctrl+C), que apaga el zumbador y limpia la pantalla LCD.

   .. code-block:: python

       try:
           lcdsetup()  # Configurar la pantalla LCD
           loop()      # Iniciar el bucle de medición
       except KeyboardInterrupt:
           # Apagar el zumbador y limpiar la pantalla LCD en caso de interrupción del usuario (por ejemplo, Ctrl+C)
           buzzer.off()
           LCD1602.clear()
