.. note::

    Ciao, benvenuto nella comunità SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 con altri appassionati.

    **Perché unirti a noi?**

    - **Supporto esperto**: Risolvi problemi post-vendita e sfide tecniche con l'aiuto della nostra comunità e del nostro team.
    - **Impara e condividi**: Scambia consigli e tutorial per migliorare le tue competenze.
    - **Anteprime esclusive**: Ottieni accesso anticipato agli annunci di nuovi prodotti e anteprime.
    - **Sconti speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni festive e giveaway**: Partecipa a concorsi e promozioni festive.

    👉 Pronto per esplorare e creare con noi? Clicca [|link_sf_facebook|] e unisciti oggi!

.. _4.1.9_py_pi5:

4.1.6 Sistema di allarme per retromarcia
==============================================

Introduzione
------------------

In questo progetto, utilizzeremo un display LCD, un cicalino e sensori ad ultrasuoni 
per realizzare un sistema di assistenza alla retromarcia. Possiamo installarlo su un 
veicolo telecomandato per simulare il processo reale di parcheggio in retromarcia in 
un garage.

Componenti necessari
------------------------------

In questo progetto, abbiamo bisogno dei seguenti componenti.

.. image:: ../python_pi5/img/4.1.9_reversing_alarm_list.png
    :width: 800
    :align: center

È sicuramente conveniente acquistare un intero kit, ecco il link: 

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

    *   - Nome	
        - OGGETTI NEL KIT
        - LINK
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

Puoi anche acquistarli separatamente dai link qui sotto.

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

    *   - INTRODUZIONE AI COMPONENTI
        - LINK PER L'ACQUISTO

    *   - :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|

Schema elettrico
--------------------

Il sensore ad ultrasuoni rileva la distanza tra sé stesso e l'ostacolo, che verrà 
visualizzata sul display LCD sotto forma di codice. Allo stesso tempo, il sensore 
ad ultrasuoni farà emettere al cicalino un segnale acustico con frequenze diverse 
a seconda del valore della distanza.

============ ======== ======== ===
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

Procedure sperimentali
---------------------------

**Passo 1:** Costruisci il circuito.

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

**Passo 2:** Cambia directory.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Passo 3:** Esegui.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 4.1.9_ReversingAlarm_zero.py

Quando il codice viene eseguito, il modulo del sensore ad ultrasuoni rileva la 
distanza dall'ostacolo e visualizza l'informazione della distanza sul display 
LCD1602; inoltre, il cicalino emette un tono di avviso la cui frequenza varia 
in base alla distanza.

.. note::

    * Se ricevi l'errore ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, devi fare riferimento a :ref:`i2c_config` per abilitare l'I2C.
    * Se ottieni l'errore ``ModuleNotFoundError: No module named 'smbus2'``, esegui ``sudo pip3 install smbus2``.
    * Se compare l'errore ``OSError: [Errno 121] Remote I/O error``, significa che il modulo è cablato male o il modulo è guasto.
    * Se il codice e il cablaggio sono corretti, ma l'LCD continua a non visualizzare contenuti, puoi regolare il potenziometro sul retro per aumentare il contrasto.


.. warning::

    Se viene visualizzato l'errore ``RuntimeError: Cannot determine SOC peripheral base address``, fare riferimento a :ref:`faq_soc`. 

**Code**

.. note::
    Puoi **Modificare/Reimpostare/Copiare/Eseguire/Interrompere** il codice qui sotto. Ma prima di tutto, devi andare nel percorso del codice come ``raphael-kit/python-pi5``. Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l'effetto.

.. raw:: html

    <run></run>

.. code-block:: python

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

    # Inizializza il sensore a ultrasuoni con i pin GPIO
    sensor = DistanceSensor(echo=24, trigger=23)  # Pin Echo è GPIO 24, Pin Trigger è GPIO 23

    # Inizializza il cicalino collegato al pin GPIO 17
    buzzer = Buzzer(17)

    def lcdsetup():
        # Inizializza l'LCD con l'indirizzo I2C e attiva la retroilluminazione
        LCD1602.init(0x27, 1)  # 0x27 è l'indirizzo I2C dell'LCD
        LCD1602.clear()  # Pulisci il display LCD
        # Mostra messaggi di avvio sull'LCD
        LCD1602.write(0, 0, 'Ultrasonic Starting')
        LCD1602.write(1, 1, 'By SunFounder')
        time.sleep(2)  # Attendi 2 secondi

    def distance():
        # Calcola e restituisci la distanza misurata dal sensore
        dis = sensor.distance * 100  # Converti la distanza in centimetri
        print('Distance: {:.2f} cm'.format(dis))  # Stampa la distanza con due decimali
        time.sleep(0.3)  # Attendi 0,3 secondi prima della prossima misurazione
        return dis

    def loop():
        # Misura continuamente la distanza e aggiorna l'LCD e il cicalino
        while True:
            dis = distance()  # Ottieni la distanza attuale
            # Mostra la distanza e gestisci gli avvisi in base alla distanza
            if dis > 400:  # Controlla se la distanza è fuori dal range
                LCD1602.clear()
                LCD1602.write(0, 0, 'Error')
                LCD1602.write(3, 1, 'Out of range')
                time.sleep(0.5)
            else:
                # Mostra la distanza attuale sull'LCD
                LCD1602.clear()
                LCD1602.write(0, 0, 'Distance is')
                LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                # Regola la frequenza del cicalino in base alla distanza
                if dis >= 50:
                    time.sleep(0.5)
                elif 20 < dis < 50:
                    # Distanza media: frequenza media del cicalino
                    for _ in range(2):
                        buzzer.on()
                        time.sleep(0.05)
                        buzzer.off()
                        time.sleep(0.2)
                elif dis <= 20:
                    # Distanza ravvicinata: alta frequenza del cicalino
                    for _ in range(5):
                        buzzer.on()
                        time.sleep(0.05)
                        buzzer.off()
                        time.sleep(0.05)

    try:
        lcdsetup()  # Configura il display LCD
        loop()      # Avvia il ciclo di misurazione
    except KeyboardInterrupt:
        # Spegni il cicalino e pulisci l'LCD all'interruzione dell'utente (es. Ctrl+C)
        buzzer.off()
    LCD1602.clear()



