Современные ПЛК, как и другие подобные устройства на производстве, обладают возможностями восстановления после сбоя. Имеются в виду программные средства восстановления состояния системы управления до момента перед сбоем, приведшем к перезагрузке. Если аппаратная часть исправна, то необходимо “подхватить” управление системой и привести её в безопасное состояние, либо продолжить выполнение алгоритма, если это возможно.
Чтобы продолжить работу программы нужно восстановить состояние алгоритма управления до сбоя. Для этого у ПЛК есть специальные средства, наличие которых определено стандартами. Codesys имеет специальные области определения для хранимых переменных и системную библиотеку, предоставляющую функции для записи и восстановления содержимого этих областей. Мы обсудим работу с областью retain переменных на примере Raspberry Pi.

Область retain переменных

Одним из типов переменных, сохраняющих своё значение при завершении работы программы, являются retain переменные. Почитать про свойства различных типов подобных переменных можно на справочной страничке (англ.): Remanent Variables – RETAIN, PERSISTENT .

Нас будет интересовать несколько вещей, связанных с retain переменными:

  • как их объявить;
  • как заставить их работать;
  • какого размера они могут быть;
  • как их применять.

С объявлением всё просто, достаточно добавить после var слово retain:

С размером немного сложнее. По умолчанию Codesys для Raspberry Pi ограничивает размер области retain переменных значением примерно в 4 КБ. Это выяснится при попытке загрузить программу, имеющую большую retain область, в устройство.

Определение границ различных областей памяти находится в файле описания устройства, имеющим окончание .devdesc.xml. При установке пакета для Raspberry Pi этот файл автоматически был добавлен в список доступных ПЛК. Предлагаю изменить этот файл таким образом, чтобы был доступен любой размер области retain переменных.

Для этого нужно выполнить следующую последовательность действий:

Шаг 1. Нужно извлечь файл CODESYS Control for Raspberry Pi SL.devdesc.xml из пакета CODESYS Control for Raspberry PI 3.5.x.x.package, который на самом деле является архивом.

Шаг 2. Найти в файле поиском по ключевому слову retain область с описанием секций памяти и привести её к следующему виду:

Здесь выше параметра с именем dynamic-retain добавлен код:

Этот код на самом деле позволяет Codesys динамически вычислять размер области retain переменных при компиляции.

Шаг 3. После этого нужно открыть репозиторий устройств в среде разработки Codesys и установить устройство, используя изменённый файл CODESYS Control for Raspberry Pi SL.devdesc.xml. При этом обновятся параметры уже установленного устройства. Больше этот файл не понадобится, т.к. при установке он копируется в систему. Теперь можно объявлять массивы произвольного размера, если это нужно.

Сохранение и восстановление retain области

Одного только объявления недостаточно, чтобы всё работало. Необходим специальный код поддержки, основанный на функциях из системной библиотеки CmpApp. Пример такого кода можно обнаружить на некоторых форумах: здесь и здесь. Два источника одного кода, если вдруг кому-то понадобится изобрести свой велосипед.

Может возникнуть вопрос: Почему поддержка retain переменных не встроена в среду разработки полностью?

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

Предлагаю свой вариант адаптации, основанный на указанных выше источниках. Код поддержки retain переменных для Raspberry Pi оформлен в виде функционального блока TRetainControl:

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

Правильная работа в режиме принудительного сохранения (ForceSave) требует разрешения на выполнение внешних программ. Для этого нужно в пользовательском файле конфигурации /etc/CODESYSControl_User.cfg добавить/изменить следующие строки:

Эта настройка позволяет выполнять любую команду из программы Codesys.

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

Таким образом, регулярное выполнение этого функционального блока формирует “снимки” области retain переменных, сохраняемые в специальном файле. Если произойдёт перезагрузка устройства или исполняемого файла Codesys RTS, то значения переменных будут восстановлены, кроме случаев, оговоренных в справочной системе.

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

Тестовый проект

Предлагаю в качестве примера использовать проект: Raspberry.RetainTest.ST.project .

В проекте объявлена область retain переменных с одной переменной n, которая инкрементируется каждую секунду. По истечении минуты вызывается скрипт рестарта сервиса Codesys, имитируя “мягкий” сбой. При этом в файл лога /var/opt/codesys/log.txt добавляется запись времени рестарта и значение retain переменной. По файлу лога можно оценить правильность работы с retain переменными и какое время такой проект может проработать без ошибок.

В этом проекте используется функция Restart(), которая выполняет команду (запуск скрипта):

Этот скрипт необходимо самостоятельно создать в папке /var/opt/codesys и назначить ему исполняемые права.

Сразу скажу, метод управляемого рестарта можно использовать для обхода ограничения демо версии Codesys для Raspberry Pi (2 часа работы), если пауза в несколько секунд не повлияет на работу системы. Для этого нужно предусмотреть в алгоритме программы “нейтральное” безопасное состояние, в котором осуществлять перезагрузку и восстановление работы программы. Переход в это состояние выполнять по таймеру. Такая особенность работы существенно ограничит области применения и усложнит код, но позволяет рассматривать Raspberry Pi не только как обучающую платформу.

Приложение

Обсудить на форуме.

Работа с retain переменными на Raspberry Pi
Метки:        

Комментарии:

Работа с retain переменными на Raspberry Pi: 8 комментариев

  • 22 октября 2018 в 19:20
    Постоянная ссылка

    Спасибо за статьи про CodeSys на Raspberry. В русскоязычном интернете их очень мало.
    Хотел задать вопрос вы не знаете как реализовать отправку email писем на малине из codesys c поддержкой ssl/tsl шифрования?

    Ответить
  • 11 декабря 2018 в 18:27
    Постоянная ссылка

    Вячеслав, а у Вас рестарт процесса codesysa
    sudo systemctl restart codesyscontrol &
    сразу заработал? Мне пришлось скрипт переписать.

    Ответить
    • 12 декабря 2018 в 16:31
      Постоянная ссылка

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

      Ответить
        • 12 декабря 2018 в 20:14
          Постоянная ссылка

          Я только что проверил работу по инструкции выше на Codesys 3.5.13.10 с RTS 3.5.13.20. Перезагрузка происходит. Лог файл содержит следующий текст:
          2018-12-12 15:05:04 restart codesys, n=45, savecnt=12
          2018-12-12 15:06:11 restart codesys, n=91, savecnt=12
          2018-12-12 15:07:13 restart codesys, n=137, savecnt=12
          2018-12-12 15:08:15 restart codesys, n=183, savecnt=12
          2018-12-12 15:09:17 restart codesys, n=228, savecnt=12
          2018-12-12 15:10:19 restart codesys, n=273, savecnt=12
          2018-12-12 15:11:21 restart codesys, n=319, savecnt=12

          Ответить
  • 12 января 2019 в 17:08
    Постоянная ссылка

    Вячеслав, с одним вопросом не поможете?

    в логе codesyscontrol.log такие сообщения
    1547254171, 0x00000002, 4, 16, 40, Retain restore from file failed: [Application]
    1547254171, 0x00000002, 2, 1288, 49, Retain data are initialized now of [Application]
    1547254177, 0x00000002, 1, 0, 2, Application [Application] loaded via [Bootproject]
    поля лога такие
    ;
    ;Timestamp, CmpId, ClassId, ErrorId, InfoId, InfoText
    ;

    Можно ли отловить это событие (event)? куда смотреть? CmpApp EventIDs смотрел, что то не нашел…. И что такое CmpId, ClassId, ErrorId, InfoId?

    Ответить
    • 13 января 2019 в 18:58
      Постоянная ссылка

      Разбором внешних файлов codesys не занимался. Нужно стараться обойтись внутренними документированными возможностями codesys. Отловить ошибку инициализации retain переменных можно и с помощью TRetainControl. Переменная ResIEC должна вернуть значение отличное от нуля в случае ошибки. В первом цикле можно попробовать прочитать несколько раз и если не получилось, то назначить принудительно безопасные значения, переведя систему в начальное состояние.

      Ответить

Добавить комментарий для Салихов Ильдар Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *