使用Python作为上位机实现汇川EASY300实验:PLC与传感器连接实时数据展示及曲线绘制,数据保存至MYSQL数据库

目录

引言

一、产品特点

二、应用场景

三、产品系列

四、市场评价

实验要求

PLC配置

确定PLC的网络配置

确定PLC的通信协议

IO端口映射

GL20-4AD模块配置和参数设置

PYTHON上位机

数值转换

MYSQL数据库创建数据表

QT主程序


引言

汇川EASY系列PLC是一款全场景紧凑型小型PLC,其设计理念来源于真实的使用场景和用户“痛点”,旨在为用户提供易用、高效、可靠的自动化解决方案。以下是对汇川EASY系列PLC的详细介绍:

一、产品特点
  1. 易实现运动控制和过程控制
  2. 四核处理器带来卓越性能,实现纳秒级指令处理速度。
  3. 32轴高速总线控制,支持同步运动,实现复杂工艺。
  4. 集成免调试自整定PID算法,快速响应、精准调节,轻松控制温度、压力、流量。
  5. 易选型、易扩展
  6. 全系列8个机型,满足严苛体积、多轴运控、温度控制、通信组网等中小型自动化设备需求。
  7. 支持扩展卡和模块扩展,特定场景支持2个扩展卡槽,适配通信/模拟量/数字量等。
  8. 本地扩展GL20系列刀片式IO,采用Push-in端子,免工具接线,节省空间和时间。
  9. 易互联、易组网
  10. 本地集成多种工业网络通信协议,轻松对接数据采集系统和周边设备。
  11. 支持扩IP模块,实现设备内外网隔离,无需修改设备内部网络配置即可接轨上位系统。
  12. 双网口设计,省网线省交换机,便捷组网可级联。
  13. 易编程、模块化
  14. 完全自主化的编程软件,持续迭代易用性功能,符合工程师应用习惯。
  15. 支持ST语言编程,工程师可轻松编写复杂算法和逻辑。
  16. 支持功能块封装,工艺算法复用;支持离线调试和联合离线仿真,提高编程效率,缩短项目调试周期。
二、应用场景

