пятница, 13 января 2017 г.

System Manager и четыре рантайма

При попытке создать несколько рантаймов и добавить несколько ПЛК-проектов, System Manager начинает капризничать, брыкаться, а в конце выдает ошибку: Runtime system is used by another project!



... и это не баг и не фича — это нюанс, который придется обойти.

Проект строится с помощью двух системных программ: System Manager — конфигуратор ПЛК и PLC Control в котором непосредственно разрабатывается программа контроллера. В какой-то момент разработки необходимо пробросить между ними мостик и познакомить их, передавать настройки из одной в другую и обратно. Для этого служат файлы с расширением .tpy, которые делает PLC Control при сборке (Project → Build) или пересборке (Project → Rebuild all) проекта.
Кроме файлов TPY, также существуют файлы TPA. Их создает System Manager, когда вы добавляете в конфигурацию новый проект или пересканируете уже существующие приекты (Rescan Project...). В эти TPA-файлы System Manager сохраняет конфигурацию переменных ввода/вывода (%I*, %Q*), заменяя звездочки (*) на реальные адреса.

При последующей пересборке проекта, PLC Control увидит файл TPA, созданный ранее System Manager'ом, и добавит в ПЛК-проект конфигурацию переменных, которую впоследствии можно увидеть в Resources → Global Variables → TwinCAT_Configuration.
В файле TPY находится полная информация о проекте, в том числе информация о рантайме, в котором планируется исполнять ПЛК-программу. К сожалению, невозможно выбрать нужный рантайм вручную, если вы разрабатываете проект без контроллера на столе и рядом с вами. По умолчанию система автоматически подставляет в проект первый рантайм, а затем сама же на это ругается, когда вы пытаетесь добавить второй, третий или четвертый проект в System Manager: ведь первый рантайм уже занят и нужно выбрать другой?

Чтобы покинуть тупиковую ситуацию, придется вручную отредактировать файл TPY, а конкретнее поле <Port> настроек роутинга <RoutingInfo> проекта <PlcProjectInfo>. Откройте в любом текстовом редакторе файл с расширением .tpy:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--This file is created by the TCatPlcCtrl automatically. Manually changes will be overwritten!-->
<PlcProjectInfo xmlns:p="http://www.beckhoff.com/2002/01/TcPlcProjectDesc">
    <ProjectInfo>
[...]
    </ProjectInfo>
    <RoutingInfo>
        <AdsInfo>
            <NetId>0.0.0.0.0.0</NetId>
            <Port>801</Port>
            <TargetName>
                <![CDATA[Target: Local (192.168.56.1.1.1), Run Time: 1]]>
            </TargetName>
        </AdsInfo>
    </RoutingInfo>

Номера портов жестко фиксированы: 1 — 801; 2 — 811; 3 — 821; 4 — 831. Достаточно заменить номер порта на соответствующий необходимому рантайму, а все остальные упоминания о рантайме можно оставить без изменений: на них система не обращает никакого внимание. Сохраните файл и без проблем добавьте его в конфигурацию System Manager'а.

среда, 30 ноября 2016 г.

TcHVAC: Структура библиотеки и проекта

Функционал управления отоплением, вентиляцией и кондиционированием (ОВК, ОВиК, HVAC: Heating, Ventilation, & Air Conditioning) в TwinCAT оформлены в виде библиотеки TcHVAC. Библиотека стоит денег и обозначена артикулом TS8000. В справочной системе можно найти в разделе: TS8000 | TwinCAT PLC Lib: HVAC.


Структура справки и структура каталогов в библиотеке различается, поэтому будем отталкиваться от структуры библиотеки, так как она ближе к практике. Следует сразу учесть, что библиотека строилась с учетом специфики разработки в виде функциональных блоков (FBD, CFC) и на ST временами будет выглядеть уродливо: за универсальность приходится платить.

Как правило, простые системы HVAC строятся исходя из релейной логики — "тумблеры и лампы": нажали кнопку, собралась цепочка, загорелась лампа (включился мотор, открылся вентиль и т. п.). Для полного описания такой системы составляют таблицу входов/выходов, оптимизируют ее (например, вручную с помощью карт Карно) и только затем переносят в виде LD-диаграмм или блоков FBD|CFC. На практике так никто не делает. Поэтому библиотека построена так, что следуя ее логике, цепочка функциональных блоков сложится сама: библиотека просто настроена на это — ставите один блок, за ним неминуемо тянутся другие.

Управление объектами строится на базе одного или каскада ПИД-регуляторов. Причем есть как классические (универсальные) регуляторы, так и специализированные, заточенные под управление конкретными объектами ОВиК, что позволяет объединять управляемые объекты в цепочки типа заслонка-рекуператор/подмешивание-подогреватель-увлажнитель-вентилятор-итп (смотри картинку выше).


Каталоги библиотеки


  • Actuators — насосы, моторы, одно-, двух-, трех-скоростные, резервирование и авторотация основной-резервный по времени наработки. Под мотором можно понимать целый исполнительный механизм, например, вентилятор.
  • Analog modules — преобразование аналоговых данных в обе стороны. Исполнительные механизмы с аналоговым управлением и датчики контролируемых параметров: температура PT100/1000, давление, управляющие сигналы 0-10В, 4-20мА или сигналы обратной связи и т. п. Параметры можно масштабировать в обе стороны.
  • BackupVar NOVRAM — автосохранение и автовосстановление переменных и настраиваемых параметров функциональных блоков библиотеки в NOVRAM памяти контроллера.
  • BackupVat Persistent — аналогично предыдущему пункту, но сохранение производится на флешку ПЛК.
  • Controller — различные регуляторы: ПИД, двухточечные, цепочки регуляторов, регуляторы заточенные под конкретный исполнительный механизм.
  • Room functions — специализированные функции для управления параметрами в жилых помещениях: климат-контроль, освещение, засветка Солнцем.
  • Setpoint modules — формируют кривые и рампы задания, основываясь на времени суток, летнем-зимнем сезоне и т. п.
  • Special functions — вспомогательные функции, помогающие преобразовывать типы данных, контролировать фронты входов/выходов или просто универсальные функции-обертки, позволяющие строить универсальные алгоритмы, подходящие для ПЛК различных типов. Самый простой пример — функция Blinker для мигания лампочкой с интервалом в одну секунду.
  • System — обще-системные функции: чтение/установка часов операционной системы, создание копий параметров функциональных блоков, получать сведения о циклах ПЛК-задачи и немного других системных функций.
  • Time schedule — планировщик действий по расписанию на один день, неделю, месяц, по праздникам и будням и т. д.


