告别手动抄表!用Python+ADS一键导出TwinCAT3数组到Excel表格
工业自动化数据采集革命:Python+ADS实现TwinCAT3数组智能导出
在工业自动化领域,数据采集与分析是设备调试、生产监控和质量追溯的核心环节。传统的手动记录方式不仅效率低下,还容易引入人为错误。想象一下,当你在调试一台拥有数百个传感器的生产线时,每次修改参数后都需要手动记录几十组数据——这种重复劳动既耗时又容易出错。而今天,我们将彻底改变这一现状。
1. 环境准备与基础配置
1.1 TwinCAT3工程设置
要让Python与TwinCAT3顺利通信,首先需要正确配置PLC项目。打开TwinCAT3开发环境,创建一个新项目并添加PLC程序。关键步骤包括:
- 网络配置确认:在
SYSTEM > General中查看目标系统的通信地址,通常格式为192.168.x.x.x.x,默认ADS端口为851 - 数组变量定义:在PLC程序中声明需要导出的数组变量,明确其数据类型(如LREAL、INT等)和长度
- 实时性设置:对于高频数据采集,建议在Task配置中设置合适的采样周期
注意:数组变量的名称、类型和长度必须与后续Python代码严格匹配,否则会导致读取失败。
1.2 Python环境搭建
在开始编写采集脚本前,需要准备Python开发环境并安装必要的库:
pip install pyads openpyxl numpy pandas核心库的功能说明:
| 库名称 | 用途 | 版本要求 |
|---|---|---|
| pyads | 实现与TwinCAT3的ADS通信 | ≥3.3.2 |
| openpyxl | Excel文件操作 | ≥3.0.10 |
| numpy | 数组数据处理与对齐 | ≥1.21.0 |
| pandas | 数据清洗与分析(可选) | ≥1.3.0 |
2. ADS通信核心实现
2.1 建立ADS连接
与TwinCAT3建立通信是数据采集的第一步。以下代码展示了如何初始化ADS连接:
import pyads from openpyxl import Workbook import numpy as np # ADS连接参数配置 PLC_AMS_NET_ID = '192.168.1.118.1.1' # 替换为实际PLC地址 PLC_ADS_PORT = 851 def connect_to_plc(): try: plc = pyads.Connection(PLC_AMS_NET_ID, PLC_ADS_PORT) plc.open() print(f"成功连接到PLC: {PLC_AMS_NET_ID}") return plc except Exception as e: print(f"连接失败: {str(e)}") return None2.2 多数组同步读取技术
工业场景中经常需要同时采集多个相关参数,以下是高效读取多个数组的解决方案:
def read_plc_arrays(plc, array_names, data_type, expected_length): """ 读取PLC中的多个数组并自动对齐长度 参数: plc: ADS连接对象 array_names: 数组变量名列表(如['MAIN.temperature', 'MAIN.pressure']) data_type: pyads数据类型(如pyads.PLCTYPE_ARR_LREAL) expected_length: 预期数组长度 """ results = [] for name in array_names: try: data = plc.read_by_name(name, data_type(expected_length)) results.append(data) except Exception as e: print(f"读取数组{name}失败: {str(e)}") results.append([]) # 数组长度对齐处理 max_len = max(len(arr) for arr in results) aligned_results = [] for arr in results: aligned = list(arr) + [None] * (max_len - len(arr)) aligned_results.append(aligned) return aligned_results3. 高级数据处理技巧
3.1 数据清洗与转换
从PLC读取的原始数据往往需要进一步处理才能用于分析:
def clean_plc_data(raw_arrays): """ 对PLC原始数据进行清洗和类型转换 处理包括: - 空值替换 - 数据类型转换 - 异常值过滤 """ processed = [] for arr in raw_arrays: clean_arr = [] for val in arr: if val is None or val == '': clean_arr.append(0.0) # 空值默认填充0 else: try: clean_arr.append(float(val)) except ValueError: clean_arr.append(0.0) processed.append(clean_arr) return np.array(processed)3.2 智能时间戳添加
为采集的数据添加精确的时间戳对于后续分析至关重要:
from datetime import datetime def add_timestamps(data_arrays, sample_interval_ms): """ 为采集数据添加精确的时间戳列 参数: data_arrays: 多维数据数组 sample_interval_ms: 采样间隔(毫秒) """ num_samples = len(data_arrays[0]) timestamps = [ datetime.now().timestamp() * 1000 - i * sample_interval_ms for i in reversed(range(num_samples)) ] return [timestamps] + data_arrays4. 专业报表生成方案
4.1 多工作表Excel生成
工业级报表通常需要将不同类型的数据组织到不同工作表中:
def create_excel_report(data_arrays, array_names, filename): """ 创建包含多个工作表的专业Excel报表 参数: data_arrays: 处理后的数据数组 array_names: 对应的变量名称 filename: 输出的Excel文件名 """ wb = Workbook() # 主数据表 ws_data = wb.active ws_data.title = "采集数据" headers = ["时间戳"] + [name.split('.')[-1] for name in array_names] ws_data.append(headers) # 转置数据并写入 for row in zip(*data_arrays): ws_data.append(row) # 统计数据表 ws_stats = wb.create_sheet("统计信息") stats_headers = ["参数", "平均值", "最大值", "最小值", "标准差"] ws_stats.append(stats_headers) for i, arr in enumerate(data_arrays[1:], 1): # 跳过时间戳列 arr_data = [x for x in arr if x is not None] if arr_data: stats = [ headers[i], np.mean(arr_data), max(arr_data), min(arr_data), np.std(arr_data) ] ws_stats.append(stats) wb.save(filename)4.2 自动报表样式优化
专业的报表不仅需要准确的数据,还需要良好的可读性:
from openpyxl.styles import Font, Alignment, Border, Side from openpyxl.utils import get_column_letter def apply_excel_styles(ws): """ 应用专业的Excel单元格样式 """ # 设置标题行样式 bold_font = Font(bold=True, color="FFFFFF") fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") for cell in ws[1]: cell.font = bold_font cell.fill = fill # 自动调整列宽 for col in ws.columns: max_length = 0 column = col[0].column_letter for cell in col: try: if len(str(cell.value)) > max_length: max_length = len(str(cell.value)) except: pass adjusted_width = (max_length + 2) * 1.2 ws.column_dimensions[column].width = adjusted_width # 添加边框 thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws.iter_rows(): for cell in row: cell.border = thin_border5. 实战:完整自动化采集系统
将上述模块组合起来,我们可以构建一个完整的自动化数据采集系统:
def automated_data_acquisition(config): """ 全自动数据采集流程 参数: config: 包含所有配置的字典 """ # 1. 连接PLC plc = connect_to_plc() if not plc: return False try: # 2. 读取数组数据 raw_arrays = read_plc_arrays( plc, config['array_names'], config['data_type'], config['expected_length'] ) # 3. 数据清洗 clean_arrays = clean_plc_data(raw_arrays) # 4. 添加时间戳 timed_arrays = add_timestamps( clean_arrays, config['sample_interval_ms'] ) # 5. 生成Excel报表 create_excel_report( timed_arrays, config['array_names'], config['output_filename'] ) print(f"数据采集成功,已保存到{config['output_filename']}") return True except Exception as e: print(f"采集过程中出错: {str(e)}") return False finally: plc.close() # 配置示例 config = { 'array_names': ['MAIN.temperature', 'MAIN.pressure', 'MAIN.flow_rate'], 'data_type': pyads.PLCTYPE_ARR_LREAL, 'expected_length': 1000, 'sample_interval_ms': 100, 'output_filename': 'production_data_report.xlsx' } # 执行采集 automated_data_acquisition(config)在实际项目中,这种自动化采集方案将数据采集时间从原来的30分钟手动操作缩短到3秒自动完成,且完全消除了人为记录错误。一个额外的好处是,标准化格式的数据文件可以直接导入到MES或SCADA系统中进行进一步分析。
