March 24, 2016

Визуализации в TwinCAT 3

Третьего марта прошел вебинар на тему новых систем визуализации в третьем Твинкате. Для начала были рассмотрены три типовых сценария работы:
  1. Локальная программа-клиент (Local PLC HMI Client) работает и отображает визуализацию на том же ПЛК, где работает ПЛК-задача. Поток данных ложится в цепочку:
    ПЛК → ADS-сервер → HMI-клиент.
  2. Удаленный клиент (Remote PLC HMI Client) — программа клиент работает и рисует "картинку" на другом компьютере:
    ПЛК → ADS-сервер ~→~ Локальная и сеть или VPN ~→~ ADS-сервер → HMI-клиент.
  3. Удаленный мобильный клиент (Remote PLC HMI Web) с возможностью отображать визуализацию через веб-браузеры (акцент на использование обычных интернет-браузеров):
    ПЛК → ADS-сервер → MS IIS веб-сервер ~→~ Интернет (http/https) ~→~ Веб-браузер.
Обработчик данных ПЛК-задачи VISU_TASK работает совместно с TwinCAT-runtime в режиме ядра операционной системы (kernel mode). HMI-клиент работает в пользовательском кольце (user mode) и через ADS-cервер переправляет в VISU-TASK события мыши, клавиатуры, сенсорного экрана и пр. "телодвижения" пользователя, а от VISU-TASK получает команды на отрисовку/обновление/перерисовку интерфейса визуализации.


Начало работы


Редактор визуализаций встроен в среду разработки и доступен в дереве проекта в разделе ПЛК-задачи. Состоит из трех частей:
  1. Поле рисования (Interface Editor) состоит из трех вкладок:
    - Переменные визуализации. Это самостоятельные переменные принадлежащие задаче визуализации VISU-TASK.
    - Настройки горячих клавиш.
    - Список графических элементов на визуализации.
  2. Стандартные элементы интерфейса визуализации: кнопки, графические элементы, тренды, индикаторы и т. п.
  3. Параметры элементов очень похожие на параметры WinForms.

Visualization Manager — главный компонент проекта, отвечающий за визуализации. Он содержит различные настройки, такие как:
  • Тема или стиль отображения.
  • Язык по умолчанию (интернационализация интерфейса).
  • Управление пользователями для разграничения доступа.

Для активации локального PLC HMI или PLC Web HMI необходимо добавить соответствующие объекты в ветку Vizualization Manager. После этого автоматически создается и добавляется задача визуализации VISU_TASK.


Клиентская часть HMI


Заявлены следующие преимущества HMI-клиента:
  1. Отдельная программа в виде независимого .exe файла.
  2. Клиент работает как независимый процесс операционной системы.
  3. Клиент запускается автоматически (только при ручном добавлении в папку автостарта TwinCAT).
  4. Обмен данными только через ADS. Никакой блокировки отладочного debug-интерфейса.

Преимущества Web-клиента:
  1. Работает на веб-сервере Microsoft IIS, который встроен во все контроллеры Бекхофф.
  2. Построен на HTML5 и JavaScript.
  3. Клиент платформонезависим т. к. работает через браузер.
  4. Идеально подходит для обслуживания объектов и диагностики, в том числе удаленно (со смартфона, например).

Можно запустить несколько PLC HMI-клиентов, с синхронизацией вида на разных клиентах с разных ПК. Удаленный PLC HMI могут просматривать множество пользователей: максимальное количество зависит только от настроек размера буфера связи.


TwinCAT _PLC_ HMI — это не TwinCAT HMI


Различия между TwinCAT__PLC__HMIa и TwinCAT__HMIb:
  • (a) старая-добрая таргет-визуализация, (b) почти-скада.
  • (a) встраивается в ПЛК-проект, (b) выступает как независимый проект.
  • (a) подключен только к одному ПЛК-проекту. (b) может подключаться к множеству различных рантаймов одновременно.
  • (a) рабоатет состандартным набором элементов, в (b) можно легко добавлять новые элементы.
  • Цифровой осциллограф будет только в (b), для (a) будут доступны простые тренды.


Анонсы и слухи


Ближайший крупный билд TwinCAT 3 —  3.1.4020. В нем обещают:
  • Обновление User Management — работа с пользователями и правами доступа к страницам, контролам и т. п. Пользователи TwinCAT не связаны с пользователями операционной системы. Это отдельная подсистема прав безопасности TwinCAT.
  • Event Table — элемент интерфейса который может показывать сообщения системного журнала TcEventLog.
  • Recipe Management.
  • Trend — появится только в третьем квартале 2016 г.


Следующий вебинар пройдет 30 марта 2016 года по теме TwinCAT Интернет вещей (IoT) — быстрый и стандартизированный доступ в "облако".
Полный вебинар на английском языке TwinCAT 3 | Visualisation – from engineering to target and web

March 22, 2016

Автоматизация TwinCAT.Ads API

Удобные библиотеки Бекхофф для работы с протоколом ADS, к сожалению, работают на достаточно низком уровне. С каждым новым обновлением уровень немного повышается, но по прежнему приходится работать с функциями обмена данными, а хочется работать непосредственно с данными. Поэтому был разработан очередной бесплатный костыль на C# .NET 4.5 — библиотека AdsRemote. С открытым исходным кодом.

Внезапно, текущая версия библиотеки 0.5, т. е. родилась она не вчера и уже работает в некоторых проектах. Основные фишки AdsRemote — автоматический контроль канала связи на обрыв соединения и переподключения, а также простой способ работы с переменными ПЛК-программы и шины данных вообще. Кроме этого, библиотека умеет находить контроллеры в Ethernet-подсети и удаленно добавлять запись в AMS-роутер контроллера.

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