Структура проекта


Входная точка управления вентиляцией (и всем остальным) расположена в недрах функционального блока FB_HVACStartAirConditioning. Основная роль этого ФБ — быть диспетчером или дирижером всего оркестра устройств. Именно к нему прикрепляются все остальные функциональные блоки, именно он дает разрешение в виде сигнала Enable на блоки управления заслонками, вентиляторами, насосами и т. п.

Параллельно с блоком StartAirConditioning, каждый цикл вызывается ряд блоков, отвечающих за системные функции. Типичный набор этих функций выглядит так:
  • Считывание уличной температуры с компенсацией, FB_HVACOutsideTempDamped.
  • Мигалка, формирователь однополярного меандра, FB_HVACBlink.
  • Сохранение энергонезависимых данных, FB_HVACPersistentDataHandling.
  • Чтение системного времени, FB_HVACGetSystemTime.
  • Чтение параметров ПЛК-задачи, FB_HVACSystemTaskInfo.
  • Дополнительно: трансляция данных наружу через один или несколько протоколов передачи данных (например, Modbus).

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

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

В ответ ФБ StartAirConditioning выдает сигналы на специализированные ФБ, которые управляют исполнительными механизмами: воздушные заслонки, вентили подогревателя, увлажнители, вентиляторы и другие устройства.

Если такая структура вас не устраивает — можно самостоятельно разработать логику управления. Все "большие" блоки построены на основе других, более специализированных функций библиотеки.

четверг, 24 ноября 2016 г.

Взгляд со стороны клиента ModbusTCP

Копнем чуть глубже — как выглядит сервер ModbusTCP с точки зрения клиента — по каким адресам модбаса нужно стучаться и что мы там найдем. Для свежести в памяти — обзор катушек и холдинг регистров и настройка сервера Modbus TCP.

После установки сервера ModbusTCP у нас уже есть настроенный конфигурационный файл, которым заранее удобно пользоваться. Все адреса десятеричные и все это можно позднее переделать под себя в том же конфигурационном файле. Пока же воспользуемся параметрами заданными по умолчанию в конфигурационном файле. Сетевой порт TCP = 502, полезная справочная документация = Mapping between Modbus and ADS.


Работа со стандартными массивами


Немецкие инженеры о нас позаботились — четыре заранее сформированные массива открывают доступ к данным Modbus. Причем открывают без какой-либо головоломки с расчетом индексов, упаковкой битов в слова и других отвлекающих преобразований.

После установки на ПЛК сервера ModbusTCP, последний автоматически ищет четыре глобальные переменные с заранее заданными именами.
Эти имена (или пара индекс-смещения) задаются в конфигурационном файле в разделах <VarName> или парой <IndexGroup> // <IndexOffset>.
Еще раз: в самой ПЛК-программе, вам ничего добавлять не нужно: сервер сам попытается найти эти имена среди глобальных переменных, и если найдет — автоматически начнет трансляцию данных по шине Modbus. Включать в проект дополнительные библиотеки не требуется, просто добавляем в глобальные переменные четыре массива:

.mb_Input_Coils [0..255] OF BOOL
.mb_Output_Coils  [0..255] OF BOOL
.mb_Input_Registers [0..255] OF WORD
.mb_Output_Registers  [0..255] OF WORD

С точки зрения ModbusTCP массивы получают адреса начиная с 3276810 (или 0x800016). Расчет полного адреса ведется с учетом индекса в массиве:

.mb_Input_Coils [0..255] OF BOOL
.mb_Output_Coils  [0..255] OF BOOL

Адрес Modbus = 32768 + индекс в массиве (0..255)

Одна катушка или дискретный порт ввода-вывода соответствует одной ячейке массива типа BOOL. Это очень удобно, так как не требуется упаковка битов в "слово". Аналогично с регистрами:

.mb_Input_Registers [0..255] OF WORD
.mb_Output_Registers  [0..255] OF WORD

Адрес Modbus = 32768 + индекс в массиве (0..255)

В каждом массиве всего 256 элементов, поэтому адресация этих массивов заканчивается для Modbus на числе 33023. Полный диапазон 32768..33023.


Переменные ввода/вывода


Дополнительно к массивам, автоматически транслируется область переменных ввода-вывода, то есть также одновременно транслируются те переменные, которые связаны с физическими входами/выходами или, иначе говоря, переменные, которые обозначены как AT %I* и AT %Q*. Простые правила помогут запомнить что-с-чем ассоциируется:
  • Катушки (coils) можно намагничивать и размагничивать — поэтому они могут менять свое значение и поэтому они связаны с AT %Q*. Аналогичное правило для регистров хранения (holding registers): в них тоже можно сохранять и читать.
  • Inputs — это входа и они только для ввода данных, поэтому записывать нельзя — AT %I*.

Чтение с помощью функций модбаса:
  • Катушки %QX — функция #1, Read Coils.
  • Регистры хранения %QB, %QW,... — #3, Read Holding Registers.
  • Дискретные входа %IX — функция #2, Read Discrete Inputs.
  • Дискретные регистры ввода %IB%IW,... — #4, Read Input Registers.

