вторник, 31 января 2017 г.

Функціональний каркас для розробки програм для програмованих контролерів IEC 61131

Сьогодні допилив чорнову версію опису каркасу для ПЛК. Сам каркас (в першій робочій редакції) доробив ще на початку року для Unity PRO + Zenon. Крім того він ліг в основу з певними змінами в новий проект на TIA13. Деякі зміни були принциповими, але я їх не запам'ятав. Щоб не забути все інше вирішив добити хоча б якусь чорнову версію, бо не знаю коли наступного разу до нього доберуся.
Посилання та короткий опис тут http://asu.in.ua/viewtopic.php?f=7&t=1755
Ідея каркасу вже вітає давно, та і вона не нова. Тим не менше, реальні роботи почалися з замовлення "Саутком", яке я так і не доробив з причин "нахватався робіт більше, ніж міг виконати". Сподіваюся, що я їх не підвів, принаймні вони нічого з цього приводу не казали. Їм треба було дещо інше, але дуже близько до цього.
У той же час розробка програм для ГРС потребувала багато функціональності стосовно сервісних функцій. З кожною функцією шанхай ріс, і розробка каркасу для передбачення усіх можливих типових функцій - це була нагайна потреба. Плинний каркас добре ліг з однієї платформи (Юніті) на іншу (ТІА), практично копіпастом. Це суперперрезультат, враховуючи що реальної серйозної перевірки юнітьовський каркас не проходив. Головне не код, а ідеологія. Ті речі, за які переживав, що щось не врахував - практично усі заробили. Так, були ньюанси, але вони не порушують загальної працездатності основних приницпів.
 Оба базові рівні "канали" і "змінні" запрацювали. Рівень виконавчих механізмів сильно відрізнявся від демо-проекту (бачки) і реального (ГРС). У останньому використовуються крани, які в наших переробних процесах практично відсутні. Тому ці крани прийшлося допилювати серйозно в ТІАшному проекті. Вилізла необхідність додаткової змінної керування краном CMDPRG яка паралельно йде з CMDHMI, оскільки постійне забивання одного і того ж CMD з  програми не давало шансів ЛМІ-шному. Це характерно тільки для обєктів цього левела та вище.
Далі планую, як тільки з'явиться трохи часу (хоча він, собака, вже років десять не з'являється) описати каркас в ппт та і можливо зняти якесь відео. У будь якому випадку, буду намагатися зробити його нашим (кафедральним) корпоративним стандартом. Потрібно перетворювати написання базового рівня програм в трудовий процес а не експерементально-творчий. Тоді можна буде братися за велику об'єкти. Маю на це сподівання.          

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

Побував на I-й Всеукраїнській конференції «Цифрові комунікації у глобальному просторі. Змішана освіта».



Сьогодні був на I-й Всеукраїнській конференції «Цифрові комунікації у глобальному просторі. Змішана освіта». Програма з пошти:


Програма конференції:
10.00 – 11.00 – Зустріч гостей, реєстрація учасників
11.00 – 12.45 – Проведення першого пленарного засідання
• Співзасновник платформи масових відкритих онлайн-курсів «Prometheus» Іван Примаченко - Технологічна реформа навчання проти «трикутника смерті» української освіти
• Кандидат наук із соціальних комунікацій, доцент кафедри видавничої справи та редагування КПІ ім. І. Сікорського Радміла Сегол - Пілотний проект впровадження змішаного навчання: Досвід КПІ ім. І. Сікорського
• Кандидат технічних наук, доцент кафедри конструювання електронно-обчислювальної апаратури КПІ ім. І. Сікорського Євген Короткий - Досвід впровадження змішаного навчання в умовах скорочення аудиторного навантаження
12.45 – 13.30 – Кава-брейк
13.30 – 18.00 – Проведення другого пленарного засідання
• Кандидат юридичних наук, виконавчий директор Міждисциплінарного науково-освітнього центру протидії корупції в Україні НаУКМА Оксана Несторенко - Поєднання класичних та онлайн форм навчання в сфері протидії корупції
• Кандидат технічних наук, асистент кафедри комп’ютеризованих систем автоматики Національного університету «Львівська політехніка», Solution Architect компанії SoftServe Зеновій Верес - Використання змішаного навчання в рамках програми Інтернет речей
• Аспіранти факультету інформатики та обчислювальної техніки КПІ ім. І. Сікорського Артем Коротенко, Георгій Ісаченко - Особливості використання змішаного навчання у відкритих групах слухачів та в університетських групах


