Полезные советы — различия между версиями

Материал из WebHMI Wiki
Перейти к: навигация, поиск
(Формирование суточных, недельных и т.п. отчетов)
(Формирование суточных, недельных и т.п. отчетов)
Строка 182: Строка 182:
  
 
Результатом будет являться отчет такого вида:<br>
 
Результатом будет являться отчет такого вида:<br>
[[Файл:Rep example.png | 800 px]]
+
[[Файл:Rep example.png | 800 px]]<br>
 
При поминутной регистрации данные результаты получаться, если время скана будет меньше чем секунда. Тогда "виртуальный" электросчетчик не пропустит своих секунд.
 
При поминутной регистрации данные результаты получаться, если время скана будет меньше чем секунда. Тогда "виртуальный" электросчетчик не пропустит своих секунд.

Версия 15:24, 18 ноября 2016

Запуск скрипта по фронта или срезу дискретного сигнала

Скрипт нужно вызываеть по изменению регистра. Внутри скрипта нужно сделать проверку текущего состояния этого регистра и выполнять соответветсующие действия либо по фронту (текущее состояние =1), либо по срезу (=0). Пример скрипта:

Rising edge.png

Создание переключателя

Элемент слайдер можно использовать для управления типа открыть- закрыть, вкл.-выкл. и т.п. Для этого нужно "привязать" его к битовому регистру и указать опцию "user can change value" на дешборде. Также такой слайдер наглядно может отобразить положение переключателя (ручн. - акт., местное - дистанционное управение), заслонки , шибера и т.д.

Реализация таймера - задержки включения (TON)

Таймер TON начинает отчет пока вход = 1, по истечении времени задержки выход тоже устанавливается в "1".

TIMER_DELAY = 20; -- задержка таймера 20 сек. 
tmr = false; -- начальное состояние - отсчет времени не идет  
tmrStartTime = 0; -- время начала работы таймера 
-- 
function main (userId)
  -- переменные 
  local in_value = (GetReg(212) == 1); -- Просто бит (D301@WebHMI)
  local now = GetReg(28); -- Текущее время (T0@WebHMI)
-- ПРОВЕРЯЕМ УСЛОВИЕ - СОСТОЯНИЕ ВХОДА ----------
if in_value then
    if not tmr then
        tmr = true;
        tmrStartTime = now; -- запомнить время начала отсчета
    else 
        if ( now - tmrStartTime ) > TIMER_DELAY then 
            -- действие по истечении таймера 
            WriteReg("TON_out", 1); -- сигнал таймера , битовый регистр с псевдонимом "TON_out"
        end
    end    
else 
tmr = false;
tmrStartTime = 0;
WriteReg("TON_out", 0); -- сигнал таймера 
end
-- КОНЕЦ  
end

Звуковая (релейная) сигнализация об ошибках связи

В WebHMI имеются buzzer для подачи звукового сигнала, и выходные реле 2 шт. , которыми можно управлять для сигнализации (выдать на сигнальную колонну либо в ПЛК сигнал о проблеме). Алгоритм подачи сигнализации может быть такой:

  • анализировать регистр С0 (внутренний регистр - см. описание здесь ) на неравенство 0 в течении заданного интервала , например 30 секунд, используя таймер - скрипт lua.
  • после установки сигнала от таймера, можно выдавать сигналы на встроенный динамик через регистр B0, либо включать реле через внутр. регистры DO0,DO1, отправить смс или сообщение в messenger telegram .

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

Пример реализации ПИД регулятора в WebHMI:

-- глобальные переменные, сохраняются между вызовами скрипта
Kp = 1; -- пропорциональная составляющая
Ti = 0.9; -- инт. составляющая
Td = 1;  -- дифф. составляющая
SampleTime = 10 ; -- время цикла ПИД
TimeStamp = 0; -- метка для запоминания времения последнего вызова
Limit = 100; -- ограничение выхода регулятора
Int_sum = 0; -- интегральный накопитель
--
function main (userId)
  -- локальные переменные 
  local now = GetReg("SysTime"); -- Время 
  local PV = GetReg("PID_PV"); -- PV (D14@Тест) обратная связь 
  local Sp = GetReg("PID_Sp"); -- Sp (D10@Тест) задание 
  local prevErr = 0.0; -- предыдущая ошибка для вычисления дифф. составляющей
