using Aurora.Api; using VisionCommon; using VisionAligner; using VisionCalibrator; using VisionSequence.Camera; using System.Collections.Generic; using Aurora.View; using Hermes; namespace VisionSequence.Aligner { /// /// N개 패턴, N번 얼라인 시퀀스 파라미터 /// public class AlignProcSeqParams_PN_AN : SeqParamsBase { /// 얼라인 키 정보 public AlignInfo AlignInfo { get; set; } /// 얼라인 레퍼런스 정보 public RefDistParam RefDistParam { get; set; } /// 플라잉 위치 인덱스 (Optional) public object GrabImage { get; set; } /// 메인 화면 타입 public eDisplayType DisplayType { get; set; } /// /// N개 패턴, N번 얼라인 시퀀스 파라미터를 얻어온다. /// /// 얼라인 키 정보 /// 센터로부터 각 패턴의 정위치까지 떨어진 거리 파라미터 /// 그랩 이미지 (Optional) /// 메인 화면 타입 /// 시퀀스 모드 public AlignProcSeqParams_PN_AN( AlignInfo alignInfo, RefDistParam refDistParam, object grabImage = null, eDisplayType displayType = eDisplayType.Main_1, eSeqMode seqMode = eSeqMode.Auto) : base(seqMode) { this.AlignInfo = alignInfo; this.RefDistParam = refDistParam; this.GrabImage = grabImage; this.DisplayType = displayType; } } /// /// CAM 1대 / FOV 1개 / 패턴 N개 / 1 Point Align N개 / MeasurePattern to (Center + Ref Dist Offset) /// public class AlignProcSeq_PN_AN : SubSeqBase { private readonly Logger LOG = new Logger(typeof(AlignProcSeq_PN_AN).Name); private AlignProcSeqParams_PN_AN _Params; private FovInfo _FovInfo; private AlignRecipe _AlignRecipe; private SubSysInfo _SubSysInfo; private VisionAligner.Aligner _Aligner; private CsvManager _CsvManager = new CsvManager(); private ImageManager _ImageManager = new ImageManager(); private Dictionary _ReferenceResults = new Dictionary(); // _Params.AlignTgtDists로 재구성한 레퍼런스 private Dictionary _AlignResults = new Dictionary(); 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_MOVE_FIRST_TEACHING_POS = "SEQ_ID_MOVE_FIRST_TEACHING_POS"; private const string SEQ_ID_SET_REFERENCES = "SET_REFERENCES"; private const string SEQ_ID_CHECK_GRAB = "CHECK_GRAB"; private const string SEQ_ID_SET_GRAB_SEQ_PARAMS = "SET_GRAB_SEQ_PARAMS"; private const string SEQ_ID_GRAB_SEQ = "GRAB_SEQ"; private const string SEQ_ID_SET_GRAB_IMAGE = "SET_GRAB_IMAGE"; // Dry Run private const string SEQ_ID_CHECK_DRY_RUN = "CHECK_DRY_RUN"; private const string SEQ_ID_DO_DRY_RUN_ACTION = "DO_DRY_RUN_ACTION"; private const string SEQ_ID_CHECK_ALIGN_SEQ_TYPE = "CHECK_ALIGN_TYPE"; private const string SEQ_ID_ALIGN_SEQ_TYPE_NG = "ALIGN_SEQ_TYPE_NG"; private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2 = "SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2"; private const string SEQ_ID_ALIGN_SEQ_C1_F1_AP2_A2 = "ALIGN_SEQ_C1_F1_AP2_A2"; private const string SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN = "SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN"; private const string SEQ_ID_ALIGN_SEQ_C1_F1_SPN_AN = "ALIGN_SEQ_C1_F1_SPN_AN"; private const string SEQ_ID_SET_ALIGN_RESULTS = "SET_ALIGN_RESULTS"; private const string SEQ_ID_SAVE_CSV = "SAVE_CSV"; private const string SEQ_ID_SAVE_SCREENSHOT = "SAVE_SCREENSHOT"; private const string SEQ_ID_SEQ_COMPLETE = "SEQ_COMPLETE"; #endregion /// /// 생성자 /// public AlignProcSeq_PN_AN() { } private void SetActions(SequenceBuilder sb) { var grabSeqBuilder = SubSeqManager.CreateSubSeqBuilder(new GrabSeq(), typeof(GrabSeq).Name); SequenceBuilder alignSeqBuilder_C1_F1_AP2_A2 = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_C1_F1_AP2_A2(), typeof(AlignSeq_C1_F1_AP2_A2).Name); SequenceBuilder alignSeqBuilder_C1_F1_SPN_AN = SubSeqManager.CreateSubSeqBuilder(new AlignSeq_C1_F1_SPN_AN(), typeof(AlignSeq_C1_F1_SPN_AN).Name); sb.AddAction(SEQ_ID_INIT, Init); sb.AddAction(SEQ_ID_CLEAR, Clear); sb.AddAction(SEQ_ID_MOVE_FIRST_TEACHING_POS, MoveFirstTeachingPos); sb.AddAction(SEQ_ID_SET_REFERENCES, SetReferences); sb.AddDecision(SEQ_ID_CHECK_GRAB, CheckGrab); // _Params.GrabImage가 null이면, 신규 그랩 시도 sb.AddAction(SEQ_ID_SET_GRAB_SEQ_PARAMS, SetGrabSeqParams); sb.AddSubsequence(SEQ_ID_GRAB_SEQ, grabSeqBuilder); sb.AddAction(SEQ_ID_SET_GRAB_IMAGE, SetGrabImage); // Dry Run sb.AddDecision(SEQ_ID_CHECK_DRY_RUN, CheckDryRun); sb.AddAction(SEQ_ID_DO_DRY_RUN_ACTION, DoDryRunAction); sb.AddDecision(SEQ_ID_CHECK_ALIGN_SEQ_TYPE, CheckAlignSeqType); sb.AddAction(SEQ_ID_ALIGN_SEQ_TYPE_NG, AlignSeqTypeNG); sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2, SetAlignSeqParams); sb.AddSubsequence(SEQ_ID_ALIGN_SEQ_C1_F1_AP2_A2, alignSeqBuilder_C1_F1_AP2_A2); sb.AddAction(SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN, SetAlignSeqParams); sb.AddSubsequence(SEQ_ID_ALIGN_SEQ_C1_F1_SPN_AN, alignSeqBuilder_C1_F1_SPN_AN); sb.AddAction(SEQ_ID_SET_ALIGN_RESULTS, SetAlignResults); sb.AddAction(SEQ_ID_SAVE_CSV, SaveCsv); sb.AddAction(SEQ_ID_SAVE_SCREENSHOT, SaveScreenShot); 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_MOVE_FIRST_TEACHING_POS] > sb[SEQ_ID_SET_REFERENCES] > sb[SEQ_ID_CHECK_GRAB] // _Params.GrabImage가 null이면, 신규 그랩 시도 > sb[SEQ_ID_SET_GRAB_SEQ_PARAMS] > sb[SEQ_ID_GRAB_SEQ] > sb[SEQ_ID_SET_GRAB_IMAGE] > sb[SEQ_ID_CHECK_DRY_RUN] > sb[SEQ_ID_CHECK_ALIGN_SEQ_TYPE] // 얼라인 C1_F1_AP2_A2 수행 > sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2] > sb[SEQ_ID_ALIGN_SEQ_C1_F1_AP2_A2] > sb[SEQ_ID_SET_ALIGN_RESULTS] > sb[SEQ_ID_SAVE_CSV] > sb[SEQ_ID_SAVE_SCREENSHOT] > sb[SEQ_ID_SEQ_COMPLETE] ); sb.Flows( sb[SEQ_ID_CHECK_DRY_RUN] // 얼라인 타입 에러 > sb[SEQ_ID_DO_DRY_RUN_ACTION] > sb[SEQ_ID_SEQ_COMPLETE] ); sb.Flows( sb[SEQ_ID_CHECK_ALIGN_SEQ_TYPE] // 얼라인 C1_F1_SPN_AN 수행 > sb[SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN] > sb[SEQ_ID_ALIGN_SEQ_C1_F1_SPN_AN] > sb[SEQ_ID_SET_ALIGN_RESULTS] ); sb.Flows( sb[SEQ_ID_CHECK_ALIGN_SEQ_TYPE] // 얼라인 타입 에러 > sb[SEQ_ID_ALIGN_SEQ_TYPE_NG] ); sb.Flows( sb[SEQ_ID_CHECK_GRAB] // 그랩 Skip > sb[SEQ_ID_CHECK_ALIGN_SEQ_TYPE] ); 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 AlignProcSeqParams_PN_AN; } else { LOG.E($"Param is null."); return null; } _AlignRecipe = VisionRecipeManager.GetAlignRecipe(_Params.AlignInfo); _SubSysInfo = VisionRecipeManager.GetSubSysInfo(_Params.AlignInfo.UnitId, _Params.AlignInfo.SubSysId); _FovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo, eFovId.Fov1); _Aligner = AlignAgentManager.GetAlignAgent(_Params.AlignInfo); _VisionLog = new Logger(_SubSysInfo.SubSysName, VisionKeys.LogKey); return SequenceAction.Ok(); } private SequenceActionResult Clear( SequenceContext context, string id, SequenceActionResult param) { for (int patternPosIdx = 0; patternPosIdx < _Params.RefDistParam.RefDists.Count; patternPosIdx++) { if (!_ReferenceResults.ContainsKey(patternPosIdx)) { _ReferenceResults.Add(patternPosIdx, null); } else { _ReferenceResults[patternPosIdx] = null; } } _AlignResults.Clear(); return SequenceAction.Ok(); } private SequenceActionResult MoveFirstTeachingPos( SequenceContext context, string id, SequenceActionResult param) { if (EquipAdapter.Instance.EquipMode.IsSimulMode()) { return SequenceAction.Ok(); } if (_AlignRecipe.ProcParams.FirstTeachingMoveEnabled) { int res = E1.GENERIC; var fov1Info = new FovInfo(_SubSysInfo, eFovId.Fov1); // 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(); } private SequenceActionResult SetReferences( SequenceContext context, string id, SequenceActionResult param) { //var refDists = _Params.RefDistParam.RefDists; var refPos = VisionRecipeManager.GetRefPoint(_FovInfo); // FOV 센터에 alignTgtDist를 더한 위치를 레퍼런스로 사용 (보정량이 작게 나옴) for (int patternPosIdx = 0; patternPosIdx < _Params.RefDistParam.RefDists.Count; patternPosIdx++) { RefDist refDist = _Params.RefDistParam.RefDists[patternPosIdx]; if (refDist == null) { _ReferenceResults[patternPosIdx] = refPos; } else { StaticPoint refDistOffset = new StaticPoint(refDist.DistX, refDist.DistY); StaticPoint newRefPos = refDistOffset + refPos.Clone() as StaticPoint; _ReferenceResults[patternPosIdx] = newRefPos; } } return SequenceAction.Ok(); } private string CheckGrab( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (_Params.GrabImage != null) { ClearMeasureGraphics(); return SEQ_ID_CHECK_ALIGN_SEQ_TYPE; // 그랩 Skip } else { return SEQ_ID_SET_GRAB_SEQ_PARAMS; // 그랩 시도 } } private void ClearMeasureGraphics() { var camDisplay = CameraDisplayManager.GetDisplay(_FovInfo); camDisplay.ClearMeasureGraphics(); } private SequenceActionResult SetGrabSeqParams( SequenceContext context, string id, SequenceActionResult param) { // FOV 패턴 2개 중 첫 패턴을 기준으로 한 장의 이미지만 찍는다. // Fork문으로 병렬 처리되므로, 조명을 바꿔가며 이미지를 2번 찍는 시나리오는 없으며, 2개 패턴이 같은 이미지를 공유한다. var procPatternInfo_1 = VisionRecipeManager.GetProcPatternInfo(_FovInfo, _AlignRecipe.AlignId.ToString(), eProcPatternId.ProcPattern1); var patternInfo_1 = GetPatternInfo(_Params.AlignInfo, _FovInfo, procPatternInfo_1); return SequenceAction.Ok( new GrabSeqParams(_FovInfo, patternInfo_1, _Params.DisplayType, _Params.SeqMode)); } private SequenceActionResult SetGrabImage( SequenceContext context, string id, SequenceActionResult param) { _Params.GrabImage = param.Param; return SequenceAction.Ok(); } #region Dry Run private string CheckDryRun( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (EquipAdapter.Instance.EquipMode.IsDryrunOrTransferMode()) { return SEQ_ID_DO_DRY_RUN_ACTION; } else { return SEQ_ID_CHECK_ALIGN_SEQ_TYPE; } } private SequenceActionResult DoDryRunAction( SequenceContext context, string id, SequenceActionResult param) { for (int patternPosIdx = 0; patternPosIdx < _Params.RefDistParam.RefDists.Count; patternPosIdx++) { var alignResult = new AlignResult() { Status = AlignStatus.DRY_RUN_OK, Delta = new AlignDelta(), DisplayType = _Params.DisplayType, AlignAlgorithm = _AlignRecipe.ProcParams.AlignAlgorithm, }; if (!_AlignResults.ContainsKey(patternPosIdx)) { _AlignResults.Add(patternPosIdx, alignResult); } } return SequenceAction.Ok(); } #endregion private string CheckAlignSeqType( SequenceContext context, string id, ICollection branches, SequenceActionResult param) { eProcFovType procFovType = _AlignRecipe.ProcParams.ProcFovType; switch (procFovType) { case eProcFovType.C1_F1_AP2_A2: return SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2; case eProcFovType.C1_F1_SPN_AN: return SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN; } return SEQ_ID_ALIGN_SEQ_TYPE_NG; } private SequenceActionResult AlignSeqTypeNG( SequenceContext context, string id, SequenceActionResult param) { LOG.FuncE("Align Seq Type NG!!"); return SequenceAction.Error(); } private SequenceActionResult SetAlignSeqParams( SequenceContext context, string id, SequenceActionResult param) { switch (id) { case SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_AP2_A2: return SequenceAction.Ok(new AlignSeqParams_C1_F1_AP2_A2( _Params.AlignInfo, _ReferenceResults, _Params.RefDistParam, _Params.GrabImage, _Params.DisplayType, _Params.SeqMode)); case SEQ_ID_SET_ALIGN_SEQ_PARAMS_C1_F1_SPN_AN: return SequenceAction.Ok(new AlignSeqParams_C1_F1_SPN_AN( _Params.AlignInfo, _ReferenceResults, _Params.RefDistParam, _Params.GrabImage, _Params.DisplayType, _Params.SeqMode)); } return SequenceAction.Error(); } private SequenceActionResult SetAlignResults( SequenceContext context, string id, SequenceActionResult param) { // Param : Dictionary _AlignResults = param.Param as Dictionary; return SequenceAction.Ok(); } private SequenceActionResult SaveCsv( SequenceContext context, string id, SequenceActionResult param) { if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) { var dataList = new List(); foreach (var itemPairs in _AlignResults) { var alignResult = itemPairs.Value; dataList.Add(AlignResultItemManager.GetAlignResultItem(_SubSysInfo, alignResult)); } _CsvManager.SaveCsv(_SubSysInfo, dataList, eSaveDataType.Align); } return SequenceAction.Ok(); } private SequenceActionResult SaveScreenShot( SequenceContext context, string id, SequenceActionResult param) { if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) { var materialInfo = context.GetValue(VisionContextKeys.CNTXT_KEY_MATERIAL_INFO); var fovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo.UnitId, _SubSysInfo.SubSysId, eFovId.Fov1); foreach (var itemPairs in _AlignResults) { var alignResult = itemPairs.Value; if (_Aligner.IsAlignStatusNG(alignResult.Status) || VisionSettingManager.VisionSetting.SaveOkSceenShotImage) { var lastFovId = context.GetValue(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), _Params.GrabImage); } } } return SequenceAction.Ok(); } private SequenceActionResult SeqComplete( SequenceContext context, string id, SequenceActionResult param) { context.PutValue(string.Format(VisionContextKeys.CNTXT_KEY_ALIGN_RESULTS, _Params.AlignInfo.GetKey()), _AlignResults); return SequenceAction.Ok(_AlignResults); } 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) { } } }