Servomotor SG90 con Raspberry PI

Mi amigo Jorge me «presentó» los servomotores SG90. Son lindos, chiquitos, baratos, y fáciles de operar. Me traje un pack de 20 de AliExpress para hacer algunas pruebas, y hace unos días llegaron.

Este servo recibe un pulso por uno de sus pines. El ancho del pulso determina el ángulo de rotación (de -90º a 90º) al cual el motor debe llegar. Ya que debe enviarse el pulso constantemente dentro un rango de tiempo (20ms en caso del SG90), se puede usar cualquier librería para crear una modulación por ancho de pulsos. El RPi tiene la librería PWM de Python para ello. El duty cycle es el porcentaje de tiempo que el pin elegido estará en 1 lógico. El resto del tiempo estará en cero. El código para moverlo es bastante sencillo:

#!/usr/bin/env python3

from RPi import GPIO
from time import sleep

# El pin del GPIO que estará conectado al pin de PWM del servo.
PIN = 2

# Configuramos el pin del RPi
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT)

# El 2do parámetro es la frecuencia del ciclo en Hertz. El manual del SG90
# indica un periodo del ciclo de 20ms (0,02s), entonce la frecuencia es
# 1/0,02 = 50 Hz
servo = GPIO.PWM(PIN, 50)

# Iniciamos el PWM, colocando el servo en 0º. Para ello, debemos enviarle
# un pulso de 1.5ms de ancho. La librería de Python requiere especificar el
# 'duty cycle' ('ciclo de trabajo', el tiempo que el pulso estará en 1) en
# porcentaje del ciclo. 1.5ms de 20ms es el 7.5%
servo.start(7.5)

# Le damos un segundo para que se mueva
sleep(1)

# Cambiamos el duty cycle para mover el servo completamente a la derecha, -90º.
# Para ello, el SG90 espera un pulso de 2ms = 10%. Cambiamos el duty cycle.
servo.ChangeDutyCycle(10)

# Esperamos un segundo
sleep(1)

# Ahora, completamente a la izquierda, 90º, cambiamos el DC a 1ms = 5%
servo.ChangeDutyCycle(5)
sleep(1)

# Detenemos el PWM y reseteamos los pins del RPi
servo.stop()
GPIO.cleanup()

En la práctica encontré que completamente a la derecha no es un duty cycle de 10%, sino 12%. Igual a la izquierda, no es 5%, sino 3%. Es cuestión de jugar un poco para llegar a los valores exactos.

El servo requiere 5V para trabajar. El RPi tiene un pin de 5v, pero preferí usar una fuente externa de energía. No quisiera sobrcargar el RPi y malograrlo

A este código le añadí un socketserver para la comunicación desde Dorothy, donde hice un programa en JavaScript/PHP para el control que uso con el celular. El JavaScript envía el ángulo via Ajax al PHP, quien se lo envía al RPi via socket UDP, et voilà. Más emocionante fue ver a mi amigo Oscar, que está en Estados Unidos, mover el servo desde allá

Al inicio del vídeo el servo no responde bien. A veces tiembla, a veces se mueve solo. Pienso que puede ser por el hecho que el Raspberry PI corre un Linux completo (con interrupciones y todo), es lento, y por defecto no trae (ni estoy usando la librerías para) un kernel con soporte para trabajo en tiempo real. Ya que el ancho del pulso enviado al servo es entre 1 y 2 milisegundos, es probable que a veces el RPi se distraiga y demore más en apagar la señal del pulso, ergo enviando valores al azar al servo. Pero hey… funciona