using Bro.Common.Base;
|
using Bro.Common.Helper;
|
using Bro.Common.Interface;
|
using Bro.Common.Model;
|
using Bro.Device.InsCamera;
|
using Bro.M135.Common;
|
using Bro.M135.DBManager;
|
using Bro.Process;
|
using Bro.Process.DataBase.Models;
|
using Bro.UI.Model.Winform;
|
using HalconDotNet;
|
using Newtonsoft.Json;
|
using Newtonsoft.Json.Linq;
|
using NPOI.SS.Formula.Functions;
|
using Org.BouncyCastle.Asn1.X509;
|
using Org.BouncyCastle.Ocsp;
|
using ScottPlot.Drawing.Colormaps;
|
using Sunny.UI;
|
using Sunny.UI.Win32;
|
using System;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.Drawing.Imaging;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using Windows.ApplicationModel.Appointments;
|
using ZXing;
|
using static Bro.Common.Helper.EnumHelper;
|
using static Bro.Process.ProcessControl;
|
using static Org.BouncyCastle.Math.EC.ECCurve;
|
|
namespace Bro.M141.Process
|
{
|
public partial class M141Process : ProcessControl
|
{
|
#region constructor
|
public M141Process() { }
|
|
public M141Process(string productCode) : base(productCode) { }
|
#endregion
|
|
TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
|
public event Action<string, P_PRODUCT_DETAIL, string> OnSinglePostionDetectResultUpdate;
|
|
protected M141Config M141Config => Config as M141Config;
|
|
public static object _productListLock = new object();
|
public List<ProductModel> ProductList = new List<ProductModel>();
|
MachineLearningBase ML = null;
|
Spec _errorSpec = null;
|
|
//volatile int _productIndex = 0;
|
|
public M141Process_Mysql mysqlhelper = new M141Process_Mysql();
|
|
public event Action RerefreshBasketcodeUI;
|
|
public void RerefreshBasketcode()
|
{
|
RerefreshBasketcodeUI?.Invoke();
|
}
|
|
|
|
public override void InitialProcessMethods()
|
{
|
base.InitialProcessMethods();
|
|
if (ThHeartPlc == null)
|
{
|
ThHeartPlc = new Thread(Heartplc);
|
ThHeartPlc.IsBackground = true;
|
ThHeartPlc.Start();
|
}
|
}
|
|
public override void ProcessRunStateChanged()
|
{
|
base.ProcessRunStateChanged();
|
//if (CurrentState == EnumHelper.RunState.Running)
|
//{
|
// OldDataClear.Instance.SetAllowFlag(false, M141Config.DBDataTimeLimit);
|
//}
|
//else
|
//{
|
// OldDataClear.Instance.SetAllowFlag(true, M141Config.DBDataTimeLimit);
|
//}
|
}
|
|
public PLCBase Plc1;
|
bool devicestate = false;
|
PLCBase Plc2;
|
public Thread ThHeartPlc;
|
|
|
public override void Open()
|
{
|
base.Open();
|
devicestate = true;
|
ML = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase) as MachineLearningBase;
|
if (ML == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"未设置ML实例");
|
}
|
Plc1 = DeviceCollection.FirstOrDefault(u => u is PLCBase) as PLCBase;
|
|
if (Plc1 == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未设置plc");
|
}
|
_errorSpec = M141Config.SpecCollection.FirstOrDefault(u => u.Code == M141Config.CheckErrorSpecCode) as Spec;
|
|
//InitialProductList();
|
|
NetWarmUp();
|
|
_positionCheckTimeDict.Clear();
|
_positionSpecHeads.Clear();
|
|
mysqlhelper.IniDBIP(M141Config.IPforall);
|
RerefreshBasketcode();
|
}
|
|
|
public override void Close()
|
{
|
devicestate = false;
|
base.Close();
|
|
}
|
|
|
public void Heartplc()
|
{
|
Thread.Sleep(1000);
|
|
//Open();
|
|
string _statisticFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Statistic.json");
|
if (File.Exists(_statisticFilePath))
|
{
|
try
|
{
|
string dataStr = "";
|
using (StreamReader reader = new StreamReader(_statisticFilePath, System.Text.Encoding.UTF8))
|
{
|
dataStr = reader.ReadToEnd();
|
}
|
|
lock (StatisticRecordsFull)
|
{
|
var temRecords = JsonConvert.DeserializeObject<StatisticRecords_Full>(dataStr);
|
if (StatisticRecordsFull != null && temRecords != null)
|
{
|
StatisticRecordsFull.CurRecord = temRecords.CurRecord;
|
StatisticRecordsFull.HistoryRecord = temRecords.HistoryRecord;
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"产品统计信息反序列化异常");
|
StatisticRecordsFull = new StatisticRecords_Full();
|
}
|
}
|
|
int numsum = 0;
|
//List<int> Statelist = new List<int>();
|
|
|
Dictionary<string, List<int>> StateDIC = new Dictionary<string, List<int>>();
|
int numplc = 0;
|
while (true)
|
{
|
numplc++;
|
numsum++;
|
|
|
if (!devicestate)
|
{
|
Thread.Sleep(1000);
|
continue;
|
}
|
try
|
{
|
if (M141Config.WorkShiftList != null && M141Config.WorkShiftList.Count > 0 && numsum >= 0)
|
{
|
for (int i = 0; i < M141Config.WorkShiftList.Count; i++)
|
{
|
if (M141Config.WorkShiftList[i].IsClearProductSummary)
|
{
|
double timeshap = (DateTime.Now - M141Config.WorkShiftList[i].ShiftTime_Start).TotalMinutes % 1440;
|
|
if (timeshap > 0 && timeshap < 1)
|
{
|
StatisticRecordsFull.CurRecord.ProductSummary.RecordsList.Clear();
|
StatisticRecordsFull.CurRecord.DefectSummary.RecordsList.Clear();
|
numsum = -62;
|
}
|
}
|
}
|
}
|
|
lock (StatisticRecordsFull)
|
{
|
if (numsum > 20)
|
{
|
numsum = 0;
|
using (FileStream fileStream = new FileStream(_statisticFilePath, FileMode.OpenOrCreate, FileAccess.Write))
|
{
|
fileStream.Seek(0L, SeekOrigin.Begin);
|
string s = JsonConvert.SerializeObject(StatisticRecordsFull);
|
byte[] bytes = Encoding.UTF8.GetBytes(s);
|
fileStream.Write(bytes, 0, bytes.Length);
|
fileStream.SetLength(bytes.Length);
|
fileStream.Flush();
|
fileStream.Close();
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
|
}
|
|
|
try
|
{
|
if (numplc > 3)
|
{
|
numplc = 0;
|
if (Plc1 != null)
|
{
|
Plc1.WriteSingleAddress(M141Config.heartadd, 0, out _);
|
}
|
}
|
}
|
catch
|
{
|
|
}
|
|
|
try
|
{
|
string csvhead = "时间";
|
string csvdata = DateTime.Now.ToString("yyyyMMddHHmmss") + "T";
|
|
if (Plc1 != null)
|
{
|
foreach (var item1 in M141Config.PLCAlarm)
|
{
|
try
|
{
|
if (!item1.isused)
|
{
|
continue;
|
}
|
|
var alrams = item1.AlarmDetails;
|
var plcdev = DeviceCollection.FirstOrDefault(u => u.Id == item1.plcname) as PLCBase;
|
|
if (!StateDIC.ContainsKey(plcdev.Name))
|
{
|
StateDIC[plcdev.Name] = new List<int>();
|
}
|
|
foreach (var item in alrams.GroupBy(u => u.address))
|
{
|
int add = item.Key;
|
var readres = plcdev.Read(add, 1, out _)[0];
|
|
var Allbin = Convert.ToString(readres, 2).PadLeft(16, '0').Select(c => c - '0').ToArray();
|
|
Allbin = Allbin.Reverse().ToArray();
|
|
foreach (var item2 in item)
|
{
|
item2.value = Allbin[item2.address2];
|
}
|
}
|
List<int> list = new List<int>();
|
foreach (var item in alrams)
|
{
|
csvhead += $",{item.alarmname}";
|
csvdata += $",{(item.value == 1 ? "1" : "")}";
|
list.Add(item.value);
|
}
|
|
if (!StateDIC[plcdev.Name].SequenceEqual(list))
|
{
|
StateDIC[plcdev.Name].Clear();
|
StateDIC[plcdev.Name].AddRange(list);
|
|
CSVRecordAsync($"PLCstate_{plcdev.Name}.csv", csvdata, csvhead);
|
|
var showdata = alrams.Where(u => u.value == 1).Select(u => u.alarmname).ToList();
|
|
if (showdata == null)
|
{
|
showdata = new List<string>();
|
}
|
|
if (showdata.Count > 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"{plcdev.Name}报警 个数:{showdata.Count} {string.Join(',', showdata)}");
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{plcdev.Name}报警 个数:0");
|
}
|
}
|
}
|
catch
|
{
|
|
}
|
}
|
}
|
|
}
|
catch
|
{
|
|
}
|
|
Thread.Sleep(1000);
|
}
|
}
|
|
/// <summary>
|
/// 网络预热
|
/// </summary>
|
/// <exception cref="NotImplementedException"></exception>
|
private void NetWarmUp()
|
{
|
string warmUpImageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarmUp");
|
if (!Directory.Exists(warmUpImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"程序根目录下没有\"WarmUp\"预热图片文件夹");
|
return;
|
}
|
|
var ml = DeviceCollection.FirstOrDefault(u => u is MachineLearningBase && u.CurrentState == EnumHelper.DeviceState.DSOpen) as MachineLearningBase;
|
if (ml == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"预热时未能获取开启的深度学习驱动");
|
return;
|
}
|
var netNames = ml.IConfig.NetCollections.Where(u => u.IsEnabled).Select(u => u.Name).ToList();
|
var imageFiles = new DirectoryInfo(warmUpImageFolder).GetFiles().Select(u => u.FullName).ToList();
|
|
Parallel.ForEach(netNames, n =>
|
{
|
Parallel.ForEach(imageFiles, i =>
|
{
|
HImage hImage = new HImage();
|
hImage.ReadImage(i);
|
|
ml.RunNetEvaluate(n, hImage);
|
|
hImage.Dispose();
|
hImage = null;
|
});
|
});
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "深度学习驱动预热完成");
|
|
|
//if (M141Config.WarmUp && M141Config.WarmUpList.Count > 0)
|
//{
|
// M141Config.WarmUpList.AsParallel().ForAll(x =>
|
// {
|
// try
|
// {
|
// HImage im = new HImage(x.PicFilePath);
|
// var tool = GetHalconTool(null, "", x.HalconFilePath);
|
// if (tool != null)
|
// {
|
// //int num = 0;
|
// //for (int i = 0; i < 10; i++)
|
// //{
|
// try
|
// {
|
// var res = tool.RunProcedure(null, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", im } }, new List<string>() { "OUTPUT_Results_1", "OUTPUT_Results_2" }, null);
|
|
// //if (res != null)
|
// //{
|
// // if (res.Item1&& res.Item2[$"OUTPUT_Results_{i}"].HTupleToDouble()[0]!=-1234)
|
// // {
|
// // num++;
|
// // if (num >= 2)
|
// // {
|
// // LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"算法{x.HalconFilePath}预热完成{i}");
|
// // break;
|
// // }
|
// // }
|
// //}
|
// }
|
// catch
|
// {
|
|
// }
|
// //if (i==9)
|
// //{
|
// // LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败{num}");
|
// //}
|
// //}
|
// }
|
// im.Dispose();
|
|
// }
|
// catch
|
// {
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"算法{x.HalconFilePath}预热失败");
|
// }
|
// });
|
//}
|
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, "算法预热完成");
|
}
|
|
static object _positionCheckTimeLock = new object();
|
Dictionary<string, List<int>> _positionCheckTimeDict = new Dictionary<string, List<int>>();
|
Dictionary<string, List<string>> _positionSpecHeads = new Dictionary<string, List<string>>();
|
|
|
volatile int uploadId = 0;
|
|
|
public void NewProductIntoList(ProductModel p, bool isSaveDB)
|
{
|
lock (_productListLock)
|
{
|
ProductList.RemoveAll(u => u.PID == p.PID || u.SEQUENCE == p.SEQUENCE);
|
ProductList.Insert(0, p);
|
while (ProductList.Count > 200)
|
{
|
ProductList.RemoveAt(ProductList.Count - 1);
|
}
|
}
|
|
if (isSaveDB)
|
{
|
mysqlhelper.NewProduct(p);
|
}
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"{p.PID}_{p.SEQUENCE}产品入列完成");
|
}
|
|
public virtual ProductModel FindProductBySequence(string sequence, bool isEnabelQueue)
|
{
|
ProductModel p = null;
|
if (isEnabelQueue)
|
{
|
lock (_productListLock)
|
{
|
p = ProductList.FirstOrDefault(u => u.SEQUENCE == sequence);
|
}
|
}
|
|
if (p != null)
|
{
|
return p;
|
}
|
else
|
{
|
p = mysqlhelper.GetProduct(sequence);
|
if (p == null)
|
{
|
p = new ProductModel();
|
p.SEQUENCE = sequence;
|
p.PID = p.PID + "_" + sequence.Split('_')[sequence.Split('_').Length - 1];
|
|
p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Where(u => u.IsEnabled).Select(u => u.PositionName).ToList());
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"未能从数据库获取产品对象,使用临时新建产品对象 {sequence}");
|
}
|
NewProductIntoList(p, false);
|
}
|
|
return p;
|
}
|
|
public async Task RunImageCheckAsync(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, MeasureBind measureBind)
|
{
|
await Task.Run(() =>
|
{
|
List<DetectResult> resultList = new List<DetectResult>();
|
if (products == null || products.Count == 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空");
|
imgSet.HImage?.Dispose();
|
imgSet.HImage = null;
|
return;
|
}
|
|
try
|
{
|
List<string> pidList = products.Select(u => u.PID).OrderBy(u => u).ToList();
|
if (imgSet == null || imgSet.HImage == null)
|
{
|
throw new Exception($"产品{string.Join(",", pidList)}检测{measureBind.GetDisplayText()}未能获取图片对象");
|
}
|
|
RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedMonitorId, resultList);
|
RunCustomizedMethod(products, triggerText, triggerSource, imgSet, measureBind.CustomizedCombineMethodId, resultList);
|
|
//检测顺序 ML->自定义检测
|
if (!string.IsNullOrWhiteSpace(measureBind.DetectionId))
|
{
|
string detectionName = (ML.InitialConfig as MLInitialConfigBase).DetectionConfigs.FirstOrDefault(u => u.Id == measureBind.DetectionId)?.Name;
|
|
|
|
List<DetectResult> detectResults = ML?.RunMLDetectionSync(imgSet, pidList, measureBind.DetectionId, false, null, null, "", products[0].ImagePaths);
|
|
|
|
if (measureBind.WorkPosition == "P1" && M141Config.StationCode == "S5" && detectResults.GetDefectDescList().Count == 0)
|
{
|
var defecttem = detectResults.SelectMany(u => u.NetResults.SelectMany(m => m.DetectDetails)).Where(u => u.NetName == M141Config.defectname).ToList();
|
List<Netdefectdetail> Netdefectdetails = mysqlhelper.GetNetdefectdetails(products[0].SEQUENCE);
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN} 进入S3S5检测 S3数据{Netdefectdetails.Count} S5数据{defecttem.Count}");
|
|
int num = 0;
|
foreach (var item1 in defecttem)
|
{
|
double x1 = item1.Rect.Point_LU.X + item1.Rect.Width / 2.0;
|
double y1 = item1.Rect.Point_LU.Y + item1.Rect.Height / 2.0;
|
num++;
|
//HOperatorSet.AffineTransPoint2d(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
|
//HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}原坐标{num} {x1},{y1}");
|
HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}新坐标{num} {qx},{qy}");
|
|
|
Netdefectdetail temc = new Netdefectdetail()
|
{
|
centerX = qx,
|
centerY = qy,
|
name = M141Config.defectname,
|
};
|
if (Netdefectdetails.Any(u => u == temc))
|
{
|
item1.IsAbandoned = false;
|
item1.FinalResult = ResultState.NG;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{products[0].PID}_{products[0].SEQUENCE}工位{measureBind.WorkPosition} S3S5组合检测检出缺陷:{item1.NetName}");
|
break;
|
}
|
}
|
}
|
|
List<DetectResult> ngResults = new List<DetectResult>();
|
detectResults.GroupBy(u => u.PID).ToList().ForEach(u =>
|
{
|
if (u.ToList().Count > 0 && u.ToList().Any(m => m.ResultState != EnumHelper.ResultState.OK))
|
{
|
if (u.ToList().GetDefectDescList().Count == 0)
|
{
|
var errorSpec = _errorSpec.Copy();
|
errorSpec.Code = "检测TBD";
|
errorSpec.ActualValue = -999;
|
DetectResult ngResult = new DetectResult() { Specs = new List<ISpec>() { errorSpec }, PID = u.Key, Id = Guid.NewGuid().ToString() };
|
ngResults.Add(ngResult);
|
}
|
}
|
});
|
detectResults.AddRange(ngResults);
|
resultList.AddRange(detectResults);
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}");
|
|
var errorSpec = _errorSpec.Copy();
|
errorSpec.ActualValue = -999;
|
products.ForEach(p =>
|
{
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List<DetectResult>()
|
{
|
new DetectResult()
|
{
|
Specs = new List<ISpec>()
|
{
|
errorSpec
|
},
|
PID = p.PID,
|
}
|
});
|
});
|
}
|
finally
|
{
|
|
try
|
{
|
if (resultList.Count > 0)
|
{
|
products.ForEach(p =>
|
{
|
var pResults = resultList.Where(u => u.PID == p.PID).ToList();
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}");
|
});
|
}
|
|
products.ForEach(p =>
|
{
|
if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束");
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}");
|
}
|
});
|
|
|
if (resultList.Any(u => u.ResultState != EnumHelper.ResultState.OK))
|
{
|
|
if (measureBind.NGImageSwitch)
|
{
|
if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录");
|
}
|
else
|
{
|
string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "NG");
|
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
|
string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}";
|
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatNG))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatNG];
|
}
|
else
|
{
|
post = M141Config.ImageFormatNG.ToString().ToLower();
|
}
|
|
string ngImageFile = Path.Combine(folder, $"{id}.{post}");
|
var bitmap = imgSet.HImage.ConvertHImageToBitmap();
|
bitmap.Save(ngImageFile, M141Config.ImageFormatNG);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}NG图片已保存");
|
bitmap.Dispose();
|
}
|
}
|
}
|
else
|
{
|
|
if (measureBind.OKImageSwitch)
|
{
|
if (string.IsNullOrWhiteSpace(M141Config.NGImageFolder))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未配置NG图片保存目录");
|
}
|
else
|
{
|
string folder = Path.Combine(M141Config.NGImageFolder, DateTime.Now.ToString("yyyyMMdd"), measureBind.WorkPosition, "OK");
|
|
if (!Directory.Exists(folder))
|
{
|
Directory.CreateDirectory(folder);
|
}
|
|
string id = string.Join("_", products.Select(u => $"{u.PID}_{u.SN}")) + $"-{measureBind.ImageIndex}_{DateTime.Now.ToString("HHmmssfff")}";
|
string post = "";
|
if (ImageSet.ImageFormatPostDict.ContainsKey(M141Config.ImageFormatOK))
|
{
|
post = ImageSet.ImageFormatPostDict[M141Config.ImageFormatOK];
|
}
|
else
|
{
|
post = M141Config.ImageFormatOK.ToString().ToLower();
|
}
|
|
string ngImageFile = Path.Combine(folder, $"{id}.{post}");
|
var bitmap = imgSet.HImage.ConvertHImageToBitmap();
|
bitmap.Save(ngImageFile, M141Config.ImageFormatOK);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存");
|
bitmap.Dispose();
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}");
|
}
|
|
try
|
{
|
|
if (imgSet != null && imgSet.HImage != null)
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == measureBind.CameraId) as CameraBase;
|
List<IShapeElement> eleList = new List<IShapeElement>();
|
TextDisplay txt = new TextDisplay();
|
txt.LineLimit = M141Config.LineLimit_p;
|
txt.FontSize = M141Config.FontSize_p;
|
eleList.Add(txt);
|
|
txt.StartX = txt.StartY = 0;
|
|
txt.AddText(products[0].SN, products[0].SN != "NOREAD" ? Color.Lime : Color.Red, Color.Transparent);
|
txt.AddText(" ", Color.Transparent, Color.Transparent);
|
|
|
var specList = products[0].Details.SelectMany(u => u.ResultList.SelectMany(r => r.Specs)).ToList();
|
specList.ForEach(v =>
|
{
|
txt.AddText($"{v.Code} {v.GetMeasureValueStr(3)}", v.MeasureResult == true ? Color.Lime : Color.Red, Color.Transparent);
|
});
|
|
camera.SaveFitImage(eleList, imgSet);
|
}
|
}
|
catch
|
{
|
|
}
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片{imgSet.PID}开始释放");
|
imgSet.HImage?.Dispose();
|
imgSet.HImage = null;
|
imgSet.Dispose();
|
imgSet = null;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"图片已释放");
|
|
}
|
});
|
}
|
|
|
public async Task RunImageCheckAsync(List<ProductModel> products, string triggerText, string triggerSource, MeasureBind measureBind)
|
{
|
await Task.Run(() =>
|
{
|
List<DetectResult> resultList = new List<DetectResult>();
|
if (products == null || products.Count == 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"工位{measureBind.WorkPosition}检测时产品信息为空");
|
return;
|
}
|
|
try
|
{
|
|
RunCustomizedMethod(products, triggerText, triggerSource, null, measureBind.CustomizedMonitorId, resultList);
|
RunCustomizedMethod(products, triggerText, triggerSource, null, measureBind.CustomizedCombineMethodId, resultList);
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBind.WorkPosition}检测过程异常,{ex.ToString()}");
|
|
var errorSpec = _errorSpec.Copy();
|
errorSpec.ActualValue = -999;
|
products.ForEach(p =>
|
{
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, new List<DetectResult>()
|
{
|
new DetectResult()
|
{
|
Specs = new List<ISpec>()
|
{
|
errorSpec
|
},
|
PID = p.PID,
|
}
|
});
|
});
|
}
|
finally
|
{
|
|
try
|
{
|
if (resultList.Count > 0)
|
{
|
products.ForEach(p =>
|
{
|
var pResults = resultList.ToList();
|
p.AddNewDetectResults(M141Config.StationCode, measureBind.WorkPosition, pResults);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}添加工位{measureBind.WorkPosition}检测结果,数量{pResults.Count}");
|
});
|
}
|
|
products.ForEach(p =>
|
{
|
if (p.PositoinCheckDone(measureBind.WorkPosition, measureBind.CheckIndex, out string msg))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,该工位检测全部结束");
|
}
|
else
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{p.PID}_{p.SEQUENCE}工位{measureBind.WorkPosition}的第{measureBind.CheckIndex}检测完成,{msg}");
|
}
|
});
|
|
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{measureBind.WorkPosition},产品{string.Join(",", products.Select(u => u.PID))}的NG图片保存异常,{ex.GetExceptionMessage()}");
|
}
|
|
}
|
});
|
}
|
|
|
private void RunCustomizedMethod(List<ProductModel> products, string triggerText, string triggerSource, IImageSet imgSet, string methodId, List<DetectResult> resultList)
|
{
|
try
|
{
|
if (!string.IsNullOrWhiteSpace(methodId))
|
{
|
|
var monitorSet = Config.GetAllMonitorSet().FirstOrDefault(u => u.Id == methodId);
|
|
if (monitorSet.OpConfig is IImageCheckOperationConfig iConfig)
|
{
|
var opConfig = iConfig.Clone();
|
|
opConfig.Products = new List<ProductModel>(products);
|
opConfig.ImageSet = imgSet;
|
|
opConfig.TriggerStr = triggerText;
|
opConfig.TriggerSource = triggerSource;
|
|
|
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"图片id,{imgSet.id}");
|
var res = RunSelectedMonitorSetByManual(methodId, opConfig);
|
|
if (res.DataObj is List<DetectResult> dr)
|
{
|
dr.ForEach(r =>
|
{
|
r.IsPreTreatDone = r.IsNetCheckDone = r.IsAfterTreatDone = true;
|
r.SetResult();
|
});
|
resultList.AddRange(dr);
|
}
|
|
if (res.Result != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{res.Message}");
|
}
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"自定义检测过程异常,{ex.GetExceptionMessage()}");
|
}
|
}
|
|
|
|
|
|
#region plc
|
public ResponseMessage RunImageCheck_plc(IOperationConfig config)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
msg.Result = 1;
|
List<MeasureBind> measureBinds = new List<MeasureBind>();
|
string inputSequence = "";
|
var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
try
|
{
|
RunImageCheckPreTreat_plc(config, out measureBinds, out inputSequence);
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}");
|
msg.Result = -1;
|
msg.Message = ex.Message;
|
return msg;
|
}
|
|
List<string> cameraIds = measureBinds.Select(u => u.CameraId).ToList();
|
try
|
{
|
ConcurrentDictionary<MeasureBind, IImageSet> imgSetDicts = new ConcurrentDictionary<MeasureBind, IImageSet>();
|
var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == triggerDatas[0]);
|
|
measureBinds.AsParallel().ForAll(b =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == b.CameraId) as CameraBase;
|
if (camera != null)
|
{
|
imgSetDicts[b] = null;
|
|
try
|
{
|
imgSetDicts[b] = CollectHImage(camera, b.SnapshotOpConfig);
|
if (positionSet.ispiccover)
|
{
|
Plc1.WriteSingleAddress(positionSet.plcover, 1, out _);
|
}
|
}
|
catch (Exception ea)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{measureBinds[0].WorkPosition}的第{measureBinds[0].CheckIndex}检测获取图像信息异常 {ea.ToString()}");
|
}
|
|
var pList = b.ProductIndices.Select(pi =>
|
{
|
string sequence = $"{inputSequence}_{pi}";
|
return FindProductBySequence(sequence, true);
|
}).ToList();
|
|
RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, imgSetDicts[b], b);
|
}
|
else
|
{
|
var pList = b.ProductIndices.Select(pi =>
|
{
|
string sequence = $"{inputSequence}_{pi}";
|
return FindProductBySequence(sequence, true);
|
}).ToList();
|
|
RunImageCheckAsync(pList, config.TriggerStr, config.TriggerSource, b);
|
}
|
});
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测处理异常,{ex.GetExceptionMessage()}");
|
msg.Result = -1;
|
msg.Message = ex.Message;
|
return msg;
|
}
|
|
CheckPositionDoneAsync_plc(measureBinds[0].WorkPosition, inputSequence, config, cameraIds);
|
return msg;
|
}
|
|
|
public void RunImageCheckPreTreat_plc(IOperationConfig config, out List<MeasureBind> measureBinds, out string inputSequence)
|
{
|
Task.Run(() =>
|
{
|
SetProcessRunState(EnumHelper.RunState.Running);
|
});
|
|
measureBinds = new List<MeasureBind>();
|
inputSequence = "";
|
|
var triggerDatas = config.TriggerStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
if (triggerDatas.Length < 2)
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}解析失败,数据长度小于2");
|
}
|
|
string positionValue = triggerDatas[0];
|
int checkIndex = -1;
|
if (!int.TryParse(triggerDatas[1].Replace("Scan", ""), out checkIndex))
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}解析失败,未能获取检测序号");
|
}
|
|
|
var positionSet = M141Config.WorkPositionCollection.Where(u => u.IsEnabled).FirstOrDefault(u => u.TriggerValue == positionValue);
|
if (positionSet == null)
|
{
|
throw new ProcessException($"触发文本{config.TriggerStr}未能获取{positionValue}对应的可用工位信息");
|
}
|
|
measureBinds = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionSet.PositionName && u.CheckIndex == checkIndex).ToList();
|
if (measureBinds.Count == 0)
|
{
|
throw new ProcessException($"未能获取工位{positionSet.PositionName}的第{checkIndex}检测配置信息");
|
}
|
|
measureBinds.Select(u => u.CameraId).ToList().ForEach(c =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase;
|
if (camera != null)
|
{
|
camera.ClearImageBufferQueue();
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"相机{camera.Name}检测前清理缓存完成");
|
}
|
});
|
|
|
|
inputSequence = triggerDatas[triggerDatas.Length - 1];
|
|
string tempSequence = inputSequence;
|
|
string pidstr = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
measureBinds.Where(b => b.IsFirstPosition).ToList().ForEach(b =>
|
{
|
b.ProductIndices.ForEach(i =>
|
{
|
ProductModel p = new ProductModel();
|
p.SEQUENCE = $"{tempSequence}_{i}";
|
p.PID = $"{pidstr}T_{i}";
|
|
if (M141Config.Isreadbasketcode)
|
{
|
p.BasketCode = M141Config.basketcode;
|
}
|
else
|
{
|
p.BasketCode = mysqlhelper.Getbasketcode(p.SEQUENCE, out string sntem);
|
p.SN = sntem;
|
p.PID = $"{sntem}_{i}";
|
if ("NoRead".Equals(p.BasketCode))
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{p.PID}_{p.SEQUENCE}获取框具码失败 赋值Noread");
|
}
|
}
|
|
if (positionSet.IsLastPosition)
|
{
|
p.Initial(M141Config.StationCode, new List<string>() { positionSet.PositionName });
|
}
|
else
|
{
|
p.Initial(M141Config.StationCode, M141Config.WorkPositionCollection.Select(u => u.PositionName).ToList());
|
}
|
NewProductIntoList(p, true);
|
});
|
});
|
|
Thread.Sleep(50);
|
|
int de = 0;
|
measureBinds.Where(b => (b.CheckIndex == de || b.CheckIndex == 1) && b.ImageIndex == 0).AsParallel().ForAll(b =>
|
{
|
List<int> temint = new List<int>();
|
|
temint = new List<int>() { 1 };
|
|
temint.ForEach(i =>
|
{
|
string sequence = $"{tempSequence}_{i}";
|
var p = FindProductBySequence(sequence, b.IsEnabelQueryFromQueue);
|
|
//初始化产品的检测次数
|
var checkIndexList = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition && u.ProductIndices.Contains(i)).Select(u => u.CheckIndex).OrderBy(u => u).ToList();
|
p.InitialPositionCheckList(b.WorkPosition, checkIndexList, M141Config.StationCode);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{p.PID}_{p.SEQUENCE}已清理{b.WorkPosition}检测数据。当前已完成工位{string.Join(",", p.Details.Select(u => u.PositionName))}");
|
|
});
|
|
//初始化工位的检测次数
|
var positionCheckTimes = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == b.WorkPosition).Select(u => u.CheckIndex).ToList();
|
lock (_positionCheckTimeLock)
|
{
|
_positionCheckTimeDict[b.WorkPosition] = positionCheckTimes;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}初始化检测次数:{string.Join(",", positionCheckTimes)}");
|
}
|
});
|
|
measureBinds.AsParallel().ForAll(b =>
|
{
|
lock (_positionCheckTimeLock)
|
{
|
_positionCheckTimeDict[b.WorkPosition].RemoveAll(u => u == b.CheckIndex);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位{b.WorkPosition}开始第{b.CheckIndex}次检测,待检测序号:{string.Join(",", _positionCheckTimeDict[b.WorkPosition])}");
|
}
|
});
|
}
|
|
public async Task<List<ProductModel>> CheckPositionDoneAsync_plc(string positionName, string inputSequence, IOperationConfig config, List<string> cameraIds)
|
{
|
string triggerSource = config.TriggerSource;
|
return await _taskFactory.StartNew(() =>
|
{
|
try
|
{
|
string index = config.TriggerStr.Split(',')[1];
|
var positionSet = M141Config.WorkPositionCollection.FirstOrDefault(u => u.PositionName == positionName);
|
|
var checkRemains = _positionCheckTimeDict[positionName];
|
|
var pIndices = M141Config.MeasureBindCollection.Where(u => u.WorkPosition == positionName).SelectMany(u => u.ProductIndices).Distinct().OrderBy(u => u).ToList();
|
pIndices = new List<int> { 1 };
|
|
|
var pList = pIndices.Select(u =>
|
{
|
string sequence = $"{inputSequence}_{u}";
|
return FindProductBySequence(sequence, true);
|
}).ToList();
|
List<bool> plcresult = new List<bool>();
|
if (pList.Any(u => u == null))
|
{
|
plcresult = new List<bool>() { false, false, false };
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"获取工位{positionName}汇总结果时产品信息为空");
|
}
|
else
|
{
|
int waitInterval = 300;
|
int repeatTime = M141Config.DetectTimeout / waitInterval;
|
do
|
{
|
if (!pList.All(p =>
|
{
|
p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail);
|
return detail?.IsDone ?? false;
|
}))
|
{
|
Thread.Sleep(waitInterval);
|
repeatTime--;
|
}
|
else
|
{
|
Thread.Sleep(50);
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"成功完成工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测");
|
break;
|
}
|
|
if (repeatTime < 0)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位{positionName}产品{string.Join(",", pList.Select(u => $"{u.PID}_{u.SEQUENCE}"))}检测获取结果超时");
|
break;
|
}
|
} while (true);
|
}
|
|
|
pList.ForEach(p =>
|
{
|
var isOK = p.GetPositionResult(M141Config.StationCode, positionName, out P_PRODUCT_DETAIL detail);
|
plcresult.Add(isOK);
|
List<string> specHeads = new List<string>();
|
string head = p.GetCSVHead(ref specHeads, positionName);
|
|
//_positionSpecHeads[positionName] = specHeads;
|
|
string data = p.GetCSVData(specHeads, positionName);
|
CSVRecordAsync($"{positionName}_Record_{DateTime.Now.ToString("yyyyMMdd")}.csv", data, head);
|
|
//UpdatePositionResultToDB(detail);
|
//var seqData = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
ReplyPlcData(positionSet, plcresult);
|
mysqlhelper.UpdateProduct(p);
|
if (positionSet.IsLastPosition)
|
{
|
UpdateProductResultAsync(p);
|
mysqlhelper.NewForAll(p, M141Config.StationCode, M141Config.defectname);
|
if (M141Config.IsfinDevice)
|
{
|
SummaryAllprodata(p);
|
}
|
}
|
});
|
//ReplyPlcData(positionSet, plcresult);
|
if (positionSet.IsLastPosition)
|
{
|
if (_ct != null)
|
{
|
UpdateCT(null, (float)((DateTime.Now - _ct.Value).TotalSeconds));
|
}
|
_ct = DateTime.Now;
|
}
|
|
//ReplyPlcData(positionName, config.TriggerValue);
|
|
cameraIds.ForEach(c =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == c) as CameraBase;
|
if (camera != null)
|
{
|
camera.ClearImageBufferQueue();
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"相机{camera.Name}清理缓存");
|
}
|
});
|
|
return pList;
|
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, ex.ToString());
|
return null;
|
}
|
|
});
|
}
|
|
|
public void ReplyPlcData(WorkPositionSet p, List<bool> result)
|
{
|
if (p.plcresult != 0)
|
{
|
Plc1.WriteSingleAddress(p.plcresult, result[0] ? 1 : 2, out _);
|
}
|
Plc1.WriteSingleAddress(p.plcover, 1, out _);
|
|
}
|
|
|
public void SummaryAllprodata(ProductModel p)
|
{
|
_taskFactory.StartNew(() =>
|
{
|
try
|
{
|
ProductModel newp = new ProductModel();
|
newp.SEQUENCE = p.SEQUENCE;
|
newp.PID = p.PID;
|
newp.BasketCode = p.BasketCode;
|
newp.Result = p.Result;
|
newp.SN = p.SN;
|
|
Thread.Sleep(500);
|
var plist = mysqlhelper.GetProductList(p.SEQUENCE);
|
|
|
if (plist != null)
|
{
|
foreach (var item in plist)
|
{
|
newp.Details.AddRange(item.Details);
|
}
|
}
|
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"AllDeviceProductRecord从数据库获取到数据{p.SEQUENCE} plist数量{plist.Count} Details数量{newp.Details.Count}");
|
|
//newp.Details.AddRange(p.Details);
|
|
List<string> specHeadListforall = new List<string>();
|
List<string> positionListforall = new List<string>();
|
string csvHeadforall = newp.GetCSVHead(ref specHeadListforall, ref positionListforall);
|
CSVRecordAsync($"AllDeviceProductRecord.csv", newp.GetCSVData(specHeadListforall, positionListforall), csvHeadforall);
|
|
}
|
catch (Exception exx)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, "AllDeviceProductRecord数据汇总异常 " + exx.ToString());
|
}
|
});
|
|
}
|
|
|
|
|
#endregion
|
}
|
|
|
|
|
|
}
|