news 2026/4/21 10:46:36

树莓派中pymodbus主站程序编写流程:手把手教学

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
树莓派中pymodbus主站程序编写流程:手把手教学

树莓派变身工业网关:用pymodbus打造你的第一个Modbus主站

你有没有遇到过这样的场景?工厂里一堆传感器、电表、PLC设备各自为政,数据拿不到手,监控靠人抄表,效率低还容易出错。或者你在做一个农业大棚项目,温湿度、光照、土壤水分都得实时采集,但设备五花八门,通信协议各不相同。

别急,今天我们就来解决这个问题——让树莓派当“翻译官”,把各种工业设备的数据统一收进来。而实现这个目标的核心工具,就是pymodbus


为什么是pymodbus + 树莓派?

在工业控制领域,Modbus是个老资格了。从1979年诞生至今,它依然是最主流的串行通信协议之一。原因很简单:开放、简单、可靠。无论是PLC、变频器,还是智能电表、环境传感器,几乎都能找到支持Modbus的型号。

而树莓派呢?便宜、小巧、能跑Linux、自带网络和GPIO,简直是做边缘网关的“天选之子”。再加上Python这门以开发效率著称的语言,三者一结合,就能快速搭建一个功能完整的工业数据采集系统。

pymodbus正是这个拼图中关键的一块——它是一个纯Python实现的Modbus协议栈,不需要编译,安装方便,API简洁,特别适合原型开发和中小规模部署。


先搞明白:pymodbus到底能干啥?

我们常说“主站”“从站”,那在实际应用中是什么意思?

想象一下,一个车间有5台设备(从站),它们负责干活并上报状态;而树莓派就像车间主任(主站),每隔一段时间就挨个问:“你那边怎么样?”、“温度多少?”、“有没有报警?”。

pymodbus就是这位“主任”的对讲机+记录本,它能:

  • 主动向设备发起读写请求(比如读寄存器、写线圈)
  • 支持两种最常见的传输方式:
  • Modbus TCP:走网线,适用于带以太网口的设备
  • Modbus RTU:走RS485串口,适合远距离、抗干扰强的现场总线
  • 自动处理底层协议打包解包、CRC校验、超时重试等细节
  • 提供清晰的接口让你只关注“我要读哪个地址”、“怎么解析数据”

更重要的是,整个过程你只需要写几行Python代码,不用再啃晦涩的C语言驱动或复杂的DLL调用。


准备工作:给树莓派装上“通信引擎”

在动手写代码前,先把环境搭好。

1. 系统基础检查

确保你的树莓派运行的是最新版Raspberry Pi OS(建议64位),并通过SSH或桌面终端登录。

先更新系统:

sudo apt update && sudo apt upgrade -y

确认Python版本(需要3.7以上):

python3 --version

2. 安装pymodbus库

一句话搞定:

pip3 install pymodbus