Запись доступна только для катушек и регистров хранения, по одному за раз, но вообще можно и несколько за раз (функции 15 и 16):
  • Катушки %QX — функция #5, Write/Force Single Coil.
  • Регистры хранения %QB, %QW,... — #6, Write/Preset Single Register.

В итоге выстраивается стройная система — с точки зрения Modbus, мы номером функции выбираем тип переменных (чтение/запись, катушки/регистры), а затем адресом уточняем какую именно переменную мы хотим.

Адрес Modbus для переменных ввода данных (AT %I) лежит в диапазоне 0..32767. Для переменных ввода/вывода (AT %Q, катушки и регистры хранения) верхняя граница занижена 0..12287, иначе они будут пересекаться с меркерной памятью (читай ниже).

Расчет адресов идет по единому принципу и для тех, и для других. Так как дискретные или битовые входа/выхода упаковываются в байты — значения адресов Modbus придется немного повычислять, :

%IX#.@ (где # — номер байта, @ — номер бита в байте)
%QX#.@

Адрес модбас = # * 8 + @

Пример:

bSomeVar AT %IX6.2 : BOOL;

Адрес модбас = 6 * 8 + 2 = 50


Для байтовых входов/выходов все проще:

%IB# (где # — номер байта)
%QB#

Адрес модбас = #


"Слова" состоят из двух байт, поэтому идут с шагом два. Например, для %IW и %QW:

iSomeVar0 AT %QW0 : WORD;
iSomeVar1 AT %QW2 : WORD;
iSomeVar2 AT %QW4 : WORD;
[...]
iSomeVarN AT %QW* : WORD;

Адрес модбас = N * 2


Меркерная память


Для шины Modbus эта область памяти (AT %M*) лежит в диапазоне адресов 12288..24575. Адреса строятся аналогично переменным ввода/вывода из предыдущего пункта.
Обратите внимание, что адреса Modbus для меркерной памяти пересекаются с адресами переменных ввода/вывода %Q и в то же время не пересекаются с адресами переменных ввода %I. Это происходит по причине доступности переменных %M как на чтение, так и на запись, аналогично переменным ввода/вывода %Q. Именно поэтому M- и Q-области памяти  выглядят одинаково с точки зрения Modbus, а значит и доступны с помощью одних и тех же функций Modbus.


Порядок слов


Modbus как таковой ничего о типах данных не знает и перегоняет битовые единицы упакованными в "слово", а регистры просто как "слова" (WORD). При этом протокол ничего не знает ни о знаке числа (для него все числа целые), ни о плавающей запятой, ни о порядке байт в слове.

Например, я сейчас включил ПЛК и при использовании типа WORD получил следующую картину:

%MB0 — младший байт
%MB1 — старший байт

%MW0 — 12288 (%MB1 : %MB0)
%MW2 — 12289 (%MB3 : %MB2)
%MW4 — 12290 (%MB5 : %MB4)

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


Загадочные области памяти


На самом деле — нет, но начиная с 24576 идет область данных, где хранятся значения переменных ПЛК-программы. Оттуда можно вытащить через Modbus значения вообще любых переменных ПЛК-программы, но особого смысла ковыряться в ней — нет. Зачем? Когда есть все выше изложенное.

четверг, 3 ноября 2016 г.

Системный диалог даты-времени в Windows CE

Как быстро сделать ввод системной даты/времени при создании визуализации TwinCAT 2 под Windows CE? Нужно воспользоваться системным диалогом из панели управления — открыть  проводник explorer.exe, а дальше оператор сам найдет, исправит, настроит, испортит. Чтобы избежать такого поведения можно открывать только панель даты/времени.

1. Из меню Start запускаем notepadce.
2. Аккуратно вводим одну строчку, внимательно следя за пробелами и другими символами:

35#"ctlpnl.exe" \Windows\cplmain.cpl,13

35# — это количество символов в строке. Между ..ctlpnl.exe" и \Windows\... стоит пробел.

3. Файл сохраняем как datetime.lnk во флэш памяти контроллера (имя файла произвольное, если-что). Сохранить можно где-нибудь в \Hard Disk\datetime.lnk

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

Input → Execute program: "\Hard Disk\datetime.lnk"

Теперь при нажатии на элемент можно отображать только системную панель настройки даты/времени:



Можно открывать и другие апплеты панели управления:


PC Connection – 35#"ctlpnl.exe" \Windows\cplmain.cpl,0
Dialing – 35#"ctlpnl.exe" \Windows\cplmain.cpl,1
Keyboard – 35#"ctlpnl.exe" \Windows\cplmain.cpl,2
Password – 35#"ctlpnl.exe" \Windows\cplmain.cpl,3
Owner – 35#"ctlpnl.exe" \Windows\cplmain.cpl,4
Power – 35#"ctlpnl.exe" \Windows\cplmain.cpl,5
System – 35#"ctlpnl.exe" \Windows\cplmain.cpl,6
Display – 35#"ctlpnl.exe" \Windows\cplmain.cpl,7
Mouse – 35#"ctlpnl.exe" \Windows\cplmain.cpl,8
Stylus – 35#"ctlpnl.exe" \Windows\cplmain.cpl,9
Volume & Sounds – 35#"ctlpnl.exe" \Windows\cplmain.cpl,10
Input Panel – 35#"ctlpnl.exe" \Windows\cplmain.cpl,11
Remove Programs –  35#"ctlpnl.exe" \Windows\cplmain.cpl,12
Date/Time – 35#"ctlpnl.exe" \Windows\cplmain.cpl,13
Certificates – 35#"ctlpnl.exe" \Windows\cplmain.cpl,14
Accessibility – 35#"ctlpnl.exe" \Windows\cplmain.cpl,15


Для открытия CX Configuration или полностью Beckhoff CX Configuration Tool, нужно запустить другой апплет:

35#"ctlpnl.exe" \Windows\CxConfigCpl.cpl


