汇川EASY300实验——python作为上位机,PLC与传感器相连,实时显示传感器值并绘制曲线,保存到MYSQL数据库

news/2024/9/1 2:31:04 标签: 笔记, PLC

目录

引言

一、产品特点

二、应用场景

三、产品系列

四、市场评价

实验要求

PLC%E9%85%8D%E7%BD%AE-toc" style="margin-left:80px;">PLC配置

PLC%E7%9A%84%E7%BD%91%E7%BB%9C%E9%85%8D%E7%BD%AE-toc" style="margin-left:120px;">确定PLC的网络配置

PLC%E7%9A%84%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE-toc" style="margin-left:120px;">确定PLC的通信协议

IO端口映射

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

PYTHON上位机

数值转换

MYSQL数据库创建数据表

QT主程序


引言

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

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

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

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

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

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

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

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

实验要求

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

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

PLC%E9%85%8D%E7%BD%AE">PLC配置

PLC%E7%9A%84%E7%BD%91%E7%BB%9C%E9%85%8D%E7%BD%AE">确定PLC的网络配置

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

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

PLC%E7%9A%84%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE">确定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)

http://www.niftyadmin.cn/n/5561675.html

相关文章

ELK日志管理与应用

目录 一.ELK收集nginx日志 二.收集tomcat日志 三.Filebeat 一.ELK收集nginx日志 1.搭建好ELKlogstashkibana架构 2.关闭防火墙和selinux systemctl stop firewalld setenforce 0 3.安装nginx [rootlocalhost ~]# yum install epel-release.noarch -y [rootlocalhost …

PDF公式转Latex

文章目录 摘要数据集 UniMER介绍下载链接 LaTeX-OCRUniMERNet安装UniMER 用的数据集介绍下载链接 PDF-Extract-Kit整体介绍效果展示评测指标布局检测公式检测公式识别 使用教程环境安装参考[模型下载](models/README.md)下载所需模型权重 在Windows上运行在macOS上运行运行提取…

LLaMA-Factory

文章目录 一、关于 LLaMA-Factory项目特色性能指标 二、如何使用1、安装 LLaMA Factory2、数据准备3、快速开始4、LLaMA Board 可视化微调5、构建 DockerCUDA 用户&#xff1a;昇腾 NPU 用户&#xff1a;不使用 Docker Compose 构建CUDA 用户&#xff1a;昇腾 NPU 用户&#xf…

把当前img作为到爷爷的背景图

&#xff08;忽略图大小不一致&#xff0c;一般UI给的图会刚好适合页面大小&#xff0c;我这网上找的图&#xff0c;难调大小&#xff0c;我行内的就自己随便写的宽高&#xff09;&#xff0c;另外悄悄告诉你最后有简单方法&#xff5e;&#xff5e; 先来看看初始DOM结构代码 …

C++--copy

copy 拷贝,把源迭代器区间的值拷贝到目的迭代器。使用者保证目的空间足够。时间复杂度O(n)。 函数声明如下: template<class InputIterator, class OutputIterator> OutputIterator copy( InputIterator _First, //源开始迭代器 InputIterator _Last, //源结束迭代…

四六级词汇小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;英语词汇管理&#xff0c;易错词管理&#xff0c;学习笔记管理&#xff0c;签到打卡管理&#xff0c;论坛管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;英语词汇&…

C++写一个线程池

C写一个线程池 文章目录 C写一个线程池设计思路测试数据的实现任务类的实现线程池类的实现线程池构造函数线程池入口函数队列中取任务添加任务函数线程池终止函数 源码 之前用C语言写了一个线程池&#xff0c;详情请见&#xff1a; C语言写一个线程池 这次换成C了&#xff01;…

beego框架_golang web框架_使用介绍

beego简介 beego是一个用于快速开发Go应用的http框架&#xff0c;由Go语言方面的技术大牛设计。beego可以用来快速开发API、Web、后端服务等各种应用&#xff0c;是一个RESTful的框架&#xff0c;主要设计灵感来源于tornado、sinatra、flask这三个框架&#xff0c;但结合了Go本…