Używamy plików cookies (tzw. ciasteczka) by spersonalizować treść i ogłoszenia oraz by analizować ruch na stronie.  W sposób automatyczny dzielimy się informacjami o Twoim użyciu tego portalu z dostawcami ogłoszeń, którzy mogą połączyć te informacje z informacjami, które im udzieliłaś/łeś lub, które sami zebrali. Korzystanie z witryny bez zmiany ustawień dotyczących cookies oznacza, że będą one zamieszczane w Państwa urządzeniu końcowym.  Możecie Państwo dokonać w każdym czasie zmiany ustawień dotyczących cookies zmieniając opcje przeglądarki.

Jeszcze jeden sposób komunikacji z PLC

Przed paroma dniami otrzymałem maila od Sergio, który zwrócił moją uwagę na projekt WebVisu rozwijany przez Franka Benkerta w ramach SourceForge.net (https://sourceforge.net/projects/webvisu/). Autorowi udało się rozszyfrować zasady komunikacji pomiędzy sterownikiem, a standardowymi wizualizacjami webowymi opartymi o aplety Javy. Gdy już rozpracował protokół, przygotował kod, który odtwarza wizualizacje zrobione w CoDeSysie w dowolnej przeglądarce przy wykorzystaniu WYŁĄCZNIE JavaScriptu. Brzmi fascynująco? Bo jest!

Oto krótka ilustracja, o co w ogóle chodzi:

webvisu

Aby zobaczyć, jak to wszystko działa należy:

  1. Włączyć obsługę wizualizacji webowych w Target Settings->Visualization->Web visualization
  2. Przygotować wizualizację w CoDeSys, wgrać ją wraz z programem na sterownik,
  3. Pobrać ze strony sourceforge plik WebVisu.html
  4. Wgrać przez FTP ww. plik na sterownik do katalogu ‘webserv’
  5. W przeglądarce wpisać adres: „http://IPsterownika/webserv/webvisu.html"

Dokonania Franka Benkerta są dla mnie niesamowite z 2 powodów:

  1. Pokazał sposób komunikacji ze sterownikiem PLC, o którym nie wspomina żadna dokumentacja,
  2. Pokazał możliwość otrzymania ze sterownika informacji o miejscu umieszczenia w pamięci (adresie) zmiennych, którym nie przypisano adresu w kodzie programu.

 

 

Zacznijmy od protokołu

Komunikacja ze sterownikiem odbywa się przez zapytania POST wysyłane na adres /plc/webvisu.htm.

Aby odczytywać zmienne (czyli również stany wejść/wyjść) zapytanie powinno być ustrukturyzowane w następujący sposób:

| 0 | liczba-adresów-do-odczytania
| nr-zmiennej-licząc-od-zera | adres | adres | ilość-bajtów | rodzaj-zmiennej |

Odczytanie stanów 2 pierwszych wyjść na moim sterowniku odbywa się w następujący sposób:

|0|2|
0|2|48|0|0|
1|2|29|0|0|

Odpowiedź sterownika to|0|0|

Adresu, ilości bajtów i rodzaju zmiennej wcale nie trzeba znać. Dane te publikowane są przez sterownik w pliku plc_visu.xml. Piszę o tym w drugiej części artykułu.

Zmiana wartości zmiennej odbywa się komendą:

|1| liczba-adresów-do-zmiany
|nr-zmiennej-licząc-od-zera| adres | adres | ilość-bajtów | rodzaj-zmiennej | wartość |

Zmiana wartości zmiennej typu BYTE zaadresowanej przeze mnie na %MB6 na 7 wykonana zostanie komendą
|1|1|0|0|6|1|2|7|

Dla takiego amatora, jak ja, który nie lubi MODBUSA, takie zasady komunikacji są przejrzyste i proste. Do odczytania stanów 100 wyjść wystarczy prosty program w PYTHONie:

#!/usr/bin/python
import requests 	#you might need to install requests separatelly
req = "|0|100"
for num in range (0,99):
        req+= "|"+str(num)+"|2|"+str(num)+"|1|2"
req+= "|"
r = requests.post('http://192.168.1.3/PLC/webvisu.htm', data=req)
print r.text

Odpowiedź sterownika to:

|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|….

Czas wykonania takiego skryptu to 0.2 sek.

W javascriptcie (z jQuery) odczytanie danych wyglądałby następująco:

<script>
req = "|0|100";
for (var i=0; i<100; i++) {
req+="|"+i+"|2|"+i+"|1|2";
}
req += "|"
console.log(req);
$.ajax({
	type: "POST",
	url: "http://192.168.1.3/plc/webvisu.htm",
	data: req,
	success: function (data) {
		console.log(data);
	}
});
</script>

Przewaga tego sposobu nad wykorzystywanym przeze mnie dotychczas READPI/WRITEPI jest dość oczywista. Można bardzo szybko odczytywać dużą ilość zmiennych. To duże uproszczenie wobec konieczności każdorazowego konstruowania zapytania „READPI?ADR=…..&FORMAT=%d”. Tak naprawdę powinienem teraz przepisać całą moją wtyczkę i wszystkie programy…

Adresowanie

Poniższe 4 paragrafy są teorią dla dociekliwych. Niecierpliwi mogą od razu przewinąć do słów „Nie trzeba jednak tego wszystkiego wiedzieć”

Każda z odczytywanych lub zapisywanych zmiennych przedstawiana jest jako:

| adres | adres | ilość-bajtów | rodzaj-zmiennej |

Wygląda na to, że pierwsza część adresu to grupa. Na moim sterowniku zmienne, którym przypisałem adres (np. przez AT %MB0 : BYTE) umieszczone są w grupie 0, wejścia – 1, wyjścia – 2, inne zmienne użyte w programie – 4.

Pierwsze wyjście DO ma u mnie adres %QX3.0, jako że pierwsze trzy ‘słowa’ zajęte zostały przez moduł komunikacji RS232. 3 słowa to 3x16 bitów = 48 bitów, licząc od 0 to 0-47. Stąd też adres mojego %QX3.0 to 2,48.

Ilość bajtów zależy od rodzaju zmiennej. Dla fizycznych wejść i wyjść jest to 0 (?), dla BOOL i BYTE – 1, WORD – 2, DWORD – 4, STRING – o 1 więcej niż długość.

Rodzaje zmiennej określone są następująco: BOOL – 0, INT – 1, BYTE – 2, WORD – 3, DINT – 4, DWORD – 5, REAL – 6, TIME – 7, STRING – 8, ARRAY – 9. Choć określenie rodzaju nie jest krytyczne, tj. można odczytywać całą pamięć kawałkami 1-bajtowymi określając rodzaj jako 2. Właściwe podanie rodzaju zapewnia jednak odpowiednio sformatowaną odpowiedź. 4-znakowy string, może wrócić jako „abcd”, gdy podamy rodzaj 8, lub 47821, gdy podamy rodzaj 5.

Nie trzeba jednak tego wszystkiego wiedzieć. Kolejna rzecz, którą opisuje Frank Benkert dotyczy publikowania przez sterownik adresów zmiennych użytych w wizualizacji.

Wyobraźmy sobie prosty program z następującymi zmiennymi:

PROGRAM PLC_PRG
VAR
	AddressedVariable  AT %MB0 : BOOL;
	StringVariable	: STRING(5);
	ByteVariable : BYTE;
	WordVariable: WORD;
END_VAR

W programie takim tworzymy wizualizację „PLC_VISU” z 4 elementami wyświetlającymi wartości ww. zmiennych, oraz z piątym, który prezentuje wartość pierwszego wyjścia w sterowniku. Gdy wgramy taki program do sterownika (zakładając, że opcja Target Settings->Visualization->Web visualization jest zaznaczona), w katalogu PLC wygenerowany zostanie plik „plc_visu.xml”.

W dolnej części tego pliku znajdziemy:

<variablelist>
	<variable name="PLC_PRG.AddressedVariable">0,0,1,0</variable>
	<variable name="PLC_PRG.StringVariable">4,0,6,8</variable>
	<variable name="PLC_PRG.ByteVariable">4,6,1,2</variable>
	<variable name="PLC_PRG.WordVariable">4,7,2,3</variable>
	<variable name=".OUT0">2,0,0,0</variable>
</variablelist>

Oto adresy, których szukaliśmy! Możemy teraz odczytać ich wartości – przy pomocy zapytań “|0|…”, READPI czy też MODBUSA. Dla mnie jest to odkrycie przełomowe. Oto mam dostęp do danych bez konieczności wcześniejszego żmudnego adresowania w sterowniku.  Możemy odczytać wartość StringVariable wysyłając "|0|1|0|4|0|6|8|" lub wszystkich ww. adresów poprzez"|0|5|0|0|0|1|0|1|4|0|6|8|2|4|6|1|2|3|4|7|2|3|4|2|0|0|0|"

Zamiast więc przypisywać każdej zmiennej, którą chcemy odczytywać i zmieniać z zewnątrz, adresu poprzez „VAR variable AT %M….”, możemy umieścić na wizualizacji element, prezentujący jej wartość. Po wgraniu wizualizacji na sterownik, adres takiej zmiennej będzie do znalezienia w pliku nazwa_vizualizacji.xml.

Ważna uwaga: umieszczenie zmiennych i bloków funkcyjnych w pamięci sterownika ustalane jest przez kompilator w czasie generowania kodu programu. Każda zmiana w samym programie może prowadzić do przypisania innych adresów. Wszelkie programy integrujące powinny więc prowadzić komunikację w oparciu o adresy pozyskane każdorazowo z pliku xml… Dla programistów to jednak nic trudnego ;)

Wielkie podziękowania dla Sergio za podrzucenie mi tematu ;)