Для юных исследователей доступен каталог \Windows, который может содержать (и содержит) другие апплеты панели управления в виде файлов с расширением .cpl

вторник, 18 октября 2016 г.

Я сделаю свой NC с рампами и траекториями

В частотных приводах AX5000 и сервомодулях EL72xx изначально заложена возможность прямого управления сервоусилителями: кидаете задание Velocity command value, формируете слово управления Master control word и постоянно следите за словом состояния Drive status word. По сути вам необходимо самостоятельно обрабатываете все, что есть в AT|MDT ветках сервоусилителя. Просто и дешево, но:
  • Не умеет масштабировать величины. Все значения задаются в инкрементах. Хотя можно реализовать пересчетные функции (как уже сделано в NC).
  • Только базовый набор функций: вкл/откл силового питания, вращение с заданной скоростью, абсолютное позиционирование, контроль тока, ограничение момента.
  • Все управление идет из ПЛК-задачи: если в программе тех. процесса допустить ошибку, то она отразится в том числе и на работе сервоусилителя, так как они все вместе работают внутри одной и той же задачи (в отличии от NC, которая работает как независимая подсистема TwinCAT).
  • Зависимость от времени цикла ПЛК-задачи. NC не зависит от времени цикла задачи, что положительно сказывается на скорости реакции, плавности/точности траекторий и пр. 
  • Нет разгонно-тормозных рамп, но можно реализовать их самостоятельно.
  • Зависимость от режима работы сервоусилителя: нельзя задать скорость вращения в режиме позиционирования и обратная ситуация — нельзя выйти в абсолютную позицию в режиме управления по скорости.
  • Нет ни гарантии, ни тех. поддержки: умер разработчик — умерла система.

Должны быть плюсы:
  • Дешево.
  • Будет работает на всем, что может обеспечить EtherCAT-мастер, в том числе и на контроллерах CX8010 + EK1110.


Что-то подобное уже всплывало в зачем нужен NC PTP и что он себе позволяет.

вторник, 11 октября 2016 г.

SIL-3

EL6900 и желтые Safety-терминалы соответствуют системному уровню надежности SIL-3. Будет ли разрабатываемая система считаться безопасной или нужны дополнительные процедуры?

В документации по желтым модулям постоянно встречается упоминание SIL-3, а в конце тех. документации есть изображение сертификатов, которые к тому же можно скачать отдельным pdf-документом. В дополнение к ним можно посмотреть на сертификаты таможенного союза (Россия, Белоруссия, Казахстан). Там же есть соответствия требованиям промышленной безопасности, которое говорит, что модули можно использовать в промышленности и они будут соответствовать бюрократическим требованиям.

В общем, не важно когда начинать разрабатывать программную и safety-логики: до согласования или после сертификации. Модули уже соответствуют SIL-3. Это означает, что они готовы и могут обеспечить соответствующие требования МЭК/TUV. Правда соответствие модулей не означает, что вся система будет соответствовать требованиям безопасности только потому, что в ней все модули безопасности соответствуют SIL-3. Да и сам SIL-3 говорит только о степени надежности отдельных модулях, а не о безопасности всей системы в целом.

Еще раз: модули соответствуют требованиям SIL-3. Функционал модулей достаточен для обеспечения соответствующего уровня надежности системы. Что в итоге "вылепит" разработчик — никому не известно.

Как итог, приемку системы в целом, будет осуществлять заказчик по своим нормам и правилам или делегирует в какую-либо сертификационную/проверочную организацию. Лучше с самого начала узнать у заказчика, что он собственно подразумевает, когда просит SIL-3 и работать в соответствии с этим.

Хорошая статья в тему: SIL — это не сложно.

вторник, 4 октября 2016 г.

Как добавить точку в ломаную линию?

В преддверии новой визуализации на html5 и css3 поковыряем нюансы старой-доброй визуализации под TwinCAT 2.

Начнем с простого — надписью может быть любой элемент, достаточно отключить у него бордюр: Colors → No frame color.

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

Поле Variables → Invisible — это в прямом смысле "невидимость". TRUE → элемент невидим, FALSE → элемент отображается, то есть его видно.

Значение параметров фигуры (цвет, размер и пр.) могут задаваться в нескольких местах одновременно и тогда одни значения начинают перекрывать другие. Можно задать величину параметра как статическое значение (например, цвет в поле Colors). Это значение перекроется значением, заданным в виде переменной  из раздела ColorVariables. Переменную, в свою очередь, может перекрыть программная структура из раздела Programmability. При отладке программы, значения переменных введенные через Watch-n-Recipe перекрывают вообще все.

Можно добавить новую точку в ломаную линию или многоугольник: удерживая клавишу Ctrl, тянем левой кнопкой мыши за уже существующую точку и вытягиваем из нее новую точку. Ctrl + Shift + клик — удаляет уже существующую точку.

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

Motion absolute:
  • Углы задаются в градусах.
  • Масштабирование, оно же Scale: 1000 = 100% размера фигуры. Масштабирование касается всей фигуры в целом, в том числе и расстояния до центра фигуры.
  • Y-offset, X-offset — сдвинуть всю фигуру влево-вправо / вверх-вниз.
  • Angle — поворот относительно центра (кружок с перекрестием), но(!): Shape (прямоугольники и эллипсы) вращаются так, что верх фигуры остается всегда вверху. Polygon (многоугольники, контуры, кривые) вращаются так, что все точки совершают вращение относительно центра фигуры. Если вам нужен квадрат вращающийся относительно своего центра — нарисуйте его из ломаной поли-линии.

Можно добавить один экран визуализации на другой экран в виде элемента меньшего размера. Размер такого элемента определяется типом масштабирование пропорций:
  • Anisotropic — произвольные пропорции и размер.
  • Isotropic — фиксированные пропорции, но произвольный размер.
  • Fixed — фиксированные пропорции и размер.
  • Fixed and scrollable — как и Fixed, но можно прокручивать (не работает в Windows CE, см. раздел про ограничения).

