.. note::

    Ciao, benvenuto nella community di SunFounder Raspberry Pi & Arduino & ESP32 su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

    **Perché unirsi?**

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

    👉 Sei pronto per esplorare e creare con noi? Clicca su [|link_sf_facebook|] e unisciti oggi stesso!

.. _4.1.8_py_pi5:

4.1.5 Benvenuto
=====================================

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

In questo progetto, utilizzeremo il PIR per rilevare il movimento dei pedoni, 
e useremo servocomandi, LED e un cicalino per simulare il funzionamento della 
porta automatica di un negozio. Quando un pedone entra nel raggio di rilevamento 
del PIR, la spia luminosa si accenderà, la porta si aprirà e il cicalino suonerà 
il campanello di apertura.

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

In questo progetto, avremo bisogno dei seguenti componenti.

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

È sicuramente comodo acquistare un kit completo, ecco il link:

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

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

Puoi anche acquistarli separatamente dai link sottostanti.

.. 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_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|


Diagramma schematico
-------------------------

============ ======== ======== ===
T-Board Name physical 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

Procedure Sperimentali
----------------------------

**Passo 1:** Monta il circuito.

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

**Passo 2:** Cambia la 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.8_Welcome_zero.py

Dopo l'esecuzione del codice, se il sensore PIR rileva il passaggio di qualcuno,
la porta si aprirà automaticamente (simulata dal servo), si accenderà
l'indicatore e verrà riprodotta la melodia del campanello. Dopo che la melodia
sarà terminata, il sistema chiuderà automaticamente la porta e spegnerà
l'indicatore, aspettando il prossimo passaggio.

Ci sono due potenziometri sul modulo PIR: uno regola la sensibilità e l'altro la distanza di rilevamento. Per far funzionare meglio il modulo PIR, è necessario ruotarli entrambi in senso antiorario fino in fondo.

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

.. warning::

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

**Code**

.. note::
    Puoi **Modificare/Resettare/Copiare/Eseguire/Fermare** il codice qui sotto. Prima di farlo, devi andare nel percorso del codice sorgente, 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

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

   # Configurazione dei pin GPIO per LED, sensore di movimento (PIR) e cicalino
   ledPin = LED(6)
   pirPin = MotionSensor(21)
   buzPin = TonalBuzzer(27)

   # Fattore di correzione della larghezza d'impulso per il servo e calcolo
   myCorrection = 0.45
   maxPW = (2.0 + myCorrection) / 1000  # Larghezza d'impulso massima
   minPW = (1.0 - myCorrection) / 1000  # Larghezza d'impulso minima

   # Inizializzazione del servo con larghezze d'impulso personalizzate
   servoPin = Servo(25, min_pulse_width=minPW, max_pulse_width=maxPW)

   # Melodia musicale per il cicalino, con note e durate
   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)  # Converte l'angolo in valore per il servo
       servoPin.value = value      # Imposta la posizione del servo
       time.sleep(0.001)           # Breve ritardo per il movimento del servo

   def doorbell():
       """
       Play a musical tune using the buzzer.
       """
       for note, duration in tune:
           buzPin.play(note)       # Riproduce la nota
           time.sleep(float(duration))  # Durata della nota
       buzPin.stop()               # Ferma il cicalino dopo la melodia

   def closedoor():
       # Spegni il LED e muovi il servo per chiudere la porta
       ledPin.off()
       for i in range(180, -1, -1):
           setAngle(i)             # Muovi il servo da 180 a 0 gradi
           time.sleep(0.001)       # Breve ritardo per un movimento fluido
       time.sleep(1)               # Pausa dopo la chiusura della porta

   def opendoor():
       # Accendi il LED, apri la porta (muovi il servo), riproduci la melodia e chiudi la porta
       ledPin.on()
       for i in range(0, 181):
           setAngle(i)             # Muovi il servo da 0 a 180 gradi
           time.sleep(0.001)       # Breve ritardo per un movimento fluido
       time.sleep(1)               # Pausa prima della melodia
       doorbell()                  # Riproduci la melodia
       closedoor()                 # Chiudi la porta dopo la melodia

   def loop():
       # Ciclo principale per controllare il movimento e operare la porta
       while True:
           if pirPin.motion_detected:
               opendoor()               # Apri la porta se viene rilevato movimento
           time.sleep(0.1)              # Breve ritardo nel ciclo

   try:
       loop()
   except KeyboardInterrupt:
       # Pulizia dei GPIO in caso di interruzione dell'utente (ad es., Ctrl+C)
       buzPin.stop()
       ledPin.off()



