734 lines
30 KiB
C#
734 lines
30 KiB
C#
/*
|
|
* Copyright (c) 2025 LG Electronics Inc.
|
|
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
|
|
*/
|
|
using Aurora.Api;
|
|
using Aurora.Api.Devices;
|
|
using VisionCommon;
|
|
using VisionSequence.Pattern;
|
|
using VisionAligner;
|
|
using Hermes;
|
|
using VisionDirector;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.Remoting.Contexts;
|
|
using VisionCommon.DB.Align;
|
|
using VisionCommon.DB;
|
|
using System;
|
|
|
|
namespace VisionSequence.Aligner {
|
|
/// <summary>
|
|
/// 얼라인 공정 시퀀스 파라미터
|
|
/// </summary>
|
|
public class AlignProcSeqParams : SeqParamsBase {
|
|
/// <summary>얼라인 키 정보</summary>
|
|
public AlignInfo AlignInfo { get; set; }
|
|
/// <summary>FOV별로 이동시킬 절대위치</summary>
|
|
public Dictionary<eFovId, Position> FovPositions { get; set; }
|
|
/// <summary>메인 화면 타입</summary>
|
|
public eDisplayType DisplayType { get; set; }
|
|
|
|
/// <summary>
|
|
/// 얼라인 재시도(Retry) 카운트 초기화 플래그
|
|
/// 1) 비전에서 Move와 Retry를 처리할 경우 [True]
|
|
/// 2) 제어에서 Move와 Retry를 처리하면서, 얼라인 시퀀스를 신규 호출한 경우 [True]
|
|
/// 3) 제어에서 Move와 Retry를 처리하면서, Retry로 얼라인 시퀀스를 다시 호출한 경우 [False]
|
|
/// </summary>
|
|
public bool AlignCntClear { get; set; }
|
|
|
|
/// <summary>
|
|
/// DB 사용시에만 할당해서 사용
|
|
/// </summary>
|
|
internal VisionAlignDB AlignDB { get; set; }
|
|
|
|
/// <summary>
|
|
/// 얼라인 시퀀스 파라미터를 얻어온다.
|
|
/// </summary>
|
|
/// <param name="alignInfo">얼라인 키 정보</param>
|
|
/// <param name="fovPositions">FOV별로 이동시킬 절대위치. null일 경우, 자동으로 Adapter에 정의된 티칭위치로 이동</param>
|
|
/// <param name="displayType">메인 화면 타입</param>
|
|
/// <param name="alignCntClear">얼라인 횟수</param>
|
|
/// <param name="seqMode">시퀀스 모드</param>
|
|
public AlignProcSeqParams(
|
|
AlignInfo alignInfo,
|
|
Dictionary<eFovId, Position> fovPositions = null,
|
|
eDisplayType displayType = eDisplayType.Main_1,
|
|
bool alignCntClear = true,
|
|
eSeqMode seqMode = eSeqMode.Auto) : base(seqMode) {
|
|
|
|
this.AlignInfo = alignInfo;
|
|
this.FovPositions = fovPositions;
|
|
this.DisplayType = displayType;
|
|
this.AlignCntClear = alignCntClear;
|
|
AlignDB = VisionSettingManager.VisionSetting.UseDBService ? new VisionAlignDB(alignInfo, seqMode) : null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 얼라인 공정 시퀀스
|
|
/// </summary>
|
|
public class AlignProcSeq : SubSeqBase {
|
|
private readonly Logger LOG = new Logger(typeof(AlignProcSeq).Name);
|
|
private Logger _VisionLog = new Logger(typeof(AlignProcSeq).Name, VisionKeys.LogKey);
|
|
|
|
private TactTimeChecker _TactTimeChecker;
|
|
private VisionAligner.Aligner _Aligner;
|
|
private AlignRecipe _AlignRecipe;
|
|
private SubSysInfo _SubSysInfo;
|
|
private AlignProcSeqParams _Params;
|
|
private CsvManager _CsvManager = new CsvManager();
|
|
private ImageManager _ImageManager = new ImageManager();
|
|
|
|
private string _SeqName;
|
|
|
|
#region Sequence Id
|
|
private const string SEQ_ID_INIT = "INIT";
|
|
private const string SEQ_ID_MOVE_FIRST_TEACHING_POS = "SEQ_ID_MOVE_FIRST_TEACHING_POS";
|
|
|
|
// Dry Run
|
|
private const string SEQ_CHECK_DRY_RUN = "CHECK_DRY_RUN";
|
|
private const string SEQ_ID_SET_DRY_RUN_SEQ_PARAMS = "SET_DRY_RUN_SEQ_PARAMS";
|
|
private const string SEQ_ID_DRY_RUN_SEQ = "DRY_RUN_SEQ";
|
|
private const string SEQ_ID_DRY_RUN_UPDATE_UI = "DRY_RUN_UPDATE_UI";
|
|
|
|
private const string SEQ_ID_CLEAR = "CLEAR";
|
|
private const string SEQ_ID_CHECK_PROC_PATTERN = "SEQ_ID_CHECK_PROC_PATTERN";
|
|
private const string SEQ_ID_UNDEFINED_PATTERN_NG = "SEQ_ID_UNDEFINED_PATTERN_NG";
|
|
private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS = "SET_ALIGN_SEQ_PARAMS";
|
|
private const string SEQ_ID_ALIGN_SEQ = "ALIGN_SEQ";
|
|
private const string SEQ_ID_CHECK_STATUS = "CHECK_STATUS";
|
|
private const string SEQ_ID_MARK_NG = "MARK_NG";
|
|
private const string SEQ_ID_DISTANCE_NG = "DISTANCE_NG";
|
|
private const string SEQ_ID_ALIGN_LIMIT_NG = "ALIGN_LIMIT_NG";
|
|
private const string SEQ_ID_RETRY_COUNT_NG = "RETRY_COUNT_NG";
|
|
private const string SEQ_ID_ALIGN_RESULT_NULL = "ALIGN_RESULT_NULL";
|
|
|
|
private const string SEQ_ID_FORK = "FORK";
|
|
private const string SEQ_ID_APPLY_OFFSET = "APPLY_OFFSET";
|
|
private const string SEQ_ID_CHECK_MOVE_ENABLED = "CHECK_MOVE_ENABLED";
|
|
private const string SEQ_ID_MOVE_DELTA = "MOVE_DELTA";
|
|
private const string SEQ_ID_MOVE_FINISHED = "MOVE_FINISHED";
|
|
private const string SEQ_ID_UPDATE_UI = "UPDATE_UI";
|
|
private const string SEQ_ID_SAVE_CSV = "SAVE_CSV";
|
|
private const string SEQ_ID_SAVE_SCREENSHOT = "SAVE_SCREENSHOT";
|
|
private const string SEQ_ID_JOIN = "JOIN";
|
|
|
|
private const string SEQ_ID_CHECK_RETRY = "CHECK_RETRY";
|
|
private const string SEQ_ID_SEQ_COMPLETE = "SEQ_COMPLETE";
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 생성자
|
|
/// </summary>
|
|
/// <param name="seqName">시퀀스 이름</param>
|
|
/// <param name="alignInfo">시퀀스 키 정보</param>
|
|
public AlignProcSeq(string seqName, AlignInfo alignInfo) {
|
|
_SeqName = seqName;
|
|
_AlignRecipe = VisionRecipeManager.GetAlignRecipe(alignInfo);
|
|
_SubSysInfo = alignInfo?.ToSubSysInfo();
|
|
}
|
|
|
|
private void SetActions(SequenceBuilder sb) {
|
|
SequenceBuilder dryRunSeqBuilder = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_DryRun(), typeof(AlignSeq_DryRun).Name);
|
|
SequenceBuilder alignSeqBuilder = SubSeqManager.CreateSubSeqBuilder(new AlignSubSeq(), typeof(AlignSubSeq).Name);
|
|
|
|
sb.AddAction(SEQ_ID_INIT, Init);
|
|
sb.AddAction(SEQ_ID_MOVE_FIRST_TEACHING_POS, MoveFirstTeachingPos);
|
|
|
|
// Dry Run
|
|
sb.AddDecision(SEQ_CHECK_DRY_RUN, CheckDryRun);
|
|
sb.AddAction(SEQ_ID_SET_DRY_RUN_SEQ_PARAMS, SetDryRunSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_DRY_RUN_SEQ, dryRunSeqBuilder);
|
|
sb.AddAction(SEQ_ID_DRY_RUN_UPDATE_UI, UpdateUI);
|
|
|
|
sb.AddAction(SEQ_ID_CLEAR, Clear);
|
|
sb.AddDecision(SEQ_ID_CHECK_PROC_PATTERN, CheckProcPattern);
|
|
sb.AddAction(SEQ_ID_UNDEFINED_PATTERN_NG, UndefinedPatternNG);
|
|
sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS, SetAlignSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_ALIGN_SEQ, alignSeqBuilder);
|
|
sb.AddDecision(SEQ_ID_CHECK_STATUS, CheckStatus);
|
|
sb.AddAction(SEQ_ID_MARK_NG, MarkNG);
|
|
sb.AddAction(SEQ_ID_DISTANCE_NG, DistanceNG);
|
|
sb.AddAction(SEQ_ID_ALIGN_LIMIT_NG, AlignLimitNG);
|
|
sb.AddAction(SEQ_ID_RETRY_COUNT_NG, RetryCountNG);
|
|
sb.AddAction(SEQ_ID_ALIGN_RESULT_NULL, AlignResultNull);
|
|
|
|
sb.AddFork(SEQ_ID_FORK);
|
|
sb.AddAction(SEQ_ID_APPLY_OFFSET, ApplyOffset);
|
|
sb.AddDecision(SEQ_ID_CHECK_MOVE_ENABLED, CheckMoveEnabled);
|
|
sb.AddAction(SEQ_ID_MOVE_DELTA, MoveDelta);
|
|
sb.AddAction(SEQ_ID_MOVE_FINISHED, MoveFinished);
|
|
|
|
sb.AddAction(SEQ_ID_UPDATE_UI, UpdateUI);
|
|
sb.AddAction(SEQ_ID_SAVE_CSV, SaveCsv);
|
|
sb.AddAction(SEQ_ID_SAVE_SCREENSHOT, SaveScreenShot);
|
|
sb.AddJoin(SEQ_ID_JOIN);
|
|
|
|
sb.AddDecision(SEQ_ID_CHECK_RETRY, CheckRetry);
|
|
sb.AddAction(SEQ_ID_SEQ_COMPLETE, SeqComplete);
|
|
}
|
|
|
|
public override SequenceBuilder Builder(string seqName) {
|
|
_SeqName = seqName;
|
|
_TactTimeChecker = new TactTimeChecker(_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_MOVE_FIRST_TEACHING_POS]
|
|
> sb[SEQ_CHECK_DRY_RUN]
|
|
> sb[SEQ_ID_CHECK_PROC_PATTERN]
|
|
> sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS]
|
|
> sb[SEQ_ID_ALIGN_SEQ]
|
|
> sb[SEQ_ID_CHECK_STATUS]
|
|
> sb[SEQ_ID_FORK]
|
|
> sb[SEQ_ID_APPLY_OFFSET]
|
|
> sb[SEQ_ID_CHECK_MOVE_ENABLED]
|
|
> sb[SEQ_ID_MOVE_DELTA]
|
|
> sb[SEQ_ID_MOVE_FINISHED]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_PROC_PATTERN]
|
|
> sb[SEQ_ID_UNDEFINED_PATTERN_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_CHECK_DRY_RUN] // Dry Run
|
|
> sb[SEQ_ID_SET_DRY_RUN_SEQ_PARAMS]
|
|
> sb[SEQ_ID_DRY_RUN_SEQ]
|
|
> sb[SEQ_ID_DRY_RUN_UPDATE_UI]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_FORK]
|
|
> sb[SEQ_ID_UPDATE_UI]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS] // Mark NG
|
|
> sb[SEQ_ID_MARK_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS] // Distance NG
|
|
> sb[SEQ_ID_DISTANCE_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS] // Align Limit NG
|
|
> sb[SEQ_ID_ALIGN_LIMIT_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS] // Retry Count NG
|
|
> sb[SEQ_ID_RETRY_COUNT_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS] // Align Result Null
|
|
> sb[SEQ_ID_ALIGN_RESULT_NULL]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_MOVE_ENABLED]
|
|
> sb[SEQ_ID_MOVE_FINISHED]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_MOVE_FINISHED]
|
|
> sb[SEQ_ID_JOIN]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_UPDATE_UI]
|
|
> sb[SEQ_ID_SAVE_CSV]
|
|
> sb[SEQ_ID_SAVE_SCREENSHOT]
|
|
> sb[SEQ_ID_JOIN]
|
|
> sb[SEQ_ID_CHECK_RETRY]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_RETRY] // Retry
|
|
> sb[SEQ_ID_CLEAR]
|
|
);
|
|
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) {
|
|
_TactTimeChecker.Start(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey);
|
|
|
|
if (param.Param != null) {
|
|
_Params = param.Param as AlignProcSeqParams;
|
|
}
|
|
else {
|
|
LOG.E($"Param is null.");
|
|
return null;
|
|
}
|
|
|
|
_Aligner = AlignAgentManager.GetAlignAgent(_Params.AlignInfo);
|
|
_AlignRecipe = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo);
|
|
_SubSysInfo = VisionRecipeManager.GetSubSysInfo(_Params.AlignInfo.UnitId, _Params.AlignInfo.SubSysId);
|
|
_VisionLog = new Logger(_SubSysInfo.SubSysName, VisionKeys.LogKey);
|
|
_VisionLog.V("[START]");
|
|
context.PutValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo), _AlignRecipe.ProcParams);
|
|
if (_Params.AlignCntClear) {
|
|
_Aligner.Clear();
|
|
}
|
|
if (VisionDBAgentManager.IsUseDB) {
|
|
VisionDBAgentManager.GetAlignDBAgent().AllocNextSeqId(_Params.AlignDB);
|
|
}
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult Clear(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
GrabFindSeqUtil.Clear(_SubSysInfo);
|
|
AlignResultItemManager.Clear(_SubSysInfo);
|
|
PatternResultItemManager.Clear(_SubSysInfo);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult MoveFirstTeachingPos(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
if (EquipAdapter.Instance.EquipMode.IsSimulMode()) {
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
|
|
if (_AlignRecipe.ProcParams.FirstTeachingMoveEnabled || // 첫번째 티칭 위치로 이동 설정이 True인 경우 첫 Fov로 이동한다.
|
|
(alignResult != null && alignResult.Status == AlignStatus.RETRY && _AlignRecipe.AlignRetry.Enabled)) { // Align Retry 상황의 경우 첫 Fov로 이동한다.
|
|
int res = E1.GENERIC;
|
|
var fov1Info = new FovInfo(_SubSysInfo, eFovId.Fov1);
|
|
if (_Params.FovPositions != null && _Params.FovPositions.ContainsKey(eFovId.Fov1)) {
|
|
// 파라미터로 넘겨받은 절대위치로 이동
|
|
res = EquipAdapter.Instance.TeachingMotionManager.AbsMove(fov1Info, _Params.FovPositions[eFovId.Fov1]);
|
|
}
|
|
else {
|
|
// Adapter에 정의된 티칭위치로 이동
|
|
res = EquipAdapter.Instance.TeachingMotionManager.MovePosition(fov1Info, ePositionType.Teaching);
|
|
}
|
|
|
|
if (res == E1.OK) {
|
|
ApplyGrabDelay(_SubSysInfo);
|
|
return SequenceAction.Ok();
|
|
}
|
|
else {
|
|
return SequenceAction.Error(E2.ABORTED);
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
#region Dry Run
|
|
private string CheckDryRun(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsDryrunOrTransferMode()) {
|
|
return SEQ_ID_SET_DRY_RUN_SEQ_PARAMS;
|
|
}
|
|
else {
|
|
return SEQ_ID_CHECK_PROC_PATTERN;
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult SetDryRunSeqParams(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
var fovInfos = new Dictionary<eFovId, FovInfo>();
|
|
foreach (var fovInfo in VisionRecipeManager.GetFovInfos(_SubSysInfo)) {
|
|
fovInfos.Add(fovInfo.FovId, fovInfo);
|
|
}
|
|
|
|
return SequenceAction.Ok(new AlignSeqParams_DryRun(_Params.AlignInfo, fovInfos, displayType: _Params.DisplayType));
|
|
}
|
|
#endregion
|
|
|
|
private string CheckProcPattern(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
var subsysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo);
|
|
foreach (var fovRecipe in subsysRecipe.FovRecipes) {
|
|
if((int)fovRecipe.FovId >= ProcParams.GetFovNum(_AlignRecipe.ProcParams.ProcFovType)) {
|
|
// 얼라인에 사용하는 Fov의 수만큼만 확인한다.
|
|
continue;
|
|
}
|
|
foreach (var procPattern in fovRecipe.PatternRecipe.ProcPatternInfos) {
|
|
if (_Params.AlignInfo.AlignId.ToString() == procPattern.ProcId) {
|
|
if((int)procPattern.ProcPatternId >= ProcParams.GetProcNum(_AlignRecipe.ProcParams.ProcFovType)) {
|
|
// 얼라인에 사용하는 Pattern의 수만큼만 확인한다.
|
|
continue;
|
|
}
|
|
if (procPattern.PatternId == -1) {
|
|
return SEQ_ID_UNDEFINED_PATTERN_NG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return SEQ_ID_SET_ALIGN_SEQ_PARAMS;
|
|
}
|
|
|
|
private SequenceActionResult UndefinedPatternNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
string errMsg = "Undefined PatternID Available";
|
|
PrintErrorLogAndShowErrorToast(LOG, errMsg);
|
|
|
|
context.PutValue<AlignResult>(
|
|
string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()),
|
|
new AlignResult()
|
|
{
|
|
Status = AlignStatus.UNDEFINED_PATTERN,
|
|
DisplayType = _Params.DisplayType,
|
|
AlignAlgorithm = _AlignRecipe.ProcParams.AlignAlgorithm,
|
|
});
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SetAlignSeqParams(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
return SequenceAction.Ok(new AlignSubSeqParams(_Params.AlignInfo, _Params.FovPositions, _Params.DisplayType, _Params.SeqMode));
|
|
}
|
|
|
|
private string CheckStatus(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) { // Param : AlignResult
|
|
|
|
var alignResult = param.Param as AlignResult;
|
|
alignResult.DisplayType = _Params.DisplayType;
|
|
|
|
if (alignResult == null) {
|
|
return SEQ_ID_ALIGN_RESULT_NULL;
|
|
}
|
|
|
|
if (alignResult.Status == AlignStatus.NOT_FOUND) {
|
|
return SEQ_ID_MARK_NG;
|
|
}
|
|
else if (alignResult.Status == AlignStatus.DISTANCE_NG) {
|
|
return SEQ_ID_DISTANCE_NG;
|
|
}
|
|
else if (alignResult.Status == AlignStatus.ALIGN_LIMIT_OVER) {
|
|
return SEQ_ID_ALIGN_LIMIT_NG;
|
|
}
|
|
else if (alignResult.Status == AlignStatus.RETRY_COUNT_OVER) {
|
|
return SEQ_ID_RETRY_COUNT_NG;
|
|
}
|
|
else {
|
|
return SEQ_ID_FORK;
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult MarkNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
DoNgActions(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult DistanceNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
DoNgActions(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult AlignLimitNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
DoNgActions(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult RetryCountNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
DoNgActions(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult AlignResultNull(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private void DoNgActions(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()), alignResult.Clone());
|
|
|
|
UpdateUI(context, id, param);
|
|
SaveCsv(context, id, param);
|
|
SaveScreenShot(context, id, param);
|
|
}
|
|
|
|
private SequenceActionResult ApplyOffset(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
AlignResult alignResultWithOffset = alignResult.Clone();
|
|
|
|
// Retry일 때는 오프셋을 반영하지 않는다.
|
|
if (alignResult.Status == AlignStatus.OK || alignResult.Status == AlignStatus.F_OK) {
|
|
if (_AlignRecipe.AlignOffset.Enabled) {
|
|
var alignOffset = _AlignRecipe.AlignOffset;
|
|
alignResultWithOffset.Delta.X += alignOffset.OffsetX;
|
|
alignResultWithOffset.Delta.Y += alignOffset.OffsetY;
|
|
alignResultWithOffset.Delta.T.Degree += alignOffset.OffsetT;
|
|
}
|
|
}
|
|
|
|
context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()), alignResultWithOffset);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private string CheckMoveEnabled(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
if (_AlignRecipe.ProcParams.AlignDeltaMoveEnabled && _Params.SeqMode == eSeqMode.Auto) {
|
|
return SEQ_ID_MOVE_DELTA;
|
|
}
|
|
else {
|
|
return SEQ_ID_MOVE_FINISHED; // Skip Move
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult MoveDelta(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsSimulMode()) {
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
AlignResult alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()));
|
|
var alignDirector = AlignDirectorManager.Instance.GetDirector(_SubSysInfo);
|
|
var motionDelta = alignDirector.ApplyDirection(alignResultWithOffset.Delta.ToPosition());
|
|
var res = EquipAdapter.Instance.AlignMotionManager.RelMove(_SubSysInfo, motionDelta);
|
|
|
|
if (res != E1.OK) {
|
|
LOG.E("Move Failed.");
|
|
return SequenceAction.Error(E2.ABORTED);
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult MoveFinished(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
// Join을 위해 지나가는 노드
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult UpdateUI(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
alignResult.DisplayType = _Params.DisplayType; // 개별 AlignSequence 에서 진행해 주어야하는 부분인데, 놓쳤을 시 방어코드개념으로 추가
|
|
var subSysInfo = _Params.AlignInfo.ToSubSysInfo();
|
|
VisionEnv.AuroraEnv.EventPublisher.Publish(
|
|
new EventMessage(_Params.AlignInfo.GetKey(), VisionEventId.UPDATE_ALIGN_RESULT, alignResult));
|
|
PrintVisionLog(alignResult);
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SaveCsv(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
_CsvManager.SaveCsv(
|
|
_Params.AlignInfo, AlignResultItemManager.GetAlignResultItem(_Params.AlignInfo, alignResult), eSaveDataType.Align);
|
|
if (VisionDBAgentManager.IsUseDB) {
|
|
_Params.AlignDB.AllocAlignResult(alignResult);
|
|
_Params.AlignDB.SetSeqEnd();
|
|
VisionDBAgentManager.GetAlignDBAgent().SetDataAsync(_Params.AlignDB);
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SaveScreenShot(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
var materialInfo = context.GetValue<MaterialInfo>(VisionContextKeys.CNTXT_KEY_MATERIAL_INFO);
|
|
var fovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo.UnitId, _SubSysInfo.SubSysId, eFovId.Fov1);
|
|
|
|
if (_Aligner.IsAlignStatusNG(alignResult.Status) || VisionSettingManager.VisionSetting.SaveOkSceenShotImage) {
|
|
var lastFovId = context.GetValue<eFovId>(string.Format(VisionContextKeys.CNTXT_KEY_LAST_MEASURE_FOV_ID, _Params.AlignInfo.GetKey()));
|
|
_ImageManager.SaveScreenShot(
|
|
VisionRecipeManager.GetFovInfo(_SubSysInfo, lastFovId),
|
|
alignResult.Status.ToString(), materialInfo, _Params.DisplayType,
|
|
AlignResultItemManager.GetTimeStamp(_SubSysInfo, alignResult));
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private string CheckRetry(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
AlignResult alignResult = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
|
|
if (_Params.SeqMode == eSeqMode.Auto) {
|
|
if (_AlignRecipe.AlignRetry.Enabled) {
|
|
if (alignResult.Status == AlignStatus.RETRY) {
|
|
if (_AlignRecipe.ProcParams.AlignDeltaMoveEnabled) {
|
|
return SEQ_ID_CLEAR; // RETRY
|
|
}
|
|
else {
|
|
return SEQ_ID_SEQ_COMPLETE; // RETRY, BUT NOT MOVE
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return SEQ_ID_SEQ_COMPLETE; // OK
|
|
}
|
|
|
|
private SequenceActionResult SeqComplete(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
AlignResult alignResultWithOffset = new AlignResult();
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
|
|
alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT_WITH_OFFSET, _Params.AlignInfo.GetKey()));
|
|
}
|
|
else { // DryRun의 경우 Offset이 없는 얼라인 결과를 전달
|
|
alignResultWithOffset = context.GetValue<AlignResult>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULT, _Params.AlignInfo.GetKey()));
|
|
}
|
|
SetPatternResults(context, alignResultWithOffset);
|
|
|
|
_TactTimeChecker.Stop(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey); // 택타임 측정 종료
|
|
_VisionLog.V("[END]");
|
|
|
|
if (context.GetValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo)) != null)
|
|
{
|
|
context.RemoveValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo));
|
|
}
|
|
return SequenceAction.Ok(alignResultWithOffset);
|
|
}
|
|
|
|
private void SetPatternResults(SequenceContext context, AlignResult alignResult) {
|
|
var fovInfos = VisionRecipeManager.GetFovInfos(_SubSysInfo);
|
|
foreach (FovInfo fovInfo in fovInfos) {
|
|
var patternResult = context.GetValue<PatternResult>(string.Format(VisionContextKeys.CNTXT_KEY_PATTERN_RESULT, fovInfo.GetKey()));
|
|
if (!alignResult.PatternResults.ContainsKey(fovInfo)) {
|
|
alignResult.PatternResults.Add(fovInfo, patternResult);
|
|
}
|
|
else {
|
|
alignResult.PatternResults[fovInfo] = patternResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PrintVisionLog(AlignResult alignResult) {
|
|
_VisionLog.I($"AlignCnt : {alignResult.AlignCnt}");
|
|
_VisionLog.I($"dX : {alignResult.Delta.X:F4}, dY : {alignResult.Delta.Y:F4}, dT : {alignResult.Delta.T.Degree:F4}");
|
|
_VisionLog.I($"Status : {alignResult.Status}");
|
|
_VisionLog.I($"Algorithm : {alignResult.AlignAlgorithm}");
|
|
}
|
|
|
|
void OnStopped(
|
|
SequenceContext context) {
|
|
LOG.I($"{context.SequenceId} - STOP Handler");
|
|
HandleAbnormalFinish(context);
|
|
}
|
|
|
|
void OnForceError(
|
|
SequenceContext context, string id) {
|
|
LOG.E($"{context.SequenceId} - FORCE ERROR Handler");
|
|
HandleAbnormalFinish(context);
|
|
}
|
|
|
|
void HandleAbnormalFinish(
|
|
SequenceContext context) {
|
|
_TactTimeChecker.Stop(TactTimeType.ProcSeq, VisionKeys.AlignProcSeqKey); // 택타임 측정 종료
|
|
if(context.GetValue<ProcParams>(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo)) != null)
|
|
{
|
|
context.RemoveValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_PROC_PARAMS, _SubSysInfo));
|
|
}
|
|
}
|
|
}
|
|
}
|