Відеозапис:

Поки я під важенням, запишу тут ці враження тезисно.
Я зрозумів, що термін "змішана освіта" доволі широкий, і відсоток і тип офлайн/онлайн може принципово відрізнятися.
Найбільш впроваджуваний курс в ВУЗи як основа змішаного навчання – це CS50. Результати показали ряд проблем (зокрема про це казав Зеновій Верес із Львівської Політехніки). Студенти не встигали все за один семестр, тому доганяли частину в іншому семестрі. Останній виступ (був доволі яскравим) від менторів змішаної версії цього ж курсу в Києві. Там теж не все так гладко.
На моє питання щодо англійської мови в Прометеусі, Примаченко відповів позитивно. Це радує.
На моє питання щодо можливості розміщення своїх власних курсів на Прометеусі – можливо, але вирішується в індивідуальному порядку. Зараз дам декілька пропозицій в приваті, так як персона Примаченка в офлайні дуже востребувана, вирішив не чіпати і додовбувати його в офлайн. Треба відмітити, що він вислуховує усіх дуже уважно і чемно, що дає привід зловживати комусь його часом, і не допускати інших.
Відчував багато скепсису в залі. Старі преподи не хочуть змін, це просто витає в повітрі. Деякі відверто показували свій негатив. Зокрема два препода, молодий та професор (якийсь поважний) сиділи на виступі Примаченка і тупо деякі фрази а також презентації приймали з обуренням і зневагою. Після його виступу покинули залу. Думаю таких багато. Особливо вони люблять пастися на "наукових" конференціях і поливати брудом молодих вчених, що не мають зірок. Багато таких є і у нас.
Деякі виступи частково прослухав. На те є причини, вони нижче. Але запис є, у випадку чого можна прослухати. Мене більш цікавлять зараз презентації. Буду чекати і якщо знайду оновлю пост тут.
Але саме вразило те, що на конференції мене впізнали колеги з НУХТ. Не те, що мене впізнали а я ні, вже якось починаю звикати. Я був у відвертому шоці, коли побачив, що їх там аж 6-ро (тих кого я побачив) і всі прийшли по добрій волі. НУХТ рулить! Усі дуже переймаються освітою і в мене знову виникла думка про формування НУХТівського колективу з таких людей, які хочуть щось рухати не для галочки а тому що … люблять свою роботу. Різноманітність компетенцій тут тільки на руку. Ще для мене було здивуванням, що ці люди вже давно (набагато раніше ніж я) приймають участь в таких заходах і знають усіх цих Примаченків, Молчановських і Романко персонально. Молодці, маю надію що будемо дружити і спільно працювати!        

       

четверг, 26 января 2017 г.

TrnGetTable в Citect для лічильних даних



