.. note::

    Ciao, benvenuto nella SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community su Facebook! Approfondisci le tue conoscenze su Raspberry Pi, Arduino ed ESP32 insieme ad 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 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 concorsi**: Partecipa a concorsi e promozioni durante le festività.

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

.. _1.3.2_py:

1.3.2 Servo
==============

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

In questo progetto, impareremo come far ruotare un servo.

Componenti Necessari
---------------------------------

In questo progetto, abbiamo bisogno dei seguenti componenti. 

.. image:: ../img/list_1.3.2.png

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

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

    *   - Nome	
        - ARTICOLI IN QUESTO 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_servo`
        - |link_servo_buy|

Schema Elettrico
--------------------

.. image:: ../img/image337.png


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

**Passo 1:** Costruisci il circuito.

.. image:: ../img/image125.png

**Passo 2:** Accedi alla cartella del codice.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python/

**Passo 3:** Esegui il file eseguibile.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 1.3.2_Servo.py

Dopo l'esecuzione del programma, il servo ruoterà da 0 gradi a 180 gradi e poi da 180 gradi a 0 gradi, ciclicamente.

**Codice**

.. note::

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


.. raw:: html

    <run></run>

.. code-block:: python

    import RPi.GPIO as GPIO
    import time

    SERVO_MIN_PULSE = 500
    SERVO_MAX_PULSE = 2500
    ServoPin = 18

    def map(value, inMin, inMax, outMin, outMax):
        return (outMax - outMin) * (value - inMin) / (inMax - inMin) + outMin

    def setup():
        global p
        GPIO.setmode(GPIO.BCM)       # Numerazione GPIO in modalità BCM
        GPIO.setup(ServoPin, GPIO.OUT)   # Imposta ServoPin come output
        GPIO.output(ServoPin, GPIO.LOW)  # Imposta ServoPin a basso
        p = GPIO.PWM(ServoPin, 50)     # Imposta la frequenza a 50Hz
        p.start(0)                     # Duty Cycle = 0
        
    def setAngle(angle):      # Fa ruotare il servo a un angolo specifico (0-180 gradi) 
        angle = max(0, min(180, angle))
        pulse_width = map(angle, 0, 180, SERVO_MIN_PULSE, SERVO_MAX_PULSE)
        pwm = map(pulse_width, 0, 20000, 0, 100)
        p.ChangeDutyCycle(pwm)# mappa l'angolo sul duty cycle e lo invia    
    def loop():
        while True:
            for i in range(0, 181, 5):   # fa ruotare il servo da 0 a 180 gradi
                setAngle(i)     # Invia l'angolo al servo
                time.sleep(0.002)
            time.sleep(1)
            for i in range(180, -1, -5): # fa ruotare il servo da 180 a 0 gradi
                setAngle(i)
                time.sleep(0.001)
            time.sleep(1)
    def destroy():
        p.stop()
        GPIO.cleanup()

    if __name__ == '__main__':     # Il programma inizia qui
        setup()
        try:
            loop()
        except KeyboardInterrupt:  # Quando viene premuto 'Ctrl+C', il programma destroy() sarà eseguito.
            destroy()
        

**Spiegazione del Codice**

.. code-block:: python

    p = GPIO.PWM(ServoPin, 50)     # Imposta la frequenza a 50Hz
    p.start(0)                     # Duty Cycle = 0

Imposta il ServoPin su PWM, poi la frequenza su 50Hz e il periodo su 20ms.

p.start(0): Avvia la funzione PWM e imposta il valore iniziale su 0.

.. code-block:: python

    def setAngle(angle):      # Fa ruotare il servo a un angolo specifico (0-180 gradi) 
        angle = max(0, min(180, angle))
        pulse_width = map(angle, 0, 180, SERVO_MIN_PULSE, SERVO_MAX_PULSE)
        pwm = map(pulse_width, 0, 20000, 0, 100)
        p.ChangeDutyCycle(pwm)
    
Crea una funzione, setAngle(), per inviare l'angolo da 0 a 180 al servo.

.. code-block:: python

    angle = max(0, min(180, angle))

Questo codice viene utilizzato per limitare l'angolo entro l'intervallo 0-180°.

La funzione min() restituisce il valore minimo tra quelli in ingresso. 
Se 180<angle, allora restituisce 180, altrimenti restituisce angle.

La funzione max() restituisce l'elemento massimo in un iterabile o il più grande 
tra due o più parametri. Se 0>angle, allora restituisce 0, altrimenti restituisce angle.

.. code-block:: python

    pulse_width = map(angle, 0, 180, SERVO_MIN_PULSE, SERVO_MAX_PULSE)
    pwm = map(pulse_width, 0, 20000, 0, 100)
    p.ChangeDutyCycle(pwm)

Per convertire un angolo da 0 a 180° nel servo, l'ampiezza dell'impulso del servo è 
impostata su 0,5ms (500us) - 2,5ms (2500us).

Il periodo di PWM è 20ms (20000us), quindi il duty cycle del PWM varia da 
(500/20000)% a (2500/20000)%, e l'intervallo 0 ~ 180 è mappato su 2,5 ~ 12,5.


Immagine del Fenomeno
--------------------------

.. image:: ../img/image126.jpeg

