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:
Basit ve sağlam yapı: Düşük bant genişliğinde bile güvenilir çalışır.Evrensel destek: Neredeyse tüm endüstriyel ekipman üreticileri Modbus destekler.İki fiziksel katman: RS-485 seri hat (RTU) veya Ethernet (TCP).Açık standart: Lisans gerektirmez, belgeler herkese açıktır.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:
Hat uzunluğu 10 m'yi aşıyorsa her iki uca 120 Ω sonlandırma direnci ekleyin.Maksimum hat uzunluğu: 1200 m (9600 baud'da)Maksimum cihaz sayısı: 32 düğüm (standart sürücüler ile)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
bash
Sanal ortam oluştur ve aktifleştir
python3 -m venv modbus-env
source modbus-env/bin/activatepymodbus kur (v3.x)
pip install pymodbus pyserial
Holding Register Okuma (RTU)
python
from pymodbus.client import ModbusSerialClient
import structSeri 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)
python
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)
python
from pymodbus.client import ModbusTcpClientModbus 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)
python
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:
python
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 # saniyedef 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:
python
from pymodbus.server import StartTcpServer
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.datastore import ModbusSequentialDataBlock
import threading, time, randomVeri 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ı
CRC hatası / zaman aşımı: Baud rate ve pariteyi slave cihazla eşleştirin.Gürültü: Bükümlü çift (twisted pair) kablo kullanın ve hattı topraklayın.Yansıma: 10 m üzeri hatlarda terminal direnci eksik olabilir.Protokol Analizi
bash
Seri hattı ham olarak izle (debug için)
sudo apt install -y minicom
minicom -D /dev/ttyS1 -b 9600Wireshark 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:
Modbus RTU kullanarak RS-485 üzerinden PLC ve sensörlerle haberleşebilir,Modbus TCP kullanarak Ethernet bağlantılı analizör ve dönüştürücülerden veri toplayabilir,Modbus Slave modunda çalışarak mevcut SCADA altyapınıza entegre olabilirsiniz.Bir sonraki adım olarak toplanan verileri InfluxDB ve Grafana ile görselleştirerek gerçek zamanlı endüstriyel dashboard'lar oluşturabilirsiniz.