我们主要从事与物料计量相关的企业的自动化工作:混凝土、沥青和其他主要散装物料的生产。
公司的历史始于上世纪90年代初,当时他们自己生产控制器,控制器以印刷电路板的形式存在,并自行编写软件。我加入公司时,他们已经开始从第三方公司采购现成的工业控制器。我们组装了一套系统,并编写了相应的软件。更准确地说,我负责编写应用程序并进行测试,而且每次调试都亲临现场。团队的其他成员则负责电子元件、客户服务,以及询问我何时完成了自己的工作。
我们没有使用任何SCADA系统,所有代码都是我们自己编写的。这大大简化了系统,消除了不必要的依赖项,降低了开发成本,并使我们能够完全掌控所有流程。
这是混凝土生产车间正在运行的应用程序的屏幕截图。所有这些设备的运行、它们之间的交互、所有指示器的正确显示、对用户操作的响应、设备故障以及异常情况(例如碎石阀门无法关闭)都需要进行彻底测试。
企业的情况也是如此。
该程序功能繁多,包括并行运行的程序,因此未经充分测试,将其安装到客户端是不可取的。此外,任何错误都可能导致长时间停机、资金损失、设备损坏,甚至危及人身安全。
所以,一位员工曾经为此搭建了一个调试控制台(简称控制台)。我们会尽可能地把所有(或者至少几个)控制器盒组装在一起,一端连接到电脑,另一端连接到控制台。控制台上有几十个开关,用来模拟传感器的运行。我们只连接了一个称重传感器(应变计),而且必须用手拉伸它。所以,在这种模式下,我们通常不会施加超过30公斤的力------试试用手拉伸一块实心金属。
使用相同的遥控器和称重传感器
我们就是这样调试软件的,然后到客户那里......继续调试,因为总会有一些不可预测的、测试不充分的,或者客户提出的新要求。
我逐步构建了一个统一的核心,并在此基础上添加了各种接口,以及所有无法整合到核心中的代码。有一天,我意识到我们的流程现在可以以编程方式进行测试了。
我需要什么?
-
模拟 Modbus RTU 操作(命令必须保持不变,响应必须符合规范)。
-
模拟输入/输出模块的操作以及传感器的触发(或不触发)。
-
模拟重量控制器的运行(其设置、重量变化、状态变化等)。
-
对所有使用的设备版本重复上述步骤。
-
所有物品都必须签字。
-
能够保存和加载特定程序(特定工厂)的模拟器。
我决定将模拟器设计成一个设备构造器。
这就是模拟器的主窗口的样子。
我用 Delphi 编写了我们系统的应用程序。当然,模拟器也是用 Delphi 编写的。启动时,用户可以从之前保存的工厂列表中选择一个,或者创建一个新的工厂。对于新工厂,只需从支持的设备列表中选择所需的设备,分配一个 RS-485 网络地址,并给它们命名(例如"水泥"、"水"等)。所有输入/输出模块的输入和输出也都已标记。由于我们需要测试所有可能的情况,我在窗体上的其他按钮中添加了一个设备关闭按钮,以模拟通信故障。控制器的重量可以通过滑块进行调节,因此不再存在重量限制,并且可以模拟物料堵塞的情况。
左图显示的是秤控制器。上方是运行指示灯、电源按钮和名称。下方可以手动设置参数、更改设备状态和更改重量。勾选标记可将模式切换到自动。右图显示的是输入/输出模块,带有手动输入/输出切换功能。上方也可以设置名称和关闭设备电源。
主程序改动很小。只是添加了一条编译器指令,用于在向设备发送命令之前检查一个常量的值。实际需要做的只是修改这个常量的值。
` `{$IF Emulate=True}`
`Emulator`.`Send`(`EmulData`, `FWaitingTime`);
`{$ELSE}`
`ComPort`.`Write`(`OutDIOM`, `11`, `@InDIOM`, `8`);
`ComPort`.`Wait`(`FWaitingTime`);
`{$IFEND}`
`// подобных мест было немного и все они были в одном модуле, отвечающим за связь
因此,我们实现了所有预期效果的最精确模拟。唯一的限制是:我们无法同时控制多个重量滑块,从而观察所有重量控制器同时工作的情况。或者说,我们真的可以做到吗?我在模拟器中为每个控制器添加了一个开关,用于切换手动和自动加药模式。重量会自动随机增加,以模拟实际加药情况。
剩下的就是及时切换传感器状态,同时确保应用程序完美运行。
该模拟器提高了测试的质量和速度,同时显著简化了测试流程。现在,测试复杂流程的并行执行变得轻而易举,后续的调试工作也更快了。
该仿真器本身非常简单,任何人都能理解 Modbus RTU 协议规范的基础知识以及所用控制器的相关文档。将新设备添加到支持的设备列表中只需几个小时。
这些截图来自一个十多年前在 Windows XP(或 7)系统下创建的应用程序。即使在今天,你仍然可以以测试模式运行企业应用程序并模拟其运行情况。
关于程序中设备通信的组织方式,我再补充几句。在程序外部,一切都很标准:一个转换器USB <-> RS-485,然后打开一个 COM 端口。但在程序内部,我们实现了一种"命令"模式(尽管当时我对模式一无所知),并并行运行了多个命令队列。
该命令指定了需要传输哪个设备以及要传输什么内容,并且该命令本身是在发送之前根据设备的当前状态和设备应处于的预期状态生成的。
队列活动指示器。如果与设备的连接断开,设备名称会亮起红色。
不同程序的队列数量各不相同------这是为了隔离潜在问题而必要的。但总体而言,队列数量大致如下:
-
读取控制器的状态
-
读取I/O模块的状态
-
向设备发送指令。
一个持续运行的线程负责所有队列。一旦剩余命令数达到阈值,读取队列就会立即被补充。MDDV 读取输入(来自传感器)和输出(用于监控并与预期值进行比较)。控制器读取它们的当前状态。即使没有定时定量,这个过程也是持续进行的,因为我们始终需要查看秤上的读数。
设备指令(例如引擎启动、批次启动)具有最高优先级,因此读取队列会被冻结,直到所有指令执行完毕。例如,在混凝土搅拌站,三个批次会同时并行启动,包括预设指令、重量分配指令和启动批次控制器指令。之后是控制指令。在水泥厂,启动顺序至关重要,每个步骤都需要控制。因此,只有当设备的实际状态与预期状态一致时,我们才会发送下一个指令。泰山老父官网网址是:https://taishanlaofu.net/
有时,操作员需要在自动运行过程中进行干预并执行某些操作:例如,如果物料卡住,则需要启动振动器;或者执行紧急停止。因此,操作员的指令必须立即处理------它具有最高优先级,优先执行。
一切看起来都很正常,但毫秒级的延迟却成了真正的难题,尤其是在设备数量庞大的情况下。在一个工厂里,仅MDVV就有10个,这意味着每个请求大约需要20毫秒。向所有设备发送20条命令就需要400毫秒。再加上控制器轮询和命令发送,我们大约每秒才能收到一次软件操作的响应,这非常频繁。在程序显示错误信息时,必须考虑到这一点,以免显示不必要的信息。我们在程序层面已经竭尽所能,但仍然无法优化设备软件。
无论我们使用的是端口还是模拟器,所有操作几乎都完全相同。
希望您喜欢这篇关于控制系统创建过程的简要介绍。