1. 项目缘起:当工业边缘计算遇上开源自动化
最近在折腾一个工业数据采集与可视化的项目,手头正好有一台倍福(Beckhoff)的Edge Box RPi 200。这玩意儿本质上是个基于树莓派CM4模块的工业级边缘控制器,接口丰富,皮实耐造,非常适合放在车间现场。项目需求很明确:把产线上几台支持Modbus TCP协议的设备(比如温控器、流量计)的数据实时采集上来,然后做点简单的逻辑处理,最后推送到上位机或者Web面板进行监控。
要实现这个目标,摆在我面前的有几条路:用倍福自家的TwinCAT 3写PLC程序,那是老本行,但开发调试对于快速原型来说有点重;用Python写脚本,灵活是灵活,但数据流管理和可视化又得额外折腾。这时候,Node-RED进入了我的视线。它是一个基于流的低代码编程工具,用“节点”和“连线”就能构建应用,特别适合处理这种设备连接、数据处理和API集成的场景。最关键的是,它原生支持Modbus,社区节点丰富,而且能直接跑在Edge Box RPi 200这个Linux系统上。
于是,一个“Edge Box RPi 200 + Node-RED + Modbus TCP”的技术栈组合就成型了。这个组合的魅力在于,它用轻量级的开源工具,实现了传统工业自动化领域里需要专用软件和控制器才能完成的任务,特别适合中小型项目、快速验证和运维人员的自主开发。下面,我就把这次从环境搭建、节点配置到实际应用踩过的坑和总结的经验,详细分享一下。
2. Edge Box RPi 200:你的工业级树莓派工作站
在开始软件部署之前,有必要先了解一下我们的硬件平台——Edge Box RPi 200。它不是一台普通的树莓派,而是倍福将其工业化的产物,理解它的特点能让后续的配置事半功倍。
2.1 硬件规格与接口定位
Edge Box RPi 200的核心是树莓派Compute Module 4(CM4),这意味着它拥有树莓派的基因,但形态和接口是针对工业环境设计的。我手头这台配置是CM4带eMMC存储的版本,省去了SD卡,可靠性更高。其接口堪称豪华:
- 双千兆以太网口:这是它作为边缘网关的利器。一个口(通常
eth0)可以接入工厂局域网,用于连接Modbus TCP设备或与上位机通信;另一个口(eth1)可以配置为独立的网络,用于设备直连或实现网络隔离,非常符合工业现场的网络规划需求。 - USB、RS232、RS485接口:提供了连接串口设备(如Modbus RTU设备)的可能,扩展性很强。
- DIO(数字输入输出):可以直接连接一些开关量传感器或控制指示灯,虽然本项目主要用网络通信,但这个功能为未来集成更多本地信号留下了伏笔。
- 坚固的金属外壳和DIN导轨安装:可以直接卡在配电柜的标准导轨上,适应振动、粉尘和电磁干扰相对较差的工业环境。
从软件角度看,它预装了倍福定制的Linux系统,基于Raspberry Pi OS。系统已经做了一些优化,比如实时性增强,但本质上,你可以把它当作一个带有强大工业接口的、运行Linux的迷你电脑。这是我们能安装并运行Node-RED的基础。
2.2 系统初始化与网络配置
设备上电,通过HDMI接口接上显示器(或者更常用的,通过eth0口用SSH连接),首次启动会进行一些初始化。这里有一个关键步骤:网络配置。由于我们要用Modbus TCP,设备IP地址的稳定性至关重要。
我建议为Edge Box RPi 200设置一个静态IP地址,而不是依赖DHCP。在工业网络中,固定的IP便于管理和寻址。修改网络配置通常通过编辑/etc/dhcpcd.conf文件实现(具体方法因镜像版本可能略有不同)。例如,为eth0设置静态IP:
# 在 /etc/dhcpcd.conf 文件末尾添加 interface eth0 static ip_address=192.168.1.100/24 static routers=192.168.1.1 static domain_name_servers=8.8.8.8配置完成后重启网络服务或直接重启设备。之后,你就可以通过ssh pi@192.168.1.100(默认用户pi,密码请参考倍福文档)稳定地连接到设备了,这是所有后续操作的起点。
注意:倍福的镜像可能禁用了默认的
pi用户或使用了不同密码,请务必查阅设备随附的文档。如果找不到,尝试通过显示器和键盘本地登录查看。
2.3 环境准备:更新系统与安装必要工具
在安装Node-RED之前,先确保系统是最新的,并安装一些常用的工具,会让后续过程更顺畅。
# 1. 更新软件包列表和系统 sudo apt-get update sudo apt-get upgrade -y # 2. 安装一些常用工具(非必须,但推荐) sudo apt-get install -y curl wget git vim # 3. 安装Node.js和npm # Node-RED需要Node.js环境。Edge Box RPi 200的官方镜像可能已预装,但版本可能较旧。 # 查看当前版本: node --version npm --version # 如果未安装或版本过低,建议使用NodeSource的仓库安装LTS版本 curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs确保Node.js版本在14以上,Node-RED v3.x推荐使用Node.js 16或18 LTS版本。完成这些,我们的硬件和基础软件平台就准备好了。
3. Node-RED在边缘盒上的部署与优化
有了准备好的Linux系统,安装Node-RED本身非常简单。但如何将它配置成一个稳定、自启动的生产级服务,并管理好其节点生态,这里面有些细节需要注意。
3.1 安装Node-RED的推荐方式
不推荐直接通过npm install -g node-red进行全局安装,因为权限管理和服务化会有点麻烦。官方推荐使用脚本安装,它会处理好Node-RED的安装、将其设置为系统服务以及安全更新。
# 执行官方安装脚本 bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)这个脚本会做几件事:1) 确保Node.js版本合适;2) 将Node-RED安装到~/.node-red目录下(以当前用户运行);3) 询问你是否将其设置为自启动的系统服务。这里一定要选择“是”,这样设备重启后Node-RED也会自动运行。
安装完成后,Node-RED服务就已经启动了。默认情况下,它运行在1880端口。你可以在同一局域网的电脑浏览器上访问http://<Edge_Box_IP>:1880来打开Node-RED的流编辑器界面。
3.2 配置为可靠的生产服务
安装脚本创建的服务虽然能用,但我们可以进行一些优化,让它更适应工业边缘环境。
首先,修改服务配置文件。Node-RED的系统服务文件通常是/lib/systemd/system/nodered.service。我们需要调整运行用户和部分参数。假设我们一直用pi用户操作:
sudo systemctl stop nodered sudo systemctl disable nodered # 备份原文件 sudo cp /lib/systemd/system/nodered.service /lib/systemd/system/nodered.service.backup # 编辑文件,将User=和Group=改为你的用户名,例如 pi sudo vim /lib/systemd/system/nodered.service # 找到 User= 和 Group= 行进行修改同时,可以在[Service]部分添加环境变量,例如设置一个更友好的工作目录或调整内存限制(对于CM4,内存有限,需注意):
Environment="NODE_OPTIONS=--max-old-space-size=256"保存后,重新加载systemd并启用服务:
sudo systemctl daemon-reload sudo systemctl enable nodered sudo systemctl start nodered sudo systemctl status nodered # 检查状态,应为active (running)其次,考虑数据持久化与备份。Node-RED的流(Flows)和配置默认保存在~/.node-red目录下。其中,flows.json文件就是你的所有逻辑。务必定期备份这个文件!你可以写一个简单的cron任务,将它备份到其他位置。此外,settings.js文件包含了运行时配置(如安全认证、编辑器主题等),根据需求调整。
3.3 安装与管理Modbus节点
Node-RED的强大在于其节点库。我们需要安装Modbus相关的节点。在Node-RED编辑器中,点击右上角的菜单(三条横线)->“节点管理”->“控制面板”->“安装”,然后搜索“modbus”。
这里你会看到好几个Modbus节点包。最常用、功能最全的是node-red-contrib-modbus这个包,它由biancode维护。它包含了Modbus TCP客户端/服务器、RTU串口、Flex Getter/Setter等多种节点,足以满足绝大多数工业协议需求。点击“安装”按钮,等待完成。
安装完成后,在节点面板的左侧,你会发现多了一个“modbus”分类,里面包含了各种Modbus节点。至此,Node-RED的软件和核心节点就绪了。
4. Modbus TCP通信原理与节点深度配置
在动手连接节点之前,我们需要对Modbus TCP协议在Node-RED中的实现方式有个清晰的认识,这能帮助我们在配置时避免很多低级错误。
4.1 Modbus TCP协议简析与地址映射
Modbus TCP可以看作是Modbus RTU协议跑在TCP/IP网络上,它使用了标准的502端口。其报文结构在RTU的基础上加了一个MBAP头(Modbus Application Protocol header)。但对于Node-RED用户来说,我们更关心的是数据模型和地址映射。
Modbus设备将数据存放在四种不同的“寄存器”区:
- 线圈(Coils,地址0xxxx):可读可写的布尔量(1位),对应开关量输出。例如,控制一个继电器的开合。
- 离散输入(Discrete Inputs,地址1xxxx):只读的布尔量(1位),对应开关量输入。例如,读取一个限位开关的状态。
- 保持寄存器(Holding Registers,地址4xxxx):可读可写的16位整数(字)。这是最常用的区域,可以存放各种整型数据,也可以通过约定存放浮点数(占用两个连续的寄存器)。例如,PLC中的设定值、运行速度等。
- 输入寄存器(Input Registers,地址3xxxx):只读的16位整数(字)。通常用于存放模拟量输入值,如温度、压力传感器的实时值。
这里有一个关键点,也是新手最容易混淆的地方:Modbus协议地址和Node-RED(及很多软件)中使用的“数据地址”通常是基于0的偏移量,而设备手册上标注的地址常常是基于1的“协议地址”。
例如,设备手册上说“温度值存放在保持寄存器40001”。那么:
- 协议地址:40001
- 数据地址(偏移量):40001 - 40001 = 0 (对于4xxxx区域,通常用减去40001的方式得到偏移量)
- 在
node-red-contrib-modbus的“读保持寄存器”节点中,你需要填写的“地址”(Address)就是0。
同理,对于线圈0xxxx区域,地址00001对应偏移量0;对于输入寄存器3xxxx区域,地址30001对应偏移量0。务必在配置前,仔细查阅你的设备手册,并做好这个转换。
4.2 Modbus Flex Getter节点的核心配置
node-red-contrib-modbus提供了多种节点,我最推荐使用Modbus Flex Getter节点进行数据读取。它功能强大,配置灵活,可以一次读取多个不同地址、不同类型的数据。
双击一个Modbus Flex Getter节点,其配置主要分为三块:
Server(服务器):这里不是指你的Node-RED是服务器,而是指你要连接的Modbus TCP设备(从站)。你需要先配置一个Modbus Client节点作为“服务器”定义。点击笔形图标新建一个,关键参数如下:
- Type: TCP
- Host: 你的Modbus设备IP地址,例如
192.168.1.50 - Port: 默认502
- Unit ID: 从站地址(Slave ID)。对于很多Modbus TCP设备,这个值就是1,但也有些设备需要特定的ID,请查阅设备手册。
- Reconnect Timeout: 重连超时,建议设置为2000(毫秒)或更长,以适应不太稳定的工业网络。
Read/Write Properties(读写属性):
- FC(Function Code):功能码。例如,
Read Holding Registers (FC3)就是读保持寄存器。根据你要读的数据类型选择。 - Address:数据地址(偏移量),如上文所述。例如要读设备手册上的40001,这里填0。
- Quantity:要读取的寄存器数量。注意,一个16位寄存器是2个字节。如果要读一个32位浮点数(占2个寄存器),Quantity就是2。
- FC(Function Code):功能码。例如,
Polling(轮询):这是实现定时采集的关键。
- Poll Rate:轮询频率,单位毫秒。例如
1000表示每秒读一次。不宜设置过快,以免对设备造成过大负载。对于大多数工业场景,500ms到2000ms的间隔是合理的。 - Use Poll Interval:务必勾选,否则节点不会自动轮询,需要外部触发。
- Poll Rate:轮询频率,单位毫秒。例如
配置好这些,这个节点就会按照设定的频率,自动向指定的Modbus设备请求数据,并将结果以JavaScript对象的形式输出到msg.payload。
4.3 数据处理与消息流构建
Modbus Flex Getter节点输出的msg.payload通常是一个Buffer或数组。我们需要将其转换为可读的数据。通常后面会连接一个function节点或change节点进行数据处理。
例如,读取一个保持寄存器(地址0,即40001)的值,它是一个16位无符号整数。在function节点中:
// msg.payload 可能是一个Buffer,如 <Buffer 00 0a> // 使用Modbus节点自带的解析方法,或者直接转换 let rawValue = msg.payload.readUInt16BE(0); // 大端序读取 msg.payload = { address: 40001, value: rawValue, timestamp: new Date().toISOString() }; return msg;如果要读取一个浮点数(占用地址0和1),则需要将两个16位寄存器组合:
let buffer = msg.payload; // 假设是4字节Buffer // 假设设备使用大端序(Modbus通常是大端序) let intValue = (buffer[0] << 8) | buffer[1]; // 高字 let fracValue = (buffer[2] << 8) | buffer[3]; // 低字 // 或者使用DataView进行更标准的解析 let view = new DataView(buffer.buffer); let floatValue = view.getFloat32(0, false); // false 表示大端序 msg.payload = floatValue; return msg;处理后的数据,可以连接到debug节点查看,也可以发送到dashboard节点组进行可视化,或者通过MQTT out节点发布到消息服务器,实现数据的上云或跨系统传输。
5. 构建一个完整的边缘数据采集与监控流程
理论说再多,不如一个实际的例子来得直观。假设我们要监控一台工业烤箱,它通过一个Modbus TCP网关暴露了以下数据点:
- 当前温度:只读,存放在输入寄存器30001(偏移量0),数据类型为32位浮点数。
- 设定温度:可读写,存放在保持寄存器40001(偏移量0),数据类型为16位整数。
- 加热器状态:只读,存放在线圈00001(偏移量0),布尔量。
我们的目标是:每秒读取一次当前温度和加热器状态,在面板上显示;并提供一个滑块,可以远程修改设定温度。
5.1 流程设计与节点连接
在Node-RED编辑器中,我们拖拽节点构建如下流程:
- Modbus Client配置节点:一个即可,指向烤箱网关的IP和端口。
- Modbus Flex Getter (FC4):用于读取当前温度(输入寄存器)。配置Server为上一步的Client,Address=0, Quantity=2(因为浮点数占2个寄存器),Poll Rate=1000ms。
- Modbus Flex Getter (FC1):用于读取加热器状态(线圈)。配置相同的Server,Address=0, Quantity=1, Poll Rate=1000ms。
- 两个Function节点:分别接在两个Getter后面,用于解析数据。温度解析函数如上节所述,将两个寄存器转换为浮点数;线圈状态解析则判断
msg.payload[0]是否为真。 - Dashboard UI节点:
- 拖入两个
gauge(仪表)节点,分别连接温度解析和状态解析的输出,用于显示实时值。状态仪表可以设置颜色,比如绿色为“运行”,红色为“停止”。 - 拖入一个
slider(滑块)节点和一个button(按钮)节点到画布上,它们属于UI输入元件,暂时不连线。 - 拖入一个
Modbus Flex Setter节点,用于写入设定值。配置Server为同一个Client,FC=写单个保持寄存器(FC6),Address=0。
- 拖入两个
- 写入逻辑:将
slider节点和button节点连接到一个function节点。这个函数节点负责在按钮按下时,获取滑块的数值,并构造给Modbus Flex Setter节点的消息。Setter节点需要msg.payload包含要写入的值。
然后,配置滑块节点,在其“主题(Topic)”属性中填写// 当按钮被按下时,msg.payload是按钮的配置,我们需要取滑块的值 // 这里假设滑块节点的id是“setpoint_slider”,我们需要用context或flow变量来传递 // 更简单的方法:将滑块和按钮连到同一个function节点,判断消息来源 if (msg.topic === "setpoint_change") { // 来自滑块的消息,我们只更新一个临时变量,不立即写入 flow.set("targetTemp", msg.payload); return null; // 不向下传递 } if (msg.topic === "write_trigger") { // 来自按钮的消息,执行写入操作 let valueToWrite = flow.get("targetTemp") || 150; // 默认值 msg.payload = valueToWrite; return msg; // 传递给Modbus Setter }setpoint_change,按钮节点的主题填写write_trigger。这样,滑动滑块只改变内存变量,点击按钮才真正下发写入命令,避免了网络频繁写操作。
5.2 Dashboard的布局与部署
点击Node-RED右上角的菜单,打开“Dashboard”侧边栏。在这里你可以:
- 创建标签页(Tabs):比如“烤箱监控”。
- 创建分组(Groups):在标签页下创建分组,如“实时数据”、“参数设置”。
- 将UI节点分配到分组:编辑每个
gauge、slider、button节点,在“Group”下拉框中选择刚才创建的分组。你还可以设置它们的尺寸(Width/Height),以调整布局。
布局完成后,访问http://<Edge_Box_IP>:1880/ui就能看到专属的监控面板了。这个面板是响应式的,在手机或平板上也能良好显示。
5.3 流程的调试与错误处理
在实际运行中,流程可能会因为网络抖动、设备响应超时等问题出错。Node-RED提供了catch节点来捕获流程中其他节点抛出的错误。你可以将一个catch节点拖入画布,它会自动订阅所有节点的错误。将其输出连接到一个debug节点,或者一个可以发送警报的节点(如email节点或telegram节点),这样就能实时知晓系统异常。
对于Modbus通信,node-red-contrib-modbus节点在出错时,通常会在msg.error属性中携带错误信息。你可以在catch节点后面的function节点里分析msg.error,区分是连接失败、超时还是非法地址,并做出不同的处理,比如重试、记录日志或升级报警。
6. 进阶应用:性能优化、安全与维护
当基本流程跑通后,我们需要考虑如何让这个边缘系统更健壮、更安全、更易于维护。
6.1 性能优化与资源管理
Edge Box RPi 200的CM4模块内存和CPU资源有限(通常1GB或2GB内存),在运行Node-RED并处理多个Modbus轮询时需要注意:
- 控制轮询频率:不要将所有设备的轮询周期都设为100ms。根据数据变化快慢分级,关键数据快(如500ms),一般数据慢(如2s、5s)。使用
Inject节点配合stoptimer,可以实现更复杂的定时逻辑,比如只在设备运行时高频采集,待机时低频采集。 - 合并请求:如果可能,使用
Modbus Flex Getter的“Read Multiple”功能,一次读取多个连续的寄存器,而不是为每个数据点建立一个单独的Getter节点。这能大幅减少请求次数和网络开销。 - 流的结构化:对于大型项目,不要把所有逻辑都放在一个巨大的流里。使用子流程(Subflow)功能,将通用的功能(如“解析32位浮点数”、“错误处理模板”)封装起来,使主流程更清晰,也便于复用。
- 监控Node-RED自身:安装
node-red-dashboard的template节点,可以展示系统信息。或者使用node-red-contrib-moment节点定期将内存使用情况、活动连接数等信息通过debug输出或记录到文件。
6.2 安全加固措施
默认安装的Node-RED编辑器(1880端口)和Dashboard界面(1880/ui)是对外开放的,这在工业网络中存在风险。
- 启用用户认证:这是最重要的步骤。编辑
~/.node-red/settings.js文件,找到adminAuth部分,取消注释并进行配置:
使用命令adminAuth: { type: "credentials", users: [{ username: "admin", password: "$2b$08$YourHashedPasswordHere", // 使用 node-red-admin hash-pw 命令生成 permissions: "*" }] },node-red-admin hash-pw生成密码的bcrypt哈希值替换上面注释部分。重启Node-RED后,访问编辑器就需要登录了。 - Dashboard认证:在
settings.js中同样可以配置ui: { path: "ui", middleware: (req, res, next) => { ... } },通过中间件来为/ui路径添加认证,或者依赖反向代理(如Nginx)来做HTTP基础认证。 - 使用HTTPS:如果数据敏感,考虑配置HTTPS。这需要在
settings.js中配置https选项,并提供证书和私钥。 - 防火墙限制:在Edge Box RPi 200上,使用
ufw或iptables防火墙,只允许特定的管理IP地址访问1880端口。例如:sudo ufw allow from 192.168.1.10 to any port 1880 proto tcp # 只允许IP为192.168.1.10的电脑访问 sudo ufw enable
6.3 备份、版本控制与持续集成
将Node-RED的流当作代码来管理是一个好习惯。
- 手动备份:定期备份
~/.node-red目录,尤其是flows.json。可以写一个简单的shell脚本用scp或rsync同步到远程服务器。 - 使用Git:将
~/.node-red初始化为一个Git仓库,每次对流程做重大修改后都进行提交。这样你可以清晰地看到历史变更,并且可以轻松地回滚到任何一个版本。cd ~/.node-red git init git add flows.json settings.js package.json git commit -m "Initial commit of oven monitoring flow" - 项目化部署:对于更复杂的项目,可以考虑使用Node-RED的“项目”(Project)功能。项目将流、依赖的节点、README文件等组织在一起,更适合团队协作和版本管理。你可以在编辑器中创建项目,并将其与GitHub或GitLab仓库关联。
7. 从Modbus TCP出发的生态扩展
基于Edge Box RPi 200和Node-RED这个稳固的边缘基座,采集到的Modbus数据可以轻松地流向更广阔的信息化系统,打破OT(运营技术)与IT(信息技术)的壁垒。
7.1 数据上行:与IT系统集成
Node-RED拥有海量的社区节点,可以轻松实现数据上行:
- MQTT发布:安装
node-red-contrib-aedes或使用node-red-node-iot-gateway节点,将处理后的数据(如{temperature: 25.6, status: true})发布到MQTT Broker(如Mosquitto, EMQX)。这样,任何订阅了该主题的IT系统(如数据库、数据分析平台、移动App)都能接收到实时数据。 - 写入数据库:安装
node-red-node-mysql或node-red-contrib-postgresql节点,可以将数据直接写入关系型数据库。对于时序数据,更推荐使用node-red-contrib-influxdb写入InfluxDB,或node-red-contrib-timescale写入TimescaleDB,这些数据库对时间序列数据的查询和压缩优化得更好。 - 调用REST API:使用内置的
http request节点,可以将数据以JSON格式发送到任何支持HTTP/HTTPS的云平台或企业内部API,例如ThingsBoard、Azure IoT Hub、AWS IoT Core或者自研的数据中台。
7.2 横向扩展:连接更多工业协议
Modbus TCP只是工业协议的冰山一角。Node-RED的生态支持许多其他协议,让你能用同一套逻辑处理多种设备:
- OPC UA:安装
node-red-contrib-opcua节点,可以连接更现代、更安全的OPC UA服务器。这对于连接西门子、罗克韦尔等品牌的新型PLC非常有用。 - 西门子S7:通过
node-red-contrib-s7节点,可以直接与西门子S7-1200/1500系列PLC进行通信,无需额外的OPC服务器。 - 三菱、欧姆龙等:社区也有相应的节点,虽然可能不如Modbus和OPC UA成熟,但为连接特定品牌设备提供了可能。
- 自定义TCP/UDP:对于非标协议,可以使用
tcp in/tcp out或udp节点,配合function节点进行二进制报文的解析和组包,灵活性极高。
7.3 边缘智能:在本地实现轻量级逻辑
除了数据转发,Edge Box RPi 200完全有能力在边缘侧运行一些轻量级的智能算法或逻辑控制:
- 数据预处理:在数据上传前进行过滤、清洗、聚合(如计算5分钟平均值)、单位转换、越限报警判断。这能减少网络传输量和云端计算压力。
- 简单控制逻辑:利用Node-RED的
function、switch、delay等节点,可以实现基于状态的自动控制。例如,当温度超过设定值一定范围时,自动通过另一个Modbus Write节点关闭加热器,实现本地的闭环安全保护。 - 运行机器学习模型:虽然CM4算力有限,但运行一些训练好的轻量级TensorFlow Lite模型是可行的。你可以使用
node-red-contrib-tfjs或node-red-contrib-tflite节点,对采集到的图像(通过USB摄像头)、振动传感器数据等进行实时推理,实现缺陷检测、预测性维护的初级功能。
通过将Node-RED部署在Edge Box RPi 200这样的工业边缘硬件上,我们构建的不仅仅是一个数据采集网关,而是一个可编程、可扩展、具备一定智能的边缘计算节点。它成本低廉、开发敏捷、生态丰富,非常适合作为工业4.0和物联网项目中,连接物理世界与数字世界的那座关键桥梁。从Modbus TCP这个起点出发,你能探索的可能性远不止于此。