← До всіх проєктів
Автоматизація Початковий

Сервопривід SG90 слідує за потенціометром: ШІМ 50 Гц без бібліотек

Як сервопривід розуміє кут із ширини імпульсу, чому його живлять від 5 В, а не від 3.3, і як отримати імпульс 0.5–2.4 мс напряму через LEDC. Крутимо ручку — крутиться серво.

Складність
Початковий
Час
30 min
Категорія
Автоматизація
Оновлено

Про проєкт

Сервопривід — двигун з редуктором і власним регулятором положення: ви кажете йому кут, він сам туди повертається і тримає. Ним керують жалюзі, заслінки, клешні роботів. Зробимо найпростіше: серво повторює положення ручки потенціометра.

Що знадобиться

  • ESP32 DevKit
  • Сервопривід SG90 (або MG90S з металевими шестернями)
  • Потенціометр 10 кОм
  • Для кількох серво — окреме живлення 5 В ≥ 1 А

Схема

Деталь Провід ESP32
SG90 коричневий (GND) GND
червоний (V+) 5V (VIN)
помаранчевий (сигнал) GPIO13
Потенціометр крайні 3V3 і GND
середній GPIO34

Сервоприводу потрібні 5 В: від 3.3 В він слабкий і тремтить. Сигнальний вхід при цьому нормально сприймає 3.3 В з ESP32. На старті SG90 кидком бере до 500–700 мА. Одне серво USB витримає, а кілька — ні: плата перезавантажуватиметься через просідання напруги (brownout).

Як серво розуміє кут

Кожні 20 мс (50 Гц) серво отримує імпульс, і його ширина задає кут:

Імпульс Кут
~0.5 мс 0°
~1.45 мс 90°
~2.4 мс 180°

Точні межі в різних серво відрізняються, тож їх підбирають так, щоб серво не впиралося в упори й не гуділо.

ШІМ через LEDC

ledcAttach(pin, 50, 14) — 50 Гц із роздільністю 14 біт (0…16383 на весь період 20 мс). Щоб отримати імпульс у мікросекундах, переводимо: duty = us × 16383 / 20000. Приведення до uint32_t потрібне, щоб множення не переповнило 16-бітне int. На ESP32 int 32-бітний, але звичка корисна.

Код

// Серво повторює положення потенціометра (ШІМ 50 Гц через LEDC)
const int SERVO_PIN = 13;
const int POT_PIN = 34;

void writeAngle(int angle) {
  int us = map(angle, 0, 180, 500, 2400);             // ширина імпульсу
  ledcWrite(SERVO_PIN, (uint32_t)us * 16383 / 20000);  // частка від періоду 20 мс
}

void setup() {
  Serial.begin(115200);
  ledcAttach(SERVO_PIN, 50, 14);   // 50 Гц, 14 біт
}

void loop() {
  int angle = map(analogRead(POT_PIN), 0, 4095, 0, 180);
  writeAngle(angle);
  Serial.println(angle);
  delay(50);
}

Бібліотека чи вручну

Бібліотека ESP32Servo робить те саме в один рядок (servo.attach(13); servo.write(90);) і сама розподіляє канали LEDC між кількома сервоприводами. Ручний варіант корисний, щоб розуміти, що відбувається, і коли треба нестандартну частоту чи межі імпульсу.

Корисно знати

  • Тремтіння. Шум АЦП змушує кут «стрибати» на 1–2°. Усередніть кілька вимірювань або ігноруйте зміни менше 2°.
  • Гудіння на місці. Серво під навантаженням постійно підтримує кут і гріється. Коли тримати не треба, вимкніть сигнал: ledcWrite(SERVO_PIN, 0).
  • Спільна земля. Якщо серво живиться від окремого блока, його GND обов'язково з'єднайте з GND ESP32.