313 lines
12 KiB
C#
313 lines
12 KiB
C#
/*
|
|
* Copyright (c) 2025 LG Electronics Inc.
|
|
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Aurora.Api;
|
|
using VisionCommon;
|
|
using VisionInspector;
|
|
using Hermes;
|
|
using VisionCommonUI;
|
|
using VisionCommonUI.Resources;
|
|
|
|
namespace VisionSequence.Inspector {
|
|
/// <summary>
|
|
/// 패턴 간의 거리 검사 시퀀스 파라미터
|
|
/// </summary>
|
|
public class InspSeqParams_PatternDistance {
|
|
/// <summary>얼라인 키 정보</summary>
|
|
public AlignInfo AlignInfo { get; set; }
|
|
/// <summary>패턴 검출 결과</summary>
|
|
public Dictionary<eFovId, BaseResult> MeasureResults { get; set; }
|
|
|
|
/// <summary>
|
|
/// 생성자
|
|
/// </summary>
|
|
/// <param name="alignInfo">얼라인 키 정보</param>
|
|
/// <param name="measureResults">패턴 검출 결과</param>
|
|
public InspSeqParams_PatternDistance(
|
|
AlignInfo alignInfo,
|
|
Dictionary<eFovId, BaseResult> measureResults) {
|
|
|
|
this.AlignInfo = alignInfo;
|
|
this.MeasureResults = measureResults;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 서로 다른 FOV에서 찾은 두 패턴 간에 거리 검사 (서브시퀀스로 호출해서 사용)
|
|
/// </summary>
|
|
public class InspSeq_PatternDistance : SubSeqBase {
|
|
private readonly Logger LOG = new Logger(typeof(InspSeq_PatternDistance).Name);
|
|
private Logger _VisionLog = new Logger("InspSeq_PatternDistance", VisionKeys.LogKey);
|
|
|
|
private InspSeqParams_PatternDistance _Params;
|
|
private SubSysInfo _SubSysInfo;
|
|
private SubSysRecipe _SubSysRecipe;
|
|
private PatternDistanceParam _PatternDistanceParam;
|
|
private CsvManager _CsvManager = new CsvManager();
|
|
|
|
private string _SeqName;
|
|
|
|
#region Sequence Id
|
|
private const string SEQ_ID_INIT = "INIT";
|
|
private const string SEQ_ID_CLEAR = "CLEAR";
|
|
private const string SEQ_ID_MEASURE_DISTANCE = "MEASURE_DISTANCE";
|
|
private const string SEQ_ID_UPDATE_UI = "UPDATE_UI";
|
|
private const string SEQ_ID_SAVE_CSV = "SAVE_CSV";
|
|
private const string SEQ_ID_SEQ_COMPLETE = "SEQ_COMPLETE";
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 생성자
|
|
/// </summary>
|
|
public InspSeq_PatternDistance() {
|
|
}
|
|
|
|
private void SetActions(SequenceBuilder sb) {
|
|
sb.AddAction(SEQ_ID_INIT, Init);
|
|
sb.AddAction(SEQ_ID_CLEAR, Clear);
|
|
sb.AddAction(SEQ_ID_MEASURE_DISTANCE, MeasureDistance);
|
|
sb.AddAction(SEQ_ID_UPDATE_UI, UpdateUI);
|
|
sb.AddAction(SEQ_ID_SAVE_CSV, SaveCsv);
|
|
sb.AddAction(SEQ_ID_SEQ_COMPLETE, SeqComplete);
|
|
}
|
|
|
|
public override SequenceBuilder Builder(string seqName) {
|
|
_SeqName = seqName;
|
|
|
|
SequenceBuilder sb = new SequenceBuilder(1000);
|
|
SetActions(sb);
|
|
sb.OnStopped(OnStopped);
|
|
sb.OnForceError(OnForceError);
|
|
|
|
sb.Flows(
|
|
sb.Init
|
|
> sb[SEQ_ID_INIT]
|
|
> sb[SEQ_ID_CLEAR]
|
|
> sb[SEQ_ID_MEASURE_DISTANCE]
|
|
> sb[SEQ_ID_UPDATE_UI]
|
|
> sb[SEQ_ID_SAVE_CSV]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_SEQ_COMPLETE]
|
|
> sb.Final
|
|
);
|
|
|
|
#if SEQ_DRAW
|
|
sb.Draw($"{GetType().Name}.pdf");
|
|
#endif
|
|
|
|
return sb;
|
|
}
|
|
|
|
private SequenceActionResult Init(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (param.Param != null) {
|
|
_Params = param.Param as InspSeqParams_PatternDistance;
|
|
}
|
|
else {
|
|
MessageBoxUtil.ShowMessageBoxError(
|
|
string.Format(StrTokens.MSG_E_ParamIsNull));
|
|
return SequenceAction.Error(E1.ARGUMENT);
|
|
}
|
|
|
|
_SubSysInfo = _Params.AlignInfo.ToSubSysInfo();
|
|
var alignRecipe = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo);
|
|
_PatternDistanceParam = alignRecipe.InspParams.PatternDistanceParam; // Spec, ErrRange
|
|
|
|
if (!IsValidMeasureResults()) {
|
|
return null;
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private bool IsValidMeasureResults() {
|
|
if (_Params.MeasureResults == null) {
|
|
LOG.E("_Params.MeasureResults is null.");
|
|
return false;
|
|
}
|
|
else if (_Params.MeasureResults.Count < 2) {
|
|
LOG.E($"_Params.MeasureResults.Count is less than 2.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private SequenceActionResult Clear(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
PatternDistanceResultItemManager.Clear(_SubSysInfo);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult MeasureDistance(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
List<eFovId> fovList = _Params.MeasureResults.Keys.ToList();
|
|
List<eFovIdPair> fovIdPairs = VisionRecipeManager.GetFovIdPairs(fovList);
|
|
var patternDistanceResults = new List<PatternDistanceResult>();
|
|
|
|
foreach (eFovIdPair fovIdPair in fovIdPairs) {
|
|
var result = new PatternDistanceResult();
|
|
|
|
switch (fovIdPair) {
|
|
case eFovIdPair.Fov1_2:
|
|
MeasureDistanceInternal(eFovId.Fov1, eFovId.Fov2, ref result);
|
|
break;
|
|
case eFovIdPair.Fov1_3:
|
|
MeasureDistanceInternal(eFovId.Fov1, eFovId.Fov3, ref result);
|
|
break;
|
|
case eFovIdPair.Fov1_4:
|
|
MeasureDistanceInternal(eFovId.Fov1, eFovId.Fov4, ref result);
|
|
break;
|
|
case eFovIdPair.Fov2_3:
|
|
MeasureDistanceInternal(eFovId.Fov2, eFovId.Fov3, ref result);
|
|
break;
|
|
case eFovIdPair.Fov2_4:
|
|
MeasureDistanceInternal(eFovId.Fov2, eFovId.Fov4, ref result);
|
|
break;
|
|
case eFovIdPair.Fov3_4:
|
|
MeasureDistanceInternal(eFovId.Fov3, eFovId.Fov4, ref result);
|
|
break;
|
|
}
|
|
patternDistanceResults.Add(result);
|
|
}
|
|
|
|
context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_DISTANCE_RESULTS, _Params.AlignInfo.GetKey()), patternDistanceResults);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private void MeasureDistanceInternal(eFovId startFov, eFovId endFov, ref PatternDistanceResult result) {
|
|
if (IsValidFovIds(startFov, endFov)) {
|
|
double distance = MathUtil.CalculateDistance(
|
|
_Params.MeasureResults[startFov].MaterialPosition, _Params.MeasureResults[endFov].MaterialPosition);
|
|
double spec = GetSpec(startFov, endFov);
|
|
InspStatus status = GetStatus(startFov, endFov, spec, distance);
|
|
|
|
result.StartFov = startFov;
|
|
result.EndFov = endFov;
|
|
result.Distance = distance;
|
|
result.ErrRange = distance - spec;
|
|
result.InspStatus = status;
|
|
}
|
|
else {
|
|
LOG.E($"_Params.MeasureResults does not contain all fov keys. [{startFov}, {endFov}]");
|
|
}
|
|
}
|
|
|
|
private bool IsValidFovIds(eFovId startFov, eFovId endFov) {
|
|
if (_Params.MeasureResults.ContainsKey(startFov) && _Params.MeasureResults.ContainsKey(endFov)) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private double GetSpec(eFovId startFov, eFovId endFov) {
|
|
return GetRefDistance(startFov, endFov);
|
|
}
|
|
|
|
private InspStatus GetStatus(eFovId startFov, eFovId endFov, double spec, double measuredDistance) {
|
|
double measureDiff = measuredDistance - spec;
|
|
|
|
if (Math.Abs(measureDiff) <= Math.Abs(_PatternDistanceParam.ErrRange)) {
|
|
return InspStatus.OK;
|
|
}
|
|
else {
|
|
return InspStatus.NG;
|
|
}
|
|
}
|
|
|
|
// FOV RefPoint(기준점) 간에 거리를 Spec으로 활용한다. RefPointOffset이 0이면, Spec은 FovCenter 간에 거리가 된다.
|
|
private double GetRefDistance(eFovId startFov, eFovId endFov) {
|
|
var startFovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo, startFov);
|
|
var endFovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo, endFov);
|
|
var startRefPoint = VisionRecipeManager.GetRefPoint(startFovInfo);
|
|
var endRefPoint = VisionRecipeManager.GetRefPoint(endFovInfo);
|
|
|
|
return MathUtil.CalculateDistance(startRefPoint, endRefPoint);
|
|
}
|
|
|
|
private SequenceActionResult UpdateUI(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
var patternDistanceResults = context.GetValue<List<PatternDistanceResult>>(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_DISTANCE_RESULTS, _Params.AlignInfo.GetKey()));
|
|
var subSysInfo = _Params.AlignInfo.ToSubSysInfo();
|
|
|
|
VisionEnv.AuroraEnv.EventPublisher.Publish(
|
|
new EventMessage(subSysInfo.GetKey(), VisionEventId.UPDATE_PATTERN_DISTANCE_RESULTS, patternDistanceResults));
|
|
|
|
PrintVisionLog(patternDistanceResults);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SaveCsv(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
|
|
var patternDistanceResults = context.GetValue<List<PatternDistanceResult>>(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_DISTANCE_RESULTS, _Params.AlignInfo.GetKey()));
|
|
|
|
foreach (PatternDistanceResult result in patternDistanceResults) {
|
|
_CsvManager.SaveCsvSync(
|
|
_SubSysInfo, PatternDistanceResultItemManager.GetPatternDistanceResultItem(_SubSysInfo, result), eSaveDataType.PatternDistance);
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SeqComplete(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
var patternDistanceResults = context.GetValue<List<PatternDistanceResult>>(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_DISTANCE_RESULTS, _Params.AlignInfo.GetKey()));
|
|
|
|
return SequenceAction.Ok(patternDistanceResults);
|
|
}
|
|
|
|
private void PrintVisionLog(List<PatternDistanceResult> patternDistanceResults) {
|
|
foreach (PatternDistanceResult result in patternDistanceResults) {
|
|
_VisionLog.I($"StartFov : {result.StartFov}");
|
|
_VisionLog.I($"EndFov : {result.EndFov}");
|
|
_VisionLog.I($"Distance : {result.Distance:F3}");
|
|
_VisionLog.I($"ErrRange : {result.ErrRange:F3}");
|
|
_VisionLog.I($"Status : {result.InspStatus}");
|
|
}
|
|
}
|
|
|
|
private void OnStopped(SequenceContext context) {
|
|
LOG.I($"{context.SequenceId} - STOP Handler");
|
|
HandleAbnormalFinish(context);
|
|
}
|
|
|
|
private void OnForceError(SequenceContext context, string id) {
|
|
LOG.E($"{context.SequenceId} - FORCE ERROR Handler");
|
|
HandleAbnormalFinish(context);
|
|
}
|
|
|
|
void HandleAbnormalFinish(SequenceContext context) {
|
|
}
|
|
}
|
|
} |