← Blog Chmura

Modbus RTU i TCP w modernizacji przemysłowego IoT: łączenie starych sterowników PLC z Azure

Wejdź do dowolnej fabryki wybudowanej przed 2010 rokiem, a spotkasz tego samego ducha: szafę sterowniczą pełną sterowników PLC, które wciąż bezbłędnie prowadzą linię, mówią w Modbusie i nigdy nie były projektowane z myślą o dotknięciu publicznego internetu. Ich wymiana rzadko wchodzi w grę. Nakłady inwestycyjne są ogromne, przestój nie do zaakceptowania, a szczerze mówiąc te sterowniki przetrwały trzy pokolenia strategii IT. Rozsądną drogą naprzód jest retrofit: zostaw sterowniki PLC w spokoju, zainstaluj bramkę brzegową i przesyłaj dane, które po cichu produkują od trzydziestu lat, do Azure IoT Hub, gdzie mogą wreszcie zacząć być przydatne.

Ten wpis to przewodnik terenowy, którego brakowało nam przy pierwszym projekcie brownfield. Omówimy Modbus RTU i TCP na poziomie bitów, błędy w okablowaniu RS-485, które zjadają weekendy, kody funkcji, których faktycznie użyjesz, pułapki adresowania, które zrujnowały więcej integratorów niż cokolwiek innego, oraz działający wzorzec bramki ESP32 łączącej Modbus z MQTT i Azure. Jeśli rozważasz opcje modernizacji przemysłowego IoT, zacznij tutaj.

Dlaczego Modbus jest wciąż wszędzie

Modbus został opublikowany przez Modicon w 1979 roku. Jest to protokół żądanie/odpowiedź, master/slave (nowocześniejsza terminologia to klient/serwer) i nie niesie żadnego zabezpieczenia, żadnego uwierzytelniania i niemal żadnych metadanych. To powinien być problem. W praktyce to właśnie dlatego Modbus wygrał. Specyfikacja mieści się na kilkudziesięciu stronach, każdy producent PLC ją implementuje, a format ramki jest tak prosty, że można go zdekodować oscyloskopem i papierowym notatnikiem.

Modbus spotkasz w dwóch głównych odmianach. Modbus RTU działa po RS-485 (czasami RS-232) z prędkością od 9600 do 115200 bodów, z kompaktową ramką binarną i sumą kontrolną CRC-16. Modbus TCP opakowuje tę samą jednostkę danych protokołu w pakiet TCP na porcie 502, rezygnuje z CRC (integralnością zajmuje się TCP) i dodaje 7-bajtowy nagłówek MBAP. Istnieje też Modbus ASCII, którego, miejmy nadzieję, nigdy nie spotkasz.

Kody funkcji, których naprawdę potrzebujesz

Modbus definiuje około dwudziestu kodów funkcji, ale cztery z nich pokrywają mniej więcej 95 procent rzeczywistych integracji:

  • 0x03 Read Holding Registers — koń roboczy. 16-bitowe rejestry do odczytu/zapisu. Używaj do nastaw, konfiguracji i większości wartości analogowych.
  • 0x04 Read Input Registers — 16-bitowe rejestry tylko do odczytu. Często używane do odczytów z czujników (temperatura, ciśnienie, przepływ).
  • 0x06 Write Single Register — zapis jednego 16-bitowego rejestru. Atomowy, prosty, idealny do zmiany nastaw.
  • 0x10 Write Multiple Registers — zapis ciągłego bloku. Przydatny przy wartościach wielosłowowych (32-bitowe liczby zmiennoprzecinkowe, znaczniki czasu), tak aby zapis był atomowy z perspektywy PLC.

Czasami spotkasz też 0x01 Read Coils i 0x05 Write Single Coil do wejść/wyjść logicznych oraz 0x02 Read Discrete Inputs do wejść cyfrowych tylko do odczytu. Unikaj diagnostycznych kodów funkcji (0x08, 0x11), o ile nie masz ku temu konkretnego powodu; wsparcie producentów bywa nierówne, a one i tak nie zarobią na swoje utrzymanie.

