383 lines
17 KiB
C#
383 lines
17 KiB
C#
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)
|
|
{
|
|
//HW 연결오류
|
|
if (PUB.AGV.IsOpen == false)
|
|
{
|
|
PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR);
|
|
PUB.sm.SetNewStep(eSMStep.IDLE);
|
|
return;
|
|
}
|
|
|
|
//가동불가 조건 확인
|
|
if (CheckStopCondition() == false) return;
|
|
|
|
//중단기능이 동작이라면 처리하지 않는다.
|
|
if (PUB.sm.bPause)
|
|
{
|
|
System.Threading.Thread.Sleep(200);
|
|
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.alarmSoundTerm)
|
|
{
|
|
PUB.Speak(Lang.전방에물체가감지되었습니다);
|
|
LastSpeakTime = DateTime.Now;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//선로이탈감지
|
|
if (PUB.AGV.error.runerror_by_no_magent_line == true)
|
|
{
|
|
var tsSpeak = DateTime.Now - LastSpeakTime;
|
|
if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm)
|
|
{
|
|
PUB.Speak(Lang.선로를이탈했습니다);
|
|
LastSpeakTime = DateTime.Now;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//현재위치를 모르는 상태라면 이동하여 현재 위치를 찾는다
|
|
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return;
|
|
|
|
//나머지 상황체크
|
|
switch (PUB.sm.RunStep)
|
|
{
|
|
case ERunStep.GOHOME:
|
|
if (_SM_RUN_GOHOME(runStepisFirst, PUB.sm.GetRunSteptime) == true)
|
|
{
|
|
PUB.log.Add($"홈 이동이 완료되어 준비상태로 전환합니다");
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
}
|
|
break;
|
|
case ERunStep.GOTO: //목적지까지 이동하는 경우
|
|
if (_SM_RUN_GOTO(runStepisFirst, PUB.sm.GetRunSteptime) == true)
|
|
{
|
|
//목적지가 BUFFER라면 버퍼투입대기위치까지 완료했다는 시그널을 보낸다.
|
|
var target = PUB._virtualAGV.TargetNode;
|
|
PUB.log.Add($"목적지({target.RfidId}) 도착완료 타입:{target.Type}, 출발지:{PUB._virtualAGV.StartNode.RfidId}");
|
|
|
|
switch(target.StationType)
|
|
{
|
|
case AGVNavigationCore.Models.StationType.Buffer:
|
|
//현재위치가 마지막경로의 NODEID와 일치해야한다
|
|
var lastPath = PUB._virtualAGV.CurrentPath.DetailedPath.LastOrDefault();
|
|
if (lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNode.Id))
|
|
{
|
|
//버퍼진입전 노드에 도착완료했따
|
|
PUB.XBE.BufferInReady = true;
|
|
PUB.XBE.BufferReadyError = false;
|
|
}
|
|
else
|
|
{
|
|
//마지막위치가 아닌 다른 위치에 있으니 버퍼 작업을 할 수없다
|
|
PUB.log.AddAT("목적지 버퍼이동완료 했지만 마지막 노드가 아닙니다");
|
|
PUB.XBE.BufferInReady = false;
|
|
PUB.XBE.BufferReadyError = true;
|
|
}
|
|
PUB.XBE.BufferInComplete = false;
|
|
PUB.XBE.BufferOutComplete = false;
|
|
break;
|
|
}
|
|
|
|
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None;
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
}
|
|
break;
|
|
|
|
case ERunStep.MARKSTOPB: //후진방향으로 마크스탑
|
|
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.READY);
|
|
PUB.log.AddAT("충전 해제로 대기상태로 전환 합니다");
|
|
}
|
|
}
|
|
break;
|
|
case ERunStep.LOADER_OUT: //로더아웃
|
|
if (_SM_RUN_LOADER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹해제완료);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.LoaderInComplete = false;
|
|
PUB.XBE.LoaderOutComplete = true;
|
|
|
|
//대기상태로 전환
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.LOADER_IN: //로더도킹
|
|
if (_SM_RUN_LOADER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.LoaderInComplete = true;
|
|
|
|
//로더아웃으로 자동 진행하지 않음 (ACS 명령 대기)
|
|
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOn || PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOff)
|
|
{
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop; // Command consumed
|
|
}
|
|
else
|
|
{
|
|
// Legacy behavior or Goto command: Auto-exit?
|
|
// User said separation is key. Let's Stop here too or keep legacy for GOTO?
|
|
// Assuming GOTO might rely on this, but safer to STOP if we want strict separation.
|
|
// However, let's keep legacy behavior for GOTO if possible, but for PickOn/Off we STOP.
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.LOADER_OUT);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.UNLOADER_OUT: //언로더아웃
|
|
if (_SM_RUN_UNLOADER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹해제완료);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.UnloaderInComplete = false;
|
|
PUB.XBE.UnloaderOutComplete = true;
|
|
|
|
//대기상태로 전환
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.UNLOADER_IN: //언로더도킹
|
|
if (_SM_RUN_UNLOADER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.UnloaderInComplete = true;
|
|
|
|
//언로더아웃으로 자동 진행하지 않음
|
|
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOn || PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOff)
|
|
{
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
|
|
}
|
|
else
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.UNLOADER_OUT);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.CLEANER_OUT: //클리너아웃
|
|
if (_SM_RUN_CLEANER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹해제완료);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.CleanerInComplete = false;
|
|
PUB.XBE.CleanerOutComplete = true;
|
|
|
|
//대기상태로 전환
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.CLEANER_IN: //클리너도킹
|
|
if (_SM_RUN_CLEANER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.CleanerInComplete = true;
|
|
|
|
//클리너아웃으로 자동 진행하지 않음
|
|
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOn || PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOff)
|
|
{
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
|
|
}
|
|
else
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.CLEANER_OUT);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.BUFFER_OUT: //버퍼아웃
|
|
if (_SM_RUN_BUFFER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹해제완료);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.BufferInComplete = false;
|
|
PUB.XBE.BufferOutComplete = true;
|
|
|
|
//대기상태로 전환
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case ERunStep.BUFFER_IN: //버퍼도킹
|
|
if (_SM_RUN_BUFFER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
|
{
|
|
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
|
|
|
//도킹완료상태를 업데이트한다.
|
|
PUB.XBE.BufferInComplete = true;
|
|
|
|
//버퍼아웃으로 자동 진행하지 않음
|
|
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOn || PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOff)
|
|
{
|
|
PUB.sm.SetNewRunStep(ERunStep.READY);
|
|
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
|
|
}
|
|
else
|
|
{
|
|
PUB.sm.ClearRunStep();
|
|
PUB.sm.SetNewRunStep(ERunStep.BUFFER_OUT);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}//cvass
|
|
}
|