Русский
Русский
English
Статистика
Реклама

S7

Промышленный интернет вещей в ПЛК Simatic S7-1x00 на примере протокола MQTT

13.01.2021 20:16:14 | Автор: admin

Обнаружил в базе знаний Siemens (SIOS) интересный пример использования контроллеров линейки S7-1200 и S7-1500 в качестве клиента протокола MQTT

Ссылка на первоисточник:https://support.industry.siemens.com/cs/document/109748872/fb-lmqtt_client-for-simatic-s7-cpu?dti=0&pnid=13685&lc=en-RU

По ссылке можно найти саму библиотеку с функциональным блоком MQTT_Client (с открытыми исходниками, кстати) и пояснительную записку к примеру. Документация сама по себе вполне исчерпывающая, знающие английский язык могут смело идти по ссылке и не читать эту заметку, подарив тем самым себе несколько увлекательных часов инженерных изысканий. А для остальных, менее опытных и/или более ленивых, я кратко расскажу основное и продемонстрирую свой пример работы клиента, творчески переработанный под более-менее реальное применение.

Кратко о терминах.

MQTT message queuing telemetry transport. Протокол телеметрии для передачи сообщений. Затрудняюсь перевести название корректно на русский.

Message сообщение. Непосредственно, сами передаваемые данные. Сообщение состоит из нескольких частей:

-Topic, тема сообщения. Символьная строка, размер которой в исходном примере ограничен 200 символами. Клиенты для получения сообщений должны предварительно подписаться на конкретную тему, т.е. topic

-QoS, quality of service. Дополнительный признак, указывающий ждать ли подтверждения получения сообщения или нет.

-Message text, текст сообщения. Текстовая строка из 500 символов.

Протокол построен на модели подписчик/издатель, общая логика которого слегка отличается от обычной клиент-серверной модели, привычной в промышленных протоколах.

При клиент-серверном подходе один или несколько участников исполняет роль сервера, т.е. узла в сети, который отвечает на запросы клиента. Сервер сам по себе не инициирует связь и не проявляет активность, он лишь отдает запрошенные данные и принимает уставки и команды. При этом адресация данных, тип данных и прочее закладываюся и структурируются изначально на этапе разработки серверной части. Клиент тоже должен знать эту карту адресов Modbus. Изменение набора данных требует перенастройки и клиента, и сервера.

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

Итак, роли в протоколе MQTT.

Издатель он же publisher. Узел, который отправляет сообщения (текстовую информацию) на определенную тему (topic).

Подписчик он же subscriber. Узел, который подписывается на определенные темы. Новые сообщения в заявленных темах подписчик получает автоматически.

Роли издателя и подписчика могут совмещаться на одном и том же узле сети. Это роли клиента.

Роль сервера в протоколе MQTT выполняет узел, который называется брокер. Именно брокер запоминает, какие клиенты на какие темы подписались. Именно брокер принимает сообщения от издателей на определенную тему и автоматически раздает их соответствующим подписчикам.

К брокеру может быть подключено несколько и подписчиков, и издателей. Максимальное количество мне неизвестно. Предположу, что все ограничено лишь мощностью железа, на которой работает брокер и настройками стека TCP/IP операционной системы.

В первоисточнике (см. ссылке в начале) идет архив с библиотекой LMQTT_Client. Архив необходимо распаковать, а библиотеку подключить к уже созданному проекту Step 7. Подключение библиотеки выполняется через пункт меню Options Global Libraries Open library. В результате Вы увидите следующее:

Библиотека подключена к проекту

Библиотека содержит две версии функционального блока клиента протокола MQTT для контроллеров S7-1200 и S7-1500. В моем примере будет использоваться младший ПЛК, S7-1214. Реализации отличаются тем, что старшие S7-1500 позволяют адресовать брокер по доменному имени, а S7-1200 только по ip-адресу. Необходимо перетащить блок LMQTT_Client из библитеки во вкладку Program Files контроллера. Типы данных скопируются в проект автоматически. Далее я отхожу от примера и осуществляю вызов ФБ MQTT_Client из своего собственного функционального блока под названием MQTTExchange:

В принципе, если выполнить все настройки правильно и играть запросами через поля экземпляра функционального блока, то можно проверить работоспособность прямо сейчас. Но вначале пройдемся по основным входным и выходным пинам этого ФБ.

enable при положительном фронте этой дискретной переменной устанавливается соединение с брокером MQTT, при отрицательном фронте соединение разрывается. Т.е. для работы необходимо держать этот вход в состоянии TRUE

publishData структура для отправки (публикации) сообщения. Состоит из бита запроса на публикацию (для отправки сообщения бит необходимо взвести в истину и снять в ложь после появления флага done или error), топика и текста сообщения, а так же признака качестве QoS

subscribeToTopic структура, которая содержит флаг запроса на подписку, флаг запроса на отписку (да, можно в любой момент отписаться от топика), непосредственно имя топика и признак качества

На начальном этапе нам важны следующие две структуры, которые необходимо для установления связи с брокером: это tcpConnParam и mqttParam. Эти структуры я заполняю единожды в OB100 при запуске контроллера. Необходимый минимум для работы протокола описывается ниже.

Аппаратный идентификатор интерфейса контроллера

Идентификатор интерфейса ( сетевой карты ) ПЛК. В моем случае у меня всего один интерфейс. Его ID я уже помню наизусть, поэтому пишу 64. Подсмотреть Hardware ID можно в аппаратной конфигурации ПЛК.

Следующее идентификатор соединения. Именно логического соединения по протоколу TCP/IP, connection ID. Должно иметь значение от 1 до 4096, назначается программистом, у каждого логического соединения должен быть свой уникальный айди, иначе связь не будет функционировать. В моем случае у меня присутствует одно-единственное соединения, и я смело назначаю ему 1

Следующее назначение IP-адрес хоста, на котором функционирует брокер.

В данном примере брокер работает на моем домашнем рабочем компьютере с публичным статическим ip-адресом. Из соображений информационной безопасности два байта ip-адреса стерты. В качестве брокера выступает mosquitto под Windows. Разные способы установки брокера хорошо описаны по ссылке:

http://www.steves-internet-guide.com/install-mosquitto-broker/#manual

Там же можно скачать уже настроенный в базе брокер, его я и использую:

http://www.steves-internet-guide.com/install-mosquitto-broker/#

Никаких особенных настроек не применяется. Сертификаты шифрования не используются (об этом чуть позже). На удаленном компьютере просто запущена программа mosquitto.exe, а на удаленном маршрутизаторе сделан проброс порта 1883 (порт для стандартных коммуникаций MQTT) в локальную сеть.

Я умышленно использую брокер, недоступный локально. Одно дело поднять все в рамках локальной сети в горячо любимом диапазоне адресов 192.168.0.х или 192.168.1.х, а совсем другое убедиться в возможности работы системы, как ей и положено, по удаленным каналам связи. Ведь сам контроллер находится сейчас в лаборатории, он подключен к местному маршрутизатору от провайдера, и у контроллера есть только локальный ip-адрес, а не публичный и, тем более, не публичный статический ip.

Кстати, помним, что для организации выхода в интернет контроллеру в данном случае необходимо явно указывать шлюз в настройках его ip-адреса.

Обязательно надо прописать router address, иначе ПЛК не сможет подключиться к внешнем ресурсам глобальной сети

Следующая настройка порт, по которому удаленный брокер слушает соединения. По непонятной причине в примере этот порт указан, как 1884, в то время как стандартным портом для нешифрованных коммуникаций является 1883. Задаю его явно:

Последняя настройка символьное имя клиента. Должно быть уникально в системе. В качестве имени у меня задано S7-1214.

Гораздо разумнее было бы сделать имя клиента уникальным автоматически. Например, сделать его составным из слова SIMATIC и уникального серийного номера центрального процессора (прочитав его соответствующей системной функцией и переведя в строковое представление). С остальными настройками рекомендую ознакомиться в документации. Остановлюсь на двух из них, весьма интересных.

Первое. Last will. Буквально на русском языке завещание (сетевые граждане такие юмористы!). Если выполнить эту настройку, то клиент при подключении к брокеру передает и ее. В случае отвала связи клиента, брокер автоматически разошлет это завещание всем участникам обмена. Завещание является таким же сообщением, у него так же задается топик и текст.

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

Выставив поле activateSecureConn в настройках необходимо провести еще ряд манипуляций активировать глобальные настройки безопасности проекта, импортировать сертификат брокера, создать сертификат контроллера и так далее. Вопросы зашифрованного соединения я уже поднимал в заметке про OPC UA коммуникации. В целом же действия тут больше напоминают настройки безопасного соединения для Open User Communications (SecOUC). В настоящем примере вопросами безопасности передаваемых данных я пренебрегаю. Подробности настройки описаны все в той же документации.

Закончив настройки, необходимо убедиться, что все работает, как надо. Для начала, конечно же, просто подпимем соединение с удаленным брокером. Для этого достаточно подать истину на вход enable функционального блока LMQTT_Client:

