Mocne i słabe strony języków tekstowych

Język tekstu strukturalnego znany jest tylko co trzeciemu inżynierowi w Polsce. To niewiele, biorąc pod uwagę, że wraz z postępującą integracją automatyki oraz IT będzie to coraz bardziej wygodne narzędzie programowania PLC. Warto bliżej przyjrzeć się jego plusom i minusom.

Wczesne systemy komputerowe były programowane ręcznie przy użyciu fizycznych przełączników do konfiguracji adresu, danych i granic kontrolnych maszyny. W celu wprowadzenia danych do pamięci każda instrukcja była konwertowana na wzory bitowe. Na ich podstawie ustawiano odpowiednie przełączniki adresowe, danych i poleceń. Podczas konwertowania instrukcji na numeryczny kod maszynowy komputera można było łatwo popełnić błąd. Problem rozwiązano za pomocą pierwszego z tekstowych języków listy instrukcji (IL, z ang. instruction list), inaczej nazywanego asemblerem. Asembler jest najstarszym językiem nie maszynowym, który pozwala na tworzenie programów w formie czytelnej dla człowieka. Kod listy instrukcji składa się z sekwencji instrukcji ułożonych w liniach, z których każda zawiera kolejno jeden symbol rodzaju operacji (operator), jeden argument operacji i opcjonalnie jeden modyfikator:

LD               R1

JMPC           RESET

LD               PRESS_1

ST               MAX_PRESS

RESET: LD    0

ST               A_X43

Języki asemblerów obejmują typy danych i struktury programowe, które są bezpośrednio realizowane na wykorzystywanym sprzęcie. Są zależne od określonego sprzętu, więc wymagają bardzo dobrej znajomości architektury danego procesora i listy rozkazów. Ponowne użycie kodu na różnych architekturach komputerowych stanowi nie lada wyzwanie. Aby mu sprostać, stworzono języki tekstu strukturalnego wyższego poziomu, które mają być zwykle niezależne od platformy sprzętowej poprzez oddzielenie warstwy sprzętowej. Powszechnie przyjmuje się, że z powodu wprowadzenia przynajmniej jednej dodatkowej warstwy abstrakcji, języki tekstu strukturalnego oferują – kosztem szybkości i pamięci – skrócony czas rozwoju oprogramowania i zwiększoną przenośność kodu.

Te korzyści wyniosły tekstowe języki programowania wysokiego poziomu ponad języki listy instrukcji niskiego poziomu i przyczyniły się do ich rozpowszechnienia w dziedzinie rozwoju oprogramowania.  

Prawie jak Pascal

Tekst strukturalny (ST, z ang. structured text) jest językiem tekstowym wysokiego poziomu. Ma dobrze zdefiniowaną składnię, umożliwiającą: reprezentowanie typów danych, przypisywanie wartości zmiennym, definiowanie i wywoływanie funkcji oraz tworzenie złożonych algorytmów obejmujących podejmowanie decyzji.

Język tekstu strukturalnego jest podobny do języka Pascal i wykorzystuje dobrze zdefiniowane konstrukcje, takie jak „if-then” do sterowania wykonywaniem programu. Duże programy są zwykle dzielone hierarchicznie na mniejsze elementy funkcjonalne, które określają organizację programu. Twórcy oprogramowania zwykle używają podejścia „od góry do dołu” lub „od dołu do góry” przy tworzeniu oprogramowania z użyciem języka tekstowego. W przypadku podejścia „od góry do dołu” poświęcają początkowy czas tworzenia oprogramowania na definiowanie górnego poziomu struktury aplikacji i interfejsów pomiędzy mniejszymi częściami kodu, zwykle zwanymi podprogramami lub funkcjami. W przypadku podejścia „od dołu do góry” jest odwrotnie: twórcy oprogramowania zaczynają od tworzenia rozmaitych podprogramów wykonujących specyficzne zadania i wykorzystują tak stworzoną bibliotekę funkcji do zaimplementowania większej aplikacji.

