Шторка на окне должна была ездить по команде пятнадцать оборотов в минуту — а открылась на треть и встала с ровным рычанием. Счётчик в скетче честно отстучал все двести шагов, мотор гудел, вал стоял. Это было моё первое знакомство с инерцией: ротор не успел за полем, шаги прошли мимо, и команда «с места в карьер» обошлась в вечер диагностики и переписанный скетч. Физику срыва и момент мы считали в отдельном уроке; здесь — как не дать мотору повода срываться: трапеция скорости, посчитанная в шагах в секунду.
Физика в одну строфу. Магнитное поле шагает дискретно и мгновенно: команда пришла — поле уже на новом зубце. Ротор вместе с ремнём, кареткой или шторкой тянет за собой инерцию и на высокой стартовой частоте не успевает дотянуться до следующей позиции: поле ушло на два зубца, вал остался на месте, а счётчик шагов даже не заметил подмены. У типового NEMA 17 на двенадцати вольтах с лёгким валом потолок мгновенного старта — порядка ста-трёхсот шагов в секунду; с ремнём и грузом — вдвое-втрое ниже. Всё, что выше, набирается разгоном.
Все числа урока живут в шагах в секунду, а паспорта моторов — в оборотах в минуту, поэтому держите под рукой перевод: об/мин равны шагам в секунду, умноженным на шестьдесят и делённым на двести. Стартовые сто шагов в секунду — это тридцать об/мин, потолок тысяча двести — триста шестьдесят. Сверяйте свой потолок с паспортной кривой момента: если в паспорте момент гарантирован до шестисот оборотов в минуту, всё, что выше двух тысяч шагов в секунду, — уже работа на остатках характеристики, и запас до срыва нужен вдвое против табличного.
Трапеция — способ выдать мотору ровно ту скорость, которую он способен набрать: разгон по прямой, плато на потолке, торможение зеркально. В этом уроке всё считается в родных единицах драйвера — шагах в секунду: сколько шагов занимает рампа, когда включать торможение и что делать, если ход короче двух рамп. Код — на чистых long без библиотек, чтобы каждую микросекунду было видно; производственный вариант на AccelStepper приложу ссылками. Ручной разгон через интервалы мы уже делали в уроке про рывок и разгон — здесь собираем полный профиль с расчётом рампы.
Три участка хода в цифрах
Арифметика рампы живёт в двух формулах. Число шагов разгона от нуля до потолка: n = v² / (2a). Время разгона: t = v / a. Подставим рабочие числа: потолок тысяча двести шагов в секунду, ускорение три тысячи шагов в секунду за секунду — рампа занимает двести сорок шагов и четыре десятых секунды. Торможение зеркально: те же двести сорок шагов, скорость падает по тому же закону. Между ними — плато, и вся траектория на графике скорости рисует трапецию, откуда профиль и получил имя.
Почему потолок не резиновый: обмотка — индуктивность, ток в ней нарастает не мгновенно. У типовой обмотки с парой ом и единицами миллигенри постоянная времени — около миллисекунды; на полке в сотню шагов в секунду фаза держится десятки миллисекунд, и ток выходит на уставку целиком, а на тысяче полпериода фазы становится сравним с этой миллисекундой — до уставки ток доезжает не весь. Меньше ток — слабее поле — ниже момент: кривая момента в даташите падает с частотой именно поэтому, и у быстрых осей два лекарства — ниже потолок или выше напряжение питания.
Торможение включается не по таймеру, а по остатку пути: как только до цели осталось меньше шагов, чем занимает тормозная рампа на текущей скорости, начинается спуск. Считается это на лету той же формулой v²/(2a). Пропустили момент — мотор проносит цель и гасит скорость уже за её пределами; затормозили раньше — плато срезается, ход растягивается, но не срывается. Правило остатка — центр всей конструкции, и именно его чаще всего не хватает скетчам с гудящими моторами.
Ход короче двух рамп — трапеция не влезает, и профиль складывается в треугольник: разгон до пика v = sqrt(a × N), где N — весь ход, и сразу торможение. Для трёхсот шагов при том же ускорении пик — около девятисот пятидесяти шагов в секунду; потолок тысяча двести даже не достигается, и это нормально: профиль подстраивается под ход, а не ход под профиль. Пытаться дотянуть треугольник до трапеции — значит снова ловить срыв на разгоне.
| Участок | Что происходит | Формула | Числа для v=1200, a=3000 |
|---|---|---|---|
| Разгон | скорость растёт на a/v за каждый шаг | n = v²/(2a) | 240 шагов, 0,4 с |
| Плато | интервал между импульсами постоянен | v = vmax | 1200 шагов/с — это 360 об/мин |
| Торможение | зеркально разгону, по остатку пути | остаток ≤ v²/(2a) | 240 шагов |
| Треугольник | ход короче двух рамп | v_пик = sqrt(a × N) | N=300 → около 950 шагов/с |
const int STEP_PIN = 4;const int DIR_PIN = 3; long vmax = 1200; // потолок, шагов в секундуlong uskorenie = 3000; // шагов в секунду за секунду void shag() { digitalWrite(STEP_PIN, HIGH); delayMicroseconds(3); // ширина импульса против даташитной 1 мкс digitalWrite(STEP_PIN, LOW);} void ehod(long n, int napravlenie) { digitalWrite(DIR_PIN, napravlenie); delayMicroseconds(10); // DIR устаканился до первого фронта long v = 100; // стартовая частота: ротор берёт её с места unsigned long moment = micros(); for (long sdelano = 0; sdelano < n; sdelano++) { long doKontsa = n - sdelano; long rampa = v * v / (2 * uskorenie); // рампа от текущей v if (doKontsa <= rampa) { // торможение по остатку v -= uskorenie / v; if (v < 100) { v = 100; } } else if (v < vmax) { // разгон v += uskorenie / v; if (v > vmax) { v = vmax; } } shag(); while (micros() - moment < 1000000 / v) {} // интервал 1/v секунд moment += 1000000 / v; }} void setup() { pinMode(STEP_PIN, OUTPUT); pinMode(DIR_PIN, OUTPUT);} void loop() { ehod(1200, HIGH); // 6 оборотов: 240 шагов рампы, 720 плато, 240 тормоза delay(2000); ehod(1200, LOW); delay(2000);}Внутри цикла живёт вся математика урока: за шаг длительностью 1/v секунд скорость прирастает на a/v шагов в секунду, всё в целых числах, без float и накопления погрешности. busy-wait на micros держит частоту точнее delay, который квантует время по миллисекунде и ломает рампу на верхних скоростях. Стартовая частота — сто шагов в секунду: поле стартует не с нуля, а с ползучей скорости, которую ротор с лёгкой нагрузкой берёт с места без всякой рампы; у маленьких моторов эта цифра ниже.
Потолок софтовой генерации — сам по себе ограничитель: digitalWrite на Uno стоит около пяти микросекунд, плюс арифметика рампы, и честный потолок такого цикла — четыре-пять тысяч шагов в секунду. Для тысячи двухсот запас троекратный, но помните о нём, поднимая vmax. Дальше — таймеры или библиотека: у AccelStepper внутри та же трапеция, вылизанная годами, а его maxSpeed и acceleration — те же v и a из этого урока, только с английскими именами и готовыми проверками.
На верхней полке рампы добавляется арифметика, которую на полусотне шагов в секунду можно не замечать. Интервал между фронтами равен единице, делённой на скорость: при четырёх тысячах шагов в секунду это двести пятьдесят микросекунд, а драйвер между фронтом и срезом просит минимум — микросекунду у A4988 и почти две у DRV8825. Запас кажется огромным, пока в кадр не войдут собственные пять микросекунд digitalWrite и арифметика рампы. Генератор, который ради скорости режет импульс ниже даташитного минимума, теряет шаги на самом быстром участке хода — там, где каждая потеря дороже всего.
Стенд: трапеция по фазам
Симулятор рисует вал, скетч показывает скелет профиля: скорость идёт ступенями — несколько на разгоне, плато, зеркально на торможении. В реальном скетче выше ступени сливаются в плавную рампу, здесь они разрежены нарочно: каждый Serial-отпечаток — участок, который на живом моторе занимает десятки миллисекунд. Ползунок A0 режет потолок скорости, кнопка D2 пускает ход на шесть оборотов, светодиод D12 горит, пока вал едет.
Прогон: пустите ход на низком потолке — рампа занимает те же сто восемьдесят шагов, а плато растягивается на глазах. Поднимите ползунок — время хода съёживается целиком за счёт плато, разгон и торможение не меняются ни на шаг. Это и есть практический вывод трапеции: ускорение определяет края хода, потолок — только середину. На моторах, которые гудят посередине плато, живут резонансные зоны — их обходят, поднимая потолок или меняя деление, цену этого обмена мы считали в уроке про полушаг и микрошаг.
Резонансные зоны — не страшилка, а конкретная полка: у полношагового NEMA 17 она лежит вокруг ста-двухсот оборотов в минуту. Ротор на каждом скачке поля проскакивает позицию, звенит, и на краю зоны начинает терять шаги даже на идеально ровной рампе. Лечится по-разному: деление шага сглаживает сам скачок поля, ускорение через зону не даёт скорости в ней застрять, а если плато попадает точно в зону — потолок сдвигают выше или ниже делением. Гул на одном и том же участке хода, повторяющийся из раза в раз, — почти всегда она.
Трение в этой истории не только враг. Совершенно свободный вал после каждого скачка поля колеблется, как маятник, и в резонансной зоне размах растёт до потери шагов; лёгкое постоянное сопротивление — ремень, редуктор, вязкая смазка — гасит колебание за считанные такты. Отсюда типичная картина: на голом столе мотор звенит, а в сборе с ремнём едет тише — нагрузка работает демпфером. У лекарства есть граница: как только трение съедает заметную долю момента, демпфер превращается в тормоз, и рампу приходится делать положе.
Сколько брать ускорения — второй вопрос после потолка, и ответ зависит от нагрузки. Лёгкий вал NEMA 17 берёт три-шесть тысяч шагов в секунду за секунду; ремень с кареткой или шторкой — тысяча-две тысячи; винт с тяжёлыми салазками — ещё ниже. 28BYJ-48 за своим редуктором 1:64 прячет микроскопическую инерцию ротора и прощает рампы, от которых NEMA 17 срывается, но потолок у него копеечный: на выходе — порядка десяти-пятнадцати оборотов в минуту. Рабочий приём настройки: удваивайте ускорение, пока мотор не сорвётся на разгоне, потом откатитесь на треть — получите потолок своего механизма, а не чужой цифры с форума.
Скелет из симулятора переносится на реальный мотор один в один: ступени превращаются в непрерывное приращение из скетча с micros, числа в Serial — в момент перехода фаз. Единственное, чего стенд не показывает, — счётчик шагов после срыва: движок не умеет терять шаги, а настоящий мотор умеет, и именно поэтому рампа нужна. Неблокирующий вариант хода, где loop не запирается на шесть оборотов, собирается каркасом из урока про планировщик на millis — трапеция отлично живёт в одном тике с остальной логикой.
- 1. v = 1000 шагов/с, a = 2000 шагов/с². Сколько шагов занимает рампа разгона?
- 2. Когда скетч должен начать торможение?
- 3. Ход — 300 шагов, рампа при потолке — 200 шагов. Какой профиль получится?
- 4. Мотор гудит на старте и не трогается. Что делать в первую очередь?
- 5. 200 шагов на оборот, 800 шагов в секунду — сколько оборотов в минуту?
- Рампа: n = v²/(2a); 1200 шагов/с при a = 3000 — 240 шагов и 0,4 с
- Торможение стартует по остатку пути, не по таймеру
- Ход короче двух рамп — треугольник с пиком sqrt(a × N)
- Старт со 100-300 шагов/с; потолок софтовой генерации на Uno — 4-5 тысяч шагов/с
- v и a из этого урока — это maxSpeed и acceleration в AccelStepper
Частые вопросы по теме урока
- v = 1000 шагов/с, a = 2000 шагов/с². Сколько шагов занимает рампа разгона?
- n = v²/(2a) = 250 шагов, время — полсекунды. Торможение зеркально: те же двести пятьдесят. 250
- Когда скетч должен начать торможение?
- Остаток ≤ v²/(2a) — единственная надёжная граница. Таймер врёт при любом изменении параметров хода. Когда остаток пути сравняется с тормозной рампой
- Ход — 300 шагов, рампа при потолке — 200 шагов. Какой профиль получится?
- Две рампы — уже четыреста шагов, больше хода: разгон до пика sqrt(a × N) и сразу спуск. Треугольник
- Мотор гудит на старте и не трогается. Что делать в первую очередь?
- Гудение на старте — ротор не поспевает за полем. Сначала рампа и стартовая частота, ток — последняя инстанция. Увеличить ток вдвое
- 200 шагов на оборот, 800 шагов в секунду — сколько оборотов в минуту?
- 800 × 60 / 200 = 240 об/мин. Перевод полезен для сверки с паспортными кривыми момента мотора. 240