Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – biblioteka s7netplus

0
296

Na początek krótki wstęp historyczny. Pierwszą bibliotekę oferującą dostęp z własnej aplikacji do zasobów sterownika oferował sam Siemens. Biblioteka ta nazywała się PRODAVE i była rozwijana tak naprawdę do 2012 roku, kiedy to pojawiła się jej ostatnia wersja 6.2 oferująca kompatybilność z Windows 7. Był to oczywiście produkt płatny z zamkniętym źródłem.

Najstarszym rozwiązaniem open source istniejącym do dzisiaj jest biblioteka libnodave (jak widać nawiązująca sprytnie nazwą do wspomnianego Prodave). Biblioteka jest napisana w C i można ją znaleźć na sourceforge lub github

O libnodave wspominam celowo, gdyż przetarła ona szlaki dla kolejnych rozwiązań, które są dzisiaj aktywnie rozwijane. Oczywiście można się pokusić o korzystanie z czystego libnodave w aplikacji .Net przez mechanizm pozwalający na korzystanie z bibliotek niezarządzanych lub skorzystać z przygotowanego wrappera, ale chyba nie warto tego robić gdy istnieją wygodniejsze rozwiązania.

Długo zastanawiałem się od jakiej biblioteki zacząć i zdecydowałem się wybrać s7netplus . Biblioteka jest wciąż utrzymywana i aktualizowana – poza jej autorem posiada również kilku kontrybutorów. Jest ona całkiem wygodna i dość bezproblemowa w wykorzystaniu. Bez pro blemu połaczymy się za jej pomocą ze sterownikami S7-200, S7-300, S7-400, S7-1200 oraz S7-1500. Działa również z zyskującym ostatnimi czasy na popularności SoftPlc.

Do dyspozycji otrzymujemy również bardzo fajny manual (dostępny tutaj). Dokumentacja jest na tyle dobra, że posiadając jakąkolwiek wiedzę na temat architektury przechowywania danych w sterowniku Simatic S7 bez problemu zrozumiemy jak korzystać z udostępnionych funkcji.

Bibliotekę do naszego projektu możemy zaimportować korzystając z nuget-a.

Algorytm komunikacji ze sterownikiem można opisać bardzo prosto:

  1. Nawiąż połączenie
  2. Odczytaj/Zapisz dane
  3. Zamknij połączenie

Oczywiście jeżeli nasza aplikacja wykonuje odczyt lub zapis cyklicznie, to operacji nawiązywania i zamykania połączenia nie musimy wykonywać, a nawet nie powinniśmy, za każdym razem. Warto jednak wtedy odpowiednio monitorować stan połączenia (w przypadku opisywanej biblioteki obiekt realizujący komunikację posiada właściwość IsAvaiable, która sprawdza jego dostępność w sieci oraz IsConnected, która informuje o stanie połączenia). W razie jego zerwania (np. przez rozłączenie z siecią) możemy wtedy nawiązać połączenie ponownie.

Ja w przypadku konieczności odczytu/zapisu cyklicznego używam zwykle timer-a z przestrzeni System.Timers, który realizuje komunikację, w momencie zaś odebrania paczki danych wystawia zdarzenie informujące o tym fakcie (przykład w kodzie źródłowym na github).

Dlaczego timer a nie np. wątek ? Ponieważ należy pamiętać o tym, że bez względu na to, czy komunikacja realizowana jest przez fizyczny port ethernetowy w CPU sterownika czy też przez procesor komunikacyjny to i tak CPU realizuje większość funkcji komunikacyjnych. Realizując komunikację przez wątek i nie stosując opóźnień obciążamy mocno CPU i w przypadku słabszych modeli może się okazać, że jest duży problem z dodatkowym połączeniem się za pomocą np. programatora.

Warto też pamiętać o tym, że cała komunikacja odbywa się na jednym porcie (w przypadku sterowników S7 jest to zawsze port 102) i nie jest wielowątkowa. Jeżeli realizujemy cykliczny odczyt realizowany w wątku (czy też timera realizowanego jako wątek), to w momencie incydentalnego zapisu (np. w reakcji na wciśnięcie przycisku na formie) należy zadbać o to, aby zapis nie był realizowany w tym samym czasie co odczyt. Do tego celu można oczywiście dowolnego mechanizmu kontroli wątków. Ja zwykle używam do tego najprostszego mechanizmu lock.

Zdefiniujmy więc obiekt klasy Plc i przypiszmy parametry naszego połączenia:

Myślę, że nie trzeba tu wiele tłumaczyć. O rack i slot wspominałem już w poprzednim poście.

następnie nawiązujemy połączenie:

W zmiennej result otrzymamy informację zwrotną odnośnie wyniku. Jest to enum ErrorCode, opisany dokładnie we wspomnianym wcześniej manualu. Oczywiście chcemy otrzymać tutaj NoError potwierdzający poprawność połączenia.

Dane ze sterownika odczytamy za pomocą metody Read a zapiszemy za pomocą metody Write. Metoda ta posiada przeciążenie i możemy zarówno przeczytać lub zapisać pojedynczą zmienną korzystając z adresowania sterownikowego (np. DB10.DBW0) lub przeczytać czy też zapisać konkretną ilość bajtów z pożądanej przestrzeni.

Jeżeli czytamy większą ilość zmiennych rozsianych po całym bloku, to zdecydowanie lepiej przeczytać większą ilość danych a następnie wyłuskać je z otrzymanej tablicy bajtów, niż realizować wiele mniejszych odczytów. Zyska na tym szybkość i optymalność komunikacji. W przypadku biblioteki S7netplus mamy w zanadrzu świetny mechanizm “mapowania” bloku na strukturę lub klasę, o którym wspominam w dalszej części postu.

WAŻNA UWAGA. Jeżeli zdarzy się sytuacja, w której uda się poprawnie nawiązać połączenie a odczyt jednak nie będzie działał poprawnie to warto sprawdzić czy w konfiguracji hardware sterownika włączona jest funkcja zezwalająca na realizację komunikacji PUT/GET.
Metodę parametryzacji sterownika opisałem w tym poście

W przypadku wykorzystania metody Read w jej uproszczonej wersji, w której zapisujemy format zmiennej w zapisie sterownikowym otrzymamy od razu odpowiednią wartość. Jeżeli czytamy większą ilość danych i otrzymamy tablicę bajtów należy zadbać o konwersję formatów. Dane w sterowniku S7 (ze względu na historyczne zaszłości) przechowywane są w notacji BigEndian, natomiast w przypadku architektury komputerów PC mamy do czynienia z notacją LittleEndian.

Konwersji na szczęście nie musimy robić na piechotę. Z pomocą przyjdą nam metody rozszerzone zdefiniowane w bibliotece. Przykłady konwersji znajdziemy w manualu, o którym wspomniałem powyżej.

Po zakończeniu realizacji komunikacji (w przypadku komunikacji cyklicznej np. w momencie zamknięcia aplikacji) należy koniecznie zamknąć połączenie. W przypadku opisywanej biblioteki zrobimy to łatwo za pomocą metody Close();

Warto pamiętać, że jeżeli nie zamkniemy poprawnie połączenia i będziemy go nawiązywać ponownie – to oczywiście uda się nam to zrobić – jednak nie w nieskończoność. Otwarte połączenia będą nadal widziane przez sterownik jako istniejącej i po przekroczeniu liczby dozwolonych jednocześnie połączeń (zwykle 8-miu) sterownik odmówi nam nawiązania kolejnego połączenia. Oczywiście mowa tu o próbach połączenia w trakcie działania aplikacji. Zamknięcie aplikacji (a więc i zwolnienie zasobów zajmowanych przez bibliotekę) resetuje nawiązane połączenia.

Jest jeszcze jedna fajna cecha, o której warto wspomnieć w odniesieniu do tej biblioteki. Istnieją funkcje pozwalające na zapis/odczyt struktur i klas. Układamy wtedy w naszej klasie zmienne dokładnie według takiej kolejności jak mamy je zdefiniowane w bloku DB w sterowniku. Trzeba jedynie pamiętać o tym, aby skrupulatnie dobrać właściwe typy dla danych odwzorowujące zmienne w bloku. Wtedy możemy odczytywać/ zapisywać całą strukturę lub klasę za pomocą jednej metody. W przypadku odczytu otrzymamy również już skonwertowane wartości, które możemy dalej wykorzystywać. Dokładny opis tego rozwiązania znajduje się w manualu, o którym wspomniałem powyżej. Simple as that 🙂

Kod aplikacji do przetestowania jest oczywiście dostępny na github.

Wszystkie posty w tym cyklu:

Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – wstęp
Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – protokół S7 i konfiguracja sterownika
Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – projekty testowe
Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – biblioteka s7netplus
Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – biblioteka Sharp7 (Snap7)
Biblioteki .Net do komunikacji ze sterownikami PLC Siemens – biblioteka DotNetSiemensPlcToolboxLibrary

ZOSTAW ODPOWIEDŹ

Please enter your comment!
Please enter your name here