modbus-tk

Need help using modbus_tk library


I'm using modbus_tk library to use as a Modbus RTU slave. I have an off the shelf Modbus RTU master simulator running on another PC through a usb to 485 converter. I cannot see my holding register in the Master.

I have verified that the serial link is good because I can send strings to the slave using a serial program. I have tried setting up the Master for 16 and 32 bit ints the response is always 83 04. I have tried using a few different masters with staring address of 0, this one happens to default to first register 40001. Baud rates and serial port setting match.

import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import serial
import time  

modbusServ = modbus_rtu.RtuServer(serial.Serial('/dev/ttyS0'),baudrate= 9600,
                 bytesize=8, parity='N', stopbits=1, xonxoff=0)
print("start")

modbusServ.start()

slave_1 = modbus_tk.modbus.Slave(1)

slave_1.add_block("BlockName", modbus_tk.defines.HOLDING_REGISTERS, 40001, 10)

aa= (1,2,3,4,5,6,7,8,9,10) # data in the register

while True:

    slave_1.set_values ("BlockName", 40001, aa)
    time.sleep(0.5)

Solution

  • First off, I don't see any reason for you to keep updating the values on your "BlockName" in the loop, but maybe you have one.

    The numbering of your register also seems to be wrong, you don't need to define register 0 as number 40001, you can replace these lines:

    slave_1.add_block("BlockName", modbus_tk.defines.HOLDING_REGISTERS, 40001, 10)
    slave_1.set_values ("BlockName", 40001, aa)
    

    With:

    slave_1.add_block("BlockName", cst.HOLDING_REGISTERS, 0, 10)
    slave_1.set_values ("BlockName", 0, aa)
    

    There is also a small problem in the way you instantiate your data block and slave.

    So a complete slave example should look like this:

    import modbus_tk
    import modbus_tk.defines as cst
    from modbus_tk import modbus_rtu
    import serial
    import time  
    
    modbusServ = modbus_rtu.RtuServer(serial.Serial('/dev/ttyS0'),baudrate= 9600,
                     bytesize=8, parity='N', stopbits=1, xonxoff=0)
    print("start")
    
    modbusServ.start()
    
    slave_1 = modbusServ.add_slave(1)
    
    slave_1.add_block("BlockName", cst.HOLDING_REGISTERS, 0, 10)
    
    aa= (1,2,3,4,5,6,7,8,9,10) # data in the register
    
    #you need to get a new handler to write values to your slave
    slave = modbusServ.get_slave(1)
    
    slave.set_values ("BlockName", 0, aa)
    
    while True:
    
        print("Modbus Server Waiting for client queries...")
        time.sleep(0.5)
    

    There is a full slave example with command line arguments and all included with the code: https://github.com/ljean/modbus-tk/blob/master/examples/rtuslave_example.py

    To be consistent with the register numbering, in your client you have to read from register 0 too:

    master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 10)
    

    Resulting in: (1,2,3,4,5,6,7,8,9,10)

    I guess you already know but there are some other good libraries to work with Modbus like pymodbus and pylibmodbus.

    EDIT: After testing I had to correct my complete example to add

    slave = modbusServ.get_slave(1)
    

    Apparently, you cannot use the original slave_1 as a handler to write values on your salve, instead you have to call function modbusServ.get_slave(slave_id)