В данной статье речь пойдёт об открытой библиотеке для построения распределённых систем управления — libuniset, написанной на языке C++ под ОС Linux. Будет дан общий обзор основных понятий, элементов и концепций, используемых в библиотеке.
Основной целью библиотеки libuniset является предоставление готовых «кубиков» для построения распределённых автоматизированных систем управления (АСУ). В любой АСУ можно выделить такие основные направления как:
- ввод/вывод;
- сетевой обмен;
- процессы управления (алгоритмы);
- хранение данных;
- работа с БД.
В libuniset сделана попытка создать готовые для использования, согласованные и взаимодействующие между собой компоненты для всех указанных направлений, и при этом создать достаточно универсальную и легко расширяемую библиотеку.
Типичным проектом с использованием данной библиотеки является проект, состоящий из порядка 20-25 узлов, реализующих управление и контроль состояния, а также операторских станций (обычно не меньше двух резервирующих друг друга) отображающих информацию и, помимо этого, реализующих журналирование всех событий, происходящих в системе (то есть заполняющих базу данных). В общем случае число узлов системы не ограничено.
Небольшая историческая справка
Библиотека libuniset развивалась (и развивается сейчас) как и положено — постепенно. В ходе работы над различными проектами систем управления из них выделялись какие-то общие для всех систем свойства, механизмы или компоненты, и эти общие части вносились в библиотеку для дальнейшего повторного использования. На данный момент текущей версией является версия 1.6, которая представляет из себя уже достаточно зрелую библиотеку с установившимся API, которая позволяет легко (и быстро) создавать и разворачивать системы управления.
На данный момент библиотека и все её вспомогательные утилиты собираются под дистрибутив ALT Linux,
а так же дополнительно, при помощи системы Korinf, библиотека собирается под:
Что такое libuniset
На рисунке сделана попытка графически представить, что из себя представляет libuniset.
В основу положена технология CORBA, на ней построено всё взаимодействие «компонентов» системы между собой. При этом следует заметить, что API библиотеки «маскирует» взаимодействие, основанное на CORBA и при необходимости взаимодействие может быть переписано с использованием других механизмов, не затрагивая интерфейсы, предназначенные для использования в проектах. Можно видеть, что libuniset по возможности задействует сторонние библиотеки (стараясь избегать изобретения велосипедов). Методы использования библиотеки могут быть различны: начиная от написания необходимой функциональности путём наследования от классов библиотеки и заканчивая использованием уже готовых компонентов без какой-либо модификации, а лишь настраивая их под свои задачи.
Основные понятия
Основной информационной единицей в библиотеке является датчик. По сути, датчик — это некая переменная, хранящая состояние. Практически любая информация (о событиях, о состоянии того или иного процесса, объекта, сообщение оператору и т.п.) передаётся через состояние «датчика». В библиотеке предусмотрено четыре типа датчиков:
- DI — дискретный вход (DigitalInput)
- DO — дискретный выход (DigitalOutput)
- AI — аналоговый вход (AnalogInput)
- AO — аналоговый выход (AnalogOutput)
Исходно данные типы используются непосредственно процессами ввода/вывода. «Выходы» (DO, AO) — это команды «от системы управления», «Входы» (DI, AI) — это информация от объекта «в систему управления». Помимо этого, датчики не обязательно должны быть «живыми» входами или выходами — при помощи этих четырёх типов можно кодировать любую информацию. Например, можно передавать сообщения оператору, заранее создавая для каждого сообщения свой «датчик» и в случае необходимости послать сообщение выставлять его в «1». Удобство и универсальность числовых датчиков позволяет использовать для передачи данных большое число различных протоколов, рассчитанных на передачу только цифровой информации. Например: CAN, ModbusRTU, ModbusTCP и т.п.
Вторым важным понятием является объект. Под объектом подразумевается некая сущность, способная принимать сообщения. Объекты создаются, инициализируются и запускаются в работу специальным активатором.
Дополнительно можно ещё ввести понятие процесс. Под процессом подразумевается системный процесс (запущенная программа), выполняющий те или иные функции управления и обменивающийся для этого с другими процессами сообщениями или удалённо вызывающий функции других объектов. Чаще всего понятия процесс и объект совпадают. В некоторых случаях процесс может содержать несколько взаимодействующих объектов. Все процессы в системе — многопоточные, так как для взаимодействия с другими объектами (процессами) в обязательном порядке создаются потоки для CORBA, а также у каждого объекта создаётся свой поток обработки сообщений (если его специально не отключить).
Взаимодействие процессов на узле
В ходе развития проекта опытным путём сформировалась следующая схема взаимодействие процессов на узле:
Центральным элементом системы является SharedMemory (SM) — это процесс, осуществляющий хранение состояния всех датчиков. Всё взаимодействие между процессами осуществляется через него. При этом не следует путать это название с понятием «разделяемая память», относящимся к механизмам взаимодействия в UNIX-системах. В данном случае процесс SharedMemory просто выполняет функцию разделяемого хранилища и поэтому получил такое название. Помимо этого SharedMemory осуществляет рассылку уведомлений другим процессам об изменении состояния того или иного датчика.
Все процессы условно можно разделить на два типа: «активные» и «пассивные».
Пассивные процессы — это процессы, которые большую часть времени «спят», ожидая сообщений об изменении того или иного датчика. В основном к таким процессам относятся процессы управления.
Активные процессы — это процессы, которые постоянно выполняют какую-то работу. К таким процессам относятся:
- процессы обмена по сети (в данном случае CAN);
- процессы работы с картами ввода/вывода (IOControl);
- процессы обмена с какими-то внешними устройствами (RS485 или ModbusTCP).
Так как активные процессы тесно взаимодействуют с SharedMemory, то для оптимизации работы (исключения удалённых вызовов процедур через CORBA) все активные процессы запускаются в одном адресном пространстве с SharedMemory (каждый процесс в отдельном потоке), и работают с SM напрямую, через указатели. Этот «объединённый» процесс по историческим причинам называется SharedMemory2.
Отдельно можно выделить группу «вспомогательных» процессов. На данном рисунке к таким относится DBServer, обычно запускаемый на операторских станциях, где ведётся БД. Его задача — получать уведомления от SM по изменении любого датчика и сохранять эти события в БД. По умолчанию в libuniset реализована поддержка MySQL и SQLite, но при необходимости можно реализовать взаимодействие с любой СУБД, разработав соответствующий DBServer.
Распределённое взаимодействие (сетевое)
На рисунке представлена типичная схема сетевого взаимодействия на основе libuniset.
Для обеспечения «прозрачности сети» на каждом узле запускается своя копия SharedMemory(SM). «Прозрачность» при этом обеспечивают процессы обмена между узлами по соответствующему протоколу (на рисунке это CAN и UNET). Узлы постоянно обмениваются между собой датчиками обеспечивая «одинаковость» хранимой в SM информации. Каждый процесс обмена получает от других узлов информацию о находящихся у них датчиков, и в свою очередь посылает другим узлам информацию о датчиках находящихся у него на узле.
Так же через SM функционирует и процесс ввода/вывода (IOControl). Всё, что считывается с каналов ввода, сохраняется в SM, а состояние «выходов» читается из SM и выводится в каналы вывода.
Из рисунка можно видеть, что взаимодействие может быть построено практически на основе любого интерфейса (Ethernet, CAN, RS, MIL-STD и т. п.). Для этого достаточно написать процесс обмена, реализующий соответствующий интерфейс и взаимодействующий с SM. При этом вся остальная система не потребует модификации.
Краткое описание готовых компонентов, входящих в libuniset
Готовые компоненты представляют из себя уже законченные программы (процессы), которые «умеют» взаимодействовать с SharedMemory и позволяют легко «развёртывать» распределённые системы. В библиотеке libuniset имеются следующие готовые компоненты:
- SharedMemory — хранение «переменных»;
- IOControl — работа с картами ввода/вывода;
- ModbusMaster — реализация Modbus TCP/RTU master режима;
- ModbusSlave — реализация Modbus TCP/RTU slave режима;
- UNetExchange — взаимодействие по протоколу UDP;
- LogicProcessor — компонент, позволяющий описывать алгоритмы на основе логических схем (записываемых в xml-файле);
- DBServer_MySQL — сервер для взаимодействия с БД MySQL;
- DBServer_SQLite — сервер для работы с SQLite.
Утилиты, входящие в состав libuniset
По мере работы над проектами и развитием возможностей библиотеки, в неё стали включаться различные вспомогательные утилиты, позволяющие вести наладку проектов, созданных с её использованием. Вот список основных утилит с кратким описанием:
Группа утилит для работы с датчиками:
- uniset-admin — многофункциональная консольная утилита, позволяющая писать/читать состояние датчиков, а таки же имеющая различные вспомогательные функции;
- uniset-simitator — имитатор линейного изменения аналоговых датчиков;
- uniset-sviewer-text — просмотр состояния всех датчиков;
- uniset-smviewer — просмотр состояния всех датчиков;
- uniset-smonit — мониторинг изменения состояния датчика (или группы датчиков).
Утилиты работы с сетевыми протоколами:
- uniset-mbtcpserver-echo — имитатор Modbus TCP Slave устройства;
- uniset-mbtcptest — Консольная утилита, позволяющая опрашивать (проверять) устройства по протоколу Modbus TCP (режим Master);
- uniset-mbrtuslave-echo — имитатор Modbu RTU Slave устройства;
- uniset-mbrtutest — Консольная утилита, позволяющая опрашивать (проверять) устройства по протоколу Modbus RTU (режим Master);
- uniset-unet-udp-tester — работа с протоколом UnetUDP.
Различные дополнительные утилиты:
- uniset-iotest — тестирование работы с картами ввода-вывода;
- uniset-iocalibr — калибровка аналоговых датчиков;
- uniset-codegen — генератор скелета процесса управления.
Дополнительные проекты
Программный интерфейс (API) библиотеки libuniset стабилизировался уже давно, и постепенно в дополнение к ней возникли различные вспомогательные программы. Поскольку целью данной статьи является общее знакомство именно с libuniset, ограничимся только перечислением таких дополнений:
- uniset-configurator— графическая утилита, позволяющая производить настройку различных параметров системы (карт ввода/вывода, каналов ввода/вывода, сетевое взаимодействие и т. п. (http://git.etersoft.ru/projects/asu/uniset-configurator.git).
- uniset-testsuite — набор утилит (отдельный проект) для создания специальных тестовых сценариев позволяющих проводить автоматические (регрессионные и не только) тесты работы системы построенной на основе libuniset (http://git.etersoft.ru/people/pv/packages/uniset-testsuite.git).
- uniwidgets — библиотека для построения графических интерфейсов на основе gtkmm, взаимодействующая с использованием libuniset (http://git.etersoft.ru/projects/asu/uniwidgets.git).
Заключение
Библиотека libuniset позволяет довольно быстро создавать «сложные» системы. В чём-то она похожа по идеологии на SCADA-системы, но следует иметь ввиду, что это только поверхностное сходство: пользователю в данном случае представлен полный контроль над работой системы, возможность программировать любые алгоритмы (на языке C++). Хотя следует заметить, что система, построенная на libuniset, может быть легко интегрирована в какую-либо существующую систему (на основе SCADA) — просто выступая, например, в качестве Modbus Slave узла. Или же наоборот, может взаимодействовать с любой сторонней SCADA-системой, просто используя процесс обмена Modbus Master (готовый компонент).
Имеется положительный опыт применения её в ответственных проектах, где она проявила себя как надёжно работающая система (24x7x365).
Ссылки по теме
- Git-репозиторий проекта: git.etersoft.ru/projects/asu/uniset.git
- Страничка проекта: wiki.etersoft.ru/UniSet
Автор: PavelVainerman