基于reComputer R1000与FIN的工业设备图形化HMI快速开发实践

1. 项目概述:当工业设备遇上“乐高式”图形化

最近在折腾一个工业数据可视化的项目,客户现场有几十台不同型号的PLC、传感器和机械臂,数据源五花八门,协议也各不相同。传统的组态软件要么太“重”,部署麻烦;要么太“死”,定制化开发周期长得让人头疼。就在这个当口,我接触到了reComputer R1000FIN这套组合,尝试用它来快速创建设备图形界面,结果有点出乎意料——它把这件事变得像搭乐高积木一样直观。

简单来说,reComputer R1000是一台基于NVIDIA Jetson平台的边缘AI计算机,性能强劲且接口丰富,天生就是为工厂车间这种环境设计的,耐高温、抗震动,可以直接挂在产线旁边。而FIN则是一个开源的、基于Web的工业物联网(IIoT)平台和可视化工具。它的核心组件之一Graphics Builder,允许你通过拖拽的方式,为物理设备创建动态的、数据驱动的图形化界面。

这个项目的核心价值在于,它解决了工业现场两个最实际的痛点:一是快速交付,面对客户“明天就要看效果”的需求,用FIN的图形化编辑器,从零搭建一个包含实时数据、历史曲线和报警面板的设备总览图,可能只需要几个小时,而不是几天或几周。二是降低门槛,让熟悉设备工艺但不一定精通JavaScript或复杂图形库的工程师,也能参与到人机界面(HMI)的开发中来,实现“所见即所得”的配置。

如果你是一名工业自动化工程师、系统集成商,或者正在寻找一种轻量、灵活且强大的方式来可视化你的物联网设备数据,那么这套基于reComputer R1000和FIN的方案,绝对值得你花时间深入了解。接下来,我将从设计思路到实操细节,完整拆解这个过程。

2. 整体方案设计与核心组件解析

在决定采用 reComputer R1000 和 FIN 之前,我们评估过几种常见的方案。比如传统的桌面组态软件(如WinCC、iFix等),它们功能强大但授权费用高,且客户端沉重;也考虑过用纯Web技术栈(如Vue.js + ECharts + Node.js)自研,虽然灵活,但开发周期长,需要前端、后端、运维多方协作,对小型项目或快速原型不友好。

2.1 为什么是 reComputer R1000 + FIN?

最终选择这个组合,是基于以下几个关键考量:

  1. 边缘计算与显示的融合:reComputer R1000 不仅是一个数据采集和计算节点,它本身就是一个完整的计算机,可以直接连接显示器作为HMI终端。这意味着我们无需额外的工控机或服务器,实现了“采集-计算-显示”一体化部署,简化了硬件架构,降低了成本和故障点。
  2. FIN 的开源与开放性:FIN 是开源的,这避免了昂贵的软件许可费用。更重要的是,其架构是模块化和微服务化的,我们可以按需部署所需的服务(如数据采集、流处理、可视化),而不用启动一个庞大的单体应用。它的数据模型和API设计也足够开放,能轻松接入各种协议(如 OPC UA, MQTT, Modbus)的数据。
  3. Graphics Builder 的革命性体验:这是打动我的最关键因素。它不是一个简单的图表配置工具,而是一个功能完整的矢量图形编辑器。你可以绘制或导入SVG图形,然后将图形中的元素(如一个矩形、一条管道、一个文本标签)与后台的实时数据点进行“绑定”。数据变化时,图形的颜色、大小、位置、可见性等属性会随之动态变化。这几乎是把Adobe Illustrator和实时数据库连接在了一起,创意和实现之间没有了隔阂。

2.2 核心组件分工与数据流

理解整个系统如何协同工作至关重要。下图清晰地展示了从物理设备到最终屏幕显示的数据流转路径和各个核心组件的职责:

flowchart TD A[物理设备<br>PLC/传感器/CNC等] -->|Modbus/OPC UA/MQTT等协议| B[边缘网关<br>reComputer R1000] B --> C[数据采集与处理<br>FIN Core 服务] C --> D[实时数据存储<br>FIN 时序数据库] D --> E{数据消费端} E --> F[图形化界面<br>FIN Graphics Builder] E --> G[报警与事件管理] E --> H[历史数据分析] F --> I[可视化渲染<br>Web浏览器/本地显示] subgraph R1000 [reComputer R1000 边缘节点] B C D F end

数据流解读

  1. 数据上行:物理设备通过工业协议将数据发送至 reComputer R1000 上运行的 FIN 数据采集服务(如fin-ua处理 OPC UA,fin-modbus处理 Modbus)。
  2. 数据处理与存储:采集到的数据经过简单的清洗、转换(在 FIN 流处理模块中可配置)后,被写入 FIN 内置的高性能时序数据库。
  3. 数据消费与展示:Graphics Builder 创建的图形界面,通过 WebSocket 或 REST API 从时序数据库中订阅实时数据。当数据更新时,图形界面无需刷新页面即可动态更新。
  4. 最终呈现:用户可以通过车间内的任意一台电脑或平板电脑的浏览器访问 R1000 的 IP 地址来查看界面,也可以直接将 R1000 连接到大屏幕或触摸屏作为固定监控终端。

这个架构的优势在于低延迟高可用性。所有数据处理和展示都在边缘侧完成,不依赖于云端网络,即使外网中断,车间内的监控和操作也不受影响。同时,FIN 的微服务架构保证了单个服务的故障不会导致整个系统崩溃。

3. 环境搭建与基础配置实操

理论讲完了,我们动手把环境跑起来。假设你手上已经有一台 reComputer R1000(我用的型号是 J4012,搭载 Jetson Orin Nano),并且已经按照官方指南刷好了 JetPack 系统(Ubuntu 20.04/22.04 LTS)。

3.1 在 reComputer R1000 上部署 FIN 套件

FIN 官方推荐使用 Docker 进行部署,这对于资源有限的边缘设备来说是非常好的方式,能保证环境隔离和依赖管理。以下是在 R1000 上的步骤:

  1. 安装 Docker 和 Docker Compose

    # 更新软件包列表 sudo apt-get update # 安装 Docker 必要依赖 sudo apt-get install -y ca-certificates curl software-properties-common # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker Engine sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io # 安装 Docker Compose Plugin (v2) sudo apt-get install -y docker-compose-plugin # 将当前用户加入 docker 组,避免每次用 sudo sudo usermod -aG docker $USER # 提示:需要重新登录或重启使组生效 newgrp docker
  2. 获取 FIN 的 Docker Compose 配置文件: FIN 的核心服务都定义在一个docker-compose.yml文件中。我们创建一个工作目录并下载它。

    mkdir ~/fin-stack && cd ~/fin-stack # 从 FIN 的 GitHub 仓库获取最新的 compose 文件示例 wget https://raw.githubusercontent.com/final-iot/fin/main/docker-compose.yml # 查看一下内容,里面定义了 fin-core, fin-db, fin-ui 等多个服务 cat docker-compose.yml | head -30
  3. 启动 FIN 服务: 这是最简单的一步,一条命令启动所有服务。

    docker compose up -d

    使用docker compose ps查看所有服务状态,当所有容器都显示为running时,说明启动成功。首次启动会从 Docker Hub 拉取镜像,可能需要几分钟,取决于网络速度。

  4. 访问 FIN 管理界面: 在 reComputer R1000 本机的浏览器中,打开http://localhost:8080(如果从同一网络的其他电脑访问,则使用http://<R1000的IP地址>:8080)。你应该能看到 FIN 的登录界面。默认用户名是admin,密码是admin首次登录后请务必立即修改密码!

实操心得一:资源优化reComputer R1000 的 Jetson Orin Nano 虽然性能不错,但内存(通常8GB或16GB)相对有限。在docker-compose.yml中,可以为关键服务(如fin-db时序数据库)配置内存限制,避免某个服务异常占用所有资源导致系统卡死。例如,在fin-db服务下添加:

deploy: resources: limits: memory: 2G

根据你的设备总内存和容器数量合理分配。

3.2 配置第一个数据源(以模拟数据为例)

在开始画图之前,我们需要先有数据。FIN 支持多种数据接入方式。为了快速演示,我们先创建一个模拟数据源。

  1. 登录 FIN UI,进入主界面。
  2. 创建“节点”:在左侧导航栏找到“节点浏览器”或类似菜单。节点是 FIN 中数据的基本组织单位,可以理解为文件夹或标签。右键点击根节点,创建一名为DemoPlant的新节点。
  3. 创建历史数据点:在DemoPlant节点下,右键创建新的“历史点”。我们创建一个名为Tank1_Level的点,用来模拟一个水箱的液位。在配置中,设置其工程单位(EU)为%,量程(EGU)为0100。最关键的一步,在“数据源”选项卡中,选择“仿真”数据源,并设置一个变化规则,比如正弦波,幅度50,周期60秒。这样,这个点就会自动生成模拟的液位数据。
  4. 验证数据:创建完成后,你可以在“点详情”页面看到该点的实时值在动态变化。也可以在“趋势”功能中,拖入这个点,看到它生成的正弦波形曲线。

至此,我们的数据基础就准备好了。接下来进入最核心的部分——用 Graphics Builder 为这个“虚拟水箱”创建一个图形界面。

4. Graphics Builder 核心功能与设备图形创建

Graphics Builder 是 FIN 的图形化编辑界面,通常可以通过http://<R1000_IP>:8080/graphics/builder直接访问。它的界面类似于简化版的 Figma 或 Inkscape,但核心功能是数据绑定。

4.1 界面初识与基本图形绘制

打开 Graphics Builder,你会看到一个画布和左侧的工具面板。工具面板主要包含:

  • 选择工具:选择和移动对象。
  • 基本形状:矩形、圆形、多边形、线条等。
  • 文本工具:添加静态或动态文本。
  • 图表组件:趋势图、仪表盘、按钮等更复杂的控件。
  • 图层与对象树:管理画布上所有元素的层级关系。

让我们为Tank1_Level创建一个简单的水箱图形:

  1. 绘制水箱外壳:使用矩形工具,画一个细长的矩形作为水箱主体。在右侧的“属性”面板中,可以设置其填充颜色(如浅蓝色)、边框粗细和颜色。
  2. 绘制动态液位:再画一个矩形,放在水箱主体内部,底部对齐。这个矩形将代表实际的液位。我们暂时将其填充为深蓝色。
  3. 绘制标尺和文本:使用线条工具在水箱旁边画几条刻度线。使用文本工具添加一个“%”符号和“液位”标签。

现在,你有了一个静态的水箱示意图。关键的一步来了:如何让里面的深蓝色矩形随着Tank1_Level的数据点实时变化其高度?

4.2 数据绑定:让图形“活”起来

这是 Graphics Builder 的灵魂功能。我们选中代表液位的那个深蓝色矩形,在右侧属性面板中,找到“高度”属性。通常,属性输入框旁边会有一个小图标(如数据库或链接符号),点击它。

  1. 打开数据绑定对话框:点击后,会弹出一个窗口让你选择要绑定的数据点。通过节点浏览器,找到我们之前创建的DemoPlant/Tank1_Level点。
  2. 配置绑定规则:绑定不仅仅是简单的“值等于高度”。我们需要一个转换规则。液位点的值是 0-100 的百分比,而矩形的高度是像素值。因此,需要设置一个线性映射。
    • 输入范围:源数据点的值范围,这里输入0100
    • 输出范围:目标属性(矩形高度)的范围。假设我们希望液位从0%到100%对应矩形高度从0像素到200像素,这里就输入0200
    • 绑定模式:选择“值”,表示矩形的“高度”属性直接由数据点的值经过上述映射后驱动。
  3. 应用并预览:点击确定。回到画布,你可能立即就看到那个矩形的高度发生了变化,因为它已经订阅了Tank1_Level的实时值。你可以打开另一个浏览器标签页,去修改仿真数据点的参数(比如把幅度调大),然后切回 Graphics Builder 页面,会发现液位矩形的高度在动态变化,无需刷新页面!

实操心得二:绑定与表达式数据绑定不仅支持简单的线性映射,还支持使用JavaScript 表达式。例如,你可以绑定矩形的“填充颜色”属性。规则可以写成:value > 80 ? '#ff0000' : (value > 50 ? '#ffff00' : '#00ff00')。这样,当液位超过80%时显示红色(报警),50%-80%显示黄色(预警),低于50%显示绿色(正常)。这种灵活性使得创建复杂的、状态驱动的界面变得非常简单。

4.3 创建交互式控件

一个完整的设备图形不仅用于显示,还应能进行控制。我们为水箱添加一个简单的“泵”开关,并模拟其状态。

  1. 创建控制数据点:在 FIN 中,为DemoPlant节点下再创建一个点,名为Pump1_RunCmd,数据类型可以是布尔型(Boolean),表示泵的启动/停止命令。
  2. 绘制泵的图形:在 Graphics Builder 中,可以用两个圆形和一个三角形组合画一个简单的泵图标。将泵的“填充颜色”属性绑定到另一个新的数据点Pump1_Status(布尔型,仿真其运行状态)。绑定规则:value == true ? '#00ff00' : '#cccccc',运行是绿色,停止是灰色。
  3. 添加按钮控件:从组件库拖一个“按钮”到画布上,放在泵旁边。双击按钮编辑文本,如“启动/停止”。
  4. 为按钮添加点击动作:选中按钮,在属性面板找到“事件”或“动作”选项卡。添加一个“点击”事件。在动作配置中,选择“写数据点”。
    • 目标点:选择我们创建的Pump1_RunCmd
    • 写入值:这里我们可以玩点花样。不直接写truefalse,而是写一个翻转逻辑。由于 FIN 的表达式支持,我们可以写入!{Pump1_RunCmd}。这个表达式的意思是,向Pump1_RunCmd写入它当前值的非值(即取反)。这样,每次点击按钮,命令就会在truefalse之间切换,实现一个乒乓开关。
  5. 模拟状态反馈:为了让Pump1_Status能响应Pump1_RunCmd,我们需要一点简单的逻辑。这可以在 FIN 的“流处理”模块中完成,创建一个简单的流,监听Pump1_RunCmd的变化,然后延迟1秒(模拟泵的启动时间)后,将同样的值写入Pump1_Status。这样,点击按钮后,泵的图标颜色会稍后改变,模拟真实设备的响应。

现在,你就拥有了一个带实时数据展示和简单控制功能的设备图形。液位动态变化,点击按钮可以“控制”泵的启停,并且泵的图标状态会随之改变。

5. 高级技巧与复杂图形构建

掌握了基础操作后,我们可以构建更贴近真实工业场景的复杂图形。

5.1 使用SVG导入与分层设计

对于复杂的设备,如一台数控机床或一个反应釜,用基本形状手绘效率太低。Graphics Builder 支持导入SVG(可缩放矢量图形)文件。

  1. 准备SVG:使用专业的矢量绘图软件(如 Inkscape、Adobe Illustrator)绘制设备示意图,或者从设备厂商提供的资料中获取。确保图形是分层的、逻辑清晰的(例如,外壳、内部组件、管道、仪表盘分别在不同图层)。
  2. 导入与解组:在 Graphics Builder 中,通过“文件”->“导入”SVG。导入后,整个SVG通常是一个组合。右键点击它,选择“解组”或“进入组”,你就可以访问到其中各个独立的路径和形状了。
  3. 分层绑定:将解组后的各个部分分别绑定到对应的数据点。例如,将电机的外壳绑定到设备温度(颜色映射),将旋转的叶片绑定到电机转速(旋转角度绑定),将压力表指针绑定到压力值(旋转角度绑定,并设置不同的输入输出范围)。

注意事项:SVG 文件优化直接从设计软件导出的 SVG 可能包含大量元数据、无关图层和复杂的路径,这会导致 Graphics Builder 渲染变慢,尤其是在资源有限的 R1000 上。导入前,建议使用工具(如 SVGOMG)进行优化,删除无用信息,简化路径。同时,在 Graphics Builder 中,将不常变化的静态背景层“锁定”或合并,可以减少运行时需要处理的动态元素数量,显著提升性能。

5.2 创建可复用的图形模板与符号库

在同一个项目中,往往有多个同类型的设备(如多个相同的水泵)。为每个设备重复绘制和绑定是低效的。Graphics Builder 支持创建符号

  1. 创建符号:绘制并绑定好一个完整的水泵图形后,全选所有相关图形元素,右键选择“创建符号”或“制作组件”。
  2. 定义属性:在创建符号时,可以定义其“属性”。例如,为水泵符号定义一个属性叫MotorSpeedTag,类型是“数据点引用”。
  3. 使用与配置符号:将创建好的符号从库中拖到画布上。选中这个符号实例,在属性面板中,你会看到之前定义的MotorSpeedTag属性。在这里,你可以为这个特定的水泵实例指定具体的数据点,比如PlantA/Pump1_Speed
  4. 批量更新:如果需要修改所有水泵的图形样式(比如把颜色主题从蓝色改成绿色),只需要修改符号库中的原始符号,所有使用了该符号的实例都会自动更新,但每个实例绑定的具体数据点保持不变。

这个功能极大地提升了大型项目界面的开发效率和维护性。

5.3 集成趋势图与报警面板

设备图形旁边,通常需要辅以趋势图和报警列表,以提供更全面的信息。

  1. 内嵌趋势图组件:Graphics Builder 提供了趋势图组件。将其拖到画布上,调整大小。在组件属性中,添加需要显示的趋势笔。例如,将Tank1_LevelTank1_InletFlow(假设有)都添加进去,并设置各自的颜色和线型。这个趋势图组件会自动从 FIN 的历史数据库中查询和绘制数据。
  2. 创建报警摘要:报警信息通常由 FIN 的报警服务管理。我们可以创建一个动态表格或列表组件,将其数据源绑定到 FIN 的报警查询 API(通过 REST 数据源绑定方式),过滤显示当前活动报警或特定优先级以上的报警。当有新报警产生或确认时,列表会自动更新。
  3. 布局与导航:对于拥有多台设备或多个工艺段的大型界面,可以使用“页面”或“视图”功能。创建多个图形页面,然后使用按钮或菜单栏组件,为按钮设置“导航到页面”的动作,实现类似网页的跳转效果,让整个 HMI 系统结构清晰。

6. 部署、优化与常见问题排查

图形创建完成后,我们需要将其部署为可独立访问的运行时界面,并确保其在 reComputer R1000 上稳定、高效地运行。

6.1 发布与独立访问

在 Graphics Builder 中完成的图形,默认是在编辑模式下。我们需要将其“发布”。

  1. 发布图形:在 Graphics Builder 中,点击“发布”或“导出”按钮。这会将图形及其所有绑定配置打包成一个独立的运行时文件(通常是一个 JSON 描述文件)。
  2. 创建视图:在 FIN 的主 UI 管理界面,找到“视图”或“仪表板”管理。创建一个新视图,并选择刚才发布的图形文件作为其内容。
  3. 生成访问链接:保存视图后,FIN 会为其生成一个唯一的 URL,例如http://<R1000_IP>:8080/view/abc123。你可以将这个链接发送给操作人员,他们无需登录 FIN 管理后台,直接在浏览器中打开这个链接,就能看到纯净的设备监控界面,没有编辑工具栏等多余元素。
  4. 全屏与Kiosk模式:为了达到最佳监控效果,可以在显示终端(连接 R1000 的屏幕)的浏览器中,将此 URL 添加到书签,并设置为启动页。同时,可以使用浏览器自带的“全屏”模式(F11),或者使用专门的 Kiosk 模式浏览器应用,实现开机自启动、全屏显示且禁止用户退出的工业终端效果。

6.2 在 reComputer R1000 上的性能优化

边缘设备的资源需要精打细算。以下是一些针对 R1000 的优化建议:

  1. 图形复杂度控制
    • 减少动态元素:只将必须随数据变化的元素进行数据绑定。静态背景、边框等大量元素应合并或栅格化为背景图。
    • 简化 SVG 路径:如前所述,优化导入的 SVG 文件。
    • 慎用高频率动画:避免使用基于时间的、与数据无关的连续动画(如闪烁),这会持续消耗 GPU 资源。
  2. FIN 服务配置优化
    • 调整数据采样与存储间隔:不是所有数据点都需要毫秒级记录。对于变化缓慢的工艺参数(如温度、液位),可以适当降低历史数据的存储频率(如每5秒存一次),大幅减轻fin-db的负担。
    • 限制并发连接数:在 FIN 的网关或前端服务配置中,可以设置最大 WebSocket 连接数,防止意外的大量客户端连接拖垮服务。
  3. 系统层面优化
    • 启用 ZRAM:在内存有限的 Jetson 设备上,启用 ZRAM(内存压缩交换)可以有效防止在内存压力大时系统直接卡死。可以通过安装zram-config包并启用。
    • 关闭不必要的系统服务:如果 R1000 专用于运行 FIN HMI,可以关闭图形桌面(使用纯命令行模式),并通过 Docker 运行 FIN。或者关闭不需要的 snapd、蓝牙等服务。

6.3 常见问题与排查实录

在实际部署中,我遇到过一些典型问题,这里分享排查思路:

问题一:Graphics Builder 中图形更新延迟高或卡顿。

  • 排查
    1. 首先打开浏览器的开发者工具(F12),切换到“网络”标签页,查看 WebSocket 连接是否稳定,数据推送频率是否正常。
    2. 在“性能”标签页录制一段时间,查看是 JavaScript 执行耗时过长,还是渲染(Painting)耗时过长。
  • 解决
    • 如果是数据推送慢,检查 FIN Core 服务和数据库容器的 CPU/内存使用率(docker stats),可能是后端处理瓶颈。
    • 如果是渲染慢,一定是前端图形太复杂。回到“5.2”章节的优化建议,简化图形。特别是检查是否有隐藏的、未绑定但非常复杂的 SVG 路径。
    • 尝试将浏览器硬件加速设置为“使用硬件加速(如果可用)”。

问题二:在远程电脑浏览器访问界面,图片或字体加载失败。

  • 排查:这通常是跨域资源共享(CORS)问题。FIN 的某些服务(如提供静态资源的服务)可能没有正确配置 CORS 头。
  • 解决:修改 FIN 前端服务(如fin-ui)的 Docker 配置,在环境变量或默认配置中添加 CORS 允许的源。或者,更简单的方法是,通过一个反向代理(如 Nginx)来统一代理所有 FIN 服务,并在 Nginx 层面统一配置 CORS 头。

问题三:数据点绑定失效,图形显示“NaN”或不变。

  • 排查
    1. 在 Graphics Builder 编辑器中,选中出问题的图形元素,检查其数据绑定配置,确认数据点路径是否正确。
    2. 在 FIN 的点浏览器中,确认该数据点是否有实时数据流入(值是否在变化)。
    3. 检查绑定规则中的输入输出范围设置是否正确,特别是当数据点值为字符串或布尔值时,线性映射可能不适用。
  • 解决
    • 重新选择数据点进行绑定。
    • 对于非数值型数据,使用“表达式”绑定模式,直接返回处理后的值,例如value ? '运行' : '停止'
    • 确保数据点的“启用历史记录”选项被勾选,否则可能无法通过历史/实时接口读取。

问题四:Docker 容器频繁重启或退出。

  • 排查:使用docker logs <容器名>查看容器退出前的日志,通常会有错误信息。
  • 常见原因与解决
    • 内存不足(OOM Killer):这是 R1000 上最常见的原因。通过docker stats监控容器内存使用,并按照“6.2”章节为容器设置内存限制。
    • 存储空间不足:时序数据库会持续写入数据。使用df -h检查磁盘空间,定期清理旧数据或配置数据保留策略。
    • 端口冲突:确保docker-compose.yml中映射的宿主机端口(如8080, 4840等)没有被其他程序占用。

这套基于 reComputer R1000 和 FIN 的设备图形创建方案,从我的实际项目经验来看,它最大的优势在于极大地缩短了从数据到价值的路径。以往需要前后端开发紧密配合才能完成的复杂HMI,现在工艺工程师自己就能主导完成大部分可视化工作。而 R1000 提供的稳定边缘算力,确保了这套系统在严苛工业环境下的可靠运行。当然,它并非万能,对于需要极其复杂动画或游戏级渲染的场景,仍需要定制开发。但对于90%以上的工业监控与数据可视化需求,它无疑是一个高效、优雅且成本可控的解决方案。