Skip links

Послання зеленим і недосвідченим #почтипрограмістам ПЛК від #читопрограмера-читовиклада. Ч.1

При цьому я спираюсь на конкретну платформу, і дуже мало (не те щоб зовсім, але не достатньо) віддаю часу алгоритміці та підходам в розробці та наладці прикладного ПЗ для контролерів. Очевидно це у більшій мірі із-за того, що я, ще в студентські роки не проходив курсу на кшталт “розробки алгоритмів для систем керування в реальному часі”, та навіть не знаю, чи такі існують. Однак, постійно підробляючи програмістом (#читопрограмером) та наладчиком систем АСУТП, я, сам того не усвідомлюючи, вбирав від своїх колег кращі, на мою думку, практики, та відшліфовував свій стиль програмування.  Однак, дивлячись на молоде покоління, я бачу, що ті проходять такий саме шлях як і я, роблять ті самі помилки, зустрічаються з тими саме проблемами. 

І на цьому місці моєї писанини я уявляю, як Ви, потужний #суперпрограміст_АСУТП зі стажем (не сумніваюся ні грама), втрачаєте інтерес до нижченаписаного, адже ви цей шлях пройшли!  Тоді задумайтесь над тим, що можливо вам колись прийдеться доробляти програму зеленого програміста,… хоча я здогадуюсь чим це закінчиться – все викинете і поставите/напишете своє! Тоді … може вас нажахає ситуація, коли ви будете працювати в парі з молодим програмістом?! Аааа, Ви його навчите самі?! А може є сенс скоротити шлях молодого бійця ще до цього та визначити разом кращі практики? 

Я вважаю, що є сенс на першій ітерації принаймні спробувати виписати #суб’єктивно_кращі_практики, тобто визначити типові підходи до розробки прикладного ПЗ для систем керування на базі програмованих контролерів. Буде закид – можливо будуть коментарі, а це кращий зі спосіб вдосконалення і шляху до об’єктивності! Отже, цей матеріал можливо буде цікавим як молодим #почтипрограмістам так і дуже досвідченим #суперпрограмістам. Першим для навчання, другим в контексті “Ну-ну, чого я там не бачив? Хоч потролю!”. Саме конструктивного тролінга,  шановні програмісти-аси, я від вас і чекаю.     

Хтось із вас, очевидно #непрограмістів_контролерів_асутп (а може вони) скаже, що класичні комп’ютерні  #програмісти можуть похвалитися своїм високим пілотажем в даному питанні. У них же там такі дисципліни по програмуванню, алгоритмам і багато-чого корисного (без сарказму)! Але чомусь у мене виникають сумніви щодо калькування їх підходів у практику програмування контролерів в АСУТП. Чому? На це є багато причин, які пов’язані зі специфікою як систем керування так і типом об’єкту автоматизації (#техпроцес), і ось деякі з них: 

  • функціонування системи в реальному часі, 
  • перевага МЕК-овських мов програмування, 
  • специфічність задач, 
  • необхідність відлагодження програми без зупинок процесу, а отже і програми, 
  • зміна коду по місцю #не_автором_програми
  • далі думку можна розвивати для важливості і ексклюзивності наших асутпшних програмістів, але це якраз пункт для них, тому тут закінчу перелік 

То, можливо, необхідна своя дисципліна “розробка алгоритмів для контролерів АСУТП” а може вона вже є?

Хто зна? Що мені попадалося. Не можу сказати, що я досліджував дану проблему, все-таки не наукову статтю пишу, і не в науковому журналі, і не для науковців, і … ну ви зрозуміли. Деякі класичні алгоритми бачив у відомій книжці Ендрю Парра (доречі, в Інтернеті є перекладена російською версія). Приклади там реалізовані ще на ПЛК епохи 80-х та 90-х, але не повірите, практично нічого не змінилося! Кльова книга –  рекомендую для прочитання. 

 1

Деякі підходи ми зі співавторами писали в методичках до курсового проекту, не так щоб багато, але трохи було. Немалий набір рекомендацій щодо побудови програми та її відлагодженні (наприклад з використанням примітивних імітаційних моделей) викладені і в нашому посібнику “Програмування промислових контролерів в середовищі Unity PRO” (це типу реклами). 

Нещодавно мене здивувала розмова з розробником вітчизняних промислових контролерів, який при реалізації алгоритму управління серво-приводом (типу МЕО) наткнувся на ті самі проблеми, на які натикаються більшість при програмуванні. Дивування визвано тим, що я вважав, що це все давно вирішено. Звичайно вирішення цих проблем давно відоме десь в наукових статтях та #голоснобрендових реалізаціях, однак вони до сих пір не дають спокійно жити експлуатаційному персоналу підприємств з інстальованими пристроями інших брендів. Таким чином пора збирати #платформоіндепендент-рішення. Я почну, а ви можете продовжувати.  

Стиль статті базується на методі проблемного викладення, мій улюблений. Але це не значить, що вона наукова. Але якщо її захочуть включити в індексацію SCOPUS, я не буду сильно ображатися.       

1. Загальні рекомендації.

Чи використовуєте Ви коментарі?

Завжди все коментуйте і документуйте. Щось змінили на об’єкті – запишіть. Нікого не здивував подібною заявою? Згадайте це, коли на наступний рік після гарячих пусконаладок будете правити свою програму. Ваша дисциплінарність повинна заставляти вносити правки не тільки в код програми  (навіть з коментарями), а і в свій щоденник (лог) проекту. Усі свої шишки, непорозуміння треба занотовувати, хоч кривим текстом з купою помилок (типу “клапан чогось дьоргався потім перстав, я так і не пньяв чому”, помилки не виправляти! – примітка до редактору), але обов’язково фіксувати. Це буквально 15-30 хвилин роботи, а економія при повторній наладці/відлагодженні/тиражуванні суттєва.    

Чи робите ви план робіт, алгоритм, чи продумовуєте структуру?

Спочатку продумайте – а потім робіть! Спочатку алгоритм – потім програма! Алгоритм може бути в якому завгодно вигляді, як зручно для Вас. Тобто не обов’язково ромбики з прямокутниками рисувати, можна і на словах і у вигляді таблиці, можна навіть у вигляді типу SFC, чи якихось діаграм іншого типу. Але перед цим з постановкою задачі бажано не одну ніч переспати, в прямому сенсі цього слова.  Якщо на вашому рахунку є принаймні одна реалізована система, ви вже повинні саме з цього починати.   

Як ви розробляєте програму для ПЛК нового для вас типу?

Дайте вгадаю – так як і для старого! Ну там же ж МЕК і все те саме! Ага! Новий ПЛК – нові проблеми, часто пов’язані саме з тим, що старі методи вирішення старих проблем не підходять для даного ПЛК. Як з цим можна боротися? Я підхожу до цього так: перед написанням програми з малознайомим ПЛК спочатку роблю міні-проект з достатнім функціоналом, щоб врахувати особливості даного ПЛК. Якщо необхідно перевірити роботу бібліотеки (наприклад контуру регулювання), реалізовується весь контур, включаючи обмін зі SCADA/HMI. Та це просто еджайл!  

А ви замислюєтесь, у якому стані повинні бути виходи ПЛК при його зупинці (в режимі STOP)? А при старті? А при аварії?

Необхідно врахувати первинний запуск (холодний старт), операції при зупинках, аварійну обробку. І взагалі, варто задуматись про те, що система може перебувати у декількох станах, і алгоритми роботи можуть від цього принципово змінюватися. Звичайно не варто вводити стан, коли директор проходить біля ПЛК і треба поблимати лампочками, типу наповнити рівні в танках і сховати на СКАДі всі аларми. Хоча, треба над цим подумати… 

Як далеко Ви можете зайти, щоб прискорити роботу програми та зменшити її обсяг?

Програмісти, що люблять низькорівневі мови дуже пишаються тим, що їх програми крім них самих ніхто не може прочитати. Круто, правда! Гммм… Прочитайте свій код через декілька років. А ще… попробуйте його дуже швидко відлагодити на працюючому об’єкті. Ні… не те… О! Давайте для повної впевненості у вірності ваших підходів влаштуємо Вас на роботу в колектив, де наладкою займаються інші люди, ніж ті які пишуть програми! О, там якраз всі будуть хизуватися вашим умінням компактного написання!   

“Наш ПЛК розрахований рівно на стільки функцій, як прописано в ТЗ. Так що прийдеться його міняти на інший.”Знайома ситуація? 

Вибирайте та компонуйте ПЛК заздалегідь більшими ресурсами по пам’яті, ЦПУ, входам/виходам. Пам’ятайте, що здешевлення системи у більшості випадків приводить до негативних наслідків, в тому числі вищеописаних. Не забувайте ще про те, що робОти (не рОботи) у вас теж, як правило, при цьому прибавляється. 

2. Структура програми користувача.

Які  структурні одиниці для ПЛК Ви знаєте?

Згідно МЕК 61131 (біблія для АСУТПшного програміста, доречі хто з вас її читав?) є окремі незалежні куски програми, як POU (Program Organization Unit):

  • програми (секції);
  • функції;
  • функціональні блоки;

У деяких ПЛК є ще неМЕКовські одиниці типу підпрограми та процедури.

Для ПЛК невеликої канальності,  як правило, ділити програму не можна, максимум – використовувати підпрограми. А чи враховуєте Ви можливості конкретної моделі при реалізації програми?    

А ви користуєтесь багатозадачністю? 

Не слід плутати багатозадачність з логічним структуруванням програми. Багатозадачність дає можливість економити перш за все часові ресурси контролера, забезпечуючи реальний час з використанням великих за обсягом програм. Так, наприклад, якщо всю програму написати в одну циклічну задачу (тобто ту, яка виконується відразу після того як виконується, відразу після того як виконується …), то цикл може бути  таким великим, що швидкість обробки не буде задовольняти умови керування певними процесами. “Ну, так, можна через певні куски коду виконувати одну і ту саму процедуру керування” скажете Ви. Проблема в тому, що у більшості випадків оновлення входів і виходів ПЛК проводиться на початку або в кінці задачі. Тому, наприклад, 10 раз змінюючи вихідну змінну за цикл, вона все одно на вихід запишеться тільки один раз в кінці циклу (примітка для #суперпрограмерів: я знаю про різні там периферійні входи/виходи та безпосереднє читання та запис). Ось тут і потрібна багатозадачність, щоб деякі алгоритми викликати частіше, і входи/виходи, які в них використовуються теж оновлювати частіше. Для багатозадачних середовищ (multitask), задачі можуть виконуватися циклічно, періодично, або за подією.  Останні, як правило, мають найвищий пріоритет і повинні виконатися миттєво при виникненні якоїсь події. 

“Ці кляті контури регулювання з’їдають 90% часу задачі, програма не встигає керувати дискретними клапанами для швидких функцій. Що робити?”  

Для початку визначіться, з якою періодичністю необхідно викликати регулятори. Для простоти можна вважати, що усі наприклад 20-ть регуляторів повинні викликатися з періодичністю 1 с. Тоді можна створити #типушедулер, який буде викликати по 2 регулятори з періодичністю 100 мс, але на кожний цикл інші. Так за десять циклів (протягом 1 сек) викличуться всі контури, але тривалість кожного циклу буде як тривалість виконання 2-х регуляторів. Я називаю цей механізм #розмазування_по_циклам.  Звичайно, для частої обробки контурів такий механізм не згодиться і прийдеться… вибирати інший контролер, або добавляти ще парочку. 

Ви знаєте що таке декомпозиція? 

Слово то яке чудове! Не намагайтеся всю логіку вписати в одну секцію (POU). Коли у Вас є арсенал різноманітних POU, не цурайтесь ними користатися, адже відлагодження все одно будете робити частинами, а не одним махом. 

Ви не знаєте як ділити програму на POU? Можна скористатися вихідними даними до проекту: наприклад, схемою автоматизації, переліком функцій та задач з технічних вимог, чи технічного завдання. Можна виділити:

  • окремі процеси (приготування продукту, процес мийки) ;
  • окремі  об’єкти регулювання (бачки, реактори, технологічні установки з обв’язкою)
  • окремі технологічні задачі (періодичні процеси); 
  • окремі контури регулювання (наприклад контур регулювання температури TC1a);
  • комбінація

Так буде простіше реалізовувати і відлагоджувати програму, наче у вас не один ПЛК, а декілька маленьких регуляторів з’єднаних одним залізом та змінними. Налагоджуєте контур регулювання, знайшли секцію (функцію, фб) з його назвою, відкрили – і все перед вами без зайвого коду (якщо ви звісно свідомо чи несвідомо туди його не вписали).  

Ну, і крім того є звичайно класичне призначення функцій та функціональних блоків – повторне використання коду з передачею параметрів. Тому виділяйте підфункції, які можна використати декілька раз.  Наприклад, керування клапаном зі зворотним зв’язком та сигналізацією. 

Доречі, ви пам’ятаєте навіщо потрібні функції, функціональні блоки та процедури, чим вони відрізняються між собою та від підпрограм?

Як об’єднати всі ці структурні  частини?

Декомпозицію зробили, а тепер треба робити агрегування. Основну програму можна реалізувати як виклики менших програм чи функцій, які при необхідності можна у будь який момент часу відключити. Цей підхід я бачив практично у всіх #чужих_програмах. Це просто дуже зручно, функціональний кусок програми відключається в одному рядку для текстових мов, або порожнім контактом в LD, або інверсією в потрібному місці контакту EN в FBD (пам’ятаєте що це таке?).  

Ви користуєтесь в основній програмі вхідними та вихідними змінними ПЛК?  

Маєте право. У цьому плані усі програмісти діляться на дві групи: 

  1. ті, які використовують проміжні внутрішні змінні та десь в програмі відображають їх на зовнішні
  2. ті, які користуються в програмі тільки посиланнями на оригінальні змінні входів та виходів (типу %I чи %IW) 

Якщо Ви ортодоксальний противник дублювання змінних (#варонедублювальщик), тобто Ви відносите себе до другої групи і не хочете змінювати релігійних поглядів, цей пункт вам треба пропустити, тому що далі йде жорстка #вароєресь. Спори з цього приводу неодноразово піднімалися на форумах. Якщо ж Ви все-таки користуєтесь проміжним переприсвоєнням, далі рекомендації наведені для Вас.   

Для ПЛК великої та середньої канальності всі проміжні перетворення можна робити в окремих структурних одиницях.  При використанні проміжних перетворень структуру програми можна представляти як послідовність виконань: 

  • секція/функція обробки входів, 
  • секції/функції основної програми, 
  • секція/функція обробки виходів.

2

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

“Що це дає?” – спитають ортодоксальні #варонедублювальщики, які все таки наперекір мені дочитали до цього місця. Ось деякі можливі переваги:

  • незалежність програми від фізичного підключення каналу: часто на об’єкті місце підключення фізичних каналів змінюється по різним причинам (проектна помилка, згорів канал, #ойпроблемакопіпаста тощо);
  • швидка заміна каналів при переключенні на резервний;
  • можливість налагодження програмним шляхом: вхідні і вихідні змінні просто “відключаються” від внутрішніх простим відключенням секцій, і далі роби з цими “дублями” що хочеш, хоч змінюй засобами налагодження, хоч програмно імітуй;
  • незалежний зв’язок SCADA/HMI з PLC: не забувайте, що просте переключення каналу тягне за собою зміну адреси і в СКАДА, звичайно якщо Ви не використали запропонований підхід, в якому  при переприсвоєнні адреси “дублів” залишаються без змін; 

Ложка дьогтю (на радість ортодоксальним #варонедублювальщикам):

  • йде дублювання змінних (надлишок пам’яті): так, наприклад, замість однієї %I у вас з’являється ще й %M

Але, враховуючи функціональні потужності сучасних ПЛК, практично вся алгоритмічна база працює з масштабованими та заздалегідь обробленими величинами. Тому у місці масштабування все одно вхідні змінні перетворюються у внутрішні. Так, що нерідко платформа примушує змінювати релігію (глумливо показую язика).

“Якщо умова не виконується тоді відключити виклик функції ПІД-регулятору”. Ви добре подумали?

Платформа сильно накладає свої #депендент-штучки на реалізацію контурів регулювання. Тим не менше, хоча б задумайтесь про можливі наслідки. У Вашого ПЛК є чудова функція реалізації ПІД-регулятору, і Ви не можете не нарадуватися усілякими реалізованими смакотами типу безударність переходу, антинасиченість, режим слідкування в каскаді, можливість заморозки складових!? Так чого ви його тоді до біса відключаєте?! Уявіть собі, що Ви ПІД-регулятор, який повинен безударно перейти в автомат з ручного режиму, і це при тому, що вас тільки-но розбудили!? Та Ви навіть не знали, в якому значенні був клапан в ручному режимі! Замість включення/відключення використовуйте спеціальний режим, наприклад слідкування. Якщо такого режиму у регулятору немає, забезпечте його попередню ініціалізацію, перед введенням в дію. Принаймні про це теж треба думати.

Ну що, стомились? – далі в наступному випуску буде про вибір мови та підходи до програмування.

Коментарі та ваші кращі практики дуже навіть вітаються  – почуємось в он-лайн просторі:))

Продовження публікації за цим посиланням 

Олександр Пупена, викладач, Київ 

This website uses cookies to improve your web experience.