using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Text; using arCtl; using Project.StateMachine; using COMM; using AR; using AGVNavigationCore.Models; namespace Project { public partial class fMain { private void AGV_Message(object sender, arDev.Narumi.MessageEventArgs e) { if (e.MsgType == arDev.arRS232.MessageType.Normal) PUB.logagv.AddE(e.Message); else if (e.MsgType == arDev.arRS232.MessageType.Normal) PUB.logagv.Add(e.Message); else if (e.MsgType == arDev.arRS232.MessageType.Recv) { if (e.Message.Substring(1).StartsWith("STS") == false) PUB.logagv.Add("AGV-RX", e.Message); } else if (e.MsgType == arDev.arRS232.MessageType.Send) PUB.logagv.Add("AGV-TX", e.Message); else { PUB.logagv.Add(e.MsgType.ToString(), e.Message); } } bool _charging = false; private void AGV_DataReceive(object sender, arDev.Narumi.DataEventArgs e) { try { //데이터 파싱 switch (e.DataType) { case arDev.Narumi.DataType.STS: { //마크센서 확인 var agv_err = PUB.AGV.error.Value; var agv_emg = PUB.AGV.error.Emergency; var agv_chg = PUB.AGV.system1.Battery_charging; var agv_stp = PUB.AGV.system1.agv_stop; var agv_run = PUB.AGV.system1.agv_run; var agv_mrk = PUB.AGV.signal.mark_sensor; //if (chg_run && PUB.AGV.system1.agv_run) PUB.Speak("이동을 시작 합니다"); VAR.BOOL[eVarBool.AGVDIR_BACK] = PUB.AGV.data.Direction == 'B'; if (VAR.BOOL[eVarBool.AGV_ERROR] != (agv_err > 0)) { VAR.BOOL[eVarBool.AGV_ERROR] = (agv_err > 0); PUB.logagv.Add($"new AGV_ERROR ({PUB.AGV.error.Value})"); } if (VAR.BOOL[eVarBool.EMERGENCY] != agv_emg) { VAR.BOOL[eVarBool.EMERGENCY] = agv_emg; PUB.logagv.Add($"new EMERGENCY ({VAR.BOOL[eVarBool.EMERGENCY]})"); } //차징상태변경 if (_charging != agv_chg) { if (agv_chg) { VAR.TIME[eVarTime.ChargeStart] = DateTime.Now; PUB.logagv.Add($"충전시작:{VAR.TIME[eVarTime.ChargeStart]}"); } _charging = agv_chg; } //배터리충전상태 if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] != agv_chg) { PUB.log.Add($"충전상태전환 {agv_chg}"); VAR.BOOL[eVarBool.FLAG_CHARGEONA] = agv_chg; } //자동충전해제시 곧바로 수동 충전되는 경우가 있어 자동 상태를 BMS에 넣는다 230118 PUB.BMS.AutoCharge = agv_chg; if (PUB.AGV.error.Charger_pos_error != VAR.BOOL[eVarBool.CHG_POSERR]) { if (PUB.AGV.error.Charger_pos_error) { PUB.Speak(Lang.충전기위치오류); } VAR.BOOL[eVarBool.CHG_POSERR] = PUB.AGV.error.Charger_pos_error; } //나르미가 멈췄다면 다음 마크 이동 기능이 OFF 된다 if (agv_stp) { if (VAR.BOOL[eVarBool.NEXTSTOP_MARK]) { VAR.BOOL[eVarBool.NEXTSTOP_MARK] = false; PUB.logagv.Add($"NEXTSTOP_MARK 변경({VAR.BOOL[eVarBool.NEXTSTOP_MARK]})"); } } //마크센서 상태가 변경이 되었다면 if (VAR.BOOL[eVarBool.MARK_SENSOR] != PUB.AGV.signal.mark_sensor) { PUB.logagv.Add($"MARK_SENSOR 변경({PUB.AGV.signal.mark_sensor})"); VAR.BOOL[eVarBool.MARK_SENSOR] = PUB.AGV.signal.mark_sensor; //AGV가 멈췄고 마크센서가 ON되었다면 마지막 RFID 위치가 확정된경우이다 if (agv_stp && VAR.BOOL[eVarBool.MARK_SENSOR]) { PUB.log.Add("마크스탑이 확인되어 최종위치를 PASS 처리 합니다"); var curnode = PUB._virtualAGV.SetCurrentNodeMarkStop(); if (curnode == true) { PUB.log.Add($"마크스탑으로 해당노드의 이동을 확정합니다"); } else PUB.log.AddAT($"마크스탑이 확인되었으나 현재 노드가없어 PASS를 설정하지 못함"); } } if (VAR.BOOL[eVarBool.MARK_SENSOROFF] != VAR.BOOL[eVarBool.MARK_SENSOR]) { VAR.BOOL[eVarBool.MARK_SENSOROFF] = !VAR.BOOL[eVarBool.MARK_SENSOR]; VAR.TIME[eVarTime.MarkSensorOff] = DateTime.Now; PUB.log.Add($"MARK_SENSOROFF 변경({VAR.BOOL[eVarBool.MARK_SENSOROFF]})"); } } break; case arDev.Narumi.DataType.TAG: { //자동 실행 중이다. PUB.log.Add($"AGV 태그수신 : {PUB.AGV.data.TagNo}"); PUB.Result.LastTAG = PUB.AGV.data.TagNo.ToString(); //POT/NOT 보면 일단 바로 멈추게한다 if (PUB.Result.CurrentPos == ePosition.POT || PUB.Result.CurrentPos == ePosition.NOT) { var logEMsg = $"Stop by [POT/NOT]"; PUB.AGV.AGVMoveStop(logEMsg); PUB.log.AddE(logEMsg); } //virtual agv setting var CurrentNode = PUB._mapNodes.FirstOrDefault(t => t.RfidId.Equals(PUB.Result.LastTAG, StringComparison.OrdinalIgnoreCase)); if (CurrentNode == null) { //없는 노드는 자동으로 추가한다 var newNodeId = $"AUTO_{PUB.Result.LastTAG}"; var newNode = new MapNode { NodeId = newNodeId, RfidId = PUB.Result.LastTAG, Name = $"자동추가_{PUB.Result.LastTAG}", Type = NodeType.Normal, Position = new Point(100, 100), // 기본 위치 IsActive = true, DisplayColor = Color.Orange, // 자동 추가된 노드는 오렌지색으로 표시 CreatedDate = DateTime.Now, ModifiedDate = DateTime.Now }; // 맵 노드 리스트에 추가 PUB._mapNodes.Add(newNode); // 캔버스에 노드 반영 (재설정) PUB._mapCanvas.Nodes = PUB._mapNodes; // 로그 기록 PUB.log.AddI($"RFID:{PUB.Result.LastTAG} 노드를 자동 추가했습니다 (NodeId: {newNodeId})"); // CurrentNode에 새로 생성한 노드 할당 CurrentNode = newNode; } else { //모터방향 확인해서 UI와 AGV클래스에 적용한다 var MotDireciton = PUB.AGV.data.Direction == 'B' ? AGVNavigationCore.Models.AgvDirection.Backward : AGVNavigationCore.Models.AgvDirection.Forward; PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, CurrentNode, MotDireciton); PUB._virtualAGV.SetPosition(CurrentNode, MotDireciton); } //태그를 읽었다면 상태를 바로 전송한다 PUB.XBE.SendStatus(); } break; case arDev.Narumi.DataType.ACK: PUB.logagv.Add($"AGV_[ACK]Receive : {PUB.AGV.ACKData}"); break; default: PUB.logagv.Add($"AGV_DataReceive : {e.DataType}"); break; } //이 후 상황을 예측한다 if (PUB._mapCanvas != null) { var nextAction = PUB._virtualAGV.Predict(); var message = $"[다음 행동 예측]\n\n" + $"모터: {nextAction.Motor}\n" + $"마그넷: {nextAction.Magnet}\n" + $"속도: {nextAction.Speed}\n" + $"이유: {nextAction.Message}\n\n" + $"---\n" + $"현재 상태: {PUB._virtualAGV.CurrentState}\n" + $"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" + $"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" + $"현재 노드: {PUB._virtualAGV.CurrentNodeId ?? "없음"}"; PUB._mapCanvas.PredictMessage = message; } } catch (Exception ex) { Console.WriteLine($"[AGV_DataReceive] {ex.Message}"); } } } }