Продолжаю рассказ о том, как мы автоматизировали свой поселок, начало здесь. В этой части расскажу о работе со шлагбаумами и о том, как можно сделать светофор, очень похожий на настоящий.

Поскольку стояла задача наладить работу шлагбаумов, пришлось разобраться как они устроены. Настроек у них довольно много, однако нам достаточно знать, что 99% всех шлагбаумов и откатных ворот как основной интерфейс для взаимодействия с управляющими устройствами используют "сухие контакты". Другими словами, внутри у них есть пара контактов, которые можно замкнуть — и тогда шлагбаум откроется, и будет открытым до тех пор, пока контакты соединены. После размыкания он ждет некоторое время и закрывается. Прикрепите к этим контактам обычную кнопку — и простейший пульт управления готов. В нашем случае вместо кнопки используются различные устройства, выполняющие ту же функцию (замыкающие 2 контакта). Это ethernet реле (управляемое через REST API или MQTT), домофон, электромагнитная петля на выезд, раньше еще было GSM-реле.

Все эти устройства параллельно подключены к контактам "кнопки" шлагбаума: если хотя бы одно сработало, "кнопка" нажата и шлагбаум открывается. Поэтому далее по тексту я буду называть их всех одним словом "кнопка".
Светофор
По распознаванию номера шлагбаум поднимается, это замечательно. Но возникло и неудобство: бывает, что подъезжаешь к открытому после предыдущей машины шлагбауму и не понятно: уже номер распознался и можно ехать, или же вот-вот стрела начнет опускаться. Конечно, есть защита (фотоэлемент, определяющий, мешает ли что-то опусканию стрелы), но многим не хочется рисковать, и они останавливаются перед открытым шлагбаумом, ожидая какого-нибудь визуального подтверждения что можно ехать (например, стрела начнет опускаться и дёрнется на полпути, после начнёт обратно подниматься). Так возникла идея сделать светофор.
Задача разбивается на две части: сделать саму конструкцию с лампочками и подключить ее к шлагбауму. Начнем с изготовления конструкции. Можно в продаже найти готовые светофоры: представляют они собой корпус, в который вставлены светодиодные панели и провода питания от них выведены наружу. Подаем напряжение на пару проводов -- и соответствующая секция светофора загорается. Можно зажечь хоть все сразу. Однако, стоят они немало, и я отправился искать более бюджетный вариант. Сам светящийся элемент нашелся за 1000р, держатель из фанеры был выпилен лобзиком и покрашен, провод питания выведен вниз.

Осталось подключить его к шлагбауму. Логика представлялась простая: когда замкнуты контакты "кнопки" шлагбаума, зеленый свет должен гореть, когда разомкнуты -- не гореть. Как этого добиться? Например, собрать простейшую цепь из источника 12В и светофора и замыкать/размыкать эту цепь теми же реле ("кнопкой"), что используется для управления шлагбаумом. Но практика показала, что так это не работает.

Шлагбаум определяет, что на его "сухих контактах" появилось напряжение и воспринимает это как сигнал к открытию, и остается открытым независимо от состояния "кнопки". Решение заключается в использовании реле (других, автомобильных): "кнопка" включает два реле, которые уже замыкают контакты шлагбаума и цепь светофора соответственно.


Схема работает, все хорошо, но хочется большего: поведения "настоящего светофора".

Получается, что зеленый свет просто гаснет, потом 3 секунды ничего не происходит и затем начинается закрытие. Когда шлагбаум закрыт, светофор просто выключен, водитель может и не понять, что он есть и на него можно ориентироваться. Привычные дорожные светофоры предупреждают водителя о закрытии заранее: зеленый мигает, потом горит жёлтый и красный. Один из цветов всегда горит, давая понять, что светофор работает. Я решил, что фазу с жёлтым светом можно исключить, чтобы не слишком усложнять и удорожать светофор. Оставить зелёный, мигающий зелёный и красный.

