Shield Servo

Le shield Servo pilote jusqu’à huit servomoteurs de modélisme en parallèle depuis l’OpenMV Cam via I2C, à l’aide d’un contrôleur de servo / PWM PCA9685.

Shield Servo

Pour la fiche technique complète, les photos et les commandes, consultez la page produit du shield Servo.

Points forts

  • Contrôleur de servo / PWM PCA9685

  • Huit canaux de servo indépendants via I2C

  • Empilable avec le shield Moteur et le shield Pan and Tilt

Brochage

Brochage du shield Servo

Référence des broches

Broche

Fonction

P4

I²C SCL — horloge vers le PCA9685

P5

I²C SDA — données vers le PCA9685

Rail VIN

Alimente les servos (depuis la broche VIN de la caméra)

Rail 3,3 V

Alimente la logique du PCA9685

Rail GND

Masse commune des servos et de la caméra

L’adresse I²C par défaut est 0x40. Connectez le pont à souder intégré pour faire passer l’adresse à 0x60.

Note

Le shield prélève l’alimentation des servos directement sur la broche VIN de la caméra. L’USB n’alimente VIN sur aucune OpenMV Cam, VIN doit donc être fournie en externe (batterie, alimentation d’établi ou similaire) — choisissez une source dimensionnée pour le courant de blocage cumulé de tous les servos que vous prévoyez de piloter.

Utilisation

Pilotez les huit canaux de servo via le PCA9685 sur I²C. La plage de largeur d’impulsion varie d’un servo à l’autre, ajustez donc MIN_US et MAX_US aux vôtres — les valeurs typiques se situent autour de 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)

Le PCA9685 gère aussi du PWM 12 bits général à n’importe quelle fréquence — réutilisez la même classe avec set_duty (0–4095) pour, par exemple, faire varier la luminosité d’une LED sur le canal 0 à 1 kHz. La fonction auxiliaire ci-dessous met à l’échelle un flottant 0,0–100,0 % sur la plage de rapport cyclique 0–4095 de la puce

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)