Modbus RTU/TCP ile Endüstriyel Sensör ve Aktüatör Entegrasyonu: Katmera Üzerinde Pratik Rehber
Fabrika otomasyonu, enerji izleme ve SCADA sistemlerinin vazgeçilmezi Modbus protokolünü Katmera kartlarınızda kullanmayı öğrenin. RS-485 üzerinden RTU, Ethernet üzerinden TCP — adım adım Python örnekleriyle.
Modbus RTU/TCP ile Endüstriyel Sensör ve Aktüatör Entegrasyonu: Katmera Üzerinde Pratik Rehber
Endüstriyel otomasyon dünyasında onlarca yıldır varlığını sürdüren Modbus protokolü, bugün hâlâ SCADA sistemleri, PLC'ler, enerji analizörleri ve akıllı sensörlerin büyük çoğunluğu tarafından kullanılmaktadır. Katmera kartlarının güçlü işlemcisi ve çoklu seri port desteği sayesinde Modbus Master (veya Slave) rolünü üstlenip sahadan gelen verileri gerçek zamanlı olarak toplayabilir, işleyebilir ve buluta iletebilirsiniz.
Modbus Protokolüne Genel Bakış
Neden Hâlâ Modbus?
Modbus, 1979'da Modicon tarafından geliştirilmiş olmasına rağmen güncelliğini korur. Bunun nedenleri:
Modbus Veri Modeli
| Nesne Türü | Adres Aralığı | Erişim | Açıklama |
|------------|---------------|--------|----------|
| Coil (Bobin) | 00001–09999 | Okuma/Yazma | 1-bit dijital çıkış |
| Discrete Input | 10001–19999 | Sadece Okuma | 1-bit dijital giriş |
| Input Register | 30001–39999 | Sadece Okuma | 16-bit analog giriş |
| Holding Register | 40001–49999 | Okuma/Yazma | 16-bit genel amaçlı register |
Donanım Kurulumu
Modbus RTU için RS-485 Bağlantısı
Katmera kartlarındaki UART portuna bir RS-485 dönüştürücü modülü bağlamanız gerekir.
Bağlantı şeması:
Katmera UART TX ──► RS-485 Modülü DI
Katmera UART RX ◄── RS-485 Modülü RO
Katmera GPIO ──► RS-485 Modülü DE/RE (yön kontrolü)
GND ─── GND
3.3V ─── VCC
RS-485 hattında terminal direnci:
Modbus TCP için Ethernet Bağlantısı
Ethernet destekli Modbus slave cihazları (akıllı analizörler, dönüştürücüler) için doğrudan ağ bağlantısı yeterlidir. Varsayılan TCP portu 502'dir.
Python ile Modbus RTU — pymodbus Kurulumu
# Sanal ortam oluştur ve aktifleştir
python3 -m venv modbus-env
source modbus-env/bin/activate# pymodbus kur (v3.x)
pip install pymodbus pyserial
Holding Register Okuma (RTU)
from pymodbus.client import ModbusSerialClient
import struct# Seri port ayarları
client = ModbusSerialClient(
port='/dev/ttyS1', # Katmera'da ilgili UART portu
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1
)
if not client.connect():
print("Bağlantı kurulamadı!")
exit(1)
# Slave ID 1, adres 0'dan başlayarak 2 register oku
result = client.read_holding_registers(address=0, count=2, slave=1)
if not result.isError():
raw = result.registers
# İki 16-bit register'ı 32-bit IEEE 754 float'a dönüştür
value = struct.unpack('>f', struct.pack('>HH', raw[0], raw[1]))[0]
print(f"Okunan değer: {value:.2f}")
else:
print(f"Hata: {result}")
client.close()
Coil (Dijital Çıkış) Yazma (RTU)
from pymodbus.client import ModbusSerialClientclient = ModbusSerialClient(
port='/dev/ttyS1',
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1
)
client.connect()
# Slave ID 1, coil adres 0'ı aktif et (röleyi kapat)
result = client.write_coil(address=0, value=True, slave=1)
if not result.isError():
print("Röle başarıyla aktif edildi.")
else:
print(f"Yazma hatası: {result}")
client.close()
Python ile Modbus TCP
Holding Register Okuma (TCP)
from pymodbus.client import ModbusTcpClient# Modbus TCP slave cihazının IP adresi
client = ModbusTcpClient(host='192.168.1.100', port=502)
if not client.connect():
print("TCP bağlantısı kurulamadı!")
exit(1)
# Unit ID (slave ID) 1, adres 100'den 10 register oku
result = client.read_holding_registers(address=100, count=10, slave=1)
if not result.isError():
for i, val in enumerate(result.registers):
print(f"Register[{100 + i}] = {val}")
else:
print(f"Hata: {result}")
client.close()
Çoklu Register Yazma (TCP)
from pymodbus.client import ModbusTcpClientclient = ModbusTcpClient(host='192.168.1.100', port=502)
client.connect()
# Adres 200'den itibaren 3 register'a değer yaz
values = [1500, 2000, 500]
result = client.write_registers(address=200, values=values, slave=1)
if not result.isError():
print("Değerler başarıyla yazıldı.")
else:
print(f"Yazma hatası: {result}")
client.close()
Gerçek Dünya Senaryosu: Enerji Analizörü İzleme
Bir enerji analizöründen faz gerilimleri, akımlar ve güç değerlerini periyodik olarak okuyarak MQTT ile merkezi sisteme gönderen tam bir uygulama:
import time
import struct
import json
import paho.mqtt.client as mqtt
from pymodbus.client import ModbusSerialClient# --- Yapılandırma ---
SERIAL_PORT = '/dev/ttyS1'
BAUD_RATE = 9600
SLAVE_ID = 1
MQTT_BROKER = 'localhost'
MQTT_TOPIC = 'fabrika/enerji/panel1'
READ_INTERVAL = 5 # saniye
def regs_to_float(high: int, low: int) -> float:
"""İki 16-bit Modbus register'ını IEEE 754 float'a çevirir."""
raw = struct.pack('>HH', high, low)
return round(struct.unpack('>f', raw)[0], 3)
def read_energy_data(client: ModbusSerialClient) -> dict | None:
"""Enerji analizöründen temel ölçümleri okur."""
# Analizör register haritasına göre adresler (örnek: CHINT DTSD666)
result = client.read_holding_registers(address=0, count=20, slave=SLAVE_ID)
if result.isError():
return None
r = result.registers
return {
'v_a': regs_to_float(r[0], r[1]), # Faz A gerilimi (V)
'v_b': regs_to_float(r[2], r[3]), # Faz B gerilimi (V)
'v_c': regs_to_float(r[4], r[5]), # Faz C gerilimi (V)
'i_a': regs_to_float(r[6], r[7]), # Faz A akımı (A)
'i_b': regs_to_float(r[8], r[9]), # Faz B akımı (A)
'i_c': regs_to_float(r[10], r[11]), # Faz C akımı (A)
'p_total': regs_to_float(r[12], r[13]),# Toplam aktif güç (kW)
'pf': regs_to_float(r[18], r[19]), # Güç faktörü
}
# MQTT istemcisi
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.connect(MQTT_BROKER, 1883)
mqttc.loop_start()
# Modbus istemcisi
modbus = ModbusSerialClient(
port=SERIAL_PORT, baudrate=BAUD_RATE,
bytesize=8, parity='N', stopbits=1, timeout=1
)
modbus.connect()
print("Enerji izleme başladı...")
try:
while True:
data = read_energy_data(modbus)
if data:
payload = json.dumps(data)
mqttc.publish(MQTT_TOPIC, payload, qos=1)
print(f"Yayımlandı: {payload}")
else:
print("Veri okunamadı, yeniden deniyor...")
time.sleep(READ_INTERVAL)
except KeyboardInterrupt:
print("Durduruluyor...")
finally:
modbus.close()
mqttc.loop_stop()
mqttc.disconnect()
Modbus Slave (Sunucu) Olarak Katmera
Katmera'yı bir Modbus Slave olarak yapılandırarak diğer PLC veya SCADA sistemlerinin veri okumasına izin verebilirsiniz:
from pymodbus.server import StartTcpServer
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.datastore import ModbusSequentialDataBlock
import threading, time, random# Veri bloklarını tanımla
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [0] * 100), # Discrete Inputs
co=ModbusSequentialDataBlock(0, [0] * 100), # Coils
hr=ModbusSequentialDataBlock(0, [0] * 100), # Holding Registers
ir=ModbusSequentialDataBlock(0, [0] * 100), # Input Registers
)
context = ModbusServerContext(slaves=store, single=True)
def update_sensor_data():
"""Simüle edilmiş sensör verisini güncelle."""
while True:
temp = int(random.uniform(20.0, 35.0) * 10) # 0.1°C hassasiyet
humidity = int(random.uniform(40.0, 80.0) * 10)
store.setValues(4, 0, [temp, humidity]) # Holding register 0 ve 1
time.sleep(2)
# Arka planda sensör verisini güncelle
t = threading.Thread(target=update_sensor_data, daemon=True)
t.start()
print("Modbus TCP Slave başlatılıyor — port 502...")
StartTcpServer(context=context, address=('0.0.0.0', 502))
Hata Ayıklama İpuçları
RS-485 Hat Sorunları
Protokol Analizi
# Seri hattı ham olarak izle (debug için)
sudo apt install -y minicom
minicom -D /dev/ttyS1 -b 9600# Wireshark ile Modbus TCP paketlerini yakala
sudo wireshark -i eth0 -k -f "tcp port 502"
Yaygın Hata Kodları
| Kod | İsim | Açıklama |
|-----|------|----------|
| 0x01 | Illegal Function | İstenen fonksiyon kodu desteklenmiyor |
| 0x02 | Illegal Data Address | Adres mevcut değil veya erişim dışı |
| 0x03 | Illegal Data Value | Gönderilen değer geçersiz aralıkta |
| 0x04 | Slave Device Failure | Slave cihazda iç hata oluştu |
| 0x06 | Slave Device Busy | Slave meşgul, istek işlenemiyor |
Özet
Katmera kartları; çoklu UART portu, Gigabit Ethernet ve güçlü işlemcisiyle Modbus tabanlı endüstriyel sistemler için ideal bir kenar bilişim platformu oluşturur. Bu rehberdeki örneklerle:
Bir sonraki adım olarak toplanan verileri InfluxDB ve Grafana ile görselleştirerek gerçek zamanlı endüstriyel dashboard'lar oluşturabilirsiniz.
