.. note::

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

    **¿Por qué unirse?**

    - **Soporte de expertos**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprender y compartir**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Acceso exclusivo**: Obtén primicias sobre nuevos lanzamientos de productos y adelantos.
    - **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.

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

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

En esta lección, aprenderemos a hacer que el servo gire.

Componentes
-------------

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

Principio
------------

**Servo**

Un servo generalmente está compuesto por las siguientes partes: carcasa, 
eje, sistema de engranajes, potenciómetro, motor de corriente continua y una placa integrada.

.. image:: img/image121.png

Funciona de la siguiente manera: el microcontrolador envía señales PWM 
al servo, y la placa integrada dentro del servo recibe estas señales a 
través del pin de señal, controlando el motor interno para que gire. 
Como resultado, el motor acciona el sistema de engranajes y luego mueve 
el eje después de la desaceleración. El eje y el potenciómetro del servo 
están conectados entre sí. Cuando el eje gira, acciona el potenciómetro, 
el cual envía una señal de voltaje a la placa integrada. Entonces, la placa 
determina la dirección y velocidad de rotación en función de la posición 
actual, permitiéndole detenerse exactamente en la posición definida y mantenerse ahí.

.. image:: img/image122.png

El ángulo está determinado por la duración de un pulso que se aplica al cable de 
control. A esto se le llama Modulación de Ancho de Pulso (PWM). El servo espera 
recibir un pulso cada 20 ms. La longitud del pulso determinará cuánto gira el 
motor. Por ejemplo, un pulso de 1.5 ms hará que el motor gire a la posición de 
90 grados (posición neutra).

Cuando se envía un pulso de menos de 1.5 ms al servo, éste rota y mantiene su 
eje de salida un cierto número de grados en sentido antihorario desde el punto 
neutro. Cuando el pulso es mayor a 1.5 ms, ocurre lo contrario. El ancho mínimo 
y máximo del pulso que permitirá al servo girar a una posición válida depende de 
cada servo. Generalmente, el pulso mínimo será de aproximadamente 0.5 ms y el 
máximo será de 2.5 ms.

.. image:: img/image123.jpeg

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

.. image:: img/image337.png


Procedimiento Experimental
------------------------------

**Paso 1:** Construye el circuito.

.. image:: img/image125.png
    :width: 800

Para Usuarios de Lenguaje C
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 2**: Ve a la carpeta del código.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/davinci-kit-for-raspberry-pi/c/1.3.2

**Paso 3**: Compila el código.

.. raw:: html

   <run></run>

.. code-block::

    gcc 1.3.2_Servo.c -lwiringPi

**Paso 4**: Ejecuta el archivo compilado.

.. raw:: html

   <run></run>

.. code-block::

    sudo ./a.out

Después de ejecutar el programa, el servo girará de 0 grados a 180 grados, 
y luego de 180 grados a 0 grados, en un ciclo continuo.

.. note::

    Si no funciona después de ejecutarlo, o aparece un mensaje de error: \"wiringPi.h: No such file or directory", consulta :ref:`C code is not working?`.

**Código**

.. code-block:: c

    #include <wiringPi.h>
    #include <softPwm.h>
    #include <stdio.h>

    #define ServoPin    1       //define el servo en GPIO1
    long Map(long value,long fromLow,long fromHigh,long toLow,long toHigh){
        return (toHigh-toLow)*(value-fromLow) / (fromHigh-fromLow) + toLow;
    }
    void setAngle(int pin, int angle){    //Crear una función para controlar el ángulo del servo.
        if(angle < 0)
            angle = 0;
        if(angle > 180)
            angle = 180;
        softPwmWrite(pin,Map(angle, 0, 180, 5, 25));   
    } 

    int main(void)
    {
        int i;
        if(wiringPiSetup() == -1){ //si la inicialización de wiring falla, muestra un mensaje en pantalla
            printf("setup wiringPi failed !");
            return 1; 
        }
        softPwmCreate(ServoPin, 0, 200);       //inicializar el pin PWM del servo
        while(1){
            for(i=0;i<181;i++){     // Let servo rotate from 0 to 180.            	setAngle(ServoPin,i);
                delay(2);
            }
            delay(1000);
            for(i=181;i>-1;i--){        // Let servo rotate from 180 to 0.            	setAngle(ServoPin,i);
                delay(2);
            }
            delay(1000);
        }
        return 0;
    }
**Explicación del Código**

.. code-block:: c

    long Map(long value,long fromLow,long fromHigh,long toLow,long toHigh){
        return (toHigh-toLow)*(value-fromLow) / (fromHigh-fromLow) + toLow;
    }

Crea una función Map() para mapear el valor en el siguiente código.

