Tutorial · Intermedio · 18 min di lettura

Controlla i servomotori con PCA9685 (driver PWM I²C)

Controlla più servomotori con un PCA9685 via I²C: imposta la frequenza PWM, calibra la larghezza d'impulso dagli angoli e alimentali in sicurezza.

Un microcontrollore dispone soltanto di pochi canali PWM hardware. Va bene per uno o due servomotori, ma un braccio robotico ne ha quattro, un esapodo ne ha diciotto e Arduino esaurisce i timer molto prima che tu esaurisca le articolazioni. Il PCA9685 risolve il problema: una piccola scheda genera sedici segnali PWM indipendenti in hardware e tu controlli tutti questi segnali mediante soltanto due cavi I²C. Ecco come azioni ogni articolazione del simulatore di braccio robotico su hardware reale.

Schema etichettato di una scheda driver PWM/servomotore PCA9685 a 16 canali: sedici connettori a tre pin per servomotore lungo il bordo superiore, il chip PCA9685 al centro, un connettore di controllo I²C a cinque pin a sinistra, ponticelli di indirizzo per la saldatura e a destra un morsetto a vite V+ per l'alimentazione dei servomotori.
Sedici canali PWM in hardware, controllati mediante due pin I²C; la corrente dei servomotori proviene dal morsetto V+ separato, mai dal microcontrollore. Scarica SVG

Perché non collegare direttamente i servomotori all’Arduino?

Per due motivi. Primo, i pin: la scheda Uno dispone di timer sufficienti per pochi oggetti Servo prima che la libreria inizi a litigare con sé stessa. Secondo, e più importante, l’alimentazione: un servomotore può assorbire 500–700 mA quando è bloccato e quattro in movimento possono assorbire diversi ampere. Questa corrente non può provenire dal pin da 5 V dell’Arduino: causa il brown-out della scheda e la riavvia a metà movimento. Il PCA9685 risolve entrambi i problemi. Delega la generazione PWM a un chip dedicato e instrada la corrente dei servomotori dal proprio morsetto V+, tenendo la corrente elevata completamente lontana dalla logica.

Imposta la frequenza PWM

Ogni servomotore hobbistico prevede un segnale di controllo a 50 Hz, cioè un impulso ogni 20 ms. Il PCA9685 imposta una sola frequenza per tutto il chip, quindi impostala una volta in setup():

#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);  // default I²C address

void setup() {
  pwm.begin();
  pwm.setPWMFreq(50);   // 50 Hz — the standard servo refresh rate
}

Ora tutti e sedici i canali emettono impulsi a 50 Hz. L’angolo mantenuto da ciascun servomotore è determinato dalla larghezza del suo impulso, non dalla frequenza: questa è la parte che controlli per ogni canale.

Dall’angolo alla larghezza d’impulso: la taratura che conta

Un servomotore interpreta la larghezza dell’impulso come comando di posizione: circa 1 ms per 0°, 1.5 ms per il centro, 2 ms per 180°, ripetuto 50 volte al secondo. Questo è lo stesso codice che converte la larghezza dell’impulso in angolo usato dallo SG90; il PCA9685 si limita a generarlo in hardware.

Schema di controllo di un servomotore: un segnale PWM a 50 Hz la cui larghezza d'impulso determina l'angolo del servomotore. Un impulso di 1 millisecondo comanda 0 gradi, 1.5 millisecondi comanda 90 gradi e 2 millisecondi comandano 180 gradi, mostrati su quadranti.
Il servomotore legge la larghezza dell'impulso, non la tensione: 1 ms corrisponde a 0°, 1.5 ms al centro e 2 ms alla corsa massima, ripetuti 50 volte al secondo. Scarica SVG

Il PCA9685 non accetta direttamente i millisecondi. Divide ogni periodo di 20 ms in 4096 conteggi (risoluzione a 12 bit) e tu gli indichi per quanti conteggi l’impulso resta alto. A 50 Hz, un periodo completo è 4096 conteggi = 20 ms, quindi:

  • 1 ms ≈ 205 conteggi (0°)
  • 1.5 ms ≈ 307 conteggi (90°)
  • 2 ms ≈ 410 conteggi (180°)

Questi sono i valori nominali. I servomotori reali variano: lo stesso SG90 potrebbe fermarsi a 130 e raggiungere 490. Questo è l’unico valore che devi tarare. Memorizza un minimo e un massimo per ogni servomotore e mappa il tuo angolo in questo intervallo:

