База знаний · Датчики и модули
Шаговые двигатели и Arduino: 28BYJ-48, NEMA17 и драйверы
2048 шагов на оборот, ток задаётся отвёрткой, а не в скетче, и остановленный мотор греется не меньше едущего.
Шаговый двигатель — единственный мотор, которому можно сказать «повернись на девяносто градусов» и не ставить при этом ни одного датчика. Он не крутится плавно: вал перескакивает из одного устойчивого положения в соседнее, а плата просто считает эти перескоки. Отсюда и станки, и 3D-принтеры, и шторы, которые открываются ровно наполовину. Всё остальное в теме — про то, как заставить его не пропускать шаги и не раскаляться.
Два двигателя, которые называют одним словом
Под «шаговиком для Arduino» почти всегда имеют в виду один из двух совершенно разных моторов. Их роднит только принцип, а всё остальное — питание, ток, драйвер, цена — отличается на порядок.
| Двигатель | Обмотки | Питание | Ток | Шагов на оборот | Момент | Драйвер |
|---|---|---|---|---|---|---|
| 28BYJ-48 | 5 проводов, униполярный | 5 В | около 165 мА | 2048 полных, 4096 полушагов | 0,3 кг·см | плата на ULN2003 |
| NEMA17 (42×42) | 4 провода, биполярный | 12…24 В | 1,33 А на обмотку | 200 полных, до 3200 микрошагов | 2,2 кг·см | A4988, DRV8825, TB6600 |
Разница в моменте — семикратная, и это при том, что 28BYJ-48 идёт с редуктором, а NEMA17 крутит вал напрямую. Маленький двигатель хорош там, где нужно медленно и аккуратно повернуть что-то лёгкое: заслонку, стрелку, зеркальце. Всё, что должно двигать само себя или тянуть груз, начинается с NEMA17.
Из чего складывается один шаг
Внутри двигателя четыре обмотки и намагниченный ротор. Обмотки включают по очереди — ротор каждый раз доворачивается к той, что сейчас под током. Порядок включения и есть вся «наука»: от него зависят и число шагов в обороте, и момент, и то, насколько громко мотор работает.
Обратите внимание на средний режим: в нём в каждый момент включены две обмотки, а не одна. Момент от этого больше, но и ток вдвое выше. Именно так — и только так — работает штатная библиотека Arduino: в её исходнике зашита ровно эта четвёрка состояний, никакого выбора она не предлагает.
Почему оборот — это 2048 шагов, и почему не совсем
Ротор 28BYJ-48 делает полный оборот за 32 шага. Дальше идёт редуктор, и в паспорте у него написано «1:64». Перемножаем — получаем те самые 2048 шагов на оборот выходного вала, а в режиме полушага 4096. Эти числа подставляют в скетчи по всему интернету.
Спор о том, 2048 там или чуть меньше, идёт много лет, и у него есть простое объяснение: у разных партий двигателя разные шестерни. Один набор зубьев даёт ровно 64, другой — 63,684. Разница в полпроцента выглядит пустяком ровно до тех пор, пока вы не начинаете считать обороты: при «неудачном» редукторе команда на 2048 шагов повернёт вал не на 360 градусов, а почти на 362. За двести оборотов набежит целый лишний оборот.
Проверяется это за минуту: поставьте метку на валу, прогоните десять оборотов подряд и посмотрите, вернулась ли метка на место. Практический вывод одинаков для обоих случаев — шаговик не помнит, где он. После включения питания он считает текущее положение нулём, а накопленную ошибку исправить нечем. Поэтому во всём, где важна абсолютная точность, ставят концевой выключатель и в начале работы приезжают на него — это и называется «поиск нуля».
Как всё это соединяется
Плата на ULN2003 — это даже не драйвер в строгом смысле, а семь транзисторных ключей: каждый просто притягивает свой конец обмотки к минусу. Ток она не измеряет и не ограничивает, поэтому и подходит только к моторам, которые не могут взять лишнего.
У этой простоты есть цена, о которой не пишут. Транзисторный ключ не замыкается «в ноль»: по листу данных на ULN2003 при токе 100 мА на нём падает 0,9 вольта, а при 200 мА — целый вольт. Обмотке сопротивлением 50 Ом достаётся не 5 вольт, а около 4,1 — и ток получается не расчётные 100 мА, а примерно 82. Момент падает ровно на столько же. Это одна из причин, по которой 28BYJ-48 в жизни кажется слабее, чем в паспорте.
Один такой двигатель (около 165 мА в режиме полного шага) вывод 5 В платы вытянет. Два — уже нет: берите отдельный источник и соединяйте минусы.
Первый скетч: библиотека уже внутри
Библиотеку Stepper не надо ни искать, ни устанавливать: она встроена и в Arduino IDE, и в Trema IDE. Достаточно написать #include — среда подложит её сама.
#include <Stepper.h>
// Двигатель 28BYJ-48 через плату драйвера на ULN2003.
// Полных шагов на оборот выходного вала: 32 шага ротора × редуктор 1:64.
const int STEPS_PER_REV = 2048;
// Порядок выводов НЕ подряд, и это не опечатка. Библиотека ждёт, что
// первая пара чисел — концы одной обмотки, вторая пара — другой.
// На плате драйвера половинки одной обмотки сидят на IN1 и IN3,
// половинки второй — на IN2 и IN4. Отсюда порядок IN1, IN3, IN2, IN4.
// Выводы платы: IN1 к 8, IN2 к 9, IN3 к 10, IN4 к 11.
Stepper motor(STEPS_PER_REV, 8, 10, 9, 11);
void setup() {
Serial.begin(9600);
// Скорость в оборотах в минуту. Выше 15 этот двигатель обычно срывается:
// ротор перестаёт успевать за импульсами и вал дребезжит на месте.
motor.setSpeed(10);
}
void loop() {
Serial.println("Оборот по часовой стрелке");
motor.step(STEPS_PER_REV);
delay(500);
Serial.println("Оборот против часовой");
motor.step(-STEPS_PER_REV);
delay(500);
}
Самая частая причина «купил, подключил, а он только жужжит» — вот эта строка с выводами. Порядок в ней не подряд: 8, 10, 9, 11. Это не опечатка и не суеверие, а прямое следствие того, как устроена библиотека. Она гоняет обмотки парами: первое и второе число — концы одной обмотки, третье и четвёртое — другой. А на плате драйвера половинки первой обмотки выведены на IN1 и IN3, второй — на IN2 и IN4. Отсюда и перестановка.
Скорость задаётся в оборотах в минуту, и речь именно о выходном вале. Выше пятнадцати оборотов этот двигатель обычно уже срывается: ротор перестаёт успевать за импульсами, вал останавливается и начинает дребезжать на месте.
Почему во время движения плата глохнет
Запустите первый скетч и попробуйте в это же время что-нибудь нажать или вывести в монитор порта. Ничего не выйдет. Метод step() устроен как цикл: он крутится, сравнивая время, и не отдаёт управление, пока не отсчитает все шаги до последнего. Оборот на скорости десять оборотов в минуту — это шесть секунд, в течение которых плата занята исключительно мотором.
Это ровно та же беда, что и с delay(), только незаметнее: никакой задержки в вашем коде нет, вы вызываете «просто метод библиотеки». Пока двигатель один и делать больше нечего — это не мешает. Как только появляется кнопка «стоп», датчик или второй мотор, от штатной библиотеки приходится уходить.
Второй скетч: движение, которое не отнимает плату
AccelStepper решает обе проблемы сразу: она не блокирует выполнение и умеет разгон. Разгон — не украшение: шаговик, которому сразу дали высокую скорость, часто просто не трогается с места, потому что ротор физически не успевает за первым же импульсом.
#include <AccelStepper.h>
// HALF4WIRE — полушаг: 4096 шагов на оборот вместо 2048, вдвое мельче
// и заметно тише. Порядок выводов тот же: IN1, IN3, IN2, IN4.
AccelStepper motor(AccelStepper::HALF4WIRE, 8, 10, 9, 11);
const long HALF_STEPS_PER_REV = 4096;
const int PIN_BUTTON = 2;
void setup() {
Serial.begin(9600);
pinMode(PIN_BUTTON, INPUT_PULLUP);
motor.setMaxSpeed(700); // шагов в секунду
motor.setAcceleration(300); // прибавка скорости за секунду
motor.moveTo(HALF_STEPS_PER_REV);
}
void loop() {
// run() делает НЕ БОЛЬШЕ одного шага за вызов. Поэтому в loop()
// не должно быть ни одной задержки delay(): каждая пропущенная
// проверка — это пропущенный шаг и рваное движение.
motor.run();
if (motor.distanceToGo() == 0) {
motor.moveTo(motor.currentPosition() == 0 ? HALF_STEPS_PER_REV : 0);
}
// Плата всё это время свободна и продолжает слушать кнопку.
if (digitalRead(PIN_BUTTON) == LOW) {
motor.stop(); // плавно тормозит, а не встаёт колом
Serial.println("Стоп по кнопке");
}
}
Ключевая мысль — в комментарии к run(). Этот метод делает не больше одного шага за вызов. Значит, всё остальное в loop() должно выполняться быстро, а любая задержка превращается в пропущенные шаги и рваное движение. Ни одного delay() в таком скетче быть не должно.
Удобство стоит памяти. Мы собрали три одинаковых по смыслу скетча под Arduino Uno и сравнили — цифры в таблице получены компилятором, а не взяты из документации.
| Способ | ОЗУ, байт | Флеш, байт | За что платим | Что не так |
|---|---|---|---|---|
| Stepper 1.1.3 | 35 | 2 230 | уже внутри среды, ставить нечего | только полный шаг, и step() держит плату до конца движения |
| AccelStepper 1.64 | 119 | 5 956 | разгон, торможение, полушаг, движение не мешает остальному коду | 5,5 КБ флеша сверх пустого скетча — шестая часть памяти Uno |
| Без библиотеки | 9 | 964 | 520 байт сверх пустого скетча, полный контроль над импульсами | разгон, позицию и границы придётся писать самому |
Для сравнения: пустой скетч занимает 9 байт ОЗУ и 444 байта флеша. То есть AccelStepper обходится в 5,5 килобайта программной памяти — шестую часть всего, что есть у Uno. На плате, где уже живут дисплей и датчики, это может оказаться решающим. Сам объект тоже не бесплатный: 68 байт против 26 у штатной библиотеки.
Ещё одна деталь, о которой почти не пишут: AccelStepper распространяется по лицензии GPL V3. Для домашних поделок и уроков это ничего не меняет, но если вы делаете изделие на продажу и не собираетесь открывать его исходники, автор требует покупать коммерческую лицензию. Это написано прямо в заголовочном файле библиотеки.
И про скорость. В документации назван предел: около 4000 шагов в секунду на плате с тактовой частотой 16 МГц. Это не ограничение двигателя, а потолок самой платы — она просто не успевает выдавать импульсы чаще.
Взрослый двигатель и взрослый драйвер
Возьмём NEMA17 из нашего магазина. В карточке написано: номинальное напряжение 12…24 В, ток фазы 1,33 А, сопротивление обмотки 2,1 Ом. Перемножьте ток на сопротивление — получится 2,8 вольта. Именно столько нужно обмотке, чтобы взять свои 1,33 ампера. Откуда тогда двенадцать?
Обмотка — это катушка, и ток в ней нарастает не мгновенно. Чем быстрее мотор шагает, тем меньше времени на каждый шаг и тем меньше ток успевает дорасти. Высокое напряжение нужно не «для мощности», а чтобы разогнать ток быстрее. А чтобы он при этом не улетел за паспортное значение, драйвер измеряет его и обрывает питание, как только достигнута заданная величина, — и так тысячи раз в секунду. Поэтому напряжение источника и напряжение обмотки — это разные вещи, и питать такой мотор от 2,8 вольта было бы ошибкой.
| Драйвер | Питание двигателя | Ток на обмотку | Дробление шага | Когда брать |
|---|---|---|---|---|
| ULN2003 | 5 или 12 В | не ограничивает, только замыкает обмотку | нет | только для 28BYJ-48 и подобных слабых моторов |
| A4988 | 8…35 В | 1 А, с радиатором 2 А | до 1/16 | обычный выбор для NEMA17 |
| DRV8825 | 8,2…45 В | 1,5 А, с радиатором 2,2 А | до 1/32 | тот же разъём, но мощнее и мельче шаг |
| TB6600 | 9…42 В | до 4 А | до 1/32 | большие двигатели, станки, отдельная коробочка |
Единственная настройка, которую нельзя пропустить
На плате драйвера есть крошечный подстроечный резистор. Им задают предельный ток обмотки, и это не «тонкая доводка», а обязательный шаг: драйвер приезжает с завода настроенным как попало. Слишком большой ток — двигатель и микросхема раскаляются. Слишком маленький — мотор пропускает шаги под нагрузкой.
Формула взята из листа данных Allegro на сам чип и выглядит так: предельный ток равен опорному напряжению, делённому на восемь и на сопротивление токочувствительного резистора. Значит, для настройки её надо развернуть: напряжение = ток × 8 × сопротивление. Номинал резистора написан прямо на нём: «R100» — это 0,1 Ом, «R068» — 0,068 Ом, «R050» — 0,05 Ом. На наших модулях A4988 стоят резисторы на 0,1 Ом, у оригинальных плат Pololu с 2017 года — 0,068 Ом, и опорное напряжение для одного и того же тока у них отличается почти в полтора раза. Это и есть причина, по которой чужие «поставьте 0,7 вольта» из интернета не работают.
Обратите внимание на неприятную арифметику: наш NEMA17 просит 1,33 ампера, а A4988 без радиатора держит один. Либо радиатор и обдув, либо сознательно занижаем ток и миримся с меньшим моментом. Третьего нет.
Третий скетч: два провода и никакой библиотеки
С таким драйвером управление сводится к двум сигналам: импульс на STEP — один шаг, уровень на DIR — сторона вращения. Библиотека для этого не нужна вовсе.
// Драйвер A4988 или DRV8825: всего два управляющих вывода.
// Импульс на STEP — один шаг, уровень на DIR — сторона вращения.
const int PIN_STEP = 3;
const int PIN_DIR = 4;
const int PIN_ENABLE = 5;
// У двигателя NEMA17 двести полных шагов на оборот. Дробление шага
// задаётся перемычками MS1...MS3 на самой плате драйвера, а не здесь:
// скетчу остаётся только знать, на сколько частей поделён шаг.
const int MICROSTEP = 16;
const long STEPS_PER_REV = 200L * MICROSTEP;
void turn(long steps, bool clockwise, unsigned int pauseUs) {
digitalWrite(PIN_DIR, clockwise ? HIGH : LOW);
delayMicroseconds(5); // драйверу нужно успеть заметить смену стороны
for (long i = 0; i < steps; i++) {
digitalWrite(PIN_STEP, HIGH);
delayMicroseconds(3);
digitalWrite(PIN_STEP, LOW);
delayMicroseconds(pauseUs);
}
}
void setup() {
pinMode(PIN_STEP, OUTPUT);
pinMode(PIN_DIR, OUTPUT);
pinMode(PIN_ENABLE, OUTPUT);
digitalWrite(PIN_ENABLE, LOW); // ноль на ENABLE включает драйвер
}
void loop() {
turn(STEPS_PER_REV, true, 300);
delay(500);
turn(STEPS_PER_REV, false, 300);
// Пока двигатель просто стоит, обмотки остаются под током и греются.
// Если удерживать вал не нужно — выключаем драйвер и он остывает.
digitalWrite(PIN_ENABLE, HIGH);
delay(3000);
digitalWrite(PIN_ENABLE, LOW);
}
Последние строки — про то, о чём вспоминают, когда двигатель уже обжёг пальцы. Остановленный шаговый двигатель продолжает есть ток. Он не «отдыхает», а активно удерживает вал, и греется при этом точно так же, как на ходу. Если удерживать положение не требуется — выключайте драйвер выводом ENABLE, и всё остынет.
Микрошаг: за плавность платят скоростью
Три перемычки на драйвере делят каждый шаг на части. Ток в обмотки подаётся не «включено-выключено», а ступеньками, и ротор останавливается между обычными положениями. Движение становится плавнее и заметно тише.
| MS1 · MS2 · MS3 | Дробление | Шагов на оборот NEMA17 | Как ощущается |
|---|---|---|---|
| 0 · 0 · 0 | полный шаг | 200 | самый громкий и самый резкий |
| 1 · 0 · 0 | 1/2 | 400 | тише, момент почти не теряется |
| 0 · 1 · 0 | 1/4 | 800 | разумная середина |
| 1 · 1 · 0 | 1/8 | 1600 | плавно, но скорость уже ограничена платой |
| 1 · 1 · 1 | 1/16 | 3200 | красиво и медленно: Uno вытянет около 75 об/мин |
Здесь и прячется расплата. При дроблении 1/16 на один оборот уходит 3200 импульсов, а плата на 16 МГц выдаёт около 4000 импульсов в секунду — значит, быстрее чем примерно 75 оборотов в минуту вы не поедете. Тем же двигателем полным шагом та же плата крутила бы в шестнадцать раз быстрее. И ещё: дробление задаётся перемычками на плате драйвера, а не в скетче. Скетчу остаётся только знать, на сколько частей поделён шаг, чтобы правильно посчитать обороты.
Что нужно купить
Главная ловушка при покупке — название карточки. Двигатель 28BYJ-48 на 5 вольт — 253 ₽ продаётся отдельно от драйвера, хотя в адресе страницы и мелькает ULN2003. Плату к нему берут отдельно: есть обычная плата драйвера — 86 ₽ и адаптер, позволяющий подключить этот двигатель к A4988 — 140 ₽, если захочется микрошага на дешёвом моторе.
Для всего серьёзного — NEMA17 42×42×34 — 980 ₽ (в комплекте идёт четырёхпроводной шлейф) и драйвер A4988 с радиатором — 147 ₽. Если двигателей несколько, удобнее Motor Shield — 740 ₽: драйверы вставляются в готовые гнёзда, и не нужно разводить питание проводами. Отдельный источник на 12 вольт обязателен в любом случае — от USB такой мотор не работает.
Что пошло не так
| Что видно | В чём дело | Что делать |
|---|---|---|
| Гудит, греется, но вал стоит | Перепутан порядок выводов в скетче | Для платы на ULN2003 порядок IN1, IN3, IN2, IN4 — половинки одной обмотки идут первой парой |
| Вал дёргается вперёд-назад на месте | Провода одной обмотки разведены по разным парам | Прозвоните обмотки тестером: концы одной обмотки звонятся между собой, разные обмотки — нет |
| Крутится вхолостую, но встаёт под нагрузкой | Мало тока или слишком резкий старт | Поднимите ток подстроечником до паспортного, добавьте разгон через AccelStepper |
| Драйвер раскалился за минуту | Ток выставлен выше того, что плата тянет без радиатора | A4988 без радиатора — 1 А, DRV8825 — 1,5 А. Выше только с радиатором и обдувом |
| Пока мотор едет, плата не отвечает | Штатный метод step() крутит цикл до последнего шага | Переходите на AccelStepper: run() делает один шаг и сразу возвращает управление |
| Мотор стоит, а обмотки горячие | Так и задумано: остановленный шаговик держит вал током | Если удерживать не нужно, выключайте драйвер выводом ENABLE |
| Драйвер сгорел после перестановки мотора | Разъём двигателя переставляли при поданном питании | Питание двигателя выключается первым, включается последним — это самая частая причина смерти A4988 |
| Ничего не происходит, драйвер холодный | Выводы RESET и SLEEP висят в воздухе | Соедините их между собой перемычкой: без этого чип остаётся в спящем режиме |
Отдельно стоит запомнить последнюю строку про питание. Драйверы A4988 чаще всего погибают не от перегрева и не от ошибки в скетче, а от того, что разъём двигателя переставили, забыв выключить питание. В листе данных об этом сказано прямым текстом, и это тот редкий случай, когда предупреждение производителя стоит воспринимать буквально.
Частые вопросы
Сколько шагов на оборот у 28BYJ-48?
Ротор делает 32 шага, редуктор в паспорте 1:64 — итого 2048 полных шагов на оборот выходного вала и 4096 полушагов. Но у разных партий разные шестерни: один набор даёт ровно 64, другой 63,684. Во втором случае команда на 2048 шагов повернёт вал почти на 362 градуса вместо 360.
Почему шаговый двигатель гудит, но не крутится?
Почти всегда перепутан порядок выводов. Библиотека ждёт, что первая пара чисел — концы одной обмотки, а на плате драйвера половинки одной обмотки выведены на IN1 и IN3. Поэтому правильный порядок в скетче IN1, IN3, IN2, IN4, а не подряд.
Как настроить ток на драйвере A4988?
По формуле из листа данных: предельный ток равен опорному напряжению, делённому на 8 и на сопротивление токочувствительного резистора. Для настройки её разворачивают: напряжение = ток × 8 × сопротивление. Номинал написан на резисторе: R100 это 0,1 Ом, R068 — 0,068 Ом. Мерить между GND и центром подстроечника при отключённом питании двигателя.
Почему NEMA17 питают от 12 В, если обмотке хватает 2,8 В?
Обмотка — катушка, ток в ней нарастает не мгновенно, и на быстрых шагах он просто не успевает дорасти. Высокое напряжение разгоняет ток быстрее, а драйвер измеряет его и обрывает, как только достигнута заданная величина. Поэтому напряжение источника и напряжение обмотки — разные вещи.
Почему плата не отвечает, пока крутится двигатель?
Метод step() штатной библиотеки Stepper устроен как цикл и не отдаёт управление, пока не отсчитает все шаги. Оборот на скорости 10 об/мин — это шесть секунд полного молчания. Лечится переходом на AccelStepper: её метод run() делает один шаг и сразу возвращает управление.
Что даёт микрошаг и чем за него платят?
Плавность и тишину: шаг делится на части, ротор встаёт между обычными положениями. Платят скоростью. При дроблении 1/16 на оборот NEMA17 уходит 3200 импульсов, а плата на 16 МГц выдаёт около 4000 импульсов в секунду — быстрее 75 оборотов в минуту не выйдет.
Почему шаговый двигатель греется, когда стоит?
Потому что остановленный шаговик не отдыхает, а удерживает вал током, и греется так же, как на ходу. Если удерживать положение не нужно, выключайте драйвер выводом ENABLE — обмотки обесточатся и всё остынет.
Читайте также
Обновлено: 25 августа 2026
