Servo Shield

De Servo Shield stuurt tot acht hobbyservo’s parallel aan vanaf de OpenMV Cam via I2C, met behulp van een PCA9685 servo- / PWM-controller.

Servo Shield

Voor de volledige datasheet, foto’s en bestelinformatie, zie de productpagina van de Servo Shield.

Hoogtepunten

  • PCA9685 servo- / PWM-controller

  • Acht onafhankelijke servokanalen via I2C

  • Stapelbaar met de Motor Shield en de Pan and Tilt Shield

Pinout

Servo Shield Pinout

Pinreferentie

Pin

Functie

P4

I²C SCL — klok naar de PCA9685

P5

I²C SDA — data naar de PCA9685

VIN-rail

Voedt de servo’s (vanaf de VIN-pin van de camera)

3.3V-rail

Voedt de logica van de PCA9685

GND-rail

Gemeenschappelijke massa van servo en camera

Het standaard I²C-adres is 0x40. Verbind de soldeerbrug aan boord om het adres naar 0x60 te verplaatsen.

Notitie

De shield trekt servovoeding rechtstreeks van de VIN-pin van de camera. USB voedt VIN niet op enige OpenMV Cam, dus VIN moet extern worden geleverd (batterij, labvoeding of dergelijke) — kies een bron die geschikt is voor de gecombineerde blokkeerstroom van elke servo die je van plan bent aan te sturen.

Gebruik

Stuur de acht servokanalen aan via de PCA9685 over I²C. Het pulsbreedtebereik varieert per servo, dus stem MIN_US en MAX_US af op de jouwe — typische waarden liggen rond 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)

De PCA9685 verwerkt ook algemene 12-bit PWM op elke frequentie — hergebruik dezelfde klasse met set_duty (0–4095) om bijvoorbeeld een LED op kanaal 0 te dimmen bij 1 kHz. De helper hieronder schaalt een 0,0–100,0%-float naar het 0–4095 duty-bereik van de 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)