Шторку теплицы я перевёл с ручного привода на шаговик за один вечер, а на второй день чуть не вернул обратно. На испытаниях я выставил setSpeed(6), и всё было красиво: заслонка ползла ровно, счёт шагов сходился с расчётом. Через неделю мне захотелось ускорить открытие, и я поставил 12. Мотор издал ровный гул, светодиоды на ULN2003 весело забегали по кругу, а вал не сдвинулся ни на градус. Снизил до 8 — поехало, будто ничего не случилось. Это был мой первый живой срыв шагов: мотор исправен, драйвер исправен, скетч честен — а вращения нет.
Коварство срыва в том, что для программы его не существует: step() отсчитывает положенные такты, отчитывается о выполнении, и счётчик позиции уверенно показывает цифру, которой на валу нет. Теплица простояла открытой всю ночь, потому что скетч был уверен, что закрыл её. Ловить срыв по Serial бесполезно — программа не знает о провале; его ловят ушами и глазами: ровный гул без вращения, дрожь корпуса, стрелка на месте при бегущих светодиодах.
В уроке про скорость и позиционирование мы уже посчитали арифметику RPM и нашли практический потолок 28BYJ-48 — 10-12 оборотов в минуту без нагрузки. Сегодня копнём под этот потолок: почему он вообще существует, как момент уходит с ростом частоты, зачем мотору разгон и что делать с вибрацией. После урока симптом «жужжит, но не крутит» будет расшифровываться за минуту, а не за три вечера, как у меня тогда.
Почему момент падает с частотой
Первая причина — индуктивность обмоток. Катушка не пропускает ток мгновенно: магнитное поле нарастает какое-то время, и именно оно тянет ротор. При 6 RPM один шаг занимает почти 4,9 миллисекунды — ток успевает вырасти до рабочих 90 мА, поле полное, момент максимальный. При 20 RPM на такт остаётся 1,46 миллисекунды — ток в обмотке не досыпает до номинала, поле слабее, и мотор тянет из последних сил. Момент падает с частотой не потому, что мотор устал, а потому, что электрика не успевает: чем короче такт, тем меньше тока в обмотке в каждый момент.
Вторая причина — инерция. Ротор вместе с шестернями редуктора — это масса, которую каждый шаг разгоняет и останавливает заново; в анатомии 28BYJ-48 мы видели, сколько пластиковых пар крутится внутри. При 10 RPM это 341 такт в секунду — 341 мини-рывка, и каждый должен быть доехан; не доехал один — ползёт очередь. На высоких тактах ротор не доезжает до следующего положения, поле уже шагнуло дальше, и ротор вечно догоняет ушедшее равновесие. Третья причина — вибрация: на некоторых частотах ротор начинает качаться между соседними положениями, дрожь раскачивается и съедает и без того поделившийся момент.
К вибрации добавлю личное наблюдение с границей применимости: мой экземпляр с консольным рычагом дрожал заметнее всего в середине диапазона, около 9-11 RPM, а смена скорости на 10-15 процентов вверх или вниз лечила дрожь на глазах. И главное правило, ради которого написан весь этот абзац: 28BYJ-48 начинайте с 5-10 RPM и поднимайте по 1-2, слушая мотор на каждом шаге. Ускорять этот мотор рывком — как заводить машину с толкача на склоне: иногда прокатит, чаще — нет.
| Скорость, RPM | Такт, мс | Тяга по моим замерам | Что происходит |
|---|---|---|---|
| 5 | 5,9 | Максимум | Рабочая зона: тянет груз с запасом, старт уверенный |
| 10 | 2,9 | Около 80 процентов | Норма без нагрузки, с лёгким грузом — на пределе |
| 15 | 1,95 | Около 60 процентов | Лотерея: отдельные экземпляры срываются уже на старте |
| 20 и выше | 1,46 и меньше | Меньше половины | Гул и дрожь, вал стоит: честный срыв шагов |
#include <Stepper.h> const int STEPS_PER_REV = 2048; Stepper stepper(STEPS_PER_REV, 8, 10, 9, 11); int rpm = 4; // старт с безопасной скорости void setup() { stepper.setSpeed(rpm); Serial.begin(9600);} void loop() { for (int p = 0; p < 2048; p += 256) { // оборот порциями unsigned long t0 = millis(); stepper.step(256); Serial.print("rpm="); Serial.print(rpm); Serial.print(" portiya_ms="); Serial.println(millis() - t0); rpm = rpm + 2; // разгон: по 2 RPM на порцию if (rpm > 12) { rpm = 12; } stepper.setSpeed(rpm); } delay(3000);}Разбор по местам. Старт с 4 RPM — страховка: самая тяжёлая работа у шаговика — тронуться, на ходу он берёт скорость охотнее, потому что ротор уже качается между положениями. Прибавка по 2 RPM на порцию в 256 шагов — мягкая: в Serial видно, как portiya_ms падает с 1,9 секунды при 4 RPM до 0,9 при 8, и мотор между порциями успевает устояться. Если в loop() живут кнопки или датчики, порции нарезают мельче и разносят по времени — миллис-цикл вместо delay оставляет плате дыхание между порциями. Потолок 12 здесь не догма, а мой предел для шторки с грузом: у вашего экземпляра потолок свой, и его стоит найти экспериментом на своём грузе. И напоминание из урока про библиотеку: setSpeed вызывается до первого step, иначе фазы мелькают без паузы — это второй, самодельный способ получить жужжание без вращения.
Диагностика «жужжит, но не крутит» теперь раскладывается по цепочке. Смотрите на светодиоды ULN2003: бегут по кругу — электрика и порядок фаз живы, значит, виноваты скорость или груз; снижайте вдвое и снимайте нагрузку. Бегут, но не по кругу — перепутан порядок пинов, возвращайтесь к партитуре тактов. Горят две и не мигают — скетч застрял в удержании, это другая история. Если электрика чиста, а мотор на сниженной скорости всё равно стоит — переходите на полушаг, где такты вдвое мельче и вибрация ниже, или поднимайте питание до 6 вольт: оба хода покупают момент ценой вдвое большего числа тактов.
Что покажет симулятор
Сразу честно: симулятор идеален, и это здесь не комплимент. Его мотор не срывается никогда — стрелка доберётся до цели хоть на 20 RPM, хоть на 30, поэтому живой гул без вращения вы в браузере не услышите. Позицию и логику он показывает безупречно, а физику срыва выносит в Serial: скетч печатает модель момента — долю тяги, которую мотор имел бы на настоящей плате при текущей частоте. Модель — это линеаризация моих настольных замеров: от сотни процентов на 5 RPM мотор теряет около четырёх процентов за каждый следующий оборот в минуту. Ваша кривая может отличаться, но направление просадки у всех одно — вниз. Потенциометр на A0 задаёт обороты в пределах 3-20.
Что попробовать. Сначала поверните потенциометр в минимум: rpm=3-5, model_moment_pct= около сотни — это рабочая зона, и portiya_ms на порцию из 128 шагов лежит около секунды с четвертью. Потом выкрутите вверх до 15-20: доля момента падает до 60 и ниже, и скетч печатает предупреждение о срыве. Читать числа удобно в Serial-мониторе: строки идут парами имя=значение. Сверьте пару цифр с расчётом: 128 шагов при 5 RPM — это 128 умножить на 60000 и разделить на 5 и на 2048, примерно 750 миллисекунд, и Serial покажет около того. Расчёт сошёлся — модель времени честная, а вот модель момента живёт только в Serial: стрелка доедет при любой скорости, чего настоящая плата вам не пообещает.
- Момент падает с частотой: при 5 RPM такт 5,9 мс и ток успевает набраться, при 20 RPM такт 1,46 мс — обмотка недобирает свои 90 мА
- Три причины срыва: индуктивность обмоток, инерция ротора с редуктором, вибрация на средних частотах — лечится сдвигом скорости на 10-15 процентов
- 28BYJ-48 стартует с 5-10 RPM; разгоняйте ступенями по 1-2 RPM каждые пару сотен шагов
- Жужжит, но не крутит: сначала светодиоды (электрика), потом скорость вдвое и снять груз, потом питание 6 В и полушаг
- Срыв невидим для программы: step() отчитывается честно, счёт позиции после срыва врёт — проверяйте мотор ушами и светодиодами
- 1. Почему момент шаговика падает с ростом частоты тактов?
- 2. Сколько длится один такт при setSpeed(10) у 28BYJ-48?
- 3. Мотор гудит, светодиоды ULN2003 бегут по кругу, вал стоит. Первое действие?
- 4. Зачем мотору разгонная кривая — ramp?
- 5. Сорвётся ли шаговик в симуляторе при rpm=20?
Соберите урок в три привычки. Первая: любая новая нагрузка — это новая кривая момента, потолок ищите заново, на своём грузе, начиная с 5 RPM. Вторая: любые ускорения — только ступенями; библиотека Stepper разгона не умеет, поэтому ступени строите вы, как в скетче выше. Третья: диагноз ставится по цепочке светодиоды — скорость — питание, а не заменой железа: три вечера, которые я потратил на бракованный мотор, которого не было, — самая дорогая привычка, которую я купил в этом разделе.
У гонок за скоростью есть побочный эффект, который я заметил, когда тепличный мотор переехал в закрытый ящик: он грелся, как кружка с чаем, — и это при полностью остановленном вале. Моё правило для проектов, которые живут месяцами без присмотра: мотор в простое обязан переставать догреваться через час после хода — если градусы продолжают ползти, что-то не так. Ток, который шаговик ест, просто стоя на месте, — тема следующего урока. Там же разберём, какой нагрев для 28BYJ-48 рабочая норма, а какой — повод обесточивать, и посчитаем, сколько стоит дежурство в батарейках.
Частые вопросы по теме урока
- Почему момент шаговика падает с ростом частоты тактов?
- Катушка — индуктивность: ток нарастает со временем. Такт в 1,46 мс при 20 RPM не даёт набрать 90 мА — поле слабее, момент ниже. Индуктивность не даёт току вырасти за короткий такт
- Сколько длится один такт при setSpeed(10) у 28BYJ-48?
- 10 RPM — это 10 умножить на 2048 и разделить на 60, около 341 шага в секунду, то есть 2,9 мс на такт. 2,9 мс
- Мотор гудит, светодиоды ULN2003 бегут по кругу, вал стоит. Первое действие?
- Бегущие по кругу светодиоды — электрика в порядке. Значит, виноваты скорость или момент: снижаем и разгружаем, потом ищем дальше. Снизить скорость вдвое и снять нагрузку
- Зачем мотору разгонная кривая — ramp?
- Тронуться тяжелее, чем ехать: первый такт при высокой скорости — рывок, который ротор с грузом не отрабатывает. Разгон ступенями снимает рывок. Чтобы стартовать с безопасной скорости и не сорваться на первом такте
- Сорвётся ли шаговик в симуляторе при rpm=20?
- Симуляторный мотор никогда не срывается. Физику заменяет модель: model_moment_pct= показывает долю тяги, которая была бы на настоящей плате. Нет, мотор идеален: о риске предупреждает модель в Serial