Przy złożonych aplikacjach zwykle wymagane jest grupowanie danych w struktury. Jest to standardowo możliwe w większości języków tekstowych wysokiego poziomu, takich jak: Pascal, Fortran i ANSI C. Na przykład system zarządzania sprzętowymi wejściami / wyjściami sterownika programowalnego może wymagać złożonych mechanizmów reakcji, gdy wystąpi pewne zdarzenie. Wszystkie informacje dotyczące czujnika powinny być w najlepszym wypadku przechowywane jako pojedyncza struktura, która może zostać zaadresowana przy użyciu wspólnej unikalnej nazwy. Na przykład pompa sterowana przez sterownik programowalny może mieć bit statusu, określający, czy jest sprawna; wejście analogowe określające prędkość zadaną i wyjście analogowe określające aktualną prędkość. Wszystkie te dane mogą zostać zdefiniowane jako jedna struktura danych „pompa”, do której można potem odwoływać się jako do całości.

W porównaniu z językiem drabinkowym obsługa struktur poprawia czytelność programu i przyczynia się do redukcji błędów związanych z dostępem do danych.

Obiektowe tekstowe języki programowania, takie jak Java i C++, rozszerzają powyższą funkcjonalność nie tylko o możliwość tworzenia własnych typów danych, lecz również o możliwość definiowania specyficznych metod działających na tych danych.

Mocne strony

Wysoka przenośność pozwalająca na ponowne użycie obszernych części kodu. Języki tekstowe udostępniają konstrukcje, takie jak pętle i funkcje, które mają pomóc programistom implementować moduły logiczne wielokrotnego użytku. Te konstrukcje pozwalają na zmniejszenie wielkości programu poprzez redukcję ilości powtarzanej logiki w aplikacji. Dzięki temu programiści mogą szybko wyizolować błędy w kodzie i stworzyć programy łatwiejsze w konserwacji. 


Obecnie – a prawdopodobnie także i w przyszłości – optymalnym rozwiązaniem jest projektowanie algorytmu sterowania z użyciem kilku języków. Ogólną strukturę algorytmu sterowania oraz sterowanie dyskretne najłatwiej jest bowiem zapisać za pomocą języka sekwencyjnego schematu funkcjonalnego, zaś działania matematyczne algorytmu za pomocą języka tekstu strukturalnego.


Silna integracja z IT. Ze względu na to, że utrzymuje się trend wzrostowy podłączania przemysłowych systemów pomiarowych i sterowania do aplikacji serwerowych wyższego poziomu, coraz ważniejsze jest tworzenie aplikacji przy użyciu narzędzi programistycznych obsługujących sieć www i łączność sieciową. Wiele języków tekstowych ma wbudowane możliwości rejestracji danych w bazach danych, włącznie z przeszukiwaniem baz danych przy użyciu języka SQL (z ang. Structured Query Language). Stosuje się też funkcje kontroli kodu źródłowego służące do utrzymywania integralności oprogramowania tworzonego przez wielu programistów. Możliwa jest łączność za pośrednictwem Internetu, umożliwiająca zintegrowanie funkcjonalności tworzonej przez rosnącą społeczność obszaru usług sieciowych.

Naturalne projektowanie algorytmów. Wszystko w obszarze matematyki – od algebry liniowej począwszy, przez rachunek wektorowy, na matematyce dyskretnej skończywszy – było tradycyjnie reprezentowane w formie tekstowej. Dlatego języki tekstowe zapewniają naturalne środowisko obliczeń matematycznych i przetwarzania sygnałów. Wiele uniwersalnych tekstowych środowisk programistycznych, takich jak Microsoft Visual C#, dostarcza w standardowym pakiecie dodatkowe funkcjonalności oprócz standardowych funkcji języka programowania. Dodatkowo, specyficzne dla przemysłu tekstowe środowiska programistyczne, takie jak NI LabWindows / CVI, również udostępniają funkcjonalności zwykle używane w wąskich obszarach zastosowań, łącznie z obszernymi bibliotekami służącymi do analizy, takimi jak: przebiegi sygnałów, filtry i algorytmy sterowania PID.