Готовых решений для такого найдено не было, а значит, настало время колхозить самостоятельно. Поскольку шлагбаумы работают и на въезд, и на выезд, светофор было решено сделать двухсторонним, вторая сторона для тех кто выезжает из посёлка. Получилось 4 светодиодных модуля: 2 зеленых и 2 красных. Был взят контроллер Wemos D1 Mini (подойдет любой ардуино-подобный, он просто имелся под рукой), а к нему -- модуль на 4 реле.
К двум пинам контроллера подключаем две "кнопки" (у нас два шлагбаума, въезд и выезд), вторые контакты "кнопок" -- к пину GND. Wemos D1 умеет работать с кнопками без дополнительного подтягивающего резистора, главное не забыть включить нужную опцию при настройке работы пина. Еще к 4 пинам подключаем реле.

Код для контроллера
const int buttonPin = D5; // пин первой "кнопки"
const int button2Pin = D6; // пин второй "кнопки"
const int red1Pin = D1; // реле дла первого красного светофора
const int green1Pin = D2; // реле дла первого зеленого светофора
const int red2Pin = D3; // реле дла второго красного светофора
const int green2Pin = D4; // реле дла второго зеленого светофора
unsigned long debounceDelay = 50; // debounce для "кнопок"
unsigned long flashDuration = 350; // длительность "мигания"
bool buttonState = HIGH;
bool lastButtonState = HIGH;
unsigned long lastDebounceTime = 0; // время последнего изменения статуса кнопки 1
unsigned long flashSequenceStart = 0; // время начала моргания
unsigned long timeFromFlashingStart = 0; // текущая длительность моргания
bool buttonState2 = HIGH;
bool lastButtonState2 = HIGH;
unsigned long lastDebounceTime2 = 0;
unsigned long flashSequenceStart2 = 0;
unsigned long timeFromFlashingStart2 = 0;
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // встроенный подтягивающий резистор для кнопки
pinMode(button2Pin, INPUT_PULLUP);
pinMode(red1Pin, OUTPUT);
pinMode(green1Pin, OUTPUT);
pinMode(red2Pin, OUTPUT);
pinMode(green2Pin, OUTPUT);
digitalWrite(red1Pin, LOW); // В начале включаем зеленый и выключаем красный
digitalWrite(green1Pin, HIGH);
digitalWrite(red2Pin, LOW);
digitalWrite(green2Pin, HIGH);
}
void loop() {
loop1();
loop2();
}
void loop1() {
// Читаем положение кнопки 1
bool reading = digitalRead(buttonPin);
// debounce для кнопки
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if (millis() < lastDebounceTime) {
lastDebounceTime = 0;
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// подождали 50 мс, чтобы исключить много коротких нажатий (debounce)
if (reading != buttonState) {
buttonState = reading;
// если кнопка отпущена, начинаем моргать
if (buttonState == HIGH) {
flashSequenceStart = millis();
}
}
}
// "кнопку" нажали
if (buttonState == LOW) {
digitalWrite(green1Pin, LOW); // Turn LED on
digitalWrite(red1Pin, HIGH); // Turn LED on
}
// "кнопку" отпустили
else {
// моргаем 3 раза (по времени, прошедшему с отпускания кнопки, определяем, какой свет зажечь сейчас)
timeFromFlashingStart = millis() - flashSequenceStart;
if (timeFromFlashingStart >= 0 and timeFromFlashingStart < flashDuration) {
digitalWrite(green1Pin, HIGH);
}
if (timeFromFlashingStart >= flashDuration and timeFromFlashingStart < flashDuration * 2) {
digitalWrite(green1Pin, LOW);
}
if (timeFromFlashingStart >= flashDuration * 2 and timeFromFlashingStart < flashDuration * 3) {
digitalWrite(green1Pin, HIGH);
}
if (timeFromFlashingStart >= flashDuration * 3 and timeFromFlashingStart < flashDuration * 4) {
digitalWrite(green1Pin, LOW);
}
if (timeFromFlashingStart >= flashDuration * 4) {
digitalWrite(green1Pin, HIGH);
}
if (timeFromFlashingStart >= flashDuration * 6) {
digitalWrite(red1Pin, LOW);
}
}
// Save the current reading for next loop
lastButtonState = reading;
}
void loop2() {
// то же самое но для кнопки 2
bool reading = digitalRead(button2Pin);
if (reading != lastButtonState2) {
lastDebounceTime2 = millis();
}
if (millis() < lastDebounceTime2) {
lastDebounceTime2 = 0;
}
if ((millis() - lastDebounceTime2) > debounceDelay) {
if (reading != buttonState2) {
buttonState2 = reading;
if (buttonState2 == HIGH) {
flashSequenceStart2 = millis();
}
}
}
if (buttonState2 == LOW) {
digitalWrite(green2Pin, LOW); // Turn LED on
digitalWrite(red2Pin, HIGH); // Turn LED on
}
else {
timeFromFlashingStart2 = millis() - flashSequenceStart2;
if (timeFromFlashingStart2 >= 0 and timeFromFlashingStart2 < flashDuration ) {
digitalWrite(green2Pin, HIGH);
}
if (timeFromFlashingStart2 >= flashDuration and timeFromFlashingStart2 < flashDuration * 2) {
digitalWrite(green2Pin, LOW);
}
if (timeFromFlashingStart2 >= flashDuration * 2 and timeFromFlashingStart2 < flashDuration * 3) {
digitalWrite(green2Pin, HIGH);
}
if (timeFromFlashingStart2 >= flashDuration * 3 and timeFromFlashingStart2 < flashDuration * 4) {
digitalWrite(green2Pin, LOW);
}
if (timeFromFlashingStart2 >= flashDuration * 4) {
digitalWrite(green2Pin, HIGH);
}
if (timeFromFlashingStart2 >= flashDuration * 6) {
digitalWrite(red2Pin, LOW);
}
}
lastButtonState2 = reading;
}

