Servo Shield

Servo Shield điều khiển lên đến tám servo hobby song song từ OpenMV Cam qua I2C, sử dụng bộ điều khiển servo/PWM PCA9685.

Servo Shield

Để xem datasheet đầy đủ, ảnh và đặt hàng, hãy xem trang sản phẩm Servo Shield.

Tính năng nổi bật

  • Bộ điều khiển servo/PWM PCA9685

  • Tám kênh servo độc lập qua I2C

  • Có thể ghép chồng với Motor Shield và Pan and Tilt Shield

Sơ đồ chân

Servo Shield Pinout

Tham chiếu chân

Chân

Chức năng

P4

I²C SCL — xung nhịp đến PCA9685

P5

I²C SDA — dữ liệu đến PCA9685

Rail VIN

Cấp nguồn cho servo (từ chân VIN của camera)

Rail 3.3V

Cấp nguồn cho logic PCA9685

Rail GND

Chân đất chung của servo và camera

Địa chỉ I²C mặc định là 0x40. Kết nối cầu hàn trên bo để chuyển địa chỉ sang 0x60.

Ghi chú

Shield lấy nguồn servo trực tiếp từ chân VIN của camera. USB không cấp VIN trên bất kỳ OpenMV Cam nào, vì vậy VIN phải được cung cấp từ bên ngoài (pin, nguồn điện bàn hoặc tương tự) — chọn nguồn có công suất đủ cho tổng dòng khởi động của tất cả servo bạn dự định điều khiển.

Sử dụng

Điều khiển tám kênh servo qua PCA9685 trên I²C. Phạm vi độ rộng xung thay đổi giữa các servo, vì vậy hãy tinh chỉnh MIN_USMAX_US cho phù hợp với servo của bạn — giá trị điển hình là khoảng 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 cũng xử lý PWM 12-bit thông thường ở bất kỳ tần số nào — tái sử dụng cùng lớp với set_duty (0–4095) để, ví dụ, làm mờ đèn LED trên kênh 0 ở 1 kHz. Hàm trợ giúp bên dưới chuyển đổi số thực 0,0–100,0% sang dải duty 0–4095 của 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)