Как видно, при поданном enable выходные биты tcpEstablished и mqttEstablished содержат истину, это означает, что связь установлена успешно. В процессе испытаний я обнаружил интересное поведение блока, а именно при подачи истины на вход enable подтверждение связи появлялось на одну-две секунды и пропадало. Связь устанавливалась только со второй попытки. Кроме того, при физическом обрыве связи этот ФБ просто информирует об отсутсвии соединения, и не предпринимает попыток автоматически пересоединиться. В целях автоматического соединения и пересоединения добавлен следующий нетворк:

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

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

По переднему фронту (то есть, по единомоментному факту) установления соединения я поднимаю локальную битовую переменную #SubscriveToTopics и выставляю номер шага процедуры подписки в 1. Номер шага используется в связи с тем, что все операции у нас ассинхронные, и их надо выполнять последовательно, одну за другой, а не все сразу (все сразу не выполнятся).

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

Смотрим. Если выставлен бит выполняем подписку и шаг = 1, то

если не выставлен бит управляющей структуры подписатся, то задать имя интересующего топика (global) и поднять бит управляющей структуры подписаться

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

Шаг 2. На этом шаге не нужно делать вообще ничего. Этот шаг требуется для того, чтобы ФБ клиента вызвался хотя бы один раз со сброшенным битом управляющей структуры подписаться. Для этого есть и более изящные решения, но я обошелся простейшим таймером.

После 100мс ожидания просто идем на следующий шаг, к подписке на второй топик (шаг 3).

