857 lines
34 KiB
C#
857 lines
34 KiB
C#
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;
|
|
|
|
namespace VisionSequence.Aligner {
|
|
/// <summary>
|
|
/// 얼라인 믹서 시퀀스 파라미터
|
|
/// </summary>
|
|
public class AlignMixerSeqParams : SeqParamsBase {
|
|
/// <summary>Target 얼라인 키 정보</summary>
|
|
public AlignInfo AlignInfo_Tgt { get; set; }
|
|
/// <summary>Source 얼라인 키 정보</summary>
|
|
public AlignInfo AlignInfo_Src { get; set; }
|
|
/// <summary>Target 얼라인 결과</summary>
|
|
public AlignResult AlignResult_Tgt { 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>
|
|
/// 얼라인 믹서 시퀀스 파라미터를 얻어온다.
|
|
/// </summary>
|
|
/// <param name="alignInfo_Tgt">Target 얼라인 키 정보</param>
|
|
/// <param name="alignInfo_Src">Source 얼라인 키 정보</param>
|
|
/// <param name="alignResult_Tgt">Target 얼라인 결과가 null이 아닐 경우, 이후 Target 얼라인 스킵 (선택사항)</param>
|
|
/// <param name="fovPositions">FOV별로 이동시킬 절대위치. null일 경우, 자동으로 Adapter에 정의된 티칭위치로 이동</param>
|
|
/// <param name="displayType">메인 화면 타입</param>
|
|
/// <param name="alignCntClear">얼라인 횟수</param>
|
|
/// <param name="seqMode">시퀀스 모드</param>
|
|
public AlignMixerSeqParams(
|
|
AlignInfo alignInfo_Tgt,
|
|
AlignInfo alignInfo_Src,
|
|
AlignResult alignResult_Tgt = null,
|
|
Dictionary<eFovId, Position> fovPositions = null,
|
|
eDisplayType displayType = eDisplayType.Main_1,
|
|
bool alignCntClear = true,
|
|
eSeqMode seqMode = eSeqMode.Auto) : base(seqMode) {
|
|
|
|
this.AlignInfo_Tgt = alignInfo_Tgt;
|
|
this.AlignInfo_Src = alignInfo_Src;
|
|
this.AlignResult_Tgt = alignResult_Tgt;
|
|
this.FovPositions = fovPositions;
|
|
this.DisplayType = displayType;
|
|
this.AlignCntClear = alignCntClear;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Target(고정형)과 Source(이동형)의 얼라인 보정량을 조합하여, 최종적으로 Source를 Target에 맞추는 얼라인 시퀀스
|
|
/// Target의 3축(X,Y,T)이 모두 움직일 수가 없기 때문에, Source의 모터를 대신 움직여 얼라인 한다.
|
|
/// </summary>
|
|
public class AlignMixerSeq : SubSeqBase {
|
|
private readonly Logger LOG = new Logger(typeof(AlignMixerSeq).Name);
|
|
private Logger _VisionLog = new Logger(typeof(AlignMixerSeq).Name, VisionKeys.LogKey);
|
|
|
|
private TactTimeChecker _TactTimeChecker;
|
|
|
|
// Target Global Variables
|
|
private SubSysInfo _SubSysInfo_Tgt;
|
|
private VisionAligner.Aligner _Aligner_Tgt;
|
|
private AlignRecipe _AlignRecipe_Tgt;
|
|
private AlignResult _AlignResult_Tgt;
|
|
|
|
// Source Global Variables
|
|
private SubSysInfo _SubSysInfo_Src;
|
|
private VisionAligner.Aligner _Aligner_Src;
|
|
private AlignRecipe _AlignRecipe_Src;
|
|
private AlignResult _AlignResult_Src;
|
|
|
|
// Mixed Global Variables
|
|
private AlignResult _AlignResult_Mixed; // _AlignResult_Tgt + _AlignResult_Src
|
|
private AlignLimitChecker _AlignLimitChecker_Mixed;
|
|
private AlignRetryChecker _AlignRetryChecker_Mixed;
|
|
|
|
private AlignMixerSeqParams _Params;
|
|
|
|
private CsvManager _CsvManager = new CsvManager();
|
|
private ImageManager _ImageManager = new ImageManager();
|
|
|
|
private string _SeqName;
|
|
|
|
#region Sequence Id
|
|
private const string SEQ_ID_INIT = "INIT";
|
|
|
|
// Dry Run
|
|
private const string SEQ_ID_CHECK_DRY_RUN = "CHECK_DRY_RUN";
|
|
private const string SEQ_ID_FORK_DRY_RUN = "FORK_DRY_RUN";
|
|
private const string SEQ_ID_CHECK_ALIGN_RESULT_DRY_RUN_TGT = "CHECK_ALIGN_RESULT_DRY_RUN_TGT";
|
|
private const string SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_TGT = "SET_DRY_RUN_SEQ_PARAMS_TGT";
|
|
private const string SEQ_ID_DRY_RUN_SEQ_TGT = "DRY_RUN_SEQ_TGT";
|
|
private const string SEQ_ID_DRY_RUN_UPDATE_UI_TGT = "DRY_RUN_UPDATE_UI_TGT";
|
|
|
|
private const string SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_SRC = "SET_DRY_RUN_SEQ_PARAMS_SRC";
|
|
private const string SEQ_ID_DRY_RUN_SEQ_SRC = "DRY_RUN_SEQ_SRC";
|
|
private const string SEQ_ID_DRY_RUN_UPDATE_UI_SRC = "DRY_RUN_UPDATE_UI_SRC";
|
|
private const string SEQ_ID_JOIN_DRY_RUN = "JOIN_DRY_RUN";
|
|
|
|
// Align
|
|
private const string SEQ_ID_FORK_ALIGN = "FORK_ALIGN";
|
|
private const string SEQ_ID_CHECK_ALIGN_RESULT_TGT = "CHECK_ALIGN_RESULT_TGT";
|
|
|
|
private const string SEQ_ID_CLEAR_TGT = "CLEAR_TGT";
|
|
private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS_TGT = "SET_ALIGN_SEQ_PARAMS_TGT";
|
|
private const string SEQ_ID_ALIGN_SEQ_TGT = "ALIGN_SEQ_TGT";
|
|
private const string SEQ_ID_CHECK_STATUS_TGT = "CHECK_STATUS_TGT";
|
|
|
|
private const string SEQ_ID_CLEAR_SRC = "CLEAR_SRC";
|
|
private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS_SRC = "SET_ALIGN_SEQ_PARAMS_SRC";
|
|
private const string SEQ_ID_ALIGN_SEQ_SRC = "ALIGN_SEQ_SRC";
|
|
private const string SEQ_ID_CHECK_STATUS_SRC = "CHECK_STATUS_SRC";
|
|
private const string SEQ_ID_JOIN_ALIGN = "JOIN_ALIGN";
|
|
|
|
private const string SEQ_ID_MARK_NG = "MARK_NG";
|
|
private const string SEQ_ID_DISTANCE_NG = "DISTANCE_NG";
|
|
|
|
// Mix Align Data
|
|
private const string SEQ_ID_MIX_ALIGN_RESULTS = "MIX_ALIGN_RESULTS";
|
|
private const string SEQ_ID_CHECK_STATUS_MIXED = "CHECK_STATUS_MIXED";
|
|
private const string SEQ_ID_ALIGN_LIMIT_NG = "ALIGN_LIMIT_NG";
|
|
private const string SEQ_ID_RETRY_COUNT_NG = "RETRY_COUNT_NG";
|
|
|
|
// Apply Offset & Move
|
|
private const string SEQ_ID_FORK_MOVE = "FORK_MOVE";
|
|
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_MOVE = "JOIN_MOVE";
|
|
|
|
// Retry
|
|
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_Tgt">Target 얼라인 키 정보</param>
|
|
/// <param name="alignInfo_Src">Source 얼라인 키 정보</param>
|
|
public AlignMixerSeq(string seqName, AlignInfo alignInfo_Tgt, AlignInfo alignInfo_Src) {
|
|
_SeqName = seqName;
|
|
_AlignRecipe_Tgt = VisionRecipeManager.GetAlignRecipe(alignInfo_Tgt);
|
|
_AlignRecipe_Src = VisionRecipeManager.GetAlignRecipe(alignInfo_Src);
|
|
}
|
|
|
|
private void SetActions(SequenceBuilder sb) {
|
|
SequenceBuilder dryRunSeqBuilder_tgt = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_DryRun(), typeof(AlignSeq_DryRun).Name);
|
|
SequenceBuilder dryRunSeqBuilder_src = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_DryRun(), typeof(AlignSeq_DryRun).Name);
|
|
SequenceBuilder alignSeqBuilder_Tgt = SubSeqManager.CreateSubSeqBuilder(new AlignSubSeq(), typeof(AlignSubSeq).Name);
|
|
SequenceBuilder alignSeqBuilder_Src = SubSeqManager.CreateSubSeqBuilder(new AlignSubSeq(), typeof(AlignSubSeq).Name);
|
|
|
|
sb.AddAction(SEQ_ID_INIT, Init);
|
|
|
|
// Dry Run
|
|
sb.AddDecision(SEQ_ID_CHECK_DRY_RUN, CheckDryRun);
|
|
sb.AddFork(SEQ_ID_FORK_DRY_RUN);
|
|
sb.AddDecision(SEQ_ID_CHECK_ALIGN_RESULT_DRY_RUN_TGT, CheckAlignResult_Tgt);
|
|
|
|
sb.AddAction(SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_TGT, SetDryRunSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_DRY_RUN_SEQ_TGT, dryRunSeqBuilder_tgt);
|
|
sb.AddAction(SEQ_ID_DRY_RUN_UPDATE_UI_TGT, UpdateUI);
|
|
|
|
sb.AddAction(SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_SRC, SetDryRunSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_DRY_RUN_SEQ_SRC, dryRunSeqBuilder_src);
|
|
sb.AddAction(SEQ_ID_DRY_RUN_UPDATE_UI_SRC, UpdateUI);
|
|
sb.AddJoin(SEQ_ID_JOIN_DRY_RUN);
|
|
|
|
// Align
|
|
sb.AddFork(SEQ_ID_FORK_ALIGN);
|
|
sb.AddDecision(SEQ_ID_CHECK_ALIGN_RESULT_TGT, CheckAlignResult_Tgt);
|
|
|
|
sb.AddAction(SEQ_ID_CLEAR_TGT, Clear);
|
|
sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS_TGT, SetAlignSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_ALIGN_SEQ_TGT, alignSeqBuilder_Tgt);
|
|
sb.AddDecision(SEQ_ID_CHECK_STATUS_TGT, CheckStatus);
|
|
|
|
sb.AddAction(SEQ_ID_CLEAR_SRC, Clear);
|
|
sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS_SRC, SetAlignSeqParams);
|
|
sb.AddSubsequence(SEQ_ID_ALIGN_SEQ_SRC, alignSeqBuilder_Src);
|
|
sb.AddDecision(SEQ_ID_CHECK_STATUS_SRC, CheckStatus);
|
|
sb.AddJoin(SEQ_ID_JOIN_ALIGN);
|
|
|
|
sb.AddAction(SEQ_ID_MARK_NG, MarkNG);
|
|
sb.AddAction(SEQ_ID_DISTANCE_NG, DistanceNG);
|
|
|
|
// Mix Align Data
|
|
sb.AddAction(SEQ_ID_MIX_ALIGN_RESULTS, MixAlignResults);
|
|
sb.AddDecision(SEQ_ID_CHECK_STATUS_MIXED, CheckStatusMixed);
|
|
sb.AddAction(SEQ_ID_ALIGN_LIMIT_NG, AlignLimitNG);
|
|
sb.AddAction(SEQ_ID_RETRY_COUNT_NG, RetryCountNG);
|
|
|
|
// Move
|
|
sb.AddFork(SEQ_ID_FORK_MOVE);
|
|
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_MOVE);
|
|
|
|
// Retry
|
|
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_CHECK_DRY_RUN] // DryRun인 경우
|
|
> sb[SEQ_ID_FORK_DRY_RUN]
|
|
> sb[SEQ_ID_CHECK_ALIGN_RESULT_DRY_RUN_TGT]
|
|
> sb[SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_TGT]
|
|
> sb[SEQ_ID_DRY_RUN_SEQ_TGT]
|
|
> sb[SEQ_ID_DRY_RUN_UPDATE_UI_TGT]
|
|
> sb[SEQ_ID_JOIN_DRY_RUN]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_ALIGN_RESULT_DRY_RUN_TGT]
|
|
> sb[SEQ_ID_DRY_RUN_UPDATE_UI_TGT]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_FORK_DRY_RUN]
|
|
> sb[SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_SRC]
|
|
> sb[SEQ_ID_DRY_RUN_SEQ_SRC]
|
|
> sb[SEQ_ID_DRY_RUN_UPDATE_UI_SRC]
|
|
> sb[SEQ_ID_JOIN_DRY_RUN]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_DRY_RUN] // DryRun이 아닌 경우
|
|
> sb[SEQ_ID_FORK_ALIGN]
|
|
> sb[SEQ_ID_CLEAR_SRC]
|
|
> sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS_SRC]
|
|
> sb[SEQ_ID_ALIGN_SEQ_SRC]
|
|
> sb[SEQ_ID_CHECK_STATUS_SRC]
|
|
> sb[SEQ_ID_JOIN_ALIGN]
|
|
> sb[SEQ_ID_MIX_ALIGN_RESULTS]
|
|
> sb[SEQ_ID_CHECK_STATUS_MIXED]
|
|
> sb[SEQ_ID_FORK_MOVE]
|
|
> sb[SEQ_ID_APPLY_OFFSET]
|
|
> sb[SEQ_ID_CHECK_MOVE_ENABLED]
|
|
> sb[SEQ_ID_MOVE_DELTA]
|
|
> sb[SEQ_ID_MOVE_FINISHED]
|
|
> sb[SEQ_ID_JOIN_MOVE]
|
|
> sb[SEQ_ID_CHECK_RETRY]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_FORK_ALIGN]
|
|
> sb[SEQ_ID_CHECK_ALIGN_RESULT_TGT]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_ALIGN_RESULT_TGT] // Target 얼라인을 수행하지 않은 경우 Skip (X)
|
|
> sb[SEQ_ID_CLEAR_TGT]
|
|
> sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS_TGT]
|
|
> sb[SEQ_ID_ALIGN_SEQ_TGT]
|
|
> sb[SEQ_ID_CHECK_STATUS_TGT]
|
|
> sb[SEQ_ID_JOIN_ALIGN]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_ALIGN_RESULT_TGT] // Target 얼라인을 이미 수행한 경우 Skip (O)
|
|
> sb[SEQ_ID_CHECK_STATUS_TGT]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_TGT] // Target Align - Mark NG
|
|
> sb[SEQ_ID_MARK_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_TGT] // Target Align - Distance NG
|
|
> sb[SEQ_ID_DISTANCE_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_SRC] // Retry 후에는 Join할 필요 없이 바로 얼라인 데이터를 Mix시킨다.
|
|
> sb[SEQ_ID_MIX_ALIGN_RESULTS]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_SRC] // Source Align - Mark NG
|
|
> sb[SEQ_ID_MARK_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_SRC] // Source Align - Distance NG
|
|
> sb[SEQ_ID_DISTANCE_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_MIXED] // Mixed Align - Limit NG
|
|
> sb[SEQ_ID_ALIGN_LIMIT_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_STATUS_MIXED] // Mixed Align - Retry Count NG
|
|
> sb[SEQ_ID_RETRY_COUNT_NG]
|
|
> sb[SEQ_ID_SEQ_COMPLETE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_MOVE_ENABLED]
|
|
> sb[SEQ_ID_MOVE_FINISHED]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_FORK_MOVE]
|
|
> sb[SEQ_ID_UPDATE_UI]
|
|
> sb[SEQ_ID_SAVE_CSV]
|
|
> sb[SEQ_ID_SAVE_SCREENSHOT]
|
|
> sb[SEQ_ID_JOIN_MOVE]
|
|
);
|
|
sb.Flows(
|
|
sb[SEQ_ID_CHECK_RETRY] // Retry
|
|
> sb[SEQ_ID_CLEAR_SRC]
|
|
);
|
|
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, typeof(AlignMixerSeq).Name);
|
|
|
|
if (param.Param != null) {
|
|
_Params = param.Param as AlignMixerSeqParams;
|
|
}
|
|
else {
|
|
LOG.E($"Param is null.");
|
|
return null;
|
|
}
|
|
|
|
_SubSysInfo_Tgt = VisionRecipeManager.GetSubSysInfo(_Params.AlignInfo_Tgt.UnitId, _Params.AlignInfo_Tgt.SubSysId);
|
|
_Aligner_Tgt = AlignAgentManager.GetAlignAgent(_Params.AlignInfo_Tgt);
|
|
_Aligner_Tgt.Clear();
|
|
_AlignRecipe_Tgt = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo_Tgt);
|
|
_AlignResult_Tgt = _Params.AlignResult_Tgt;
|
|
|
|
_SubSysInfo_Src = VisionRecipeManager.GetSubSysInfo(_Params.AlignInfo_Src.UnitId, _Params.AlignInfo_Src.SubSysId);
|
|
_Aligner_Src = AlignAgentManager.GetAlignAgent(_Params.AlignInfo_Src);
|
|
_Aligner_Src.Clear();
|
|
_AlignRecipe_Src = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo_Src);
|
|
_AlignResult_Src = null;
|
|
|
|
_AlignLimitChecker_Mixed = new AlignLimitChecker(_AlignRecipe_Src);
|
|
_AlignRetryChecker_Mixed = new AlignRetryChecker(_AlignRecipe_Src);
|
|
_AlignResult_Mixed = null;
|
|
|
|
if (_Params.AlignCntClear) {
|
|
_Aligner_Tgt.Clear();
|
|
_Aligner_Src.Clear();
|
|
}
|
|
|
|
_VisionLog.V("[START]");
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult Clear(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (id == SEQ_ID_CLEAR_TGT) {
|
|
//_AlignResult_Tgt = null; // Target 얼라인 데이터는 한 번 정해지면 초기화할 필요가 없다.
|
|
GrabFindSeqUtil.Clear(_SubSysInfo_Tgt);
|
|
AlignResultItemManager.Clear(_SubSysInfo_Tgt);
|
|
PatternResultItemManager.Clear(_SubSysInfo_Tgt);
|
|
}
|
|
else {
|
|
_AlignResult_Src = null;
|
|
GrabFindSeqUtil.Clear(_SubSysInfo_Src);
|
|
AlignResultItemManager.Clear(_SubSysInfo_Src);
|
|
PatternResultItemManager.Clear(_SubSysInfo_Src);
|
|
}
|
|
|
|
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_FORK_DRY_RUN;
|
|
}
|
|
else {
|
|
return SEQ_ID_FORK_ALIGN;
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult SetDryRunSeqParams(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
SubSysInfo subSysInfo;
|
|
AlignInfo alignInfo;
|
|
|
|
if (id == SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_TGT) {
|
|
subSysInfo = _SubSysInfo_Tgt;
|
|
alignInfo = _Params.AlignInfo_Tgt;
|
|
}
|
|
else {
|
|
subSysInfo = _SubSysInfo_Src;
|
|
alignInfo = _Params.AlignInfo_Src;
|
|
}
|
|
|
|
var fovInfos = new Dictionary<eFovId, FovInfo>();
|
|
foreach (var fovInfo in VisionRecipeManager.GetFovInfos(subSysInfo)) {
|
|
fovInfos.Add(fovInfo.FovId, fovInfo);
|
|
}
|
|
|
|
return SequenceAction.Ok(new AlignSeqParams_DryRun(alignInfo, fovInfos));
|
|
}
|
|
#endregion
|
|
|
|
private string CheckAlignResult_Tgt(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
if (_Params.AlignResult_Tgt == null) {
|
|
if (id.Contains("DRY_RUN")) {
|
|
return SEQ_ID_DRY_RUN_UPDATE_UI_TGT;
|
|
}
|
|
else {
|
|
return SEQ_ID_CLEAR_TGT; // 입력받은 Target 얼라인 보정량이 없으면, 얼라인 수행
|
|
}
|
|
}
|
|
else {
|
|
if (id.Contains("DRY_RUN")) {
|
|
return SEQ_ID_SET_DRY_RUN_SEQ_PARAMS_TGT;
|
|
}
|
|
else {
|
|
return SEQ_ID_CHECK_STATUS_TGT; // 입력받은 Target 얼라인 보정량이 있으면, 얼라인 Skip
|
|
}
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult SetAlignSeqParams(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (id == SEQ_ID_SET_ALIGN_SEQ_PARAMS_TGT) {
|
|
return SequenceAction.Ok(new AlignSubSeqParams(_Params.AlignInfo_Tgt, _Params.FovPositions));
|
|
}
|
|
else {
|
|
return SequenceAction.Ok(new AlignSubSeqParams(_Params.AlignInfo_Src, _Params.FovPositions));
|
|
}
|
|
}
|
|
|
|
private string CheckStatus(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) { // Param : AlignResult
|
|
|
|
var alignResult = param.Param as AlignResult;
|
|
|
|
if (id == SEQ_ID_CHECK_ALIGN_RESULT_TGT) {
|
|
return SEQ_ID_JOIN_ALIGN; // Target Align - Skip
|
|
}
|
|
else if (id == SEQ_ID_CHECK_STATUS_TGT) {
|
|
if (alignResult != null) {
|
|
_AlignResult_Tgt = alignResult;
|
|
BindProcessData(context, id, param);
|
|
|
|
if (_AlignResult_Tgt.Status == AlignStatus.NOT_FOUND) {
|
|
return SEQ_ID_MARK_NG;
|
|
}
|
|
else if (_AlignResult_Tgt.Status == AlignStatus.DISTANCE_NG) {
|
|
return SEQ_ID_DISTANCE_NG;
|
|
}
|
|
else {
|
|
return SEQ_ID_JOIN_ALIGN; // 새로 수행한 Target Align - OK
|
|
}
|
|
}
|
|
else {
|
|
return SEQ_ID_JOIN_ALIGN; // InitParam으로 넘겨받은 Target Align - OK
|
|
}
|
|
}
|
|
else {
|
|
_AlignResult_Src = alignResult;
|
|
|
|
// Source 자체의 Retry, Limit 체크는 의미가 없기 때문에, 항상 OK로 처리
|
|
if (_AlignResult_Src.Status == AlignStatus.RETRY ||
|
|
_AlignResult_Src.Status == AlignStatus.RETRY_COUNT_OVER ||
|
|
_AlignResult_Src.Status == AlignStatus.ALIGN_LIMIT_OVER) {
|
|
_AlignResult_Src.Status = AlignStatus.OK;
|
|
}
|
|
|
|
BindProcessData(context, id, param);
|
|
|
|
if (_AlignResult_Src.Status == AlignStatus.NOT_FOUND) {
|
|
return SEQ_ID_MARK_NG;
|
|
}
|
|
else if (_AlignResult_Src.Status == AlignStatus.DISTANCE_NG) {
|
|
return SEQ_ID_DISTANCE_NG;
|
|
}
|
|
else {
|
|
if (_AlignResult_Mixed?.Status == AlignStatus.RETRY) {
|
|
return SEQ_ID_MIX_ALIGN_RESULTS; // Retry Source Align - OK, Join으로 Target을 기다릴 필요가 없다.
|
|
}
|
|
else {
|
|
return SEQ_ID_JOIN_ALIGN; // 최초 1번 Source Align - OK
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private SequenceActionResult MarkNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult DistanceNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult MixAlignResults(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (_AlignResult_Tgt != null && _AlignResult_Src != null) {
|
|
_AlignResult_Mixed = _AlignResult_Src.Clone();
|
|
_AlignResult_Mixed.Delta.X += _AlignResult_Tgt.Delta.X;
|
|
_AlignResult_Mixed.Delta.Y += _AlignResult_Tgt.Delta.Y;
|
|
_AlignResult_Mixed.Delta.T += _AlignResult_Tgt.Delta.T;
|
|
_AlignResult_Mixed.AlignName = "Mixed Align";
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private string CheckStatusMixed(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
// Mixed는 Source의 레시피를 활용하지만, Source의 Status를 그대로 사용할 수 없다.
|
|
// Mixed는 Aligner를 사용하지 않기 때문에, Mixed의 Status를 여기서 재정의 해주어야 한다.
|
|
|
|
_AlignResult_Mixed.Status = AlignStatus.OK;
|
|
|
|
if (_AlignLimitChecker_Mixed.IsEnabled()) {
|
|
_AlignResult_Mixed.Status = _AlignLimitChecker_Mixed.GetAlignLimitStatus(_AlignResult_Mixed.Delta);
|
|
|
|
if (_AlignResult_Mixed.Status == AlignStatus.ALIGN_LIMIT_OVER) {
|
|
return SEQ_ID_ALIGN_LIMIT_NG;
|
|
}
|
|
}
|
|
if (_AlignRetryChecker_Mixed.IsEnabled()) {
|
|
_AlignResult_Mixed.Status = _AlignRetryChecker_Mixed.GetRetryStatus(_AlignResult_Mixed.Delta);
|
|
|
|
if (_AlignResult_Mixed.Status == AlignStatus.RETRY_COUNT_OVER) {
|
|
return SEQ_ID_RETRY_COUNT_NG;
|
|
}
|
|
}
|
|
|
|
return SEQ_ID_FORK_MOVE;
|
|
}
|
|
|
|
private SequenceActionResult AlignLimitNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
BindProcessData(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private SequenceActionResult RetryCountNG(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
BindProcessData(context, id, param);
|
|
|
|
return SequenceAction.Error(E1.GENERIC);
|
|
}
|
|
|
|
private void BindProcessData(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
UpdateUI(context, id, param);
|
|
SaveCsv(context, id, param);
|
|
SaveScreenShot(context, id, param);
|
|
}
|
|
|
|
private SequenceActionResult ApplyOffset(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
// Retry일 때는 오프셋을 반영하지 않는다.
|
|
if (_AlignResult_Mixed.Status == AlignStatus.OK || _AlignResult_Mixed.Status == AlignStatus.F_OK) {
|
|
if (_AlignRecipe_Src.AlignOffset.Enabled) { // Mixer 서브시스템이 따로 없으므로, Source의 얼라인 레시피를 사용하기로 한다.
|
|
var alignOffset = _AlignRecipe_Src.AlignOffset;
|
|
_AlignResult_Mixed.Delta.X += alignOffset.OffsetX;
|
|
_AlignResult_Mixed.Delta.Y += alignOffset.OffsetY;
|
|
_AlignResult_Mixed.Delta.T.Degree += alignOffset.OffsetT;
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private string CheckMoveEnabled(
|
|
SequenceContext context,
|
|
string id,
|
|
ICollection<string> branches,
|
|
SequenceActionResult param) {
|
|
|
|
if (_AlignRecipe_Src.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();
|
|
}
|
|
|
|
var alignDirector = AlignDirectorManager.Instance.GetDirector(_SubSysInfo_Src);
|
|
var motionDelta = alignDirector.ApplyDirection(_AlignResult_Mixed.Delta.ToPosition());
|
|
var res = EquipAdapter.Instance.AlignMotionManager.RelMove(_SubSysInfo_Src, 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_Move를 위해 지나가는 노드
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult UpdateUI(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
AlignResult alignResult;
|
|
AlignInfo alignInfo;
|
|
|
|
if (id.Contains("DRY_RUN")) {
|
|
return SequenceAction.Ok();
|
|
}
|
|
else if (id.Contains("TGT")) {
|
|
alignResult = _AlignResult_Tgt;
|
|
alignInfo = _Params.AlignInfo_Tgt;
|
|
}
|
|
else if (id.Contains("SRC")) {
|
|
alignResult = _AlignResult_Src;
|
|
alignInfo = _Params.AlignInfo_Src;
|
|
}
|
|
else {
|
|
alignResult = _AlignResult_Mixed;
|
|
alignInfo = _Params.AlignInfo_Src;
|
|
}
|
|
|
|
VisionEnv.AuroraEnv.EventPublisher.Publish(
|
|
new EventMessage(alignInfo.ToSubSysInfo().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()) {
|
|
if (id.Contains("TGT")) {
|
|
_CsvManager.SaveCsv(_SubSysInfo_Tgt, AlignResultItemManager.GetAlignResultItem(_SubSysInfo_Tgt, _AlignResult_Tgt), eSaveDataType.Align);
|
|
}
|
|
else if (id.Contains("SRC")) {
|
|
_CsvManager.SaveCsv(_SubSysInfo_Src, AlignResultItemManager.GetAlignResultItem(_SubSysInfo_Src, _AlignResult_Src), eSaveDataType.Align);
|
|
}
|
|
else {
|
|
_CsvManager.SaveCsv(_SubSysInfo_Src, AlignResultItemManager.GetAlignResultItem(_SubSysInfo_Src, _AlignResult_Mixed), eSaveDataType.Align);
|
|
}
|
|
}
|
|
|
|
return SequenceAction.Ok();
|
|
}
|
|
|
|
private SequenceActionResult SaveScreenShot(
|
|
SequenceContext context,
|
|
string id,
|
|
SequenceActionResult param) {
|
|
|
|
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
|
|
var materialInfo = context.GetValue<MaterialInfo>(VisionContextKeys.CNTXT_KEY_MATERIAL_INFO);
|
|
VisionAligner.Aligner aligner;
|
|
AlignResult alignResult;
|
|
AlignInfo alignInfo;
|
|
SubSysInfo subSysInfo;
|
|
|
|
if (id.Contains("TGT")) {
|
|
aligner = _Aligner_Tgt;
|
|
alignResult = _AlignResult_Tgt;
|
|
alignInfo = _Params.AlignInfo_Tgt;
|
|
subSysInfo = _SubSysInfo_Tgt;
|
|
}
|
|
else if (id.Contains("SRC")) {
|
|
aligner = _Aligner_Src;
|
|
alignResult = _AlignResult_Src;
|
|
alignInfo = _Params.AlignInfo_Src;
|
|
subSysInfo = _SubSysInfo_Src;
|
|
}
|
|
else {
|
|
aligner = _Aligner_Src;
|
|
alignResult = _AlignResult_Mixed;
|
|
alignInfo = _Params.AlignInfo_Src;
|
|
subSysInfo = _SubSysInfo_Src;
|
|
}
|
|
|
|
if (aligner.IsAlignStatusNG(alignResult.Status) || VisionSettingManager.VisionSetting.SaveOkSceenShotImage) {
|
|
var lastFovId = context.GetValue<eFovId>(string.Format(VisionContextKeys.CNTXT_KEY_LAST_MEASURE_FOV_ID, 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) {
|
|
|
|
if (_AlignRetryChecker_Mixed.IsEnabled()) {
|
|
if (_AlignResult_Mixed.Status == AlignStatus.RETRY) {
|
|
if (_AlignRecipe_Src.ProcParams.AlignDeltaMoveEnabled) {
|
|
return SEQ_ID_CLEAR_SRC; // 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) {
|
|
|
|
_TactTimeChecker.Stop(TactTimeType.ProcSeq, typeof(AlignMixerSeq).Name); // 택타임 측정 종료
|
|
_VisionLog.V("[END]");
|
|
|
|
return SequenceAction.Ok(_AlignResult_Mixed);
|
|
}
|
|
|
|
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, typeof(AlignMixerSeq).Name); // 택타임 측정 종료
|
|
}
|
|
}
|
|
}
|