Implementing Modbus TCP Communication with Raspberry Pi and Python

Implementing Modbus TCP Communication with Raspberry Pi and Python
Implementing Modbus TCP Communication with Raspberry Pi and Python
With its strong performance and low cost, the Raspberry Pi is very well suited as an IoT edge device. When transmitting data collected from field sensors to a monitoring center, the Raspberry Pi can use different programming languages and communication protocols. In industrial environments, Modbus is a very common communication method. In this article, using the Python modbus_tk library as an example, a PC is used as the Modbus TCP master to communicate with a Raspberry Pi over Modbus TCP, with the Raspberry Pi acting as the slave device. This article is based on a CSDN blog post by "小鸟打字", with the Python version updated from 2.7 to 3.6 and the development platform migrated to Raspberry Pi.
1. System and Environment
The desktop PC runs Windows 10 Pro and uses the Anaconda distribution of Python (version 3.6). The Raspberry Pi runs the official Raspbian system with Python 3.7 installed. First, install the modbus_tk library.
pip install modbus_tk
Since both Python 2.7 and 3.7 are installed on the Raspberry Pi, use pip3 instead of pip to make sure modbus_tk is installed for Python 3.7.
In this example, the Raspberry Pi and the desktop PC are on the same local network. The Raspberry Pi IP address is 192.168.1.20, and port 11100 is opened for demonstration purposes.
On the Raspberry Pi, install the ufw firewall management tool from the command line and open port 11100. Basic operations such as connecting to the Raspberry Pi via SSH are omitted here.
sudo ufw enable
sudo ufw allow 11100
sudo ufw enable
2. Example Slave Program
!/usr/bin/env python
-- coding: utf_8 --
'''
Author: weizy
Date: 2019/7/23
Description: Modbus protocol slave test script
'''
import sys
import logging
import threading
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus as modbus
import modbus_tk.modbus_tcp as modbus_tcp
LOGGER = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")
if name == "main":
try:
# The address in the server should be set to the Raspberry Pi's IP and the port to be opened
SERVER = modbus_tcp.TcpServer(address="", port=11100)
logger.info("running...")
logger.info("enter 'quit' for closing the server")
# Start the service
SERVER.start()
# Create the first slave
SLAVE1 = SERVER.add_slave(1)
SLAVE1.add_block('A', cst.HOLDING_REGISTERS, 0, 4) # address 0, length 4
SLAVE1.add_block('B', cst.HOLDING_REGISTERS, 4, 14)
# Create another slave 2
SLAVE2 = SERVER.add_slave(2)
SLAVE2.add_block('C', cst.COILS, 0, 10) # address 0, length 10
SLAVE2.add_block('D', cst.HOLDING_REGISTERS, 0, 10) # address 0, length 10
SLAVE1.set_values('A', 0, 4) # change the value of the register at address 0
SLAVE1.set_values('B', 4, [1, 2, 3, 4, 5, 5, 12, 1232]) # change the values of the registers starting at address 4
SLAVE2.set_values('C', 0, [1, 1, 1, 1, 1, 1])
SLAVE2.set_values('D', 0, 10)
while True:
CMD = sys.stdin.readline()
if CMD.find('quit') == 0:
sys.stdout.write('bye-bye\r\n')
break
else:
sys.stdout.write("unknown command %s\r\n" % (args[0]))
finally:
SERVER.stop()
3. Example Master Program
!/usr/bin/env python
-- coding: utf_8 --
'''
Author: weizy
Date: 2017/3/10
Description: Modbus protocol master test script
'''
import sys
import logging
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
LOGGER = modbus_tk.utils.create_logger("console")
if name == "main":
try:
# Connect to the slave address; make sure the port and IP match the slave configuration
MASTER = modbus_tcp.TcpMaster(host="192.168.1.20", port=11100)
MASTER.set_timeout(5.0)
logger.info("connected")
# Read holding registers 0-4 from slave 1
logger.info(MASTER.execute(1, cst.READ_HOLDING_REGISTERS, 0, 4))
# Read holding registers 4-14 from slave 1. Because the registers are defined in separate blocks,
# they cannot be read continuously in one request; otherwise an out-of-range error may occur.
logger.info(MASTER.execute(1, cst.READ_HOLDING_REGISTERS, 4, 14))
# Use the execute format as required
logger.info(MASTER.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 0, output_value=[0, 1, 2]))
logger.info(MASTER.execute(1, cst.READ_HOLDING_REGISTERS, 0, 4))
logger.info(MASTER.execute(2, cst.READ_COILS, 0, 8))
logger.info(MASTER.execute(2, cst.WRITE_MULTIPLE_COILS, 0, output_value=[1, 0, 0, 0, 1]))
logger.info(MASTER.execute(2, cst.READ_COILS, 0, 8))
logger.info(MASTER.execute(2, cst.READ_HOLDING_REGISTERS, 0, 4))
# Coil and register addresses are not in the same block
except modbus_tk.modbus.ModbusError as err:
LOGGER.error("%s- Code=%d" % (err, err.get_exception_code()))
4. Modbus Function Codes: defines.py
Modbus exception codes:
ILLEGAL_FUNCTION = 1Invalid function codeILLEGAL_DATA_ADDRESS = 2Invalid data addressILLEGAL_DATA_VALUE = 3Invalid data valueSLAVE_DEVICE_FAILURE = 4Slave device failureCOMMAND_ACKNOWLEDGE = 5Command receivedSLAVE_DEVICE_BUSY = 6Slave device busyMEMORY_PARITY_ERROR = 8Memory parity error
Supported Modbus function codes:
READ_COILS = 1Read coilsREAD_DISCRETE_INPUTS = 2Read discrete inputsREAD_HOLDING_REGISTERS = 3Read holding registersREAD_INPUT_REGISTERS = 4Read input registersWRITE_SINGLE_COIL = 5Write single coilWRITE_SINGLE_REGISTER = 6Write single registerWRITE_MULTIPLE_COILS = 15Write multiple coilsWRITE_MULTIPLE_REGISTERS = 16Write multiple registers
Supported block types:
COILS = 1CoilsDISCRETE_INPUTS = 2Discrete inputs (digital inputs)HOLDING_REGISTERS = 3Holding registersANALOG_INPUTS = 4Analog inputs
Source code download:
Link: https://pan.baidu.com/s/13ke9X17YpCd_4KN-IMB7Ag
Extraction code: fv6q


