1. 需求拆解与整体方案选型
老话常讲“简易系统不简单”。单看“简易数据采集与分析系统”这九个字,很多朋友第一反应是拿串口助手刷点传感器数据,或者接个plc做个监视画面就完事了。但真要从零搭一套能应对多种数据源、能扛住连续运行、分析结果还能看的系统,背后的工作量比想象中大得多。这期间涉及数据采集、传输、存储、分析、可视化五个环节,任何一处偷懒,后面都会以“数据对不上”“跑几天就崩”“波形是飘的”这种方式来找你算账。
我这次做的这个系统,覆盖面刻意做得比较宽,不是只针对某一种设备。数据源这边既有模拟量传感器,也有支持Modbus TCP的PLC控制器,还有像集蜂云那种以HTTP API为主的云平台数据源。这样一来,整个系统就要在多协议接入、异构数据统一处理上多花些功夫。为什么这么设计?因为在实际工程场景里,很少有人能守着单一品牌、单一协议的设备过日子。车间里既有老旧的Modbus继电器模块,也有西门子S7-1500这样走Profinet的高端控制器,实验室里还可能摆着LabVIEW搭的虚拟仪器台架。如果采集系统只能接一种数据源,那它的适用性就大打折扣了。
整个系统的设计思路可以拆成三条主线:第一,用统一的“数据点”模型去抽象所有异构数据,无论是PLC里的DB块变量、ADC采集到的电压幅值,还是网站上统计的HTTP状态码次数,最终都归一成“时间戳+标识符+数值”的三元组;第二,传输层解耦,硬件设备侧尽量走工业标准协议,软件系统侧走HTTP或者消息队列;第三,存储和展示要用成熟的时序数据库加可视化套件,没必要自己重复造轮子。
在技术选型上,我最终的组合是Python + InfluxDB + Grafana + FastAPI。Python不用多说,生态最全,做数据采集、清洗、分析的效率极高。InfluxDB专门为时序数据设计,写入性能好,还内置了数据保留策略,不用天天手动清理过期数据。Grafana做仪表板那是真的漂亮,而且对InfluxDB的兼容性几乎是无缝的。FastAPI则用来给外部系统提供数据访问接口,需要对接数据时就能直接通过RESTful API拉取,非常方便。
选型时还需要考虑团队的实际情况。比如LabVIEW数据采集这块,我只把它作为上位机采集方案的一种,并没有硬塞进系统架构里。药企ADC药物质量研究与分析系统那边更多是单机版的分析仪器应用,将数据导出到共享文件夹或数据库比实时联网更常见。所以我给系统预留了CSV文件导入接口,专门处理这类“半离线”数据源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 硬件连接与数据采集层的搭建
2.1 模拟量采集的核心参数:ADC精度与采样率
模拟量数据是数据采集系统里最基础、也最容易做错的一环。很多朋友在选ADC芯片或采集模块时只盯着分辨率,觉得16位一定比12位好,采样率越高越踏实。实际上这个认知不够全面。ADC的选型有三个关键参数必须同步考虑:采样率、分辨率、输入量程与阻抗匹配。
拿CT探测器数据采集率来举例,这类场景对采样率的要求高得离谱,一般ADC达不到,需要用到高速并行采样架构。但放到我们这种“简易系统”里,面对的更多是温度、压力、振动这类工业信号,采样率往往几百赫兹到几万赫兹就足够。比如做轴承振动分析,通常用IEPE加速度传感器,配合10kHz采样率就很有余量了。盲目追求高采样率只会让数据量爆炸,存储压力陡增,处理时还容易把噪声一起采进来。
分辨率直接影响测量精度。12位ADC的理论分辨率是1/4096,16位则是1/65536。但要注意,这个精度是理想情况,实际会有非线性误差和温漂。如果你是直接买现成的采集模块,比如使用24位Σ-Δ型ADC的模块,那么整机精度还会受前端调理电路的影响。在LabVIEW加速度传感器数据采集场景里,经常会把信号调理器和采集卡分开,目的就是为了提高信噪比。
还有一点必须提醒:量程不匹配是新手最容易犯的错误。传感器输出0到5V,你非要接到量程0到10V的采集卡上,虽然不会烧坏设备,但会让有效分辨率直接减半。更危险的是反过来,传感器输出0到10V,你接入0到5V量程,那直接就削顶失真了。所以接线之前一定要先确认输入量程和传感器满量程输出,宁可信号幅度只有量程的60%到80%,也要保证峰值不超限。
2.2 工业现场的数据接入:以S7-1500 PLC为例
工业现场的数据采集绕不开PLC。这次我以西门子S7-1500为例做讲解,一方面是因为它在中小型产线中非常普及,另一方面是它支持的协议比较开放,既能走Profinet,也支持Modbus TCP和OPC UA,对二次开发相当友好。
采集PLC数据的第一步是明确你要哪些变量。在TIA Portal里,S7-1500的变量存放在PLC变量表或DB数据块中。我需要采集设备启停状态、电机电流、产线节拍计数、设备温度这四类数据。为了减少通信报文的数据量,我建议用户把需要采集的变量在DB块中连续排列,这样通信时可以直接读取一片连续区域。比如把设备状态放在DB1.DBD0,电机电流放在DB1.DBD4,节拍计数放在DB1.DBD8,温度放在DB1.DBD12,这样一次性读取16个字节就能拿到所有需要的数据。
从系统集成角度看,S7-1500本身支持OPC UA服务端,理论上可以直接让上位机通过OPC UA读取。但在实际项目中,我见过太多因为OPC UA证书过期或者安全策略不一致导致连不上的案例。所以这次我决定用Snap7这个开源库走S7协议直接读取,简单粗暴且非常稳定。Snap7封装好了S7通信层的细节,只需要知道PLC的IP地址、机架号、槽号和DB块编号就能开始读取。
下面是我在采集网关里写的一段核心代码,基于Python的Snap7库实现:
python复制import snap7
import struct
def read_plc_data(plc_ip, rack=0, slot=1):
plc = snap7.client.Client()
plc.connect(plc_ip, rack, slot)
# 从DB1开始,连续读取16个字节
data = plc.db_read(db_number=1, start=0, size=16)
# 前4个字节是整数,表示设备启停状态
status = struct.unpack('>i', data[0:4])[0]
# 第5到8字节是浮点数,表示电机电流
current = struct.unpack('>f', data[4:8])[0]
# 第9到12字节是整数,表示节拍计数
count = struct.unpack('>i', data[8:12])[0]
# 第13到16字节是浮点数,表示温度
temp = str