Пунктирные, штрихпунктирные и прочие тире-тире-точки можно получить, задав ColorVariables → Frame flag отличный от нуля. Тип линии меняется только во время работы визуализации и не меняется во время разработки:
  • 0 сплошная ____
  • 1 пунктир - - - -
  • 2 точки ......
  • 3 тире-точка -.-.-
  • 4 тире-точка-точка -..-..-
  • 8 невидимая, но ее толщина учитывается

Input → Execute Program — это целый отдельный мир программирования. Здесь можно создавать макросы (Macro). Например, при нажатии кнопки Сохранить на экране задания параметров, сменяется текущая визуализация (Input → Zoom to viz.). Можно сделать так, что одновременно со сменой визуализации будет задаваться значение какой-либо переменной (как глобальной, так и локальной в подпрограмме). Таким образом можно отследить, что пользователь уходит с экрана настроек и необходимо сохранить persisitent-переменные, если он нажал ОК, и не сохранять, если он ушел по кнопке Отмена.

Programmability → Object name, если установить галку и ввести имя переменной, то после перекомпиляции проекта появляется новая глобальная переменная-структура типа VisualObjectType. Объявление этой переменной не видно в проекте, но она как суслик все-равно есть и доступна для Intellisense по F2.


Все эти вопросы неплохо рассмотрены в справочной системе, но на английском языке (или немецком) и все равно всплывают раз-за-разом:

среда, 28 сентября 2016 г.

Вебинар. Новое поколении TwinCAT HMI

Много клиентов, много серверов, много рантаймов и много всего остального. Основной акцент на слово "много". Сводный обзор по возможностям и полезностям визуализаций в TwinCAT 3 провел Дэймон Томпсон (Daymon Thompson). По окончании на вопросы ответил глобальный продукт-манагер Свен Обершмидт (Sven Oberschmidt). По прежнему хочется "мяса" из инженеров.



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

Основные черты продукта:
  • Основан на технологиях пришедших из интернета: html5, css3, javascript.
  • Клиенты из-под браузеров (в том числе и Edge) и клиенты на мобильных системах Android и iOS, ведь там тоже есть браузеры, только мобильные.
  • Система рассчитана на продолжительный срок жизни: придет и останется с нами надолго.
  • Всё такое масштабируемое, модульное и независимое, векторное и веб-ориентированное. Если кратко и без патетики — должно стать удобнее как в разработке, так и в применении.


TwinCAT HMI Creator


Визуальный редактор: не нужно программировать, просто рисуйте и редактируйте готовые шаблоны.
  • Интеграция с Visual Studio.
  • Интеграция с TwinCAT.
  • Редактор с упором на визуальную разработку.
  • Использование систем контроля версий (tfs, svn, git, ...).
  • Менеджер пакетов.
  • Готовые шаблоны проектов.
  • Темы оформления.
  • Графическая библиотека готовых элементов: SVG, сложные и составные элементы.


TwinCAT HMI Framework


  • Готовые контролы (элементы управления интерфейсом):
    • стандартные;
    • графики, чарты, события/логи/журналы (events);
    • пользовательские (самодельные) контролы.
  • Применение сложных типов данных (структуры, дата/время и пр.).
  • Интернационализация:
    • переключение языков;
    • национальные единицы измерения, меры длины, денежные знаки и т. п.
  • Расширябильность засчет html5 и javascritpt.


TwinCAT HMI Server


Веб-сервер написанный Бекхоффом (фирмой, а не человеком). Обещают, что будет работать на всем, что начинается с CX9020. В том числе и на Windows CE.

  • ADS — что позволяет использовать рантайм как от TwinCAT 3, так и от TwinCAT 2.
  • OPC UA — что позволит использовать вообще все что угодно.
  • Цифровой осциллограф Scope. Пока не понятно куда и как он будет встраиваться, но возможно имеется в виду его серверная часть.
  • Безопасность данных (https, tls и прочий эS).
  • Уровни доступа пользователей (роли пользователей, login | logout).
  • Предварительно подготовленные данные для тестирования и отладки (recipe management).
  • Логирование событий.
  • Сбор данных.
  • Сможет расширяться модулями на C++ / C#.


Разработка


  • Сплошная интеграция с Visual Studio.
  • Живое взаимодействие с визуализацией во время разработки. Будет сразу видно, что и как работает.
  • Графический редактор с набором стандартных и не очень элементов.
  • Предварительно настроенные шаблоны, которые можно доработать. Обещают современный внешний вид с анимацией и прочими свистелками.
  • Контролы пользователя расширяются с помощью javascript. Серверная часть расширяется на C++ / C#. Можно подготовить заранее темы в корпоративном стандарте под брендбук, а затем использовать во всех остальных проектах.

Про архитектуру уже было в Новый HMI для TwinCAT 3 (8 декабря 2015). Про сценарии применения было в Визуализации в TwinCAT 3 (24 марта 2016), но если кратко:

  • Наиболее распространенный сценарий "локальный клиент": визуализация и браузер работают на одном контроллере, а графическая панель подключается через DVI.
  • Много клиентов через интернет (например, мобильные телефоны и планшеты) подключаются к локальному клиенту.
  • Много клиентов подключается к одной машине с сервером TwinCAT HMI, который собирает (агрегирует) данные с нескольких ADS-серверов (умных коплеров или младших моделей CX).
  • Много TwinCAT HMI серверов, которые подключены к одной машине, которая отображает сводные данные со всех других серверов (сервер серверов).

При этом сохраняется мультипротокольность: сервер общается с коплерами по любым протоколам, клиенты подключаются к серверу через http(s) и браузеры.