**Spiegazione del Codice**

#. Questo script utilizza diverse librerie per il suo funzionamento. La libreria ``LCD1602`` gestisce il display LCD, mentre ``time`` fornisce funzioni legate al tempo. La libreria ``gpiozero`` è essenziale per l'interazione con i pin GPIO del Raspberry Pi, in particolare per operare il sensore di distanza e il cicalino.

   .. code-block:: python

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

#. Il sensore a ultrasuoni è configurato con i suoi pin echo e trigger collegati rispettivamente ai pin GPIO 24 e 23. Inoltre, un cicalino è collegato al pin GPIO 17.

   .. code-block:: python

       # Inizializza il sensore a ultrasuoni con i pin GPIO
       sensor = DistanceSensor(echo=24, trigger=23)  # Pin Echo è GPIO 24, Pin Trigger è GPIO 23

       # Inizializza il cicalino collegato al pin GPIO 17
       buzzer = Buzzer(17)

#. L'inizializzazione del display LCD comporta la sua pulizia e la visualizzazione di un messaggio di avvio.

   .. code-block:: python

       def lcdsetup():
           # Inizializza l'LCD con l'indirizzo I2C e attiva la retroilluminazione
           LCD1602.init(0x27, 1)  # 0x27 è l'indirizzo I2C dell'LCD
           LCD1602.clear()  # Pulisci il display LCD
           # Mostra messaggi di avvio sull'LCD
           LCD1602.write(0, 0, 'Ultrasonic Starting')
           LCD1602.write(1, 1, 'By SunFounder')
           time.sleep(2)  # Attendi 2 secondi

#. La funzione ``distance`` calcola la distanza misurata dal sensore a ultrasuoni e la restituisce, mostrando il valore in centimetri.

   .. code-block:: python

       def distance():
           # Calcola e restituisci la distanza misurata dal sensore
           dis = sensor.distance * 100  # Converti la distanza in centimetri
           print('Distance: {:.2f} cm'.format(dis))  # Stampa la distanza con due decimali
           time.sleep(0.3)  # Attendi 0,3 secondi prima della prossima misurazione
           return dis

#. Il ciclo principale misura continuamente la distanza, aggiornando sia l'LCD che il cicalino. Gestisce diverse gamme di distanza con azioni specifiche, come la visualizzazione di messaggi di errore o la variazione della frequenza del cicalino in base alla distanza misurata.

   .. code-block:: python

       def loop():
           # Misura continuamente la distanza e aggiorna l'LCD e il cicalino
           while True:
               dis = distance()  # Ottieni la distanza attuale
               # Mostra la distanza e gestisci gli avvisi in base alla distanza
               if dis > 400:  # Controlla se la distanza è fuori dal range
                   LCD1602.clear()
                   LCD1602.write(0, 0, 'Error')
                   LCD1602.write(3, 1, 'Out of range')
                   time.sleep(0.5)
               else:
                   # Mostra la distanza attuale sull'LCD
                   LCD1602.clear()
                   LCD1602.write(0, 0, 'Distance is')
                   LCD1602.write(5, 1, str(round(dis, 2)) + ' cm')
                   # Regola la frequenza del cicalino in base alla distanza
                   if dis >= 50:
                       time.sleep(0.5)
                   elif 20 < dis < 50:
                       # Distanza media: frequenza media del cicalino
                       for _ in range(2):
                           buzzer.on()
                           time.sleep(0.05)
                           buzzer.off()
                           time.sleep(0.2)
                   elif dis <= 20:
                       # Distanza ravvicinata: alta frequenza del cicalino
                       for _ in range(5):
                           buzzer.on()
                           time.sleep(0.05)
                           buzzer.off()
                           time.sleep(0.05)

#. All'esecuzione, lo script configura l'LCD e entra nel ciclo principale. Può essere interrotto con un comando da tastiera (Ctrl+C), che spegne il cicalino e pulisce l'LCD.

   .. code-block:: python

       try:
           lcdsetup()  # Configura il display LCD
           loop()      # Avvia il ciclo di misurazione
       except KeyboardInterrupt:
           # Spegni il cicalino e pulisci l'LCD all'interruzione dell'utente (es. Ctrl+C)
           buzzer.off()
           LCD1602.clear()