⚠️ 注意:不是modbus,也不是py-modbus,一定要安装pymodbus(作者是Advanced Systeмics Inc.

如果你要用串口(RTU模式),还得加上串口支持:

pip3 install pyserial

3. 配置串口权限(仅RTU需要)

插上USB转RS485模块后,设备通常会出现在/dev/ttyUSB0或树莓派自带串口/dev/serial0。默认情况下普通用户没有访问权限。

执行以下命令将当前用户加入dialout组:

sudo usermod -aG dialout $USER

重启生效。否则程序会报“Permission denied”。


动手实战:从零写出一个Modbus主站

假设我们有一台温湿度传感器,设备地址是2,温度值存在保持寄存器地址100,单位是0.1°C。我们要每5秒读一次数据。

下面分别演示TCP和RTU两种方式怎么写。


场景一:Modbus TCP —— 走网线连接设备

这种最简单,只要设备在同一局域网内就行。

代码实现
from pymodbus.client import ModbusTcpClient import time import logging # 启用日志,方便调试 logging.basicConfig(level=logging.INFO) # 配置参数 SERVER_IP = "192.168.1.100" # 设备IP SERVER_PORT = 502 # Modbus标准端口 SLAVE_ID = 2 # 从站地址 def read_temperature_tcp(): client = ModbusTcpClient(SERVER_IP, port=SERVER_PORT) try: if not client.connect(): print("❌ 连接失败,请检查网络或IP是否正确") return print("✅ 已连接到Modbus TCP设备") while True: # 发起读取请求:从地址100开始,读1个保持寄存器 response = client.read_holding_registers(address=100, count=1, slave=SLAVE_ID) if hasattr(response, 'registers'): raw_value = response.registers[0] temperature = raw_value / 10.0 print(f"🌡️ 当前温度: {temperature:.1f} °C") else: print(f"⚠️ 读取异常: {response}") time.sleep(5) # 每5秒读一次 except Exception as e: print(f"🚨 程序异常: {e}") finally: client.close() print("🔌 连接已关闭") if __name__ == "__main__": read_temperature_tcp()
关键点解析
代码片段说明
ModbusTcpClient(ip, port)创建TCP客户端对象
read_holding_registers()功能码0x03,读保持寄存器
slave=SLAVE_ID指定目标设备地址
hasattr(..., 'registers')判断是否成功响应,防止空指针

运行后你会看到类似输出:

✅ 已连接到Modbus TCP设备 🌡️ 当前温度: 25.6 °C 🌡️ 当前温度: 25.7 °C ...

如果连不上,先 ping 一下IP,确认设备在线且防火墙没拦。


场景二:Modbus RTU —— 通过RS485串口通信

这是更常见的工业现场场景,尤其适合长距离布线或多设备组网。

硬件准备提示
  • 使用 USB-to-RS485 转换器(推荐FTDI芯片款)
  • 接线务必正确:A接A,B接B,共地(GND)
  • 树莓派可用GPIO串口/dev/serial0,但注意电平匹配(需加MAX485转换电路)
代码实现
from pymodbus.client import ModbusSerialClient import time import logging logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) def read_temperature_rtu(): # 配置串口参数(必须与从站一致!) client = ModbusSerialClient( method='rtu', port='/dev/ttyUSB0', # 或 '/dev/serial0' baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=2 ) SLAVE_ID = 2 try: if not client.connect(): print("❌ 无法打开串口,请检查设备是否插入或权限设置") return print("✅ Modbus RTU串口连接成功") while True: # 这里假设温度在输入寄存器(功能码0x04) response = client.read_input_registers(address=100, count=1, slave=SLAVE_ID) if not response.isError(): raw_value = response.registers[0] temperature = raw_value / 10.0 print(f"📊 寄存器[100]原始值: {raw_value}, 温度: {temperature:.1f}°C") else: print(f"❌ Modbus错误响应: {response}") time.sleep(5) except KeyboardInterrupt: print("\n⏹️ 用户中断退出") except Exception as e: print(f"🚨 其他异常: {e}") finally: client.close() if __name__ == "__main__": read_temperature_rtu()
常见坑点提醒
  • 波特率不一致:两边必须都是9600(或其他统一值)
  • 奇偶校验错误:N/O/E要对应,多数设备默认是无校验(’N’)
  • 地址不对:确认是从站地址,不是寄存器地址
  • 接线反了:A/B接反会导致完全收不到数据
  • 缺少终端电阻:超过百米距离建议在总线两端加120Ω电阻

你可以把日志级别改成DEBUG,看看真实的十六进制报文:

Send: 0x2 0x4 0x0 0x64 0x0 0x1 0x71 0xf5 Recv: 0x2 0x4 0x2 0x1 0x90 0xc2 0x7b

这就是Modbus RTU帧的真实模样。


实际应用中的工程思维

写完demo只是第一步,真正落地还要考虑稳定性、可维护性和扩展性。

如何避免“一断就死”?

工业现场干扰多,偶尔超时很正常。我们可以加个简单的重试机制:

def read_with_retry(client, func, retries=3): for i in range(retries): response = func() if not hasattr(response, 'isError') or not response.isError(): return response print(f"🔁 第{i+1}次尝试失败,正在重试...") time.sleep(1) return response # 最终返回最后一次结果

然后这样调用:

response = read_with_retry(client, lambda: client.read_input_registers(100, 1, slave=2))

怎么让它开机自动运行?

别手动启动脚本了,用systemd注册成服务:

创建文件/etc/systemd/system/modbus-reader.service

[Unit] Description=Modbus Data Reader After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/modbus_project ExecStart=/usr/bin/python3 /home/pi/modbus_project/main.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target

启用服务:

sudo systemctl enable modbus-reader.service sudo systemctl start modbus-reader.service

从此再也不怕断电重启。


数据不止是打印出来:下一步往哪走?

你现在拿到了数据,接下来就可以玩出花了:

  • 上传云端:用MQTT发到阿里云IoT、ThingsBoard、Home Assistant
  • 本地存储:写入SQLite或InfluxDB,配合Grafana画曲线图
  • 触发告警:温度过高自动发微信通知或邮件
  • 远程配置:做个Flask网页,让用户改轮询周期、增删设备
  • 协议转换:把Modbus数据转成HTTP API供其他系统调用

甚至还能反过来,让树莓派也当从站,供别人读你的数据。


写在最后:小设备也能干大事

很多人觉得工业自动化很高门槛,非得用昂贵的PLC、HMI、SCADA系统不可。但其实,像树莓派+pymodbus这样的组合,已经足够应对很多真实场景。

我在一个智慧灌溉项目中就用这套方案替代了万元级的商用网关,成本不到十分之一,效果却毫不逊色。学生做毕业设计、工程师打样验证、小微企业做智能化改造,都可以大胆尝试。

技术的本质不是炫技,而是解决问题。当你亲手让一台小小的树莓派稳稳地读出几十米外传感器的数据时,那种成就感,远胜于复制粘贴一万行代码。

所以,别光看教程了——插上你的RS485模块,打开终端,现在就开始写第一行Modbus代码吧。

如果你在实现过程中遇到了挑战,欢迎留言交流,我们一起踩过的坑,都是通往精通的台阶。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 0:24:43

如何快速掌握电路板查看器:OpenBoardView完整使用指南

如何快速掌握电路板查看器:OpenBoardView完整使用指南 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView 还在为复杂的电路板文件查看而烦恼吗?OpenBoardView作为一款免费的跨平台电路…

作者头像 李华
网站建设 2026/4/19 2:52:43

B站Hi-Res音频下载终极指南:3步高效获取无损音质

B站Hi-Res音频下载终极指南:3步高效获取无损音质 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bil…

作者头像 李华
网站建设 2026/4/17 8:45:41

突破硬件限制:用ZLUDA在AMD显卡上流畅运行CUDA应用

突破硬件限制:用ZLUDA在AMD显卡上流畅运行CUDA应用 【免费下载链接】ZLUDA CUDA on AMD GPUs 项目地址: https://gitcode.com/gh_mirrors/zlu/ZLUDA 还在为NVIDIA显卡的高昂价格而烦恼吗?想不想让你的AMD GPU也能运行那些原本只能在CUDA环境下工作…

作者头像 李华
网站建设 2026/4/20 16:59:37

Obsidian微信读书同步插件:终极使用指南

Obsidian微信读书同步插件:终极使用指南 【免费下载链接】obsidian-weread-plugin Obsidian Weread Plugin is a plugin to sync Weread(微信读书) hightlights and annotations into your Obsidian Vault. 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian…

作者头像 李华
网站建设 2026/4/21 6:30:26

OpenBoardView:电路板查看器的完整实用指南

OpenBoardView:电路板查看器的完整实用指南 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView 还在为无法打开专业电路板文件而烦恼吗?OpenBoardView作为一款功能强大的开源工具&#…

作者头像 李华
网站建设 2026/4/20 6:20:29

如何用diff2html实现专业级的代码差异可视化?

如何用diff2html实现专业级的代码差异可视化? 【免费下载链接】diff2html Pretty diff to html javascript library (diff2html) 项目地址: https://gitcode.com/gh_mirrors/di/diff2html diff2html是一款强大的JavaScript库,专门将枯燥的Git dif…

作者头像 李华