Лицензирование


  • Стоимость не зависит от количеств тегов. 
  • Инструменты разработчика бесплатны, включая обновление, сопровождение и поддержку.
  • Лицензирование касается только сервера. Клиенты работают бесплатно и не лицензируются.

Стоимость лицензии строится исходя из:
  • уровня платформы на которой будет работать TwinCAT HMI Server;
  • количества клиентов и целевых систем (target runtimes).

Пример


TF2000 HMI Server — рассчитан на 1 клиента (браузер) и  одну целевую систему (netId), то есть в базовой версии один клиент — один таргет.

Можно добавить клиентов или таргетов:
- TF20x0 Clients Pack 1/3/10/25 (пакет клиентов — один, три, десять дополнительных клиентов).
- TF20x0 Targets Pack 1/3/10/25 (пакет таргетов).

Можно добавить расширения визуализации HMI Extension (Scope, OPC UA) — это расширения для добавления протоколов или дополнительных функций.

В итоге будет сформирована лицензия TwinCAT 3 HMI License.


Итого


  • Быстрая разработка, где мало разработки и больше рисования.
  • HTML5, javascript.
  • Клиент не зависит от платформы. 
  • Модные веб-технологии.
  • Гибкая архитектура.
  • Модульность.


Вопросы-ответы


  • Разница между TwinCAT PLC HMI и TwinCAT HMI? Первый будет только патчиться, новые фичи будут появляться только в TwinCAT HMI.
  • Какие версии Visual Studio? Пока что 2013-2015. Дальше будет видно, а пока этого достаточно.
  • Локальные переменные будут доступны (транслируются) в контекст браузера. Надо смотреть что там имелось в виду.
  • Когда? В этом году (2016) немецкая версия, в начале следующего года для всех остальных, кто говорит на английском.
  • Веб-сессии (sessions) поддерживаются, информация о веб-клиенте доступна.
  • PLC HMI контролы и модные HMI контролы, да и другие элементы тоже, смешивать и перемещать туда-сюда нельзя. Вполне возможно, хотя и маловероятно, в будущем появится конвертер первого во второй, но не обратно.


Полный вебинар на английском языке TwinCAT HMI | The next HMI generation.

четверг, 8 сентября 2016 г.

Пропорционально-интегрально-дифференцирующий

С параметрами ПИД-регулятора можно играться как с кошкой — до бесконечности: пока в колебательный процесс не впадет или не надоест.

Несмотря на тонны матана, прячущиеся за тройкой входных параметров, около 90% регуляторов в мире основано на ПИД (гугл, википедия, нормальное распределение). Именно благодаря простому интерфейсу, скрывающему интегралы-дифуры, использовать ПИД-регулятор невероятно просто, главное правильно отстроить и не умереть от скуки.

TcControllerToolbox.lib — это основная профессиональная библиотека TwinCAT для работы с регуляторами, генераторами и прочими алгоритмами автоматизации. Там много разных штук, но мы посмотрим на ПИД-регуляторы, как самые распространенные и востребованные.


PLC Controller Toolbox


В прайсе эта библиотека обозначена артикулом TF4100. Это для TwinCAT 3. Если вам нужно модернизировать старую систему на TwinCAT 2, ищите TS4100. Библиотека платная, но построена профессионально — с учетом всего того, что просто необходимо учитывать.
Например: все ФБ библиотеки контролируют циклы и тайминги программных циклов. В случае повторного вызова ФБ за один и тот же цикл или если будет пропуск цикла — ФБ адекватно обработает эту ситуацию. Даже если будет пропущен не один цикл или не один раз.

Кроме непосредственно регулирования, блоки ПИД-регулятора умеют дополнительные опции.

FB_CTRL_PI
FB_CTRL_PID
  • Контроль интегрального насыщения, верхний и нижний пределы.
  • Ручная уставка задания в обход автоматической: можно вмешаться в работу регулятора.
  • Ручное отключение интегральной составляющей.
  • Жесткий контроль циклов ПЛК-задачи и таймингов.

FB_CTRL_PID_EXT
  • Зона нечувствительности для входного значения. При нахождении в ней значение выхода регулятора постоянно.
  • Зона нечувствительности для нулевой величины выхода.
  • Окно для отключения интегральной составляющей (она постоянна или равна нулю).
  • Окно для уменьшения масштаба интегральной составляющей.

FB_CTRL_PID_SPLITRANGE
  • Аналогично FB_CTRL_PID, но можно задать разные наборы коэффициентов "p-i-d" для охлаждения (температура ниже нуля) и для нагрева (температура выше нуля).
  • Имеет два различных выхода, но активен только один. В зависимости от величины выхода — больше нуля или меньше нуля, он запускает нагрев или охлаждение, обнуляя значение противоположного выхода. Кусок кода, для разнообразия:
fOut := fY;

IF fOut > 0.0 THEN
    fOutPos := fOut;
    fOutNeg := 0.0;
ELSE
    fOutNeg := fOut;
    fOutPos := 0.0;
END_IF

FB_CTRL_PID_EXT_SPLITRANGE
  • Всё и сразу: FB_CTRL_PID + _EXT + _SPLITRANGE.


Простой ПИД-регулятор


К тому же бесплатный. Можно было бы перевести дословно — "примитивный", но он работает и это — самое главное.

В бесплатной библиотеке TcUtilities.lib, есть встроенный функциональный блок FB_BasicPID, который умеет три параметра и — все. Больше он ничего не умеет (плюс демпфирование диф.-составляющей Td, но это у разработчика случайно получилось).

Главное отличие от профессиональной библиотеки — это:

FB_BasicPID
  • нет контроля интегрального насыщения;
  • нет контроля повторного или пропущенного вызова за цикл. Вызывайте строго один раз за цикл — иначе пожалеете.

С циклом более менее понятно, а вот отсутствие контроля за интегральным насыщением (integral windup, reset windup, integral saturation) может сыграть злую шутку. Мы сейчас попробуем поиграться с этим эффектом, и заодно убедимся, что функция регулятора действительно примитивная.