汇川EASY系列PLC适用于多种应用场景,包括但不限于:

  • 严苛体积要求的自动化设备
  • 多轴运动控制场景
  • 温度、压力、流量等过程控制场景
  • 通信组网需求高的场景
  • 三、产品系列

    汇川EASY系列PLC包括多个子系列,如EASY300系列和EASY500系列等,每个系列都有其特定的应用场景和优势:

  • EASY300系列:适用于离散单机,设备相对简单,工艺不复杂,追求易用、便宜和快速交易。
  • EASY500系列:适用于快速交付需求市场,交期很紧,点位控制居多,追求快速交付和现场零调试。
  • 四、市场评价

    汇川EASY系列PLC在市场上受到了广泛的关注和好评。其卓越的性能、易用的特性和广泛的应用场景使得它成为中小型自动化设备领域的热门选择。同时,汇川技术作为国产PLC的领军企业之一,其产品的质量和售后服务也备受用户信赖。

    综上所述,汇川EASY系列PLC是一款功能强大、易于使用、灵活扩展、高效互联的全场景紧凑型小型PLC。它能够满足用户对中小型自动化设备的各种需求,为自动化行业的发展贡献自己的力量。

    实验要求

    实验需要分别测量输入端和输出端压力流量温度,上位机实时显示传感器值,每个量的波形曲线显示,数据保存到MYSQL数据库

    编程软件AutoShop是汇川小型PLC的专用上位机软件,它提供了友好的编程和调试环境,支持多种编程语言,并具备丰富、强大的通讯和控制功能。

    PLC配置

    确定PLC的网络配置

    确认PLC的IP地址:确保PLC已经配置了有效的IP地址,以便它可以通过以太网与你的网络中的其他设备通信。

    检查网络设置:验证PLC的网络设置(如子网掩码、网关等)是否正确,并确保它与你的网络兼容。

    确定PLC的通信协议

    确定PLC使用的通信协议,如Modbus TCP、Ethernet/IP、Profinet等。选择使用Python作为上位机进行通信。例如,对于Modbus TCP,使用pymodbus库。

    IO端口映射

    对于直接连接到PLC的IO模块或远程IO模块,需要在PLC程序中设置IO映射,以便将特定的物理IO端口映射到PLC内部的逻辑地址或寄存器上

    GL20-4AD模块配置和参数设置

    对于4-20mA的输入,需要设置相应的输入通道为电流输入模式,使能通道以接收4-20mA(对应0-20000)的模拟量输入,可根据具体需求修改

    PYTHON上位机

    数值转换

    根据购买的传感器量程转换,将PLC返回的数据解析为实际值,这里转换有些误差,有更好的转换方法欢迎指出

    # 压力转换
    def convert_value(raw_value):
        return (raw_value / 20000) * 4
    
    
    # 流量转换
    def convert_value_2(raw_value):
        return (raw_value / 20000)* 120
    
    
    # 温度转换
    def convert_value_3(return_value):
        return -50 + (return_value / 20000) * (200 - (-50))
    MYSQL数据库创建数据表
    # MySQL数据库
    conn = pymysql.connect(user='root', password='123456', host='localhost', database='plc')
    cursor = conn.cursor()
    cursor.execute("DROP TABLE IF EXISTS sensor_data")
    CREATE TABLE sensor1_data(  
        id INTEGER PRIMARY KEY AUTO_INCREMENT,  
        time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  
        input_pressure FLOAT,  
        input_flow FLOAT,  
        input_temperature FLOAT,  
        output_pressure FLOAT,  
        output_flow FLOAT,  
        output_temperature FLOAT  
    ) 
    cursor.execute(createTab)
    
    QT主程序

    使用PYQT显示六个传感器实际值到界面,绘制实时曲线并保存到MYSQL数据库

    
    class PlotWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            # 连接PLC
            self.plc_ip = '192.168.1.2'
            self.plc_port = 502
            self.client = ModbusTcpClient(self.plc_ip, port=self.plc_port)
    
            # 设置主窗口
            self.setWindowTitle('波形曲线据显示')
            self.setGeometry(800, 300, 1200, 1000)
    
            # 创建绘图部件
            self.central_widget = QWidget()
            self.setCentralWidget(self.central_widget)
            self.canvas = FigureCanvas(Figure())
            layout = QVBoxLayout(self.central_widget)
            layout.addWidget(self.canvas)
    
            # 初始化图表
            self.fig = self.canvas.figure
            self.axs = self.fig.subplots(3, 2)
            self.lines = []
            self.labels = ['Input Pressure', 'Output Pressure', 'Input Flow', 'Output Flow', 'Input Temperature',
                           'Output Temperature']
            self.x = np.arange(100)
            self.y = np.zeros((6, 100))
            self.values = np.zeros(6)
    
            for i in range(3):
                for j in range(2):
                    ax = self.axs[i, j]
                    ax.set_xlim(0, 100)
                    ax.grid(True)
                    ax.set_ylabel(self.labels[i * 2 + j])
                    ax.set_xlabel("Time")
                    line, = ax.plot(self.x, self.y[i * 2 + j])
                    self.lines.append(line)
    
            self.axs[0, 0].set_ylim(0, 4000)
            self.axs[0, 1].set_ylim(0, 4000)
            self.axs[2, 0].set_ylim(-50, 200)
            self.axs[2, 1].set_ylim(-50, 200)
            self.axs[1, 1].set_ylim(10, 120)
            self.axs[1, 0].set_ylim(10, 120)
    
    
            # 启动一个线程用于读取PLC数据
            self.plc_thread = threading.Thread(target=self.read_plc_data)
            self.plc_thread.start()
    
            # 定时器更新图表
            self.timer = self.fig.canvas.new_timer(interval=100)
            self.timer.add_callback(self.update_plot)
            self.timer.start()
    
            # 传感器数据界面
            self.data_window = QWidget()
            self.data_window.setWindowTitle('传感器值')
            self.data_window.setGeometry(400, 300, 400, 1000)
            layout = QVBoxLayout(self.data_window)
            self.labels = []
            for i in range(6):
                label = QLabel()
                self.labels.append(label)
                layout.addWidget(label)
    
            self.data_window.show()
    
        def update_plot(self):
    
            for i in range(6):
                data = self.y[i]
                data[:-1] = data[1:]
                data[-1] = self.values1[i]
                line = self.lines[i]
                line.set_data(self.x, data)
                self.axs[i // 2, i % 2].relim()
                self.axs[i // 2, i % 2].autoscale_view(True, True, True)
                line.set_color('r')
                line.set_linewidth(2.0)
    
            self.fig.canvas.draw()
    
        def read_plc_data(self):
            while True:
                if self.client.connect():
                    addresses = [100, 101, 102, 103,104, 105]
                    count = 1
                    new_values = []
                    for address in addresses:
                        response = self.client.read_holding_registers(address, count, unit=1)
                        if response.isError():
                            print(f"读取寄存器数据时发生错误:{response}")
                        else:
                            new_values.append(response.registers[0])
    
                    self.values = new_values
                    value0_raw=self.values[0]
                    print(value0_raw)
                    print(self.values[2])
                    # print(self.values[1])
                    if value0_raw<0:
                        value0_raw=0
                    value1 = convert_value(self.values[0])
                    # value1 = convert_value(value0_raw)
                    value2 = convert_value_2(self.values[1])
                    value3 = convert_value_3(self.values[2])
                    value4 = convert_value(self.values[3])
                    value5 = convert_value_2(self.values[4])
                    value6 = convert_value_3(self.values[5])
                    self.values1 = [value1, value4, value2, value5, value3, value6]
    
                    sql = ("INSERT INTO sensor1_data "
                           "(TIME, InputPressure,InputFlow, InputTemperature,OutputPressure, OutputFlow, "
                           "OutputTemperature) "
                           "VALUES (%(TIME)s, %(InputPressure)s, %(InputFlow)s, %(InputTemperature)s, %(OutputPressure)s,"
                           "%(OutputFlow)s,%(OutputTemperature)s)")
    
                    data = {
                        'TIME': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                        'InputPressure': str(value1),
                        'InputFlow': str(value2),
                        'InputTemperature': str(value3),
                        'OutputPressure': str(value4),
                        'OutputFlow': str(value5),
                        'OutputTemperature': str(value6)
                    }
                    cursor.execute(sql, data)
                    conn.commit()
    
                    labels_text = [
                        f'输入侧压力: {value1:.2f} MPa',
                        f'输入侧流量: {value2:.2f} m³/h',
                        f'输入侧温度: {value3:.2f} °C',
                        f'输出侧压力: {value4:.2f} MPa',
                        f'输出侧流量: {value5:.2f} m³/h',
                        f'输出侧温度: {value6:.2f} °C'
                    ]
                    font = QFont()
                    font.setPointSize(20)
                    for i in range(6):
                        self.labels[i].setFont(font)
                        self.labels[i].setText(labels_text[i])
    
                    # 关闭连接
                    self.client.close()
                else:
                    print("无法连接到PLC")
    
                time.sleep(0.1)
    

    作者:passion更好

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用Python作为上位机实现汇川EASY300实验:PLC与传感器连接实时数据展示及曲线绘制,数据保存至MYSQL数据库

    发表回复