3.16. Control de servos¶
Un servo de aficionado (RC) es un pequeño motorreductor en una carcasa sellada con control de posición en lazo cerrado integrado. Dentro de la carcasa hay un motor de corriente continua, una caja reductora, un potenciómetro conectado al eje de salida y una pequeña placa controladora que compara la lectura del potenciómetro con una consigna que llega desde el exterior. El controlador hace girar el motor en el sentido que reduce el error y se detiene cuando la posición coincide. Desde el lado de la cámara nada de esto es visible: simplemente le indicas al servo a dónde ir.
3.16.1. La señal PWM¶
Un servo recibe su consigna como una señal PWM a una frecuencia de fotograma fija de 50 Hz, donde el ancho de pulso selecciona la posición:
Un pulso de 1,0 ms lleva el eje a un extremo de su recorrido.
Un pulso de 1,5 ms deja el eje en el centro.
Un pulso de 2,0 ms lleva el eje al otro extremo.
Cualquier valor intermedio se asigna a una posición intermedia.
El fotograma PWM del servo dura 20 ms; el ancho de pulso (1,0 – 2,0 ms) selecciona la posición.¶
A diferencia de los LED y los motores, el servo no promedia el PWM. El propio ancho de pulso es el comando: la lógica interna del servo mide cada pulso, fija su objetivo en consecuencia y hace girar el motor hasta que la salida coincide. El ciclo de trabajo como fracción (entre el 5 % y el 10 % en todo el rango) es incidental: lo que importa es el ancho de pulso absoluto, que es lo que el software necesita controlar.
3.16.2. Cableado¶
Los servos de aficionado usan un conector de tres hilos:
Alimentación (habitualmente rojo): la alimentación propia del servo, normalmente de 4,8 V a 6 V. No alimentes el servo desde el riel de 3,3 V de la cámara – no puede suministrar la corriente de bloqueo y el riel sufrirá una caída de tensión.
Tierra (habitualmente negro o marrón): el camino de retorno para la alimentación del servo, conectado a la tierra de la cámara para que la señal también tenga una referencia común.
Señal (habitualmente blanco, amarillo o naranja): la línea PWM proveniente del GPIO de la cámara.
3.16.3. Código¶
duty_u16() funcionaría, pero fija el ciclo de trabajo como fracción del periodo – incómodo para una señal en la que lo que importa es el ancho de pulso absoluto y el periodo es fijo. duty_ns() fija el ancho de pulso directamente en nanosegundos:
from machine import PWM, Pin
servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000) # centre
La portadora es de 50 Hz (periodo de 20 ms); el tiempo en alto de cada ciclo es exactamente de 1500 µs. Una pequeña función auxiliar hace explícita la correspondencia entre posición y pulso:
def set_position(angle):
# angle: 0..180 degrees mapped to 1.0..2.0 ms
pulse_us = 1000 + (angle * 1000) // 180
servo.duty_ns(pulse_us * 1000)
set_position(0) # full one way
set_position(90) # centre
set_position(180) # full the other way
Un barrido lento a lo largo del rango:
import time
for angle in range(0, 181, 5):
set_position(angle)
time.sleep_ms(20)
for angle in range(180, -1, -5):
set_position(angle)
time.sleep_ms(20)
El rango de 1,0 – 2,0 ms es el estándar, pero muchos servos aceptan un rango más amplio (a menudo de 500 µs a 2500 µs) para el recorrido completo. La hoja de datos del servo indica los límites exactos del ancho de pulso; valores fuera de ese rango pueden estrellar el motor contra sus topes mecánicos.
Para un servo con un rango no estándar, lleva los límites a constantes y parametriza la correspondencia:
PULSE_MIN_US = 500 # full one way (from the data sheet)
PULSE_MAX_US = 2500 # full the other way
def set_position(angle):
span_us = PULSE_MAX_US - PULSE_MIN_US
pulse_us = PULSE_MIN_US + (angle * span_us) // 180
servo.duty_ns(pulse_us * 1000)