.. code-block:: c

    void setAngle(int pin, int angle){    //Crea una función para controlar el ángulo del servo.
        if(angle < 0)
            angle = 0;
        if(angle > 180)
            angle = 180;
        softPwmWrite(pin,Map(angle, 0, 180, 5, 25));   
    } 

Crea una función, setAngle(), para escribir el ángulo en el servo.

.. code-block:: c

    softPwmWrite(pin,Map(angle,0,180,5,25));  

Esta función puede cambiar el ciclo de trabajo del PWM.

Para hacer que el servo gire de 0 a 180°, el ancho de pulso debe variar
dentro del rango de 0.5ms a 2.5ms cuando el período es de 20ms; en la
función, softPwmCreate(), hemos establecido que el período es
200x100us=20ms, por lo que necesitamos mapear 0 a 180 a 5x100us a 25x100us.

El prototipo de esta función se muestra a continuación.

.. code-block:: 

    int softPwmCreate（int pin，int initialValue，int pwmRange）;


**Parámetro pin:** Cualquier pin GPIO de Raspberry Pi se puede configurar como pin PWM.

**Parámetro initialValue:** El ancho de pulso inicial es el valor de initialValue
multiplicado por 100us.

**Parámetro pwmRange:** El período de PWM es el valor de pwmRange multiplicado por 100us.

Para Usuarios de Lenguaje Python
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 2**: Ve a la carpeta del código.

.. raw:: html

   <run></run>

.. code-block::

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

**Paso 3**: Ejecuta el archivo.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 1.3.2_Servo.py

Después de ejecutar el programa, el servo girará de 0 grados 
a 180 grados, y luego de 180 grados a 0 grados, en un ciclo continuo.

**Código**

.. note::

    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Antes de eso, necesitas dirigirte a la ruta del código fuente como ``davinci-kit-for-raspberry-pi/python``. 
    
.. 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)       # Numerar los GPIOs según BCM
        GPIO.setup(ServoPin, GPIO.OUT)   # Configurar el modo de salida de ServoPin
        GPIO.output(ServoPin, GPIO.LOW)  # Poner ServoPin en bajo
        p = GPIO.PWM(ServoPin, 50)     # Configurar frecuencia en 50Hz
        p.start(0)                     # Ciclo de trabajo = 0
        
    def setAngle(angle):      # hacer que el servo gire a un ángulo específico (0-180 grados) 
        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)#mapear el ángulo al ciclo de trabajo y enviarlo
        
    def loop():
        while True:
            for i in range(0, 181, 5):   #hacer que el servo gire de 0 a 180 grados
                setAngle(i)     # Escribir en el servo
                time.sleep(0.002)
            time.sleep(1)
            for i in range(180, -1, -5): #hacer que el servo gire de 180 a 0 grados
                setAngle(i)
                time.sleep(0.001)
            time.sleep(1)

    def destroy():
        p.stop()
        GPIO.cleanup()

    if __name__ == '__main__':     #El programa comienza aquí
        setup()
        try:
            loop()
        except KeyboardInterrupt:  # Cuando se presiona 'Ctrl+C', se ejecutará destroy().
            destroy()

**Explicación del Código**

.. code-block:: python

    p = GPIO.PWM(ServoPin, 50)     # configurar la frecuencia en 50Hz
    p.start(0)                     # Ciclo de trabajo = 0

Configura el pin ServoPin como pin PWM, luego la frecuencia a 50Hz, y el período a 20ms.

p.start(0): Ejecuta la función PWM y establece el valor inicial en 0.

.. code-block:: python

    def setAngle(angle):      # hacer que el servo gire a un ángulo específico (0-180 grados) 
        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)#mapear el ángulo al ciclo de trabajo y enviarlo
    
Crea una función, setAngle(), para escribir el ángulo que varía de 0 a 180 en el servo.

.. code-block:: python

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

Este código se usa para limitar el ángulo dentro del rango de 0 a 180°.

La función min() devuelve el mínimo de los valores de entrada. 
Si 180 < ángulo, devuelve 180; si no, devuelve ángulo.

El método max() devuelve el elemento máximo en un iterable o el mayor de 
dos o más parámetros. Si 0 > ángulo, devuelve 0; si no, devuelve ángulo.

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

Para ajustar un rango de 0 a 180° en el servo, el ancho de pulso del servo
se configura entre 0.5ms (500us) y 2.5ms (2500us).

El período de PWM es 20ms (20000us), por lo que el ciclo de trabajo de PWM es
(500/20000)% - (2500/20000)%, y el rango de 0 a 180 se asigna a 2.5 a
12.5.

Imagen de Fenómeno
------------------------

.. image:: img/image126.jpeg