Для работы понадобится установленный TwinCAT 2.11 или 3.1, иначе говоря — необходим работающий AMS-роутер. Еще проще говоря — Твинкат должен быть установлен и работать. Инженерной версии вполне достаточно. Не забудьте добавить записи в таблицы роутеров.


Подключение и отключение


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

PLC plc = new PLC("5.2.100.109.1.1");


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

plc.DeviceReady += Plc_DeviceReady; // когда связь установлена или восстановлена
plc.DeviceLost += Plc_DeviceLost;   // когда связь потеряна

[...]

private void Plc_DeviceReady(object sender, AdsDevice e)
{
    Log("READY [" + e.Address.Port.ToString() + "]");
}

AdsDevice в данном случае — это ADS-устройство в составе контроллера. Именно они идентифицируются на шине по номеру порта. Если связь с контроллером прервется, мы получим столько уведомлений, сколько устройств зарегистрировано в объекте ПЛК. Соответственно, при отключении только одного устройства — придет только одно уведомление.


Работа с переменными 


Создавать устройства AdsDevice мы не можем: при добавлении новой переменной, автоматически анализируется номер порта устройства и, при необходимости, добавляется новое устройство. В принципе, разработчику можно об устройствах и портах не задумываться, а работать исключительно с переменными:

Var<short> main_count = plc.Var<short>("MAIN.count");
Var<ushort> main_state = plc.Var<ushort>("MAIN.state");
Var<ushort> frm0 = plc.Var<ushort>("Inputs.Frm0InputToggle", 27907);
Var<ushort> devState = plc.Var<ushort>(0xF030, 0x5FE, 27907);
Var<short> g_Version = plc.Var<ushort>(".VERSION");


С момента создания переменной, ее значение будет автоматически обновляться в соответствии с переменной на стороне контроллера. Переменные типа Var<T> могут спокойно участвовать в обычных арифметических операциях. За редким исключением их тип будет автоматически приведен к значимому или строковому:

long countTotal += main_count;
MessageBox.Show(main_count);


Можно подписаться на уведомления об изменении значения переменной:

main_count.ValueChanged +=
    delegate
    {
        counterStatusLabel.Text = main_count;
    };


Можно использовать единый обработчик для нескольких переменных:

main_count.ValueChanged += OnValueChanged;
main_state.ValueChanged += OnValueChanged;

protected void OnValueChanged (object src, Var v)
{
    ushort val = (ushort)v.GetValue();
    framesTotal += val / 2;
    label1.Text = val.ToString();
};


Для изменения значения переменной на стороне контроллера, необходимо обратиться к внутреннему свойству переменной — RemoteValue:

main_count.RemoteValue = 123;


Связывание группы переменных


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

public class PRG_Main
{
    [LinkedTo("MAIN.count")]
    public Var<short> count;

    [LinkedTo("MAIN.state")]
    public Var<ushort> state;
}


Более подробный вариант:

public class PRG_Main
{
    [LinkedTo("MAIN.count", As: typeof(short), Port: (int)AmsPort3.PlcRuntime1)]
    public Var count;

    [LinkedTo("MAIN.state", Port: (int)AmsPort3.PlcRuntime1)]
    public Var<ushort> state;

    [LinkedTo("Inputs.Frm0InputToggle", Port: 27907)]
    public Var<ushort> frm0_1;

    [LinkedTo(IGrp: 0xF030, IOffs: 0x5F4, Port: 27907)]
    public Var<ushort> frm0;
}

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

Для дальнейшего использования переменных в связке с WPF-контролами — необходимо объявить их как параметры:

public class PRG_Main
{
    [LinkedTo("MAIN.count")]
    public Var<short> count { get; set; }

    [LinkedTo("MAIN.state")]
    public Var<ushort> state { get; set; }
}


После задания описания, объект с данными создается и активируется одной строкой:

PRG_Main Main = plc.Class<PRG_Main>();


Если требуется вызов сложного конструктора — можно воспользоваться следующим вариантом:

Main = new PRG_Main(param1, param2, ...);
plc.Class(Main);

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

March 10, 2016

Асинхронные функции TwinCAT.Ads API

