using Bro.Common.Base;
|
using Bro.Common.Helper;
|
using Bro.Common.Interface;
|
using Bro.Common.Model;
|
using Bro.M141.Process;
|
using HalconDotNet;
|
using System.Text.RegularExpressions;
|
using static Org.BouncyCastle.Math.EC.ECCurve;
|
|
namespace Bro.M141_AOI3.Process
|
{
|
[Process("AOI3", EnumHelper.DeviceAttributeType.Device)]
|
public class AOI3Process : M141Process
|
{
|
#region constructor
|
public AOI3Process() : base() { }
|
public AOI3Process(string productCode) : base(productCode) { }
|
#endregion
|
|
AOI3Config AOI3Config => Config as AOI3Config;
|
|
#region position1
|
[ProcessMethod("", "PositionCheck_P1", "工位1检测", InvokeType.TestInvoke)]
|
public ResponseMessage PositionCheck_P1(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = RunImageCheck1(config);
|
msg.IsReply = false;
|
|
if (msg.Result != 1)
|
{
|
msg.IsReply = true;
|
msg.DataStr = "1#,C,NG,NG,NOREAD,NOREAD";
|
}
|
|
return msg;
|
}
|
#endregion
|
|
#region position2
|
bool _isLastCheckFlag = false;
|
|
[ProcessMethod("", "SycnPointsData_P2", "同步工位2检测点位", InvokeType.TestInvoke)]
|
public ResponseMessage SycnPointsData_P2(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
//_isLastCheckFlag = true;
|
ResponseMessage msg = new ResponseMessage();
|
|
var allPoints = AOI3Config.CheckPoints_P2.Where(u => u.IsEnabled);
|
string pointDataStr = string.Join(",", allPoints.Select(u => $"{u.PointPosition.Y.ToString("f3")}"));
|
|
pointDataStr = $"{config.TriggerStr.Split(',')[0]},Points,{allPoints.Count()},{pointDataStr}";
|
msg.DataStr = pointDataStr;
|
msg.IsReply = true;
|
|
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], 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}对应的可用工位信息");
|
}
|
|
var 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).Distinct().ToList().ForEach(u =>
|
//{
|
// var camera = DeviceCollection.FirstOrDefault(c => c.Id == u) as CameraBase;
|
// camera.ReleaseImageWaitHandle();
|
// camera.ClearImageBufferQueue();
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{camera.Name}相机工位2检测前清理缓存");
|
//});
|
|
return msg;
|
}
|
|
[ProcessMethod("", "PositionCheck_P2", "工位2检测", InvokeType.TestInvoke)]
|
public ResponseMessage PositionCheck_P2(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
msg.Result = 1;
|
msg.IsReply = false;
|
|
List<MeasureBind> measureBinds = new List<MeasureBind>();
|
string inputSequence = "";
|
|
try
|
{
|
RunImageCheckPreTreat(config, out measureBinds, out inputSequence);
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"检测预处理异常,{ex.GetExceptionMessage()}");
|
msg.Result = -1;
|
msg.Message = ex.Message;
|
|
msg.IsReply = true;
|
msg.DataStr = $"2#,C,NG,NG,NOREAD,NOREAD";
|
return msg;
|
}
|
|
int measureNums = measureBinds.Count;
|
|
_isLastCheckFlag = false;
|
measureBinds.GroupBy(u => u.CameraId).AsParallel().ForAll(c =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == c.Key) as CameraBase;
|
|
foreach (var i in c.ToList().OrderBy(u => u.ImageIndex).ToList())
|
{
|
var products = i.ProductIndices.Select(pi =>
|
{
|
return FindProductBySequence($"{inputSequence}_{pi}", true);
|
}).ToList();
|
|
IImageSet imgSet = null;
|
try
|
{
|
imgSet = CollectHImage(camera, i.SnapshotOpConfig);
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位2{camera.Name}取像{i.ImageIndex}异常,{ex.GetExceptionMessage()}");
|
}
|
|
if (_isLastCheckFlag)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"当前流程已过期,获取图片不执行检测");
|
//Interlocked.Decrement(ref measureNums);
|
measureNums = 0;
|
break;
|
}
|
else
|
{
|
RunImageCheckAsync(products, config.TriggerStr, config.TriggerSource, imgSet, i).ContinueWith(t =>
|
{
|
Interlocked.Decrement(ref measureNums);
|
});
|
}
|
}
|
});
|
|
while (measureNums > 0 && !_isLastCheckFlag)
|
{
|
Thread.Sleep(50);
|
}
|
|
if (_isLastCheckFlag)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"当前流程已过期,退出检测,不执行反馈");
|
msg.IsReply = false;
|
return msg;
|
}
|
|
//检测完成后清理图片缓存
|
measureBinds.Select(u => u.CameraId).Distinct().ToList().ForEach(u =>
|
{
|
var camera = DeviceCollection.FirstOrDefault(c => c.Id == u) as CameraBase;
|
camera.ClearImageBufferQueue();
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{camera.Name}相机工位2检测后清理缓存");
|
});
|
|
string positionName = measureBinds[0].WorkPosition;
|
var pList = CheckPositionDoneAsync(positionName, inputSequence, config, new List<string>()).GetAwaiter().GetResult();
|
|
//string replyData = $"2#,C";
|
|
//pList.ForEach(p =>
|
//{
|
// var isOK = p.GetPositionResult(AOI3Config.StationCode, positionName, out _);
|
// replyData += $",{(isOK ? "OK" : "NG")}";
|
//});
|
|
//replyData += $",{string.Join(",", pList.Select(u => u.SN))},{string.Join(",", pList.Select(u => u.IsPreStationOK ? "OK" : "NG"))}";
|
|
//ReplyTcpData(positionName, config.TriggerSource, replyData);
|
return msg;
|
}
|
|
[ProcessMethod("ImageCheck", "GetProductBarcode_P2", "工位2获取产品条码", InvokeType.TestInvoke)]
|
public ResponseMessage GetProductBarcode_P2(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
|
if (config is IImageCheckOperationConfig opConfig)
|
{
|
var results = opConfig.Products.Select(u =>
|
{
|
DetectResult result = new DetectResult();
|
result.PID = u.PID;
|
result.Specs = GetSpecListFromConfigSelection(opConfig.SpecCollection);
|
return result;
|
}).ToList();
|
|
msg.DataObj = results;
|
|
var tool = GetHalconTool(null, "", opConfig.AlgorithemPath);
|
var ret = tool.RunProcedure(null, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", opConfig.ImageSet.HImage } }, new List<string>() { "OUTPUT_Flag", "OUTPUT_Results", "OUTPUT_Barcode" });
|
if (!ret.Item1 || ret.Item2["OUTPUT_Flag"].I != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"工位2条码检测工具运行失败,{ret.Item4}");
|
msg.Result = -1;
|
return msg;
|
}
|
|
FillSpecResults(results[0].PID, results[0].Specs, ret.Item2["OUTPUT_Results"].HTupleToDouble(), opConfig.Products[0].SEQUENCE);
|
var barcodeSpec = results[0].Specs.FirstOrDefault(u => u.Code == AOI3Config.BarcodeSpecCode);
|
|
string barcode = ret.Item2["OUTPUT_Barcode"].S;
|
opConfig.Products[0].SN = barcode;
|
opConfig.Products[0].Details.ForEach(u => u.SN = barcode);
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{opConfig.Products[0].PID}条码获取为{barcode}");
|
|
UpdateProductSNIntoDB(opConfig.Products[0].PID, barcode);
|
|
if (!string.IsNullOrWhiteSpace(AOI3Config.BarcodeRegex))
|
{
|
bool isOK = Regex.IsMatch(barcode, AOI3Config.BarcodeRegex);
|
if (!isOK)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"产品{opConfig.Products[0].PID}条码{barcode}未能通过验证,判定条码NG");
|
if (barcodeSpec == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"未能获取产品条码标准,请检查流程配置中是否选择条码标准或条码检测操作中是否添加条码标准");
|
|
results[0].Specs.ForEach(u => u.ActualValue = -999);
|
}
|
else
|
{
|
barcodeSpec.ActualValue = -999;
|
}
|
}
|
}
|
|
//if (AOI3Config.IsEnabelMESUpload)
|
//{
|
// if (barcodeSpec == null || barcodeSpec.MeasureResult != true)
|
// {
|
// opConfig.Products[0].IsPreStationOK = false;
|
// LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"产品{opConfig.Products[0].PID}条码获取失败,默认前站检测NG");
|
// }
|
// else
|
// {
|
// var res = CheckProductSNByMES(new OperationConfigBase() { TriggerStr = barcode }, null, null);
|
// opConfig.Products[0].IsPreStationOK = res.Result == 1;
|
// }
|
//}
|
//else
|
//{
|
// opConfig.Products[0].IsPreStationOK = true;
|
//}
|
}
|
|
return msg;
|
}
|
#endregion
|
|
#region position3
|
[ProcessMethod("", "PositionCheck_P3", "工位3检测", InvokeType.TestInvoke)]
|
public ResponseMessage PositionCheck_P3(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = RunImageCheck(config);
|
msg.IsReply = false;
|
if (msg.Result != 1)
|
{
|
msg.IsReply = true;
|
msg.DataStr = "3#,C,NG,NG,NOREAD,NOREAD";
|
}
|
return msg;
|
}
|
|
object locko3 = new object();
|
[ProcessMethod("ImageCheck", "CheckPosition_P3", "工位3检测产品位置度", InvokeType.TestInvoke)]
|
public ResponseMessage CheckPosition_P3(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
|
if (config is IImageCheckOperationConfig opConfig)
|
{
|
var preSpecs = GetSpecListFromConfigSelection(opConfig.SpecCollection);
|
var measureItemSpecs = GenerateSpecByMeasureItems(AOI3Config.MeasureItemBinds);
|
|
var results = opConfig.Products.Select(u =>
|
{
|
DetectResult result = new DetectResult();
|
result.PID = u.PID;
|
result.Specs = preSpecs.Concat(measureItemSpecs).ToList();
|
return result;
|
}).ToList();
|
|
msg.DataObj = results;
|
|
#region 计算位置度的点位
|
List<double> standardPoints = new List<double>();
|
AOI3Config.MeasurePointCollection.ForEach(p =>
|
{
|
standardPoints.Add(p.X);
|
standardPoints.Add(p.Y);
|
});
|
#endregion
|
|
#region 计算位置度点位的方向
|
List<string> standardPointsDirection = new List<string>();
|
AOI3Config.MeasurePointCollection.ForEach(p =>
|
{
|
if (p.ContourEdge == ContourEdge.X)
|
{
|
standardPointsDirection.Add("X");
|
}
|
else
|
{
|
standardPointsDirection.Add("Y");
|
}
|
});
|
#endregion
|
|
List<ContourPoint> contourPoints = AOI3Config.MeasurePointCollection.Select(u => u.Copy()).ToList();
|
|
var tool = GetHalconTool(null, "", opConfig.AlgorithemPath);
|
//var ret = tool.RunProcedure(new Dictionary<string, HalconDotNet.HTuple>() { { "INPUT_StandardPoints", standardPoints.ToArray() }, { "INPUT_StandardPointsDirection", standardPointsDirection.ToArray() } }, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", opConfig.ImageSet.HImage } }, new List<string>() { "OUTPUT_Results", "OUTPUT_Distances", "OUTPUT_Flag", "OUTPUT_Points" }, null);
|
Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> ret = null;
|
|
lock (locko3)
|
{
|
ret = tool.RunProcedure(new Dictionary<string, HalconDotNet.HTuple>() { { "INPUT_StandardPoints", standardPoints.ToArray() }, { "INPUT_StandardPointsDirection", standardPointsDirection.ToArray() } }, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", opConfig.ImageSet.HImage } }, new List<string>() { "OUTPUT_Results", "OUTPUT_Distances", "OUTPUT_Flag", "OUTPUT_Points" }, null);
|
|
}
|
if (!ret.Item1 || ret.Item2["OUTPUT_Flag"].I != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"脚本{opConfig.AlgorithemPath}运行异常,{ret.Item4}");
|
}
|
else
|
{
|
var pResult = results[0];
|
var p = opConfig.Products[0];
|
//根据当前产品索引,获取对应产品的补偿值配置
|
var pResultOffsets = AOI3Config.Product_PointsOffsetList.FirstOrDefault(pp => pp.ProductIndex.ToString() == p.SEQUENCE.Split("_")[p.SEQUENCE.Split("_").Count() - 1]);
|
var specDatas = ret.Item2["OUTPUT_Results"].HTupleToDouble();
|
var positionDatas = ret.Item2["OUTPUT_Distances"].HTupleToDouble();
|
var points = ret.Item2["OUTPUT_Points"].HTupleToDouble();
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"计算位置度,输入点位:{string.Join(",", standardPoints.Select(u => u.ToString("f3")))};输出原始检测数据:{string.Join(",", string.Join(",", specDatas.Select(u => u.ToString("f3"))))};输出原始点位数据:{string.Join(",", positionDatas.Select(u => u.ToString("f3")))}");
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位3位置度检测原始输出数据,Spec:{string.Join(",", specDatas.Select(u => u.ToString("f3")))};测量项:{string.Join(",", positionDatas.Select(u => u.ToString("f3")))};点位数据:{string.Join(",", points.Select(u => u.ToString("f3")))}");
|
|
|
List<Pointdata> Pointdatas = new List<Pointdata>();
|
if (positionDatas.Count != AOI3Config.MeasurePointCollection.Count)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"位置度点位数据数量{positionDatas.Count},和预置点位数量{AOI3Config.MeasurePointCollection.Count}不一致");
|
}
|
else
|
{
|
for (int i = 0; i < contourPoints.Count; i++)
|
{
|
//初始化补偿值,并根据当前处理的点位名称、及补偿开关,获取补偿值进行相关计算
|
double offsetX = 0.0, offsetY = 0.0;
|
if (pResultOffsets != null)
|
{
|
var checkPointsOffset = pResultOffsets.CheckPointsOffsetList.FirstOrDefault(c => c.ReadyToOffsetMeasurePointName == contourPoints[i].Name);
|
if (checkPointsOffset != null && checkPointsOffset.IsOffsetCalculate == true)
|
{
|
offsetX = checkPointsOffset.OffsetX;
|
offsetY = checkPointsOffset.OffsetY;
|
}
|
}
|
|
if (points.Count > (i * 2 + 1))
|
{
|
contourPoints[i].ActualX = points[i * 2] + offsetX;
|
contourPoints[i].ActualY = points[i * 2 + 1] + offsetY;
|
}
|
else
|
{
|
contourPoints[i].ActualX = -999;
|
contourPoints[i].ActualY = -999;
|
}
|
|
|
if (contourPoints[i].ContourEdge == ContourEdge.X)
|
{
|
contourPoints[i].Error = Math.Abs(positionDatas[i]) + offsetY;
|
}
|
else
|
{
|
contourPoints[i].Error = Math.Abs(positionDatas[i]) + offsetX;
|
}
|
|
Pointdatas.Add(new Pointdata
|
{
|
Code = contourPoints[i].Name,
|
ValueX = contourPoints[i].ActualX,
|
ValueY = contourPoints[i].ActualY,
|
});
|
}
|
|
var tempDatas = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
string positionNum = tempDatas[tempDatas.Count - 1];
|
PositionPointDataRecord(contourPoints, pResult.PID, preSpecs, specDatas, positionNum);
|
}
|
|
if (M141Pointlist.Count > 500)
|
{
|
M141Pointlist.Add(Pointdatas);
|
M141Pointlist.RemoveAt(0);
|
}
|
else
|
{
|
M141Pointlist.Add(Pointdatas);
|
}
|
lock (o_numrefresh)
|
{
|
if (numrefresh > 10)
|
{
|
PointRefreshUI();
|
numrefresh = 0;
|
}
|
else
|
{
|
numrefresh++;
|
}
|
}
|
|
FillSpecResults(opConfig.Products[0].PID, preSpecs, specDatas, opConfig.Products[0].SEQUENCE);
|
|
measureItemSpecs.ForEach(m =>
|
{
|
var measureItem = AOI3Config.MeasureItemBinds.FirstOrDefault(u => u.SpecCode == m.Code || u.FAIName == m.Code);
|
if (measureItem != null)
|
{
|
var point = contourPoints.FirstOrDefault(u => u.Name == measureItem.MeasurePointNameCollection[0].MeasurePointName);
|
m.ActualValue = point.Error;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{pResult.PID}位置度检测项{m.Code}赋值{m.GetMeasureValueStr()},结果{m.GetMeasureResultStr()}");
|
}
|
});
|
}
|
}
|
|
return msg;
|
}
|
object o_numrefresh = new object();
|
int numrefresh = 0;
|
string _contourPointDataHead = "";
|
private async void PositionPointDataRecord(List<ContourPoint> points, string pid, List<ISpec> specs, List<double> doubles, string positionNum)
|
{
|
await Task.Run(() =>
|
{
|
if (string.IsNullOrWhiteSpace(_contourPointDataHead))
|
{
|
_contourPointDataHead = "Time,PID,Position,";
|
specs.OrderBy(u => u.Code).ToList().ForEach(u =>
|
{
|
_contourPointDataHead += $"{u.Code},";
|
});
|
points.OrderBy(u => u.Name).ToList().ForEach(u =>
|
{
|
_contourPointDataHead += $"{u.Name}_X,{u.Name}_Y,{u.Name}_ActualX,{u.Name}_ActualY,{u.Name}距离,";
|
});
|
}
|
|
DateTime dt = DateTime.Now;
|
string data = $"{dt.ToString("HH:mm:ss.fff")}T,{pid},{positionNum},";
|
doubles.ForEach(u =>
|
{
|
data += $"{u.ToString()},";
|
});
|
points.OrderBy(u => u.Name).ToList().ForEach(u =>
|
{
|
data += $"{u.X.ToString("f3")},{u.Y.ToString("f3")},{u.ActualX.ToString("f3")},{u.ActualY.ToString("f3")},{u.Error.ToString("f3")},";
|
});
|
|
CSVRecordAsync($"PositionPointRecord_{dt.ToString("yyyyMMdd")}.csv", data, _contourPointDataHead);
|
});
|
}
|
#endregion
|
|
|
[ProcessMethod("", "PositionCheck_P4", "工位4检测", InvokeType.TestInvoke)]
|
public ResponseMessage PositionCheck_P4(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = RunImageCheck(config);
|
msg.IsReply = false;
|
|
if (msg.Result != 1)
|
{
|
msg.IsReply = true;
|
msg.DataStr = "4#,C,NG,NG,NOREAD,NOREAD";
|
}
|
|
return msg;
|
}
|
|
[ProcessMethod("ImageCheck", "CheckPosition_P4", "工位4检测产品位置度", InvokeType.TestInvoke)]
|
public ResponseMessage CheckPosition_P4(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
ResponseMessage msg = new ResponseMessage();
|
|
if (config is IImageCheckOperationConfig opConfig)
|
{
|
var preSpecs = GetSpecListFromConfigSelection(opConfig.SpecCollection);
|
var measureItemSpecs = GenerateSpecByMeasureItems(AOI3Config.MeasureItemBinds);
|
|
var results = opConfig.Products.Select(u =>
|
{
|
DetectResult result = new DetectResult();
|
result.PID = u.PID;
|
result.Specs = preSpecs.Concat(measureItemSpecs).ToList();
|
return result;
|
}).ToList();
|
|
msg.DataObj = results;
|
|
#region 计算位置度的点位
|
List<double> standardPoints = new List<double>();
|
AOI3Config.MeasurePointCollection.ForEach(p =>
|
{
|
standardPoints.Add(p.X);
|
standardPoints.Add(p.Y);
|
});
|
#endregion
|
|
#region 计算位置度点位的方向
|
List<string> standardPointsDirection = new List<string>();
|
AOI3Config.MeasurePointCollection.ForEach(p =>
|
{
|
if (p.ContourEdge == ContourEdge.X)
|
{
|
standardPointsDirection.Add("X");
|
}
|
else
|
{
|
standardPointsDirection.Add("Y");
|
}
|
});
|
#endregion
|
|
List<ContourPoint> contourPoints = AOI3Config.MeasurePointCollection.Select(u => u.Copy()).ToList();
|
|
var tool = GetHalconTool(null, "", opConfig.AlgorithemPath);
|
Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> ret = null;
|
lock (locko3)
|
{
|
ret = tool.RunProcedure(new Dictionary<string, HalconDotNet.HTuple>() { { "INPUT_StandardPoints", standardPoints.ToArray() }, { "INPUT_StandardPointsDirection", standardPointsDirection.ToArray() } }, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", opConfig.ImageSet.HImage } }, new List<string>() { "OUTPUT_Results", "OUTPUT_Distances", "OUTPUT_Flag", "OUTPUT_Points" }, null);
|
}
|
if (!ret.Item1 || ret.Item2["OUTPUT_Flag"].I != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"脚本{opConfig.AlgorithemPath}运行异常,{ret.Item4}");
|
}
|
else
|
{
|
var pResult = results[0];
|
var p = opConfig.Products[0];
|
//根据当前产品索引,获取对应产品的补偿值配置
|
var pResultOffsets = AOI3Config.Product_PointsOffsetList.FirstOrDefault(pp => pp.ProductIndex.ToString() == p.SEQUENCE.Split("_")[p.SEQUENCE.Split("_").Count() - 1]);
|
var specDatas = ret.Item2["OUTPUT_Results"].HTupleToDouble();
|
var positionDatas = ret.Item2["OUTPUT_Distances"].HTupleToDouble();
|
var points = ret.Item2["OUTPUT_Points"].HTupleToDouble();
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"计算位置度,输入点位:{string.Join(",", standardPoints.Select(u => u.ToString("f3")))};输出原始检测数据:{string.Join(",", string.Join(",", specDatas.Select(u => u.ToString("f3"))))};输出原始点位数据:{string.Join(",", positionDatas.Select(u => u.ToString("f3")))}");
|
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"工位4位置度检测原始输出数据,Spec:{string.Join(",", specDatas.Select(u => u.ToString("f3")))};测量项:{string.Join(",", positionDatas.Select(u => u.ToString("f3")))};点位数据:{string.Join(",", points.Select(u => u.ToString("f3")))}");
|
|
if (positionDatas.Count != AOI3Config.MeasurePointCollection.Count)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"位置度点位数据数量{positionDatas.Count},和预置点位数量{AOI3Config.MeasurePointCollection.Count}不一致");
|
}
|
else
|
{
|
for (int i = 0; i < contourPoints.Count; i++)
|
{
|
//初始化补偿值,并根据当前处理的点位名称、及补偿开关,获取补偿值进行相关计算
|
double offsetX = 0.0, offsetY = 0.0;
|
if (pResultOffsets != null)
|
{
|
var checkPointsOffset = pResultOffsets.CheckPointsOffsetList.FirstOrDefault(c => c.ReadyToOffsetMeasurePointName == contourPoints[i].Name);
|
if (checkPointsOffset != null && checkPointsOffset.IsOffsetCalculate == true)
|
{
|
offsetX = checkPointsOffset.OffsetX;
|
offsetY = checkPointsOffset.OffsetY;
|
}
|
}
|
|
if (points.Count > (i * 2 + 1))
|
{
|
contourPoints[i].ActualX = points[i * 2] + offsetX;
|
contourPoints[i].ActualY = points[i * 2 + 1] + offsetY;
|
}
|
else
|
{
|
contourPoints[i].ActualX = -999;
|
contourPoints[i].ActualY = -999;
|
}
|
|
//根据项目测量需求,需要计算标准点在产品上的实际点位,和基准的距离。通过脚本计算输出,故需要在上位进行基准的判断,并进行对应补偿
|
//if (contourPoints[i].ContourEdge == ContourEdge.X)
|
//{
|
// contourPoints[i].Error = Math.Abs(positionDatas[i] + offsetY);
|
//}
|
//else
|
//{
|
// contourPoints[i].Error = Math.Abs(positionDatas[i] + offsetX);
|
//}
|
if (contourPoints[i].ContourEdge == ContourEdge.X)
|
{
|
contourPoints[i].Error = Math.Abs(positionDatas[i]) + offsetY;
|
}
|
else
|
{
|
contourPoints[i].Error = Math.Abs(positionDatas[i]) + offsetX;
|
}
|
}
|
|
var tempDatas = p.SEQUENCE.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
string positionNum = tempDatas[tempDatas.Count - 1];
|
PositionPointDataRecord(contourPoints, pResult.PID, preSpecs, specDatas, positionNum);
|
}
|
|
FillSpecResults(opConfig.Products[0].PID, preSpecs, specDatas, opConfig.Products[0].SEQUENCE);
|
|
measureItemSpecs.ForEach(m =>
|
{
|
var measureItem = AOI3Config.MeasureItemBinds.FirstOrDefault(u => u.SpecCode == m.Code || u.FAIName == m.Code);
|
if (measureItem != null)
|
{
|
var point = contourPoints.FirstOrDefault(u => u.Name == measureItem.MeasurePointNameCollection[0].MeasurePointName);
|
m.ActualValue = point.Error;
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{pResult.PID}位置度检测项{m.Code}赋值{m.GetMeasureValueStr()},结果{m.GetMeasureResultStr()}");
|
}
|
});
|
}
|
}
|
|
return msg;
|
}
|
|
|
[ProcessMethod("", "BiaoDing", "标定", InvokeType.TestInvoke)]
|
public ResponseMessage BiaoDing(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
try
|
{
|
int index = Convert.ToInt32(config.TriggerStr.Split(',')[1]) - 1;
|
List<BDMeasureBind> testBd = M141Config.BDCollection.Where(u => u.CheckIndex == index).ToList();
|
|
for (int i = 0; i < testBd.Count; i++)
|
{
|
try
|
{
|
var camera = DeviceCollection.FirstOrDefault(u => u.Id == testBd[i].CameraId) as CameraBase;
|
if (camera == null)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"标定序号{index}未能获取相机设备");
|
}
|
camera.ClearImageBufferQueue();
|
var imgSet = CollectHImage(camera, testBd[i].SnapshotOpConfig);
|
camera.ClearImageBufferQueue();
|
|
var tool = GetHalconTool(null, "", ((CameraOperationConfigBase)testBd[i].SnapshotOpConfig).AlgorithemPath);
|
var ret = tool.RunProcedure(null, new Dictionary<string, HalconDotNet.HObject>() { { "INPUT_Image", imgSet.HImage } }, new List<string>() { "OUTPUT_Flag", "OUTPUT_Results" });
|
if (!ret.Item1 || ret.Item2["OUTPUT_Flag"].I != 1)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"标定序号{index}运行失败,{ret.Item4}");
|
}
|
else
|
{
|
testBd[i].BDList = ret.Item2["OUTPUT_Results"].HTupleToDouble();
|
}
|
}
|
catch (Exception e)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"标定异常,{e.ToString()}");
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"标定异常,{ex.ToString()}");
|
}
|
SaveProcessConfig(M141Config);
|
ResponseMessage msg = new ResponseMessage();
|
msg.IsReply = true;
|
msg.DataStr = config.TriggerStr;
|
return msg;
|
}
|
|
|
|
|
|
|
}
|
}
|