From 9400b9e89193c189e6ee995465acb3c84fe3a529 Mon Sep 17 00:00:00 2001 From: Tyrone CT Date: Thu, 27 Feb 2025 15:28:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A5=E9=AA=A4=E4=B8=8B=E5=8F=91=E6=9B=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/ProModelPars/ProExModel.cs | 70 +++++++-- CapMachine.Wpf/Services/DataRecordService.cs | 7 +- .../Services/MachineRtDataService.cs | 26 ++-- CapMachine.Wpf/Services/ProRuntimeService.cs | 143 +++++++++++++++++- .../ViewModels/ProConfigViewModel.cs | 39 +++++ CapMachine.Wpf/Views/ProConfigView.xaml | 67 ++++++++ 6 files changed, 319 insertions(+), 33 deletions(-) diff --git a/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs b/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs index bfdab53..1f6e0e7 100644 --- a/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs +++ b/CapMachine.Wpf/Models/ProModelPars/ProExModel.cs @@ -56,6 +56,7 @@ namespace CapMachine.Wpf.Models.ProModelPars /// /// 程序步骤集合 + /// 在ProRuntimeService中已经初始实例化 /// public List ListProStepExe { get; set; } @@ -118,6 +119,12 @@ namespace CapMachine.Wpf.Models.ProModelPars public DateTime StepEndDt { get; set; } + /// + /// 循环扫描每个参数的结束时间是否到达的线程是一个线程循环执行,逐个执行,理论上每个都不同步,有一点点时间差,就是执行步骤会延后一点点 + /// 我们的打点斜坡数据是自己的定时器执行的,每个参数同步执行,而且是有一点点提前执行的,因为先打点执行循环后再计算结束时间 + /// 以上的就会造成,当新步骤到来执行时,其实之前的步骤的斜率打点的步骤可能已经打点完毕了,那么是乐见这样的状态,防止了两个的时间冲突问题。 + /// + private DateTime _CurrentDateTime; /// /// 当前时间 @@ -142,7 +149,7 @@ namespace CapMachine.Wpf.Models.ProModelPars if (NextProStepExe == null) { Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + - $"【Msg】:没有下一步,当前仪表参数全部执行完毕 "); + $"【Msg】:当前仪表参数全部执行完毕 "); //为空时不执行后续的数据 RunEnable = false; @@ -152,7 +159,7 @@ namespace CapMachine.Wpf.Models.ProModelPars Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + $"【程序Seg】{CurProStepExe.ProSegName} " + $"【程序步骤】{CurProStepExe.MeterStep} " + - $"【Msg】:时间到,开始执行下一步步骤 "); + $"【Msg】:新步骤开始执行-----------> "); ////////首先判断参数是否相同/////////// @@ -181,8 +188,10 @@ namespace CapMachine.Wpf.Models.ProModelPars //存在坡度数据 var SecStepDur = NextProStepExe.EndSV - NextProStepExe.StartSV; var SecStepValue = SecStepDur * 1.0 / NextProStepExe.KeepTime; - //先清除数据 - ListSlopExStep.Clear(); + + //如果ListSlopExStep上还在执行打点任务的话,则如何处理 + //先清除数据,并暂停 + StopSlopExStep(); //组装斜坡数据,按照秒为间隔发送 for (var i = 1; i <= NextProStepExe.KeepTime; i++) { @@ -212,6 +221,12 @@ namespace CapMachine.Wpf.Models.ProModelPars CurLoadPID = PidResult == true ? new PID() { P = (short)NextProStepExe.CurConfigPIDDto.P, I = (short)NextProStepExe.CurConfigPIDDto.I, D = (short)NextProStepExe.CurConfigPIDDto.D } : new PID(), RunStepType = GetRunStepType(PidResult, LimitResult, true), }); + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【程序Seg】{CurProStepExe.ProSegName} " + + $"【程序步骤】{CurProStepExe.MeterStep} " + + $"【SV】{NextProStepExe.EndSV} " + + $"【保持时间】{NextProStepExe.KeepTime} 秒" + ); } @@ -257,7 +272,7 @@ namespace CapMachine.Wpf.Models.ProModelPars //设置下一步步骤运行时间 RunEnable = true; - + } else { @@ -313,10 +328,21 @@ namespace CapMachine.Wpf.Models.ProModelPars /// private void StartSlopExStep() { - //用SlopExEnable控制,存在一个可能,就是设置后,立刻执行,那么第一个步骤(第一秒)时间会被压缩,后面就正常了。最大是快一秒了,第一秒提前打点,这是可以接受的。 + //用SlopExEnable控制,存在一个可能,就是设置后,立刻执行,那么第一个步骤(第一秒)时间会被压缩,后面就正常了。最大是快一秒了,第一秒提前打点,这是可以接受的, + //结合步骤的扫描执行,形成时间差,就是新步骤到来时,斜率打点已经执行完毕,防止冲突,乐见这个状态 SlopExEnable = true; } + /// + /// 停止执行打点任务的执行 + /// + private void StopSlopExStep() + { + SlopExEnable = false; + //清空数据 + ListSlopExStep.Clear(); + } + /// /// 斜率执行步骤集合 /// 打点集合 @@ -363,15 +389,22 @@ namespace CapMachine.Wpf.Models.ProModelPars $"【斜坡打点值SV】{NoExData.First().SV} " + $"【Msg】:发送斜坡打点 "); + //执行一个循环打点后判断是否整个打点循环执行完毕 + if (!ListSlopExStep.Where(a => a.IsHasEx == false).Any()) + { + //执行完毕就标记状态 + SlopExEnable = false; + Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + + $"【程序Seg】{CurProStepExe.ProSegName} " + + $"【程序步骤】{CurProStepExe.MeterStep} " + + $"【Msg】:斜坡打点执行完毕 "); + } } else { //执行完毕了,没有要执行的数据效率 SlopExEnable = false; - Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 【参数名称】:{MeterName} " + - $"【程序Seg】{CurProStepExe.ProSegName} " + - $"【程序步骤】{CurProStepExe.MeterStep} " + - $"【Msg】:斜坡打点执行完毕 "); + return; } } @@ -385,6 +418,23 @@ namespace CapMachine.Wpf.Models.ProModelPars } } + /// + /// 周期斜坡打点暂停执行 + /// + public void PauseSlopExCyclePause() + { + SlopExEnable = false; + } + + /// + /// 周期斜坡打点 继续运行 + /// + public void ContinueSlopExCyclePause() + { + SlopExEnable = true; + } + + /// /// 周期定时器 /// diff --git a/CapMachine.Wpf/Services/DataRecordService.cs b/CapMachine.Wpf/Services/DataRecordService.cs index 255ea79..3a80b49 100644 --- a/CapMachine.Wpf/Services/DataRecordService.cs +++ b/CapMachine.Wpf/Services/DataRecordService.cs @@ -204,6 +204,7 @@ namespace CapMachine.Wpf.Services //}).AsTable("RecordData").ExecuteAffrows(); + //实时数据记录管道数据监听 Task.Run(() => ListenRecoredChannelAction()); @@ -388,9 +389,9 @@ namespace CapMachine.Wpf.Services //增加日期和时间两个列 model.WorkDay = model.CreateTime.ToString("yyyy-MM-dd"); model.Time = model.CreateTime.ToString("HH:mm:ss"); - - + + return model; } @@ -440,7 +441,7 @@ namespace CapMachine.Wpf.Services var DataInfo = MachineRtDataService.TagManger.DicTags .ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value.EngPvValue); DataInfo.Add("创建时间", DateTime.Now); - + var RecordData = new RecordChannelData() { CreateTime = DateTime.Now, diff --git a/CapMachine.Wpf/Services/MachineRtDataService.cs b/CapMachine.Wpf/Services/MachineRtDataService.cs index cdb18f9..b281064 100644 --- a/CapMachine.Wpf/Services/MachineRtDataService.cs +++ b/CapMachine.Wpf/Services/MachineRtDataService.cs @@ -1592,23 +1592,23 @@ namespace CapMachine.Wpf.Services if (ProRunChannelData.RunStepType == RunStepType.SlopCell) { SiemensDrive.Write("D1", (short)ProRunChannelData.SV); - Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + - $"【参数名称】:{ProRunChannelData.MeterName} " + - $"【程序Seg】{ProRunChannelData.ProSegName} " + - $"【程序步骤】{ProRunChannelData.MeterStep} " + - $"【斜坡打点步骤】{ProRunChannelData.SlopStepNo} " + - $"【斜坡打点值SV】{ProRunChannelData.SV} " + - $"【Msg】:接受到仿真写入PLC OK "); + //Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + + // $"【参数名称】:{ProRunChannelData.MeterName} " + + // $"【程序Seg】{ProRunChannelData.ProSegName} " + + // $"【程序步骤】{ProRunChannelData.MeterStep} " + + // $"【斜坡打点步骤】{ProRunChannelData.SlopStepNo} " + + // $"【斜坡打点值SV】{ProRunChannelData.SV} " + + // $"【Msg】:接受到仿真写入PLC OK "); } else { SiemensDrive.Write("D1", (short)ProRunChannelData.SV); - Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + - $"【参数名称】:{ProRunChannelData.MeterName} " + - $"【程序Seg】{ProRunChannelData.ProSegName} " + - $"【程序步骤】{ProRunChannelData.MeterStep} " + - $"【步骤SV】{ProRunChannelData.SV} " + - $"【Msg】:接受到步骤仿真写入PLC OK "); + //Console.WriteLine($"【时间】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} " + + // $"【参数名称】:{ProRunChannelData.MeterName} " + + // $"【程序Seg】{ProRunChannelData.ProSegName} " + + // $"【程序步骤】{ProRunChannelData.MeterStep} " + + // $"【步骤SV】{ProRunChannelData.SV} " + + // $"【Msg】:接受到步骤仿真写入PLC OK "); } diff --git a/CapMachine.Wpf/Services/ProRuntimeService.cs b/CapMachine.Wpf/Services/ProRuntimeService.cs index 3803eee..a32334e 100644 --- a/CapMachine.Wpf/Services/ProRuntimeService.cs +++ b/CapMachine.Wpf/Services/ProRuntimeService.cs @@ -23,6 +23,8 @@ using System.Windows.Forms; using HslCommunication.Profinet.Siemens; using Masuit.Tools.Hardware; using CapMachine.Model.MeterConfig; +using Masuit.Tools; +using System.Timers; namespace CapMachine.Wpf.Services { @@ -164,8 +166,12 @@ namespace CapMachine.Wpf.Services //程序运行实时管道数据监听 //Task.Run(() => ListenProRunChannelAction()); + } + + + /// /// 选中的程序运行集合 /// @@ -206,10 +212,14 @@ namespace CapMachine.Wpf.Services return; } + //取消之前的程序执行 + EndProRun(); //先清空之前的步骤数据 foreach (var itemProExModel in ListProExModel) { itemProExModel.ListProStepExe.Clear(); + itemProExModel.ListSlopExStep.Clear(); + } //多个选中的程序块循环 @@ -251,6 +261,9 @@ namespace CapMachine.Wpf.Services { //单行步骤中包含多个仪表参数的配置,需要逐个仪表参数手动操作解析 + //统计当前步骤itemStep的速度所有时间,供后面的其他参数使用,因为其他的参数也是牟定当前步骤速度是总时间,在这个步骤中,所有的参数的总时间是一样的 + var SpeedStepTotaolTime = 0; + //********* 单个【速度】步骤信息的解析 ********* { var CurMeterName = "速度"; @@ -259,7 +272,9 @@ namespace CapMachine.Wpf.Services switch (itemStep.MeterSpeeds.FirstOrDefault()!.ValueType) { case ConfigValueType.Constant: //常值 - //常值的话就一个数据,循环执行一次 + //常值没有斜率和多个步骤,就一个总时间 + SpeedStepTotaolTime = itemStep.MeterSpeeds.FirstOrDefault()!.KeepTime; + //常值的话就一个数据,循环执行一次 foreach (var itemMeterValueCell in itemStep.MeterSpeeds) { var Pid = new ConfigPID(); @@ -307,10 +322,13 @@ namespace CapMachine.Wpf.Services ProStepInfo = $"{itemStep.StepNo}-{itemMeterValueCell.StepNo}", }); + } break; case ConfigValueType.Slope: //斜率 - //根据循环次数确定 + //斜率有多个步骤和循环的次数,统计一个总时间 + SpeedStepTotaolTime = itemStep.SpeedCycle * itemStep.MeterSpeeds.Sum(a => a.KeepTime); + //根据循环次数确定 for (int StepIndex = 0; StepIndex < itemStep.SpeedCycle; StepIndex++) { //根据循环次数执行 @@ -364,6 +382,7 @@ namespace CapMachine.Wpf.Services }); } } + break; default: break; @@ -494,6 +513,28 @@ namespace CapMachine.Wpf.Services } else { + //判断当前的参数是全部都没有设置还是这一步没有设置,如果这个步骤没有设置,则沿用上一个步骤数据 + var CurMeterListStepExe = ListProExModel.FindFirst(a => a.MeterName == CurMeterName).ListProStepExe; + if (CurMeterListStepExe.Any()) + { + //之前有步骤数据的话,则直接使用上一步的数据 + + //Copy这个步骤的数据 + var LastStepData = CurMeterListStepExe.OrderByDescending(a => a.MeterStep).FirstOrDefault().DeepClone(); + //处理这个步骤的数据-处理按照常值的恒定的模式运行,就是维持结束的常值数据 + LastStepData!.MeterStep = LastStepData.MeterStep + 1;//步骤+1 + LastStepData.KeepTime = SpeedStepTotaolTime;//时间是整个时间 + LastStepData.ExistSlop = false; + LastStepData.StartSV = LastStepData.EndSV; + LastStepData.ProStepInfo = $"{itemStep.StepNo}-{1}"; + //添加 + CurMeterListStepExe.Add(LastStepData); + //SpeedStepTotaolTime + } + else + { + //之前步骤没有数据的话,则放弃,不做任何处理 + } LogService.Warn($"【名称】: {CurMeterName} - 未找到步骤信息。步骤为空"); } @@ -590,12 +631,25 @@ namespace CapMachine.Wpf.Services //集合没有数据,不进行操作 return 0; } - } - #region 程序调度执行 + /// + /// 暂停的时间 + /// + public int PauseSecTime { get; set; } + + /// + /// 暂停开始时间 + /// + public DateTime PauseStartDt { get; set; } + + /// + /// 暂停结束时间 + /// + public DateTime PauseEndDt { get; set; } + /// /// 开始程序调度运行 /// @@ -614,20 +668,95 @@ namespace CapMachine.Wpf.Services itemProExModel.StepEndDt = DateTime.Now; } + ProRunTaskScanTimeEnable = true; //运行扫描任务 ProRunTimeScan(); } - private bool ProRunTaskEnable = true; + + /// + /// 结束程序调度执行 + /// + public void EndProRun() + { + ProRunTaskScanTimeEnable = false; + ProRunTimeScanTokenSource.Cancel(); + + //先清空当前步骤数据 + foreach (var itemProExModel in ListProExModel) + { + itemProExModel.ListProStepExe.Clear(); + itemProExModel.ListSlopExStep.Clear(); + } + } + + /// + /// 暂停程序调度执行 continue + /// + public void PauseProRun() + { + //开始暂停的计时 + PauseStartDt = DateTime.Now; + + //取消扫描 + ProRunTaskScanTimeEnable = false; + ProRunTimeScanTokenSource.Cancel(); + + //斜坡打点暂定 + foreach (var itemProExModel in ListProExModel) + { + itemProExModel.PauseSlopExCyclePause(); + } + } + + /// + /// 继续程序调度执行 + /// + public void ContinueProRun() + { + + PauseEndDt = DateTime.Now; + //统计的暂停的时间 + var PauseTime = (PauseEndDt - PauseStartDt).TotalSeconds; + + //斜坡打点暂定 + foreach (var itemProExModel in ListProExModel) + { + itemProExModel.ContinueSlopExCyclePause(); + itemProExModel.StepEndDt = itemProExModel.StepEndDt.AddSeconds(PauseTime < 0 ? 0 : PauseTime); + } + + //然后继续运行 + ProRunTaskScanTimeEnable = true; + //运行扫描任务 + ProRunTimeScan(); + + } + + + /// + /// 运行任务的Task扫描时间是否启用,这个等级较高,为False时,不进行扫描,整个方法取消执行 + /// 扫描时间判定是否切入下一步 + /// + private bool ProRunTaskScanTimeEnable { get; set; } = true; + + /// + /// 任务取消管理 + /// 用于管理取消操作 + /// + public CancellationTokenSource ProRunTimeScanTokenSource { get; set; } = new CancellationTokenSource(); + /// /// 运行时间扫描 /// private void ProRunTimeScan() { + ProRunTimeScanTokenSource = new CancellationTokenSource(); + ProRunTimeScanTask = Task.Run(async () => { - while (ProRunTaskEnable) + while (ProRunTaskScanTimeEnable) { try { @@ -648,7 +777,7 @@ namespace CapMachine.Wpf.Services } //Console.WriteLine($"扫描时间:{DiagnosticsTime.Elapsed.TotalMilliseconds.ToString()}"); } - }); + }, ProRunTimeScanTokenSource.Token); } diff --git a/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs b/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs index e3d91da..29b7123 100644 --- a/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs +++ b/CapMachine.Wpf/ViewModels/ProConfigViewModel.cs @@ -2297,6 +2297,45 @@ namespace CapMachine.Wpf.ViewModels } } + private DelegateCommand _ProRunSelectedDelete1; + /// + /// 删除命令 + /// + public DelegateCommand ProRunSelectedDelete1 + { + set + { + _ProRunSelectedDelete1 = value; + } + get + { + if (_ProRunSelectedDelete1 == null) + { + _ProRunSelectedDelete1 = new DelegateCommand((p) => ProRunSelectedDelete1Method(p)); + } + return _ProRunSelectedDelete1; + } + } + + private void ProRunSelectedDelete1Method(string Par) + { + if (Par.Contains("1")) + { + ProRuntimeService.EndProRun(); + } + else if (Par.Contains("2")) + { + ProRuntimeService.PauseProRun(); + } + else if (Par.Contains("3")) + { + ProRuntimeService.ContinueProRun(); + } + else + { + } + + } private DelegateCommand _GenProPlcCmd; /// diff --git a/CapMachine.Wpf/Views/ProConfigView.xaml b/CapMachine.Wpf/Views/ProConfigView.xaml index 7024f36..ec4e846 100644 --- a/CapMachine.Wpf/Views/ProConfigView.xaml +++ b/CapMachine.Wpf/Views/ProConfigView.xaml @@ -523,6 +523,73 @@ Text="删除" /> + + + +