Да собственно уже играемся — длинная портянка графика справа показывает, как мы сначала нагрели нечто до 27 градусов, а затем пытаемся охладить, но что-то никак не получается...
Зеленый — задание-уставка.
Синий — выход ПИД-регулятора.
Красный — актуальное, текущее значение на выходе исполнительного механизма.
... А все потому, что не хватает возможности исполнительного механизма — он не справляется, а ПИД-регулятор все топит и топит педальку тормоза-охлаждения. И график ползет вниз...

Чтобы хоть как-то исправить ситуацию, мы попробуем ограничить выход регулятора в соответствии с возможностями нашего исполнительного механизма. Предположим, что он может нагреть до 60 и охладить до 18 условных градусов, условного цельсия:

PID(
    SetpointValue := TargetValue,
    ActualValue   := ActualValue,
    Kp := kp,
    Ti := ti,
    Tv := tv,
    Td := td,
    MaxCtrlOutput := Model.LimitHi,
    MinCtrlOutput := Model.LimitLow,
    CtrlOutput    => SetpointValue);

IF SetpointValue < 18 THEN
    SetpointValue := 18;
END_IF

IF SetpointValue > 60 THEN
    SetpointValue := 60;
END_IF

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

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



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

// расчет интегральной части
IF is_Ipart THEN
    IF (maxLimReached AND (e >= 0.0)) OR (minLimReached AND (e <= 0.0)) THEN
        yi := yi1;                    // замораживаем интегральную часть
    ELSE
        yi := yi1 + di * (e + e1);    // интегрируем
    END_IF
ELSE
    yi := 0.0;
END_IF;

[...]

y := yp + yi + yd;    // суммируем П-И-Д части для расчета выхода регулятора

// проверяем выход на ограничения
IF y < MinCtrlOutput THEN
    y := MinCtrlOutput;
    minLimReached := TRUE;
    maxLimReached := FALSE;
ELSIF y > MaxCtrlOutput THEN
    y := MaxCtrlOutput;
    minLimReached := FALSE;
    maxLimReached := TRUE;
ELSE
    minLimReached := maxLimReached := FALSE;
END_IF

CtrlOutput := y;      // формируем выход функционального блока


Проверяем:



Модель процесса


Это абстрактная модель "какого-то" объекта, имитирующая "какой-то" слегка нелинейный процесс. Чтобы придать модели линейность — уберите в расчете переменной delta часть под квадратным корнем (вместе с самим корнем SQRT) и оставьте только Grow и CycleTime.

PROGRAM Model
VAR_INPUT
    Run       : BOOL;
    Setpoint  : LREAL;
    Grow      : LREAL  := 0.1;    // градусы за секунду
    CycleTime : LREAL  := 0.01;   // секунды
    LimitHi   : LREAL  := 70;
    LimitLow  : LREAL  := 18;
END_VAR
VAR_OUTPUT
    Actual : LREAL;
END_VAR
VAR
    delta  : LREAL;
END_VAR

[...]

IF Setpoint > LimitHi THEN
    Setpoint := LimitHi;
END_IF

IF Setpoint < LimitLow THEN
    Setpoint := LimitLow;
END_IF
 
delta := Grow * CycleTime * SQRT(ABS(Actual * Actual - Setpoint * Setpoint));

IF Actual > Setpoint THEN
    Actual := Actual - delta;
ELSE
    Actual := Actual + delta;
END_IF

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


Про диф.-составляющие


Чаще всего используется ПИ-регулятор. Дальше можете не читать.

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

Чтобы включить ПИД-регулятор в FB_BasicPID необходимо выставить оба диф. коэффициента в значения отличные от нуля. Причем основным диф. параметром является Tv (он расположен в числителе). Td — это время демпфирования и находится в знаменателе диф. составляющей. Его значение можно выставить равным единице и тогда останется только основная Tсоставляющая диф. компоненты ПИД-регулятора.

среда, 17 августа 2016 г.

Тысячи TON

Иногда нужно подождать несколько миллисекунд или переждать час-другой. В таком случае на помощь приходит стандартный блок TON. Так ли он прост или есть нюансы?

Погружаясь в глубины TcBase.lib, туда, где живет наш функциональный блок, мы вскоре ударяемся о дно: внутренности блока TON прячутся в толще TwinCAT, а хвост ведет к ядру операционной системы. Как же нам узнать каким образом отсчитываются интервалы времени: банальный счетчик или что-то посерьезнее? У меня есть догадки, и я попробую подойти к вопросу медленно и с другой стороны.

Нафантазируем систему в которой необходимо много таймеров с разными интервалами срабатывания и различными временами старта. Под словом "много" я принимаю порядки 100, 1000, 10'000, ... и чуть позже станет понятно зачем мне необходимо так много.

Для испытаний возьмем CX9020 (ARM, WinCE) и TwinCAT 2, а затем попробуем старшего брата — CX5010 (x86, WinCE) и наконец CX2030 с настольной операционной системой и TwinCAT 3. Для всех тестов настройки будут по умолчанию: базовое время = 1мс, цикл ПЛК-программы = 10мс.

Загрузим тестовую программу в которой каждый цикл обрабатывается очень много таймеров (одновременно):

PROGRAM MAIN
VAR CONSTANT
    HOW_MANY_TONS : UDINT := 100;
    START_TIME    : TIME  := t#100ms;
    NEXT_PLUS     : TIME  := t#1ms;
END_VAR
VAR
    i      : UDINT;
    pt     : TIME := START_TIME;
    timers : ARRAY [1..HOW_MANY_TONS] OF TON;
    state  : UINT;
END_VAR

[...]

CASE state OF
0:
    FOR i := 1 TO HOW_MANY_TONS DO
        timers[i](IN:= FALSE, PT := pt);
        pt := pt + NEXT_PLUS;
    END_FOR

    state := 100;