Библиотеки ADS.API поддерживают событийно-ориентированное программирование — вместо постоянного чтения значения переменной (поллинг, polling) можно подписаться на рассылку уведомлений и получать уведомление только при изменении значения переменной. Впрочем, можно составить и постоянный опрос: уведомления будут приходить через интервалы времени, заданные разработчиком.
Можно одновременно использовать механизм уведомлений и обычные синхронные операции.
Инициатива по созданию событий-уведомлений (Device Notification) принадлежит программе созданной на языке высокого уровня (в нашем случае — C#, ПК), но сам механизм уведомлений находится в роутере контроллера. Не рекомендуется создавать более 550 уведомлений для одного устройства, т. к. каждая новая подписка дополнительно нагружает контроллер. Для увеличения нагрузочной способности лучше упаковать или организовать данные в структуры и обмениваться пачками данных. Для снижения нагрузки на клиентское приложение, можно ввести ограничение на частоту возникновения уведомлений, а точнее, на промежуток между отправкой уведомлений.
Всегда приходит первое уведомление. После подписки приемник считает, что значение переменной не определено, поэтому сразу же приходит первое уведомление с актуальным значением переменной.

Использование дополнительных задач


Начнем сразу со сложного: создаем дополнительную задачу (Additional Task), оставляем порт равным 301 по умолчанию, и затем связываем переменные задачи с модулями расширения физических входов/выходов на шине EtherCAT:


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


Подписка


Переходим к программе на C#. Для подписки на события используется метод AddDeviceNotification класса TcAdsClient:

TcAdsClient client301;
int h_client301;

AdsStream adsStream;

private void MainForm_Load(object sender, EventArgs e)
{
    client301 = new TcAdsClient();
    client301.Connect("5.2.100.109.1.1", 301);

    adsStream = new AdsStream(32);
 
    try
    {
        h_client301 = clientPlc.AddDeviceNotification(
            "Task 2.Inputs.EL1018",
            adsStream, 0, sizeof(byte),
            AdsTransMode.OnChange, 100, 10000,
            null);
    }
    catch (AdsErrorException adsExc)
    {
        // LOG: adsExс.Message;
        client301.Dispose();
        client301 = null;
    }

    if (client301 != null)
    {
        client301.AdsNotification += Client301_AdsNotification;
    }
    
    [...]

В метод передается имя переменной на изменения которой мы подписываемся. Затем указывается поток входных данных AdsStream. Необходимо создать поток с буфером, размер которого достаточен для размещения значений переменной. Кроме этого, задается смещение в потоке и размер данных переменной в байтах (подробнее — ниже).

AdsTransMode определяет тип опроса переменной. На выбор предоставляется несколько вариантов, но в данный момент реализовано только два. Cyclic — задает периодический опрос значения переменной с интервалом заданным параметром cycleTime (в примере выше, это 100 миллисекунд). OnChange — уведомления приходят только при изменении значения переменной.

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

В последний параметр userData разработчик может передать какие-либо свои данные. Они будут доступны при получении уведомления.


Освобождение ресурсов


Уведомления создаются на стороне контроллера, поэтому по отношению к программе клиенту они являются внешними и соответственно неуправляемыми ресурсами (umanaged resources). По окончании работы лучше освободить их.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    if (client301 != null)
    {
        try
        {
            client301.DeleteDeviceNotification(h_client301);
        }
        catch (AdsErrorException adsExс)
        {
            // LOG: adsExс.Message;
        }
        finally
        {
            client301.Dispose();
            client301 = null;
        }
    }
    
    [...]
 
В принципе, финализаторы библиотеки самостоятельно справятся с освобождением занятого, но во избежании внезапных протечек памяти лучше сделать это самостоятельно.


Уведомления


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

private void Client301_AdsNotification(object sender, AdsNotificationEventArgs e)
{
    e.DataStream.Position = e.Offset;
    byte el1008 = (byte)e.DataStream.ReadByte();

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


Чтение данных EtherCAT-шины


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


Включенный сервер не является потребителем данных. Без задач, читающих данные с шины, вы получите спящую шину и по прежнему неработающий ADS-сервер: Device 'Device 3 (EtherCAT)' needs sync master (at least one variable linked to a task variable). Создайте хотя бы одну дополнительную задачу и слинкуйте хотя бы одну переменную.

Подписываемся аналогично, за исключением номера порта — 27907:

clientECat = new TcAdsClient();
clientECat.Connect("5.2.100.109.1.1", 27907);

h_clientECat = clientECat.AddDeviceNotification(
    "Inputs.Frm0InputToggle",
    adsStream, 1, sizeof(ushort),
    AdsTransMode.OnChange, 10, 0,
    null);


Работа со структурами


TYPE ST_DataPack :
STRUCT
    Index    : UINT;
    Name     : STRING(10);
    Speed    : REAL;
END_STRUCT
END_TYPE

PROGRAM MAIN
VAR
    Pack     : ST_DataPack := (Index := 0, Name := '', Speed := 0);
    state    : UINT;
END_VAR

CASE state OF
0: (* Инициализация *)
    Pack.Index    := 1;
    Pack.Name     := 'LightSpeed';
    Pack.Speed    := 0;

    state := 100;

100: (* Ускорение *)
    Pack.Speed := Pack.Speed + 0.1;
    Pack.Index := REAL_TO_UINT(Pack.Speed / 100);

END_CASE


На стороне клиента объявляется аналогичная структура.
В примере ниже предлагается почленное заполнение полей структуры, поэтому нет необходимости в строгой последовательности полей и применении атрибутов типа StructLayout и т. п.
Следует помнить о несоответствии размеров типов данных TwinCAT и C#, а также правильно вычислить размер буфера для потока. Для строковых переменных необходимо указывать максимальное количество символов (по умолчанию TwinCAT задает его равным 80 символам).

public struct DataPack
{
    public ushort Index;
    public string Name;
    public float Speed;
}

DataPack backpack = new DataPack();

TcAdsClient clientPlc;
int h_clientPlc;

AdsStream adsStream;

private void MainForm_Load(object sender, EventArgs e)
{
    clientPlc = new TcAdsClient();
    clientPlc.Connect("5.2.100.109.1.1", (int)AmsPort.PlcRuntime1);
    adsStream = new AdsStream(32);
 
    try
    {
        h_clientPlc = clientPlc.AddDeviceNotification(
            "MAIN.Pack",
            adsStream, 3, sizeof(ushort) + sizeof(float) + 10,
            AdsTransMode.OnChange, 100, 0,
            null);
    }
    catch (AdsErrorException adsExc)
    {
        // LOG: adsExс.Message;
        clientPlc.Dispose();
        clientPlc = null;
    }

    if (clientPlc != null)
    {
        clientPlc.AdsNotification += ClientPlc_AdsNotification;
    }

    [...]


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

private void ClientPlc_AdsNotification(object sender, AdsNotificationEventArgs e)
{
    e.DataStream.Position = e.Offset;

    var reader = new AdsBinaryReader(e.DataStream);

    backpack.Index = reader.ReadUInt16();
    backpack.Name  = new string(reader.ReadChars(10));
    backpack.Speed = reader.ReadSingle();
}


Запись структуры производится точно так же как и запись обычной переменной.

backpack.Index = 0;
backpack.Name  = "PC written";
backpack.Speed = 300000;

clientPlc.WriteSymbol("MAIN.Pack", backpack, false);

March 2, 2016

Конфигурирование AX2000-B900

Устаревшее оборудование выходит из строя, разработчик давно сгинул в лесах амазонки, а ЗИП внезапно требует первоначальной настройки. Источник адреса задается dip-переключателями #7-8.


1 2 3 4 5 6 7 8
------------------
0 0 0 0 0 0 0 1 – адрес выдается сервером (или роутером) через DHCP. Дипы #1..6 обязательно в OFF.
0 0 0 0 0 0 1 0 – адрес выдается BootP-сервером.
0 0 0 0 0 0 0 0 – адрес выдается RT-Ethernet мастером, т. е. контроллером.

Если адреса выдает RT-Ethernet-мастер и есть несколько подчиненных, то адреса выдаются последовательно, начиная с мастера, которому достается адрес 172.16.17.1, затем 172.16.17.2... 3... 4...

Также существует легенда, что дипами 1..6 можно непосредственно задать IP-адрес, но подтвердить это, пока не удалось.

February 29, 2016

Установка и запуск TwinCAT PLC HMI

Запуск визуализации TwinCAT PLC HMI для настольных операционных систем (Windows XP, Windows 7 Standard, 8, 10) может вызвать кратковременную непроходимость мозга.

TwinCAT 2: TS1800 | TwinCAT PLC HMI. Скачиваем и устанавливаем.
TwinCAT 3: TF1800 | TC3 PLC HMI. Уже идет в комплекте вместе с XAE, то есть не потребует скачивания и установки.

После включения в CE|Compact опции визуализации (через CX Configuration), среда визуализации начнет запускаться автоматически. В настольных ОС визуализация автоматически запускаться не будет. Ее автостарт необходимо настроить вручную. Это можно сделать двумя способами, но в любом случае понадобится собрать проект и "залить" его в контроллер как загрузочный (boot-project). Иначе среде визуализации нечего будет визуализировать, а нам трудно понять — получилось у нас автозапустить или еще нет.


Автозапуск


TwinCAT 2
Создаем ярлык для приложения среды визуализации  x:\TwinCAT\Plc\TCatPlcCtrlHmi.exe. В параметрах ярлыка указываем путь к .pro-файлу проекта, а затем переносим этот ярлык в меню Start → Programms → TwinCAT → Startup.

TwinCAT 3
Ссылку (ярлык) на среду визуализации x:\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\Tc3PlcHmi.exe нужно добавить/переместить/поместить в каталог x:\TwinCAT\3.1\Target\StartUp. После перезагрузки, контроллер автоматически стартует загрузочный проект и оболочку визуализации.


NT_StartProcess


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

В примере ниже не забудьте все x:\ заменить на свою букву диска, обычно это C:\

NT_StartProcess (
  NETID    :=, 
  PATHSTR  :=
    'x:\TwinCAT\Plc\TCatPlcCtrlHmi.exe x:\TwinCAT\Plc\ProjectName.pro /userlevel 1 /Password 1234 /Visu Overview',
  DIRNAME  :=
    'x:\TwinCAT\Plc\', 
  COMNDLINE:=, 
  START    := TRUE, 
  TMOUT    := T#2S, 
  BUSY     =>, 
  ERR      =>, 
  ERRID    =>);

Дополнительные параметры:
  • /openfromplc — при старте, визуализация выводит окно диалога и предлагает выбрать рантайм контроллера. После выбора, забирает с рантайма исходный код программы, компилирует его и запускает. Если исходный код не был выгружен разработчиком в контроллер — будет "ой".
  • /nofullscreenmode — запускать визуализацию в окне, а не во весь экран.
  • /noaltf4 — не реагировать на Alt+F4.
  • /userlevel — уровень пользователя по умолчанию для встроенной функции безопасности.
  • /password — пароль пользователя  для встроенной функции безопасности.
  • /visu — название окна визуализации которое отобразится первым. По умолчанию, это по прежнему TC_VISU.

Для TwinCAT 3 можно запустить оболочку визуализации с помощью такого же функционального блока из библиотеки Tc2_Utilities (System):

NT_StartProcess ( 
  NETID    :=, 
  PATHSTR  := 'x:\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\Tc3PlcHmi.exe', 
  DIRNAME  := 'x:\TwinCAT\3.1\Components\Plc\Tc3PlcHmi\', 
  COMNDLINE:=, 
  START    := TRUE, 
  TMOUT    := T#2S, 
  BUSY     =>, 
  ERR      =>, 
  ERRID    =>);

После этого начинается самое интересное: настройки оболочки визуализации хранятся в файле Tc3PlcHmi.ini который лежит рядом к исполняемым файлом оболочки Tc3PlcHmi.exe. В случае с TwinCAT 3 оболочку визуализации можно запустить не только на том же контроллере/компьютере, где работает рантайм TwinCAT, но и на любом другом, лишь бы была связь и добавлены все необходимые записи в ADS-роутер.
UPD (18 сент. 2020): Начиная с версии TwinCAT 3.1.4022.0 файл настроек Tc3PlcHmi.ini должен находится в каталоге C:\TwinCAT\3.1\Boot\Plc. Спасибо Андрею П. за уточнение.
Можно запустить несколько оболочек на различных машинах объединенных сетью. Визуализация будет полноценно работать и отображать единую картинку на всех точках запуска. При этом сохраняется возможность отладки ПЛК-программы, что было невозможно в TwinCAT 2 при запуске визуализации в настольных операционках. Подробнее в справочной системе TF1800 TC3 PLC HMI.


Runtime already in use!


Ошибка относится к TwinCAT 2 и это именно тот случай, почему не удобно использовать PLC HMI визуализацию в настольных операционках.

Похоже, что в TwinCAT 2 среда визуализации изготовлена из среды разработки PLC Control путем выкидывания лишних элементов интерфейса. При этом визуализация подключается к рантайму через интерфейс отладки программы (debug runtime), блокируя любые другие попытки подключения. Занято! Вы не можете отлаживать свою программу, потому что запущена визуализация! Идите к черту, говорит нам визуализация: "Я одна, а вас много".

Чтобы получить отладку ПЛК-программы, придется разбить ее на две части: загружать технологический цикл в один рантайм, а визуализацию в другой. Иначе неминуема ошибка: Runtime already in use!

Именно в этом гигантское преимущество TwinCAT 3 PLC HMI. Ну, и еще таблицы с произвольными данными, новые тренды, выпадающие списки и куча других приятных плюшек.


Обновлено: 18 сентября 2020 г.

February 25, 2016

Сервер Modbus TCP

Протокол Modbus поддерживается практически всеми производителями и реализован на многих устройствах. В TwinCAT он существует в виде модбас-сервера как для десктопа, так и для компактной Windows CE:

TS6250 | TwinCAT Modbus TCP Server
TS6250-0030 | TwinCAT Modbus TCP Server CE
В 8000 серии модбас-сервер уже встроен, но про 8000 серию мы разговаривать не будем, так как она мне не нравится.
Итак, чтобы установить — прочтите руководство по установке. Там все просто и подходит для всех видов операционок.

После установки получаем сервер и библиотеку с функциональными блоками. Библиотека позволяет использовать произвольные функции Modbus, работать в роли клиента или использовать UDP-протокол вместо скучного и надежного TCP.

Для передачи данных чаще используют заранее подготовленные глобальные переменные или области памяти, но если очень хочется, то порт и прочие настройки можно переназначить в файле настроек — TcModbusSrv.xml. Там же можно переназначить порты ADS и адреса смещений. В операционной системы CE | Compact файл должен лежать в \hard disk\system. Если его там нет — значит сервер настроен по умолчанию. Работа с файлом конфигурации описана в Mapping between Modbus and ADS.

Для настольных операционных систем существует готовый конфигуратор, после установки лежащий в x:\TwinCAT\TcModbusSrv.


Тонкая настройка сервера


Все начинается с <Configuration>. По умолчанию, как это принято в сетях Модбас, коммуникационный сетевой порт равен 502:

<!-- Modbus TCP port, default = 502-->
<Port>502</Port>

Далее идет раздел маппинга: <Mapping>, в котором задается отражение адресного пространства Modbus на адресное пространство операционного образа ПЛК или, проще говоря, к каким областям памяти контроллера приведут заданные адреса Modbus.

Начинаем конфигурировать дискретные входа (биты дискретных входов только для чтения): <InputCoils>. Если вы внезапно забыли о функциях Modbus — кратко ознакомьтесь с обзорной статьей: она короткая и надолго вас не задержит.

Задаем стартовый адрес пространства Modbus: <StartAddress>0</StartAddress>
...и конечный адрес: <EndAddress>32767</EndAddress>

Остается настроить место, куда эти адреса приведут на стороне контроллера. ADS-порт выбирает устройство на шине EtherCAT. 801 — это стандартный порт первого рантайма ПЛК-задачи:

<!-- AdsPort: TwinCAT2 PLC1 = 801, PLC2 = 811...-->
<AdsPort>801</AdsPort>


Затем идет индекс группы и смещения. Они конкретизируют переменные, области памяти и пр.:

<!-- IndexGroup 61473 = 0xF021 -> physical plc inputs %IX -->
<IndexGroup>61473</IndexGroup>
<!-- Bit offset-->
<IndexOffset>0</IndexOffset>


Большего быстродействия можно добиться, указывая индекс группы и смещения, как это сделано выше, но для удобства можно просто задать имя переменной:

<MappingInfo>
<AdsPort>801</AdsPort>

<!-- Modbus input coils -->
<StartAddress>32768</StartAddress>
<EndAddress>33023</EndAddress>

<VarName>.mb_Input_Coils</VarName>

</MappingInfo>
</InputCoils>

Обычно приводят простой пример в котором описывают мапинг переменных ПЛК-программы, но мы заглянем глубже — как сделать мапинг непосредственно ADS-шины. Для начала, необходимо включить ADS-сервер шины и задать номер порта (обычно 27907 для TwinCAT 2, но можно и другой):
TwinCAT 2: I/O - Configuration → I/O Devices → Device 1 (EtherCAT) → Device 1-Image → ADS → Enable ADS Server.
TwinCAT 3: I/O → Devices → Device 1 (EtherCAT) → Image → ADS → Enable ADS Server.

Номер функции Modbus как бы выбирает индекс группы (Index Group), тогда как адрес Modbus задает смещение области памяти, на которую отображаются переменные, а точнее часть операционного образа. Получается, что с помощью настроечного файла XML можно отразить не только образ данных ПЛК-задачи, но и любой другой образ. Например, образ области памяти данных EtherCAT-шины, что нам и требуется.

<MappingInfo>
<AdsPort>27907</AdsPort>

<!-- Modbus input coils -->
<StartAddress>32768</StartAddress>
<EndAddress>33023</EndAddress>

<VarName>Inputs.Frm0InputToggle</VarName>

February 9, 2016

Имя контроллера

Откуда по умолчанию берется имя контроллера?

Из обозначения серии (C, CX, P, ...) и последних шести символов MAC-адреса: CX_02646D.
MAC-адрес контроллера CX можно подсмотреть на шильде-наклейке (MAC-ID 1):


February 4, 2016

Простые функции ADS.API

В ADS.API существуют две функции, которые позволяют читать/писать данные с контроллера буквально одной строкой: ReadSymbol и WriteSymbol. Эти функции сильно упрощают разработку на языках высокого уровня. Как обычно, далее про C#.

Разработка ADS.API двигается по пути упрощения интерфейса библиотеки: от работы с потоками через индексы и смещения (AdsStream), к работе с произвольными типами данных в виде именованных переменных (Read|WriteAny). Имена переменных ПЛК-задачи удобнее, чем абстрактные потоки байт, но по-прежнему необходимо преобразовывать имена в дескрипторы и только затем работать с ними. Напрашивается сделать следующий шаг на пути сокращения.

Symbol в TwinCAT-системе — это описание переменной и вся возможная информация о ней, т. е. что-то очень похожее на отражения или рефлексию в языках высокого уровня. Вообще, работа с переменными в библиотеке ADS.API построена не самым лучшим образом. Если есть желание взглянуть на то, каким оно должно быть или стать в будущем — лучше взгляните на независимый проект adsclient на гитхабе. Когда понравится — перечитайте про преимущество другой стороны ADS.

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

using (TcAdsClient client = new TcAdsClient())
{
    client.Connect("192.168.1.17.1.1", 801);
    
    client.WriteSymbol("MAIN.uint16", (ushort)123, false);
    
    bool    m_bool1   = (bool)   client.ReadSymbol( "MAIN.bool1",   typeof(bool),   false);
    byte    m_byte8   = (byte)   client.ReadSymbol( "MAIN.byte8",   typeof(byte),   false);
    short   m_int16   = (short)  client.ReadSymbol( "MAIN.int16",   typeof(short),  false);
    ushort  m_uint16  = (ushort) client.ReadSymbol( "MAIN.uint16",  typeof(ushort), false);
    ushort  m_word16  = (ushort) client.ReadSymbol( "MAIN.word16",  typeof(ushort), false);
    float   m_real4b  = (float)  client.ReadSymbol( "MAIN.real4b",  typeof(float),  false);
    double  m_lreal8b = (double) client.ReadSymbol( "MAIN.lreal8b", typeof(double), false);
}


Аналогично для "системных" типов данных:

client.WriteSymbol("MAIN.word16", (UInt16)456, false);

Int16  s_int16   = (Int16)  client.ReadSymbol( "MAIN.int16",   typeof(Int16),  false);
UInt16 s_uint16  = (UInt16) client.ReadSymbol( "MAIN.uint16",  typeof(UInt16), false);
UInt16 s_word16  = (UInt16) client.ReadSymbol( "MAIN.word16",  typeof(UInt16), false);
Single s_real4b  = (Single) client.ReadSymbol( "MAIN.real4b",  typeof(Single), false);
Double s_lreal8b = (Double) client.ReadSymbol( "MAIN.lreal8b", typeof(Double), false);


Обратная разработка


Упрощения не даются просто так и где-то что-то приходится приносить в жертву. Простые в использовании функции могут работать как-то не так или просто "тормозить". Заглянем во внутренности библиотеки, а конкретнее — в TcAdsClient. С небольшими сокращениями функции выглядят так:

public object ReadSymbol(string name, Type type, bool reloadSymbolInfo)
{
    [...]

    if (this._symbolInfoTable == null)
        this._symbolInfoTable = new SymbolInfoTable(this);

    return this._symbolInfoTable.ReadSymbol(name, type, reloadSymbolInfo);
}


public void WriteSymbol(string name, object value, bool reloadSymbolInfo)
{
    [...]

    if (this._symbolInfoTable == null)
        this._symbolInfoTable = new SymbolInfoTable(this);

    this._symbolInfoTable.WriteSymbol(name, value, reloadSymbolInfo);
}

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

namespace TwinCAT.Ads.Internal
{
    internal class SymbolInfoTable
    {
        private Dictionary<string, TcAdsSymbol> _symbolTable;
        private DatatypeInfoTable _datatypeTable;
        private TcAdsClient _adsClient;
        
        public SymbolInfoTable(TcAdsClient adsClient)
        {
            this._adsClient = adsClient;
            this._symbolTable = new Dictionary<string, TcAdsSymbol>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
            this._datatypeTable = new DatatypeInfoTable(adsClient);
        }

И да, действительно, это обертки для кеширования информации о переменных: словарь имен и таблиц символов, коллекция типов данных и обратная ссылка на владельца — класс AdsClient. Делаем вывод — данная таблица создается при первом вызове одной из функций ads-клиента и хранит информацию о переменных, что сокращает время и количество операций при работе с переменными ПЛК-задачи.


Третий параметр


Вернемся к "reloadSymbolInfo", третьему параметру функций Read|WriteSymbol. Он позволяет сбросить, стереть кешированную символьную информацию, накопленную в таблицах объекта класса SymbolInfoTable. Это хорошо видно в реализации методов класса (в начале каждого метода параметр проверяется и если требуется — таблица очищается):

public void WriteSymbol(string name, object value, bool bReloadInfo)
{
    if (bReloadInfo)
        this.Cleanup();
    [...]


public object ReadSymbol(string name, Type type, bool bReloadInfo)
{
    if (bReloadInfo)
        this.Cleanup();
    [...]

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


Передача данных


Осталось выяснить как передаются данные. Продолжаем рассматривать методы Read|WriteSymbol класса SymbolInfoTable, пропускаем сброс таблиц (3):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public void WriteSymbol(string name, object value, bool bReloadInfo)
{
    [...]
    TcAdsSymbol symbol = this.GetSymbol(name, true);
    if (symbol == null)
        TcAdsDllWrapper.ThrowAdsException(AdsErrorCode.DeviceSymbolNotFound);

    TcAdsDatatype dataype = this._datatypeTable.GetDataype(symbol.Type);
    if (dataype == null)
        throw new NotSupportedException("Type of symbol not supported");

    AdsStream stream = new AdsStream((int) dataype.size);
    AdsBinaryWriter writer = new AdsBinaryWriter(stream);

    if (dataype.IsPrimitive)
        this.SetPrimitiveType(symbol.Name, value, dataype.managedType, symbol.Datatype, symbol.Size, writer);

В строках 4-6 идет выборка кешированной информации, затем (строки 8-10) выборка типов переменных и наконец подготовка потоков (строки 12-13, AdsStream, AdsBinaryWriter). Никакой магии.

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


Выводы:
  • Символьная информация кешируется, а дескрипторы создаются и уничтожаются незаметно для разработчика.
  • Если что-то случится, таблицы можно сбросить.
  • Передача данных по-прежнему ведется через потоки, т. е. быстро.
  • Функции удобны, просты и нужно использовать.

February 2, 2016

Что такое TwinCAT?

Часто встречающийся вопрос: «Я прочитал про вас в …, но я так и не понял… что такое TwinCAT? Что нужно… могу ли я… а можно вместо этого… сколько стоит…». Далее краткое введение в оборудование Бекхофф и систему TwinCAT.


Компактные контроллеры


Компактные контроллеры (Embedded PC, серия «CX») – это полноценные персональные компьютеры с операционной системой Windows, но в компактном корпусе и с возможностью установить на дин-рейку.

Операционная система предустанавливается на заводе-изготовителе. Это может быть как обычная, десктоп версия Windows Embedded XP, Standard 7, так и компактная версия Windows CE 5, 6, Compact 7.

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

Какую ОС выбрать? Если вам не требуются возможности десктоп Windows (XP, 7, Standart и т. п.) – выбирайте Windows CE (Compact): по крайней мере она быстрее загружается.

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

Несмотря на свою компактность, эти контроллеры – полноценные персональные компьютеры, вплоть до ПК с многоядерными процессорами класса Intel Core-i7. Аналогично персональному ПК на них можно запустить базу данных, Word, Excel, интернет-браузер, воспроизведение мультимедиа и одновременно использовать возможности промышленного контроллера.


Промышленные ПК


Промышленные ПК (Industrial PC, серия «C») – полноценные персональные компьютеры в промышленном исполнении. Могут быть как совмещены с графической сенсорной панелью (Panel PC), так и выполнены отдельно, в виде небольшого блока "кирпича" (Control cabinet Industrial PC).

«Panel PC» могут быть как встраиваемые – «built-in Panel PC», так и на штанге - «Panel PC with mounting arm».

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


Графические сенсорные панели


Серия «CP» (Control Panel). По сути, представляют собой обычные мониторы в промышленном исполнении с сенсорным мультитач-управлением. Подключаются к контроллеру через DVI- и USB интерфейсы.

Специальные накладки с дополнительными кнопками, сенсорными трекпадами, USВ-разъемами и пр., позволяют организовать специализированный пульт управления. Например, для управления ЧПУ-станком.

Для увеличения расстояния "панель" – контроллер существуют специальные конвертеры-преобразователи. Специальный программный пакет CP-Link позволяет размножать изображение или строить различные системы вида «много дисплеев – один контроллер».


Модули расширения


Серии «EL», «ES». Модули (EtherCAT Terminal) ввода/вывода сигналов в/из контроллер. Серия «ES» имеет съемную верхнюю панель для удобства монтажа, но увеличивается количество контактных сопряжений.

Кроме модулей перечисленных в статье Физические интерфейсы и модули расширения, существуют специальные защищенные модули для ввода/вывода в полевых условиях (Fieldbus box, серии «EP», «EQ» - сталь, «ER» - цинк-анодированные).


Коплеры


Коплеры (серия «EK») предназначены для упаковки модулей расширения в точки сбора сигналов с последующим объединением коплеров в единую шину. Коплеры могут находиться друг от друга на значительном расстоянии и как следствие позволяют значительно увеличить длину шины.


Сервоусилители


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

Для подбора комплектации обратитесь в региональную тех. поддержку (см. Disclaimer в подвале блога).


Что такое TwinCAT


TwinCAT – Total Windows Control and Automation Technology (англ.). Технология автоматизации и управления для операционной системы Microsoft Windows. Программно-аппаратный комплекс — набор технических и программных средств, работающих совместно для выполнения одной или нескольких сходных задач автоматизации.

TwinCAT работает только под операционной системой Microsoft Windows (XP, 7, 8, 8.1, 10). Непосредственный запуск TwinCAT из-под Linux, Unix, MacOS – невозможен, но можно запустить из виртуальной машины, не забывая что комплекс программно-аппаратный, т. е. существуют определенные аппаратные требования.


Зачем нужен TwinCAT


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

Как итог, разработчик и пользователь получают два устройства в одном: на одном и том же персональном компьютере могут одновременно работать как обычные программы (Word, Excel, Photoshop), так и программы, управляющие технологическим процессом. Еще проще: компьютер один, но благодаря TwinCAT одновременно получается персональный компьютер + промышленный контроллер.

Верно и обратное – промышленный контроллер с TwinCAT на борту, может работать как обычный персональный компьютер, выполняя те же самые действия и программы.

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

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

Удаляется TwinCAT точно также как и другие программы.

Чтобы ПК под управлением Windows мог стать полноценным промышленным контроллер, необходим райнтайм (runtime) – среда реального времени для выполнения программ технологического процесса. Рантайм – одна из основных частей Твинката.


TwinCAT 2


Твинкат бывает TwinCAT 2 и TwinCAT 3 (TwinCAT 3.1 – это то же самое, что Твинкат 3, только новее). Видимо когда-то существовал TwinCAT 1, но про него уже забыли.

Как ни странно, Твинкат 3 не лучше чем Твинкат 2, а второй не лучше, чем третий.
UPD август 2018: TwinCAT 3 лучше, чем TwinCAT 2. Третий твинкат более стабильный и более предсказуемый, меньше ест ресурсов и вообще лучше ими распоряжается.

Второй более стабильный, «отполированный», выдержанный и проверенный временем, о нем больше информации. В третьем больше интересных и полезных возможностей, удобнее и более открытая среда разработки (Microsoft Visual Studio).

В начале 2016 года мы все еще активно используем вторую версию, т. к. в третьей не все готово. UPD: в середине 2018 года мы все больше ругаемся на заморочки TwinCAT 2 и упорно пытаемся переползти на третью версию.

Рантайм второго Твинката работает только под 32-х разрядными операционными системами. Поэтому существует две версии второго Твинката: инженерная и полная.

Полная версия содержит конфигуратор контроллера (System Manager), среду разработки программ контроллера (PLC Control) и рантайм TwinCAT. Эта версия позволяет не только конфигурировать и разрабатывать, но и сделать из ПК разработчика полноценный промышленный контроллер. При условии, что устанавливается на 32-х разрядную версию Windows.

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

Инженерная версия (x64 Engineering) позволяет конфигурировать контроллер и разрабатывать программы. Она полностью бесплатна. Эта версия предназначена для 64-х разрядных версий Windows. Не имеет смысла устанавливать эту версию на контроллер. Она целиком и полностью предназначена для установки на компьютер (ноутбук) разработчика, инженера, программиста, наладчика.


TwinCAT 3

  • Единая среда разработки и конфигурирования. Встраивается в Microsoft Visual Studio. Если Visual Studio не установлена, то устанавливается оболочка Visual Studio 2010.
  • Рантайм может работать как в 32-х разрядных, так и в 64-х разрядных системах.
  • Полная версия называется «eXtended Automation Engineering (XAE)». Версия, где есть только рантайм, без среды разработчика называется «eXtended Automation Runtime (XAR)».
  • Система автоматически предложит 7-ми дневный демо-режим, если у вас не хватает каких-либо лицензий. Затем еще 7 дней, и еще, но каждый раз необходимо вводить капчу.
  • Наконец-то появились уровни производительности контроллеров. Стало легче выбирать контроллер под классы задач.


Установка TwinCAT


Компактные контроллеры серии «CX» продаются с предустановленной операционной системой и TwinCAT выбранных вами версий. Поэтому необходимо очень внимательно формировать заказной номер контроллера.

Для промышленных (серия «C») и персональных ПК существует вероятность самостоятельной установки операционной системы, драйверов и TwinCAT.

TwinCAT можно бесплатно загрузить с веб-сайта: http://beckhoff.com/english/download/default.htm

TwinCAT 3 установится полностью автоматически, а для TwinCAT 2 необходимо выполнить несколько дополнительных действий, перечисленных ниже.

Если в процессе установки TwinCAT 2 запросит серийный номер - оставьте поле ввода пустым для установки в 30-ти дневном демо-режиме.

Уровни функционала TwinCAT 2:
  • TwinCAT CP – драйверы для панели управления Windows. 
  • TwinCAT IO – установить драйверы системы ввода/вывода TwinCAT. Для разработчиков использующих протокол ADS. 
  • TwinCAT PLC – полноценная система с возможностью конфигурирования, программирования, а также использования локальной системы как ПЛК. 
  • TwinCAT NC PTP – PLC + цифровое управление движением приводов. 
  • TwinCAT NC I – PLC + NC PTP + система ЧПУ для трехосевых станков. 

Дополнительные функции:
  • TwinCAT IO – поддержка ввода/вывода протокола ADS для различных языков программирования. 
  • TwinCAT Scope View – цифровой осциллограф. 
  • TwinCAT Cam Server – расширенный сервер движения по заданной траектории (кулачковые механизмы). 
  • TwinCAT EDS, GSD Files – файлы словарей для экспорта в другие системы. 
  • TwinCAT Remote Manager – одновременная поддержка нескольких версий TwinCAT на одной локальной системе. 
  • TwinCAT Drive Manager – конфигурирование и работа с сервоусилителями и моторами. 
  • TwinCAT BACnet/IP – поддержка протокола BACnet/IP. 

January 13, 2016

Android на компактных контроллерах CX

В отличие от младших контроллеров CX9020, в старших ‒ загрузчик располагается непосредственно на флеш-диске. Это относится как к серии CX20x0, так и к CX5xxx. Такое расположение загрузчика позволяет загрузить произвольную операционную систему. Раз контроллеры компактные, то мобильные. Продолжая следовать блонд-логике, будем ставить Android-x86 и делать скриншоты камерофоном.

Вставляем USB-флешку с образом и перезагружаем контроллер. На встроенном дисплее горит надпись "Booting OS..."



На внешнем сенсорном дисплее (подключенном через DVI-выход) появляются сообщения загрузчика



А вот и андроид...



Могла быть Убунта, но не в этот раз. Выбираем язык интерфейса. Для этого пришлось подключить мышь и клавиатуру:



Сенсорный экран, даже после калибровки, работает некорректно, но все равно предлагает чувствовать себя "как дома"



Запускаем Энгри Бердс...



Контроллер CX5010 проявил себя аналогично ‒ систему загрузил (правда, очень сильно тормозил).