Сервопривід SG90 слідує за потенціометром: ШІМ 50 Гц без бібліотек
Як сервопривід розуміє кут із ширини імпульсу, чому його живлять від 5 В, а не від 3.3, і як отримати імпульс 0.5–2.4 мс напряму через LEDC. Крутимо ручку — крутиться серво.
Про проєкт
Сервопривід — двигун з редуктором і власним регулятором положення: ви кажете йому кут, він сам туди повертається і тримає. Ним керують жалюзі, заслінки, клешні роботів. Зробимо найпростіше: серво повторює положення ручки потенціометра.
Що знадобиться
- 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.