我正在从事一个项目,其中使用 MODBUS PLC 控制器 (WAGO 750-891) 来控制一组 100 个阀门(Festo MH1 3/2 路电磁阀)。阀门需要以特定的频率进行切换,该频率在阀门之间有所不同,并且可以根据用 Python 编写的图像分割算法的结果实时变化。
我使用 PC 来控制 PLC,它充当 MODBUS TCP 客户端。
目前我正在开发单个阀门来测试代码性能。该代码以 20Hz 的开关频率打开和关闭单个阀门一分钟。之后,打印经过的时间。
在理想的世界中,经过的时间应该是 60 秒左右,但在我的情况下是 75 秒左右(1 5.4 Hz)。该代码是从终端执行的,终端是唯一打开的应用程序。该计算机配备 i5 第 11 代和 16 GB 内存。
我选择Python的主要原因是因为分割算法也是用Python编写的。不知道换成其他语言会不会影响代码之间的“沟通”
我想知道是否有一些方法可以提高代码性能,或者是否最好切换到 LabVIEW 等其他东西。我尝试了 Matlab,但代码甚至更慢(运行时间:88 秒)并且使用 PyPy 并没有显着提高性能。
这是我正在使用的代码:
import asyncio
import time
from pymodbus.client.tcp import AsyncModbusTcpClient as ModbusTCPClient
async def single_valve_pumping_cycle(client, valve):
i = 0
duration = 60 # in seconds
thread_frequency = 20 # Hz
main_t1 = time.time()
while i < duration * thread_frequency:
await client.write_coil(valve, False)
await asyncio.sleep(1 / thread_frequency)
i += 1
await client.write_coil(valve, True)
await asyncio.sleep(1 / thread_frequency)
i += 1
main_t2 = time.time()
main_delta = [main_t2 - main_t1]
print("The elapsed time is " + str(main_delta))
async def write_coils(client):
await client.connect()
await single_valve_pumping_cycle(client, 512)
async def main():
ip_address = '192.168.1.3' # Replace with your PLC's IP address
port = 502 # Modbus TCP port
client = ModbusTCPClient(ip_address, port)
await write_coils(client)
if __name__ == "__main__":
asyncio.run(main())
您是否使用落下的水幕来显示图像?这是你第一次看到它时完全令人瞠目结舌的事情之一:-)
我不知道人们应该对Python asyncio有多少期望,但它肯定值得尝试LabVIEW,可能使用定时循环结构来执行Modbus命令,并并行运行一个单独的循环以从Python获取数据代码并将其传递到定时循环中 - 如果您不想丢失任何数据,则使用队列;如果您只想要最新值,则使用通知程序或局部变量。您可能能够从 LabVIEW 调用 Python 代码,或者您可能需要在 Python 和 LabVIEW 之间实现自己的通信,例如使用 TCP/IP 或 UDP。
如果这还不够好,那么您可能只是遇到了在桌面操作系统上使用软件计时的限制。如果您可以更改硬件,那么您可以使用硬件定时I/O,其中您可以通过代码在硬件设备上提供缓冲区,然后根据硬件时钟写出数据 - LabVIEW 和 NI 数字 I/O 硬件当然可以做这个。或者,您可能需要迁移到实时平台,其中时序不会受到其他进程的影响 - NI 有 LabVIEW Real-Time,但如果您还没有许可证捆绑包,则需要额外费用,并且您可能需要也可以在专用硬件上运行它。或者,如果您已经了解 PLC 或微控制器编程,那么将实时代码放在这些平台之一上可能会更具成本效益和时间效益。
一个明显的问题是,您的 Modbus 设备是网络上唯一的设备吗?或者其他设备之间的流量是否会损害网络延迟?