多块大屏同步显示:工厂车间可视化电子看板从采集到展示的工程实践
发布时间:2026/10/1 14:43:04来源:尧图网络
1. 项目缘起与整体设计思路1.1 为什么工厂车间需要可视化电子看板在制造现场待过的人都有一个共同感受数据不是没有而是散落在各个角落。MES系统里有工单进度PLC里有设备状态质检那边有合格率仓库那边有库存水位但这些数据各自躺在不同的屏幕、不同的系统、甚至不同人的Excel表格里。车间主任想看一眼当前产线的实时产出得打电话问班组长厂长想了解当天各线体达成率得等统计员下午出报表。这种信息滞后在快节奏的生产环境里就是实打实的效率损耗。可视化电子看板要解决的核心问题就一个把分散的、滞后的、需要人工汇总的数据变成实时的、集中的、一眼能看懂的大屏画面。上海这边很多制造企业——尤其是汽车零部件、电子组装、精密加工这类行业——车间面积大、产线多、设备品牌杂对看板的需求尤其强烈。一块好的电子看板能让管理者在车间走一圈就掌握全局能让操作工抬头就知道当前任务和进度能让异常在发生的头几分钟就被暴露出来。这个项目标题里提到的“多块大屏同步数据显示”是实际落地中最容易被低估的难点。单块屏幕显示数据不难难的是让分布在车间不同位置、不同楼层、甚至不同厂区的多块大屏在同一时刻显示完全一致的内容并且当数据源更新时所有屏幕几乎同时刷新。这背后涉及数据采集、传输协议、时间同步、渲染策略等一系列工程问题不是随便找个前端页面投屏就能糊弄过去的。1.2 整体架构选型为什么这么搭先把我最终落地的架构摆出来再解释每一层为什么这么选。数据流向大致是设备层PLC、传感器、扫码枪→ 采集层边缘网关、OPC UA客户端→ 数据处理层MES接口服务、消息队列→ 数据分发层WebSocket服务、NTP时间同步→ 展示层多块大屏终端。采集层我选的是边缘网关加OPC UA的组合。车间里的设备品牌很杂三菱、西门子、欧姆龙、台达都有协议从Modbus到Profinet到EtherNet/IP不一而足。边缘网关的好处是它把协议转换这件事下沉到了设备侧网关统一用OPC UA或MQTT往上送数据上层服务不用关心底下是什么牌子的PLC。上海这边有些老厂区网络条件一般边缘网关还能做本地缓存网络抖动时数据不丢恢复后补传。数据处理层直接对接MES系统的数据库和API。这里有个坑要提前说很多MES厂商的数据库表结构是加密的或者文档缺失直接读库风险很大。我的做法是优先走MES提供的WebService或REST接口实在没有接口的字段再考虑只读方式查库并且一定要加只读账号和查询限流。热词里提到的“webservice mes”和“mes系统开源”其实反映了两种路线——用商业MES的走接口用开源MES的可以直接改代码加数据出口各有各的玩法。数据分发层是整个同步显示的关键。我用的方案是后端服务订阅消息队列RabbitMQ或Kafka收到数据变更后通过WebSocket推送给所有大屏终端。为什么不用HTTP轮询因为轮询的实时性和服务器压力是一对矛盾——轮询间隔短了服务器扛不住间隔长了数据滞后。WebSocket是长连接服务端有数据就推延迟可以做到毫秒级而且多块屏幕收到的是同一条消息天然同步。时间同步这块单独拎出来说。多块大屏如果各自用自己的本地时间做数据时间戳哪怕差几秒显示出来的“最后更新时间”就会不一致操作工看到会懵。NTP在这里的作用就是让所有终端、服务器、采集网关的时间基准统一。华为云NTP服务器地址是很多国内项目的首选延迟低、稳定性好。我在项目里配置的是内网自建NTP服务加华为云NTP做备用终端每5分钟同步一次偏差控制在50毫秒以内。1.3 多块大屏同步的核心难点与对策同步显示这件事拆开来看有三个层面数据同步、渲染同步、视觉同步。数据同步靠WebSocket广播加消息序号机制。每条数据变更消息带一个自增序号终端收到后按序号处理乱序到达的消息会被暂存等待。这样即使网络有轻微抖动最终所有屏幕处理的数据顺序是一致的。渲染同步靠统一的渲染时钟。我在前端用requestAnimationFrame配合一个全局的帧计数器所有屏幕的动画和刷新都对齐到这个时钟上。听起来有点过度设计但实际跑下来当大屏上有滚动字幕或闪烁报警时没有这个机制几块屏幕的动画节奏会肉眼可见地不同步。视觉同步最容易被忽略的是屏幕本身的差异。不同品牌、不同批次的LED屏色温和亮度曲线不一样同一张画面投上去颜色会有偏差。我的处理是在每块屏幕的播放端加一层色彩校正配置用同一张标准色卡照片做参照逐块调整伽马值和白平衡。这个活很琐碎但做完之后多屏一致性提升非常明显。2. 核心细节解析与实操要点2.1 数据采集从PLC到看板的完整链路先讲最底层的采集。车间里一台典型的加工设备我需要从它身上拿到几个关键数据运行状态运行/停机/故障、当前工单号、已完成数量、节拍时间。这些数据通常在PLC的寄存器里地址需要跟设备厂商或电气工程师确认。以三菱FX系列为例假设运行状态在D100寄存器0表示停机、1表示运行、2表示故障。边缘网关的配置大概是这样# 网关采集点配置示例 points: - name: machine_status protocol: melsec address: D100 data_type: uint16 scale: 1 offset: 0 deadband: 0 # 状态变化立即上报 - name: completed_count protocol: melsec address: D200 data_type: uint32 scale: 1 offset: 0 deadband: 1 # 数量变化1才上报这里有个实操细节deadband死区的设置很关键。像完成数量这种累计值如果每变化1就上报一次高频生产时消息量会爆炸。我一般设死区为1同时加一个最大上报间隔比如5秒保证即使数量不变也能定期刷新心跳。状态类数据死区设0因为状态变化必须立即反映。采集频率方面状态数据我设的是200毫秒扫描一次数量数据500毫秒。再快没有意义因为人眼看大屏的刷新感知也就到几百毫秒级别而且会给PLC通讯增加不必要的负担。实测下来一台网关带30台设备200毫秒周期CPU占用不到15%。2.2 MES数据对接接口优先查库兜底MES系统是看板数据的重要来源工单信息、计划数量、实际产出、合格率这些通常都在MES里。对接MES我踩过的坑最多这里展开说。第一选择是走MES官方接口。商业MES一般会提供WebService或RESTful接口虽然文档可能不全但至少是官方支持的升级后不容易挂。调用时注意加超时和重试MES服务器在出报表时响应会变慢看板服务不能被拖死。# MES接口调用示例带超时和重试 import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session requests.Session() retry Retry(total3, backoff_factor0.5, status_forcelist[500, 502, 503]) session.mount(http://, HTTPAdapter(max_retriesretry)) def fetch_work_order(order_no): try: resp session.get( fhttp://mes-server/api/order/{order_no}, timeout(3, 10) # 连接3秒读取10秒 ) resp.raise_for_status() return resp.json() except requests.exceptions.RequestException as e: # 记录日志返回缓存数据或None logger.error(fMES接口调用失败: {e}) return None第二选择是只读查库。有些老MES没有对外接口只能读数据库。这时候务必做到用单独的只读账号、只查必要的表和字段、加查询超时、避免全表扫描。我见过有人直接SELECT * FROM production_order把MES库拖垮的这种事千万别干。第三选择是让MES主动推。如果MES支持消息通知或触发器可以在关键表上建触发器数据变更时写入一张中间表看板服务轮询中间表。这种方式对MES侵入小实时性也不错。热词里提到的“skywalking能部署到mes制造系统上面吗”其实反映的是可观测性需求。我的建议是看板服务自己做好日志和指标监控就行MES系统本身要不要上APM得看MES厂商的支持态度强行部署可能影响MES稳定性。2.3 多屏同步的通信设计WebSocket服务我用的是Node.js加ws库或者Python的FastAPI加websockets两者都跑过性能都够用。关键设计点有三个连接管理每块大屏终端建立连接时带上自己的标识如screen-01、screen-02服务端维护一个连接池。终端断线重连时服务端要能识别并恢复推送。消息广播数据变更时服务端向所有连接广播同一条消息。消息体包含数据内容、时间戳、序号。// WebSocket广播示例 const clients new Set(); wss.on(connection, (ws, req) { const screenId new URL(req.url, http://localhost).searchParams.get(id); ws.screenId screenId; clients.add(ws); ws.on(close, () clients.delete(ws)); }); function broadcast(data) { const message JSON.stringify({ seq: globalSeq, ts: Date.now(), payload: data }); for (const client of clients) { if (client.readyState WebSocket.OPEN) { client.send(message); } } }心跳与重连终端每30秒发一次ping服务端回pong。超过90秒没收到ping就认为连接已断清理连接池。终端侧检测到连接断开后用指数退避策略重连1秒、2秒、4秒、8秒最大30秒。注意WebSocket连接数不是越多越好。如果大屏数量超过50块建议引入Redis Pub/Sub做消息中转WebSocket服务做成多实例每个实例只管一部分连接Redis负责跨实例广播。2.4 NTP时间同步的配置细节时间同步这件事不出问题的时候感觉不到一出问题就是大问题。我遇到过因为某块屏幕时间慢了3分钟导致看板上“最后更新”时间显示异常操作工以为数据卡死了实际数据是新的。NTP配置分三层服务器层看板服务器和采集网关都配置NTP客户端指向内网NTP服务或华为云NTP。Linux下用chronyWindows下用系统自带的时间同步。# chrony配置示例 /etc/chrony.conf server ntp.internal.company.com iburst server ntp.myhuaweicloud.com iburst driftfile /var/lib/chrony/drift makestep 1.0 3 rtcsyncmakestep 1.0 3的意思是前3次同步如果偏差超过1秒就直接跳变之后 gradual 调整。这个配置对看板服务器很重要因为服务器时间跳变会导致消息时间戳混乱。终端层大屏播放终端通常是迷你PC或工控机也要配NTP。Windows终端可以用组策略统一推送NTP服务器地址Linux终端用chrony或systemd-timesyncd。应用层即使系统时间同步了应用层也要做校验。我在看板前端加了一个逻辑收到消息后对比消息时间戳和本地时间如果偏差超过5秒在屏幕角落显示一个时间异常提示。这个提示帮我们提前发现过好几次终端时间漂移的问题。3. 实操过程与核心环节实现3.1 从零搭建看板服务的完整步骤假设你从一台干净的Ubuntu服务器开始下面是我实际跑通的步骤。第一步基础环境准备。安装Docker和Docker Compose后续所有服务都用容器跑方便迁移和备份。# 安装Docker curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER # 安装Docker Compose sudo apt install docker-compose-plugin第二步部署消息队列。用RabbitMQ管理界面方便排查问题。# docker-compose.yml 片段 services: rabbitmq: image: rabbitmq:3.12-management ports: - 5672:5672 - 15672:15672 environment: RABBITMQ_DEFAULT_USER: kanban RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASS} volumes: - rabbitmq_data:/var/lib/rabbitmq第三步部署数据采集服务。我用Python写了一个采集服务通过OPC UA客户端读边缘网关的数据处理后发到RabbitMQ。# collector.py 核心逻辑 import asyncio from asyncua import Client import aio_pika import json async def main(): # 连接OPC UA网关 opc_client Client(opc.tcp://gateway:4840) await opc_client.connect() # 连接RabbitMQ mq_conn await aio_pika.connect_robust(amqp://kanban:passrabbitmq/) channel await mq_conn.channel() exchange await channel.declare_exchange(kanban_data, aio_pika.ExchangeType.FANOUT) # 订阅数据变化 nodes { status: ns2;sMachine1.Status, count: ns2;sMachine1.CompletedCount } while True: data {} for key, node_id in nodes.items(): node opc_client.get_node(node_id) data[key] await node.read_value() await exchange.publish( aio_pika.Message(bodyjson.dumps(data).encode()), routing_key ) await asyncio.sleep(0.5) asyncio.run(main())第四步部署WebSocket推送服务。用FastAPI加websockets订阅RabbitMQ收到消息后广播给所有大屏。# ws_server.py 核心逻辑 from fastapi import FastAPI, WebSocket, WebSocketDisconnect import aio_pika import json import asyncio app FastAPI() clients set() app.websocket(/ws) async def websocket_endpoint(ws: WebSocket): await ws.accept() clients.add(ws) try: while True: await ws.receive_text() # 保持连接 except WebSocketDisconnect: clients.remove(ws) async def consume_mq(): conn await aio_pika.connect_robust(amqp://kanban:passrabbitmq/) channel await conn.channel() queue await channel.declare_queue(kanban_broadcast, durableTrue) async with queue.iterator() as it: async for message in it: async with message.process(): data message.body.decode() for client in list(clients): try: await client.send_text(data) except Exception: clients.discard(client) app.on_event(startup) async def startup(): asyncio.create_task(consume_mq())第五步大屏终端页面。前端用Vue或React都行核心是WebSocket连接和数据渲染。// 大屏前端核心逻辑 const ws new WebSocket(ws://kanban-server/ws?id${screenId}); let lastSeq 0; const pendingMessages new Map(); ws.onmessage (event) { const msg JSON.parse(event.data); if (msg.seq lastSeq 1) { render(msg.payload); lastSeq msg.seq; // 检查暂存区是否有后续消息 while (pendingMessages.has(lastSeq 1)) { const next pendingMessages.get(lastSeq 1); render(next.payload); lastSeq next.seq; pendingMessages.delete(lastSeq); } } else if (msg.seq lastSeq 1) { pendingMessages.set(msg.seq, msg); } }; // 断线重连 ws.onclose () { setTimeout(() location.reload(), 3000); };3.2 多块大屏的部署与调试大屏终端的选型上我推荐用迷你PC如Intel NUC或国产工控机而不是智能电视自带系统。原因有三一是浏览器可控能锁定版本和配置二是可以远程管理批量部署和更新三是性能稳定长时间运行不卡顿。部署时每块屏幕的配置项包括屏幕ID、WebSocket服务器地址、NTP服务器地址、色彩校正参数、显示布局模板。这些配置我统一放在一个JSON文件里终端启动时读取。{ screenId: line-a-01, wsServer: ws://10.0.1.100:8000/ws, ntpServer: ntp.internal.company.com, colorProfile: profile-a.json, layout: line-dashboard, refreshInterval: 1000 }调试多屏同步时我用的方法是在服务端加一个“测试模式”每秒广播一个递增的计数器所有屏幕同时显示这个计数器。如果肉眼看到某块屏幕的数字落后就说明那块屏幕的网络或渲染有问题。这个方法很土但非常有效能快速定位是网络延迟还是终端性能问题。3.3 数据刷新策略与性能优化看板数据不是刷新越快越好。我的经验是分三类处理状态类数据运行/停机/故障变化即推无变化时每30秒推一次心跳。这类数据实时性要求最高。计数类数据完成数量、合格数每5秒推一次或者变化超过死区时立即推。这类数据变化频繁全量推送会压垮前端。统计类数据达成率、OEE每30秒或1分钟推一次。这类数据计算量大在服务端算好再推。前端渲染也要做优化。大屏上通常有表格、图表、滚动字幕等多种元素如果每次数据更新都全量重绘性能会很差。我的做法是用虚拟DOM做差异更新只重绘变化的单元格。图表用ECharts的话用setOption的增量更新模式不要每次clear再setOption。实操心得大屏浏览器建议开启硬件加速并且禁用不必要的插件和扩展。我遇到过因为浏览器某个扩展导致内存泄漏大屏跑两天就卡死的情况。后来统一用Chrome的kiosk模式干净很多。4. 常见问题与排查技巧实录4.1 数据不同步的排查思路多块大屏不同步是最常见的问题排查要按链路逐段来。先看服务端在WebSocket服务上加日志记录每条广播消息的序号和发送时间。如果服务端日志显示消息是按序发出的问题就在终端侧。再看网络在终端上用ping和traceroute检查到服务器的网络质量。如果延迟波动大或丢包考虑换有线连接或调整网络拓扑。最后看终端在终端浏览器控制台看WebSocket消息的到达时间和序号。如果消息到达时间一致但渲染时间不同就是终端性能问题需要优化前端渲染或升级硬件。下面这张表是我整理的问题速查表现象可能原因排查方法解决措施某块屏数据滞后网络延迟或终端性能不足对比消息到达时间戳换有线网络优化渲染所有屏数据都滞后服务端处理慢或MQ积压看服务端日志和MQ队列长度优化查询增加消费者数据偶尔跳变消息乱序或重复检查消息序号加序号校验和去重时间显示不一致NTP未同步对比各终端系统时间统一配置NTP屏幕颜色不一致屏幕硬件差异用标准色卡对比逐块色彩校正4.2 MES接口超时与数据缺失的处理MES接口超时是家常便饭尤其是月底出报表的时候。我的处理策略是缓存兜底看板服务本地缓存最近一次成功获取的数据接口超时时先用缓存数据顶着同时在屏幕角落显示“数据可能延迟”的提示。异步刷新不要在看板请求路径上同步调MES接口。用后台任务定期拉取MES数据写入本地数据库看板只读本地库。这样MES慢不会直接影响看板。降级策略如果MES接口连续失败超过阈值自动切换到只显示设备直采数据MES相关字段显示为“--”。等接口恢复后自动切回。4.3 大屏长时间运行的稳定性问题大屏是要7x24小时跑的稳定性比功能更重要。我踩过的坑包括浏览器内存泄漏、WebSocket连接假死、终端系统自动更新重启。内存泄漏前端代码里注意清理定时器和事件监听。我习惯在组件销毁时统一清理用AbortController管理fetch请求。连接假死WebSocket的onclose不一定能捕获所有断线情况。我加了一个应用层心跳终端每30秒发一个ping服务端回pong连续3次没收到pong就主动重连。系统更新终端工控机一定要关闭自动更新。Windows用组策略Linux用unattended-upgrades的配置。我见过大屏在半夜自动更新重启第二天早上车间主任发现屏幕是黑的。避坑技巧给每块大屏配一个智能插座支持远程重启。遇到终端卡死又远程连不上的情况直接断电重启比派人去现场快得多。这个土办法救过我好几次。4.4 LED屏体相关的注意事项虽然这个项目主要是软件层面的同步显示但LED屏体本身也有几个点要注意。驱动芯片的消隐时间如果大屏是LED拼接屏驱动芯片的消隐时间设置不当会导致低灰度下出现鬼影。这个参数通常在屏体控制软件里调不同品牌的芯片如聚积、明微默认值不同需要根据实际显示效果微调。刷新率与拍摄如果车间有拍摄需求比如远程巡检摄像头LED屏的刷新率要设高一些否则拍出来会有扫描线。一般建议1920Hz以上。亮度自适应车间光照变化大白天和晚上的屏幕亮度需要自动调整。我用的是一个光照传感器加脚本根据环境光强动态调屏幕亮度既省电又护眼。5. 项目落地后的效果与个人体会这套看板在上海这边一个汽车零部件工厂落地后最直观的变化是车间主任不用再拿着对讲机问产量了抬头看屏就行异常停机从原来的平均15分钟才被发现缩短到2分钟内报警每天的生产报表从人工统计2小时变成系统自动生成。我个人在实际操作中的体会是电子看板这个事技术难度不在单点而在系统工程。数据采集、传输、处理、展示每一环都有坑而且往往是环环相扣的。比如NTP没配好会导致消息时间戳混乱进而让同步逻辑出错最后表现为屏幕数据不一致。排查的时候如果只盯着屏幕看永远找不到根因。另外一点是不要追求大而全。我见过一些项目一开始就想把MES、ERP、WMS、QMS所有数据都堆到看板上结果数据源太多、接口太杂项目拖了半年上不了线。我的建议是分期做第一期只做设备状态和产量跑稳了第二期加工单和合格率第三期再加OEE和异常分析。每期上线后收集一线反馈迭代优化。最后分享一个小技巧看板上一定要留一个“数据更新时间”的显示精确到秒。这个小小的字段在排查问题时价值巨大。操作工看到时间在跳就知道系统是活的工程师看到时间停了就知道该查哪里了。
网站建设高端定制企业官网