Шаг 3 аналогичен шагу 1, за исключением имени топика. После успешного завершения шага 3 сбрасывается локальный бит выполнить подписку (#SubscriveToTopics) и обнуляются шаги подпрограммы подписки.

После выполнения подписки можно смело проверять работу клиента. Для этого я вызываю программуmosquitto_pub.exe:

mosquitto_pub.exe -h myhost.mydomain.ru -t global -m kill all humans

, где

myhost.mydomain.ru доменное имя удаленного брокера

global топик global, на который только что подписался клиент

kill all humans текст сообщения в топике global

После отправки сообщения смотрим выходную структуру subscriptionsMessage:

Как видно, в топике global прошло сообщение kill all humans

Флаг newMessageReceived нам еще пригодится в дальнейшем. Этот флаг выставляется сразу по получению нового сообщения и действителен в течении одного цикла сканирования. По нему очень удобно будет обрабатывать полученные команды, уставки или запросы.

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

Нетворк отправки данных для разнообразия написан на SCL, а не нарисован в LAD. Право же, оперировать строками в графических языках не самое удобное дело.

Всего отправляется значение 4 переменных, три из которых заданы статично в блоке данных, а одна постоянно увеличивается на небольшую дельту. На первом шаге подпрограммы задается имя топика, это имя personal0. А так же формируется строка сообщения. Поскольку оперируем мы именно символьными данными, приходится выполнять преобразование типа REAL_TO_WSTRING и конкатенацию строк. Для контроллеров, тем более, начального уровня, это не самое лучшее занятие очень быстро расходуется память и неплохо так съедаются вычислительные ресурсы. Длина передаваемого сообщения 500 символов, есть куда развернуться. Можно, так же, добавить еще и метку времени. Можно формировать буфер сообщений, тем самым аккумулируя хотя бы минимум данных на период отсутствия связи. В общем, тут можно делать, что угодно (но лучше делать, что написано в ТЗ).

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

Запустим клиент MQTT и посмотрим, что приходит в топике personal0 (именно в этот топик ПЛК и отправляет данные):

Ну, и напоследок. Демонстрация возможностей удаленного управления. Если в топике personal0 пришло сообщение exterminate, дискретный выход Q0.0 устанавливается в значение истина.

Команда издателя:

mosquitto_pub.exe -h host.domain.ru -t personal0 -m exterminate

Нетворк программы контроллера:

Проверка пришедшего сообщения выполняется только по факту прихода самого сообщения (бит newMessageReceived), что вполне логично. А далее необходимо только проверять имя топика и текст сообщения. Любые дальнейшие действия программируются, как угодно.

На этом технический пример заканчивается, и хочется немного порассуждать о возможностях применения. Они есть, и, кажется, весьма широкие. Фактически, это можно применять в любых распределенных недорогих системах, где присутствуют малые объемы информации и, в силу этого, использование специализированных телемеханических протоколов нецелесообразно в виду их высокой стоимости. Ну, например, в ЖКХ. Если маленький ПЛК смотрит на расход энергоресурсов (общедомовых, а, может, даже и поквартирных) и раз в сутки отправляет сводку в диспетчерский центр. Или смотрит на состояние общедомового оборудования, шлет параметры раз в час, но при аварии моментально. Достаточно лишь снабдить ПЛК GSM-модемом, и фактически, ничего больше не требуется, кроме простого компьютера с фиксированным ip-адресом. Рассуждая дальше, можно и без физического ПК обойтись, засунув его в облако. Главное, не забыть должным образом настроить шифрование трафика. В этом случае имеет смысл данные потребления энергоресурсов из клиента сразу складывать в базу данных, но это уже требует высокоуровневого программирования

Или, как вариант, та же распределенная система, но не только сбор данных, но и взаимодействие M2M (контроллер-контроллер). Тут точно так же, достаточно минимального канала связи и доступного брокера.

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

Дальнейшие исследование показали отличное применение mqtt совместно со средой Node-RED. На Node-RED была "нарисована" программа, принимающая эти данные от брокера, разбирающая полученную строку и записывающая всю информацию (метку времени, значение) в базу данных MariaDB. Она же, программа на Node-RED позволила вытаскивать информацию за указанный временной промежуток, показывать ее в виде таблицы, графика и делать выгрузку в виде .csv файла.

Подробнее..

Морской старт возвращение блудного космодрома

14.09.2020 10:18:41 | Автор: admin


На Дальнем Востоке, порту Славянка, у списанных плавучих доков и стареньких буксиров, над серыми пятиэтажками инопланетной белоснежной громадой возвышается Морской старт. Плавучий стартовый комплекс космических ракет состоит из двух судов Sea Launch Commander и Odyssey. Более двадцати лет своей активной жизни они провели неподалеку от Лос-Анджелеса, а сейчас вернулись домой.

Морской старт можно считать историческим наследником программы Энергия-Буран. Хотя напрямую они не связаны, но занимались созданием плавучего космодрома во-многом те же специалисты. Идея запускать ракету из самой географически подходящей точки на Земле акватории Тихого океана в области экватора понравилась многим и в консорциум вступили российская РКК Энергия (25%), норвежский производитель нефтяных платформ Kvaerner (20%), украинские КБ Южное и ПО Южмаш (15%), и американский Boeing (40%).

Основным источником средств выступал Boeing, остальные же участники больше вкладывались технологиями и работой. Для американцев интерес был двойной: с одной стороны загрузить работой постсоветских ракетчиков, чтобы они не разъехались по Иранам, Северным Кореям и прочим дружественным Америке странам; с другой США было нужно более дешевое средство запуска тяжелых геостационарных спутников чем Space Shutlle.

Проект стартовал в 1995 году, и в 1999 состоялся первый успешный пуск демонстрационной болванки. Место запуска из Тихого океана выбрано по трем причинам:
с экватора наименее энергозатратны запуски на геостационарную орбиту телекоммуникационных спутников, т.к. не приходится тратить топливо на изменение наклонения орбиты;
пуску с экватора дополнительно помогает осевое вращение Земли, добавляя около 150 м/с скорости или около 3% экономии массы топлива, по сравнению с Байконуром;
после старта отработавшие ступени ракеты падают в океан, и не надо тратиться на их утилизацию.

Морской старт требовал уникальных технологий, ведь в относительно компактных масштабах пришлось разместить монтажно-испытательный комплекс, заправочную систему, наземную станцию управления, Центр управления полетом, и стартовый стол. Причем всё это для ракеты тяжелого класса. Всё это на обычных космодромах занимает сотни гектар, а тут распределяется между судном обеспечения Sea Launch Commander длиной 203 м, и пусковой платформой Odyssey длиной 133 м. Но всё равно это получились колоссальные конструкции, масштаб которых сложно оценить по фотографиям.



Юридически там тоже была непростая схема. Компания Sea Launch была американской, но её долями владели участники проекта из разных стран. Требования Госдепа США о нераспространении технологий относились к этому проекту, несмотря на мир, дружбу и жвачку между американцами и постсоветскими странами. Головной частью ракеты занимался Boeing и она доставлялась в порт уже в полностью собранном и капсулированном виде чтобы российские и украинские пусковые команды не могли заглянуть под обтекатель. Ракета использовалась украинская Зенит-3 в морской модификации. Разгонный блок российский ДМ от РКК Энергия, также на Зените использовались российские двигатели РД-171.



Все компоненты: американская головная часть с полезной нагрузкой, российский разгонный блок и украинская ракета собирались в порту Лонг Бич в трюмах Sea Launch Commander. Там же готовая к пуску, но незаправленная ракета перегружалась на Odyssey, после чего проходил сухой вывоз и установка ракеты для последних проверок.



Успешно проведя репетицию платформа прятала ракету в ангаре и своим ходом отправлялась в море. Командный корабль догонял платформу через несколько дней. На точке пуска проходили последние приготовления, заправка, и команда Odyssey переходила по трапу на Commander.

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



Предпусковая подготовка ракеты выполнялась в автоматическом режиме, и следовал старт.

Далеко не все пуски проходили успешно. Из 36 стартов было три аварии, причем одна прямо на стартовом столе.



От взрыва никто не пострадал, но корабль пришлось почти год ремонтировать. Ещё через год компания подала на банкротство. Трехмиллиардные инвестиции не окупались, у США появились свои тяжелые ракеты благодаря программе EELV, и спрос упал. Бизнес-план Морского старта предполагал не менее четырех пусков в год, но удалось такое только три раза. Последний пуск состоялся в 2014 году после чего любое сотрудничество России и Украины в космосе стало невозможным.

После банкротства 2009 года проект перешел практически в полную собственность РКК Энергия, но долг перед Boeing в $330 млн оставался. За эту юридическую спецоперацию тогдашний глава РКК Энергия Виталий Лопота получил уголовное дело и сейчас находится под подпиской о невыезде.

В 2016 году проект выкупила российская частная компания S7 Space, а долги перед американцами компенсировал Роскосмос. За счет российского госбюджета астронавтам NASA предоставили дополнительные места в российских космических кораблях Союз. Подробнее я уже рассказывал.

Всё это время пара кораблей базировалась в порту Лонг Бич в Калифорнии. S7 Space попыталась деполитизировать российско-украинско-американский космический проект с помощью сборки ракет там же в порту, но не справилась с этим. Производство Зенитов восстановить не удалось, а запускать другие ракеты не давал Госдеп США. Ситуация серьезно усугубилась после гибели в авиакатастрофе совладелицы группы компаний S7 Наталии Филёвой. Окончательно подкосил российского авиа-космического частника коронакризис, который сильно ударил по основному бизнесу компании.

Главное достижение S7 Space транспортировка пусковой платформы и командного судна в российский порт Славянка, под Владивостоком. Но за этот заплатить пришлось не только деньгами.



Главная потеря часть радиоэлектронного и пускового оборудования плавучего космодрома. Американское правительство потребовало, чтобы американская техника осталась на родном берегу, и украинская тоже. Глава Роскосмоса так описывал потери: перед его передачей компании S7 все оборудование управления космическим пуском буквально "с мясом" было выдрано.

Были слухи, что к плавучему космодрому присматривался Росатом, и оценил восстановление в $1,2 млрд Но официального подтверждения не было. Позже вице-премьер Юрий Борисов озвучил планы правительства: Морской старт восстанавливается за бюджетные средства в размере примерно $0,5 млрд, Роскосмос создает ракеты Союз-5 и Союз-6, S7 Space продолжает участие в частно-государственном партнерстве. Возможно какое-то участие примет и Росатом.

В сентябре 2020 года уже российский космодром Морской старт впервые показали журналистам и блогерам.

Первое, что поражает это масштаб. Корабли огромны, особенно для тех, кто не привык к таким размерам.



С пирса даже широкоугольного объектива не хватает чтобы охватить взглядом хотя бы одно судно.

Второе диссонанс между ухоженными, хоть и не самыми современными кораблями Sea Launch, и окружающей приморской действительностью. Серые безлюдные цеха, с выбитыми стеклами и эко-крышами, поросшими молодым тропическим лесом. Брошенные умирать плавдоки, и корабли, которые если и выйдут в море, то только на резделку.







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



Многих журналистов и блогеров интересовали те самые места на кораблях разоренные когтями американских ястребов. Но их-то и не показали, чтобы не портить впечатление. Зато проводили на верхнюю палубу командного судна.





Кают-компанию.



Командную рубку.



Важное технологическое оборудование управления пуском.



Место капитана напомнило что-то из Star Trek.





На вертолетном ангаре из окон видны логотипы спутников, которые запускались Sea Launch.



Монтажно-испытательный трюм.



Сейчас это просто склад для оборудования, которое эвакуировали из США. Например этот контейнер от разгонного блока ДМ.



Крестовую отвертку под этот винт я так и не нашел.



Хотя, на самом деле, это крепления для найтовки груза.



Следующий на очереди посещения стартовая платформа Odyssey.

Необычная конструкция под рубкой управления устройство перегрузки ракеты из командного судна в пусковое.



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

После перегрузки, ракету закрепляли в лежачем виде на подъемном устройстве, и так, в закрытом ангаре, проводили транспортировку.



Любопытно, что парой лет ранее я побывал на Атоммаше где делали этот подъемник, а сейчас производят корпуса атомных реакторов. О своем вкладе в космонавтику там до сих пор помнят и гордятся.



Наконец, апофеоз экскурсии стартовый стол.
Газоотводный канал, который принимал струи всех 36 ракет, которые отсюда стартовали. Необычные клыки в канале это система охлаждения пламяотсекателя и гашения аккустических волн. Через них подается пресная вода, которая снижает нагрузки на конструкцию стартового стола.



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

Вот так эта часть конструкции выглядит со стороны.

На фоне lozga

В момент включения ракетного двигателя видно как гигантские струи пара разлетаются в стороны из-под стартового стола.



Совсем неподалеку емкости хранения жидкого кислорода. Обычно они защищаются от ракетных газов небольшим заслоном.



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

Кабель-мачта. (А-образные элементы, расставленные по всему столу это опоры для корабля на случай его установки в сухой док).



Наконец, ответы на самые важные вопросы:

Может ли космодром совершать пуски сегодня, если будет ракета?
Нет, не может из-за удаленной американцами электроники и украинских стартовых систем.



Что из электроники удалено и требует замены?
Системы радиосвязи между двумя судами. И это не только рации для переговоров между экипажами. Это практически вся командно-телеметрическая система, передающая информацию между ЦУПом и стартовым столом вместе с ракетой. Такая система есть на каждом космодроме, но, как правило это кабельная сеть. На Морском старте была дистанционная, и её уже нет.
И это еще не всё. Вторая жизненно-необходимая система позиционирования, без которой невозможно идеально точно поставить два гигантских корабля рядом в центре океана. Такое позиционирование необходимо для перехода экипажа с пускового судна на командное перед стартом.



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

Способна ли Славянка обеспечить Морской старт в режиме работы активного космодрома?
Нет, нужна новая теплоэлектростанция, а для неё нужно тянуть газ в Славянку. Тут можно рассуждать об улучшении уровня жизни в поселке после прихода газа, мне же подумалось, что эта задача подходящее применение для плавучей атомной электростанции Росатома.



Сможет ли Морской старт конкурировать со SpaceX?
Нет, не сможет. Однозначно. Нынешняя политическая и экономическая ситуация в мире ставит крест на всех надеждах добиться прибыльности российских космических ракет на мировом рынке, с какого бы космодрома, какая бы ракета ни запускала. Когда SeaLaunch был американским оставалась надежда, что его получится использовать для обхода ограничений Пентагона, но сейчас уже никак. Поэтому впереди только госзаказ, и редкие заказы третьих стран, которые не боятся американских санкций.

Зачем тогда вообще нужен России Морской старт?
Да, прост. Крутая же штука, жалко резать на металлолом.
А если серьезно, то это прежде всего хороший имиджевый проект. Красивый и романтичный, хоть и бесполезный для экономики, как город на Марсе. Для Роскосмоса он дает ряд косвенных выгод это дополнительный удобный повод перейти на новые ракеты Союз-5 и Союз-6, и сэкономить на строительстве стартовой площадки для них. А ракеты эти, в свою очередь, нужны чтобы дать работу химкинскому Энергомашу, который двадцать лет держался продавая двигатели украинским Зенитам и американским Atlas V, и находится под угрозой остаться совсем без работы через год-два. Нынешняя рабочая лошадка Роскосмоса Союз-2 прекрасная ракета и эстетически и технически, но двигатели для неё производит предприятие Ростеха, т.е. вне контура, что выводит часть бюджетных средств на сторону от Роскосмоса, это его не устраивает. Также Союз-5 и Союз-6 это элементы проектируемой Роскосмосом лунной ракеты, поэтому если будут летать они, то покорение Луны станет немного дешевле и реальнее, если государство-таки найдет средства на эту задачу.

Будет ли жить Морской старт и вообще российская космонавтика?
Да, но за наш с вами счет, дорогие налогоплательщики. Так, что обогащайтесь, господа, законопослушные граждане, обогащайтесь. Поднимайте ВВП и космос будет наш.

Выражаю признательность пресс-службе Роскосмоса за помощь в подготовке фоторепортажа.
Подробнее..

Сервер Modbus TCP для Simatic S7-1200 S7-1500

06.01.2021 08:23:22 | Автор: admin

Первая спецификация протокола Modbus была опубликова в 1979 году. Протокол предназначен для опроса подчиненных устройств по принципу запрос-ответ. Modbus RTU (Remote Terminal Unit) работает по последовательному интерфейсу передачи данных (RS-232, RS-485, RS-422). Сегодня речь пойдет о немного измененном протоколе, Modbus TCP, работающий на прикладном уровне стека протоколов TCP/IP.

Для начала посмотрим, как настраивается (программируется, если быть точнее) серверная часть. Modbus TCP Server аналог Modbus RTU Slave, то есть, является подчиненным устройством. Это важно, не путайте. Сервер лишь отвечает на запросы, но не генерирует их.

В данном примере применяется CPU S7-1516 с версией прошивки 2.6. Серия S7-1200 программируется аналогично.

Для начала разместим в OB1 экземпляр функционального блока MB_SERVER (Instructions Communications Others MODBUS TCP).

Далее необходимо сделать три вещи. Во-первых, подать что-нибудь на вход MB_HOLD_REG. Этот входной пин экземпляра ФБ должен содержать область памяти, которая выделяется на регистры хранения (holding registers).

Небольшое отступление. В версиях библиотек Modbus TCP до 5.0 переменные дискретные входы (Discrete inputs), т.е. те двоичные переменные, которые можно только читать это непосредственно все BOOL'евые переменные из области процесса %I. Coils, катушки дискретные переменные, которые можно и читать, и записывать, это область %Q. Input Registers, входные регистры это слова данных из области %I, точнее %IW. Грубо говоря, все дискретные переменные протокола Modbus и аналоговые входа являются переменными областей памяти I или Q. Это дает возможность читать непосредственно значение входов, а так же записывать значения дискретных выходов напрямую. С моей точки зрения нелогично отдавать возможность управлять дискретными выходами какой-нибудь сторонней системе, пусть даже и теоритическую, поскольку в зависимости от построения прикладного ПО контроллера, на эти выхода будет приходить правильное с точки зрения системы значение. Для того, чтобы ограничить клиентам Modbus TCP возможность прямого обращения к выходам, в экземпляре функционального блока есть несколько переменных.

Нас интересуют все переменные, которые начинаются на IB и QB. Указав в качестве значений QB_Count, QB_Read_Count и IB_Count нули, вместо значения по умолчанию 65535, мы запрещаем полностью чтение/запись входов/выходов напрямую.

Для чтения/записи регистров хранения, в свою очередь, необходимо отдельно вручную задать область данных. Мой личный опыт показывает, что наиболее удобный способ это структура, объявленная в глобальном блоке данных со стандартным (а не оптимизированным) доступом. Я сейчас продемонстрирую, как надо, а под конец данной заметки мы пройдемся по граблям и посмотрим типичные ошибки, которые возникнут, если заполнить данное поле неправильно.

В версии библиотеки, начиная с 5.0 (требуется прошивка 2.5 для S7-1500 и 4.2 для S7-1200) можно иначе переназначать входные дискреты, катушки и прочие переменные модбас. Например завести все в битовые переменные глобального блока данных. Необходимо дополнительная конфигурация, которая описана в пункте Access to data areas in DBs instead of direct access to MODBUS addresses as of version V5.0 встроенной справки.

Итак, добавляем глобальный блок данных с неоптимизированным доступом в картинках.

Нажать Add new block

Выбрать Data block и дать ему осмысленное имя, далее нажать ОК

Вызвать свойства свежедобавленного блока данных

Найти в атрибутах блока галочку Оптимизированный доступ, снять ее, подтвердить снятие и нажать ОК

Открыть в редакторе блок данных и создать в нем отдельную структуру

Заполнить поля этой структуры. Имеет смысл сразу в коментариях делать пометки о номере(адресе) регистра хранения. Откомпилировать блок данных.

Подать созданную структуру на входной пин MB_HOLD_REG

Во-вторых, требуется создать и заполнить структуру типа TCON_IP_v4 или TCON_Configured. Данная структура содержит некоторые подробности для коммуникации контроллера. Лично я предпочитаю первый способ, он мне кажется более аскетичным, а кроме того он не требует загрузки Hardware, в отличии от второго. В связи с тем, что структура относится к настроечной части протокола Modbus, ее можно разместить в уже созданном блоке данных (хотя, никто не запрещает объявить ее, где угодно).

Добавление структуры типа TCON_IP_v4

Поле InterfaceID заполним чуть позже, а сейчас пройдемся по остальным полям.

ID внутренний идентификатор соединения. Допустимые значения от 1 до 4096. Каждое соединение (экземпляр блока MBSERVER, хотя на самом деле все немного сложнее). должно иметь свой уникальный идентификатор. Ставлю равным 1.

ConnectionType тип соединения. По умолчанию стоит 11 (0B в шестнадцатиричной системе): TCP. Его и оставляем.

ActiveEstablished оставляем false, в данном случае сервер не является инициатором связи, инициатором связи являютя клиенты.

RemoteAddress если оставить нули, то к серверу сможет подключиться любой клиент. Если задать удаленный IP-адрес конкретно, то к серверу может обратиться только один явно заданный клиент. Оставляем нули.

RemotePort оставляю ноль, не органичиваю и номер порта со стороны клиента

LocalPort номер TCP порта, по которому будет отвечать сервер. В соответствии со старой-доброй традицией (и RFC) протокол Modbus TCP работает на порту 502 (а игра Doom по порту 666, но это совсем другая история). Порт 502 я указываю явно.

В итоге получаем следующее:

Осталось задать лишь ID интерфейса. Это присвоение я делаю в программное коде, разместив network с присвоением (MOVE) до вызова блока Modbus. Идентификаторы интерфейсов уже созданы в Step 7 автоматически, необходимо лишь найти нужную переменную. В моем случае Modbus будет работать на интерфейсе X1. Его я и нахожу в списке переменных, выпадающем автоматически.

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

Можно так же просто указать значение 64 для переменной "ModbusData".CONNECT_Struct.InterfaceId

Далее подаем на вход CONNECT заполненную структуру и получаем следующую программу:

И, наконец, в третьих, не забываем про переменные экземпляра MB_SERVER_DB. Я о них говорил выше, описание этих переменных можно почитать во встроенной справке. Если их не трогать, то обмен, все равно, будет работать, это уже вопрос доводки обмена и доступа ко входам и выходам.

Компилируем программу, загружаем ее в контроллер и выходим Online:

Статус 7002 не означает ошибку, он говорит о том, что соединиение устанавливается. Обязательно почитайте описание возможных значений поля STATUS, пригодится. Перед тем, как начать читать/записывать данные при помощи стороннего Modbus-клиента, дадим переменным ненулевые значения (разумеется, мои любимые число зверя и три топора).

В качестве Modbus-клиента можно использовать любой проверенный софт. Главное правильно сформировать запрос со стороны клиента. В нашем случае объявлено всего 5 регистров хранения, и если запросить 10, то сервер Modbus вернет ошибку, и будет прав. Второй немаловажный момент не забывайте про порядок байт в слове: если little endian отображать, как big endian, или наоборот, то вместо разумных чисел на экране будет ерунда. На данном скриншоте клиент настроен на опрос 5 регистров хранения, представление данных, как float, настроено переворачивание байт в словах:

Чуть выше я говорил, что дискретные выхода контроллера (точнее, биты области %Q) это и есть койлы с точки зрения протокола Modbus, и что при настройках по умолчанию клиент получит возможность как читать сигналы напрямую, так и записывать их. Давайте в этом убедимся. Для начала на модуле дискретных выходов я объявляю переменную, для дальнейшего удобства:

Нулевой бит восьмого байта выходной области. Номер 64, если считать с нуля (8 * 8 + 0 = 64). Задам в контроллере значение истина и прочитаю в Modbus-клиенте:

Вижу значение истина (читаю один койл с начальным смещением 64). Изменю это значение на ложь со стороны modbus:

Значение, разумеется, так же изменилось и в Step 7, и в контроллере, и на выходе модуля (это одно и то же):

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

После этого изменения в блоке данных (прямо в online, без перезаливки и перезагрузки контроллера) клиент протокола modbus в ответ на требование записи катушки показал табличку Illegal data address, а именно такое сообщение и вернул сервер. Дополнительную информацию читаем в справке: Restriction of read access to process images as of version V5.0.

Теперь давайте посмотрим, что происходит при некорректном назначении области памяти от регистров хранения. В первую очередь достаем встроенную справку Step 7 и читаем:

В качестве регистров хранения применять глобальный блок данных с оптимизированным доступом или битовую область. И вот тут очень интересно. Потому что справка в части MBHOLDREG parameter выглядит следующим образом:

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

Эксперимент 1. Регистры хранения это структура в блоке данных с оптимизированным доступом (почти, как сделано в этом примере). В этом случае получаем ошибку 8187 : The MBHOLD_REG parameter has an invalid pointer. Data area is too small.

Эксперимент 2. Массив переменных типа WORD, объявленный в оптимизированном блоке данных. Работает, со стороны клиента переменные меняются, ошибок нет.

Эксперимент 3. Меркерная область. Работает, с клиента удалось внести значения, ошибок нет.

С моей точки зрения, в документации недостаточно ясно. Должно быть написано используйте блок данных со стандартным доступом или битовую (меркерную) память, а не оптимизированным доступом. В случае оптимизированного доступа вполне подойдут массивы слов. И с моей точки зрения самым удобным способом является способ, описанный в изначальном примере. Эксперимент 2 в принципе тоже работоспособен (и тому есть объяснение), но с моей точки зрения неудобен для работы.

В следующий раз мы займемся клиентом Modbus TCP.

Подробнее..

Клиент Modbus TCP для Simatic S7-1200 S7-1500

07.01.2021 14:19:53 | Автор: admin

Продолжаем тему программирования протокола Modbus TCP на контроллерах Simatic S7-1500. В прошлый раз речь шла о серверной части, сегодня опишем клиентскую. Клиент Modbus TCP это узел, который генерирует запросы к серверу, т.е. запрашивает данные и передает уставки/команды. В терминологии Modbus RTU это мастер, ведущее устройство. В отличии от RTU, в протоколе TCP может быть несколько мастеров (правильно клиентов).

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

По этой причине имеет смысл программировать клиента на языке SCL (ST в терминологии МЭК 61131-3) и завернуть всю обработку в функциональный блок. Для большей реалистичности в данном примере контроллер будет общаться с двумя серверами Modbus TCP с несколькими запросами к каждому.

В первую очередь создадим функциональный блок ModbusClient на языке SCL и добавим вызов его экземпляра в OB1.

Далее в области STAT переменных функционального блока необходимо прописать две структуры TCON_IP_v4. Зачем две? Затем, что у нас два соединения с двумя разными серверами. Фактически у нас два разных соединения (connection) и каждое необходимо описать. Как я говорил ранее, возможно применить и конфигурируемые соединения, но в данном примере они не используются.

Объявлено две структуры для связи с двумя серверами

Далее необходимо заполнить обе структуры. Это возможно сделать как программным кодом, так и просто занести необходимые значения данных. Пойдем по второму пути.

Первое поле, InterfaceId. Идентификатор интерфейса (или сетевой карты) нашего контроллера. Клиент Modbus работает на интерфейсе 1 контроллера, смотрим его ID в конфигурации устройства.

Его ID равен 64. Обращаю внимание, что нужен идентификатор именно интерфейса, а не его портов.

Следующее поле структуры, ID. Это идентификатор соединения. Не путать с идентификатором интерфейса. Не путать с номером модбас-устройства. Это некий внутренний логический номер коннекшена, который программист назначает самостоятельно в диапазоне от 1 до 4096. У каждого коннекшена должен быть свой уникальный идентификатор. Ответственность за корректное присвоение целиком на ваших плечах. Назначаем ID = 1 и едем дальше.

Далее идет тип соединения, ConnectionType TCP или UDP. По умолчанию значение этого поля 0x0B в hex или 11 в dec. Оставляем по умолчанию, TCP.

Флаг ActiveEstablished. Выставляем его в истину. В случае клиента именно наша сторона должна инициировать соединение.

RemoteAddress. Тут пишем IP-адрес нашего первого сервера. Пусть будет 192.168.43.100.

RemotePort. Номер порта, по которому сервер Modbus TCP будет отвечать на наши запросы. По умолчанию все сервера этого протокола должны слушать порт 502.

LocalPort. Оставляем равным нулю.

В итоге, описание соединения с первым сервером выглядит следующим образом.

Описание соединения с первым сервером

Вторая структура заполняется аналогично. Разумеется, пишем другой ID и другой IP адрес. В итоге получаем.

Сделаем первые робкие шаги и попробуем прочитать один регистр хранения с одного сервера. Для начала надо перетащить ФБ MB_CLIENT из библиотеки в программу.

После перетаскивания появится диалогое окно о создании экземпляра. Выбираем мульти-экземпляр и немного корректируем имя.

Выбираем мультиэкзепляр

Промежуточный итог

Приведем вызов в человеческий вид

Кратко пройдемся по параметрам этого вызова. Подробное описание в нашей горяч0 любимой документации, которую мало кто, почему-то, читает.

REQ активирует выполнение опроса. Пока REQ = TRUE, клиент проводит чтение данных с сервера или запись данных на сервер.

DISCONNECT разорвать соединение

MB_MODE режим работы клиента. В совокупности со входом MB_DATA_ADDR оказывает влияние на используемую функций Modbus TCP. Возможные значения описаны в документации. Для чтения одного или нескольких регистров хранения значение MODE должно быть равно 0.

MB_DATA_ADDR указывает адрес в адресном пространстве протокола Modbus TCP. Значение нашего примера 40001 первый регистр хранения

MB_DATA_LEN количество читаемых или записываемых величин. В нашем случае единица. В итоге все три указанных выше параметра означают читать один регистр хранения начиная с адреса 40001

MB_DATA_PTR переменная или структура данных, куда мы записываем прочитанное значение. Переменная может быть в любом блоке данных, я объявил локальную статическую переменную SingleHR типа INT, размер которой равен 2 байтам и совпадает с размером одного регистра хранения Modbus. При несовпадении размерности читаемой области данных с локальным хранилищем вызов функционального блока завершится ошибкой.

CONNECT уже созданная нами структура типа TCON_IP_V4

Остается только запустить на ноутбуке сервер Modbus, скомпилировать и загрузить программу контроллера, и не получить ничего. Сервер не отвечает. Ответов нет. Вообще ничего нет. Ничего. По буквам Николай, Илья, Харитон ( Остапа понесло ). Для того, чтобы уточнить ошибку, необходимо доработать программу следующим образом.

Дело в том, что флаги успешного (DONE) или неуспешного (ERROR) вызова блока живут всего один цикл сканирования программы. Естественно, невозможно заметить настолько быстрое изменение. Поэтому по флагу ошибки я копирую статус вызова в отдельную переменную. А по флагу успешного выполнения обнуляю статус.

Кроме того, добавлены флаги управления запросом и соединением.

Немного прокоментирую ошибку, которая возникла у меня. В моем случае код ошибки был 80C6. В описании на блок MB_CLIENT этой ошибки нет, поэтому я вбил код ошибки в поиск справочной системы и нашел ссылку на функцию TCON (так же при неоднозначных ошибках можно искать и среди TSEND, TRECEIVE и прочих похожих блоках). Описание: The connection partner cannot be reached (network error). Ошибки сети. Ответ был очень прост и заключался в том, что программа-иммитатор Modbus не была прописана в разрешениях встроенного в Windows Firewall. Точнее, разрешение на ее работу было настроено только на частные сети, а интерфейс программатора был назначен в качестве публичной сети. Это лишний раз подчеркивает, что техника виновата в последнюю очередь, а чаще всего ошибку надо искать в радиусе закругления рук и в соответствии этого радиуса ГОСТам. После изменения настроек брэндмауэра ОС обмен заработал.

Усложним теперь задачу самую малость, и попробуем считать с сервера одну вещественную переменную. Одна вещественная переменная (REAL) это 4 байта. Или 2 регистра. Итого, в вызове я увеличил количество читаемых регистров до 2, и изменил указатель на прочитанные данные. Этот указатель все еще весьма прост это внутренняя статическая переменная типа REAL (дальше будет интереснее).

Хотелось бы обратить внимание на одну важную деталь. Если прогружать измененное прикладное ПО на горячую, с переинициализацией переменных нашего функционального блока ModbusClient в то время, когда контроллер ведет опрос сервера Modbus, то обмен может прекратиться, и на выходе блока будет стоять статус 80A3. Связано это, разумеется, со вмешательством во внутренние структуры обмена (из-за переинициализации всего блока). В моем случае это приводило к полной невозможности коммуникаций до рестарта контроллера переключателем старт/стоп. Я намеренно изменил сейчас функциональный блок (добавил еще одну переменную), чтобы продемонстрировать эту ошибку:

После стоп/старта контроллера и поднятия флага Srv1Req обмен успешно возобновляется. Чтобы не допустить такого зависания обмена (как ни крути, это частный случай) необходимо поднимать флаг Srv1Disconnect, проводить изменения в переменных функционального блока (имеются в виду именно переменные, т.е. интерфейсная часть блока, а не сам программный код), выполнять загрузку с переинициализацией, а потом вручную возобновлять обмен. Помните же, что флаги REQ и DISCONNECT у нас подключены к переменным, и этими переменными можно управлять, как вручную, так и посредством программного кода.

Пока мы не продвинулись дальше, хочется продемонстрировать описанный выше случай с разноконечностью (little-endian и big-endian) данных. В моем примере сервер modbus держит в двух регистрах хранения вещественную переменную со значением 0.666. Наш клиент Modbus вместо этого числа читает 1.663175E+38, что сильно отличается от нужного (увы, вне зависимости от того, покупаем мы или продаем). Связано это, конечно же, с порядком байт в словах и порядком самых слов в двойном слове. Пробуем разрешить ситуацию. Доработаем программный код следующим образом.

Инструкция SWAP меняет порядок байт (конкретно тут в двойном слове). Но в данном случае она не помогает, на выходе (в переменной Data.Test) все еще находится неправильное значение. Скорее всего, это означает, что сервер отдает регистры в неправильном порядке, а байты в правильном, то есть информация перемешалась. Радует, что байта всего 4 и составить их в нужном порядке дело техники.

Итак, снова модифицируем запрос. Складываем результат чтения двух регистров в массив из 4 байт и объявляем еще один массив из 4 байт, которым и будем манипулировать.

Функция Deserialize складывает массив из байт в какое-либо конкретное значение, в данном случае в вещественную переменную. Потребовалась всего одна итерация, чтобы получить корректное значение переменной с сервера Modbus.

Перед тем, как вернуться к штатной рутинной работе, необходимо рассказать про одну очень частую ошибку, возникающую при обмене по протоколу Modbus TCP, а именно указание или неуказание адреса (номера) подчиненного устройства (сервера). В протоколе Modbus RTU все слейвы имеют свой уникальный адрес в сети. Мастер, формируя запрос, указывает адрес слейва, однобайтовое поле в заголовке пакета. Unit ID, Device ID, адрес неважно, как называется, смысл один. В протоколе Modbus TCP адресом абонентского устройства является его IP-адрес. Тем не менее, поле Device ID в заголовке сохранилось. И это часто вносит путаницу, непонимание и ошибки. Дело в том, что в соответствии со спецификациями обычный сервер Modbus TCP должен игнорировать поле ID в запросе к нему. Unit ID учитывается лишь для устройств, преобразующих Modbus RTU в Modbus TCP (гейты, шлюзы, конвертеры протоколов и так далее). На практике же многие сервера Modbus проверяют и однобайтовый адрес Unit ID. При несовпадении своего адреса и адреса в запросе, сервер в этом случае чаще всего не отправляют никакую ответную телеграмму, и клиент возвращает ошибку опроса. Если на практике вы столкнетесь с таким странным поведением, то откройте экземпляр функционалного блока клиента Modbus и поищите в его статических переменных байтовую величину MB_Unit_ID. Это и есть адрес подчиненного устройства, т.е. сервера Modbus. По умолчанию его значение равно 0xFF или 255. Нормальные сервера его игнорируют, достаточно уже самого факта установления соединения по протоколу TCP/IP. Если же попался ненормальный, то поставьте тут вручную Unit ID вашего устройства. Связь должна установиться.

Кроме того, в статических переменных есть ряд полезных настроек, таких, как таймауты, количество повторных попыток запроса и т.д. Изучить эти переменные можно во встроенной справке.

Закончив описание подводных камней, вернемя к изначальной задаче. Будем считывать с первого сервера 3 вещественных переменных (6 регистров), начиная с 40001, и записывать одну (начальный адрес 40011). Предполагаем, что порядок слов и байт правильный. Шесть регистров (шесть слов данных) и три вещественных переменных. Можно, конечно, просто в лоб читать информацию в локальный массив байт, а потом средствами дополнительной обработки представлять их в виде трех вещественных величин (тем же Deserialize, например), но не стоит создавать себе лишнюю работу. Гораздо удобнее будет сразу разложить читаемую информацию в собственную структуру. В блоке данных Data я создаю структуру, состоящую из трех полей типа REAL.

Обращаю внимание, что блок данных Data должен быть стандартным или неоптимизированным, в противном случае вы будете получать ошибку опроса, к примеру 818B.

Разумеется, содержание этой структуры полностью зависит от того, в каком порядке и в какой форме отдаются данные от сервера.

Программа обретает следующий вид, и данные успешно читаются.

0.5, 0.7, 0.33 (с) ВИА Несчастный случай

Теперь необходимо добавить еще один запрос на запись одной вещественной уставки (двух регистров). Необходимо понимать, что для обмена с одним сервером по одному соединению у нас выделен один экземпляр функционального программного блока коммуникаций. И если выполнять второй запрос, не дожидаясь результатов первого не будет работать ни один. Необходимо работать последовательно вначале выполнить один запрос, а после его завершения формировать следующий. Для этого достаточно добавить в наш программный блок переменную номер шага (или номер запроса, если вам так удобнее).

В итоге получаем вот такую программу.

Переменная, на основании который выбирается опрос, называется у меня Server1Query (будет еще Server2Query). Выбор запроса выполнется в операторе CASE. Номер запроса меняется на следующий лишь в случае успешного или неуспешего выполнения текущего опроса.

Для того, чтобы организовать опрос второго сервера, достаточно лишь подготовить хранилище для локальных переменных от сервера и к серверу и дописать существующую программу. Отличия в ней минимальные, тот же принцип, отличаются лишь все переменные (включая экземпляр функциональого блока MODBUS_CLIENT) и запрашивамые/записывемые данные.

Со вторым сервером у нас настроено отдельное соединение, есть отдельный экземпляр функционального блока modbus. Его мы можем вызывать одновременно с коммуникациями первого сервера, поэтому в общей программе есть два оператора CASE, которые работают независимо друг от друга.

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

Тем не менее, описание работы с протоколом Modbus TCP на этом я заканчиваю. В следующий раз посмотрим на программирование протокола Modbus RTU.

Подробнее..

Программирование Modbus RTU Master на примере Simatic S7-1200 и ПЧ Sinamics V20

08.01.2021 22:18:59 | Автор: admin

Давно хотел рассказать про тонкости программирования обмена по протоколу Modbus RTU в случае, когда контроллер (в нашем случае S7-1214) выступает RTU Master'ом. Недавно меня попросили помочь с обменом между ПЛК и частотным преобразователем Sinamics V20, ну и почему бы не написать заодно заметку, постаравшись приблизить решение задачи к боевым условиям.

Собственно говоря, сами немцы эту тему давно осветили:

SINAMICS V: Speed Control of a V20 with S7-1200 (TIA Portal) via USS protocol/MODBUS RTU with HMI

https://support.industry.siemens.com/cs/ru/ru/view/63696870/en

Смотрите этот пример, он сделан очень толково, с визуализацией,диалогами и квестамии возможностью расширить прикладную программу до опроса множества ПЧ V20 по нескольким интерфейсам (S7-1200 позволяет установить в свою корзину до 4 портов RS-485/422). Пример сделан очень хорошо и очень педантично. Вопросов коммуникаций по протоколу Modbus TCP я уже касался ранее, они есть на хабре.

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

Адрес подчиненного устройства модбас в сети: 1

Параметры связи: 9600 8-Even-1

Регистры хранения подчиненного устройства для чтения:

40110 ZSW Слово состояния

40111 HIW Текущая скорость

Регистры хранения для записи:

40100 STW Слово управления

40101 HSW Задание скорости

Параметр частотника Telegram off time (ms) P2014[0] рекомендую оставить по умолчанию, равным в 2000 мс (2 секунды), хоть пример и рекомендует снизить эту величину до 130 мс. Конкретно к протоколу Modbus это замечание не относится, разумеется, просто у меня при таймауте в 130 мс, ПЧ терял связь и выдавал ошибку Fault 72.

С частотником разобрались. Теперь о моей конфигурации ПЛК. Это S7-1214 с коммуникационным модулем 1241 под RS-485/422:

Среда программирования Step 7 V15.1 Update 4, версия прошивки CPU 4.3.

Итак, приступим. Для опроса подчиненных устройств с контроллера Simatic нам необходимо применить два функциональных блока: Modbus_Comm_Load (единовременно, только для конфигурации коммуникационного процессора) и Modbus_Master (циклически для чтения и/или записи регистров/катушек). Поэтому в программе экземпляр FB Modbus_Comm_Load у нас будет встречаться только один раз, а экземпляр Modbus_Master несколько раз, но с разными входными параметрами, в зависимости от адреса подчиненного устройства, типа читаемых данных и их количества, а так же направления передачи данных (чтение или запись). Обращаю ваше внимание, что для одного коммуникационного процессора (а их в системе может быть очень много) у вас не может быть больше одного экземпляра каждого блока данных.

С моей точки зрения весь обмен удобнее завернуть в один внешний функциональный блок, а сам блок, с учетом необходимости разбирать данные, реализовать на текстовом языке SCL. Поэтому создаем в проекте функциональный блок с именем ModbusMasterV20 на языке SCL. Сразу после создания открываем его свойства и снимаем настройку оптимизированный доступ, т.е. используем стандартный доступ. Личный опыт показал, что использование оптимизированного доступа рано или поздно приведет к ошибкам работы блока Modbus_Master и невозможности обмена. Это связано с порядком, в котором переменные идут в объявленной структуре данных, при стандартном доступе порядок соответствует заданному в программе, при оптимизированном система сама раскидывает переменные, как сочтет нужным.

Объявляем следующие входные переменные

Init (Bool) инициализация коммуникационного процессора, ее необходимо выполнить один раз перед началом обмена

PORT (PORT) аппаратный идентификтор коммуникационного процессора

BAUD (UDINT) скорость обмена по порту

STOP_BITS (USINT) количество стоповых бит кадра

PARITY (USINT) четность, где 0 нет четности, 1 odd, нечет, 2 even, чет

В статической области переменных так же прописываем переменную с именем Step и типом UInt, она отвечает за номер опроса или шаг работы алгоритма

Так же в статической области объявляем экземпляры ФБ для работы по протоколу Modbus RTU

Строки программы, отвечающие за инициализацию обмена.

По флагу инициализации выставляем номер шага 1. Следующие строчки очень важны для работы

#instModbusCommLoad.MODE := 4; //для линии RS-485 должна быть 4!

#instModbusCommLoad.STOPBITS := #STOP_BITS;

Тут мы задаем значения статических переменных экземпляра ФБ Modbus_Comm_Load, которые отвечают за физику передачи. Не понимаю, почему немцы поместили эти важные конфигурационные параметры в статическую область, а не в область входов. Дело в том, что они (переменные) все описаны во встроенной справке. Беда лишь в том, что большинстволенивых жопновичков до этого пункта справку не читает, а потом тратят несколько часов, а то и дней, пока не найдут ответ. А справка-то, вот она:

Переменная MODE отвечает за режим, в котором будет работать коммуникационный процессор. Как видно из справки, для RS-485 надо явно выставить 4. Значение по умолчанию 0, от этого большинство ошибок у программистов.

STOP_BITS количество стоповых бит.

Далее следует вызов блока настройки коммуникационного интерфейса Modbus_Comm_Load. Про параметр PORT (аппаратный идентификатор) будет рассказано чуть ниже. Параметры BAUD и PARITY скорость и четность приходят на вход внешнего блока данных, куда мы и завернули весь обмен. А вот параметр MB_DB интересен. На этот вход надо подать структуру типа P2P_MB_BASE, которая находится в области статических переменных экземпляра функционального блока Modbus_Master. Этот экземпляр в нашем большом функциональном блоке уже объявлен, привожу скриншот:

Следующая часть: функциональный блок приступает к циклическому обмену.

Я сразу заворачиваю обмен в CASE, чтобы не переписывать код в дальнейшем, но пока мы ограничимся чтением слова состояния и скорости ПЧ, т.е. прочитаем два регистра хранения.

Давайте посмотрим на вызов блока Modbus Master повнимательнее:

#instModbusMaster(REQ := TRUE,MB_ADDR := 1,MODE := 0,DATA_ADDR := 40110,DATA_LEN := 2,DATA_PTR := #ZSWHIW);

Входной параметр REQ включить опрос. Пока на входе TRUE, он выполняется, если FALSE не выполняется. Нет необходимости подавать положительный фронт на этот вход самостоятельно (в отличии от работы Modbus RTU в системах S7-300/S7-400), поэтому я просто даю TRUE константой

MB_ADDR адрес подчиненного устройства Modbus RTU. В моем случае адрес частотника = 1.

MODE направление передачи данных, 0 чтение, 1 запись

DATA_ADDR адрес интересуемых нас данных. В моем случае необходимо прочитать два регистра хранения (поэтому первая цифра4), начиная со 110го. В протоколе Modbus (что RTU, что TCP) очень часто возникает путаница в понятиях адрес и номер. И очень часто производитель оборудования эту путаницу добавляет в свою систему. Вот смотрите. Мы должны прочитать 2 регистра, начиная с адреса 40110. Для чтения регистров хранения в протоколе Modbus используется функция с номером 3. Именно 3 будет передаваться в телеграмме Modbus. А в качестве адреса в телеграмме будет передаваться не 40110, а 109. Связано это с тем, что код функции уже содержит описание области данных. А в самой телеграмме мы передаем не адрес, а номер требуемого регистра или катушки. И эта нумерация идет не с единицы, а с нуля. Сейчас я работаю именно с адресами и режимом (чтении или запись), поэтому мне достаточно указать то, что я нашел в документации. Если же в вашем устройстве будет указано входной регистр номер 0 содержит текущий статус устройства, то вам на вход DATA_ADDR необходимо будет подать 30001. Так же имейте в виду, что из-за частой путаницы с номерами и адресами, иногда эта адресация съезжает на единицу, поэтому не бойтесь экспериментировать. Если вместо полезных данных по запросу 16ого регистра вам прилетает полная чехарда, не имеющая ничего общего с документацией, прочитайте 15ый регистр. Не помогло? Опрашивайте 17ый. Более подробно с материалом необходимо ознакомиться опять же во встроенной справке.

DATA_LEN количество читаемых регистров, их 2

DATA_PTR указатель на область памяти, куда необходимо положить результат чтения регистров. Собственно, это те данные, которые мы прочитали и необходимо подсказать функциональному блоку, куда эти данные надо записать. С моей точки зрения самый удобный способ в этом случае это объявить в области STAT неименованную структуру должного размера. Поля структуры мы объявляем, в зависимости от самих читаемых данных, ведь это могут быть и наборы бит, и вещественные числа (расположенные в двух соседних регистрах). И нам еще повезет, если порядок байт в слове и слов в двойных словах контроллера и подчиненного устройства совпадут, иначе нам еще потребуется осуществить сдвиги байт/слов.

В данном случае я счел уместным объявить структуру из двух слов и скормить ее на вход FB:

, где

ZSW слово состояния (так оно называется в документации на ПЧ)

HIW скорость вращения двигателя

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

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

Пока оставляем прием данных без обработки, компилируем и грузим программу, смотрим на результат. Кстати, обращаю еще внимание на один факт. Поскольку мы работаем, завернув системные вызовы в свой функциональный блок, то любое изменение своего ФБ с последующей загрузкой ПЛК, будет нарушать обмен в связи с переинициализацией экземпляра нашего ФБ. Например, будет уходить в ноль значение шага обмена. Да и внутренние статические переменные коммуникационных вызовов тоже пострадают. Самый простой способ стоп и старт контроллера. В боевом проекте это опасно, поэтому там на вход Init я бы подал еще одну переменную и поднимал ее самостоятельно после изменений в коммуникациях. Пока же боремся с остановом обмена простым стоп-стартом ПЛК.

Добавляем вызов нашего функционального блока в OB1 и грузим CPU

Переменная FirstScan имеет значение истина при первом цикле выполнения программы OB. Она назначается операционной системой ПЛК автоматически, ее применение настраивается в свойствах CPU.

Port. Это значение смотрим в проекте Step 7, аппаратная конфигурация:

Остальные параметры касаются скорости, четности и количества стоповых бит. Загружаем контроллер и смотрим, что нам приходит в ответ на единственный циклический запрос, открыв экземпляр нашего ФБ

В слове состояния что-то есть, скорость равна нулю. Открываем документацию и смотрим состав слова состояния ZSW:

Low enabled в примечаниях означает инверсию. К примеру, бит 15, перегрузка частотника, возникает, когда этот бит равен 0, а в нормальном состоянии приходит значение 1. Посмотрим на это слово состояния в watch table и посмотрим, какие его биты выставлены, а какие нет, оценим общее состояние ПЧ:

Тут нам везет, порядок байт в словах совпадают. Если вкратце, то видно, что ПЧ не готов, не включен, и сейчас активен сигнал аварии (fault, бит 3).

Далее я попытался разложить слово состояния в биты состояния, заменив WORD на структуру из бит, но что-то явно пошло не так.

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

После чего задумываюсь, убираю из имен переменных окончание Inv и дописываю функциональный блок:

Теперь в глобалном блоке данных у нас находятся статусные биты преобразователя частоты без какой-либо инверсии:

Думаю, что сразу в блок данных надо вписать переменную типа Real, которая будет содержать текущие обороты двигателя. Текущие обороты приходят от ПЧ в виде определенного численного кода, и мы вольны трактовать этот код, как нам удобнее. Допустим, что хочу трактовать этот код, как Герцы, поданные на двигатель.

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

Обратимся к документации и посмотрим состав слова управления частотным преобразователем:

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

Изменю алгоритм на шаге 1, при успешном или неуспешном завершении опроса сделаю переход на шаг 2.

Добавим еще локальную структуру ФБ, которая содержит слово управления и слово задания скорости:

Дорабатываю программу обмена. Не забываем, что при изменении переменных функционального блока, после загрузки изменений в ПЛК происходит его переинициализация, посему надо выполнять стоп/старт CPU.

Параметры функционального блока модбас в данном случае отличаются от первого вызова. Разумеется, у нас тут другой адрес регистра. А так же отличается режим (MODE), он равен 1, так как в данном случае данные не читаются с частотника, а записываются в него. Разумеется, указатель на область данных так же другой.

Обратите внимание, что некоторые биты слова управления я принудительно выставляю в истину, другие в ложь. Всего два бита управления (включить и квитировать) доступны для внешней программы. Необходимое значение бит управления я вычитал в документации примера. Разумеется, это указано и в документации на сам преобразователь частоты. Изучая исходный пример, я обратил внимание, что если частотнику отдавать пустое (все биты выставлены в ноль) слово управления, то это подчиненное устройство модбас возвращает ошибку Invalid data. Однако, в этом примере я пробовал слать полностью пустое слово управления, и V20 принимал его. Однако, некоторые биты управления, все равно, должны быть установлены. К примеру, если снять бит Control by PLC, то запускаться ПЧ не будет. RTFM, как говорится!

Теперь пора перейти к регистру, который отвечает за задание скорости (ну и сразу же к регистру, который отображает текущую скорость). Из исходного примера я понял, что этот регистр меняет свое значение в пределах от 0 до 16384. Это же мельком нашел и в документации. Пока не будем делать никаких переводов величин, и зададим ПЧ максимальную скорость жестко прямо в программном коде.

Откроем наш блок данных DataV20 и выставим команду пуск:

V20 запустился и работает, судя по индикации своего экранчика, на максимальной скорости, т.е. на 50 Гц. Давайте посмотрим еще сырые данные его скорости, которые приходит по modbus.

Значит, пришло время доработать шаг 1 обмена (перевести коды скорости в герцы), ну и шаг 2 в части обратного преобразования, герцы в численное значение задания скорости. Математика самая простая, без проверок на достоверность и выход за диапазон, хотя все это не помешает.

После загрузки изменений откроем блок данных DataV20 и поуправляем частотником из него.

Даем задание 25 Гц, даем пуск и наблюдаем за появлением сигнала Running и текущей скоростью.

Все регистры, которые можно считать с V20, описаны в документе по ссылке

https://support.industry.siemens.com/cs/attachments/109768394/V20opinstr0419en-US.pdf?download=true

Судя по описанию регистров, есть и другие способы управления, но нас сейчас интересует не это. В моей практике с пребразователей частоты еще частенько просили считать ток(и), напряжение(я), мощность, детализацию ошибок и т.д. Давайте последуем этой старой-доброй традиции и считаем дополнительно вот эти параметры, а так же переведем их в понятное представление:

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

В принципе, мотор маленький, крутится без нагрузки, поэтому значения похожи на достоверные. Тем не менее, задача стоит в демонстрации считывания данных, поэтому будем считать наличие хоть каких-либо цифры за огромный технологический прорыв. Итак, вы уже заметили, что я добавил читаемые параметры в блок данных DataV20. Дополнительно был доработан функциональный блок коммуникаций:

Читаются (mode = 0) четыре регистра хранения по адресу 40025. Результат помещается во внутренний статический массив [0..4] of WORD. Далее эти слова переводятся в формат Real и помещаются во внешний блок данных в результате несложных преобразований.

Ну, и напоследок остается проанализировать качество связи. Ведь не зря же на каждом шаге после выполнения ФБ Modbus_Master смотрю его флаги DONE или Error (кстати, эти флаги имеют значение истина только на протяжении одного вызова после успешного или неуспешного выполнения запросы, в остальное время ложь). Для этого я объявил массив из булевых переменных

Массив размерностью три, по количеству запросов Modbus. Соответственно, если на шине будет 10 частотников, по три запроса к каждому, то размерность этого массива, как и количество шагов алгоритма, будет равно 30. Ну, и в конце каждого опроса, при анализе флагов, наконец, прописываем присвоение флагам значения.

Будем считать, что частотник стабильно обменивается информацией с ПЛК, когда все три запроса к нему выполнены успешно. Поэтому самая последняя строчка нашего функционального блока будет такой (предварительно добавим булевую переменную Connected в блоке данных DataV20):

Подробнее..

О несомненной пользе применения современного оборудования Simatic

20.01.2021 12:12:03 | Автор: admin

Году эдак в 2011 я на правах фрилансера написал и внедрил ПО для управления водонапорной станцией. По итогам система получилась распределенной и даже немного сложной, но начиналось все с локальной станции управления одной насосной установкой.

Проектная организация заложила CPU Simatic S7-313C. Аппаратный релиз был еще с 64 килобайтами рабочей памяти, тогда как актуальные сегодня версии оборудованы аж 128 килобайтами. Контроллер управлял двумя задвижками с приводами Auma Matic AM01.1 по профибасу и, по профибасу же, частотным преобразователем Robicon (модель не помню, здоровенная хреновина как минимум в мегаватт полезной мощности).

То есть, тут у нас технологически несложная насосная установка - задвижка на напоре, задвижка на всасе, датчики давления, насос, обвязанный датчиками вибрации и температуры, вакуумный выключатель для частотника, лампочки/кнопочки на шкафу, панель оператора.

Неожиданно мне стало интересно, как это будет выглядеть на новой линейке Simatic? Влезет ли прикладная программа, легко ли она портируется? Сколько стоит решение - внедренное ранее и выбранное мной сейчас?

С моей точки зрения такую несложную систему надо сегодня делать на S7-1200, поэтому она и была выбрана в качестве целевой системы.

Портировать прикладную программу оказалось несложно. Повозиться пришлось лишь в нескольких местах. Во-первых, в классическом Step 7 (версии 5.5 SP4) провел замену оборудования до актуальных заказных номеров. Это Step 7 знает всё своё железо с момента выхода в свет. TIA Portal ограничен более-менее актуальными релизами. А мигрировать прикладное ПО со старого Степа на новый решил полностью, включая аппаратную конфигурацию.

Второй источник боли - это прикладная программа в части вставок кода на языке STL. Дело в том, что S7-1200 не поддержкивает STL от слова вообще. А я его применял. Для копирования переменных, для несложных рассчетов и т.д. Ну, на не LADe же городить ветки с блоком MOVE. К слову, исходная программа написана на языке LAD с этими самыми вставками на STL.

В конечном итоге это превратилось в программу на языке LAD с нетворками на языке SCL.

Третье затруднение - это системные вызовы для обмена ЛСУ с вышестоящим мастер-контроллером, как профинет-подчиненнное устройство. В S7-300 через CP 343-1 LEAN для этого применялись отдельные функции. Тут я не стал заморачиваться и внедрил обмен через область процесса. Удобнее. А для контроля качества связи в обоих направлениях соорудил счетчик. В общем, никаких системных функций.

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

Ну, а теперь немного картинок. И, конечно же, про деньги.

Так выглядит исходная (и внедренная) конфигурацияТак выглядит исходная (и внедренная) конфигурация

Большинство дискретных сигналов управления влазило на блок CPU, но, все равно, не хватало, поэтому проектировщики добавили модули DI16 и DO16. DI16 и DO16 оказалось слишком много. По хорошему эти два модуля можно спокойно заменить на комбинированный DIO8/8. На аналоговых модулях AI8 висят сигналы давления и обвязка насоса.

Новая сборка на базе S7-1214Новая сборка на базе S7-1214

Все сигналы управления влезли вот в такой вариант. S7-1214 это минимальной возможный подходящий CPU. И его хватает с запасом. С учетом того, что технологическое оборудование работает по шине Profibus, пришлось доставлять отдельно CM1243-5, а это значительно удорожает спецификацию. Увы, но без него никак, ибо я мигрирую систему управления, но не всю технологию.

Пришло время посмотреть, что получилось с прикладной программой.

Исходный вариант:

Итого, примерно 24 килобайта рабочей памяти и 35 килобайт загрузочной.

Портированный на S7-1200 вариант:

14 килобайт рабочей памяти. Почти в два раза меньше. Частично это достигается отказом от функций PNIOSEND, PNIOECV. Частично некоторой оптимизацией кода. Не смог я просто скопировать наработки семилетней давности, ряд вещей переработал. Напоминаю, что сейчас сравниваются программы с абсолютно идентичным функционалом. И в новой линейке для того же функционала требуется меньше памяти. Удивительно, я ожидал обратного.

А теперь, конечно же, про деньги.

Стоимость исходной конфигурацииСтоимость исходной конфигурации

Обратите внимание, что тут я для оптимизации заменил два дискретных модуля DI16 и DO16 на один комбинированный DI/DO 8/8. А так же выбрал карту памяти MMC на 64 кБ в целях удешевления системы (разумный подход к делу требует, чтобы объем загрузочной памяти, т.н. флешки, был больше рабочей памяти). Округляя, получаем стоимость 3400 ойро без НДС.

Интересно, а что же получилось на S7-1200?

Стомость новой конфигурацииСтомость новой конфигурации

Даже с учетом применения дорогого модуля Profibus DP Master, даже с учетом применения дин-рейки за 30 евро, сборка получилась почти в два раза дешевле, 1630 евро. При том же функционале.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru