Showing posts with label архитектура. Show all posts
Showing posts with label архитектура. Show all posts

November 10, 2020

Секретный сервис 700

Не все сервисы TwinCAT описаны в документации. В старых исходниках библиотеки AdsClient, в файле AdsSpecial.cs, есть любопытная функция public string GetTargetDesc(). Описание функции гласит: "Get an xml description of the plc...". Посмотрим, какое именно описание отдаст нам контроллер.

Начнем с системного сервиса, порт номер R3_CTRLPROG = 10000. Официальное описание списка функций заканчивается номером 600 (см. таблицу System Service Index Groups). Мы же прочитаем индекс 700 (0x02BChex). Настраиваем роутинг и начинаем читать. Код C# программы:

 

Первый запрос отправляем с параметром typeof(int). Где-то внутри библиотеки это транслируется в параметр команды равный 4 — это длина типа данных int в байтах. В ответ, запрос вернет длину XML текста с описанием устройства. Зная размер, мы отправляем второй запрос в тот же порт-индекс-смещение, но в качестве параметра передаем длину описания, полученного на предыдущем шаге. Результат парсим. С помощью LINQ ищем и вытаскиваем интересующие нас поля описания.

Контроллер CX9020 вернул такой XML:

 

Сравним описания от CX9020 (Win CE) и ноутбука (Windows 10). Чтобы отследить различия, сохраним XML в отдельный файл: xdoc.Save( "cx9020.xml" ); и воспользуемся программой WinMerge:


TС/BSD

Новая, перспективная и все еще недоступная операционная система выдает следующее описание:

 

Пропали элементы `ImageDevice`, `ImageLevel`. Значение `CPUArchitecture` стало более осмысленным, но что такое 9 все еще непонятно.


Тоже сервисы

Можно найти еще несколько интересных сервисов, если копнуть глубже. Для раскопок пригодится какой-нибудь HEX-вьюер (VSCode hexdump) и следующая строка: File.WriteAllBytes( $"idx_{READDEVDESCRIPTION_IDX}.bin", adsStream.ToArray() ); // Начинайте копать.

Индекс 701 выдаст список всех сетевых интерфейсов доступных на устройстве. IP-адреса, маски подсети и что-то еще. Формат неизвестен, но можно разобраться самостоятельно. Копайте.

Из любопытного, для TC/BSD сервис возвращает название сетевого интерфейса в юникс стиле — `em0`.
А для Windows возвращает GUID: "{7D8FDCBA-6250-8DFF-4089-AB0845B12EDC} Qualcomm Atheros AR5BWB222 Wireless Network Adapter 192.168.2.177 255.255.255.0".

Индекс 702 отдает имя целевой машины: PC-8E5B1A, CX-3F5BC9... Строка заканчивается '\0', не забывайте про .TrimEnd('\0'); Продолжайте копать.


November 6, 2020

Агент данных OPC UA

Настроим агент данных на трансляцию данных из OPC UA сервера. Одновременно оставим без изменения трансляцию из ADS переменных. Пусть ADS работает параллельно с OPC UA. Активируйте конфигурацию каждый раз, когда изменяете что-либо в схеме агента. Он перезапустится с новой схемой автоматически.

ПКМ по пустому месту → Add Gate (OpcUaDevice). В окне `Properties` ввести в поле`Url` адрес своего OPC UA сервера: opc.tcp://192.168.1.100:4840. Добавьте канал подписчика: Add Channel (Subscriber), стрелка вниз 🡇.

Теперь открываем окно `Target Browser`, закладка `OpcUa`, добавляем OPC UA сервер контроллера, выбираем необходимые объекты-переменные и тащим их на "подписчика".

Возможно понадобится донастроить переменные подписчика. В моем случае Агент добавил мусор в имя переменной ns=4;s=MAIN.nCounter. Исправляется в окне `Properties`, поле `URN` и превращается в MAIN.nCounter. Ниже в примере исправлена только одна переменная-символ:

>>> {"Timestamp":"2020-11-06T11:48:08.151","GroupName":"_MQTT Broker_28","MAIN.nCounter":-1946,"ns=4;s=MAIN.rCounter":784486.0}
>>> {"Timestamp":"2020-11-06T11:48:09.150","GroupName":"_MQTT Broker_28","MAIN.nCounter":-1846,"ns=4;s=MAIN.rCounter":784586.0}
>>> {"Timestamp":"2020-11-06T11:48:10.150","GroupName":"_MQTT Broker_28","MAIN.nCounter":-1746,"ns=4;s=MAIN.rCounter":784686.0}

November 3, 2020

Начало работы с агентом данных

Агент позволяет передавать переменные программы и другие данные из одного места в другое. Например, есть группа контроллеров CX8090. На отдельном ПК устанавливается TC3 IoT Data Agent. Он настраивается на проброс данных через интернет на сервер-брокер MQTT. Из брокера данные забираются в базу данных. Позже аналитики анализируют, а сервисный отдел мониторит и бдит. Версия TwinCAT, разрядность и тип процессора, древность контроллеров — все это не важно. Переменные из контроллера можно передавать куда угодно, в обе стороны.

Изображение: Beckhoff Automation

Современные протоколы типа MQTT–AMQTT–RabbitMQ не требуют входящего подключения. Агент и контроллеры могут находится за NAT, файерволом или другой сетевой инфраструктурой. IP-адрес может быть серым и динамическим, но подключение к брокеру всегда исходящее. Поэтому переменные контроллера легко отдавать и легко забирать. В обе стороны.


Лицензии

Для ПК, на котором установливается Агент, необходимы минимум две лицензии: TC1000 | TC3 ADS и TF6720 | TC3 IoT Data Agent. Доступна пробная лицензия на 7 дней.

Лицензирование основано на группах порталов. Порталы объединяются в пакеты (Gate packs). Порталом называют одно подключение. Например, подключение к устройству через ADS или OPC UA. Лицензия TF6720 обеспечивает работу с четырьмя порталами. Большее количество порталов можно получить после покупки дополнительных лицензий (TF6721-TF6724). Количество порталов складываются: TF6720 + TF6721 = 8 порталов.


Принципы работы

Open local, Save local работают со схемой в локальной конфигурации Агента C:\TwinCAT\3.1\Boot\TcIotDataAgentConfig.xml. Эта схема будет использована при старте Агента на этом локальном ПК. Во время работы рядом будет лежать лог TcIotDataAgent.log. По нему можно проводить диагностику работы Агента.

Open file, Save file импорт/экспорт схемы из отдельного файла.

С помощью кнопки "активировать конфигурацию", можно активировать схему на удаленном контроллере. На кнопке изображена традиционная горка кубиков (Save to selected target and activate).

В окне `Topology` создаем схему передачи данных. Нужно запомнить два простых принципа: создаем правой кнопкой мыши (ПКМ), а затем соединяем элементы с помощью Ctrl + тащим и бросаем. Например:

  • ПКМ по пустому месту → Add Gate (ADS) → получился круг — это ADS-портал, ведущий к переменным контроллера.
  • Затем, ПКМ → Add Gate (MQTT) → появилось облако — это брокер MQTT, источник данных.
  • ПКМ ADS портал → Add Channel (Subscriber) → создается подписчик (subscriber) в виде прямоугольника. Стрелка вниз 🡇 указывает направление подключения.
  • ПКМ Подписчик → Add Symbol → добавляется новая переменная (symbol) для чтения из контроллера. Можно сделать проще: открыть окно `Target Browser`, перетащить и бросить переменную на "подписчика".
Схему можно создавать и редактировать через другие окна программы. Исследуйте их. Выберите удобный способ работы с программой.

Аналогично поступаем с порталом MQTT Broker, где вместо `Add Gate` доступен `Add Channel`. Брокер работает не с переменными, а с каналами. Через них идут потоки переменных.

Дальше тащим прямоугольник подписчика ADS: Ctrl + левая клавиша мыши (ЛКМ). Бросаем его на прямоугольник канала MQTT. Между элементами появляются связи.

Настройки всех элементов собраны в окне `Properties`.


Пример программы

Необходимо проработать четыре момента:

  • ПЛК программу как источник данных. Подойдет любая версия TwinCAT. Я брал как вторую, так и третью версию TwinCAT. Меняется номер порта ADS 801 → 851, но принципы создания схемы остается прежним.
  • Создать схему передачи данных для Агента.
  • Выбрать MQTT брокер данных.
  • Создать клиента для брокера MQTT. Я напишу простую программу на C#. Она будет читать данные из брокера. Здесь можно воспользоваться готовыми клиентами MQTT и запустить их на смартфоне.


ПЛК программа примитивная:

PROGRAM MAIN
VAR
    iCount: INT;
    rCount: REAL;
END_VAR

iCount := iCount + 1;
rCount := rCount + 0.1;


Схема Агента

Пора выбрать бесплатного брокера на тестирование. Мне понравился HiveMQ. Кроме него проверил Mosquitto. Он работал, но значительно медленнее.

Пришло время создать схему:


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

  • Ads_Mqtt_11_19 — транслирует переменную MAIN.rCount;
  • Ads_Mqtt_11_17 — передает целое число из переменной MAIN.iCount.

Внутри канала данные брокера можно раскидать по темам (Topic). Это настраивается в окне `Properties`. Например, пусть `rCount` как бы передается из жилой комнаты GOT/TWINCAT/ROOM, а переменная `iCount` приходит из офиса GOT/TWINCAT/OFFICE. В клиенте брокера я смогу выбрать или одну конкретную, интересующую меня тему, или сразу несколько тем. Темы фильтруются с помощью спец. символов `*`, `?` или `#`. Например, я хочу в одном канале получать данные ROOM+OFFICE: GOT/TWINCAT/#.


Клиент брокера

Для C# я использовал библиотеку MQTTnet. Она легко устанавливается из NuGet. Раскомментируйте строку и подставьте название своего топика-комнаты в константу `MQTT_TOPIC`.

 

Результат работы клиента:


Одновременно я установил на телефон бесплатный клиент `MQTT Dash` и он также смог отображать данные с ПЛК. Трансляция идет через интернет, можно сходить на обед и одним глазом посматривать как контроллер продолжает работать:

August 13, 2020

Вебинар. TwinCAT 3 Eventlogger

И опять с просмотра вебинара начнем знакомство с Eventlogger'ом. То есть с чтения конспекта, пропущенного через инженера. Вебинар `TwinCAT 3 Eventlogger: event-based communications from the TwinCAT runtime system` прошел 8 мая 2018 года, но нас это не остановит, так как с возрастом продукт становится только стабильнее и, главное, понятнее. За счет выпущенной документации и конечно же опыта разработчика.
Изображение: Beckhoff Automation

Центральный компонент — EventLogger. Он встроен непосредственно в ядро TwinCAT и для своей работы не требует покупки или активации каких-либо лицензий. Это неотъемлемая часть ядра TwinCAT. Доступ к этому ядру ПЛК-программы осуществляют через библиотеки (например, Tc3_Eventlogger), а библиотеки в свою очередь через интерфейс COM-объектов TcСOM и ADS.
Изображение: Beckhoff Automation

Ряд сообщений можно автоматичеки пробрасывать в журналы Windows. Откройте "Просмотр событий" Windows (или EventLogger) и вы увидите ряд сообщений, таких же что и в TwinCAT. 
Eventlogger поддерживает произвольный набор сообщений, то есть вы можете создавать свои собственные сообщения и события. Вы можете конструировать их, встраивать в свои конфигурации, компилировать и затем использовать в своих системах. Для создания сообщений служит ветка Solution Explorer → SYSTEM → Type System в конфигурации проекта. Закладка справа Event Classes позволяет объединять сообщения в классы по каким-либо удобным для вас критериям. 

События представлены специальным типом данных TwinCAT. События управляются с помощью TwinCAT Type System. Следовательно они едины и одинаковы для всех компонентов проекта, написанных на любом из доступых язков программирования: ST, LD, C++, ... Плюс к этому, конфигурация событий хранится в TMC-файлах, соответственно это XML-файл, который можно легко автогенерировать с помощью произвольных (в том числе и внешних) инструментов.

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

Текст сообщений может параметризоваться. Можно добавить прямо в текст метки, которые в коде программы будут заменяться на актуальные значения: "Текущая температура {1} превышает {0}". Кроме этого, можно задать источник события и таким образом впоследствии увидеть, что сообщения одинакового типа отправляются из разных подпрограмм (источников).

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


Библиотека Tc3_EventLogger


Позволяет создавать события из программы ПЛК.

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

Кроме сообщений можно создавать "Тревоги" (Alarms) которые могут находиться в одном из состояний: тревога установлена (Raise), тревога сброшена (Release) и тревога квитирована (Confirm). Также можно полностью удалить экземпляр объекта тревоги из памяти (Clear), но в логе сообщения сообщение все равно остается и не пропадает. Иллюстрация из справочной системы:
Изображение: Beckhoff Automation

Работа из C++ очень похожа на работу из ST программ. Из C# тоже, но это будет отдельно.


Получение событий


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

Для C++ аналогично.


Доступ извне


События TwinCAT EventLogger можно просматривать в Visual Studio: View → Other Windows → TwinCAT Logged Events.

Программы написанные на C# могут получить дступ через ADS Proxy. С помощью класса TcEventLogger из сборки ADS. Причем текст сообщения можно получать с учетом интернационализации локали, то есть на разных языках в зависимости от предпочтений разработчика либо настроек системы.


Интернационализация


Если она вам не нужна (а она вам нужна, так как вы читаете блог на русском языке), то можете игнорировать эту возможность и все будет на английском языке (или немецком).

August 4, 2020

Всё есть файл

В Unix/Linux устройства могут выступать в качестве файла или бинарного/символьного потока. Такая философия позволяет работать с потоком данных устройства, как с обычным файлом: открываем-читаем-пишем. Все что нужно — это иметь права доступа к устройству и знать протокол и структуру данных. В Windows иногда тоже можно. Попробуйте, например, создать на рабочем столе файл с именем com2.txt. Будет занято.


Источник


Сначала нужно определиться, что именно будем читать. Для начала я не стал брать последовательные порты или другие устройства, а решил воспользоваться псевдоустройством... поэтому будем читать случайные числа из /dev/urandom. Это не совсем то, что мне хотелось бы проверить, но пока обойдемся этим. Как вариант можно считать память операционной системы через /dev/mem. Сервис TwinCAT под BSD запускается с root доступом, поэтому проблем возникнуть не должно.

Прочитанное из устройства, можно просто сохранить в массив, но мы сделаем два дела сразу — кроме чтения устройства, сохраним результат в файл, лежащий на другом ПЛК. Итого: два ПЛК (один с TC/BSD, другой с Windows), соединены обычной локальной сетью Ethernet. На одном ПЛК читаем случайные числа из файла-псевдоустройства, а результат сохраняем на другой ПЛК в настоящий файл.


Код


Код настолько простой, что смотреть особенно не на что: ряд обычных файловых операций. Именно в этом заключается преимущество подхода "всё есть файл".


Открывать несколько файлов можно с помощью одного и того же ФБ. Главное делать это последовательно: сначала один, затем другой. Основная задача получить хендлер файла для дальнейших файловых операций. Нам нужно получить два хэндлера, от двух файлов, заданных следующими путями: sDevPath — задает путь к источнику '/dev/urandom' и sResPath — путь к файлу с результатом 'c:\dev\random.txt'. Сразу видно — где Юникс, а где Виндовс (подсказка, обратить внимание на /слэши/ в путях). В финале добавим в константы VAR CONSTANT адрес удаленного ПЛК: sRemoteNetId = '172.17.176.49.1.1'.

Будем читать бинарные данные, то есть числа в виде потока байтов. Поэтому при открытии файла необходимо установить флаг бинарного режима чтения nMode := ... FOPEN_MODEBINARY. Кстати, читать можно и блоками по несколько килобайт за раз, но в данном случае так проще сохранять числа в виде текста.

В остальном все очень просто: открываем, читаем, обрабатываем-конвертируем и сохраняем. Преобразование значения байта как числа из диапазона 0..255 в текстовый вид делается в строке:
tmpStr := CONCAT(BYTE_TO_STRING(buf), '$r$n');
... а в конце добавляем символ '$r$n' — перевод каретки CRLF, таким образом выстраивая числа в столбик. Позднее, я засуну эти случайные числа в Эксель для анализа.

Набрав достаточное количество чисел, стоит вежливо остановить процесс через принудительную установку переменной RUN в значение FALSE. Резкая остановка работы программы, чревато тем, что на приемной стороне файл с результатом останется открытым и занятым: ни прочитать, ни удалить. Если такое произойдет, необходимо на приемной стороне вручную перезапустить системный сервис TwinCAT System Service или выполнить из командной строки с привелегиями администратора: powershell -command "Restart-Service TcSysSrv -Force". Заметьте, какой уровень доверия возникает на двух ПЛК, между которыми налажен роутинг. Это к вопросу о безопасности и отказоустойчивости по обе стороны сетевого кабеля.


Анализируем случайные числа


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


Интересно посмотреть как распределяется нагрузка по ядрам. Всего виртуальной машине выделены два ядра, но не факт, что ядра настоящие: возможно, что и просто два потока (хост с гипертредингом). Зато видно как нагружен TcSystemService — системный сервис TwinCAT:


Вместо диспетчера задач здесь используется утилита top или можно установить более красивый htop: doas pkg install htop. На картинке выше используется htop.

July 1, 2020

Параметры NC осей

Параметры приводных проектов специально разнесены по нескольким местам. Во первых, они разбиты по слоям или, иначе говоря, по месту применения: железо (сервоусилитель) + NC + софт (PLC). Во вторых, так безопаснее: железо имеет свои железные настройки, а все остальное и мягкое — располагает своими собственными "крутилками" и "показометрами".

Изображение: Beckhoff Automation

Тем не менее из ПЛК-проекта можно программно изменить любые настройки любого слоя. Это не всегда очевидно, но добраться все-таки можно.


Железо


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


Унификация и абстракция


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

Кроме собственныъ настроек у NC-системы есть свой собственный контур управления, который может... делайте выводы сами:



Технологический процесс


Процессом управляет программа. Управление она делает с помощью исполнительных механизмов. Получается, что программа дергает за ручки и кнопки слоя абстракции NC. У программы есть какие-то свои пожелания, которые она передает в слой NC.
 
Приводную часть настраивает "приводник" - специалист своего дела, а программы пишет "программист" - он тоже специалист, но уже своего дела. Хорошо когда это один человек: сам настроил, сам запрограммировал. Тем не менее, после тонкой настройки железа, эти настройки лучше оставить в покое и больше не трогать. Правда бывает, что нужно и что-то подкрутить программно.


Крутим параметры


Предположим, изменился коэффициент масштабирования энкодера инкрементов-на-миллиметр. В лексиконе приводника - это Nc feed constant. На самом деле это настройка не слоя железа, а настройка слоя NC. Такое смешение сделано для удобства: приводник настраивает все низко-уровневые и средне-уровневые параметры движения и железа в одном месте. Программист же может управляет параметрами движения типа скорость-ускорение и подрегулировать динамику через NC. Опять-таки удобно.

На картинке как раз кусок железа Drive Manager'a, где смешались в кучу слои:


Привод можно донастраивать через SoE, CoE и пр. В параметры NC можно залезть через функциональные блоки типа MC_WriteParameter, предоставляемой библиотекой Tc2_MC2. Эти настройки не навсегда — при следущей загрузке параметры откатятся до значений заданных в конфигурации. Так сделано для безопасности.

Список всех доступных настроек содержится в перечисляемом типе MC_AxisParameter. Его интересно полистать пару минут, вчитываясь в комментарии типа: (* new since 1/2012 *) или ...- available in Tc3 *) — история как она есть.

Чтобы как-то повлиять на значение параметров в конфигурации, можно при каждом старте ПЛК-программы задавать новые коэффициенты. Так и приходилось делать в TwinCAT 2. Теперь уже не обязательно — в TwinCAT 3 появились функции типа MC_WriteParameterPersistent. Через них достаточно задать параметр один раз и его значение легко переживет перезапуск ПЛК. При активации новой конфигурации, эти значения будут заменены на значения из новой конфигурации.

Небольшой пример как пользоваться, но там и так все понятно:

June 23, 2020

Очередной билд TwinCAT 3.1.4024.10

Появилась интеграция с Visual Studio 2019, потому что вышел очередной билд TwinCAT 3.1.4024.10. Очередной билд - когда меняется самая последняя цифра, например, 10. Темной темы по прежнему нет, поэтому посмотрим, что еще нового оно нам принесло.



Установка


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

В результате оболочка XAE 2017, несмотря на мои пожелания, все-равно установилась, а может и осталась от прошлой инсталляции. Зато интеграция в Visual Studio Professional 2019 так и не произошла. Вывод: птичку не трогать, пусть ставит XAE в любом случае, тогда интеграция в VS 2019 пройдет без проблем, как и было задумано.


Шаблон проекта


В "студии" 2019 изменился стартовый экран создания проекта, соответственно это отразилось и на создании проекта TwinCAT. Теперь чтобы создать проект нужно приложить усилие для поиска нужного шаблона. Разработчики забыли (или не смогли, или это невозможно) добавить теги и нужно пролистать список довольно далеко или сразу ввести волшебное слово "twincat" в строке поиска:



По правде говоря, все не так плохо — в следующий раз шаблон проекта появится слева в списке последних шаблонов (Recent project templates):



Что нового?


Не считая изменения в интеграции со студией, в RSS-новостях промелькнула новость об изменениях в статическом анализаторе ПЛК-задач `TE1200 | TC3 PLC Static Analysis`. Там появились несколько новых правил оптимизации. В пакете умных вещей `TF6760 | TwinCAT IoT HTTPS/REST` добавилась поддержка Philips Hue и Telegram. Теперь можно управлять разноцветной лампочкой филипс не только через смартфон, но и с ПЛК, а им, в свою очередь, через смартфон с телеграммом.

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

May 9, 2020

Автозагрузка TwinCAT 3 в различных режимах

При старте операционной системы TwinCAT 3 может автоматически загрузится как в рабочем режиме, так и в режиме конфигурации. Впрочем, аналогичное происходит и со старой второй версией. Здесь важно, что задать режим можно только создав пустой проект или открыв текущий. Затем необходимо подключиться к локальной системе или удаленной системе, выбрать режим и нажать кнопку Apply. Очень много телодвижений. Иллюстрация ниже:


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

Для работы с 32-х разрядными системами:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Beckhoff\TwinCAT3\System]
"SysStartupState"=dword:00000005

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

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Beckhoff\TwinCAT3\System]
"SysStartupState"=dword:0000000F

Я назвал пост в честь TwinCAT 3.1, но мы все еще помним старушку TwinCAT 2, и там все будет выглядеть аналогично: просто нужно убрать номер версии из пути ключа, то есть сделать как-то так: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Beckhoff\TwinCAT\System. Не забывая, конечно же, про разрядность операционной системы и валшебного суффикса WOW6432Node.

Непосредственно режим задают магические числа в значении ключа SysStartupState:
  • 05 - рабочий режим / Run Mode / зеленая иконка.
  • 0F - режим конфигурации / Config Mode / синяя иконка. И да, это =15 в десятичной системе счисления.

Остается создать .reg файл и кликать по нему мышкой или отправить по почте. Вышеперечисленное относится к настольным операционным системам.

October 10, 2019

Программная активация удаленного доступа

В новых ПЛК по умолчанию отключен удаленный доступ. Во имя безопасности, конечно же. И вот когда ты подключаешься удаленно через эр-ди-пи, ви-пи-эн и прочие тим-виверы, запускаешь CERHost, а на контроллере не активен Remote Display... На помощь приходит Beckhoff Device Manager.

Что делать, если не приходит?

Найти контроллер через System Manager, подключиться к ПЛК и залить в него хитрую программу, которая в свою очередь активирует удаленный доступ.


Автостарт через реестр


Реестре содержит раздел Launch90, в который можно записать имена программ для автостарта. Название ключа явно позаимствовано из Linux, но нам нужно активировать удаленный доступ, а за него на стороне ПЛК отвечает сервис CeRDisp.exe. Теперь всё готово, осталось подать материал в жерло FB_RegSetValue из TcUtilities.lib.

После добавления записи в реестр, необходимо перезагрузить ПЛК. Для этого воспользуемся функцией NT_Reboot из той же библиотеки. Результат:

PROGRAM MAIN
VAR
    Reboot: NT_Reboot;
    RegSetValue: FB_RegSetValue;

    newValue: STRING := 'CeRDisp.exe';
END_VAR
VAR CONSTANT
    HKLM_INIT_SUBKEY: STRING := 'init';
    REG_LAUNCH90_VALUE: STRING := 'Launch90';
END_VAR

(* @END_DECLARATION := '0' *)

RegSetValue(
    sNetId   := '',
    sSubKey  := HKLM_INIT_SUBKEY,
    sValName := REG_LAUNCH90_VALUE,
    eValType := REG_SZ,
    cbData   := LEN(newValue) + 1,
    pData    := ADR(newValue),
    bExecute := TRUE
);

IF NOT RegSetValue.bBUSY THEN
    Reboot( NETID := '', START := TRUE);
END_IF

END_PROGRAM


Что-то еще про автостарт приложений можно прочитать в Automatic start of CE applications. И автозапустить что-нибудь еще полезное.

October 9, 2019

TF1810. TwinCAT 3 PLC HMI Web

У Бекхоффа есть несколько видов визуализаций в которых иногда можно запутаться. Сейчас меня интересует веб-визуализация TF1810 устанавливаемая на ПЛК. Работает и запускается этот вид визуализаций непосредственно на ПЛК. Просмотр и управление тех. процессом производится оператором через браузер с удаленного компьютера.

Работает всё это через JavaScript и HTML5. На контроллере обычно уже установлен, настроен и работает IIS (Microsoft Internet Information Services). При подключении, клиенту отправляются данные только отображаемых на экране элементов. Данные отправляются (т. е. обновляются) циклически независимо от того изменились они или нет. Сам микро-веб сайт разворачивается на ПЛК в каталоге /TwinCAT/3.1/Boot/Plc/Port_851/Visu. Номер порта (Port_851) может быть другим, соответственно путь также немного изменится.

Клиент подключается и рабоатет через браузер: http://plc-name-or-ip-address/Tc3PlcHmiWeb/Port_851/Visu/webvisu.htm. Веб страница в браузере содержат два канваса (Canvas) на которых рисуется вся графика визуализации. Один канвас рисует фон (на случай статичного фона), другой канвас рисует активные элементы. Для отображения графики элементов используется векторный SVG.

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


Visu Profile в 3.1.4024


Начиная с версии 3.1.4024 что-то кардинально поменялось в кухне проектов TwinCAT и теперь необходимо согласовывать версии визуализаций.
  1. Сначала запустить XAE без проекта.
  2. Выбрать необходимую версию TwinCAT.
  3. Загрузить проект над которым вы работаете.
  4. Выбрать в проекте Visu Profile "постарее".

Одновременно работать с разными версиями TwinCAT можно с помощью TwinCAT Remote Manager.

July 4, 2019

Загрузка системного модуля NC PTP

В ПЛК на базе WinCE / Compact существует операция подъема уровня лицензии TwinCAT 2: был стандартный уровень PLC, а стал контроллер с NC PTP и возможностью управления движением.

Для подъема уровня TwinCAT используется специальная утилита, которая, конечно же, требует лицензионный ключ. Вообще, такой процедурой занимается сервисная служба, но можно и самому, а итогом послужит следующая картина:


Правда итог не так очевиден из System Manager: ветка NC может отсутствовать в конфигурации. Иными словами, контроллер уже может, а вот System Manager почему-то в упор не видит NC.

На самом деле уровень лицензии подняли, а модуль в TwinCAT еще не загрузили.

TwinCAT 2 — это модульная система. Она состоит из нескольких низкоуровневых драйверов для подсистем: TcIo.sys, TcRouter.sys, TcRTime.sys, TcNc.sys... В случае с WinCE драйверы уже встроены в образ, их просто нужно подключить.

Список модулей TwinCAT 2, загружаемых при старте системы, хранится в \Hard Disk\TwinCAT\DefaultConfig.xml. Открываем этот файл и дописываем загрузку модуля TCNC. Соответственно файл после редактирования будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<TcBootProject>
    <Drivers>
        <Driver>
            <Type>1</Type>
            <ServiceName>TCIO</ServiceName>
        </Driver>
        <Driver>
            <Type>1</Type>
            <ServiceName>TCPLC</ServiceName>
        </Driver>
        <Driver>
            <Type>1</Type>
            <ServiceName>TCRTIME</ServiceName>
        </Driver>
        <Driver>
            <Type>1</Type>
            <ServiceName>TCNC</ServiceName>
        </Driver>
    </Drivers>
    <InitCmds/>
</TcBootProject>


Перезапускаем ПЛК и смотрим на результат. Было → стало:


June 28, 2019

Символьная линковка через атрибуты

Данные железа связываются с переменными программной части через конфигурацию контроллера. Иногда это не удобно и хочется идти не от конфигурации, а от кода (Code First). Как пример, я взял линковку переменных, связанных с управлением движением сервоосей NC PTP. И еще, верните, пожалуйста, карту мапинга — она была бессмысленной, но красивой ↘


Атрибуты


Переменной можно дописать атрибут — это специальная строка, которая говорит системе, что с переменно нужно сделать дополнительные телодвижения. Атрибутов было мало — сейчас стало много. В случае сервоосей нас интересует атрибут TcNcAxis:

{attribute 'TcNcAxis' := 'Axis 3'}
axMaster : AXIS_REF;

Здесь атрибут (ключевое слово attribute) заключен в фигурные скобки. Строка атрибута должна идти перед объявлением переменной или экземпляром функционального блока. Далее в кавычках следует одно или несколько(!) имен переменных или ФБ, символ присваивания  := , и наконец значение атрибута. В данном случае значением служит имя NC оси взятое из конфигурации  'Axis 3' . Записывается прямо с пробелами и другими символами, для этого и нужны кавычки.

Добавив атрибут и пересобрав проект, я автоматически получу слинкованную с сервоосью переменную типа AXIS_REF. Остается только реактивировать конфигурацию в ПЛК и все готово. Еще раз:
  1. Добавить строку атрибута или заменить имя оси в значении атрибута на другое.
  2. Пере/собрать проект (Build → Rebuild Solution).
  3. Активировать конфигурацию. Внимание! Активировать конфигурацию!
После активации, слинкованные через атрибут переменные будут подсвечены синим значком линковки (см. FromPlc и ToPlc):


Когда системе не удается слинковать данные, она сообщает об этом большим и внезапным сообщением поперек экрана. Проект в итоге соберется, но данные бегать не будут. Если же все прошло удачно, то после пересборки проекта система сообщит:
Message 06.01.2019 21:56:05 729 ms | 'TwinCAT XAE': Existing NC axis 'Axis 3' linked to instance 'MAIN.axMaster'
Очень удобно, так как теперь можно еще больше сконцентрироваться на коде. Главное не забывать пересобирать проект, а затем активировать конфигурацию. Аналогично можно работать с функциональными блоками.


Ввод/вывод


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

На этот раз воспользуемся атрибутом TcLinkTo. Вообще, он простой, поэтому я возьму что-нибудь посложнее TcLinkToOSO. Атрибут c -OSO на конце позволяет не просто связать переменную типа AT %IQ* с данными, но также задать количество разрядов тут и там, а также их битовое смещение.

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

Напомню задачу: в настройках NC оси, в ветке конфигурации Axis X → Drive → Inputs →... есть поле nState4. Седьмой бит этого поля отвечает за быстрый останов данной сервооси. Пара битов этого поля уже автоматически слинкована с какими-то данными, поэтому действовать нужно аккуратно.
Быстрый стоп не работает на виртуальных осях! Необходимо серво-железо.
Для начала сходим в конфигурацию и посмотрим, где расположены требуемые данные в конфигурации со стороны железа, то есть смотрим во вкладку Variable, текстовое поле Full Name: TINC^NC-Task 1 SAF^Axes^Axis 3^Drive^Inputs^In^nState4. Это полный путь к данным переменной nState4 в конфигурации:


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

{attribute 'TcLinkToOSO' := '<0,1,7>TINC^NC-Task 1 SAF^Axes^Axis 3^Drive^Inputs^In^nState4'}
cmd_FastStop AT %Q* : BOOL;

Мне нужен всего-лишь один бит, поэтому я расширил путь специальным суффиксом -OSO: <0,1,7>. Последовательно слева-направо:
  • 0 — битовое смещение в переменной ПЛК, то есть с какого бита ПЛК переменной начинать связывать. Можно связать не всю переменную, а только ее часть и не обязательно с начала и до конца: с помощью -OSO можно выхватить кусочек из середины.
  • 1 — количество связываемых бит.
  • 7 — битовое смещение в переменной на стороне железа (в моем случае в переменной nState4). Мне нужен бит номер 7, поэтому смещение = 7.

После сборки проекта система сообщает:
Message 06.01.2019 22:11:15 930 ms | 'TwinCAT XAE': Variable 'MAIN.cmd_FastStop' (Offs: 0) linked with 'TINC^NC-Task 1 SAF^Axes^Axis 3^Drive^Inputs^In^nState4' (Offs: 7, Size: 1)

Разбавлю полным листингом программы:

PROGRAM MAIN
VAR
    {attribute 'TcNcAxis' := 'Axis 3'}
    axMaster     : AXIS_REF;
    
    McPower      : MC_Power;
    McVelocity   : MC_MoveVelocity;

    cmd_PowerOn  : BOOL;
    cmd_Velocity : BOOL;
    {attribute 'TcLinkToOSO' := '<0,1,7>TINC^NC-Task 1 SAF^Axes^Axis 3^Drive^Inputs^In^nState4'}
    cmd_FastStop AT %Q* : BOOL;
    
    actVelo      : LREAL;
    state        : INT;
END_VAR

[...]

axMaster.ReadStatus();
actVelo := axMaster.NcToPlc.ActVelo;

CASE state OF
0:
    IF McPower.Status THEN
        cmd_Velocity := TRUE;
        state := 100;
    END_IF

100:
    IF McVelocity.InVelocity THEN
        cmd_Velocity := FALSE;
        state := 200;
    END_IF
    
200:
    IF actVelo < 0.1 OR NOT McPower.Status THEN
        cmd_PowerOn := FALSE;
        state := 300;
    END_IF     
    
300:
    IF NOT McPower.Status THEN
        cmd_FastStop := FALSE;
        state := 0;
    END_IF

END_CASE

McPower(
    Axis            := axMaster, 
    Enable          := cmd_PowerOn, 
    Enable_Positive := TRUE, 
    Enable_Negative := TRUE
);

McVelocity(
    Axis     := axMaster, 
    Execute  := cmd_Velocity, 
    Velocity := 200
);

Теперь если во время работы программы дернуть за булевый флаг cmd_FastStop и установить его в TRUE, мы незамедлительно получим быструю остановку сервооси, а система подскажет нам, что:
Message 06.01.2019 22:23:25 772 ms | 'TCNC' (500): 'Axis 3' (Axis ID: 3) <NOTE>: 'Fast axis stop' triggered by IO interrupt 'Drive->Status4->Bit7' (SignalType=1 (SignalType_RisingEdge), FastDec=0.000000, FastJerk=0.000000, IoState=1, OldIoState=0)!

Мышой проще


А еще есть кнопка Link To PLC... которая никакого отношения к символьной линковке не имеет, зато позволяет присобачить одним кликом мыши переменную AXIS_REF к NC оси, и безо всяких там NcToPlc, PlcToNc, ...


June 27, 2019

Структурированные исключения которые не работают

Версия TwinCAT 3.1.4022.29.


И похоже мы имеем дело с ядрами разных версий на десктопе и в полноценных ПЛК. Под полноценные контроллеры проект собирается без ошибок, но исключения по прежнему не работают.
Исключения доступны начиная с версии 3.1.4024.0, но только на ПЛК и только в 32-х разрядных системах. Читайте комментарии к посту. Обновлено 10 октября 2019.
Исключения эти вроде как расширение стандарта МЭК. Поэтому пока эта штука не работает можно познакомиться с Exceptionhandling in IEC Applikationen mit CODESYS и документацией на CoDeSys.

October 29, 2018

Введение PowerShell для TwinCAT

В TwinCAT 3 есть штуки, позволяющие автоматизировать рутинные последовательности действий. Дальше как в известной байке с реддита: "Этично ли будет не сообщать работодателю, что я автоматизировал свою работу"?

В текущем проекте мне необходимо периодически перегружать TwinCAT: остановить сервис TwinCAT, запустить сервис TwinCAT, перевести локальный рантайм в режим конфигурации или в рабочий режим. Вообще, не проблема написать все это на C#, но здесь уместнее будет использовать командную строку и какой-нибудь скриптовый язык программирования. Под Linux есть bash и Python. Под Windows они тоже есть, но это противоестественно для его экосистемы. Поэтому будем экологичны — воспользуемся PowerShell 'ом.

PowerShell строится вокруг инфраструктуры .NET как и C#. Он также имеет удобный доступ к COM-объектам, а на них построены множество сервисов TwinCAT. Дальше хвалить не буду, начнем чистую практику. В идеале, я хочу получить кнопку, которая будет перезапускать TwinCAT в один клик. См. иллюстрацию справа →

Перезагрузить TwinCAT несложно — достаточно остановить и стартовать заново системный сервис TcSysSrv. Сделать это можно вручную или через командную строку. Сначала, стоп: net stop TcSysSrv; затем, рестарт — net start TcSysSrv, но после этого TwinCAT запустится в режиме стоп (красная иконка). Чтобы перевести его в какой‑либо рабочий или полурабочий конфигурационный режим, необходимо использовать функции ADS.API. К сожалению, через командную строку они не доступны: нужно запускать System Manager или XAE.


Инсталляция


Запустить консоль PowerShell можно из меню Пуск: клавиша  с окошком Windows → открывается меню Пуск, начинаете набирать powershe... Там же можно запустить встроенный в Windows редактор PowerShell ISE. При запуске от имени администратора, появляется больше возможностей, но и больше дыр в защите вашего ПК.


Чтобы перезапустить сервис TwinCAT можно использовать команду Restart-Service TcSysSrv -Force. Ключ -Force избавит от лишних вопросов. Причем, заметьте, не просто остановить или запустить, а одной командой остановить и перезапустить. Уже удобнее, чем было, но есть одно "но"(!) — перед запуском необходимо разобраться с правами на запуск командлетов-скриптов PowerShell: Get-ExecutionPolicy и Set-ExecutionPolicy. Погуглите по русски или читайте справочную систему на английском-немецком Check the Powershell Cmdlet Execution policy, это домашнее задание.

Теперь осталось разобраться с функциями ADS.API. Для них есть NuGet-PowerShell пакет TcXaeMgmt. Перед использованием, его необходимо установить командой Install-Module -Name TcXaeMgmt, соглашаясь [Y] со всем, что предложат:


Windows PowerShell
(C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены.

PS C:\Windows\system32> Install-Module -Name TcXaeMgmt

Для продолжения требуется поставщик NuGet
Для взаимодействия с репозиториями на основе NuGet модулю PowerShellGet требуется версия поставщика NuGet "2.8.5.201"
или более новая. Поставщик NuGet должен быть доступен в "C:\Program Files (x86)\PackageManagement\ProviderAssemblies"
или "C:\Users\username\AppData\Local\PackageManagement\ProviderAssemblies". Поставщик NuGet можно также установить,
выполнив команду "Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force". Вы хотите, чтобы модуль
PowerShellGet установил и импортировал поставщик NuGet прямо сейчас?
[Y] Да - Y  [N] Нет - N  [S] Приостановить - S  [?] Справка (значением по умолчанию является "Y"):Y

Ненадежный репозиторий
Идет установка модулей из ненадежного репозитория. Если вы доверяете этому репозиторию, измените его значение
InstallationPolicy, запустив командлет Set-PSRepository. Вы действительно хотите установить модули из "PSGallery"?
[Y] Да - Y  [A] Да для всех - A  [N] Нет - N  [L] Нет для всех - L  [S] Приостановить - S  [?] Справка
(значением по умолчанию является "N"):Y
PS C:\Windows\system32>



Командлет


Для переключения режимов работы TwinCAT из PowerShell, используется команда: Set-AdsState -State Config.

Вообще, после установки пакета TcXaeMgmt, вы сможете делать из командой строки практически всё что угодно:... конкретнее, читайте в about_TcXaeMgmt.help.txt. Только помните — так как вы будете влиять на системные сервисы и другие важные штуки Windows, от вас часто будут требовать права Администратора. Их тоже можно выдавать автоматически из скрипта PowerShell.

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

if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).
        IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 
{
    Start-Process
        -WindowStyle Hidden
        -Verb RunAs
        powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"";
    exit
}

Restart-Service TcSysSrv -Force
Set-AdsState -State Config -Force


