Машинку-подводку для съёмки таймлапсов я собрал на транзисторном ключе из урока про NPN-транзистор: пин открывает ключ, мотор ест ток от своего блока питания, все довольны — пока не понадобился задний ход. Камера уехала к правому краю стола, и вернуть её я не смог: коллекторный мотор крутится в одну сторону, пока ток течёт в одну сторону. Смена направления — это смена полярности на щётках, а транзистор так не умеет физически: он ключ с одним полюсом. Первая мысль — переключать провода питания руками — продержалась ровно до третьего дубля, который я отснял с неподвижной камерой, потому что забыл перекинуть крокодилы.
Решение старое, как сами приводы: H-мост — четыре ключа, собранные буквой H, мотор — перекладина посередине. Открываем диагональ верхний-левый и нижний-правый — ток идёт через обмотку слева направо. Открываем другую пару — полярность меняется, и вал крутится обратно. Закрыты все четыре — мотор свободно выбегает; открыты два соседних с одной стороны — обмотка закорочена, и вращающийся вал тормозит резко. Ни одной новой детали ради заднего хода, вся магия — в раскладке ключей.
Руками мост не собирают: держать в голове, что верхний и нижний ключ одной стороны открываться одновременно не должны (сквозной ток через пару — прямой путь к сгоревшему кристаллу), — лишняя работа, которую уже сделали за нас. Микросхема L298N содержит два таких моста, до 2 А на канал при питании моторов 6-12 В, и стоит дешевле светодиодной ленты. Три ноги ведут одним каналом: ENA принимает ШИМ и режет скорость, пара IN1 и IN2 задаёт направление и способ остановки. Дальше — как я развожу типовой модуль L298N, куда теряются два его вольта и почему разгон я всегда растягиваю по millis, а не даю рывком.
H-мост: четыре ключа и один ШИМ
Таблица входов канала A помещается в четыре строки. IN1 в HIGH, IN2 в LOW — ток идёт в одну сторону, вращение вперёд. IN1 в LOW, IN2 в HIGH — полярность обратная, назад. Оба в LOW — все ключи закрыты, вал выбегает по инерции. Оба в HIGH — обмотка закорочена через открытые ключи, и вал останавливается резко: энергия вращения сгорает в обмотке. Скорость при любом направлении задаёт ENA: ШИМ с analogWrite от 0 до 255 режет не направление, а долю времени, когда мост вообще подключён к обмотке.
Теперь числа, на которых я обжигался. На биполярных ключах L298N под нагрузкой оседает около двух вольт: при питании моторов 7,4 В от двух банок Li-ion вал видит примерно 5,4 В, и мотор, купленный как шестивольтовый, крутится вполсилы — это не брак, а расплата за простоту микросхемы. Дальше джамперы стандартного модуля с синей гребёнкой. Джампер ENA замыкает вход скорости на 5 В: пока он стоит, скетч может писать в ENA что угодно — вход оторван от гребёнки, мотор всегда на полной. Джампер снимаю первым делом, ещё до проводов. Второй джампер включает бортовой 5-вольтовый регулятор для логики: при питании до 12 В он удобен, при более высоком вынимается, и пятёрку подают отдельно.
Земли складываются в одну точку: GND платы, GND драйвера и минус моторного питания. Без общего провода IN-входы висят в воздухе и мост щёлкает от наводок — я два вечера лечил «бешеную» машинку, пока не сообразил, что у неё три разных минуса. Про ток тоже честно: канал держит 2 А, но без радиатора модуль греется заметно уже на 1-1,5 А; моторчикам-вантузам хватает этого с тройным запасом, а колёсные редукторные на старте легко просят больше — радиатор или запас по драйверу закладывайте до сборки, не после.
| IN1 | IN2 | ENA | Что делает мотор |
|---|---|---|---|
| HIGH | LOW | ШИМ 0-255 | вперёд, скорость по заполнению ШИМ |
| LOW | HIGH | ШИМ 0-255 | назад, скорость та же |
| LOW | LOW | любое | свободный выбег: ключи закрыты, вал едет по инерции |
| HIGH | HIGH | любое | активное торможение: обмотка закорочена, вал замирает резко |
Плавный разгон: рампа по millis()
analogWrite(9, 255) сразу после нуля — удар по всей системе. Пусковой ток коллекторного мотора в 5-10 раз выше рабочего: обмотка холодная, противоЭДС нулевая, мост отдаёт всё, что может. На мелком моторчике это выглядит как рывок, сдёргивающий платформу с места; в моём таймлапс-слайдере та же просадка в момент пуска перезагружала плату — контроллер ловил провал питания раньше, чем мотор успевал набрать обороты. Резкий старт бьёт не только по мотору: по редуктору, по винтовке каретки, по соседям по питанию.
Лекарство — рампа: цель приходит с ручки или из логики, а текущая скорость догоняет её мелкими шагами. Мой рабочий темп — 3 единицы ШИМ каждые 15 мс: подъём с нуля до 255 занимает около 1,3 секунды, и за это время противоЭДС успевает вырасти, ток — осесть, питание — пережить пуск. Для вентилятора, которому рывок безразличен, я ставлю 10 единиц каждые 30 мс; для платформы с датчиками на том же питании — 2-3 единицы, и не потому, что мотор слабый, а потому, что каждый скачок тока бьёт по соседям по шине. Временной шаблон — тот же millis-гейт из одноимённого урока, без единого delay: между шагами рампы loop() продолжает опрашивать ручку и кнопки — так из этого же приёма вырастает кооперативный цикл, где разгон можно прервать в любой момент.
Реверс в моём скетче всегда идёт через остановку: сначала рампа съедает текущее значение ШИМ до нуля, потом пауза 50-100 мс, и только затем пара IN меняется местами. Менять полярность под полным ходом — значит заставить мост гасить противоЭДС вращающегося вала и тут же разгонять его в обратную сторону: пик тока при таком развороте бьёт выше пускового. На L298N я дважды собирал запах подгоревшей изоляции, прежде чем вбил это правило в скелет каждого моторного скетча. Активное торможение (оба IN в HIGH) оставил для аварийного стопа: оно резко, зато вал замирает на месте вместо метрового выбега.
// L298N: ENA -> 9 (ШИМ), IN1 -> 7, IN2 -> 8. GND платы и драйвера — вместе.const int ENA = 9;const int IN1 = 7;const int IN2 = 8; int tek = 0; // текущая скорость: догоняет цель шагамиunsigned long lastShag = 0; void kuda(int napravlenie, int zel) { // napravlenie: 1 вперёд, -1 назад if (napravlenie > 0) { digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); } else { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); } while (tek != zel) { // рампа: без рывка к цели if (millis() - lastShag >= 15) { lastShag = millis(); if (tek < zel) { tek = tek + 3; if (tek > zel) tek = zel; // прижим, чтобы не перескочить } else { tek = tek - 3; if (tek < zel) tek = zel; } analogWrite(ENA, tek); } }} void stopZhestko() { digitalWrite(IN1, HIGH); // активное торможение: обмотка закорочена digitalWrite(IN2, HIGH); tek = 0; analogWrite(ENA, 0);} void setup() { pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);} void loop() { kuda(1, 220); // вперёд, 86% скорости delay(2000); stopZhestko(); delay(300); // пауза: вал должен встать до смены полярности kuda(-1, 140); // назад, тише delay(2000); stopZhestko(); delay(300);}В симуляторе ниже тот же принцип, только макетка умеет то, что умеет движок: крыльчатка сидит прямо на ШИМ-пине, и автоподбор отдал ей пин 11 — на плате я ставлю ENA на 9, в скетче это одна константа. H-мост, питание и общий GND симулятор не рисует: раскладку смотрите в подписи над code-блоком, а логика рампы в обеих средах совпадает до последнего знака. Транзисторный ключ из урока про мотор и реверс драйвер заменяет целиком: все четыре ключа уже внутри микросхемы.
Вторая оговорка честная: модель мотора однонаправленная. Реверс — это полярность на обмотке, а не скважность ШИМ, поэтому задний ход в симуляторе не показать; направление всегда «вперёд», рулит только скорость. Зато рампу видно отлично: выкрутите ручку резко — крыльчатка поедет за ней с привычным запаздыванием, а по парам zad= и tek= в мониторе видно, как скорость догоняет задание.
- H-мост меняет полярность на обмотке: пара IN1/IN2 задаёт направление, ENA принимает ШИМ 0-255 и режет скорость; оба IN в HIGH — активное торможение, оба в LOW — свободный выбег
- L298N: два канала до 2 А, питание моторов 6-12 В, около 2 В оседает на биполярных ключах; джампер ENA перед скетчем снимаем, земли платы и драйвера соединяем в одну точку
- Пусковой ток мотора в 5-10 раз выше рабочего: рампа 3 единицы ШИМ каждые 15 мс растягивает разгон до 1,3 секунды и снимает просадки питания
- Реверс — только через остановку: рампа до нуля, пауза 50-100 мс, затем смена полярности; мгновенный разворот бьёт током выше пускового
- В симуляторе модель мотора однонаправленная: рампа и скорость видны, реверс остаётся в code-блоке для платы
- 1. Что задаёт вход ENA на модуле L298N?
- 2. IN1 и IN2 стоят в HIGH одновременно. Что делает мотор?
- 3. Питание моторов 7,4 В. Сколько примерно видит вал через L298N?
- 4. Почему рампу разгона я вешаю на millis(), а не на delay()?
- 5. Зачем перед сменой полярности я держу паузу 50-100 мс?
Частые вопросы по теме урока
- Что задаёт вход ENA на модуле L298N?
- ENA — вход разрешения канала с ШИМ: заполнение от 0 до 255 режет скорость. Направление ведёт пара IN1/IN2, а питается логика от пятёрки с гребёнки. скорость: на него подают ШИМ 0-255
- IN1 и IN2 стоят в HIGH одновременно. Что делает мотор?
- Оба HIGH закорачивают обмотку: вал останавливается резко, энергия вращения сгорает в обмотке. Свободный выбег — это оба LOW, а комбинация легальна и годится для аварийного стопа. активно тормозит: обмотка закорочена через открытые ключи
- Питание моторов 7,4 В. Сколько примерно видит вал через L298N?
- Дарлингтоновские ключи L298N съедают порядка двух вольт под нагрузкой. ШИМ режет среднее значение сверху, поэтому максимум на валу — те самые 5,4 В, а не 7,4. около 5,4 В: примерно два вольта оседает на биполярных ключах
- Почему рампу разгона я вешаю на millis(), а не на delay()?
- delay(15) на каждом шаге замораживает весь скетч: между шагами не читается ни ручка, ни кнопка. millis-гейт оставляет loop() живым — прервать разгон можно в любой момент. рампа на delay() блокирует loop(): ручка и кнопки перестают опрашиваться
- Зачем перед сменой полярности я держу паузу 50-100 мс?
- Разворот под полным ходом заставляет мост гасить противоЭДС и тут же разгонять вал в обратную сторону — пик тока выше пускового. Стоп-пауза-реверс снимает удар целиком. чтобы противоЭДС вращающегося вала не ударила током выше пускового