Руководство · Средний · 18 min read

Управление сервоприводами через PCA9685 (драйвер PWM по I²C)

Управляйте сервоприводами через PCA9685 по I²C: задайте частоту PWM, преобразуйте угол в ширину импульса и обеспечьте безопасное питание.

У микроконтроллера есть лишь несколько аппаратных каналов PWM. Для одного или двух сервоприводов этого достаточно, но у роботизированной руки четыре, у гексапода восемнадцать, и Arduino заканчиваются таймерами задолго до того, как закончатся суставы. PCA9685 решает эту задачу: одна небольшая плата формирует шестнадцать независимых сигналов PWM аппаратно, а управление всеми ими идёт всего по двум проводам I²C. Именно так на реальном оборудовании управляют каждым суставом симулятора роботизированной руки.

Подписанная схема 16-канальной платы драйвера PWM/сервоприводов PCA9685: шестнадцать трёхпиновых разъёмов для сервоприводов сверху, кристалл PCA9685 в центре, пятипиновый управляющий разъём I²C слева, перемычки для адреса и винтовой разъём V+ для питания сервоприводов справа.
Шестнадцать каналов PWM аппаратно, управляемых по двум выводам I²C; ток сервоприводов приходит от отдельного разъёма V+, а не от микроконтроллера. Скачать SVG

Почему не подключить сервоприводы напрямую к Arduino

Две причины. Первая — выводы: у Uno хватает таймеров лишь для нескольких объектов Servo, после чего библиотека начинает конфликтовать сама с собой. Вторая, более важная, — питание: при срыве сервопривод может потреблять 500–700 mA, а четыре движущихся одновременно — несколько ампер. Такой ток не может идти от вывода 5 V Arduino: плата проседает и перезагружается посреди движения. PCA9685 исправляет обе проблемы. Формирование PWM выполняет отдельная микросхема, а ток сервоприводов поступает от собственного разъёма V+, полностью удерживая большой ток от логики.

Задайте частоту PWM

Каждый хобби-сервопривод ожидает управляющий сигнал 50 Hz — один импульс каждые 20 ms. PCA9685 задаёт одну частоту для всей микросхемы, поэтому установите её один раз в 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
}

Теперь все шестнадцать каналов работают с частотой 50 Hz. Угол, который удерживает каждый сервопривод, задаётся шириной его импульса, а не частотой — это часть, которую вы контролируете отдельно для каждого канала.

От угла к ширине импульса — важная калибровка

Сервопривод считывает ширину импульса как команду положения: примерно 1 ms для 0°, 1.5 ms для центра, 2 ms для 180°, повторяемые 50 раз в секунду. SG90 управляется по тому же принципу — ширина импульса задаёт угол; PCA9685 просто формирует его аппаратно.

Схема управления сервоприводом: сигнал PWM 50 Hz, ширина импульса которого задаёт угол. Импульс длительностью 1 миллисекунда задаёт 0 градусов, 1.5 миллисекунды — 90 градусов, а 2 миллисекунды — 180 градусов; это показано на круговых шкалах.
Сервопривод считывает ширину импульса, а не напряжение: 1 ms — это 0°, 1.5 ms — центр, 2 ms — полный ход, повторяемые 50 раз в секунду. Скачать SVG

PCA9685 не принимает миллисекунды напрямую. Микросхема делит каждый период 20 ms на 4096 отсчётов (разрешение 12 бит), а вы указываете, сколько отсчётов импульс остаётся высоким. При 50 Hz полный период равен 4096 отсчётов = 20 ms, поэтому:

  • 1 ms ≈ 205 отсчётов (0°)
  • 1.5 ms ≈ 307 отсчётов (90°)
  • 2 ms ≈ 410 отсчётов (180°)

Это номинальные значения. Реальные сервоприводы различаются: один и тот же SG90 может останавливаться на 130 и доходить до 490. Это единственное число, которое необходимо откалибровать. Сохраните минимум и максимум для каждого сервопривода и отображайте угол в этот диапазон:

// 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);
}

Пропуск калибровки — причина того, что команда «90°» даёт фактический угол 78° на одном суставе и 96° на другом, а рука на неоткалиброванных сервоприводах никогда точно не достигает позы, запрошенной решателем обратной кинематики.

Подключение: две силовые шины, одна земля

  • Логика — VCC, GND, SDA, SCL от Arduino. Это питает только микросхему.
  • Питание сервоприводов — отдельный источник 5–6 V на винтовой разъём V+, рассчитанный на ток срыва всех сервоприводов одновременно, а не на их потребление в покое.
  • Общая земля — земля источника и земля Arduino должны быть соединены, иначе у PWM-сигнала нет опорного уровня, а сервоприводы дёргаются или игнорируют команды. То же относится к линиям I²C, передающим команды.

Добавьте конденсатор между V+ и землёй, чтобы поглотить скачок тока при запуске сервоприводов; на плате PCA9685 для этого есть посадочное место.

Код: перемещение сустава

#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() {}

Каждый setPWM(channel, 0, count) означает «включить этот канал в начале периода и выключить после count тактов». Для плавного движения сустава меняйте угол в цикле с коротким delay() между шагами, чтобы сервопривод успел двигаться, а не перескакивал.

Подводные камни

  • Откалибруйте SERVO_MIN / SERVO_MAX для каждого сервопривода. Подайте команду 0°, запомните, где фактически находится рычаг сервопривода, и слегка измените отсчёт до совпадения. Сделайте то же при 180°. Десять минут здесь предотвращают ошибки в каждом дальнейшем положении.
  • Никогда не питайте V+ от Arduino. Один сервопривод может выдержать; четыре вызовут просадку и перезагрузку платы.
  • Рассчитывайте источник на срыв, а не на покой. Слишком слабый источник проседает, когда несколько сервоприводов двигаются одновременно, и вся плата дрожит.
  • Проверьте адрес. По умолчанию 0x40. Для каскада плат соедините перемычки и передайте новый адрес конструктору.
  • Двигайтесь плавно. Постепенное приближение к цели лучше скачка: снижает скачок тока и бережнее к пластиковым шестерням.
  • Канал захвата — тот, который перегревается. Остальные суставы достигают угла и простаивают; захват, удерживающий объект, упирается в него и постоянно потребляет около половины ампера. Откройте его сразу после установки детали; в силе захвата, срыве и податливости сервопривода-захвата объясняется, почему более высокое разрешение PWM не обеспечивает более точное регулирование усилия.

Когда каждый сустав отвечает на угол, следующий шаг — геометрия: превращение целевой точки в углы суставов, которые её достигают. Именно для этого нужны обратная кинематика двухзвенной руки и симулятор роботизированной руки.

Исследуйте граф

Входит в эти сборки

Проекты и учебные пути, в которые входит это руководство.

Дополнительные материалы

Источники