Сохраняем скрипт в файл с расширением .ps1. Файл кладем в C:\TwinCAT\3.1\Target\StartMenuAdmin. Здесь же делаем на него ссылку-ярлык и изменяем имя ярлыка на удобное нам название. Оно тут же появится в системном меню TwinCAT, картинка которого была в начале поста.


October 4, 2018

Веб-конфигуратор для CX8090

Последнее время Бекхофф встраивает в свои контроллеры веб-интерфейс для начальной настройки ПЛК. Это хорошо, потому что через ADS-роутер можно кое-как выяснить IP и AmsNetId -адреса ПЛК, но для запуска FTP-сервера или сервиса удаленного доступа — этого уже мало. В умный по сути коплер CX8090 просто некуда воткнуть святую троицу монитор-клавиатура-мышь. Разъемы для них не предусмотрены и не поддерживаются. Надо изгаляться... надо было, так как теперь все это делается через веб-интерфейс. По крайней мере первый шаг, который, как известно, чего-то-там для человечества.

Находим контроллер через TC2 System Manager или роутер TwinCAT 3: иконка TC3 в системном лотке (traybar) → Router → Edit Routes → TwinCAT Static Routes. В колонке Address видим IP-адресс ПЛК. Открываем любимый браузер. Для разнообразия, и чтобы показать, что никакой разницы нет, я взял нелюбимый в народе Edge.

Вводим в адресную строку: IP-адресс-ПЛК/config. Логин по умолчанию: webguest, пароль: 1.



Есть на что посмотреть и с чем поработать. И сразу же, чтобы не забыть потом, включаем удаленный доступ для работы с ПЛК через CERHost. А дальше уже не проблема запустить FTP-сервер, "залить" русские шрифты и поправить настройки в реестре Windows CE.


August 22, 2018

Экономия на абстракциях

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

Что если разбивка на множество подпрограмм привносит дополнительную нагрузку на процессор ПЛК и снижает быстродействие?

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

Спагетти код ругают: все-таки трудно ориентироваться в бесконечной портянке неструктурированного кода непонятного назначения. Поэтому я хочу знать — имеет смысл экономить на абстракциях или я могу разбивать код на сколько угодно удобных мне частей?

Итак, исследуем влияние количества вызовов подпрограмм на загруженность процессора. Проверять TwinCAT 2 мне не очень-то и хотелось, но я проверил и не пожалел.

PROGRAM MAIN
VAR
    i: UINT;
END_VAR

FOR i := 0 TO 65000 DO
    PRG2();
END_FOR

(* ********************** *)

PROGRAM PRG2
VAR
    c : UINT;
END_VAR

;
// c := c + 1;
// c := c + 1;

Основная программа MAIN каждый цикл совершает ряд вызовов подпрограммы PRG2. Количество вызовов определяется количеством итераций цикла. Их максимальное число равно 65000 — как в примере выше. Так как нас в основном интересует нагрузка от ветвления программы, то подпрограмма PRG2 пустая. Точнее, она состоит из единственного оператора точка-с-запятой (;). Чтобы не было совсем банально, я разбавил подпрограмму парой строк со счетчиком (и это было правильным решением).

По вертикали (Y) — нагрузка процессора в процентах, по горизонтали (X) — количество вызовов подпрограммы за время одного цикла:
Ничего необычного: чем больше вызовов, тем больше нагрузка на процессор. При этом нужно учесть два факта: первый — подпрограмма PRG2 ничего не делает и нагрузка растет только за счет количества передачи управления из одной программы в другую; и второй — тест синтетический и в реальных ситуациях такого количеств вызовов за один цикл не бывает.

Теперь проверим TwinCAT 3:
...и он показывает более линейную зависимость.

Теперь об аномалиях второй версии TwinCAT. В подпрограмме PRG2 я убрал пустой оператор ";" и раскомментировал одну строку со счетчиком. Зафиксировал количество вызовов на числе 65000. Замерил нагрузку. Раскомментировал вторую строчку со счетчиком (теперь их две). Замерил нагрузку и впал в задумчивость.

Итак, внимание! С одной строкой счетчика, нагрузка составила 72%. С двумя строками счетчика — 43%. Больше кода — меньше нагрузка! Объяснить такое поведение можно только работой некоего оптимизирующего звена в компиляторе кода, но такая неявность, явно вводит в заблуждение. Я немедленно проверил то же самое в TwinCAT 3...

...и он по прежнему оказался линеен и предсказуем: 1 строка — 56%, две строки — 58%.


Выводы

  1. Вызовы подпрограмм добавляют нагрузку на процессор.
  2. Я решил, что не буду обращать на эту нагрузку внимание, так как ощутимой она становится только при каких-то очень больших числах вызовов за время одного цикла. Даже для CX8xxx серии.
  3. TwinCAT 3 стабильнее и предсказуемей, чем его вторая реализация.
  4. Upd. 29 мая 2019 года, TwinCAT 2 v2.11.2302 странности с "меньше кода - больше нагрузка" не наблюдаются. Возможно был баг с выравниванием переменных в памяти. 


P.S.: посчитаем вызовы


А как вообще прикинуть — сколько вызовов происходит в проекте?

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

Для начала, открываем проект и экспортируем его в единый файл экспорта *.exp. Затем, открываем EXP-файл в текстовом редакторе (Notepad++) и автозаменой удаляем все вхождения следующих строк: (*, STRING(, IF (. Файл в итоге будет испорчен, но для нас важнее исключить посторонние элементы. Остается сделать глобальный поиск символа открывающей скобки (, который традиционно используется при вызове подпрограмм. Как вариант, поискать закрывающие скобки, а точнее конец вызова функции, что-то похожее на );

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


На картинке выше подсвечены не все скобки, но они учтены и подсчитаны правильно.

В итоге, я нашел 560 вызовов с открывающими скобками и 433 с закрывающими. Это в два раза меньше 1000 (1-2% CPU, как в пустой программе) и совсем далеко от 65000 (56-58% CPU). Еще раз, это максимум, который можно вызвать, но который никогда не будет достигнут: программа разбита на шаги (машина состояний), в каждом из которых выполняется лишь небольшая часть всей технологической программы.