Silna optymalizacja kodu niskopoziomowego. Języki tekstu strukturalnego często umożliwiają bezpośredni dostęp do systemu operacyjnego lub odwołania do funkcji specyficznych dla danego sprzętu. Programiści mają więc większą zdolność do kontrolowania, jakie i jak wiele określonych operacji jest wykonywanych na poziomie maszynowym. Zoptymalizowane kompilatory i możliwość wywoływania kodu asemblera z języka tekstu strukturalnego również pomagają programistom w kontrolowaniu wielkości programu i szybkości jego wykonywania.

Słabe strony

Utrudnione śledzenie wykonywania kodu. Hierarchiczna natura języków tekstu strukturalnego utrudnia śledzenie rozgałęzień logicznych w trakcie wykonywania kodu. Wprawdzie tekstowe środowiska programistyczne często zawierają narzędzia służące do wykrywania i usuwania błędów z programu (ang. debugging), takie jak punkty wstrzymania, służące do tymczasowego przerwania wykonywania programu i do kontynuacji linijka po linijce. Niemniej przewidzenie, która linijka kodu wykona się jako następna, jest często trudne lub wręcz niemożliwe, w szczególności gdy podprogramy są zdefiniowane na końcu pliku źródłowego lub znajdują się we wcześniej kompilowanych modułach, takich jak biblioteki dołączalne dynamicznie (DLL, z ang. dynamic link libraries).

Równoległe wykonywanie. Wielowątkowość była kluczowym postępem w historii języków tekstowych. Dzięki możliwości wykonywania wielu wywołań funkcji pozornie naraz możliwe jest tworzenie bogatych interfejsów użytkownika, które płynnie wykonują operacje wejścia / wyjścia na plikach, rejestrowanie do baz danych i sterowanie sprzętem bez spadku wydajności. Jednakże realizacja tego korzystnego rozwiązania pociąga za sobą konieczność korzystania ze specyficznych bibliotek obsługujących wielowątkowość i czas wykonywania, aby ustalić kolejność wykonywania różnych części kodu. Na przykład przy tworzeniu aplikacji realizującej sterowanie PID i w tym samym czasie wyświetlającej interfejs użytkownika, programista musi stworzyć przynajmniej dwa wątki w aplikacji, aby zachować stały czas wykonywania wymagany w przypadku sterowania PID i przydzielić wystarczająco dużo zasobów dla zachowania płynnego i odpowiednio szybko reagującego interfejsu użytkownika. Programista musi również być ostrożny przy dostępie do danych globalnych i musi być biegły w używaniu specyficznych konstrukcji programowania wielowątkowego, takich jak semafory i blokady. W przeciwnym razie nie będzie pewien, że nie więcej niż jeden wątek będzie uzyskiwał dostęp do określonych danych w tym samym czasie.

Czas potrzebny na stworzenie oprogramowania. W porównaniu z graficznymi metodami rozwoju oprogramowania czastworzenia oprogramowania, jaki jest konieczny do stworzenia w pełni funkcjonalnej aplikacji, jest znacząco dłuższy. Ścisła natura składni języków tekstowych wymaga, aby wszystkie funkcje i zmienne były zadeklarowane i często zainicjalizowane, zanim zostaną użyte w aplikacji. Ponadto ANSI C rozróżnia małe i duże litery, zatem błędne zapisanie „readfile()” jako „readFile()” spowoduje błąd. Podczas gdy Microsoft Visual Basic chroni programistę przed tym scenariuszem, musi on i tak znać dokładną nazwę funkcji, która wykonuje określone działanie i przekazać do niej właściwe parametry w odpowiedniej kolejności, aby żądane działanie mogło być wykonane.

