using System.Diagnostics; using shjxCamera; using System.Drawing; using System.Windows.Forms; using System.Runtime.Intrinsics.Arm; namespace SHJX.Service.Control.Execute.TitrationController { public class Titration2Execute { private static readonly ILogger logger = LogFactory.BuildLogger(typeof(Titration2Execute)); public static bool Running = true; private static int titrationCount = 0; private static int slowSpeedCount = 0; private static int signalTimeLen = 10; private static int arriveRangeCount = 0; //突跃次数 private static List currSignals = new(); // 信号队列 private static List currSignalsCompare = new(); // 信号队列 private static ColorData2Graber _graber = Globals.Graber2; private static double balanceVal = 0; private static bool IsClean = true; private static readonly string titrationCamera = "D2_camera"; /// /// 滴定 /// /// 阈值 /// 体积 public static void Start(Titration2Arg arg, ref double amount) { Messager.Send("TitrationStart2"); if (Globals.Camera2 is null) { logger.LogDebug("2222222未找到摄像头,无法进行滴定操作"); return; } int threshold_gray = 5; // 色点过滤阈值 int threshold_hue = (int)arg.RangeValue; // 色相偏移阈值 int threshold_stable_check = arg.ArriveCheckCount; // 稳定检测时长 // string taskTag = $"{arg.BatchName}/{arg.TaskName}"; //Directory.CreateDirectory($"Data/{taskTag}"); //var csvWriter = new StreamWriter($"Data/{taskTag}.csv"); //csvWriter.Write("滴数,体积,红,绿,蓝,灰度,色调,饱和度,亮度\n"); //csvWriter.Flush(); // 滴定 int titrationCount = 0; List samplePoints = []; // 采样点 logger.LogCritical($"<22222222> 滴定开始(色相偏移阈值: {threshold_hue,2}, 稳定检测时长: {threshold_stable_check})"); // 快速滴定(一般用于标定) if (arg.WhetherQuicklyTitration) { bool quicklyTitrationRes = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).CheckWhetherArriveEndPoint().Execute(Convert.ToInt32(Math.Round(arg.QuicklyTitrationValue / arg.LiquidAmount * arg.LiquidConvertRatio))); if (quicklyTitrationRes) { amount += arg.QuicklyTitrationValue; logger.LogCritical("22222222快速滴定下发成功,等待15秒后继续滴定操作!"); Thread.Sleep(5 * 1000); } } //if (!ConfigInstance.IsAutomaticInLiquid)//滴定1有自动吸液,滴定2无自动吸液 // //{ int distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).CheckWhetherArriveEndPoint().Execute(LiquidSwitchPattern.In, distance); // //} // 滴定前等待 logger.LogCritical($"<22222222> 滴定前等待({arg.BeforeWaitTime}s)"); Thread.Sleep(arg.BeforeWaitTime * 1000); // 第0滴颜色采样(背景采样) ColorPoint cp = Globals.Camera2.SampleBackground(titrationCamera, threshold_gray, threshold_hue); if (cp.Hue < 10) { Messager.Send("TitrationStop2"); logger.LogCritical($"<22222222> 采集信号有误,退出滴定"); return; } logger.LogCritical($"<22222222> 第{titrationCount:D3}滴({amount:F3}), HSB({cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}), RGBL({cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3})"); //csvWriter.Write($"{titrationCount:D3},{amount:F3},{cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3},{cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}\n"); //csvWriter.Flush(); samplePoints.Add(cp); Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, cp.Hue)); Messager.Send("GraberColorValue2", cp.Hue); while (true) { // 达到最大滴定体积,结束滴定 if (amount >= arg.MaxDropVolume) { logger.LogCritical($"<2222222> 滴定结束(最大滴定量)"); break; } bool arriveEndPoint = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).IsArriveEndPoint; if (arriveEndPoint) { distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.In, distance); } LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.Out, arg.LiquidConvertRatio); titrationCount += 1; amount += arg.LiquidAmount; // 第N滴颜色采样 Thread.Sleep(1000); cp = Globals.Camera2.Sample( $"22222222/{titrationCount:D3}S", threshold_gray, threshold_hue); //csvWriter.Write($"{titrationCount:D3},{amount:F3},{cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3},{cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}\n"); //csvWriter.Flush(); samplePoints.Add(cp); logger.LogCritical($"<22222222> 第{titrationCount:D3}滴({amount:F3}), HSB({cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}), RGBL({cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3})"); //Application.Current.Dispatcher.BeginInvoke(delegate () //{ // ChartHelper.SaveGraph(samplePoints, taskTag); //}); Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, cp.Hue)); Messager.Send("GraberColorValue2", cp.Hue); if (ColorPoint.HueDiff(samplePoints.First(), samplePoints.Last()) < threshold_hue) { continue; } // 稳定判断: 达到阈值设定,进入稳定(褪色)检测 logger.LogCritical($"<22222222> 稳定检测(开始)"); bool stable = false; int chkCnt = 0; int retCnt = 0; Stopwatch sw = new(); sw.Start(); while (true) { // 到达稳定检测截止时限,完成检测 if (sw.ElapsedMilliseconds / 1000 >= threshold_stable_check) { logger.LogCritical($"22222222 稳定检测(完成)"); sw.Stop(); stable = true; break; } // 第N滴第i次稳定检测颜色采样 chkCnt++; Thread.Sleep(1000); cp = Globals.Camera2.Sample( $"22222222/{titrationCount:D3}T-{chkCnt:D2}", threshold_gray, threshold_hue); //csvWriter.Write($"{titrationCount:D3},{amount:F3},{cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3},{cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}\n"); //csvWriter.Flush(); samplePoints.Add(cp); logger.LogCritical($"22222222 稳定检测({chkCnt:D2}), HSB({cp.Hue,3},{cp.Saturation:F3},{cp.Brightness:F3}), RGBL({cp.R,3},{cp.G,3},{cp.B,3},{cp.Gray,3})"); Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, cp.Hue)); Messager.Send("GraberColorValue2", cp.Hue); if (ColorPoint.HueDiff(samplePoints.First(), samplePoints.Last()) < threshold_hue) { if (retCnt == 0) { retCnt++; continue; } logger.LogCritical($"22222222 稳定检测(中止)"); break; } else retCnt = 0; } // 稳定检测通过,滴定完成 if (stable) { logger.LogCritical($"22222222滴定结束(共{titrationCount:D3}滴, {amount:F3}ml)"); break; } } //csvWriter.Close(); // 保存图表 //string chartTitle = $"{taskTag} ({amount:F3}ml)"; //Application.Current.Dispatcher.BeginInvoke(delegate () //{ // ChartHelper.SaveGraph(samplePoints, $"{taskTag}", chartTitle); //}); Messager.Send("TitrationStop2"); logger.LogCritical($"******************************22222222滴定结束******************************"); //// 保存图表 //string chartTitle = $"{taskTag} ({amount:F3}ml)"; //Application.Current.Dispatcher.BeginInvoke(delegate () //{ // ChartHelper.SaveGraph(samplePoints, $"{taskTag}", chartTitle); //}); //Globals.EA?.GetEvent().Publish(new TitrationStatus() //{ // TitrationUnit = titrationUnit, // TaskTag = taskTag, // TitrationCount = titrationCount, // TitrationVolume = (float)amount, // SamplePoints = samplePoints, // IsRunning = false //}); } //try //{ // Messager.Send("TitrationStart2"); // if (Globals.Camera2 is null) // { // logger.LogDebug("22222222未找到摄像头,无法进行滴定操作"); // return; // } // Running = true; // titrationCount = 0; // slowSpeedCount = 0; // signalTimeLen = 10; // arriveRangeCount = 0; //突跃次数 // currSignals = new(); // 信号队列 // currSignalsCompare = new(); // 信号队列 // // _graber = Globals.Graber2; // balanceVal = -1 * arg.RangeValue; // if (!Globals.Camera2.IsOpened) // { // Globals.Camera2.OpenCamera(); // } // logger.LogCritical($"******************************22222222滴定开始******************************"); // if (arg.WhetherQuicklyTitration) //快速滴定判断 // { // bool quicklyTitrationRes = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).CheckWhetherArriveEndPoint().Execute(Convert.ToInt32(Math.Round(arg.QuicklyTitrationValue / arg.LiquidAmount * arg.LiquidConvertRatio))); // if (quicklyTitrationRes) // { // amount += arg.QuicklyTitrationValue; // logger.LogCritical("22222222快速滴定下发成功,等待15秒后继续滴定操作!"); // Thread.Sleep(5 * 1000); // } // } // Thread.Sleep(arg.BeforeWaitTime * 1000); // //if (!ConfigInstance.IsAutomaticInLiquid)//滴定1有自动吸液,滴定2无自动吸液 // //{ // int distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); // LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).CheckWhetherArriveEndPoint().Execute(LiquidSwitchPattern.In, distance); // //} // _graber.PresetLightParammanual(arg.explosion, 10); // _graber.PresetLightParam(-9); // Thread.Sleep(2000); // for (int i = 0; i < 7; i++) // 采集7段信号作为背景 // { // currSignals.Add(_graber.GrabSignal(500)); // currSignalsCompare.Add(currSignals[i]); // } // int times = 3; // while (JudgeManualTitration(currSignals)) // { // if (times == 0) // { // logger.LogCritical($"*******************22222222检测到异常样本!请尝试手工滴定*******************"); // return; // } // _graber.PresetLightParammanual(arg.explosion, 10); // _graber.PresetLightParam(-9); // Thread.Sleep(2000); // for (int i = 0; i < 7; i++) // 采集7段信号作为背景 // { // currSignals[i] = _graber.GrabSignal(500); // currSignalsCompare[i] = currSignals[i]; // } // times--; // } // if (IsClean) // { // logger.LogCritical($"*******************22222222干净样本滴定算法*******************"); // CleanSampleTitration(arg, ref amount); // } // else // { // logger.LogCritical($"*******************22222222复杂样本滴定算法*******************"); // ComplexSampleTitration(arg, ref amount); // } //} //catch (Exception ex) //{ // logger.LogError($"22222222滴定异常{DateTime.Now},ErrorInfo:{ex}"); //} //finally //{ // Messager.Send("TitrationStop2"); // logger.LogCritical($"******************************22222222滴定结束******************************"); //} // private static bool JudgeManualTitration(List currSignals) // { // double max = currSignals[0].GetRSV(); // double min = currSignals[0].GetRSV(); // for (int i = 1; i < currSignals.Count; i++) // { // if (currSignals[i].GetRSV() > max) // max = currSignals[i].GetRSV(); // if (currSignals[i].GetRSV() < min) // min = currSignals[i].GetRSV(); // } // if (max - min > 2.5 || max - min == 0 || min < 110 || max > 120) // return true; // else // return false; // } // private static void CleanSampleTitration(Titration2Arg arg, ref double amount) // { // ColorData2Point subRcurrSignals = new ColorData2Point(); // while (true) // { // if (currSignals.Count >= 7) // 信号判断 // { // double subR = 0.0; // int currpt = currSignals.Count - 6; // subRcurrSignals = _graber.GrabSignal(signalTimeLen); // currSignalsCompare.Add(subRcurrSignals); // subR = (subRcurrSignals.GetRSV() - ((currSignals[currpt - 1].GetRSV() + currSignals[currpt].GetRSV()) / 2)) * 100 / subRcurrSignals.GetRSV(); // if (subR > 0) // { // currSignals.Add(subRcurrSignals); // } // logger.LogCritical($"22222222当前第{titrationCount:D3}滴,体积:{amount:F3},阈值:{subR:F2}"); // Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, subR)); // if (subR <= balanceVal) // { // arriveRangeCount++; // Stopwatch swten = new(); // swten.Start(); // int retreatCount = 1; //后退次数 // int flag = 0; // while (true) //继续采集信号,监测是否褪色 // { // currpt = currSignals.Count - 6; // subRcurrSignals = _graber.GrabSignal(signalTimeLen); // currSignalsCompare.Add(subRcurrSignals); // subR = (subRcurrSignals.GetRSV() - ((currSignals[currpt - 1].GetRSV() + currSignals[currpt].GetRSV()) / 2)) * 100 / subRcurrSignals.GetRSV(); // if (subR > 0) // { // currSignals.Add(subRcurrSignals); // } // logger.LogCritical($"22222222已达设定阈值,观察是否褪色,阈值为:{subR}"); // if (subR <= balanceVal) // { // flag = 0; // retreatCount++; // if (swten.ElapsedMilliseconds / 1000 > arg.ArriveCheckCount) // { // break; // } // Running = false; // Thread.Sleep(1000); // continue; //颜色比较红,继续观察是否到30秒 // } // else if (++flag > 1) // { // Running = true; // if (retreatCount > 2) // { // slowSpeedCount = 5; //如果回退超过三次判定,则给定慢速10次 // logger.LogCritical($"22222222回退超过三次,给定慢速5次"); // } // break;//当检测到的信号值 大于阈值时,则滴定未结束,需要继续滴定 // } // else // { // retreatCount++; // Running = false; // Thread.Sleep(1000); // continue; //颜色比较红,继续观察是否到30秒 // } // } // swten.Stop(); // } // else // { // arriveRangeCount = arriveRangeCount > 0 ? arriveRangeCount - 1 : 0; // slowSpeedCount = slowSpeedCount > 0 ? slowSpeedCount - 1 : slowSpeedCount; // } // if (amount >= arg.MaxDropVolume) break; // if (!Running) break; // bool arriveEndPoint = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).IsArriveEndPoint; // if (arriveEndPoint) // { // int distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); // LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.In, distance); // } // bool res = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.Out, arg.LiquidConvertRatio); // if (!res) // { // logger.LogError("22222222写入失败,等待两秒后再次写入"); // Thread.Sleep(2000); // continue; // } // titrationCount += 1; // amount += arg.LiquidAmount; // Thread.Sleep((arriveRangeCount < 1 && slowSpeedCount < 1) ? arg.IntervalTime : 2000); // } // } // //CalibrationTitrationColor(arg, ref amount, titrationCount, balanceVal); // for (int i = 0; i < currSignals.Count; i++) // { // logger.LogCritical($"22222222currSignals r={currSignals[i].GetRSV()},g={currSignals[i].GetGSV()},num={i}"); // } // for (int i = 0; i < currSignalsCompare.Count; i++) // { // logger.LogCritical($"22222222currSignalsCompare r={currSignalsCompare[i].GetRSV()},g={currSignalsCompare[i].GetGSV()},num={i}"); // } // } // private static void ComplexSampleTitration(Titration2Arg arg, ref double amount) // { // ColorData2Point subRcurrSignals = new ColorData2Point(); // while (true) // { // if (currSignals.Count >= 7) // 信号判断 // { // double subR = 0.0; // int currpt = currSignals.Count - 6; // subRcurrSignals = _graber.GrabSignal(signalTimeLen); // //currSignalsCompare.Add(subRcurrSignals); // subR = (subRcurrSignals.GetRSV() - ((currSignals[currpt - 1].GetRSV() + currSignals[currpt].GetRSV()) / 2)) * 100 / subRcurrSignals.GetRSV(); // //if (subR > 0) // //{ // currSignals.Add(subRcurrSignals); // //} // logger.LogCritical($"22222222当前第{titrationCount:D3}滴,体积:{amount:F3},阈值:{subR:F2}"); // Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, subR)); // if (subR <= balanceVal) // { // arriveRangeCount++; // Stopwatch swten = new(); // swten.Start(); // int retreatCount = 1; //后退次数 // int flag = 0; // while (true) //继续采集信号,监测是否褪色 // { // currpt = currSignals.Count - 6; // subRcurrSignals = _graber.GrabSignal(signalTimeLen); // //currSignalsCompare.Add(subRcurrSignals); // subR = (subRcurrSignals.GetRSV() - ((currSignals[currpt - 1].GetRSV() + currSignals[currpt].GetRSV()) / 2)) * 100 / subRcurrSignals.GetRSV(); // //if (subR > 0) // //{ // currSignals.Add(subRcurrSignals); // //} // logger.LogCritical($"22222222已达设定阈值,观察是否褪色,阈值为:{subR}"); // if (subR <= balanceVal*0.7) // { // flag = 0; // retreatCount++; // if (swten.ElapsedMilliseconds / 1000 > arg.ArriveCheckCount) // { // break; // } // Running = false; // Thread.Sleep(1000); // continue; //颜色比较红,继续观察是否到30秒 // } // else if (++flag > 1) // { // Running = true; // if (retreatCount > 2) // { // slowSpeedCount = 5; //如果回退超过三次判定,则给定慢速10次 // logger.LogCritical($"22222222回退超过三次,给定慢速5次"); // } // break;//当检测到的信号值 大于阈值时,则滴定未结束,需要继续滴定 // } // else // { // retreatCount++; // Running = false; // Thread.Sleep(1000); // continue; //颜色比较红,继续观察是否到30秒 // } // } // swten.Stop(); // } // else // { // arriveRangeCount = arriveRangeCount > 0 ? arriveRangeCount - 1 : 0; // slowSpeedCount = slowSpeedCount > 0 ? slowSpeedCount - 1 : slowSpeedCount; // } // if (amount >= arg.MaxDropVolume) break; // if (!Running) break; // bool arriveEndPoint = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).IsArriveEndPoint; // if (arriveEndPoint) // { // int distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); // LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.In, distance); // } // bool res = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.Out, arg.LiquidConvertRatio); // if (!res) // { // logger.LogError("22222222写入失败,等待两秒后再次写入"); // Thread.Sleep(2000); // continue; // } // titrationCount += 1; // amount += arg.LiquidAmount; // Thread.Sleep((arriveRangeCount < 1 && slowSpeedCount < 1) ? arg.IntervalTime : 2000); // } // } // //CalibrationTitrationColor(arg, ref amount, titrationCount, balanceVal); // for (int i = 0; i < currSignals.Count; i++) // { // logger.LogCritical($"22222222currSignals r={currSignals[i].GetRSV()},g={currSignals[i].GetGSV()},num={i}"); // } // } // private static void CalibrationTitrationColor(Titration2Arg arg, ref double amount, int titrationCount, double balanceVal) // { // int count = 0; // if (amount >= 4 && amount < 6) // { count = 1; } // else if (amount >= 6 && amount < 8) // { count = 2; } // else if (amount >= 8 && amount < 9) // { count = 3; } // else if (amount >= 9) // { count = 4; } // for (int i = 0; i < count; i++) // { // bool arriveEndPoint = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).IsArriveEndPoint; // if (arriveEndPoint) // { // int distance = Convert.ToInt32(Math.Round(arg.PumpCapacity / arg.LiquidAmount * arg.LiquidConvertRatio)); // LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.In, distance); // } // bool res = LiquidPipeSwitchTitration2.StartNew.SetLiquidName(EquipmentNames.Titration2PotassiumPermanganate).Execute(LiquidSwitchPattern.Out, arg.LiquidConvertRatio); // if (!res) // { // logger.LogError("22222222写入失败,等待两秒后再次写入"); // Thread.Sleep(2000); // } // titrationCount += 1; // amount += arg.LiquidAmount; // Messager.Send("Titration2ValueChange", new Titration2ValueArgs(titrationCount, amount, balanceVal)); // logger.LogCritical($"22222222-------加入校准{i+1}滴"); // Thread.Sleep(300); // } // } // #endregion //} } }