**Spiegazione del Codice**

#. Lo script inizia importando i moduli necessari. La libreria ``gpiozero`` viene utilizzata per interfacciarsi con il LED, il sensore di movimento, il motore servo e il cicalino tonale. Il modulo ``time`` serve per gestire le funzioni legate al tempo.

   .. code-block:: python

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

#. Inizializza il LED, il sensore di movimento PIR e il cicalino tonale sui rispettivi pin GPIO.

   .. code-block:: python

       # Configurazione dei pin GPIO per LED, sensore di movimento (PIR) e cicalino
       ledPin = LED(6)
       pirPin = MotionSensor(21)
       buzPin = TonalBuzzer(27)

#. Calcola la larghezza d'impulso massima e minima per il motore servo, incorporando un fattore di correzione per la regolazione fine.

   .. code-block:: python

       # Fattore di correzione della larghezza d'impulso per il servo e calcolo
       myCorrection = 0.45
       maxPW = (2.0 + myCorrection) / 1000  # Larghezza d'impulso massima
       minPW = (1.0 - myCorrection) / 1000  # Larghezza d'impulso minima

#. Inizializza il motore servo sul pin GPIO 25 con larghezze d'impulso personalizzate per un posizionamento preciso.

   .. code-block:: python

       # Inizializzazione del servo con larghezze d'impulso personalizzate
       servoPin = Servo(25, min_pulse_width=minPW, max_pulse_width=maxPW)

#. La melodia è definita come una sequenza di note (frequenze) e durate (secondi). 

   .. code-block:: python

       # Melodia musicale per il cicalino, con note e durate
       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)]

#. Funzione per muovere il servo ad un angolo specificato. Converte l'angolo in un valore compreso tra 0 e 1 per il 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)  # Converte l'angolo in valore per il servo
           servoPin.value = value      # Imposta la posizione del servo
           time.sleep(0.001)           # Breve ritardo per il movimento del servo

#. Funzione per riprodurre una melodia utilizzando il cicalino. Scorre l'elenco ``tune``, riproducendo ogni nota per la sua durata specificata.

   .. code-block:: python

       def doorbell():
           """
           Play a musical tune using the buzzer.
           """
           for note, duration in tune:
               buzPin.play(note)       # Riproduce la nota
               time.sleep(float(duration))  # Durata della nota
           buzPin.stop()               # Ferma il cicalino dopo la melodia

#. Funzioni per aprire e chiudere la porta utilizzando il motore servo. La funzione ``opendoor`` accende il LED, apre la porta, riproduce la melodia e poi chiude la porta.

   .. code-block:: python

       def closedoor():
           # Spegni il LED e muovi il servo per chiudere la porta
           ledPin.off()
           for i in range(180, -1, -1):
               setAngle(i)             # Muovi il servo da 180 a 0 gradi
               time.sleep(0.001)       # Breve ritardo per un movimento fluido
           time.sleep(1)               # Pausa dopo la chiusura della porta

       def opendoor():
           # Accendi il LED, apri la porta (muovi il servo), riproduci la melodia e chiudi la porta
           ledPin.on()
           for i in range(0, 181):
               setAngle(i)             # Muovi il servo da 0 a 180 gradi
               time.sleep(0.001)       # Breve ritardo per un movimento fluido
           time.sleep(1)               # Pausa prima della melodia
           doorbell()                  # Riproduci la melodia
           closedoor()                 # Chiudi la porta dopo la melodia

#. Ciclo principale che controlla costantemente il rilevamento del movimento. Quando viene rilevato un movimento, attiva la funzione ``opendoor``.

   .. code-block:: python

       def loop():
           # Ciclo principale per controllare il movimento e operare la porta
           while True:
               if pirPin.motion_detected:
                   opendoor()               # Apri la porta se viene rilevato movimento
               time.sleep(0.1)              # Breve ritardo nel ciclo

#. Esegue il ciclo principale e garantisce che lo script possa essere interrotto con un comando da tastiera (Ctrl+C), spegnendo il cicalino e il LED per una chiusura pulita.

   .. code-block:: python

       try:
           loop()
       except KeyboardInterrupt:
           # Pulizia dei GPIO in caso di interruzione dell'utente (ad es., Ctrl+C)
           buzPin.stop()
           ledPin.off()

