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.

Servo Shield

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

Distribución de pines del Servo Shield

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)