100:
    FOR i := 1 TO HOW_MANY_TONS DO
        timers[i](IN:= TRUE);
        IF timers[i].Q THEN
            timers[i](IN := FALSE);
        END_IF
    END_FOR
END_CASE

Делаем срез производительности системы при нулевой активности (программа приостановлена). Нагрузка — максимум 18%. На графике плохо видны пики-выбросы, поэтому кажется что нагрузка чуть меньше, но она есть:



Запускаем 100 таймеров — нагрузка возрастает до 23%:



Предварительный вывод: таймеры нагружают процессор. Увеличиваем порядок до 1000... и система ведет себя неадекватно и небрежно, отнимая время у операционной системы:




Может создаться впечатление, что вызывается слишком много ФБ за один цикл, но на самом деле это не так, и для опровержения я создал ФБ, который интерфейсом повторяет TON, но внутри просто наращивает переменную каждый цикл. Результат совершенно другой: при вызове 1000 имитаций нагрузка не растет, а остается на прежнем уровне 21%.

Вывод: TON не так прост внутри, как снаружи. Внутри ФБ производится какая-то тяжелая работа.


Старшие братья и TwinCAT 3


Можно предположить, что такое поведение свойственно только младшим контроллерам или происходит только на ARM-платформе, но и это не так.

Как более производительный, CX5010 отваливается на 10'000 таймерах. Правда он при этом выдает более ровную нагрузочную кривую, но нам интересно не это. Для CX2030 и настольной операционной системы, можно ожидать лучшего, но там процессор мощнее, поэтому есть рост количества таймеров, но нагрузка все равно ощущается как нечто постороннее. Зато TwinCAT 3 наконец-то не отжирает время у операционной системы. На картинке ниже виден переход от порядка 10'000 к 100'000; система реального времени уже не справляется, но терпеливо держит планку на заданном ограничении 80%:



Объяснение


Похоже, что TON ведет в глубины операционной системы к системным таймерам и может быть даже к высокоточному таймеру HPET. Так что же делать?


Что делать?


Во первых, если от таймеров нужна не сверхточность, а их количество — можно сделать один "продолжительный" таймер и всюду использовать его внутреннее поле ElapsedTime, которое показывает сколько времени прошло с начала запуска таймера... Или может быть сделать свой простой таймер со счетчиком-инкрементом?

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


Все-таки делаем свой таймер


Попробуем доработать нашу имитацию до полноценного таймера. Я назвала его TONLi, потому что он облегченный (light) и потому, что есть LTON (long, еще более длинный).

FUNCTION_BLOCK TONLi
VAR_INPUT
    IN        : BOOL;
    PT        : TIME;
    TaskIndex : BYTE := 1;
END_VAR
VAR_OUTPUT
    Q         : BOOL;
END_VAR
VAR
    state     : BYTE;
    endCount  : UDINT;
END_VAR

[...]

IF IN THEN
    IF state = 0 THEN
        Q := FALSE;
        endCount :=
            SystemTaskInfoArr[TaskIndex].cycleCount +
            TIME_TO_UDINT(PT) * 10000 / SystemTaskInfoArr[TaskIndex].cycleTime;
        state := 10;
    END_IF
ELSE
    state := 0;
END_IF

IF state = 10 THEN
    IF SystemTaskInfoArr[TaskIndex].cycleCount >= endCount THEN
        Q := TRUE;
        state := 255;
    END_IF
END_IF

Интерфейс почти такой же: на выходе потеряли ElapsedTime (с ним будет чуть медленнее из-за дополнительных расчетов); на входе теперь нужно уточнять номер текущей задачи. Ее можно узнать с помощью функции GETCURTASKINDEX. Об этом чуть позже.
В TwinCAT 3 нужно заменить SystemTaskInfoArr на _TaskInfo и можете убрать ссылку на TcSystem.lib. Подробнее читайте в справочной системе о PlcTaskSystemInfo.

Я все еще сделать немного сложнее, чем можно было: если взять обычный счетчик, то придется вызывать таймер каждый цикл и малейший пропуск собьет весь счет времени. Если же использовать .сycleCount — вы всегда будете знать сколько циклов уже прошло (длина цикла фиксирована еще на этапе настройки системы и не меняется во время работы). В этом наш таймер похож на стандартный TON.


_TaskInfo


Чтобы в случае пропуска циклов, не терять кусок прошедшего времени, нам нужен некий независимый отсчет времени. Его мы возьмем из информации о ПЛК-задаче. В большинстве (но не во всех!) CX-системах эта информация сохраняется в структуре, расположенной в меркерной области памяти. Обратите внимание на комментарий — настоящий адрес структуры может отличаться от приведенного (the real address may differ!):

SystemTaskInfoArr AT %MB32832 (*The real address may differ!*) : ARRAY [1..4] OF SYSTEMTASKINFOTYPE;

Что в этой структуре поможет нам сейчас или пригодится в будущем:
  • firstCycle : BOOL — задача запущена и отрабатывает свой первый цикл.
  • cycleTime : UDINT — длина цикла заданной ПЛК-задачи в 100 наносекундных отрезках. Если разделить это число на 10'000 — получится значение в миллисекундах.
  • lastExecTime : UDINT — количество 100нс интервалов отработанных предыдущим циклом. Не длина предыдущего цикла (эта длина для всех одинакова), а сколько реально он работал. Задача простаивала остаток времени.
  • cycleCount : UDINT — необходимый нам счетчик циклов, прошедших с момента старта ПЛК-задачи.


Новый таймер под микроскопом


Будем проводить испытания на CX9020 и 10'000 таймерах:


Все еще работает, а ведь раньше срезался на 1000 штуках. Еще раз: было 100 — стало 10'000. Проверим на CX5010, а лучше сравним TON (левая половина графика) и TONLi (правая половина):



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