Мой первый шлагбаум открылся на пустой парковке, постоял поднятым четыре минуты и опустился за секунду до того, как к нему подъехала игрушечная машина. Логика была честная: датчик движения сработал — открыл, подождал delay(8000) — закрыл. Ломалась она о две вещи, которых я тогда не понимал: PIR-датчик докладывает «вижу движение», а не «машина проехала», а delay() на восемь секунд делает скетч глухим — вторая машина в это время не видна в принципе. Шлагбаум — первый проект, где важен не мотор, а сценарий. И это удобно: моторную половину вы уже умеете из двух предыдущих уроков, а навык сценария собирается здесь с нуля.
В этом уроке соберём шлагбаум целиком: серво со стрелой, PIR-датчик на подъезд и один светодиод «проезд свободен». Сценарий запишем состояниями на millis — как в уроке про конечный автомат на светофоре, только переходы задают датчик и таймер тишины. Два положения стрелы — это знакомая по уроку про серво-переключатель пара углов, а само серво — обычная SG90 с тремя проводами. В симуляторе ниже датчик движения — тумблер: щёлкайте им и смотрите, как сценарий живёт по секундному логу.
Слово про масштаб: макеточный шлагбаум не качает металл — стрела из соломинки или палочки весит граммы, и SG90 хватает с большим запасом. Вся ценность проекта в другом: это первый ваш автомат, у которого входы асинхронные. Датчик может щёлкнуть в любой момент между строками скетча — и сценарий обязан это переживать. Бонус проекта: здесь впервые три компонента живут на разных пинах и делят питание по-взрослому — датчику нужны свои 5 В, серво свои амперы, светодиоду резистор.
PIR: что он на самом деле докладывает
Модуль HC-SR501 ловит перемещение тёплого перед собой: человек, рука, кошка, машина с горячим капотом. Конус обзора — около 100–110°, дальность регулируется подстроечником от трёх до семи метров; вторым подстроечником ставится время удержания выхода — от пары секунд до минут. Выход модуля выдаёт 3,3 В в HIGH — для цифрового входа Arduino это честная единица, подтяжка не нужна: модуль сам держит линию и в нуле, и в единице. Подробный разбор модуля с распиновкой и ложными срабатываниями я делал в уроке про PIR-светильник на HC-SR501 — здесь беру только то, что важно для сценария. Для макеточной парковки дальность я всегда закручиваю на минимум — метр-полтора, иначе датчик реагирует на людей в другой комнате. Ставлю модуль на высоте 15–25 см от стола, конусом вдоль подъезда: ниже видит только пол, выше — ловит вас за спиной.
Для шлагбаума важны два свойства. Первое: датчик видит изменение, а не присутствие. Неподвижная машина через несколько секунд исчезает из его поля зрения — выход упадёт в LOW, хотя машина стоит у стрелы. Второе: после подачи питания PIR «сходится» 30–60 секунд и всё это время сыплет случайными срабатываниями. Значит, сценарий не может быть «датчик включил — датчик выключил»: нужен свой таймер тишины и правило на прогрев. Проверка на живой плате элементарна: проведите рукой на высоте датчика и замрите — через пару секунд выход упадёт в LOW, и это нормальное поведение, а не поломка.
Монтаж на макетке занимает минут десять, но порядок имеет значение. Сначала серво со стрелой: соломинка или палочка на качалке, в закрытом состоянии лежит вдоль бордюра. Потом датчик — он должен смотреть на подъезд, а не на траекторию стрелы; почему это критично, расскажу на тупике ниже. Светодиод — последним, на пин 12 через резистор 220 Ом: горит, пока проезд разрешён. Для одной соломинки питания 5V платы хватает — я гонял такую конфигурацию месяц без единой перезагрузки; захотите тяжёлую стрелу или вторую серво на воротах — это уже к отдельному источнику.
Сценарий из четырёх состояний
Сценарий у меня такой: шлагбаум закрыт, пока датчик молчит. Любое движение открывает стрелу и запоминает время последнего движения. Каждое новое движение перезапускает этот таймер — и это фича, а не небрежность: пока объект едет перед датчиком, стрела остаётся поднятой. Закрытие начинается только после шести секунд полной тишины. Паузы я веду через millis(), без delay() — цикл остаётся живым и между строками успевает замечать и вторую машину, и нажатия, и всё, что угодно. Состояний всего четыре, ни одно из них не требует задержки длиннее полусекундной паузы на приезд стрелы, а переходы читаются из таблицы как расписание на день.
| Состояние | Стрела | Светодиод | Переход |
|---|---|---|---|
| закрыт | 20° | погашен | PIR увидел движение → подъём |
| подъём | 20° → 110° | горит | стрела доехала → открыт |
| открыт | 110° | горит | 6 с без движения → спуск |
| спуск | 110° → 20° | погашен | стрела доехала → закрыт |
Углы 20° и 110° выбраны не для красоты. От 0° и 180° стрела отходит с запасом — серво не бьётся об упоры; а главное, поднятая стрела на 110° выйдет из конуса датчика, если датчик смотрит вдоль подъезда. Тупик из моей практики: я поставил HC-SR501 близко к оси, и стрела, проезжая перед сенсором, сама перезапускала таймер — шлагбаум не закрывался, пока я не развернул датчик конусом строго на подъезд, а не на створку. Диагностика заняла минуту по Serial: в логе pir=1 появлялся ровно в момент движения стрелы.
Шесть секунд тишины — число с условием: игрушечная машина проходит мои 40 сантиметров подъезда за 2–3 секунды, и шестисекундного окна хватает с запасом. Для живого двора, где машина может стоять у шлагбаума минуту, это окно растягивают до 30–60 секунд, а время удержания на подстроечнике модуля — наоборот, ставят на минимум: предсказуемее держать таймер в скетче, где его видно и можно поменять одной строкой. Полусекундная пауза после приказа стреле — та же прикидка: 90° SG90 проезжает примерно за 0,15 с, и запас получается тройной.
Здоровый лог выглядит так: строка pir=1 t=… при каждом щелчке датчика, затем приказ barier=110 otkryt, шесть секунд тишины и barier=20 zakryt с временем ровно на шесть секунд больше последнего движения. Если между делом затесались pir=1 без вашего участия — датчик ловит стрелу или соседей по столу, разворачивайте конус. Мой приёмочный тест всегда один: провожу машину перед датчиком медленно, останавливаю её на середине и жду — стрела обязана поехать вниз ровно через шесть секунд после остановки, ни раньше, ни позже. Дальше проект растёт сам: замените PIR на дальномер HC-SR04 — вместо «движения» получите честную дистанцию до борта, и на её основе появится счётчик свободных мест.
На живой плате подстроечники настраиваю в два хода: удержание — на минимум, чувствительность — на треть шкалы. Сначала добиваюсь, чтобы датчик не видел соседний стол и меня в кресле, и только потом расширяю зону до подъезда. И держите модуль подальше от ламп накаливания и фенов: тёплое пятно от них PIR читает как движение, и никакой таймер это не перевоспитает.
#include <Servo.h> Servo barier;unsigned long lastMotion = 0;unsigned long holdMs = 6000;int sost = 0; // 0 — закрыт, 1 — открыт void setup() { barier.attach(11); pinMode(2, INPUT); // PIR pinMode(12, OUTPUT); // светодиод barier.write(20); Serial.begin(9600); Serial.println("Shlagbaum: zakryt");} void loop() { int pir = digitalRead(2); if (pir == 1) { lastMotion = millis(); // каждое движение продлевает окно if (sost == 0) { sost = 1; digitalWrite(12, HIGH); barier.write(110); Serial.println("barier=110 otkryt"); delay(500); // даём стреле доехать } } if (sost == 1 && pir == 0 && millis() - lastMotion > holdMs) { sost = 0; digitalWrite(12, LOW); barier.write(20); Serial.println("barier=20 zakryt"); delay(500); } delay(100);}- 1. Что именно докладывает PIR-датчик на выходе?
- 2. Почему стрела ходит между 20° и 110°, а не 0–180°?
- 3. Таймер закрытия перезапускается каждым новым движением. Это баг?
- 4. Что происходит первые 30–60 секунд после подачи питания на HC-SR501?
- 5. Почему delay(8000) вместо таймера ломает сценарий?
- PIR докладывает о движении, а не о присутствии: сценарий строится из состояний, а не из реакции.
- Стрела открыта, пока движение свежее: таймер 6 с перезапускается каждым импульсом датчика.
- Рабочие углы 20° и 110° — запас от упоров и вне конуса датчика.
- Первые 30–60 с после питания PIR сыплет ложными — игнорируйте первую минуту через millis().
- Таймер держите в скетче, а не на подстроечнике модуля: скетч предсказуем и меняется одной строкой.
Частые вопросы по теме урока
- Что именно докладывает PIR-датчик на выходе?
- PIR видит перемещение теплового пятна: расстояние он не меряет вовсе, а неподвижный объект через время удержания теряет из виду. Именно поэтому сценарию нужен свой таймер, а не события датчика. что в конусе обзора появилось движение тёплого объекта
- Почему стрела ходит между 20° и 110°, а не 0–180°?
- Запас от упоров бережёт шестерёнки, а выведенная из конуса стрела не перезапускает собственный таймер — тот самый тупик с самосрабатыванием. Плюс стрела не вылезает за край макетки. у упоров серво бьётся с перегрузом, а поднятая стрела не должна попадать в конус датчика
- Таймер закрытия перезапускается каждым новым движением. Это баг?
- Именно перезапуск делает поведение осмысленным: машина, ползущая перед датчиком, не получает стрелу по лбу на середине проезда. Отсчёт всегда идёт с последнего движения. фича: пока объект едет, стрела остаётся поднятой, отсчёт идёт с последнего движения
- Что происходит первые 30–60 секунд после подачи питания на HC-SR501?
- Электронике модуля нужно время стабилизации, и первые срабатывания мусорные. Поэтому в скетче первую минуту показания датчика игнорируют через millis(). выход сыплет случайными срабатываниями — модуль «сходится»
- Почему delay(8000) вместо таймера ломает сценарий?
- delay останавливает весь цикл целиком: пока он идёт, скетч не видит ни датчик, ни что-либо ещё. Таймер на millis() держит цикл живым и вторую машину замечает. loop слепнет на восемь секунд: датчик не опрашивается, вторая машина пропускается