using Aurora.Api; using AuroraLaser.Coherent; using AuroraLaserScanner; using Hermes; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Numerics; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using WeldingCommon.Alarm; using WeldingCommon.Settings; namespace WeldingCommon.Sequences { class SeqMarkGrid { static readonly Logger Log = new Logger("SeqMarkGrid"); const string SEQ_ENTER = "[SeqMarkGrid] SEQ_ENTER"; // inputParam 으로 받자. const string SEQ_CHECK_INIT_CONDITION = "[SeqMarkGrid] Check Init Condition"; // Check Init Condition const string SEQ_DOWNLOAD_MARKING_GRID_LIST = "[SeqMarkGrid] Download Marking GridList"; const string SEQ_EXCUTE_SCANNER = "[SeqMarkGrid] Excute Scanner"; const string SEQ_WAIT_SCANNER_TASK_COMPLETE = "[SeqMarkGrid] Wait Scanner Task Complete"; const string SEQ_SAVE_RESULT_DATA = "[SeqMarkGrid] Save Result Data"; const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqMarkGrid] Write Completion PLC Bit"; const string SEQ_COMPLETE = "[SeqMarkGrid] SEQ_COMPLETE"; // 완료 static class ContextKey { public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqMarkGrid"; public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqMarkGrid"; } private SeqMarkGrid_InitParam _InitParam; private Scanner _Scanner; private SystemParameter _SystemParameter; private eListNo _MarkingGridScannerListNo; private double _JumpSpeed; private List _MarkingPositionList_MM; // MM 은 밀리미터 단위 인듯 //private DateTime _WeldingStartTime; public SequenceBuilder Builder() { var sb = new SequenceBuilder(1000, true); ////var sb = new SequenceBuilder(1000, false); // With log sb.AddAction(SEQ_ENTER, Sequence_Enter); sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기 sb.AddAction(SEQ_DOWNLOAD_MARKING_GRID_LIST, DownloadMarkingGridList); //분기 sb.AddAction(SEQ_EXCUTE_SCANNER, ExcuteScanner); sb.AddAction(SEQ_WAIT_SCANNER_TASK_COMPLETE, WaitScannerTaskComplete); sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함. sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write sb.AddAction(SEQ_COMPLETE, Complete); sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_DOWNLOAD_MARKING_GRID_LIST] > sb[SEQ_EXCUTE_SCANNER] > sb[SEQ_WAIT_SCANNER_TASK_COMPLETE] > sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]); sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final); sb.OnStopped(OnStopped); sb.OnForceError(OnForceError); //sb.Draw("SeqMarkGrid.pdf"); return sb; } private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param) { Log.I("SeqMarkGrid Start"); _InitParam = param.Param as SeqMarkGrid_InitParam; _SystemParameter = context.GetSetting(CommonSettingIds.SystemParameter); InitDev(context); if (!CheckDeviceReady(context)) { //Check Device AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_MarkGrid_DeviceNotReady); Log.E("The devices are not active."); return null; } if (InitSequenceVariable(context) == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_MarkGrid_InitVariableError); return null; } return SequenceAction.Ok(); } private bool InitSequenceVariable(SequenceContext context) { // MarkGrid 는 Scanner의 List2 를 사용한다. _MarkingGridScannerListNo = eListNo.LIST2; _JumpSpeed = _Scanner.Config.JumpSpeed; // Initialize MasterPos _MarkingPositionList_MM = new List(); float posX = 0; float posY = 0; for (int column = 0; column < _InitParam.ColumnCount; column++) { posX = _InitParam.UnitLength * ((column % _InitParam.ColumnCount) - (_InitParam.ColumnCount - 1) / 2f); for (int row = 0; row < _InitParam.RowCount; row++) { posY = _InitParam.UnitLength * ((row % _InitParam.RowCount) - (_InitParam.RowCount - 1) / 2f); _MarkingPositionList_MM.Add(new PointF(posX, posY)); } } return true; } private void InitDev(SequenceContext context) { //Device Init _Scanner = context.GetLaserScanner(); } private bool CheckDeviceReady(SequenceContext context) { List deviceListToCheck = new List() { CommonDeviceIds.Scanner }; bool isAllDeviceActivated = true; foreach (string item in deviceListToCheck) { if (!context.Devices[item].IsActivated) { isAllDeviceActivated = isAllDeviceActivated && false; } } return isAllDeviceActivated; } private bool CheckCondition() { if (CheckCondition_Interlock()) { if (InitializeDeviceStatus()) { return true; } } return false; } private bool CheckCondition_Interlock() { // PLC, Data, IO 등 Interlock checking return true; } private bool InitializeDeviceStatus() { // Device 의 status 를 맞추자. MarkGrid 는 Scanner 를 설정 한다. 초기 설정 해야 하는 값으로 //LaserCorrectionTable 사용 (1 소스 Initialize() 함수에 있던 내용) _Scanner.SelectCorrectionTable(2); // 1.스캐너 리스트 동작구성 _Scanner.SetStartList(_MarkingGridScannerListNo); // 2. SetLaserTiming은 Modulation 사용하는 레이저 장비에서 셋팅될 수 있도록 InitParam으로 받아오자.(ex. Coherent) if (_InitParam.IsModulation) { _Scanner.SetLaserTiming(_InitParam.Frequnecy, _InitParam.PulseDulation * 1000, _InitParam.PulseDulation * 1000); Log.I(string.Format($"[SetLaserTiming] LaserFrequency : {_InitParam.Frequnecy}, LaserPulseDuration : {_InitParam.PulseDulation}")); } _Scanner.SetLaesrDelay(0, 0); //3.DA(레이저 파워값) 설정 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, (float)_InitParam.MarkPower, eFunctionType.LIST); ////4.점프 및 마크 속도 설정 _Scanner.SetJumpSpeed(_JumpSpeed); _Scanner.SetMarkSpeed(_InitParam.MarkSpeed); return true; } private string CheckInitCondition(SequenceContext context, string id, ICollection branches, SequenceActionResult param) { if (!CheckCondition()) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_MarkGrid_CheckInitCondition); Log.E("Condition is not in state to start sequence."); context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false); return SEQ_COMPLETE; } var startTime = DateTime.Now; context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime); Log.D("DoCrossLaserShot Sequence CheckInitCondition"); return SEQ_DOWNLOAD_MARKING_GRID_LIST; } private SequenceActionResult DownloadMarkingGridList(SequenceContext context, string id, SequenceActionResult param) { Log.I("Start List up Marking Grid."); for (int i = 0; i < _MarkingPositionList_MM.Count; i++) { //Won : KS프로젝트에서 MarkGrid 진행 시 Jump구간 발진 되는 부분 확인, 하기 소스코드 테스트 후 적용 필요 //십자마킹 가로 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); _Scanner.JumpAbs(_MarkingPositionList_MM[i].X - _InitParam.MarkLength * 0.5, _MarkingPositionList_MM[i].Y, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, (float)_InitParam.MarkPower, eFunctionType.LIST); _Scanner.MarkAbs(_MarkingPositionList_MM[i].X + _InitParam.MarkLength * 0.5, _MarkingPositionList_MM[i].Y); //십자마킹 세로 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.LIST); _Scanner.JumpAbs(_MarkingPositionList_MM[i].X, _MarkingPositionList_MM[i].Y - _InitParam.MarkLength * 0.5, eFunctionType.LIST); _Scanner.WriteDA((uint)eAnalogPortOut.DA1, (float)_InitParam.MarkPower, eFunctionType.LIST); _Scanner.MarkAbs(_MarkingPositionList_MM[i].X, _MarkingPositionList_MM[i].Y + _InitParam.MarkLength * 0.5); } _Scanner.SetEndList(); return SequenceAction.Ok(); } private SequenceActionResult ExcuteScanner(SequenceContext context, string id, SequenceActionResult param) { Log.I("Marking Start"); //_WeldingStartTime = DateTime.Now; _Scanner.ExecuteList(_MarkingGridScannerListNo); return SequenceAction.Ok(); } private SequenceActionResult WaitScannerTaskComplete(SequenceContext context, string id, SequenceActionResult param) { Log.FuncI(MethodBase.GetCurrentMethod().Name); var res = context.RetryUntilSuccess(CheckScannerTaskComplete, _SystemParameter.WeldLinesTaskTimeOut * 1000); if (res == E2.TIMEOUT) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_MarkGrid_TimeOverExcuteList); // Scanner complete 되는 것이 timeout 까지 종료되지 않으면, excute time over 로 sequence 종료 Log.FuncE("Time Over excuteList"); return null; } return SequenceAction.Ok(); } private bool CheckScannerTaskComplete() { if (_Scanner.GetBusyStatus()) { return false; } else { return true; } } private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param) { // 결과 Data 를 업데이트 함. format 유지, MarkGrid 없음 context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true); return SequenceAction.Ok(); } private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param) { // 완료 비트 write 하는 Node 추가 필요. format 유지, MarkGrid 없음 Log.D("MarkGrid Sequence WriteCompletionPLCBit"); return SequenceAction.Ok(); } private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param) { RestoreDeviceStatus(); Log.I("MarkGrid Complete"); context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult); SeqMarkGrid_OutParam result = new SeqMarkGrid_OutParam() { Success = seqResult }; if (seqResult == false) { AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_MarkGrid_ResultFailed); } Log.D("MarkGrid Sequence Complete"); return SequenceAction.Ok(result); } private bool RestoreDeviceStatus() { //vision correctiontable로 원복 _Scanner.SelectCorrectionTable(1); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); return true; } private void OnForceError(SequenceContext arg1, string arg2) { //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Log.E("MarkGrid Sequence is stopped"); } private void OnStopped(SequenceContext obj) { //List 실행 종료 _Scanner.StopExecution(); //Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨 _Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND); //Scanner 원점 복귀 _Scanner.JumpAbs(0, 0, eFunctionType.COMMAND); Log.E("MarkGrid Sequence is stopped"); } } public class SeqMarkGrid_InitParam : InitParam { //public bool IsLaserCalibration { get; set; } public int ColumnCount { get; set; } public int RowCount { get; set; } public float UnitLength { get; set; } // 단위 mm public double MarkPower { get; set; } // 단위 % public double MarkSpeed { get; set; } // 단위 mm/s public double MarkLength { get; set; } // 단위 mm public bool IsModulation { get; set; } public uint Frequnecy { get; set; } // 단위 Hz public uint PulseDulation { get; set; } //단위 msec } public class SeqMarkGrid_OutParam : OutParam { // 레이저 쏘기만 하기 때문에 필요 없음. } }