Servo Shield¶
El Servo Shield controla hasta ocho servos de hobby en paralelo desde la OpenMV Cam a través de I2C, usando un controlador de servos / PWM PCA9685.
Para consultar la hoja de datos completa, fotos e información de compra, visita la página de producto del Servo Shield.
Características destacadas¶
Controlador de servos / PWM PCA9685
Ocho canales de servo independientes a través de I2C
Apilable con el Motor Shield y el Pan and Tilt Shield
Distribución de pines¶
Referencia de pines¶
Pin |
Función |
|---|---|
P4 |
I²C SCL — reloj hacia el PCA9685 |
P5 |
I²C SDA — datos hacia el PCA9685 |
Riel de VIN |
Alimenta los servos (desde el pin VIN de la cámara) |
Riel de 3.3V |
Alimenta la lógica del PCA9685 |
Riel de GND |
Tierra común de los servos y la cámara |
La dirección I²C por defecto es 0x40. Conecta el puente de soldadura integrado para cambiar la dirección a 0x60.
Nota
El shield toma la alimentación de los servos directamente del pin VIN de la cámara. USB no alimenta VIN en ninguna OpenMV Cam, por lo que VIN debe suministrarse externamente (batería, fuente de banco o similar): elige una fuente dimensionada para la corriente de bloqueo combinada de todos los servos que planees controlar.
Uso¶
Controla los ocho canales de servo a través del PCA9685 por I²C. El rango de ancho de pulso varía entre servos, así que ajusta MIN_US y MAX_US para los tuyos: los valores típicos rondan los 1000–2000 µs:
import time
from machine import SoftI2C, Pin
class PCA9685:
"""Minimal PCA9685 driver — 12-bit PWM on any of 8 channels."""
def __init__(self, bus, address=0x40, freq=50):
self._bus = bus
self._addr = address
bus.writeto_mem(address, 0x00, b"\x00") # reset Mode1
prescale = round(25_000_000 / (4096 * freq)) - 1
bus.writeto_mem(address, 0x00, b"\x10") # sleep
bus.writeto_mem(address, 0xFE, bytes([prescale])) # prescale
bus.writeto_mem(address, 0x00, b"\x00") # wake
time.sleep_us(5)
bus.writeto_mem(address, 0x00, b"\xA1") # restart + AI + allcall
self._period_us = 1_000_000 // freq
def set_duty(self, channel, duty):
duty &= 0xFFF # 12-bit
if duty == 0:
on, off = 0, 0x1000 # FULL_OFF
elif duty == 0xFFF:
on, off = 0x1000, 0 # FULL_ON
else:
on, off = 0, duty
self._bus.writeto_mem(
self._addr, 0x06 + 4 * channel,
bytes([on & 0xFF, on >> 8, off & 0xFF, off >> 8]))
def set_us(self, channel, pulse_us):
self.set_duty(channel, (pulse_us * 4096) // self._period_us)
MIN_US = 1000 # full-left pulse width (microseconds)
MAX_US = 2000 # full-right pulse width
bus = SoftI2C(scl=Pin("P4"), sda=Pin("P5"))
pca = PCA9685(bus, address=0x40, freq=50)
def angle(channel, deg):
pca.set_us(channel, MIN_US + (deg * (MAX_US - MIN_US)) // 180)
while True:
for ch in range(8):
angle(ch, 0)
time.sleep_ms(2000)
for ch in range(8):
angle(ch, 180)
time.sleep_ms(2000)
El PCA9685 también gestiona PWM general de 12 bits a cualquier frecuencia: reutiliza la misma clase con set_duty (0–4095) para, por ejemplo, atenuar un LED en el canal 0 a 1 kHz. El asistente de abajo escala un valor flotante de 0,0–100,0 % al rango de ciclo de trabajo 0–4095 del chip:
import time
from machine import SoftI2C, Pin
bus = SoftI2C(scl=Pin("P4"), sda=Pin("P5"))
pca = PCA9685(bus, address=0x40, freq=1000)
def brightness(channel, pct):
pca.set_duty(channel, int(pct * 4095 / 100))
while True:
# Ramp up 0 → 100%.
for pct in range(101):
brightness(0, float(pct))
time.sleep_ms(20)
# Ramp down 100 → 0%.
for pct in reversed(range(101)):
brightness(0, float(pct))
time.sleep_ms(20)