using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using Project.StateMachine; using COMM; using AR; namespace Project { public partial class fMain { DateTime LastSpeakTime = DateTime.Now; DateTime CoverControlTime = DateTime.Now; DateTime LastCommandTime = DateTime.Now; DateTime LastCommandTimeNextStop = DateTime.Now; bool runStepisFirst = false; private void _SM_RUN(Boolean isFirst, TimeSpan stepTime) { //중단기능이 동작이라면 처리하지 않는다. if (PUB.sm.bPause) { System.Threading.Thread.Sleep(200); return; } //가동불가 조건 확인 if (CheckStopCondition() == false) { PUB.sm.SetNewStep(eSMStep.IDLE); return; } //HW 연결오류 if (PUB.AGV.IsOpen == false) { PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR); PUB.sm.SetNewStep(eSMStep.IDLE); return; } //이머전시상태라면 stop 처리한다. if (PUB.AGV.error.Emergency && PUB.AGV.system1.agv_stop == true && PUB.AGV.system1.stop_by_front_detect == false) { PUB.Speak(Lang.비상정지로인해작업을중단합니다); PUB.sm.SetNewStep(eSMStep.IDLE); return; } //스텝이 변경되었다면? if (PUB.sm.RunStep != PUB.sm.RunStepNew) { runStepisFirst = true; PUB.sm.ApplyRunStep(); } else runStepisFirst = false; //처음시작이라면 시작시간을 설정한다 if (isFirst) { if (PUB.sm.RunStep == ERunStep.READY) VAR.TIME.Update(eVarTime.ReadyStart); else VAR.TIME.Update(eVarTime.RunStart); } //자동모드에서 대기상태 (추가동작없음) if (PUB.sm.RunStep == ERunStep.READY) { _SM_RUN_READY(runStepisFirst, PUB.sm.GetRunSteptime); return; } //############################################# //## 이 후에는 모든 동작루틴이 온다 //############################################# //라이더 센서에서 멈춘경우 처리 if (PUB.AGV.system1.stop_by_front_detect == true) { var tsSpeak = DateTime.Now - LastSpeakTime; if (tsSpeak.TotalSeconds >= PUB.setting.doorSoundTerm) { PUB.Speak(Lang.전방에물체가감지되었습니다); LastSpeakTime = DateTime.Now; } return; } //나머지 상황체크 switch (PUB.sm.RunStep) { case ERunStep.GOTO: //목적지까지 이동하는 경우 _SM_RUN_GOTO(runStepisFirst, PUB.sm.GetRunSteptime); break; case ERunStep.MARKSTROPB: //후진방향으로 마크스탑 case ERunStep.MARKSTOPF: //전진방향으로 마크스탑 //이동중이지 않다면 먼저 이동을 진행한다 var agvDir = PUB.sm.RunStep == ERunStep.MARKSTOPF ? arDev.Narumi.eRunOpt.Forward : arDev.Narumi.eRunOpt.Backward; PUB.AGV.AGVMoveRun(agvDir); //이동중이라면 마크스탑을 입력한다 PUB.AGV.AGVMoveStop("run-markstropb", arDev.Narumi.eStopOpt.MarkStop); //마크스탑신호를 확인한다.(최대 5초) //신호가 확인되지 않으면 오류로 정지한다 break; case ERunStep.GOCHARGE: //충전위치로 이동 if (runStepisFirst) { VAR.TIME[eVarTime.ChargeTry] = DateTime.Now; PUB.sm.ResetRunStepSeq(); PUB.log.Add("충전 명령 시작"); } else if (_SM_RUN_GOCHARGE(runStepisFirst, PUB.sm.GetRunSteptime)) { //230601 //if (PUB.Result != null && PUB.sm != null) // EEMStatus.AddEEDBSQL(PUB.sm.Step, PUB.sm.RunStep.ToString(), PUB.Result.TargetPos.ToString()); PUB.Speak(Lang.충전을시작합니다); PUB.sm.SetNewRunStep(ERunStep.CHARGECHECK); return; } break; case ERunStep.CHARGECHECK: //충전중 if (runStepisFirst) { VAR.TIME.Update(eVarTime.ChargeStart); LastCommandTime = DateTime.Now; } else if (_SM_RUN_GOCHARGECHECK(runStepisFirst, PUB.sm.GetRunSteptime)) { //충전상태가 활성화되었으므로 대기상태로 전환한다 PUB.sm.SetNewRunStep(ERunStep.READY); PUB.log.AddAT("충전상태 확인 완료로 인해 대기 합니다"); } break; case ERunStep.CHARGEOFF: if (runStepisFirst) { VAR.TIME.Update(eVarTime.ChargeEnd); LastCommandTime = DateTime.Now; } else { //충전 상태가 OFF되어야 동작하게한다 if (_SM_RUN_CHGOFF(isFirst, stepTime) == true) { //충전상태가 활성화되었으므로 대기상태로 전환한다 PUB.sm.ClearRunStep(); //충전기위치에서 OFF를 한 경우이다 if (PUB.Result.CurrentPos != ePosition.CHARGE || PUB.Result.TargetPos != ePosition.CHARGE) { PUB.Result.CurrentPos = ePosition.NONE; } else { PUB.Result.TargetPos = ePosition.QC; } PUB.Result.CurrentPosCW = "1"; PUB.sm.SetNewRunStep(ERunStep.GOHOME); PUB.log.AddAT("충전 해제로 홈으로 이동"); } } break; case ERunStep.GOUP: //상차이동 if (_SM_RUN_GOUP(runStepisFirst, PUB.sm.GetRunSteptime)) { PUB.Speak(Lang.상차작업이완료되었습니다); //230601 // if (PUB.Result != null && PUB.sm != null) // EEMStatus.AddEEDBSQL(PUB.sm.Step, PUB.sm.RunStep.ToString(), PUB.Result.TargetPos.ToString()); //QA를 제외한 경우에는 기본 QC로 이동한다 if (PUB.Result.NextPos == ePosition.QA) PUB.Result.TargetPos = ePosition.QA; else PUB.Result.TargetPos = ePosition.QC; PUB.sm.SetNewRunStep(ERunStep.GODOWN); //하차작업으로 전환 return; } break; case ERunStep.GODOWN: //하차이동 if (_SM_RUN_GODOWN(runStepisFirst, PUB.sm.GetRunSteptime)) { PUB.Speak(Lang.하차작업이완료되었습니다); VAR.TIME.Update(eVarTime.ChargeTry); PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN);// (Device.PLC.ZMotDirection.Down); //하차작업이 완료되면 커버를 내려서 바로 작업할 수 있게 한다. //230601 //if (PUB.Result != null && PUB.sm != null) // EEMStatus.AddEEDBSQL(PUB.sm.Step, PUB.sm.RunStep.ToString(), PUB.Result.TargetPos.ToString()); //하차가 완료되면 충전대기시간을 30초 남겨두고 없데이트한다 //충전이 필요할 경우 바로 될수있도록 220118 VAR.TIME[eVarTime.ChargeTry] = DateTime.Now.AddSeconds(-1 * PUB.setting.ChargeRetryTerm + 30); if (PUB.Result.CurrentPos == ePosition.QC) { PUB.Speak(Lang.대기상태로전환합니다); PUB.sm.SetNewRunStep(ERunStep.READY); } else { //홈 이동 명령처리 PUB.sm.ClearRunStep(); PUB.Result.TargetPos = ePosition.QC; PUB.sm.SetNewRunStep(ERunStep.GOHOME); PUB.Speak(Lang.홈위치로이동합니다); } return; } break; case ERunStep.GOHOME: if (runStepisFirst) { PUB.Speak(Lang.홈검색을시작합니다); } else if (_SM_RUN_GOHOME(runStepisFirst, PUB.sm.GetRunSteptime)) { //230601 // if (PUB.Result != null && PUB.sm != null) // EEMStatus.AddEEDBSQL(PUB.sm.Step, PUB.sm.RunStep.ToString(), PUB.Result.TargetPos.ToString()); PUB.Speak(Lang.홈이동완료대기상태로전환합니다); VAR.TIME.Update(eVarTime.ChargeTry); PUB.sm.SetNewRunStep(ERunStep.READY); //대기상태로 전환한다 return; } break; } } bool CheckStopCondition() { return true; } void CheckAGVMoveTo(eGoDir dir) { //계속내려간다 if (dir == eGoDir.Down) { var tsCmd = DateTime.Now - LastCommandTime; if (tsCmd.TotalMilliseconds >= 1999) { //현재 동작중인상태에서 방향이 맞지 않다면 일단 움직임을 멈춘다 if (PUB.AGV.system1.agv_run) { if (PUB.AGV.data.Direction == 'B') { PUB.log.Add($"방향이 맞지 않아 정지 합니다({dir})"); PUB.AGV.AGVMoveStop("CheckAGVMoveTo"); } else if (PUB.AGV.data.Speed == 'S') { PUB.log.Add($"마크정지를 해제하기 위해 장비를 멈춥니다"); } } else { //움직이지 않으므로 전진하도록 한다 PUB.log.Add($"AGV 기동 방향(DOWN):{dir}"); PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); } LastCommandTime = DateTime.Now; } } else { var tsCmd = DateTime.Now - LastCommandTime; if (tsCmd.TotalMilliseconds >= 1999) { if (PUB.AGV.system1.agv_run) { if (PUB.AGV.data.Direction == 'F') { PUB.log.Add($"방향이 맞지 않아 정지 합니다({dir})"); PUB.AGV.AGVMoveStop("CheckAGVMoveTo"); } else if (PUB.AGV.data.Speed == 'S') { PUB.log.Add($"마크정지를 해제하기 위해 장비를 멈춥니다"); } } else { PUB.log.Add($"AGV 기동 방향(UP):{dir}"); PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); } LastCommandTime = DateTime.Now; } } } void CheckAGVStopbyMARK(string sender) { //계속내려간다 var tsCmd = DateTime.Now - LastCommandTime; if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false || tsCmd.TotalMilliseconds >= 1500) { PUB.AGV.AGVMoveStop("CheckAGVStopbyMARK", arDev.Narumi.eStopOpt.MarkStop); LastCommandTime = DateTime.Now; PUB.log.Add($"[{sender}] MARK신호에 멈춤 설정"); } } Boolean UpdateMotionPositionForMark(string sender) { //이머전시상태에서는 처리하지 않는다. if (VAR.BOOL[eVarBool.EMERGENCY]) return false; //DOWN 작업 // if (goDIR == eGoDir.Down) { //1. 현재위치 > 대상위치 if (PUB.Result.CurrentPos > PUB.Result.TargetPos) { //계속내려간다 if (PUB.setting.AGV_Direction_FVI_Backward) CheckAGVMoveTo(eGoDir.Down); else CheckAGVMoveTo(eGoDir.Up); } //2. 현재위치 < 대상위치 else if (PUB.Result.CurrentPos < PUB.Result.TargetPos) { //올라가야한다 if (PUB.setting.AGV_Direction_FVI_Backward) CheckAGVMoveTo(eGoDir.Up); else CheckAGVMoveTo(eGoDir.Down); } //3. 현재위치 = 대상위치 else { //현재위치가 확정되었는가? var actpos = ctlPos1.GetPositionActive(PUB.Result.CurrentPos); if (actpos == false && PUB.AGV.system1.agv_stop == true) { //위치확정이되지 않았다면 AGV멈춤시에 기동하게 한다. var lastcom = DateTime.Now - LastCommandTime; if (lastcom.TotalSeconds > 3) { if (PUB.Result.CurrentPosCW == "1") { if (PUB.setting.AGV_Direction_FVI_Backward) PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); else PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); } else { if (PUB.setting.AGV_Direction_FVI_Backward) PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); else PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); } LastCommandTime = DateTime.Now; PUB.logagv.Add($"AGV가 멈춰있다 동작을 재개 합니다"); } } else { //마크센서가 들어와잇고, 위치가 act 되어있다면 해당 위치에 있는 것이다 if (PUB.AGV.error.Emergency == false && PUB.AGV.system1.agv_stop && PUB.AGV.signal.mark_sensor && actpos && PUB.Result.CurrentPos == PUB.Result.TargetPos) { //PUB.AGV.AGVMoveStop(); return true; } if (PUB.AGV.system1.agv_stop == true && PUB.AGV.system1.agv_run == false) { PUB.log.Add($"멈춰있으므로 이동을 시작 합니다"); if (PUB.Result.CurrentPosCW == "1") { if (PUB.setting.AGV_Direction_FVI_Backward) PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); else PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); } else { if (PUB.setting.AGV_Direction_FVI_Backward) PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward); else PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward); } } //AGV는 아래로 FVI방향으로 내려가고 있다 if (VAR.BOOL[eVarBool.AGVDIR_UP] == false) { if (PUB.Result.CurrentPosCW == "0") { //장비가 마크센서에의해 멈췃다면 완료이다 if (PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) { PUB.AGV.AGVMoveStop("UPdateMotionPositionForMark"); return true; } else CheckAGVStopbyMARK(sender); } else if (PUB.Result.CurrentPosCW == "1") { //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 CheckAGVMoveTo(eGoDir.Up); } else { PUB.Result.CurrentPosCW = "1"; CheckAGVMoveTo(eGoDir.Up); } } //AGV는 Qc방향으로 올라가고 있다 else { if (PUB.Result.CurrentPosCW == "1") { //네려가는 방향에서 내려가는 위치가 인식되었다면 마크에서 멈춰야 한다 if (PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) { PUB.AGV.AGVMoveStop("UPdateMotionPositionForMark"); return true; } else CheckAGVStopbyMARK(sender); } else if (PUB.Result.CurrentPosCW == "0") { //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 CheckAGVMoveTo(eGoDir.Down); } else { PUB.Result.CurrentPosCW = "0"; CheckAGVMoveTo(eGoDir.Down); } } } } } //UP 작업 //else //{ // //1. 현재위치 > 대상위치 // if (PUB.Result.CurrentPos > PUB.Result.TargetPos) // { // //계속내려간다 // CheckAGVMoveTo(eGoDir.Down); // } // //2. 현재위치 < 대상위치 // else if (PUB.Result.CurrentPos < PUB.Result.TargetPos) // { // //올라가야한다 // CheckAGVMoveTo(eGoDir.Up); // } // //3. 현재위치 = 대상위치 // else // { // //AGV는 위로가고 있다 // if (VAR.BOOL[eVarBool.AGVDIR_UP] == true) // { // if (PUB.Result.CurrentPosCW == "0") // { // //장비가 마크센서에의해 멈췃다면 완료이다 // if (PUB.AGV.system1.agv_stop && PUB.AGV.system1.stop_by_front_detect == false && PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) // { // return true; // } // else CheckAGVStopbyMARK(); // } // else if (PUB.Result.CurrentPosCW == "1") // { // //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 // CheckAGVMoveTo(eGoDir.Down); // } // } // //AGV는 내려가고 있다 // else if (VAR.BOOL[eVarBool.AGVDIR_UP] == false) // { // if (PUB.Result.CurrentPosCW == "1") // { // //네려가는 방향에서 내려가는 위치가 인식되었다면 마크에서 멈춰야 한다 // if (PUB.AGV.system1.agv_stop && PUB.AGV.system1.stop_by_front_detect == false && PUB.AGV.error.Emergency == false && PUB.AGV.signal.mark_sensor) // { // return true; // } // else CheckAGVStopbyMARK(); // } // else if (PUB.Result.CurrentPosCW == "0") // { // //내려가는 작업이고 AGV는 올라가고 있는데 RFID는 위졲이 감지되었다면 아래로 내려가야한다 // CheckAGVMoveTo(eGoDir.Up); // } // } // } //} return false; } Boolean UpdateMotionPositionForCharger(string sender) { if (VAR.BOOL[eVarBool.AGVDIR_UP] == false)// PUB.flag.get(EFlag.FLAG_DIR_BW) == true) { //충전기 검색은 항상 뒤로 검색한다 var tsCmd = DateTime.Now - tm_gocharge_command; if (tsCmd.TotalMilliseconds >= 1999 && PUB.AGV.error.Emergency == false && PUB.AGV.system1.agv_run == false) { //PUB.PLC.Move(Device.PLC.Rundirection.Backward, "UpdateMotionPosition(" + sender + ")"); PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// tm_gocharge_command = DateTime.Now; } } else { //CCW (역방향 ) //if (Pub.Result.RFIDPos < ePosition.CHARGE || Pub.Result.RFIDPos > ePosition.QC) //{ // //정상적이라면 RFID값은 QC + 혹은 QC - 에 있어야 하므로 항상 차저보다 높이 있다 // //그렇지 않다면 초기화해서 QC검색부터 다시 실행하게 한다 // //여기는 비정상 위치 값이다. // Pub.sm.SetStepSeq(1); //} //else //{ //현재위치가 충전위치이고, 움직이지 않았다면 완료된 경우라 할수 있따 if (PUB.Result.CurrentPos == ePosition.CHARGE && PUB.AGV.signal.mark_sensor == true) { PUB.log.AddI("충전위치 검색 완료"); return true; } else { //이동중이지 않다면 항상 이동을 해줘야한다 var tsCmd = DateTime.Now - LastCommandTime; if (tsCmd.TotalMilliseconds >= 1999 && PUB.AGV.error.Emergency == false && PUB.AGV.system1.agv_run == false) { //PUB.PLC.Move(Device.PLC.Rundirection.Backward, "UpdateMotionPosition #1(" + sender + ")"); PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);// LastCommandTime = DateTime.Now; } } //} } return false; } }//cvass }