Documentation built using Sphinx 2014-06-22, for MinimalModbus version 0.6.
MinimalModbus is an easy-to-use Python module for talking to instruments (slaves) from a computer (master) using the Modbus protocol, and is intended to be running on the master. Example code includes drivers for Eurotherm and Omega process controllers. The only dependence is the pySerial module (also pure Python).
This software supports the ‘Modbus RTU’ and ‘Modbus ASCII’ serial communication versions of the protocol, and is intended for use on Linux, OS X and Windows platforms. It is open source, and has the Apache License, Version 2.0. Tested with Python2.7 and Python3.2.
Modbus is a serial communications protocol published by Modicon in 1979, according to http://en.wikipedia.org/wiki/Modbus. It is often used to communicate with industrial electronic devices.
There are several types of Modbus protocols:
For full documentation on the Modbus protocol, see www.modbus.com.
Note that the computer (master) actually is a client, and the instruments (slaves) are servers.
The application for which I wrote this software is to read and write data from Eurotherm process controllers. These come with different types of communication protocols, but the controllers I prefer use the Modbus RTU protocol. MinimalModbus is intended for general communication using the Modbus RTU protocol (using a serial link), so there should be lots of applications.
As an example on the usage of MinimialModbus, the driver I use for an Eurotherm 3504 process controller is included. It uses the MinimalModbus Python module for its communication. Also a driver for Omega CN7500 is included. For hardware details on these process controllers, see Eurotherm 3500 and Omega CN7500.
There can be several instruments (slaves, nodes) on a single bus, and the slaves have addresses in the range 1 to 247. In the Modbus RTU protocol, only the master can initiate communication. The physical layer is most often the serial bus RS485, which is described at http://en.wikipedia.org/wiki/Rs485.
To connect your computer to the RS485 bus, a serial port is required. There are direct USB-to-RS485 converters, but I use a USB-to-RS232 converter together with an industrial RS232-to-RS485 converter (Westermo MDW-45). This has the advantage that the latter is galvanically isolated using opto-couplers, and has transient supression.
The instrument is typically connected via a serial port, and a USB-to-serial adaptor should be used on most modern computers. How to configure such a serial port is described on the pySerial page: http://pyserial.sourceforge.net/
For example, consider an instrument (slave) with Modbus RTU mode and address number 1 to which we are to communicate via a serial port with the name /dev/ttyUSB1. The instrument stores the measured temperature in register 289. For this instrument a temperature of 77.2 C is stored as (the integer) 772, why we use 1 decimal. To read this data from the instrument:
#!/usr/bin/env python import minimalmodbus instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 1) # port name, slave address (in decimal) ## Read temperature (PV = ProcessValue) ## temperature = instrument.read_register(289, 1) # Registernumber, number of decimals print temperature ## Change temperature setpoint (SP) ## NEW_TEMPERATURE = 95 instrument.write_register(24, NEW_TEMPERATURE, 1) # Registernumber, value, number of decimals for storage
The full API for MinimalModbus is available on http://minimalmodbus.sourceforge.net/apiminimalmodbus.html, and the documentation in PDF format is found on http://minimalmodbus.sourceforge.net/minimalmodbus.pdf
Correspondingly for Modbus ASCII mode:
instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 1, minimalmodbus.MODE_ASCII)
It is better to put the details in a driver for the specific instrument. An example driver for Eurotherm3500 is included in this library, and it is recommended to have a look at its source code. To get the process value (PV from loop1):
#!/usr/bin/env python import eurotherm3500 heatercontroller = eurotherm3500.Eurotherm3500('/dev/ttyUSB1', 1) # port name, slave address ## Read temperature (PV) ## temperature = heatercontroller.get_pv_loop1() print temperature ## Change temperature setpoint (SP) ## NEW_TEMPERATURE = 95.0 heatercontroller.set_sp_loop1(NEW_TEMPERATURE)
Correspondingly, to use the driver for Omega CN7500:
#!/usr/bin/env python import omegacn7500 instrument = omegacn7500.OmegaCN7500('/dev/ttyUSB1', 1) # port name, slave address print instrument.get_pv() # print temperature
More on the usage of MinimalModbus is found on http://minimalmodbus.sourceforge.net/usage.html
Most of the serial port parameters have the default values defined in the Modbus standard (19200 8N1):
instrument.serial.port # this is the serial port name instrument.serial.baudrate = 19200 # Baud instrument.serial.bytesize = 8 instrument.serial.parity = serial.PARITY_NONE instrument.serial.stopbits = 1 instrument.serial.timeout = 0.05 # seconds instrument.address # this is the slave address number instrument.mode = minimalmodbus.MODE_RTU # rtu or ascii mode
These can be overridden:
instrument.serial.timeout = 0.2
To see which settings you actually are using:
For details on the allowed parity values, see http://pyserial.sourceforge.net/pyserial_api.html#constants
To change the parity setting, use:
import serial instrument.serial.parity = serial.PARITY_EVEN
or alternatively (to avoid import of serial):
instrument.serial.parity = minimalmodbus.serial.PARITY_EVEN
Python versions 2.7 and higher are supported (including 3.x). Tested with Python2.7 and Python3.2. This module is pure Python.
From command line (if you have the pip installer, available at http://pypi.python.org/pypi/pip):
pip install -U minimalmodbus
sudo pip install -U pyserial sudo pip install -U minimalmodbus
You can also manually download the compressed source files from http://pypi.python.org/pypi/MinimalModbus/ (see the end of that page). In that case you first need to manually install pySerial from http://pypi.python.org/pypi/pyserial.
There are compressed source files for Unix/Linux (.tar.gz) and Windows (.zip). To install a manually downloaded file, uncompress it and run (from within the directory):
python setup.py install
sudo python setup.py install
If using Python 3, then install with:
sudo python3 setup.py install
There is also a Windows installer (.exe) available. Just start it and follow the instructions.
For Python3 there might be problems with easy_install and pip. In that case, first manually install pySerial and then manually install MinimalModbus.
To make sure it is installed properly, print the _getDiagnosticString() message. See the support section below for instructions.
You can also download the source directly from Linux command line:
wget http://downloads.sourceforge.net/project/minimalmodbus/0.5/MinimalModbus-0.5.tar.gz wget https://pypi.python.org/packages/source/M/MinimalModbus/MinimalModbus-0.5.tar.gz
Change version number to the appropriate value.
The Modbus standard defines storage in:
Some deviations from the official standard:
These are the functions to use for reading and writing registers and bits of your instrument. Study the documentation of your instrument to find which Modbus function code to use. The function codes are given in decimal in this table.
|Data type in slave||Read||Function code||Write||Function code|
|Bit||read_bit()||2 [or 1]||write_bit()||5 [or 15]|
|Register Integer, possibly scaled||read_register()||3 [or 4]||write_register()||16 [or 6]|
|Long (32 bits = 2 registers)||read_long()||3 [or 4]||write_long()||16|
|Float (32 or 64 bits)||read_float()||3 [or 4]||write_float()||16|
|String||read_string()||3 [or 4]||write_string()||16|
|Registers Integers||read_registers()||3 [or 4]||write_registers()||16|
See the API for MinimalModbus on http://minimalmodbus.sourceforge.net/apiminimalmodbus.html
Use a single script for talking to all your instruments. Create several instrument objects like:
instrumentA = minimalmodbus.Instrument('/dev/ttyUSB1', 1) instrumentB = minimalmodbus.Instrument('/dev/ttyUSB1', 2)
Running several scripts using the same port will give problems.
Since MinimalModbus version 0.5, the handling of several instruments on the same serial port has been improved for Windows.
It should no longer be necessary to use ``minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True`` when running on Windows, as this now is handled in a better way internally. This gives a significantly increased communication speed.
If the underlying pySerial complains that the serial port is already open, it is still possible to make MinimalModbus close the serial port after each call. Use it like:
#!/usr/bin/env python import minimalmodbus minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 1) # port name, slave address (in decimal) print instrument.read_register(289, 1)
In Modbus RTU, the request message is sent from the master in this format:
Slave address [1 Byte], Function code [1 Byte], Payload data [0 to 252 Bytes], CRC [2 Bytes].
|Function code (in decimal)||Payload data to slave (Request)||Payload data from slave (Response)|
|1 Read bits (coils)||Start address [2 Bytes], Number of coils [2 Bytes]||Byte count [1 Byte], Value [k Bytes]|
|2 Read discrete inputs||Start address [2 Bytes], Number of inputs [2 Bytes]||Byte count [1 Byte], Value [k Bytes]|
|3 Read holding registers||Start address [2 Bytes], Number of registers [2 Bytes]||Byte count [1 Byte], Value [n*2 Bytes]|
|4 Read input registers||Start address [2 Bytes], Number of registers [2 Bytes]||Byte count [1 Byte], Value [n*2 Bytes]|
|5 Write single bit (coil)||Output address [2 Bytes], Value [2 Bytes]||Output address [2 Bytes], Value [2 Bytes]|
|6 Write single register||Register address [2 Bytes], Value [2 Bytes]||Register address [2 Bytes], Value [2 Bytes]|
|15 Write multiple bits (coils)||Start address [2 Bytes], Number of outputs [2 Bytes], Byte count [1 Byte], Value [k Bytes]||Start address [2 Bytes], Number of outputs [2 Bytes]|
|16 Write multiple registers||Start address [2 Bytes], Number of registers [2 Bytes], Byte count [1 Byte], Value [n*2 Bytes]||Start address [2 Bytes], Number of registers [2 Bytes]|
For function code 5, the only valid values are 0000 (hex) or FF00 (hex), representing OFF and ON respectively.
It is seen in the table above that the request and response messages are similar for function code 1 to 4. The same can be said about function code 5 and 6, and also about 15 and 16.
For finding how the k Bytes for the value relates to the number of registers etc (n), see the Modbus documents referred to above.
To switch on the debug mode, where the communication details are printed:
#!/usr/bin/env python import minimalmodbus instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 1) # port name, slave address (in decimal) instrument.debug = True print instrument.read_register(289, 1) # Remember to use print() for Python3
With this you can easily see what is sent to and from your instrument, and immediately see what is wrong. This is very useful also if developing your own Modbus compatible electronic instruments.
Similar in interactive mode:
>>> instrument.read_register(4097,1) MinimalModbus debug mode. Writing to instrument: '\n\x03\x10\x01\x00\x01\xd0q' MinimalModbus debug mode. Response from instrument: '\n\x03\x02\x07\xd0\x1e)' 200.0
The data is stored internally in this driver as byte strings (representing byte values). For example a byte with value 18 (dec) = 12 (hex) = 00010010 (bin) is stored in a string of length one. This can be created using the function chr(18), or by simply typing the string '\x12' (which is a string of length 1). See http://docs.python.org/reference/lexical_analysis.html#string-literals for details on escape sequences.
For more information about hexadecimal numbers, see http://en.wikipedia.org/wiki/Hexadecimal.
Note that the letter A has the hexadecimal ASCII code 41, why the string '\x41' prints 'A'. The Latin-1 encoding is used (on most installations?), and the conversion table is found on http://en.wikipedia.org/wiki/Latin_1.
The byte strings can look pretty strange when printed, as values 0 to 31 (dec) are ASCII control signs (not corresponding to any letter). For example ‘vertical tab’ and ‘line feed’ are among those. To make the output easier to understand, print the representation, repr(). Use:
Registers are 16 bit wide (2 bytes), and the data is sent with the most significant byte (MSB) before the least significant byte (LSB). This is called big-endian byte order. To find the register data value, multiply the MSB by 256 (dec) and add the LSB.
Error checking is done using CRC (cyclic redundancy check), and the result is two bytes.
We use this example in debug mode. It reads one register (number 5) and interpret the data as having 1 decimal. The slave has address 1 (as set when creating the instrument instance), and we are using MODBUS function code 3 (the default value for read_register()):
This will be displayed:
MinimalModbus debug mode. Writing to instrument: '\x01\x03\x00\x05\x00\x01\x94\x0b'
In the section ‘Modbus implementation details’ above, the request message structure is described. See the table entry for function code 3.
Interpret the request message (8 bytes) as:
|\x01||01||1||Slave address (here 1)|
|\x03||03||3||Function code (here 3 = read registers)|
|\x00||00||0||Start address MSB|
|\x05||05||5||Start address LSB|
|\x00||00||0||Number of registers MSB|
|\x01||01||1||Number of registers LSB|
The response will be displayed as:
MinimalModbus debug mode. Response from instrument: '\x01\x03\x02\x00º9÷'
Interpret the response message (7 bytes) as:
|\x01||01||1||Slave address (here 1)|
|\x03||03||3||Function code (here 3 = read registers)|
Out of the response, this is the payload part: \x02\x00º (3 bytes)
We know since earlier that this instrument stores a temperature of 18.6 C as 186. We provide this information as the second argument in the function call read_register(5,1), why it automatically divides the register data by 10 and returns 18.6.
Some ASCII control characters have representations like \n, and their meanings are described in this table:
|repr() shows as||Can be written as||ASCII hex value||ASCII dec value||Description|
|\t||\x09||09||9||Horizontal Tab (TAB)|
|\r||\x0d||0d||13||Carriage Return (CR)|
It is also possible to write for example ASCII Bell (BEL, hex = 07, dec = 7) as \a, but its repr() will still print \x07.
More about ASCII control characters is found on http://en.wikipedia.org/wiki/ASCII.
The Modbus RTU standard prescribes a silent period corresponding to 3.5 characters between each message, to be able fo figure out where one message ends and the next one starts.
The silent period after the message to the slave is the responsibility of the slave.
The silent period after the message from the slave has previously been implemented in MinimalModbus by setting a generous timeout value, and let the serial read() function wait for timeout.
The character time corresponds to 11 bit times, according to http://www.automation.com/library/articles-white-papers/fieldbus-serial-bus-io-networks/introduction-to-modbus.
|Baud rate||Bit rate||Bit time||Character time||3.5 character times|
|2400||2400 bits/s||417 us||4.6 ms||16 ms|
|4800||4800 bits/s||208 us||2.3 ms||8.0 ms|
|9600||9600 bits/s||104 us||1.2 ms||4.0 ms|
|19200||19200 bits/s||52 us||573 us||2.0 ms|
|38400||38400 bits/s||26 us||286 us||1.0 ms|
|115200||115200 bit/s||8.7 us||95 us||0.33 ms|
Several nodes (instruments) can be connected to one RS485 bus. The bus consists of two lines, A and B, carrying differential voltages. In both ends of the bus, a 120 Ohm termination resistor is connected between line A and B. Most often a common ground line is connected between the nodes as well.
At idle, both line A and B rest at the same voltage (or almost the same voltage). When a logic 1 is transmitted, line A is pulled towards lower voltage and line B is pulled towards higher voltage. Note that the A/B nameing is sometimes mixed up by some manufacturers.
Each node uses a transceiver chip, containing a transmitter (sender) and a receiver. Only one transmitter can be active on the bus simultaneously.
Pins on the RS485 bus side of the transceiver chip:
Pins on the microcontroller side of the transceiver chip:
If the receiver is enabled simultaneusly with the transmitter, the sent data is echoed back to the microcontroller. This echo functionality is sometimes useful, but most often the TXENABLE and RXENABLE pins are connected in such a way that the receiver is disabled when the transmitter is active.
For detailed information, see http://en.wikipedia.org/wiki/RS-485.
Controlling the TXENABLE pin on the transceiver chip is the tricky part when it comes to RS485 communication. There are some options:
This driver also supports Modbus ASCII mode.
Basically, a byte with value 0-255 in Modbus RTU mode will in Modbus ASCII mode be sent as two characters corresponding to the hex value of that byte.
For example a value of 76 (dec) = 4C (hex) is sent as the byte 0x4C in Modbus RTU mode. This byte happens to correspond to the character ‘L’ in the ASCII encoding. Thus for Modbus RTU this is sent: '\x4C', which is a string of length 1 and will print as ‘L’.
The same value will in Modbus ASCII be sent as the string ‘4C’, which has a length of 2.
The frame format is slightly different for Modbus ASCII. The request message is sent from the master in this format:
Start [1 character], Slave Address [2 characters], Function code [2 characters], Payload data [0 to 2*252 characters], LRC [2 characters], Stop [2 characters].
You can make a small Python program to test the communication:
import serial ser = serial.Serial('/dev/ttyUSB0', 19200, timeout=1) print ser ser.write(':010310010001EA\r\n') print ser.read(1000) # Read 1000 bytes, or wait for timeout
It should print something like:
Serial<id=0x9faa08c, open=True>(port='/dev/ttyUSB0', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=1, xonxoff=False, rtscts=False, dsrdtr=False) :0103020136C3
It is also easy to test Modbus ASCII equipment from Linux command line. First must the appropriate serial port be set up properly:
- Print port settings: stty -F /dev/ttyUSB0
- Print all settings for a port: stty -F /dev/ttyUSB0 -a
- Reset port to default values: stty -F /dev/ttyUSB0 sane
- Change port to raw behavior: stty -F /dev/ttyUSB0 raw
- and: stty -F /dev/ttyUSB0 -echo -echoe -echok
- Change port baudrate: stty -F /dev/ttyUSB0 19200
To send out a Modbus ASCII request (read register 0x1001 on slave 1), and print out the response:
cat /dev/ttyUSB0 & echo -e ":010310010001EA\r\n" > /dev/ttyUSB0
The reponse will be something like:
If there is no communication, make sure that the settings on your instrument are OK:
The corresponding settings should also be used in MinimalModbus. Check also your:
For troubleshooting, it is recommended to use interactive mode with debug enabled. See http://minimalmodbus.sourceforge.net/usage.html#interactive-usage
If there is no response from your instrument, you can try using a lower baud rate, or to adjust the timeout setting.
See also the pySerial pages: http://pyserial.sourceforge.net/
To make sure you are sending something valid, start with the examples in the users manual of your instrument. Use MinimalModbus in debug mode and make sure that each sent byte is correct.
The terminiation resistors of the RS-485 bus must be set correctly. Use a multimeter to verify that there is termination in the appropriate nodes of your RS-485 bus.
To troubleshoot the communication in more detail, an oscilloscope can be very useful to verify transmitted data.
Local echo of the USB-to-RS485 adaptor can also be the cause of some problems, and give rise to strange error messages (like “CRC error” or “wrong number of bytes error” etc). Switch on the debug mode to see the request and response messages. If the full request message can be found as the first part of the response, then local echo is likely the cause.
Make a test to remove the adaptor from the instrument (but still connected to the computer), and see if you still have a response.
Most adaptors have switches to select echo ON/OFF. Turning off the local echo can be done in a number of ways:
To handle local echo, see http://minimalmodbus.sourceforge.net/usage.html
There have been reports on problems with serial adaptors on some platforms, for example Raspberry Pi. It seems to lack kernel drives for some chips, like PL2303. Serial adaptors based on FTDI FT232RL are known to work.
Make sure to run the dmesg command before and after plugging in your serial adaptor, to verify that the proper kernel driver is loaded.
For the data types involving more than one register (float, long etc), there are differences in the byte order used by different manufacturers. A floating point value of 1.0 is encoded (in single precision) as 3f800000 (hex). In this implementation the data will be sent as '\x3f\x80' and '\x00\x00' to two consecutetive registers. Make sure to test that it makes sense for your instrument. It is pretty straight-forward to change this code if some other byte order is required by anyone (see support section).
Changing close_port_after_each_call after instantiation of Instrument might be problematic. Set the value minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL=True immediately after import minimalmodbus instead.
When running under Python2.6, for some conversion errors no exception is raised. For example when trying to convert a negative value to a bytestring representing an unsigned long.
Send a mail to email@example.com
Describe the problem in detail, and include any error messsages. Please also include the output after running:
>>> import minimalmodbus >>> print minimalmodbus._getDiagnosticString()
Note that it can be very helpful to switch on the debug mode, where the communication details are printed. See the ‘Debug mode’ section.
Describe which instrument model you are using, and possibly a link to online PDF documentation for it.
The details printed in debug mode (messages and responses) are very useful for using the included dummy_serial port for unit testing purposes. For examples, see the file test/test_minimalmodbus.py.
More implementation details are found on http://minimalmodbus.sourceforge.net/develop.html
Unit tests are provided in the test subfolder. To run them:
Also a dummy/mock/stub for the serial port, dummy_serial, is provided for test purposes. See http://minimalmodbus.sourceforge.net/apidummyserial.html
The test coverage analysis is found at http://minimalmodbus.sourceforge.net/htmlcov/index.html. To see which parts of the code that have been tested, click the corresponding file name.
Hardware tests are performed using a Delta DTB4824 process controller. See the test subfolder for more information.
More details on the unittests are found on http://minimalmodbus.sourceforge.net/develop.html
Apache License, Version 2.0.
Significant contributions by Angelo Compagnucci, Aaron LaLonde, Asier Abalos, Simon Funke, Edwin van den Oetelaar, Dominik Socha, Luca Di Gregorio and Michael Penza.
If you find this software useful, then please like it on Facebook via http://sourceforge.net/projects/minimalmodbus/.
You can also leave a review on the SourceForge project page http://sourceforge.net/projects/minimalmodbus/ (then first make a SourceForge account).
Please also subscribe to the (low volume) mailing list firstname.lastname@example.org (see https://lists.sourceforge.net/lists/listinfo/minimalmodbus-list) so you can help other users getting started.
This README file was changed (committed) at $Date: 2014-06-22 00:02:44 +0200 (Sun, 22 Jun 2014) $, which was $Revision: 197 $.