Проект называется AtsPLC. Это мой пет-проект: я начал его в 2024 году и делал неспешно. В этой статье я расскажу об идее и о том, как с контроллером работать. А во второй части — о том, как все устроено внутри.
Идея: ladder не нужен большой экран
Мне хотелось, чтобы логику можно было увидеть и поменять прямо на устройстве. И чтобы для этого хватило маленького и дешевого экрана.
Первопричина
Все началось с аквариума. Надоело каждый день включать свет, а днем еще и следить за солнцем: от избытка света вода в аквариуме зеленела. Компрессор тоже приходилось время от времени выключать. В ящике как раз лежало несколько модулей “WeMos ESP8266 board with OLED and 18650”, и один из них стал контроллером. Сначала программа была жестко зашита в код, без всяких настроек. Но скоро стали видны ее недостатки: в выходные хотелось, чтобы свет включался позже, а пороги фотодатчика приходилось то и дело подстраивать. И каждый раз ради этого нужно было править код и перепрошивать контроллер. Тогда вспомнилась Ladder Diagram, и появилась идея: пусть программу можно будет менять прямо на устройстве.
Для этой задачи хорошо подходит ladder. Программа на ladder — это просто список сетей. Каждая сеть читается как одна строка слева направо: от левой шины через контакты к катушке у правой шины. Такую строку легко показать даже на узком экране, а список строк удобно листать двумя кнопками.
Идея не новая: писать программу прямо на устройстве давно позволяют умные реле и даже конструкторы LEGO:
|
Устройство |
Экран |
Как пишется программа на устройстве |
|---|---|---|
|
Schneider Zelio Logic SR2 |
символьный |
ladder из символов, в строке 5 контактов и катушка |
|
Eaton easyE4 |
символьный |
ladder из символов, ввод курсорными кнопками |
|
Siemens LOGO! 8 |
символьный |
FBD, не ladder |
|
LEGO Mindstorms NXT/EV3 |
графический |
цепочка блоков-иконок |
В AtsPLC на графическом экране 128×64 пишется именно ladder. Каждый элемент нарисован как настоящий элемент схемы и сразу показывает свои параметры прямо в сети: адрес контакта, уставку компаратора, время таймера, значение индикатора.
Программа и есть экран оператора
В AtsPLC программа сама показывает, что происходит:
-
Активный участок цепи нарисован сплошной линией, а пассивный — пунктиром. Сразу видно, где проходит сигнал, а где цепь разорвана.
-
Сверху экрана есть строка состояния с 8 маленькими шкалами: AI, DI, O1, O2 и V1…V4. Так значения всех входов, выходов и переменных видны всегда.
-
Элемент Indicator показывает значение адреса крупным шрифтом. Его можно масштабировать и поставить десятичную точку. Например, сырое значение АЦП можно показать сразу в вольтах.
-
В режиме Stop правая шина каждой сети пунктирная, а у отключенной сети пунктирная левая шина.
Получается, что отдельный HMI делать не нужно — он уже есть в самой программе. Нужно показать температуру? Достаточно добавить в программу сеть с одним элементом Indicator.
Железо
Фото собранного устройства
Сразу предупрежу: это макет, собранный на скорую руку. Задача была проверить идею, а не сделать красиво, поэтому здесь много термоклея и проводов поверх платы.
Устройство состоит из двух частей: платы контроллера и периферии. Плата контроллера — это готовый модуль “WeMos ESP8266 board with OLED and 18650”, а периферию я собрал на макетной плате. Для моих задач этого вполне хватает. Схема лежит в репозитории, так что при желании ее можно перенести на свою печатную плату.
Что есть на плате контроллера:
-
ESP8266;
-
OLED 0.96″ 128×64 на контроллере SSD1306, шина I2C;
-
джойстик на 5 положений: вверх, вниз и нажатие работают как кнопки Up, Down и Select;
-
на этом модуле джойстик вправо замыкает вход DI (GPIO0), поэтому DI удобно проверять без внешнего датчика, а влево сбрасывает устройство;
-
светодиод.
Что есть в периферии:
-
1 дискретный вход (DI);
-
1 аналоговый вход (AI), это АЦП ESP8266, 0…1 В;
-
2 выхода (O1, O2);
-
питание от сети 220 В через модуль AC/DC на 5 В.
Выходы я собирал в двух вариантах: с электромагнитными реле с катушкой на 12 В и переключающим контактом, и с твердотельными оптореле K293KP11BP. Входы защищены TVS-диодами и RC-фильтрами.
Схема. Деталей там немного, и все они легко находятся.
Так что если у вас в ящике лежит пара ESP8266 без дела, это хороший повод дать им работу.
Как писать программу тремя кнопками
На экране помещаются две сети, а кнопки Up и Down листают программу.
Менять программу можно только в режимах Stop и Debug, о них чуть ниже. В режиме Run программа защищена от случайных правок, и кнопки только листают ее.
Чтобы изменить сеть, нужно сделать так:
-
Select выбирает сеть.
-
Второй Select открывает ее.
-
Up и Down выбирают место в сети.
-
На выбранном месте Up и Down перебирают элементы. При этом контроллер предлагает только те элементы, которые помещаются на оставшееся место. Параметры переходят к новому элементу: например, если поменять нормально открытый контакт на нормально закрытый, адрес останется прежним.
-
Select подтверждает элемент, и дальше Up и Down меняют его параметры. Если держать Up или Down нажатой, значение меняется большим шагом.
А если долго держать Select на выбранной сети, откроются действия со всей сетью: переместить, копировать, удалить или отключить.
Как оказалось, тремя кнопками собирать программу на ladder довольно просто. Сначала я относился к этой идее скептически и собирался подключить больше кнопок. Но лень творит чудеса: новые кнопки я так и не подключил, а трех оказалось вполне достаточно.
Режимы работы
|
Режим |
Сети выполняются |
Выходы |
Редактирование |
|---|---|---|---|
|
Stop |
нет |
сброшены в 0 |
можно |
|
Run |
да |
работают по программе |
нельзя |
|
Debug |
да |
работают по программе |
можно |
Debug нужен при наладке: можно поменять уставку и сразу увидеть результат на живом объекте. Но это опасное сочетание, поэтому флаг Debug не переживает пропадание питания: после него устройство стартует в Run.
Сервисный режим
Если включить питание с нажатой кнопкой Up, откроется сервисное меню. В нем можно выбрать режим работы, настроить WiFi через приложение ESP-Touch, сохранить программу в один из 4 слотов, восстановить ее или сбросить настройки.
Какие элементы есть
Что может делать программа, зависит от набора элементов, поэтому перечислю их все. Но сначала про адреса. Доступны DI, AI, O1, O2 и переменные V1…V4, и все они хранят значения 0…255.
Входные элементы:
|
Элемент |
Что делает |
|---|---|
|
Нормально открытый контакт |
пропускает сигнал, когда значение адреса не 0 |
|
Нормально закрытый контакт |
пропускает сигнал, когда значение адреса 0 |
|
Таймер, секунды |
задержка 1…99999 с |
|
Таймер, миллисекунды |
задержка 50…99950 мс, шаг 50 мс |
|
Генератор |
импульсы, длительность паузы и импульса настраивается |
|
Компараторы |
==, <>, >, >=, <=, < со значением уставки |
|
Indicator |
показывает значение адреса с масштабом и десятичной точкой |
Выходные элементы:
|
Элемент |
Что делает |
|---|---|
|
Прямой выход |
пишет 255, пока цепь активна, и 0, когда пассивна |
|
Set |
пишет 255, когда цепь стала активной. Если цепь потом стала пассивной, значение остается 255, пока его не сбросит Reset |
|
Reset |
пишет 0, когда цепь стала активной |
|
Inc |
прибавляет 1, когда цепь стала активной, максимум 255 |
|
Dec |
вычитает 1, когда цепь стала активной, минимум 0 |
Связь между сетями:
|
Элемент |
Что делает |
|---|---|
|
ContinuationIn |
ставится в конце сети и передает ее состояние дальше |
|
ContinuationOut |
ставится в начале сети и берет это состояние |
В одну сеть помещается до 5 элементов. Если этого мало, выручает пара ContinuationIn и ContinuationOut: цепь просто продолжается в следующих сетях. Причем одна ContinuationIn может питать сразу несколько сетей ниже.
Привязки к WiFi, времени и настройкам:
|
Элемент |
Что делает |
|---|---|
|
WiFiBinding |
ищет сеть WiFi с заданным именем и пишет в переменную уровень ее сигнала |
|
WiFiStaBinding |
подключается к роутеру и пишет в переменную уровень сигнала |
|
WiFiApBinding |
поднимает свою точку доступа и пишет в переменную число подключенных клиентов. Маска по MAC-адресу задает, какие клиенты считаются: так можно учитывать только свой телефон |
|
DateTimeBinding |
пишет в переменную секунды, минуты, часы, день, день недели, месяц или год |
|
Settings |
показывает и правит одну настройку устройства прямо в сети |
Как элементы выглядят на экране
Пример: сигнализация, где телефон — это ключ
Чтобы было понятнее, как это выглядит в деле, разберу одну задачу.
Контроллер поднимает свою точку доступа WiFi. Если к ней подключен телефон хозяина, то значит, хозяин дома. Посторонний телефон к точке доступа не подключится: для этого нужно знать пароль. Но пароль могут знать и другие устройства, которые когда-то подключались: старый телефон, планшет или телефон гостя. Чтобы их не считать, в маске MAC-адреса указывается MAC телефона хозяина, и тогда хозяином считается только он. А если телефона нет и при этом открылась дверь, контроллер ждет 30 секунд и включает сирену на 10 минут. Красный светодиод показывает, в каком состоянии охрана. Линия датчика двери тоже проверяется: обрыв или короткое замыкание видно на светодиоде, а если дома никого нет, то неисправность сразу включает тревогу.
Подключение:
|
Вход или выход |
Что подключено |
|---|---|
|
AI |
датчик двери через делитель |
|
O1 |
сирена |
|
O2 |
красный светодиод |
Датчик двери включен в делитель на аналоговом входе. Благодаря этому по одному входу можно различить сразу четыре состояния:
|
AI |
Состояние |
|---|---|
|
0…29 |
неисправность, например линия замкнута |
|
30…129 |
дверь закрыта |
|
130…229 |
дверь открыта |
|
230…255 |
неисправность, например оборван резистор |
Переменные:
-
V1 — сколько телефонов подключено к точке доступа;
-
V2 — состояние охраны: 0 — тишина, 1…30 — ожидание 30 секунд, 31…180 — тревога, 181 — тревога закончилась.
V2 тут работает сразу и как состояние, и как счетчик времени. Генератор перед элементом Inc прибавляет 1 на каждом импульсе, и поэтому значение V2 растет вместе со временем.
Начнем с начала программы. Первая сеть поднимает точку доступа, а следующие три выводят значения на экран:
1 ||--[WiFiAp V1 "AtsPLC" "ats-PLC0" "************"]----|| 2 ||--[Indicator AI 0..255]-----------------------------|| 3 ||--[Indicator V1 0..255]-----------------------------|| 4 ||--[Indicator V2 0..255]-----------------------------||
Теперь запуск тревоги. Если телефона нет, дверь открыта, а охрана в покое, то V2 становится равной 1:
12 ||--[V1 == 0]--[AI >= 130]--[V2 == 0]----------------->> V213 >>-----------------------------------------------(+)--||
Дальше ожидание 30 секунд. Пока V2 находится между 1 и 30, она растет на 1 каждую секунду:
16 ||--[V2 > 0]--[V2 <= 30]------------------------------>> V217 >>--[SQW off 500ms on 500ms]---------------------(+)--||
И наконец, хозяин вернулся. Как только телефон подключился, все сбрасывается. Здесь одна ContinuationIn питает сразу три сети:
21 ||--[V1 > 0]------------------------------------------>> V222 >>-----------------------------------------------(R)--|| O123 >>-----------------------------------------------(R)--|| O224 >>-----------------------------------------------(R)--||
Все ladder-схемы в статье сделаны скриптом Tools/ladder.py из файла программы.
Сети 2-4 здесь работают как экран оператора. При наладке на них видно значение AI при открытой и закрытой двери, так что пороги можно поправить прямо на месте.
Полное описание, схема делителя и вся программа лежат в Demo/security-alarm.md. Там же есть еще три готовые программы:
-
аквариум: свет и насос фильтра по расписанию, с датчиком освещенности;
-
WiFi watchdog: перезагружает роутер, когда его сигнал слабый или пропал;
-
термостат: держит температуру в ящике с помощью нагревателя и вентилятора, датчик — термистор.
Веб-интерфейс
Когда устройство подключено к роутеру, у него появляется веб-интерфейс. Браузер показывает ту же картинку, что и OLED, только крупнее, а кнопки можно нажимать прямо на странице или с клавиатуры. При этом в браузере видно больше сетей, чем на устройстве: он собирает их из кадров, которые уже видел.
Еще через веб-интерфейс можно скачать и загрузить программу и переключить режим работы. А прошивка обновляется по WiFi через тот же HTTP-сервер, об этом во второй части.
Своего редактора программы со страницами, формами и кнопками в браузере нет, и это сделано специально. Браузер просто показывает копию экрана устройства, поэтому умеет ровно то же, что и само устройство. Как это устроено, я расскажу во второй части.
Ограничения
-
Это самодельный ПЛК. Язык программы — подобие ladder из IEC 61131-3. Контроллер подходит для несложных процессов, где не нужна высокая надежность: ESP8266 с включенным WiFi на нее и не рассчитан, а на входах нет гальванической развязки.
-
Мало входов и выходов. Сейчас их всего 1 DI, 1 AI, 2 выхода и 4 переменные. Но можно добавить расширитель GPIO: исходный код доступен, и лицензия разрешает его менять. Если сделаете это как отдельную конфигурацию, буду рад pull request.
-
Значения только 0…255. Знаковых чисел, дробей и арифметики нет.
-
Каждая сеть — одна цепочка. Так ее удобно показывать на маленьком экране. Логическое ИЛИ собирается из нескольких сетей: например, каждое условие в своей сети ставит общую переменную через Set, а отдельная сеть сбрасывает ее через Reset, когда все условия ложны.
-
Размер программы. До 80 сетей, до 5 элементов в сети, файл до 4 КБ.
-
Одно радио. ESP8266 не может одновременно держать свою точку доступа и подключение к роутеру. Поэтому, например, в программе сигнализации веб-интерфейс работает только в режиме Stop.
-
Веб-интерфейс без пароля. Устройство рассчитано на домашнюю сеть, которой вы доверяете.
Лицензия
Бесплатно для хобби, обучения и для работы внутри своей компании. А если вы продаете устройства с AtsPLC или ставите его клиентам за деньги — нужна коммерческая лицензия.
Исходный код доступен всем, но в строгом смысле это не open source, правильнее называть это source available.
Что дальше
Идея оказалась удачной, и на ее основе я начал новый проект — SuPLC. Он пока еще в разработке.
SuPLC работает на нескольких платформах из одного кода: ESP32, ESP32-S3, ESP32-P4, ESP8266, LPC4088 и Linux. Дисплеи тоже разные: E-Ink 2.13″, AMOLED 2.41″ с тачем, LCD 3.5″ с тачем, TFT 5.6″. В нем уже есть Modbus TCP и RTU, сохраняемые переменные и значения до 65535.
Фото SuPLC на трех дисплеях
А во второй части я расскажу, как AtsPLC устроен внутри: как работает цикл контроллера без постоянного опроса, как рисуется картинка на 128×64, почему веб-интерфейс — это просто копия экрана, как устройство перезапускается без потери состояния и как все это тестируется.
Ссылки
-
Репозиторий: https://github.com/viordash/AtsPLC
-
Элементы: Docs/LADDER_ELEMENTS.md
-
Готовые программы: Demo/README.md
ссылка на оригинал статьи https://habr.com/ru/articles/1103650/