Servo Shield

Servo Shield mengendalikan hingga delapan servo hobi secara paralel dari OpenMV Cam melalui I2C, menggunakan kontroler servo/PWM PCA9685.

Servo Shield

Untuk datasheet lengkap, foto, dan pemesanan, lihat halaman produk Servo Shield.

Sorotan

  • Kontroler servo/PWM PCA9685

  • Delapan saluran servo independen melalui I2C

  • Dapat ditumpuk dengan Motor Shield dan Pan and Tilt Shield

Pinout

Servo Shield Pinout

Referensi pin

Pin

Fungsi

P4

I²C SCL — clock ke PCA9685

P5

I²C SDA — data ke PCA9685

Rel VIN

Menyuplai servo (dari pin VIN kamera)

Rel 3.3V

Menyuplai logika PCA9685

Rel GND

Ground umum servo dan kamera

Alamat I²C default adalah 0x40. Hubungkan solder bridge on-board untuk memindahkan alamat ke 0x60.

Catatan

Shield mengambil daya servo langsung dari pin VIN kamera. USB tidak menyuplai VIN pada OpenMV Cam mana pun, sehingga VIN harus disuplai secara eksternal (baterai, catu daya meja, atau serupa) — pilih sumber yang mampu menangani arus stall gabungan dari semua servo yang akan dikendalikan.

Penggunaan

Kendalikan delapan saluran servo melalui PCA9685 lewat I²C. Rentang lebar pulsa bervariasi antar servo, jadi sesuaikan MIN_US dan MAX_US dengan servo Anda — nilai tipikal sekitar 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)

PCA9685 juga menangani PWM 12-bit umum pada frekuensi berapa pun — gunakan kembali kelas yang sama dengan set_duty (0–4095) untuk, misalnya, memudarkan LED pada saluran 0 pada 1 kHz. Helper di bawah ini menskalakan float 0,0–100,0% ke rentang duty 0–4095 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)