Okablowanie RS-485: tam umierają projekty

Jeśli Twoja magistrala Modbus RTU jest zawodna, przyczyną prawie nigdy nie jest protokół. To warstwa fizyczna. RS-485 to para różnicowa (A i B, czasem oznaczane D+ i D-), opcjonalnie ze wspólnym odniesieniem masy, zdolna do pracy na 1200 metrach przy 9600 bodach, jeśli uszanujesz trzy zasady.

1. Topologia musi być łańcuchem (daisy chain)

Żadnych gwiazd. Żadnych odgałęzień dłuższych niż kilka centymetrów. Kabel wchodzi do urządzenia na jednej parze zacisków i wychodzi na następnej. Każda topologia gwiazdy w produkcji to przyszła awaria czekająca na wilgotny poranek.

2. Terminacja na obu końcach

Rezystory 120 omów pomiędzy A i B na dwóch fizycznych końcach magistrali. Nie po środku. Nie przy każdym urządzeniu. Niektóre transceivery i sterowniki PLC mają przełącznik DIP lub zworkę do włączenia wewnętrznej terminacji — sprawdź, nie zakładaj. Bez terminacji dostaniesz odbicia, które wyglądają jak losowe błędy CRC.

3. Spolaryzuj linię w stanie spoczynku

Gdy żaden transceiver nie steruje magistralą, A i B pływają. Szum jest interpretowany jako bity startu. Podciągnij A do 5 V przez około 680 omów, a B do masy przez tę samą wartość, zastosowane raz na magistrali (zwykle przy masterze). Nowoczesne transceivery jak MAX13487 realizują polaryzację failsafe wewnętrznie, ale większość starych instalacji nie.

Używaj ekranowanej skrętki, uziemiaj ekran tylko z jednej strony i trzymaj kabel z dala od wyjść przemienników częstotliwości (VFD) i styczników. Widzieliśmy, jak 200-metrowy odcinek przeszedł z 80 procent błędów CRC do zera po przesunięciu go 30 cm od kabla silnikowego.

Adresowanie: zmora integratorów Modbusa

To miejsce, w którym każdy integrator obrywa przynajmniej raz. Specyfikacja Modbus używa na przewodzie adresowania liczonego od zera. Wielu producentów PLC dokumentuje swoje mapy rejestrów, używając numeracji od jedynki, czasem z wiodącym prefiksem wskazującym typ rejestru.

  • Udokumentowany adres 40001 oznacza rejestr holding, adres 0 na przewodzie.
  • Udokumentowany adres 40101 oznacza rejestr holding, adres 100 na przewodzie.
  • Udokumentowany adres 30005 oznacza rejestr input, adres 4 na przewodzie.

Jeśli odczyty zwracają bzdury lub wartości przesunięte o jeden, Twoją pierwszą hipotezą powinno być liczenie od jedynki kontra od zera. Drugą hipotezą powinna być kolejność bajtów. Modbus przesyła każdy 16-bitowy rejestr jako big-endian, ale wartości 32-bitowe (liczby zmiennoprzecinkowe, longi) rozciągają się na dwa rejestry, a producenci nie zgadzają się co do kolejności słów. Możesz zobaczyć ABCD, CDAB, BADC lub DCBA. Schneider zwykle używa jednej kolejności, Siemens innej, a tani chiński falownik kupiony na AliExpress użyje tego, na co inżynier miał ochotę danego ranka. Potwierdź na znanej wartości — niech PLC wyświetli 1.0 jako float i odczytaj obie kolejności słów, aby zobaczyć, która daje wzorzec bitowy IEEE 754 0x3F800000.

Ze znakiem kontra bez znaku to trzecia częsta pułapka. Odczyt temperatury -5 wygląda jak 65531, jeśli zdekodujesz rejestr jako bez znaku. Zawsze sprawdzaj w dokumentacji producenta typ danych dla każdego rejestru i odpowiednio konfiguruj mapę bramki.

Sprzęt bramki: ESP32 kontra rozwiązania komercyjne

Przy retrofitach o małej liczbie kanałów, w obrębie jednej szafy, ESP32 z izolowanym transceiverem RS-485 jest trudny do pobicia pod względem kosztu i elastyczności. Typowa lista materiałowa wygląda tak:

  • Moduł ESP32-WROOM-32 lub ESP32-S3
  • Transceiver RS-485 MAX3485 lub ADM2483 (izolowany galwanicznie)
  • Rezystor terminujący 120 omów z przełącznikiem DIP
  • Obudowa na szynę DIN z zasilaniem 24 VDC i izolowanym stabilizatorem 3,3 V
  • Opcjonalny PHY Ethernet (LAN8720), jeśli Wi-Fi w zakładzie jest nie do zaakceptowania

Całkowity koszt części to około 25 do 40 EUR, firmware jest w pełni pod Twoją kontrolą, a aktualizacje OTA możesz wdrażać przez bliźniaki urządzeń (device twins) Azure IoT Hub. Regularnie budujemy tego rodzaju urządzenia podłączone jako fundament większych flot.

Komercyjne bramki od Moxa, Advantech czy HMS Networks mają sens, gdy potrzebujesz certyfikatów (UL, ATEX), redundantnego zasilania, zakresów temperatur przemysłowych, albo gdy dział zakupów klienta po prostu nie zatwierdzi niestandardowej płytki. Kosztują od 400 do 1500 EUR za węzeł, a firmware jest czarną skrzynką. Kompromisem jest komfort operacyjny w zamian za uzależnienie od dostawcy.

Wzorzec bramki brzegowej: Modbus do MQTT do Azure

Architektura, którą wdrażamy, wygląda tak:

  1. Bramka brzegowa odpytuje urządzenia Modbus według harmonogramu (od 1 do 60 sekund w zależności od sygnału).
  2. Zdekodowane wartości są normalizowane do jednostek inżynierskich i oznaczane stabilnym identyfikatorem.
  3. Bramka publikuje JSON przez MQTT do Azure IoT Hub, używając SDK urządzenia.
  4. IoT Hub kieruje wiadomości do Event Hubs, następnie do Stream Analytics lub bezpośrednio do magazynu szeregów czasowych.
  5. Pulpit analityczny wizualizuje trendy i wyzwala alerty.

Ten wzorzec jest kręgosłupem niemal każdego potoku danych IoT w Azure, który budujemy. Więcej o provisioningu Huba przeczytasz w naszym artykule o Azure IoT Hub dla producentów urządzeń.

Działający kod klienta Modbus na ESP32

Poniżej znajduje się okrojony, ale realistyczny szkic w frameworku Arduino, wykorzystujący bibliotekę eModbus. Odpytuje cztery rejestry holding ze slave'a o adresie 1, dekoduje je i publikuje JSON przez MQTT.

#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ModbusClientRTU.h>

#define RS485_RX  16
#define RS485_TX  17
#define RS485_DE  4

HardwareSerial RS485(2);
ModbusClientRTU MB(RS485_DE);
WiFiClient net;
PubSubClient mqtt(net);

uint32_t lastPoll = 0;
const uint8_t SLAVE_ID = 1;
const uint16_t START_REG = 0;   // 40001 w dokumentacji producenta
const uint16_t COUNT = 4;

void onData(ModbusMessage response, uint32_t token) {
  uint16_t regs[4];
  for (uint8_t i = 0; i < COUNT; i++) {
    response.get(3 + i * 2, regs[i]);
  }
  // Zamiana slow dla floata ABCD (zalezne od producenta)
  union { uint32_t u; float f; } conv;
  conv.u = ((uint32_t)regs[0] << 16) | regs[1];
  float temperature = conv.f;
  int16_t pressure = (int16_t)regs[2];   // ze znakiem
  uint16_t status   = regs[3];

  char payload[160];
  snprintf(payload, sizeof(payload),
    "{"t":%.2f,"p":%d,"s":%u,"ts":%lu}",
    temperature, pressure, status, millis());
  mqtt.publish("devices/gw01/telemetry", payload);
}

void onError(Error err, uint32_t token) {
  Serial.printf("Modbus error 0x%02X token %un", (int)err, token);
}

void setup() {
  Serial.begin(115200);
  RS485.begin(19200, SERIAL_8E1, RS485_RX, RS485_TX);
  MB.onDataHandler(&onData);
  MB.onErrorHandler(&onError);
  MB.setTimeout(1000);
  MB.begin(RS485);

  WiFi.begin("plant-iot", "secret");
  while (WiFi.status() != WL_CONNECTED) delay(200);
  mqtt.setServer("hub.azure-devices.net", 8883);
  mqtt.connect("gw01", "hub.azure-devices.net/gw01/?api-version=2021-04-12", "<SAS>");
}

void loop() {
  mqtt.loop();
  if (millis() - lastPoll > 5000) {
    lastPoll = millis();
    Error e = MB.addRequest(0x1234, SLAVE_ID, READ_HOLD_REGISTER, START_REG, COUNT);
    if (e != SUCCESS) Serial.printf("Queue err 0x%02Xn", (int)e);
  }
}

Jest to celowo minimalne. Firmware produkcyjny dodaje TLS przez główny certyfikat CA Azure, rotację tokenów SAS, obsługę bliźniaka urządzenia, wykładniczy backoff przy utracie Wi-Fi oraz watchdog. Ale pętla odpytywania i logika dekodowania pozostają w zasadzie w tym kształcie.

Strategia odpytywania i limity szybkości

Modbus RTU jest półdupleksowy. W danej chwili nadaje tylko jedno urządzenie. Przy 19200 bodach typowy odczyt 10 rejestrów plus czas na przełączenie zajmuje około 30 ms. Z 20 slave'ami na magistrali odpytywanie każdego sygnału co sekundę jest realistyczne; odpytywanie co 100 ms już nie. Grupuj rejestry w ciągłe bloki dla każdego slave'a, aby jedno żądanie zwracało wiele wartości. Rozkładaj slave'y w czasie, aby nie kończyć jednego cyklu odpytywania i natychmiast rozpoczynać następnego — zostaw margines na ponowienia.

Przy systemach o dużej liczbie kanałów rozmieść wiele segmentów RS-485 za jedną bramką, z osobnym UART-em na segment, albo użyj bramki Modbus TCP, która pozwala zrównoleglić pracę wielu slave'ów w sieci przełączanej.

Obsługa błędów i odporność

Traktuj każdy odczyt Modbus jako coś, co się nie powiedzie. Zbuduj bramkę wokół trzech zasad:

  1. Buforuj ostatnie znane dobre wartości ze znacznikiem czasu. Gdy odpytanie się nie powiedzie, publikuj wartość z bufora z flagą jakości (dobra, nieświeża, zła), zamiast porzucać wiadomość.
  2. Buforuj telemetrię lokalnie, gdy połączenie z chmurą zniknie. Partycja 4 MB na ESP32 mieści godziny skompresowanej historii. Odtwórz ją po ponownym połączeniu.
  3. Alarmuj przy awariach na poziomie protokołu, nie tylko przy brakujących wartościach. Slave zwracający kod wyjątku 0x02 (illegal data address) oznacza, że Twoja mapa jest błędna, a nie że czujnik jest martwy.

Bezpieczeństwo: Modbus nie ma żadnego

Każdy master Modbus może zapisywać do każdego rejestru każdego slave'a na magistrali. Nie ma uwierzytelniania, nie ma szyfrowania, nie ma pojęcia operacji uprzywilejowanej. Modbus TCP odsłania tę samą sytuację w całej sieci IP. Jedynym bezpiecznym założeniem jest, że segment Modbus jest domyślnie wrogi i musi być odizolowany.

  • Umieść bramkę i sterowniki PLC w dedykowanej sieci VLAN bez trasy do internetu innej niż przez samą bramkę.
  • Bramka terminuje TLS do Azure. Ruch przychodzący z chmury musi podróżować wyłącznie przez podpisane aktualizacje bliźniaka urządzenia lub metody bezpośrednie, nigdy jako surowy TCP.
  • Nigdy nie wystawiaj portu 502 Modbus TCP do publicznego internetu. Tak, Shodan znajduje ich tysiące.
  • Jeśli potrzebujesz możliwości zapisu z chmury, obwaruj ją serwerowym silnikiem reguł, który weryfikuje żądaną nastawę względem bezpiecznych zakresów, zanim w ogóle dotrze do bramki.

Głębszy kontekst dotyczący bezpieczeństwa protokołów w całym stosie znajdziesz w naszym przeglądzie protokołów przemysłowych i tego, gdzie się sprawdzają.

Przykład z życia: 30-letnie PLC w zakładzie brownfield

Rozważmy typowy retrofit, który wykonaliśmy kilkukrotnie: linię przetwarzania metali zbudowaną na początku lat 90. Sześć sterowników Allen-Bradley SLC 500 steruje linią, każdy z kartą adaptera Modbus RTU dodaną przy wcześniejszej modernizacji. Klient chce widoczności OEE, analizy przyczyn źródłowych przestojów i pulpitu utrzymania ruchu. Wymiana sterowników kosztowałaby powyżej 400 000 EUR i wymagałaby sześciu tygodni przestoju. Żadne z tego nie wchodzi w grę.

Retrofit wyglądał tak:

  1. Dwie bramki ESP32-S3 w obudowach na szynę DIN, po jednej na pomieszczenie elektryczne, każda obsługująca trzy PLC na łańcuchowej magistrali RS-485.
  2. Mapy rejestrów producenta odtworzone metodą inżynierii wstecznej względem istniejącego HMI; 87 sygnałów oznaczonych w całej linii (prądy silników, ciśnienia hydrauliczne, liczniki cykli, bity usterek).
  3. Odpytywanie co 2 s dla sygnałów wysokiego priorytetu, co 30 s dla wolnozmiennych.
  4. MQTT do Azure IoT Hub, kierowany do Time Series Insights i Power BI.
  5. Niestandardowy pulpit w React dla zespołu utrzymania ruchu, zintegrowany z istniejącym CMMS przez webhook.

Cały projekt: dziewięć tygodni, koszt sprzętu poniżej 5000 EUR, zero zmian firmware'u PLC, zero przestoju produkcyjnego podczas uruchamiania. W ciągu trzech miesięcy pulpit zwrócił się, przypisując 14 godzin niewyjaśnionego przestoju miesięcznie do jednego przerywanego zaworu hydraulicznego, który przez poprzednie dwa lata obwiniano o trzy różne rzeczy.

Kiedy wyjść poza Modbus

Modbus to dobry transport dla okresowych danych liczbowych. Ma problem z sygnałami sterowanymi zdarzeniami, dużymi ładunkami i wszelkiego rodzaju ustrukturyzowanymi metadanymi. Jeśli Twój retrofit obejmuje widma drgań, dane z wizji maszynowej lub cokolwiek poniżej sekundy, zaplanuj OPC UA lub równoległą sieć czujników mostkowaną w bramce. Często uruchamiamy Modbus równolegle z niestandardowymi węzłami czujnikowymi IoT na tej samej bramce brzegowej, przy czym bramka harmonizuje oba do jednego schematu po stronie chmury.

Wprowadź swój zakład brownfield do sieci

Retrofit Modbus to droga o najniższym ryzyku i najszybszym zwrocie, prowadząca od starej hali produkcyjnej do nowoczesnej platformy danych. Wykonany dobrze, zwraca się w ciągu roku i otwiera dekadę analityki na sprzęcie, który już posiadasz. Wykonany źle, produkuje ścianę błędów CRC i pulpit, któremu nikt nie ufa. Różnica tkwi w głębi inżynierii — w okablowaniu, mapie rejestrów, dyscyplinie odpytywania i schemacie po stronie chmury.

FSS projektuje i wdraża retrofity przemysłowego IoT kompleksowo, od doboru kabla RS-485 przez pulpity Azure po integracje z systemami zewnętrznymi. Jeśli masz szafę pełną sterowników PLC i zaległy stos pytań bez odpowiedzi o to, co one robią, porozmawiaj z naszym zespołem urządzeń podłączonych i pozwól nam przygotować pilotaż dla jednej linii.