Слайдер для камеры я собрал за один вечер, а потом три вечера выяснял, почему он не едет. План был простой: платформа с телефоном отъезжает ровно на десять сантиметров, замирает на три секунды, камера делает кадр — и так сорок кадров подряд для таймлапса. Сервопривод для этой работы не годился в принципе: он умеет махать рогом от нуля до ста восьмидесяти градусов и не знает, сколько оборотов уже сделал. Моторчик постоянного тока с редуктором крутился бы, пока подано питание, — тоже мимо: ему плевать на сантиметры. Нужен был мотор, который считает собственные шаги.
Я заказал 28BYJ-48 — маленький шаговый двигатель с платой ULN2003, за полторы сотни рублей. Подключил по первой попавшейся картинке, залил скетч — и получил не вращение, а дрожание: мотор гудел, трясся и грелся, но вал стоял как вкопанный. Оказалось, шаговику без правильного порядка импульсов на четырёх катушках всё равно, чего вы от него хотите, — он просто дёргается на месте.
В этом уроке разберём принцип шагов, посчитаем, откуда берутся 2048 шагов на оборот, поймём, зачем между Arduino и мотором стоит ULN2003, и запустим мотор в симуляторе: один оборот вперёд, один назад, с логом в Serial.
Чем шаговый мотор не похож на обычный
У двигателя постоянного тока всё как у вентилятора: подал 5 вольт — крутится, подал 12 — крутится быстрее. Быстро, дёшево, но вслепую: ни плата, ни вы не знаете, на какой угол повернулся вал. Позицию приходится узнавать внешними датчиками — энкодером или концевиком, а это отдельные детали, провода и код.
У сервопривода датчик угла уже внутри корпуса: команда myservo.write(90) ставит вал на девяносто градусов, и он держит её. Но диапазон ограничен примерно 180 градусами, дальше — механический упор, который легко сломать. Кругового вращения у серво нет и не будет.
Шаговый двигатель устроен принципиально иначе: у него нет «непрерывного» вращения вообще. Вал поворачивается дискретными шагами, и каждый шаг — это переключение обмоток. Посчитали шаги — знаете, где вал: 2048 шагов — ровно один оборот вала 28BYJ-48. Никаких датчиков позиции, чистая арифметика. Плата за это двоякая: скорость низкая, а ток мотор жрёт даже стоя на месте — об этом у нас будет отдельный и печальный разговор ниже.
Откуда 2048 и зачем ULN2003
Внутри корпуса 28BYJ-48 прячутся две вещи: сам мотор и пластиковый редуктор. Мотор за один полный цикл переключения обмоток делает 32 шага — по 11,25 градуса на шаг. Для точных механизмов грубовато, поэтому производитель добавил редуктор с передаточным числом 1:64: моторчик делает 64 оборота, выходной вал — один.
Перемножаем: 32 × 64 = 2048 шагов на оборот вала. Отсюда и точность: один шаг — это 360 / 2048 = 0,176 градуса. Редуктор заодно умножает момент: вал уверенно проворачивает рычаг длиной 3 см с грузом около ста граммов. В описаниях встречается число 4096 — это полушаговый режим, когда обмотки переключаются через половину шага: движение плавнее, шагов вдвое больше. Классическая библиотека Stepper работает полными шагами, поэтому ей мы честно говорим 2048. Полушаги и микрошаги — тема продвинутых драйверов, до них доберёмся в другом разделе.
Теперь о посреднике. Катушка 28BYJ-48 при 5 вольтах тянет порядка 90-100 миллиампер, а в полношаговом режиме работают сразу две катушки — под 200 мА и выше. Пин Arduino способен отдать максимум 40 мА, и то не каждый. Плюс при переключении индуктивной нагрузки летят выбросы напряжения, способные убить пин за один раз. Поэтому между платой и мотором ставят микросхему ULN2003 — массив из семи транзисторов Дарлингтона: каждый канал держит до 500 мА, защитные диоды уже внутри.
Плата-переходник, которая продаётся в комплекте с мотором, — это ULN2003, разъём и четыре светодиода: они мигают в такт переключению обмоток, и по ним сразу видно, жива ли последовательность. Подключение: красный провод мотора — плюс питания 5 В, цветной шлейф — в гнездо платы (перепутать нельзя, разъём один), а четыре сигнальные линии IN1-IN4 идут на пины D8, D10, D9, D11 — да, именно в таком порядке, не по возрастанию. Библиотека Stepper ожидает обмотки в своей внутренней последовательности, и связка IN1 → 8, IN2 → 10, IN3 → 9, IN4 → 11 сложилась как стандартный рецепт, работающий без сюрпризов. Землю платы соедините с GND Arduino — общая земля обязательна, иначе сигналы повиснут в воздухе.
#include <Stepper.h> const int STEPS_PER_REV = 2048; // полных шагов на оборот вала // порядок пинов: IN1 -> D8, IN2 -> D10, IN3 -> D9, IN4 -> D11Stepper stepper(STEPS_PER_REV, 8, 10, 9, 11); void setup() { stepper.setSpeed(5); // 5 оборотов в минуту Serial.begin(9600); Serial.println("Motor ready");} void loop() { Serial.println("Odin oborot po chasovoj"); stepper.step(STEPS_PER_REV); // +2048 шагов = ровно оборот delay(1000); Serial.println("Odin oborot nazad"); stepper.step(-STEPS_PER_REV); // минус = обратное направление delay(1000);}Здесь всего три новых слова. Конструктор Stepper stepper(STEPS_PER_REV, 8, 10, 9, 11) создаёт объект мотора: первый аргумент — число шагов на оборот, дальше четыре пина в том порядке, о котором мы договорились выше. setSpeed(5) задаёт скорость в оборотах в минуту: при 2048 шагах на оборот это около 171 шага в секунду. Метод step(2048) проворачивает вал на указанное число шагов и возвращается только тогда, когда они сделаны, — программа ждёт. Отрицательное число крутит назад.
Заметьте: в loop() нет ни одного digitalWrite — вся четырёхтактная последовательность обмоток зашита внутри библиотеки. Это удобно, но скрывает физику, поэтому я советую один раз посмотреть на светодиоды платы ULN2003 на настоящем железе: они должны переключаться по кругу — IN1, IN2, IN3, IN4, снова IN1. Мигают по кругу, а вал стоит? Мотор отсоединён или сорван шаг.
В скетчах для симулятора ниже строк #include не будет — симулятору заголовки не нужны. В настоящей Arduino IDE они обязательны: #include <Stepper.h> в начале каждого скетча с мотором.
Первый запуск и эксперименты
В симуляторе мотор уже подключён к пинам 8, 10, 9, 11 через ULN2003 — схема собрана, можно запускать. Смотрите в Serial: программа честно отчитывается о каждом обороте. Обратите внимание на паузу между сообщениями — это и есть время блокировки внутри step(), которое растёт со скоростью вниз и с числом шагов вверх.
После симулятора — три задачи. Решайте их прямо здесь, не выходя из урока: каждая следующая опирается на предыдущую, а третья готовит почву для разговора о срыве шагов.
- Заставьте мотор сделать пол-оборота и отдохнуть десять секунд. Подсказка: пол-оборота — это 1024 шага, пауза — delay(10000).
- Поверните вал на 45 градусов. Посчитайте шаги на бумажке и проверьте: 45 × 2048 / 360 = 256.
- Заведите переменную
int speedRpm = 5;, используйте её в setSpeed и поднимайте по единице до 15. Следите, когда мотор начнёт пропускать шаги — у каждого экземпляра предел свой.
- Шаговый двигатель вращается дискретными шагами: 28BYJ-48 — 2048 шагов на оборот (32 шага мотора × редуктор 1:64)
- Один шаг = 0,176°; позиция считается арифметикой, без датчиков
- Катушке нужно ~100 мА, пину доступно 40 мА — поэтому между ними ULN2003 (до 500 мА на канал, защитные диоды внутри)
- Подключение: IN1→D8, IN2→D10, IN3→D9, IN4→D11; конструктор Stepper(2048, 8, 10, 9, 11)
- step(N) блокирует loop() до конца движения; отрицательное N — вращение назад
- После шага обмотки остаются под напряжением: мотор держит позицию и ест ~240 мА
- 1. Сколько полных шагов делает вал 28BYJ-48 за один оборот?
- 2. Зачем между Arduino и мотором стоит плата ULN2003?
- 3. Что произойдёт после вызова stepper.step(2048) при setSpeed(5)?
- 4. Какой вызов повернёт вал в обратную сторону?
- 5. Мотор стоит на месте, но греется и ест около 240 мА. Почему?
- 6. Почему сигнальные провода подключают в порядке 8, 10, 9, 11?
Во втором уроке раздела выжмем из мотора скорость и точность: что на самом деле делает setSpeed, почему выше 15 RPM мотор гудит и не крутится, как повернуть вал ровно на 37 градусов и как организовать движение туда-обратно, не замораживая loop(). И — обещанный ледоход: выключим обмотки после остановки и наконец остудим мотор.
Частые вопросы по теме урока
- Сколько полных шагов делает вал 28BYJ-48 за один оборот?
- Внутренний ротор делает 32 шага, редуктор 1:64 умножает: 32 × 64 = 2048. 4096 — это полушаговый режим. 2048
- Зачем между Arduino и мотором стоит плата ULN2003?
- Катушкам нужно порядка 90-100 мА каждой, пин отдаёт максимум 40 мА. ULN2003 — транзисторные ключи с защитными диодами. Пин Arduino не выдаёт нужный ток — каналы ULN2003 держат до 500 мА
- Что произойдёт после вызова stepper.step(2048) при setSpeed(5)?
- 5 RPM — один оборот за 60 секунд. step() возвращается только после последнего шага, все это время loop() стоит. Вал провернётся на оборот примерно за минуту, и всё это время loop() заблокирован
- Какой вызов повернёт вал в обратную сторону?
- Направление задаётся знаком числа шагов. setSpeed принимает положительные обороты в минуту. stepper.step(-512)
- Мотор стоит на месте, но греется и ест около 240 мА. Почему?
- Ток удержания — нормальный режим шаговика: обмотки запитаны, вал зафиксирован. Снимается обнулением четырёх пинов. Библиотека оставляет обмотки под напряжением, чтобы держать позицию
- Почему сигнальные провода подключают в порядке 8, 10, 9, 11?
- Четырёхтактная последовательность библиотеки идёт по кругу, и порядок пинов в конструкторе подгоняется под неё. Библиотека Stepper ожидает обмотки в своей внутренней последовательности — это стандартный рецепт для 28BYJ-48