2026-01-26 18:56:53 +09:00

498 lines
20 KiB
C#

/*
* Copyright (c) 2025 LG Electronics Inc.
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
*/
using Aurora.Api;
using VisionCommon;
using VisionAligner;
using VisionSequence.Camera;
using System.Collections.Generic;
using Hermes;
using VisionSequence.Pattern;
namespace VisionSequence.Aligner {
/// <summary>
/// N개 패턴, N번 얼라인 시퀀스 파라미터
/// </summary>
public class AlignProcSeqParams_PN_AN : SeqParamsBase {
/// <summary>얼라인 키 정보</summary>
public AlignInfo AlignInfo { get; set; }
/// <summary>얼라인 레퍼런스 정보</summary>
public RefDistParam RefDistParam { get; set; }
/// <summary>플라잉 위치 인덱스 (Optional)</summary>
public object GrabImage { get; set; }
/// <summary>메인 화면 타입</summary>
public eDisplayType DisplayType { get; set; }
/// <summary>
/// N개 패턴, N번 얼라인 시퀀스 파라미터를 얻어온다.
/// </summary>
/// <param name="alignInfo">얼라인 키 정보</param>
/// <param name="refDistParam">센터로부터 각 패턴의 정위치까지 떨어진 거리 파라미터</param>
/// <param name="grabImage">그랩 이미지 (Optional)</param>
/// <param name="displayType">메인 화면 타입</param>
/// <param name="seqMode">시퀀스 모드</param>
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;
}
}
/// <summary>
/// CAM 1대 / FOV 1개 / 패턴 N개 / 1 Point Align N개 / MeasurePattern to (Center + Ref Dist Offset)
/// </summary>
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<int, StaticPoint> _ReferenceResults = new Dictionary<int, StaticPoint>(); // _Params.AlignTgtDists로 재구성한 레퍼런스
private Dictionary<int, AlignResult> _AlignResults = new Dictionary<int, AlignResult>();
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
/// <summary>
/// 생성자
/// </summary>
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) {
GrabFindSeqUtil.Clear(_SubSysInfo);
AlignResultItemManager.Clear(_SubSysInfo);
PatternResultItemManager.Clear(_SubSysInfo);
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<string> 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<string> 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<string> 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<int, AlignResult>
_AlignResults = param.Param as Dictionary<int, AlignResult>;
return SequenceAction.Ok();
}
private SequenceActionResult SaveCsv(
SequenceContext context,
string id,
SequenceActionResult param) {
if (EquipAdapter.Instance.EquipMode.IsNotDryrunAndTransferMode()) {
var dataList = new List<AlignResultItem>();
foreach (var itemPairs in _AlignResults) {
var alignResult = itemPairs.Value;
dataList.Add(AlignResultItemManager.GetAlignResultItem(_Params.AlignInfo, alignResult));
}
_CsvManager.SaveCsv(_Params.AlignInfo, dataList, 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);
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<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), _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) {
}
}
}