Part III · Chapter 10
Setting Up Your Microcomputer
Time to build the workbench: a small Linux board, the Python tools, and a practice Modbus device that lives entirely in software. That's enough to run every example in the next several chapters without owning any industrial hardware.
By the end of this chapter you can
- List what the lab needs, and which chapters need which parts.
- Describe the software stack: Linux, Python 3, pymodbus and pyserial.
- Create and activate a virtual environment and install the pinned pymodbus version.
- Run a practice Modbus server on localhost and use the two-terminal workflow.
The reference machine is a Raspberry Pi: cheap, common, and Linux-based. Any comparable single-board computer, or an ordinary Linux laptop, works just as well. The commands are the same; only the box changes.
What you need
The core of the lab is the board and a way to reach it. For the Ethernet examples in Chapters 11 and 12 that's all: the board can talk Modbus TCP to itself and to other machines on your network with no extra parts. For the serial work in Chapter 13 you add one inexpensive accessory, a USB-to-RS-485 adapter, which gives the board a serial port suited to a real Modbus RTU bus.
| Item | Needed for | Notes |
|---|---|---|
| Raspberry Pi (or similar) | Everything | Any recent model; Linux-based |
| Power supply + SD card | Everything | Standard Pi essentials |
| Network connection | Modbus TCP | Wired or wireless; same network as your PC |
| USB-to-RS-485 adapter | Modbus RTU | Added in Chapter 13 |
| A real Modbus device | Optional | A meter or sensor, once you're ready |
None of it is expensive, and the first several chapters need only the bare board.
The software stack
The tools sit in a short stack. At the bottom is Linux, the operating system the board boots into (Raspberry Pi OS on a Pi). On Linux runs Python 3, pre-installed on the Pi and the language of every example. Inside Python we add one main library, pymodbus, an open-source package that implements the whole protocol, so you speak Modbus in a few lines instead of building frames by hand. For serial work it uses a companion, pyserial, to reach the serial port. That's the whole stack.
Start by bringing the system up to date. Open a terminal on the board, update the operating system, and confirm Python 3 is present (it almost always is):
sudo apt update && sudo apt full-upgrade -y
python3 --versionThe second command prints something like Python 3.11.2. Any Python 3.9 or newer is fine. If Python 3 is somehow missing, sudo apt install python3 python3-pip python3-venv installs it along with the two helpers used next.
A virtual environment
Before installing pymodbus, create a virtual environment: a self-contained folder that holds this project's Python packages separately from the system's own. It's a small habit with a large payoff. The lab's libraries can't interfere with anything else on the machine, and you can wipe and rebuild the lab by deleting one folder. Create one named modbus-lab and activate it:
python3 -m venv modbus-lab
source modbus-lab/bin/activateAfter activation your prompt gains a (modbus-lab) prefix, a reminder that you're working inside the environment. Everything you install now lands in that folder and nowhere else. Type deactivate to leave; run the source command again to return. Make activating the environment the first thing you do in every work session.
Installing pymodbus
With the environment active, one command installs both libraries. Installing pyserial now means the serial examples will work later without a second trip:
pip install "pymodbus==3.7.4" pyserialThe book's code targets the pymodbus 3.6/3.7 interface, and it runs unchanged on 3.7.4. A plain pip install pymodbus today pulls a much newer release where that code breaks: 3.8 and 3.9 removed the zero_mode argument; 3.10 and later renamed ModbusSlaveContext to ModbusDeviceContext, slaves= to devices=, and slave= to device_id=; and the current releases deprecate the datastore classes ahead of version 4. Pinning 3.7.4 keeps every example in Part III working exactly as printed. Keep the quotes around "pymodbus==3.7.4" so the shell passes it to pip intact.
When it finishes, confirm the install and check the version. The book's examples target pymodbus version 3, whose interface differs in small ways from the older version 2 you'll still find in online tutorials. Checking now saves confusion later:
python -c "import pymodbus; print(pymodbus.__version__)"3.7.4If it prints 3.7.4, your toolchain is ready. If it prints anything else (a 2.x version, or a newer 3.x), run the pinned install command again inside the activated environment; pip replaces whatever version is there with 3.7.4.
A practice device in software
To read or write Modbus you need something on the other end. Rather than require hardware on day one, you'll run a software Modbus server on the same board: a small program that behaves like a device, holding registers a client can read and write. Your client reaches it over the network connection every computer has to itself, called localhost (address 127.0.0.1). One board plays both roles, a server pretending to be a device and a client talking to it: the perfect risk-free practice rig.
Here is the entire practice server. Don't worry about every line yet: Chapter 12 builds a server from scratch and explains all of it. Save this as practice_server.py. It creates a device with one hundred holding registers and one hundred input registers, seeds a few with recognizable values, and serves Modbus TCP on port 5020:
from pymodbus.server import StartTcpServer
from pymodbus.datastore import (
ModbusSlaveContext, ModbusServerContext,
ModbusSequentialDataBlock)
hr_vals = [0] * 100
ir_vals = [0] * 100
hr_vals[0:4] = [100, 200, 300, 400]
ir_vals[0:2] = [235, 567] # 23.5 C, 56.7%
hr = ModbusSequentialDataBlock(0, hr_vals)
ir = ModbusSequentialDataBlock(0, ir_vals)
dev = ModbusSlaveContext(hr=hr, ir=ir,
zero_mode=True)
ctx = ModbusServerContext(slaves=dev, single=True)
print("Practice server on port 5020 ...")
StartTcpServer(context=ctx,
address=("0.0.0.0", 5020))Why port 5020 and not 502? Modbus TCP's official port is 502, but on Linux any port below 1024 requires administrator privileges. Port 5020 doesn't, so you can run the server as an ordinary user. (Real devices still usually listen on 502.) Run it now, in its own terminal:
python practice_server.pyPractice server on port 5020 ...The program prints its startup line and then sits quietly, waiting for connections. That's exactly right: a Modbus server does nothing until a client speaks to it, just as Part I described. Leave this terminal running. In the next chapter you'll open a second terminal, write a client, and watch it reach across localhost to read those seeded values back.
Your bench is ready: a microcomputer, the Python tools, and a practice device waiting for a client. In Chapter 11 you'll write that client, a short program that connects to the practice server, reads its registers, and prints the results, and the protocol you've studied on paper will run in front of you for the first time.
Check your understanding
1. Why does the practice server listen on port 5020 instead of Modbus TCP's official port 502?
Low-numbered ports are privileged on Linux. Using 5020 lets you run the server as an ordinary user. Real devices still usually use 502.
2. Your prompt starts with (modbus-lab). What does that tell you?
The prefix appears after source modbus-lab/bin/activate and reminds you that pip installs land in that isolated folder.
3. Why does this course install "pymodbus==3.7.4" rather than the latest release?
Later releases removed zero_mode and renamed ModbusSlaveContext, slaves= and slave=. Pinning keeps every example working as printed.
4. You start practice_server.py. It prints one line and then nothing happens. What's going on?
A Modbus server only answers. Leave it running and talk to it from a second terminal.