Ще один запис на сьогодні.
Вирішив записувати сюди деякі наробки. Стиль вільний, можна писати як хочеш, а деколи приходиться колупатися в своїх старих проектах, щоб згадати як робив. Думає це буде хороша практика, принаймні треба себе заставляти.
Друга задача, яку вирішував в Citect заставила мене трохи попотіти. Зараз є робочий прототип, тому фіксую результати. Отже задача – виводити оператору значення лічильника енергії (див попередній пост) за останню добу та 30 діб (типу за останній місяць). Задача попахує звітами, але я вирішив зробити її поки трохи лайтовою. Колись робив таке на Integraxor'і - запарився. Взагалі, дослідження проблеми формування нормальних несамопальних звітів для СКАД ще в мене висить в треї як високо пріоритетна, але поки не настільки.
Так от, лайтовість вирішення задачі передбачає не запарюватися зі звітами, а користуватися звичайними тегами. Її (задачу) варто розглядати з 2-х боків – запис та читання.
Запис значень в архів (30 діб все таки) можна проводити через бази даних (у сайтекту багато можливостей у цьому плані). Я думав піти по цьому шляху, але стало ліньки. Замість цього я вирішив скористатися трендами. Хоч дані лічильників мало корисні для відображення в якості трендів, трендовий архів дає можливість витягувати дані через сайкод функцію TrnGetTable. Отже, сказано, зроблено. Тут (стосовно конфігурування запису тренду) особливо й коментувати нічого, єдине, що аналоговий тренд треба сконфігурувати на 8-байтовий формат (про це я писав в минулому пості).
Читання - задача цікавіша. Згадую фразу одного свого викладача "Складних задач не буває. Є задачі легкі і цікаві!". Отже мені попалася задача десь на рівні між цікавою та легкою. Витягування даних за певний період з трендів проводиться за назвою трендового тегу, і як я вже казав робиться через  TrnGetTable:
       TrnGetTable(Tag, Time, Period, Length, Table, DisplayMode, Milliseconds [, sClusterName] )
Тут я трохи запарився, поки розколупав як в дійсності вона(функція) працює. Хоч усі нюанси так і залишилися за кадром (нІколи зара). Параметр Tag вказує на ім'я трендового тегу.
Time – вже вносить плутаницю. Цитую
 "The end time and date (long integer) of the desired trend section. Once you have entered the end time and date (Time), period (Period), and number of trend tag values collected (Length), the start time and date will be calculated automatically. For example, if Time = StrToDate("18/12/96") + StrToTime("09:00"), Period = 30, and Length = 60, the start time would be 08:30. In other words, the trend values for the period between 8.30am and 9am (on December 18, 1996) would be tabulated.
If this argument is set to 0 (zero), the time used will be the current time"
"end time and date" значить, що це сама свіжа дата в отриманих даних. Іншими словами, витягувати ці дані будуть з цієї дати/часу вглиб архіву. 0 – це типу "від зараз". Глибина ж архіву задається параметрами Period (задається в секундах) та Length (кількість точок виборки). Тобто діапазон даних буде  Period * Length з дискретністю Period. Дані будуть розміщені в Table, яка попередньо створюється як масив REALів. Чомусь сайтект не дає цей масив робити всередині функції, його треба виносити за межі функції. Не розбирався чому, якщо чесно. Так от, цей масив бажано заздалегідь зробити більше ніж кількість даних, що очікуються.  
DisplayMode – до сих пір під напівмраком. Він задає, як ці точки, що витягуються будуть себе вести при інвалідних даних, в якому порядку будуть слідувати в масиві (нові чи старі з 0-го елементу),  Condense та  Stretch методи (тут у мене не в усьому віра в свої догадки, тому тільки пару слів нижче), Gap Fill – тут у мене повний прольот. Condense на скільки я зрозумів задає як будуть усереднюватися дані в міждіапазонні. Stretch  що робити з точками, якщо вони разом попадають в діапазон (тут я все придумав сам, тому віри мені в цьому місці немає самому собі).
Усі інші параметри мене вже не цікавили, тому що імя кластера це стандартно а Milliseconds навіть не вчитувався.
Розбір роботи функції (хоть я вже її юзав на своїх курсах, але то ж для демки, а тут проект) я робив з використанням девайса текстового файлу, куди і вів лог всього що твориться в сайкоді. Вирішив надалі робити тонку відладку сайкода саме таким чином.
Кінцева сира реалізація, яка наче працює базується на наступних принципах:

REAL TableVAL[3600];
FUNCTION GetLastTrendData (STRING TagName, STRING TagWrName, INT Period, INT CountRec, INT EndTime)
    INT TimeREP, i;
    REAL VALold, VALnew;
    INT iold, inew, CountRec1;
    STRING Msg;
    //TrnGetTable(Tag, Time, Period, Length, Table, DisplayMode, Milliseconds [, sClusterName] )
    VALnew = 0;
    CountRec1 = TrnGetTable(TagName,EndTime, 60, 60, TableVAL[0], 12 + 2 + 256,0);
    //найбільший запис за годину буде останнім значенням 
    FOR i=0 TO CountRec1-1 DO
        IF TableVAL[i]>0 AND TableVAL[i]>VALnew THEN
         VALnew = TableVAL[i]; inew=i;
        END
    END

    //шукамо ненульову точку з мінімальним значенням в записах за період
    CountRec1=TrnGetTable(TagName,EndTime,Period, CountRec, TableVAL[0], 12 + 256,0);
    VALold = VALnew;
    FOR i=0 TO CountRec1-1 DO
        IF TableVAL[i] < VALold AND TableVAL[i]>0  THEN
            VALold=TableVAL[i]; iold=i;
        END;
    END;

    //уточнюємо в околі точки вниз з глибиною в 2 періоди, з точністю до хвилини
    CountRec1=TrnGetTable(TagName,EndTime - iold*Period, 60, Period*2/60, TableVAL[0], 12 + 256,0);
    FOR i=0 TO CountRec1-1 DO
        IF TableVAL[i] < VALold AND TableVAL[i]>0  THEN
            VALold=TableVAL[i]; iold=i;
        END;
    END;

    TagWrite(TagWrName , VALnew - VALold);
END


- шукаємо останню архівну точку в околі стартової (глибина – година: 60 точок по 60 секунд кожна); оскільки стартова в даній постановці задачі завжди "зараз" - в околі є якісь дані, на це і розраховую; нас цікавить максимум;
-  далі шукаємо мінімальне значення в записах, але ненульове; вважаємо, що спонтанних значень там немає, інакше логіку треба перебудовувати повністю (колись і таке витворяв на інтеграксорі); чому ми не беремо просто останні точки? тому що їх там просто може не бути: ну, наприклад, СКАДА тоді була в ауті, або лічильник; тому ми шукаємо "живі" значення
- однак при місячних пошуках періодичність не може бути малою, наприклад година (кількість буде 24*30); тому в області найменшого старого значення за місяць, визначеного з точністю до години, шукаємо найменше з точністю, визначеною до хвилини (думаю тут можна було би погратися з стречами та конденсами функції, але мені було ліньки).
Далі за допомогою івентів ця функція запускається з необхідною періодичністю. Думаю, тут достатньо раз в хвилину викликати. І далі юзати ці змінні як кі-пі-айні.  
Вот приблизно так.      

Читання в Citect змінних INT64



Сьогодні та вчора прийшлося витягувати в Citect змінні типу INT64 з PM5300 (аналізатори мережі від Шнейдер Електрик). Звичайно, що в Citect немає такого типу даних, максимум 32-бітний LONG. Пошаривши в Інтернеті найшов тільки один варіант вирішення проблеми. Декілька слів напишу, може кому цікаво буде, та й мені також пригодиться на майбутнє.
Качаю масив з 4-х INT. Ось як це виглядить:



 У Cicode змінні типу Real мають 64 бітну розярядність. Звичайно при дуже великих числах розбіжність INT64 та REAL64 буде, але думаю що це стане через декілька-сот років, і я вже не буду жити (хоча сподіваюсь що буду), а система точно ні.
Так от, прописую в Cicode функцію
REAL
FUNCTION ARR2INT64 (INT w0, INT w1, INT w2, INT w3)
 RETURN w0 + w1*65536.0 + w2*65536.0*65536.0 + w3*65536.0*65536.0*65536.0
END

Далі в потрібному місці відображення або запису в тренд пишу щось типу такого
ARR2INT64  (PM6_QRRECV[3], PM6_QRRECV[1],PM6_QRRECV[1], PM6_QRRECV[0])