NEMA17 + A4988 і AccelStepper: розгін, гальмування і чому крокові двигуни зриваються
Кроковий двигун не може одразу стартувати на повній швидкості: ротор не встигає за полем і пропускає кроки. Бібліотека AccelStepper будує трапецієподібний профіль швидкості. Налаштовуємо A4988, мікрокрок і прискорення, керуємо рухом командами з порту.
Про проєкт
NEMA17 — стандартний кроковий двигун 3D-принтерів і ЧПК: 200 кроків на оберт (1.8°), крутний момент 0.3–0.5 Н·м. Керує ним драйвер A4988: один імпульс на STEP — один крок, рівень на DIR — напрямок. Але якщо просто почати слати імпульси з частотою 1000 Гц, двигун загуде й не зрушить: ротор з інерцією не встигає за полем, що обертається. Потрібен розгін, і бібліотека AccelStepper робить його сама.
Що знадобиться
- ESP32 DevKit
- Двигун NEMA17 (наприклад 17HS4401) + драйвер A4988 (або DRV8825)
- Живлення 12 В ≥ 2 А і конденсатор 100 мкФ на VMOT
- Бібліотека AccelStepper
Схема
| A4988 | Підключення |
|---|---|
| VMOT / GND | +12 В / GND (конденсатор 100 мкФ біля виводів!) |
| VDD / GND | 3V3 / GND ESP32 |
| STEP | GPIO26 |
| DIR | GPIO27 |
| EN | GPIO25 (активний LOW) |
| RESET ↔ SLEEP | з'єднати перемичкою |
| 1A 1B 2A 2B | обмотки двигуна |
| MS1–MS3 | мікрокрок (див. нижче) |
Усі землі спільні. Ніколи не від'єднуйте двигун від увімкненого драйвера: викид напруги вбиває A4988.
Струм виставляється підстроювальним резистором ще до першого запуску: Vref = I × 8 × Rs. Для типового клону з R100 (0.1 Ом) і двигуна на 1.2 А це ≈ 0.8 × 1.2 × 0.85 ≈ 0.8 В. Беремо 85 % від номіналу, щоб драйвер не перегрівався.
Мікрокрок
Перемички MS1–MS3 ділять повний крок: 1/2, 1/4, 1/8, 1/16. На 1/16 двигун робить 3200 мікрокроків на оберт і крутиться тихіше й плавніше, але для тієї ж швидкості потрібно в 16 разів більше імпульсів.
Чому потрібен розгін
Двигун може «підхопити» лише певну частоту старту (pull-in rate, кілька сотень кроків за секунду з місця). Щоб вийти на 1000–2000 кроків/с, швидкість треба нарощувати поступово. Якщо поспішати, ротор відстане на крок, і двигун зірветься: загуде, завібрує, зупиниться, а позиція в програмі розійдеться з реальною.
AccelStepper рахує інтервал до кожного наступного кроку так, щоб швидкість росла лінійно (трапецієподібний профіль): розгін → рух на maxSpeed → гальмування до точки зупинки.
Код
// NEMA17 + A4988 з AccelStepper: розгін/гальмування, їзда туди-назад і команди з порту
#include <AccelStepper.h>
const int STEP_PIN = 26, DIR_PIN = 27, EN_PIN = 25;
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
long target = 800; // 4 оберти при повному кроці (200 кроків на оберт)
bool shuttle = true; // їздити туди-назад, поки не надійде команда
void setup() {
Serial.begin(115200);
stepper.setEnablePin(EN_PIN);
stepper.setPinsInverted(false, false, true); // EN у A4988 активний LOW
stepper.enableOutputs();
stepper.setMaxSpeed(800); // кроків/с
stepper.setAcceleration(1600); // кроків/с²
stepper.moveTo(target);
Serial.println("Команди: go <кроки>, speed <кроки/с>, accel <кроки/с2>, stop");
}
void loop() {
if (shuttle && stepper.distanceToGo() == 0) { // доїхали — розвертаємося
target = -target;
stepper.moveTo(target);
}
stepper.run(); // викликати якомога частіше: крок робиться лише коли настав час
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.startsWith("go ")) { shuttle = false; stepper.moveTo(cmd.substring(3).toInt()); }
else if (cmd.startsWith("speed ")) stepper.setMaxSpeed(cmd.substring(6).toFloat());
else if (cmd.startsWith("accel ")) stepper.setAcceleration(cmd.substring(6).toFloat());
else if (cmd == "stop") { shuttle = false; stepper.stop(); } // плавне гальмування
Serial.printf("позиція %ld, ціль %ld\n", stepper.currentPosition(), stepper.targetPosition());
}
}
Правила AccelStepper
run()має викликатися постійно. Жоднихdelay()уloop(): за 100 мс затримки двигун пропустить сотні кроків. Довгі дії розбивайте на частини черезmillis().moveTo()— абсолютна позиція,move()— відносна.stop()гальмує з заданим прискоренням, а не зупиняє миттєво.runSpeed()+setSpeed()— рух зі сталою швидкістю без розгону, наприклад для конвеєра. Стартувати так можна лише на невеликій швидкості.runToPosition()блокує програму до прибуття. Зручно для простих сценаріїв.- Той самий AccelStepper крутить і 28BYJ-48 з ULN2003:
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);. Зверніть увагу на порядок виводів.
Експерименти в симуляторі
- Надішліть
accel 100000: розгін стане майже миттєвим, і симулятор покаже, що двигун зривається й губить кроки. - Поставте у властивостях двигуна «важке навантаження»: максимальні швидкість і прискорення зменшаться.
- Спробуйте мікрокрок 1/16 і
speed 12800, щоб побачити ту саму швидкість обертання при в 16 разів більшій кількості імпульсів.