Modbus is open, common, relatively easy to use, and has few restrictions in its application; however, it has its shortcomings. In many cases, a user has no choice but to use it because of hardware constraints such as existing sensors or other devices that must talk over Modbus. Whether you must use Modbus or have many options, you should understand the benefits and restrictions inherent to the protocol.
If Modbus is right for the job, then it’s important to know how to use it. What are the options for implementing it? How should you design an application to take advantage of this protocol?
The Modbus application layer is implemented as a request-response, master-slave design for transmitting single-point data across various networking layers. This fundamental design works well, but has its drawbacks for some applications.
Modbus is a request-response protocol for interaction between Supervisory Control and Data Acquisition (SCADA) systems and automation devices. For every request sent, the target device should respond. There is one response for every request. In addition, requests frequently originate from a single source and target a single device. These systems can be characterized by containing a client device that generates a request and waits on the response and a server device that parses the requests from the client, handles them, and then returns a response (see Figure 1). Modbus terminology frequently refers to the client as the master, as it is usually the SCADA host, and refers to the server as the slave. The slave is commonly a sensor or automation controller.
Figure 1. A Request-Response/Client-Server Model
The Modbus messaging pattern is similar to the one defined by HTTP. An advantage of this pattern is that it does not require an extremely reliable network layer. If the client (or master) sends a request and does not receive a reply, it knows that something has gone wrong and can resend the request. Using the HTTP analogy, this would be equivalent to clicking the refresh button on a web browser. If you repeatedly send requests and don’t get a response back from the server, you may think that the server is down and temporarily stop trying to access it. This is similar to the behavior exhibited by some OPC servers such as KEPServerEX and NI OPC Servers when Modbus communication is lost. Although this does not protect against loss of control, it does ensure that master devices know when control is lost and gives them the ability to take appropriate action, such as engaging a failsafe or using a redundant device to maintain control. This is not true for the slave, or server.
Because of the requirement that all requests come from the master device, an intelligent slave does not have a reliable indication that communication has been lost. If the slave receives no requests, it could mean that the network is down, the master is down, or that the master has decided to stop sending requests. This lack of reliable status information can be resolved in different ways, but a system developer should understand the necessity.
A common solution to this problem is for devices to have a watchdog timer. If a request is not received within a designated time frame, the slave device assumes that something has failed and enter a safe state. Depending on the device and the particular application, this may be beneficial or detrimental to the overall control of the system.
The simple watchdog solution has limitations, namely that it only confirms that requests are being received. You can use schemes of increasing complexity, but a commonly used simple and effective approach is to implement a register-level heartbeat. If the device supports it or if you are developing a new device from the ground up, this approach ensures constant communication between a master and slave at the application level. That is, if the control code on the master is responsible for changing the heartbeat value and the control code on the slave is responsible for reading it, the heartbeat value represents a simple test that confirms normal system function. System functionality from the master control code through the networking layers and all the way up to the slave’s control loop are verified by this register-level heartbeat test. Another register, modified on the slave and read on the master might also be used to indicate communication in the other direction.
The nature of this master-slave architecture also means that Modbus slaves cannot provide data unsolicited to a master. Although the master can implement an event-based architecture to send data to the slave, it must continuously poll the slaves at a defined rate to retrieve new data. This requires significant overhead if changes are limited, both in terms of network bandwidth and in master CPU utilization.
In the use case of frequently updating information (for example, from a temperature sensor), this design works well. Because this data varies constantly, polling at an application-defined rate makes sense. In contrast, a slowly updating data element such as an alarm bit or a status physical switch is more effectively monitored by waiting for a value change to occur and only updating the master when such a change occurs. Modbus, nevertheless, requires that each value be polled periodically.
This inability of the slave to send unsolicited data to a master does mean that Modbus offers a level of control over the network that some applications require. In a fragile network, a request-response protocol can ensure that the master is the only device that can determine when communication occurs on the network. If configured correctly, this means that the master can eliminate network packet collisions and ensure a higher level of determinism.
This can also have more general benefits for a control system in that network communication is always at a steady state. If event-based information were transmitted across the network by any slave, it would introduce jitter into the system. Although this may be acceptable for some applications, using a strict polling mechanism for data transfer reduces this risk.
Modbus data is oriented around the concept of tags, or variables. These data elements—holding registers, input registers, coils, and discrete inputs—are called by different names within the protocol, but the idea is the same. These tags are data elements that can be written to or read from at any time, but provide only their current value. This makes sense for many applications; however, implementing concepts like events, messages, or first-in-first-out memory buffers (FIFOs) can be difficult.
Modbus defines four banks of data—the four types mentioned above—that store the vast majority of the information transported by the protocol. Each request from a master can perform a single operation on a single bank of data. That is, a single request can read from the coils bank or write to the coils bank, but not both. There are exceptions, however. For example, function code 23 allows a master to write holding registers and read holding registers in a single request/response cycle. However, this is not a commonly implemented function code. Both master and slave device documentation should be checked to verify whether this function code is available.
It is also critical to understand that data in a given bank can only be accessed sequentially, and up to the packet size limit of the Modbus protocol. This limit is typically about 240 to 250 bytes of payload data, but depends on the specific function used. This makes it extremely important to carefully design the register banks.
For example, a given application may require the transfer of significant amounts of data at a fast rate. In this case, minimizing the number of requests required is desirable. Because data must be accessed sequentially, it would make sense for this application to concentrate as much data as possible in a single bank of registers and to pack data together with the minimum number of unused data elements.
Another application may have a more complex slave that allows for some local control. In this situation, there may be some data that is read at a fast rate and some data that is monitored periodically. In this case, data should be grouped by transfer rate. The quickly updating data should be concentrated in one place, while slowly updating data should be organized into different blocks to make it easier for a single request to read or update a particular data set.
To demonstrate, consider a set of five quickly updating data values (F1-F5) and five slowly updating values (S1-S5). In addition, S1, S2, and S3 correspond to one code module while S4 and S5 correspond to another code module—that is, they may be updated at different times. In Figure 3, the ideal organization for this case gives the master the ability to read the quickly updating data in a single request and then, as needed, read the other slowly updating data sets.
If care is not taken, a data set could easily be organized as shown in Figure 4. In this case, it’s moved from a little over 20 requests per second to over 80 requests per second. It is actually more efficient for a small data set to read everything in a single block. However, these approaches quickly become unscalable for a complex system.
Figure 4. Poor Data Organization
Although internally, data in each Modbus bank is accessed using an address value from 0 to 65,535, it is more common for documentation to refer to data elements using a common addressing scheme. In such a scheme, the address of the data element is prefixed by a number that defines the bank to be accessed. Table 1 shows these prefixes.
Table 1. Data Access Prefixes
Depending on the particular documentation being referenced, addressing starts at either zero or one and uses a fixed width of between four and six values. That is, different documents could all refer to the same integer holding register as 4005, 40004, and 400005. The documentation should define the particular addressing scheme used, and any new system development should publish this information.
Request-response protocols do not necessarily make the best use of network bandwidth. Although a request from the master to read a particular piece of data certainly needs a response, a request to write data does not. However, Modbus application protocol requires that a response be sent to every request. This means that a full Modbus packet must be formed, including protocol data, application data, and any required network data. It also means that the process of requesting data and receiving it in a response can take significantly longer than simply broadcasting the data would require, due to network latency, slave processing time, and any network collisions or interference.
This is exacerbated further by the data organization considerations outlined above. If data is poorly organized within the Modbus memory space, the number of required request-response cycles can increase dramatically. Because of latency considerations, there is a finite rate at which request-response cycles can occur, even without network interference. As a result, reducing the number of requests required for interaction between a master and slave is one of the most significant ways to improve system performance.
The Modbus protocol provides little to no security. In the past, the confined nature of industrial networks meant that a physical security breach was necessary to infiltrate the network. As networks become more interconnected, security is becoming a more serious concern. In recent years, various schemes have been formulated for securing Modbus protocol communication. However, these schemes generally break compatibility with existing Modbus networks and devices.
The overall utility of a given system also varies depending on the specific driver implementation chosen. Typically, Modbus masters are integrated into an application either through a library or through a stand-alone tool like an OPC server. In contrast, a Modbus slave is usually integrated into a device using some sort of library or developed as part of the device firmware. In either case, it is important to understand the variety of implementations available to make the choice most appropriate for a given application.
Typically, an application like KEPServerEX or NI OPC Servers is more fully featured than a library, but offers less control. For example, both OPC server applications can be configured to provide specific data elements at a specific rate and both can convert the raw Modbus data into a defined data type. They are limited however in that you cannot directly generate and send a Modbus request—all requests go through the application and configuration options are limited. A library, in contrast, typically provides raw data and requires you to initiate all requests. This offers flexibility and gives you tight control over all traffic.
In either the case of an application or library implementation, some piece of the overall system is responsible for scheduling requests and determining the format of those requests. Generally, implementations take one of two forms. The first possibility would be to require that all requests and responses occur in sequence. This synchronous design approach is a common choice as the code is simple to write and is network agnostic, but it can significantly underutilize a TCP/IP network. In a synchronous design, the master must perform the following operations: generate a request, send the request across the network, wait for the server to have time to process the request and generate a response, wait for the response to traverse the network, and finally process that response—all before generating another request. For a sufficiently slow slave device or network layer, this round trip time can be significant.
The alternative is an asynchronous design, in which one process on the master is responsible for generating requests while another process is responsible for receiving responses and routing those responses internally to the code that needs the data. This design is much more efficient because multiple requests can be outstanding on the network at once, but it requires both that the slave has a large enough buffer in memory to handle the incoming requests and that the developer of the master implementation invest significantly more resources to the problem. Figure 5 demonstrates the difference between these two message passing schemes. Each arrow to the right indicates a request, while each arrow to the left indicates a response.
Figure 5. Synchronous Versus Asynchronous Message Passing
Some applications such as KEPServerEX and NI OPC Servers split the difference and implement a threading scheme that offers some of the benefits of both implementations. That is, tags and devices can be organized such that all requests occur synchronously, in a single thread, or they can be organized into different threads. In this case, all tags in a given thread are requested synchronously, but multiple devices may be accessed in parallel. This maintains fairly tight control over the network while improving the overall performance of the system.
Modbus is flexible in part because it enforces almost no restrictions on data in the system. Instead, system data consists of up to four blocks of up to 65,635 word-sized registers or Boolean elements. Data can be stored in elements of either type—U16 or Boolean—or it can be stored as subregister values, or as data that crosses the boundaries of multiple registers.
Unfortunately, this flexibility does not imply usability. Just as with TCP and serial, where data is transferred as a stream of bytes, application code using Modbus is required to format that data in a way that makes sense to the rest of the system. For example, the conversion of data from the 32 bits that make up the first and second register to a single-precision floating point value is entirely up to the application code. To make things more confusing, the ordering of this data is undefined by the protocol. It defines that registers are transferred across the network in network (big-endian) order, but various devices handle the cross-register boundaries differently.
This situation is important to consider in all implementations, as there may be variability across different devices. A library typically provides raw data in the form of registers, meaning that you have to reform data as needed for your application. If a library provides typed data, the documentation should be consulted to understand the expected format. In contrast, an application typically takes some of the variability into account. For example, KEPServerEX and NI OPC Servers give you the ability to switch the endianness of multiregister data types on a per-device basis. If this option is not exposed, you may have to implement it yourself and treat registers as raw data.
As discussed previously, addressing in Modbus is complicated because of the variety of schemes used. Although the specification strictly defines an addressing scheme (that is, holding register number five is read by requesting address 0x04 with function code 0x03), devices typically convert this information into a single number. Documentation from different sources may use the same number to refer to different values. It is critical that this be considered when using either a standard library or an application.
Typically, a library does not provide abstractions to convert from a common addressing scheme, like “400005,” into a request for the data stored by holding register five. Some libraries, especially those that contain type support, may.
In contrast, OPC servers and other applications are more likely to use the more general addressing scheme. Applications like NI OPC Servers and KEPServerEX even provide options to cover many of the permutations in addressing schemes (indexing that starts at zero or one, for example). However, these applications may still have unusual requirements—especially when it comes to interpreting registers as different data types—and application documentation should always be referenced to ensure that data is transferred and interpreted correctly.
If Modbus is selected as the protocol of choice for an application, NI offers three primary tools for Modbus communication. At the lowest level, a variety of different API libraries are available. These libraries usually provide both master and slave support. The NI LabVIEW Datalogging and Supervisory Control (DSC) and LabVIEW Real-Time modules provide a tool called the Modbus I/O server, which provides some of the flexibility and ease of use of a low-level library. I/O servers also provide master and slave support. Finally, NI OPC Servers is a fully functioning OPC server that can include driver support for Modbus masters.
NI OPC Servers is a stand-alone, fully featured OPC server application that can be the backbone of a SCADA system. Like all OPC servers prior to the release of OPC UA, NI OPC Servers is a Windows-only program, and as such is best suited to use as a supervisory system rather than a system for high-speed control of slave devices. NI OPC Servers provides a large set of drivers to allow communication not only with Modbus devices, but with devices using a wide range of vendor-specific protocols or standard protocols like OPC UA. A typical system would look something like Figure 6.
Figure 6. This typical SCADA application uses a set of Modbus TCP/IP devices and an NI OPC Servers host.
Like many OPC servers, NI OPC Servers has facilities to handle large data types, endianness settings on a per-device basis, request scheduling facilities, and many more features to abstract away some of the low-level details of Modbus. After data is in the application, it can be transferred using OPC or OPC UA to loggers, human machine interfaces (HMIs), or other Windows applications.
Figure 7. This extended view of a typical SCADA application includes interaction between Windows-based data historians and HMIs.
The Modbus I/O servers included in LabVIEW provide a middle ground between the easy-to-use range of OPC servers and the powerful low-level libraries that give full control over the protocol. Like an OPC server, I/O servers allow a simple, configuration-based interface for communicating with a Modbus device. Like an OPC server, I/O servers include their own request scheduling system and handle many of the low-level caveats in Modbus, like data endianness. However, I/O servers do offer a simple interface in LabVIEW and give programs the ability to quickly and easily access either processed data (the single-precision floating point value at registers 45 and 46) or the raw data (the unsigned 16-bit integer at register 45). Like an OPC server, I/O servers are typically used in applications where supervisory control is important, while distributed microcontrollers are responsible for the high-speed control in the system.
I/O servers can be thought of as a basic OPC server running inside your application. In typical use, the Modbus master I/O server is deployed as part of an application, and then that application is directly responsible for passing data to an HMI or to a database. In some cases, this level of developer involvement reduces the usability of the final system—a full OPC server is more scalable. However, for smaller systems it makes perfect sense to eliminate the OPC middleman and create a single simple application to handle everything.
Figure 8. A Sample Control Application Using a Modbus Master I/O Server
Just as with the I/O server master, slave servers should also be used for only supervisory control. Because the I/O server is a background process, user code has no way of knowing when a request has been received. This makes I/O servers best suited to applications in which a more powerful piece of hardware, like a PAC, is used to handle most control with occasional low-priority updates from a central hub. In such an application, Modbus data in the I/O server would be scanned in every iteration of a control loop and used to make decisions, but that data would not be used for critical communication (like an E-stop).
Figure 9. A Sample Modbus Slave I/O Server Application
Many low-level Modbus drivers exist in several languages. The LabVIEW 2014 DSC and LabVIEW 2014 Real-Time modules and later provide a low-level Modbus API to complement the features of NI OPC Servers and Modbus I/O servers.
With these drivers, you can explicitly define what happens when a Modbus request is sent or received. They also usually offer a higher maximum performance than higher level drivers. In exchange, you typically must write a lot of the data processing code, which allows your application to interact effectively with other devices in the system. The functionality and behavior of this code varies depending on whether the device is a master or a slave.
Figure 10 demonstrates how a low-level master, the LabVIEW Modbus API, provides tight control over the specific requests sent and the timing of those requests.
Figure 10. A low-level master controls the timing and content of a read request.
When used as a master, a high-performance PAC using a low-level Modbus driver can be used to effectively control a system that requires high speed and reliability. Because requests are generated directly by the application code, any failures are also reported and known immediately, allowing the system to enter a safe state or take corrective action.
In addition, the application has tight control over exactly when data is transmitted, which allows the application code to effectively use network bandwidth. Rather than scanning everything at the same rate, different rates can be used for different slave devices. If necessary, the application could even use entirely different network paths (two TCP connections, different serial lines) to meet the performance requirements of the application.
Figure 11 depicts a sample application where the developer has chosen to develop a low-speed event-based supervisory loop, similar to what you might have in a Windows-based SCADA system. In a parallel process, a deterministic control loop is used to communicate with a pump at a high speed.
Figure 11. This NI CompactRIO PAC sample application uses a low-level Modbus master driver.
In addition, because these low-level drivers are so flexible, you can use them to recreate some of the features of a high-level interface, like an I/O server, while still maintaining control over the priorities that are so critical to the behavior of the system. In this sample application, a communications loop has been developed that handles the scheduling of all requests and responses in a way that suits the specific needs of the application. A deterministic control loop can then be written with knowledge of when new data is available from the communications loop, giving many of the benefits of the first system without potential drawbacks from communications faults.
Figure 12. This custom control application moves communications to a secondary loop to reduce the impact of communication faults while maintaining the performance requirements of the system.
Because of the difficulties of handling the server side of a request-response protocol directly in application code, many Modbus slave implementations provide a background process that handles responding to master requests. This is similar in principle to the behavior of I/O server slaves.
However, in a low-level driver, it is typical and expected that application code can adjust the behavior of this process to suit the needs of the system. In some cases, low-level slaves provide an event that application code can handle. This gives you the ability to immediately respond to incoming data from the master without having to poll for changes in device memory.
Figure 13. This low-level slave driver uses events to indicate data changes in a shared data model.
In more advanced cases, the low-level driver may be written in such a way that application code can be injected directly into the data model of the slave API. Thus, rather than simply reading from a memory location, the slave may be able to respond to master requests in an application-specific way. This allows for many of the benefits provided by the low-level master, without having to write a server in application code.
Figure 14. This low-level slave application uses a custom data model to directly interact with deterministic control code in a system-specific way.
Modbus is and will continue to be a commonly used protocol in spite of the number of new technologies introduced in recent years. Although it has limitations that you should be aware of, it’s simple and flexible nature makes it an excellent choice for some designs.