Домофон и калитка
К обустройству калитки тоже было решено подойти творчески. Кто пробовал пройти через калитку с велосипедом или детской коляской, знает, что это очень неудобно. Нужно подойти к домофону у калитки, приложить ключ, открыть дверь (все это время коляска стоит в стороне), потом отпустить дверь и побежать проталкивать коляску, главное успеть пока дверь не закрылась. На выход не лучше: нажать кнопку (которая часто в стороне), добежать до двери, открыть ее, вернуться за коляской, бегом побежать в закрывающуюся дверь.
Поэтому домофон и кнопку поставили на столбики на расстоянии метра три от калитки, а на нее саму поставили электропривод. Совершенно не ясно, почему решение не пользуется популярностью (мне не попадалось такое по крайней мере), привод стоит не так уж много, сопоставимо с самой калиткой.
Помимо этого, появилась возможность сделать калитку очень широкой, чтобы в нее точно было легко пройти или проехать. Открывать такую калитку руками было бы неудобно. Управляется привод точно так же как шлагбаум: замкнули 2 контакта и дверь открылась. Остается их замкнуть по команде от домофона. Но вот проблема: домофон разрабатывался под электромагнитные замки, популярные в подъездах, а управляются они совсем иначе. Если на замок подать 12В, то электромагнит начинает работать и удерживает дверь. Если надо открыть дверь, напряжение убирается и магнит её отпускает. Получается, нам нужно чтобы когда на контактах домофона было 12В, контакты привода калитки были разомкнуты, а когда 12В пропало, контакты должны сразу замкнуться. Помогло нам в этом автомобильное реле, очень похожее на описанные ранее, но c одним дополнительным контактом.

Управляется это реле так же 12В, но при отсутствии напряжения замыкает свой дополнительный контакт с одним из оставшихся, тем самым получается ровно то что нам нужно.
В следующей части расскажу про самодельный светодиодный экран, который можно заметить на видео выше.