Jest wiele powszechnie używanych języków tekstowych, począwszy od niskopoziomowego asemblera, poprzez języki bazujące na C, aż po języki obiektowe, takie jak Java i C++. Języki tekstu strukturalnego dobrze nadają się do tworzenia aplikacji ze ścisłymi wymaganiami odnośnie miejsca zajmowanego w pamięci i wydajności lub do aplikacji wymagających wielokrotnego przetwarzania i analizy sygnałów.

W szczególności sterowniki urządzeń, systemy wbudowane i aplikacje czasu rzeczywistego korzystają ze zwiększonej szybkości i możliwości przetwarzania udostępnianych przez języki tekstu strukturalnego. Jednakże trzeba mieć świadomość znaczących wyzwań, którym trzeba stawić czoło przy tworzeniu w tych językach aplikacji wielowątkowych. Niższy poziom abstrakcji widoczny w językach tekstowych może również wpłynąć negatywnie na wydajność kodowania.


Wendy-Kay Logan jest inżynierem
produktu LabWindows/CVI
i Measurement Studio w firmie
National Instruments.

 Artykuł pod redakcją
mgra inż. Krzysztofa Michalskiego,
absolwenta Politechniki Szczecińskiej


Radzę nie ograniczać się

Dla Control Engineering Polska mówi dr inż. Bogdan Broel-Plater z Instytutu Automatyki Przemysłowej Politechniki Szczecińskiej:

Podczas projektowania algorytmu sterowania – zwłaszcza złożonego algorytmu – język tekstu strukturalnego (ST) jest na pewno bardziej przyjazny od schematu drabinkowego (LD), funkcjonalnych schematów blokowych (FBD) lub listy rozkazów (IL). Jednak myślę, że najłatwiej jest zaprojektować algorytm sterowania wykorzystując język sekwencyjnego schematu funkcjonalnego (SFC). Ze względu na jego prostotę można szybko nauczyć technologów posługiwania się nim. Graficzna postać algorytmu sterowania zapisanego za pomocą języka SFC ułatwia także „ogarnięcie” jednym spojrzeniem całego algorytmu. Zrozumienie istoty działania algorytmu sterowania zapisanego za pomogą języka ST wymaga zaś przeanalizowania całego ciągu rozkazów. Zaletą języka ST jest to, że algorytm sterowania można zapisać w sposób bardzo zwięzły. Jednak często jest to okupione małą czytelnością algorytmu. Program w języku ST łatwo jest modyfikować (zaleta), jednak jego uruchamianie i testowanie może być trudne (wada), jeśli producent sterownika nie dostarcza odpowiednich narzędzi. Moim zadaniem najważniejszą zaletą języka ST jest możliwość szybkiego pisania programów wykonujących złożone obliczenia matematyczne. Zapisanie takich algorytmów za pomocą pozostałych języków programowania sterowników PLC jest znacznie trudniejsze. Zwłaszcza jeśli sterownik ma jedynie rozkazy arytmetyki całkowitoliczbowej.

Reasumując myślę, że obecnie – a prawdopodobnie także i w przyszłości – optymalnym rozwiązaniem jest projektowanie algorytmu sterowania z użyciem kilku języków. Ogólną strukturę algorytmusterowania oraz sterowanie dyskretne najłatwiej jest bowiem zapisać za pomocą języka SFC, zaś działania matematyczne algorytmu za pomocą języka ST.


 

„Tekstowe modele obliczeń” to drugi z serii artykułów poświęconych różnym metodom tworzenia oprogramowania PLC. Pierwszy artykuł (dostępny pod adresem www.controleng.com/archives w zakładce „grudzień 2007”) opisywał logikę drabinkową. Następne artykuły będą omawiać bloki funkcyjne / przepływ danych, diagram stanów i metody symulacji/modelowania.