--
  if (TimeStamp == 0) then 
        TimeStamp = now; -- запомнить время входа в цикл
        --
        local  Err =  PV - Sp; -- вычисляем ошибку 
        local dErr = Err - prevErr; -- вычисляем производную ошибки 
            -- проверяем интегральное насыщение 
        local iSum_Limit = Limit * Ti / (Kp);
        if (Int_sum <= iSum_Limit) and (Int_sum >= 0.0) then
            Int_sum = Int_sum + Err; -- накапливаем интеграл ошибки 
        elseif Int_sum < 0 then
            Int_sum = 0;
        else
            Int_sum = iSum_Limit; -- ограничиваем интегральную составляющую
        end;
        -- ПИД - регулятор 
        G = Kp * (Err + (1/Ti)*Int_sum + Td*dErr);
        -- проверка выхода за диапазон 
        if G < 0 then
            G = 0;    
        end
        if G > Limit then
            G = Limit;
        end
        prevErr = Err; -- запомнить предыдущую ошибку для след. скана
        WriteReg("PID_out", G); -- Выход ПИД (D0@Тест) записать в регистр
  else
      if (now - TimeStamp > SampleTime ) then -- проверка начала цикла работы 
          TimeStamp = 0; 
      end 
  end
end

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

Счетчик моточасов

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

Пример реализации счетчика моточасов на Lua в WebHMI (программа выполняется в каждом скане):

-- глобальные переменные, сохраняются между вызовами скрипта
run_state = false; -- для запоминания текущего состояния 
function main (userId)
  -- локальные переменные 
  local check_mask = tonumber("0000100000000000",2); -- маска для проверки бита вращения в частотном приводе FC 51 Danfoss
  local run_status = (bit.band(GetReg(109),check_mask) ~= 0); -- результат проверка как переменная типа bool 
  local now = os.time(); -- текущее время системы 
  local time_diff = 0; -- разница во времени между текущим временем и временем последнего вызова

  -- ловим фронт события включения механизма для инициализации
  if (not run_state) and run_status then 
      WriteReg("P43StartTime", now); -- Время старта привода №П43

  -- считаем время 
 if run_state then 
     time_diff = (now - GetReg("P43StartTime")); -- посчитать разницу времени
     WriteReg("P43RunTime", GetReg("P43RunTime")+time_diff); -- увеличить счетчик моточасов
     WriteReg("P43StartTime", now); -- переписать начальную точку времени 
 end 
 run_state = run_status; 
end

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

Формирование суточных, недельных и т.п. отчетов

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

Необходимые переменные, скрипты и события -
  • скрипт, выдающий номер дня, месяца, недели, квартала и т.п. из системного времени во внутренний регистр "день недели", "час", "секунда"
  • скрипт подсчета разницы "текущие показание - предыдущие", и фиксации результата в регистре "счетчик" (скрипт работает также по изменению регистра "минута")
  • регистр-флаг генерации события, однократного, достаточного для записи текущего посчитанного счетчика и метки времени
  • скрипт, снимающий флаг, когда есть событие (т.е. данные уже зафиксированы)'
  • событие для регистрации

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

function main (userId)
  -- получить номер минуты
  local min = os.date("%M",os.time());
  -- записать во внутренний регистр
  WriteReg("minute", min); -- Минуты  (D24@Internal register)
end

Скрипт, работающий на изменение регистра "minute":

function main (userId)
  
  local current = GetReg(57); -- текущие показания
  local prevHour = GetReg("pHourTotal"); -- предыдущее значение 
  local cnt = current - prevHour; -- посчитать разницу
  
  WriteReg(59, cnt); -- записать счетчик во внутр. регистр. с ID = 59, он используется в событии
  WriteReg("pHourTotal", current); -- записать текущее в предыдущее для след. периода
  WriteReg(56, os.time()-30); -- Метка времени для привязки записи отчета к факт. минуте  (D29@Internal register)
   -- поднять флаг для отчета 
  WriteReg("minuteFlag", 1); -- Установить флаг для события  (D102@Тех Регистры)
  end

Скрипт, снимающий флаг и соответственно событие после записи:

function main (userId)
  -- проверяем выполняется ли событие 
  local event_state = (GetReg("ES1reg") == 1); -- Событие 1 выполняется  (ES1@Internal register)
  -- и сбрасываем флаг
  if event_state then 
      WriteReg("minuteFlag", 0); -- Флаг минутного отчета  (D20@Internal register)
  end 
end

Настройки события для данного отчета:
Rep example2.png
Rep example3.png


Результатом будет являться отчет такого вида:
Rep example.png
При поминутной регистрации данные результаты получаться, если время скана будет меньше чем секунда. Тогда "виртуальный" электросчетчик не пропустит своих секунд.