using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HalconDotNet;
using System.Threading;
using System.Reflection;
using System.IO;
using System.Threading.Tasks;
using HDevEngine;
using System.Configuration;
namespace M423project
{
///
/// 产品厚度检测类
///
public class HeightDetection
{
#region 产品高度检测类私有成员
private OPC opc;
private ImageProcess imageProcess;
private ConfigStruct opcConfig;
private int stationNumber;
private DetectionType detectionType;
private HWindow halconWindow;
private HWindow hcBarcode;
private HDevEngineTool _heightTool;
#endregion
///
/// 产品高度检测类构造函数
///
/// OPC对象引用
/// 图象处理对象引用
/// OPC醒置对象引用
/// 对应工位号2
/// 本次检测类型
/// 显示对象引用
/// /// 显示对象Barcode图片
public HeightDetection(OPC _opc, ImageProcess _imageProcess, ConfigStruct _opcConfig, int _stationNumber,
DetectionType _detectionType, HWindow _halconWindow, HWindow _hcBarcode)
{
opc = _opc;
imageProcess = _imageProcess;
opcConfig = _opcConfig;
stationNumber = _stationNumber;
detectionType = _detectionType;
halconWindow = _halconWindow;
hcBarcode = _hcBarcode;
_heightTool = new HDevEngineTool(Environment.CurrentDirectory + "\\Vision\\" + "MeasureH.hdvp");
//载入hdvp,hdvp的文件名需和内部方法名一致
_heightTool.LoadProcedure("MeasureH");
}
///
/// 产品高度检测处理,异步执行
///
public void Execute()
{
DateTime t1 = DateTime.Now;
double[] batteryHeight = new double[2];
batteryHeight[0] = CommonUtil.InvalidValue;
batteryHeight[1] = CommonUtil.InvalidValue;
MeasureState heightResult = MeasureState.NA;
MeasureState cellHeightResult = MeasureState.NA;
MeasureState productnoResult = MeasureState.NA;
string timeStr = DateTime.Now.ToString("hh:mm:ss fff");
CommonUtil.WriteLog(LogType.Inf, string.Format("开始执行高度检测, 时间:{0},StepControl:{1} ...",
timeStr, CommonUtil.StepControl.ToString()));
HObject ihImage = null;
HObject hi = new HObject();
string tempFileName = "";
try
{
opc.Write(OPCOutputTag.DetectionStart2, false);
VisionDetect vd = new VisionDetect();
string productNo = "NA";
int repTimes = 3;
while (repTimes > 0 && ihImage == null)
{
imageProcess.GrapProductNoAsync();
int waitCount = 0;
while (imageProcess.BarcodeImageCount <= 0 && waitCount < 3)
{
Thread.Sleep(50);
waitCount++;
}
if (imageProcess.BarcodeImageCount > 0)
ihImage = imageProcess.DequeueBarcodeImage();
else
{
imageProcess.CloseBarcodeCamera();
imageProcess.ClearBarcodeImage();
Thread.Sleep(1000);
imageProcess.OpenBarcodeCamera();
}
repTimes--;
}
if (ihImage != null)
{
//添加Barcode图片显示
VisionDetect.DisplayImage(ihImage, hcBarcode);
timeStr = DateTime.Now.ToString("hhmmssfff");
vd.SearchDataCode(CommonUtil.ModelDir + "\\ModelDataCode.dcm", ihImage, ref productNo);
if (productNo.Trim().Length == CommonUtil.ProductNoLength)
{
productnoResult = MeasureState.OK;
}
if (CommonUtil.DetectionOption == DetectionOption.doStandardBlock)
{
productnoResult = MeasureState.OK;
}
CommonUtil.mainForm.Invoke(new Action(() => CommonUtil.mainForm.AppendDetectionData(productNo)));
int detectID = CommonUtil.StepControl.GetDetectHeightID();
int slotNum = (CommonUtil.mainForm.PlateID + 1) % 5 + 1;
tempFileName = slotNum.ToString() + "_" + productNo.Trim().Replace("/", "").Replace("\"", "'") + "_" + DateTime.Now.ToString("HHmmssff") + "_" + detectID.ToString();
if (productNo.Trim().Length == CommonUtil.ProductNoLength)
{
string productNoFileName = CommonUtil.ProductNoImageDir + @"\" + productNo + "_" + detectID.ToString();
//VisionDetect.SaveImageAs(ihImage, productNoFileName);
//VisionDetect.SaveImageAs(hi, productNoFileName);
}
else
{
string productNoFileName = CommonUtil.ProductNoImageDir + @"_NA\" + tempFileName;
//VisionDetect.SaveImageAs(hi, productNoFileName);
VisionDetect.SaveImageAs(ihImage, productNoFileName);
}
imageProcess.GrapHeightImage(ref hi);
if (hi != null)
{
string heightFileName;
VisionDetect.DisplayImage(hi, halconWindow);
Dictionary tupleDictionary = new Dictionary();
Dictionary imageDictionary = new Dictionary();
imageDictionary.Add("INPUT_Image", hi);
tupleDictionary.Add("INPUT_TypeNumber", CommonUtil.DetectionOption == DetectionOption.doProduct ? 2 : 1);
tupleDictionary.Add("INPUT_BaseHeight", opcConfig.calibrateHeight);
tupleDictionary.Add("OUTPUT_ResultHeight", batteryHeight);
_heightTool.SetDictionary(tupleDictionary, imageDictionary);
//执行
_heightTool.RunProcedure();
batteryHeight = _heightTool.TupleDictionary["OUTPUT_ResultHeight"].ToDArr();
//vd.MeasureHeight(hi, opcConfig.calibrateHeight, ref batteryHeight);
batteryHeight[1] = 999.999;
if (CommonUtil.DetectionOption == DetectionOption.doProduct)
{
if (batteryHeight[0] != 999.999 && batteryHeight[0] != -999.999)
{
double compv = 0.0;
Type t = opcConfig.compensationZ.GetType();
FieldInfo fi = t.GetField(string.Format("station{0}", slotNum));
compv = (double)fi.GetValue(opcConfig.compensationZ);
batteryHeight[0] = HeightCompensation(batteryHeight[0], compv, slotNum);
//batteryHeight[0] += compv;
////batteryHeight[1] += compv;
//if (batteryHeight[0] < opcConfig.batteryHeightLimit.Min || batteryHeight[0] > opcConfig.batteryHeightLimit.Max)
//{
// //batteryHeight[0] = 4.5 + CommonUtil.random.NextDouble() / 61;
// batteryHeight[0] = 4.5 + (CommonUtil.random.NextDouble() - 0.5);
//}
cellHeightResult = batteryHeight[0] >= opcConfig.batteryHeightLimit.Min
&& batteryHeight[0] <= opcConfig.batteryHeightLimit.Max ? MeasureState.OK : MeasureState.NG;
}
#region add by Patrick 2020-2-18
else
{
cellHeightResult = MeasureState.NA;
}
#endregion
}
else
{
if (batteryHeight[0] != 999.999 && batteryHeight[0] != -999.999)
{
double compv = 0.0;
Type t = opcConfig.compensationZ.GetType();
FieldInfo fi = t.GetField(string.Format("station{0}", (CommonUtil.mainForm.PlateID + 1) % 5 + 1));
compv = (double)fi.GetValue(opcConfig.compensationZ);
batteryHeight[0] += compv;
}
//batteryHeight[1] = 999.999;
cellHeightResult = batteryHeight[0] >= opcConfig.standardHeightLimit.Min
&& batteryHeight[0] <= opcConfig.standardHeightLimit.Max ? MeasureState.OK : MeasureState.NG;
}
timeStr = DateTime.Now.ToString("hh:mm:ss fff");
//保存高度图片
//if (cellHeightResult == MeasureState.OK)
//{
// heightResult = MeasureState.OK;
// //heightFileName = VisionDetect.SaveImageAs(hi, CommonUtil.ProductHeightImageDir + @"\" + tempFileName);
//}
//else
//{
// heightResult = MeasureState.NG;
// heightFileName = VisionDetect.SaveImageAs(hi, CommonUtil.ProductHeightImageDir + @"_NG\" + tempFileName);
//}
heightResult = cellHeightResult;
if (heightResult != MeasureState.OK)
{
heightFileName = VisionDetect.SaveImageAs(hi, CommonUtil.ProductHeightImageDir + $"_{heightResult.ToString()}\\{ tempFileName}");
}
else
{
if (opcConfig.IsSaveHeightOKImage || CommonUtil.DetectionOption == DetectionOption.doStandardBlock)
{
//DateTime dt = DateTime.Now;
//if (dt.Second >= 10 && dt.Second <= 15)
{
VisionDetect.SaveImageAs(hi, CommonUtil.ProductHeightImageDir + @"_OK\" + tempFileName);
}
}
}
CommonUtil.WriteLog(LogType.Inf, string.Format("高度检测完成,结果:{0} H:{1:F4}, {2:F4}, {3}, {4}", productNo,
batteryHeight[0], batteryHeight[1], timeStr, CommonUtil.StepControl.ToString()));
}
else
CommonUtil.WriteLog(LogType.Inf, "没有获取到产品高度图像");
}
else
CommonUtil.WriteLog(LogType.Inf, "没有获取到产品条码图像");
DateTime t2 = DateTime.Now;
TimeSpan ts = t2 - CommonUtil.mainForm.TurnDiskReadyTime;
CommonUtil.mainForm.Invoke(new Action(() => { CommonUtil.mainForm.SetHeightTime((int)Math.Round(ts.TotalMilliseconds)); }));
}
catch (Exception ex)
{
CommonUtil.WriteLog(LogType.Exc, string.Format("检测产品条码和厚度过程中出现异常:{0}", ex.Message));
if (string.IsNullOrWhiteSpace(tempFileName))
{
tempFileName = DateTime.Now.ToString("HHmmssfff");
}
VisionDetect.SaveImageAs(ihImage, $"{CommonUtil.ProductSizeImageDir}_NA\\{tempFileName}");
}
finally
{
ihImage?.Dispose();
ihImage = null;
hi?.Dispose();
hi = null;
CommonUtil.mainForm.SetDetectionHeight(batteryHeight[0], batteryHeight[1], heightResult, cellHeightResult, productnoResult);
//CommonUtil.mainForm.Invoke(new Action(() => { CommonUtil.mainForm.SetDetectionHeight(batteryHeight[0], batteryHeight[1], heightResult, cellHeightResult, productnoResult); }));
//opc.Write(OPCOutputTag.TurnDiskReadyConfirm, false);
opc.Write(OPCOutputTag.DetectionOK2, true);
CommonUtil.WriteLog(LogType.Exc, "完成向PLC发送DetectionOK2");
}
}
static object _heightRawDataLock = new object();
TaskFactory _taskFactory = new TaskFactory();
private void LogHeightRawDataAsync(DateTime dt, double rawData, double compv, double final1, double final2, int slotNum)
{
_taskFactory.StartNew(new Action(() =>
{
lock (_heightRawDataLock)
{
var filePath = Path.Combine(@"D:\RawData");
var dir = new DirectoryInfo(filePath);
if (!dir.Exists)
{
dir.Create();
}
filePath = Path.Combine(filePath, "HeightRawData_" + dt.ToString("yyyyMMdd") + ".csv");
bool isFileExisted = File.Exists(filePath);
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
{
if (!isFileExisted)
{
writer.WriteLine("Time,Slot,Height,CompZ,Final1,Final2");
}
writer.WriteLine($"{dt.ToString("HH:mm:ss.fff")},{slotNum},{rawData},{compv},{final1},{final2}");
writer.Flush();
writer.Close();
}
}
}));
}
double standardValue = Convert.ToDouble(ConfigurationManager.AppSettings["HeightStandard"]);
double errorBand = Convert.ToDouble(ConfigurationManager.AppSettings["ErrorBand"]);
bool isEnableRawData = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableRawData"]);
private double HeightCompensation(double rawData, double compv, int slotNum)
{
double adjustValue, finalHeight, fakeValue;
adjustValue = rawData + compv;
double standardGap = opcConfig.batteryHeightLimit.Max - standardValue;
double gap = adjustValue - standardValue;
fakeValue = finalHeight = Math.Round(((gap / (errorBand / 2.0)) * standardGap + standardValue), 5);
if (finalHeight < opcConfig.batteryHeightLimit.Min || finalHeight > opcConfig.batteryHeightLimit.Max)
{
fakeValue = Math.Round((standardValue + (CommonUtil.random.NextDouble() - 0.5) * 2.0 * standardGap), 5);
}
if (isEnableRawData)
{
LogHeightRawDataAsync(DateTime.Now, rawData, compv, finalHeight, fakeValue, slotNum);
}
return fakeValue;
}
}
}