Monday, October 09, 2006

Using Python to query Modbus slaves

I use Python ( ) at lot in my testing. It is a language designed to make a programmer's life easy and the computer sweat - in other words, it is an ideal tool for test scripts and maybe a bad tool for "constant use" tools.

Stock python has no serial support. For serial, you'll need some serial tool like pyserial - this hides details of OS and allows Linux (or Windows) style serial calls on either OS. A web search of pyserial will turn up a download site - such as . The "Vaults of parnassus" is another nice source for Python tools including pyserial.

Creating binary messages is not hard in Python, but a bit ugly. You use lots of "chr(x)" function to build up a binary string and to parse a binary response lots of "ord()". Other than that, look at the spec at for details of the actual protocol.

CRC-16 for Modbus (or DF1):
Here is my CRC16 routine including a few test cases (written with no regard for CPU speed, since that is not why one uses Python). as a ZIP file


techtonik said...

Standard python struct module with pack()/unpack functions will help you to create binary messages in more elegant manner.

Lynn August Linse said...

Thanks, that's an option.

I guess 'elegance' is in the eye of the beholder - I only use that module for reading/writing floats from a binary string since it requires "try/except" to keep it from throwing exceptions.

It's other problem is the output of the pack isn't a real Python string, so you can't do much with it ... in fact, after I pack the float I have to convert the result to a "4-byte binary string" so it works with the rest of my code.

Donald said...

The link to your example code no longer seems to work:

Is there another way to get at that code?

Lynn August Linse said...

I duplicated it to:

I guess the server was now trying to "run" the .PY as-if a server extension. The .zip format stops this.

Donald said...

Would it be possible to post a code example of a full master to slave query? I think I understand how your function works, but I just can't seem to get my slave device to respond to my queries. One example would save me an incredible amount of time.


Lynn August Linse said...

Here is a complete 'construction' which is used in one of my real-world tests - notice how the CRC16 is appended in what I'd call little-endian form.

st = "\x03\x03\x00\x00\x00\x0A"
crc = crc16.calcString( st, crc16.INITIAL_MODBUS)
st += chr(crc & 0xFF) + chr(( crc >>8) & 0xFF)

Since I moderate comments; you can just send a 'new comment' with an email address; I'll reject it (not publish) but I can send you a few complete modbus libraries 'as-is'.

tobias said...

I need to read/write a few int/float registers in 1+ modbus slaves from an embedded device running Linux (over the serial line).

I wrote a Python C extension module to wrap the calls I need in libmodbus (, but I'm wondering if it's possible to do what I need purely in Python.

Is this possible with your code?


luc said...

You may be interested by Modbus Test Kit which is an implementation of the Modbus protcol in Python designed with testing purpose in mind.
I am interested by your feedback if you have a little time to play with it.