// Calibrate these two per servo by eye — see "Gotchas" below.
const int SERVO_MIN = 130;   // counts at the servo's 0° hard stop
const int SERVO_MAX = 490;   // counts at the servo's 180° hard stop

int angleToCount(int deg) {
  return map(deg, 0, 180, SERVO_MIN, SERVO_MAX);
}

Saltare la taratura è il motivo per cui un comando di «90°» raggiunge 78° su un’articolazione e 96° su un’altra, e il motivo per cui un braccio costruito con servomotori non tarati non raggiunge mai esattamente la posa richiesta dal risolutore di cinematica inversa.

Cablaggio: due linee di alimentazione, una massa

  • Logica — VCC, GND, SDA, SCL dall’Arduino. Questo alimenta soltanto il chip.
  • Alimentazione dei servomotori — un’alimentazione separata da 5–6 V collegata al morsetto a vite V+, dimensionata per la corrente di stallo di tutti i servomotori contemporaneamente, non per il loro assorbimento a riposo.
  • Massa comune — la massa dell’alimentazione e quella dell’Arduino devono essere collegate insieme, altrimenti il segnale PWM non ha riferimento e i servomotori si muovono a scatti oppure ignorano i comandi. Lo stesso vale per le linee I²C che trasportano i comandi.

Monta un condensatore tra V+ e massa per assorbire il picco di corrente all’avvio dei servomotori; la scheda di sviluppo PCA9685 dispone di un’esposizione predisposta esattamente a questo scopo.

Il codice: muovi un’articolazione

#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);

const int SERVO_MIN = 130;
const int SERVO_MAX = 490;

int angleToCount(int deg) {
  return map(deg, 0, 180, SERVO_MIN, SERVO_MAX);
}

void setServo(uint8_t channel, int deg) {
  pwm.setPWM(channel, 0, angleToCount(deg));  // on at count 0, off at the angle count
}

void setup() {
  pwm.begin();
  pwm.setPWMFreq(50);
  setServo(0, 90);   // base to centre
  setServo(1, 45);   // shoulder
  setServo(2, 120);  // elbow
  setServo(3, 10);   // gripper open
}

void loop() {}

Ogni setPWM(channel, 0, count) significa «attiva questo canale all’inizio del periodo e disattivalo dopo count scatti temporali». Fai scorrere un’articolazione aumentando l’angolo in un anello e inserisci un breve delay() tra i passi, così il servomotore ha tempo di muoversi invece di spostarsi di scatto.

Inconvenienti

  • Tarala SERVO_MIN / SERVO_MAX per ogni servomotore. Comanda 0°, osserva dove si trova effettivamente il braccetto e modifica leggermente il conteggio finché non corrisponde. Ripeti a 180°. Dieci minuti qui ti risparmiano ogni problema di posa a valle.
  • Non alimentare mai V+ dall’Arduino. Un servomotore potrebbe sopravvivere; quattro causeranno il brown-out e il riavvio della scheda.
  • Dimensiona l’alimentazione per lo stallo, non per il funzionamento a riposo. Un’alimentazione sottodimensionata cala di tensione quando più servomotori si muovono insieme e l’intera scheda vibra.
  • Controlla l’indirizzo. L’indirizzo predefinito è 0x40. Collega i ponticelli di saldatura per concatenare le schede e passa il nuovo indirizzo al costruttore.
  • Muoviti con delicatezza. Avvicinarti a un obiettivo a incrementi è preferibile rispetto a spostarti su di esso di scatto: riduce il picco di corrente e fa risparmiare agli ingranaggi in plastica.
  • Il canale della pinza è quello che si surriscalda. Ogni altra articolazione raggiunge il proprio angolo e resta a riposo; una pinza che trattiene un oggetto è un servomotore bloccato contro l’oggetto e assorbe continuamente circa mezzo ampere. Aprila appena hai posizionato il pezzo e consulta forza, stallo e cedevolezza del servomotore della pinza per capire perché una risoluzione PWM più fine non ti dà una forza più precisa.

Una volta che ogni articolazione risponde a un angolo, il braccio è pronto per la geometria: trasformare un punto di destinazione negli angoli delle articolazioni che lo raggiungono, che è esattamente ciò per cui servono la cinematica inversa di un braccio a due link e il simulatore di braccio robotico.

Esplora il grafo

Fa parte di queste costruzioni

Progetti e percorsi di apprendimento che includono questo tutorial.

Per approfondire

Fonti