파일정리
This commit is contained in:
145
HMI/Project/StateMachine/AGVPosition.cs
Normal file
145
HMI/Project/StateMachine/AGVPosition.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Project.StateMachine
|
||||
{
|
||||
public class AGVPosition
|
||||
{
|
||||
public enum PositionType
|
||||
{
|
||||
None,
|
||||
Tops1,
|
||||
Sstron1,
|
||||
Sstron2,
|
||||
Path
|
||||
}
|
||||
|
||||
public class Position
|
||||
{
|
||||
public int RFID { get; set; }
|
||||
public PositionType Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Direction { get; set; }
|
||||
public List<int> ConnectedPositions { get; set; }
|
||||
|
||||
public Position(int rfid, PositionType type, string name, string direction)
|
||||
{
|
||||
RFID = rfid;
|
||||
Type = type;
|
||||
Name = name;
|
||||
Direction = direction;
|
||||
ConnectedPositions = new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<int, Position> positionMap;
|
||||
private static AGVPosition instance;
|
||||
|
||||
private AGVPosition()
|
||||
{
|
||||
positionMap = new Dictionary<int, Position>();
|
||||
InitializePositions();
|
||||
}
|
||||
|
||||
public static AGVPosition Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new AGVPosition();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializePositions()
|
||||
{
|
||||
// Tops 1 관련 위치
|
||||
AddPosition(100, PositionType.Tops1, "Tops 1", "0");
|
||||
AddPosition(101, PositionType.Path, "Tops1-Sstron1 Path 1", "0");
|
||||
AddPosition(102, PositionType.Path, "Tops1-Sstron1 Path 2", "0");
|
||||
|
||||
// Sstron 1 관련 위치
|
||||
AddPosition(200, PositionType.Sstron1, "Sstron 1", "0");
|
||||
AddPosition(201, PositionType.Path, "Sstron1-Sstron2 Path 1", "0");
|
||||
AddPosition(202, PositionType.Path, "Sstron1-Sstron2 Path 2", "0");
|
||||
|
||||
// Sstron 2 관련 위치
|
||||
AddPosition(300, PositionType.Sstron2, "Sstron 2", "0");
|
||||
|
||||
// 경로 연결 설정
|
||||
ConnectPositions(100, 101);
|
||||
ConnectPositions(101, 102);
|
||||
ConnectPositions(102, 200);
|
||||
ConnectPositions(200, 201);
|
||||
ConnectPositions(201, 202);
|
||||
ConnectPositions(202, 300);
|
||||
}
|
||||
|
||||
private void AddPosition(int rfid, PositionType type, string name, string direction)
|
||||
{
|
||||
positionMap[rfid] = new Position(rfid, type, name, direction);
|
||||
}
|
||||
|
||||
private void ConnectPositions(int pos1, int pos2)
|
||||
{
|
||||
if (positionMap.ContainsKey(pos1) && positionMap.ContainsKey(pos2))
|
||||
{
|
||||
positionMap[pos1].ConnectedPositions.Add(pos2);
|
||||
positionMap[pos2].ConnectedPositions.Add(pos1);
|
||||
}
|
||||
}
|
||||
|
||||
public Position GetPosition(int rfid)
|
||||
{
|
||||
if (positionMap.ContainsKey(rfid))
|
||||
{
|
||||
return positionMap[rfid];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<int> FindPath(int startRfid, int endRfid)
|
||||
{
|
||||
if (!positionMap.ContainsKey(startRfid) || !positionMap.ContainsKey(endRfid))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var visited = new HashSet<int>();
|
||||
var path = new List<int>();
|
||||
if (FindPathDFS(startRfid, endRfid, visited, path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool FindPathDFS(int current, int end, HashSet<int> visited, List<int> path)
|
||||
{
|
||||
if (current == end)
|
||||
{
|
||||
path.Add(current);
|
||||
return true;
|
||||
}
|
||||
|
||||
visited.Add(current);
|
||||
path.Add(current);
|
||||
|
||||
foreach (var next in positionMap[current].ConnectedPositions)
|
||||
{
|
||||
if (!visited.Contains(next))
|
||||
{
|
||||
if (FindPathDFS(next, end, visited, path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path.RemoveAt(path.Count - 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
HMI/Project/StateMachine/AGVProtocolHandler.cs
Normal file
107
HMI/Project/StateMachine/AGVProtocolHandler.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Project.StateMachine
|
||||
{
|
||||
public class AGVProtocolHandler
|
||||
{
|
||||
private static AGVProtocolHandler instance;
|
||||
private AGVStateManager stateManager;
|
||||
|
||||
private AGVProtocolHandler()
|
||||
{
|
||||
stateManager = AGVStateManager.Instance;
|
||||
}
|
||||
|
||||
public static AGVProtocolHandler Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new AGVProtocolHandler();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ProcessProtocol(string protocol)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 프로토콜 형식: COMMAND:DESTINATION
|
||||
var parts = protocol.Split(':');
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var command = parts[0].ToUpper();
|
||||
var destination = parts[1].ToUpper();
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "MOVE_TO":
|
||||
return HandleMoveToCommand(destination);
|
||||
case "PICKUP":
|
||||
return HandlePickupCommand(destination);
|
||||
case "DROPOFF":
|
||||
return HandleDropoffCommand(destination);
|
||||
case "EMERGENCY_STOP":
|
||||
return HandleEmergencyStopCommand();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleMoveToCommand(string destination)
|
||||
{
|
||||
switch (destination)
|
||||
{
|
||||
case "T1":
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.MoveToTops1);
|
||||
case "S1":
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.MoveToSstron1);
|
||||
case "S2":
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.MoveToSstron2);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandlePickupCommand(string destination)
|
||||
{
|
||||
if (destination != "T1")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.PickupCart);
|
||||
}
|
||||
|
||||
private bool HandleDropoffCommand(string destination)
|
||||
{
|
||||
if (destination != "S1" && destination != "S2")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.DropoffCart);
|
||||
}
|
||||
|
||||
private bool HandleEmergencyStopCommand()
|
||||
{
|
||||
return stateManager.ProcessCommand(AGVStateManager.AGVCommand.EmergencyStop);
|
||||
}
|
||||
|
||||
public string GetCurrentStatus()
|
||||
{
|
||||
var state = stateManager.CurrentState;
|
||||
return $"Current State: {state}";
|
||||
}
|
||||
}
|
||||
}
|
||||
159
HMI/Project/StateMachine/AGVStateManager.cs
Normal file
159
HMI/Project/StateMachine/AGVStateManager.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Project.StateMachine
|
||||
{
|
||||
public class AGVStateManager
|
||||
{
|
||||
public enum AGVState
|
||||
{
|
||||
Idle,
|
||||
Moving,
|
||||
Loading,
|
||||
Unloading,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum AGVCommand
|
||||
{
|
||||
MoveToTops1,
|
||||
MoveToSstron1,
|
||||
MoveToSstron2,
|
||||
PickupCart,
|
||||
DropoffCart,
|
||||
EmergencyStop
|
||||
}
|
||||
|
||||
private AGVState currentState;
|
||||
private static AGVStateManager instance;
|
||||
private AGVPosition positionManager;
|
||||
|
||||
private AGVStateManager()
|
||||
{
|
||||
currentState = AGVState.Idle;
|
||||
positionManager = AGVPosition.Instance;
|
||||
}
|
||||
|
||||
public static AGVStateManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new AGVStateManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public AGVState CurrentState
|
||||
{
|
||||
get { return currentState; }
|
||||
}
|
||||
|
||||
public bool ProcessCommand(AGVCommand command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case AGVCommand.MoveToTops1:
|
||||
return HandleMoveCommand(100); // Tops 1 RFID
|
||||
case AGVCommand.MoveToSstron1:
|
||||
return HandleMoveCommand(200); // Sstron 1 RFID
|
||||
case AGVCommand.MoveToSstron2:
|
||||
return HandleMoveCommand(300); // Sstron 2 RFID
|
||||
case AGVCommand.PickupCart:
|
||||
return HandlePickupCommand();
|
||||
case AGVCommand.DropoffCart:
|
||||
return HandleDropoffCommand();
|
||||
case AGVCommand.EmergencyStop:
|
||||
return HandleEmergencyStop();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleMoveCommand(int targetRfid)
|
||||
{
|
||||
if (currentState != AGVState.Idle && currentState != AGVState.Moving)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현재 위치에서 목표 위치까지의 경로를 찾음
|
||||
var currentRfid = GetCurrentRfid(); // 실제 구현에서는 현재 RFID 값을 가져와야 함
|
||||
var path = positionManager.FindPath(currentRfid, targetRfid);
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentState = AGVState.Moving;
|
||||
// 경로를 따라 이동하는 로직 구현
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandlePickupCommand()
|
||||
{
|
||||
if (currentState != AGVState.Moving)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현재 위치가 Tops 1인지 확인
|
||||
var currentRfid = GetCurrentRfid();
|
||||
var position = positionManager.GetPosition(currentRfid);
|
||||
|
||||
if (position == null || position.Type != AGVPosition.PositionType.Tops1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentState = AGVState.Loading;
|
||||
// 카트 적재 로직 구현
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleDropoffCommand()
|
||||
{
|
||||
if (currentState != AGVState.Moving)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현재 위치가 Sstron 1 또는 Sstron 2인지 확인
|
||||
var currentRfid = GetCurrentRfid();
|
||||
var position = positionManager.GetPosition(currentRfid);
|
||||
|
||||
if (position == null ||
|
||||
(position.Type != AGVPosition.PositionType.Sstron1 &&
|
||||
position.Type != AGVPosition.PositionType.Sstron2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentState = AGVState.Unloading;
|
||||
// 카트 하역 로직 구현
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleEmergencyStop()
|
||||
{
|
||||
currentState = AGVState.Error;
|
||||
// 비상 정지 로직 구현
|
||||
return true;
|
||||
}
|
||||
|
||||
private int GetCurrentRfid()
|
||||
{
|
||||
// 실제 구현에서는 AGV의 현재 RFID 값을 반환해야 함
|
||||
// 예시로 100(Tops 1)을 반환
|
||||
return 100;
|
||||
}
|
||||
|
||||
public void UpdateState(AGVState newState)
|
||||
{
|
||||
currentState = newState;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
HMI/Project/StateMachine/DisplayTextHandler.cs
Normal file
29
HMI/Project/StateMachine/DisplayTextHandler.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
delegate void UpdateControlTextHandler(Control ctl, string value);
|
||||
void UpdateControlText(Control ctl, string value)
|
||||
{
|
||||
if (ctl.InvokeRequired)
|
||||
{
|
||||
ctl.BeginInvoke(new UpdateControlTextHandler(UpdateControlText), new object[] { ctl, value });
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.Text = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
296
HMI/Project/StateMachine/Step/_SM_RUN.cs
Normal file
296
HMI/Project/StateMachine/Step/_SM_RUN.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
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);
|
||||
VAR.I32[eVarInt32.PathValidationError] = 0;
|
||||
}
|
||||
|
||||
//자동모드에서 대기상태 (추가동작없음)
|
||||
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)
|
||||
{
|
||||
PUB.Result.result_message = "현재 위치 확인 중";
|
||||
PUB.Result.result_progressmax = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//나머지 상황체크
|
||||
switch (PUB.sm.RunStep)
|
||||
{
|
||||
case ERunStep.GOHOME:
|
||||
if (_SM_RUN_GOTO_HOME(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}");
|
||||
|
||||
PUB.XBE.StepMC = Device.eDocStep.NotSet;
|
||||
|
||||
switch (target.StationType)
|
||||
{
|
||||
case AGVNavigationCore.Models.StationType.Buffer:
|
||||
var lastPath = PUB._virtualAGV.CurrentPath.DetailedPath.LastOrDefault();
|
||||
if (lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNode.Id))
|
||||
{
|
||||
//버퍼진입전 노드에 도착완료했따
|
||||
PUB.XBE.StepMC = Device.eDocStep.ReadyForEnter;
|
||||
}
|
||||
else
|
||||
{
|
||||
//마지막위치가 아닌 다른 위치에 있으니 버퍼 작업을 할 수없다
|
||||
PUB.XBE.StepMC = Device.eDocStep.NotSet;
|
||||
PUB.log.AddE($"목적지가 버퍼이나 노드가 불일치 한다 오류사항");
|
||||
PUB._mapCanvas.SetAlertMessage("목적지가 버퍼이나 노드 불일치 오류");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
}
|
||||
break;
|
||||
case AGVNavigationCore.Models.StationType.Charger1:
|
||||
case AGVNavigationCore.Models.StationType.Charger2:
|
||||
|
||||
break;
|
||||
|
||||
case AGVNavigationCore.Models.StationType.Loader:
|
||||
PUB.XBE.StepMC = Device.eDocStep.ReadyForEnter;
|
||||
break;
|
||||
|
||||
case AGVNavigationCore.Models.StationType.Clearner:
|
||||
PUB.XBE.StepMC = Device.eDocStep.ReadyForEnter;
|
||||
break;
|
||||
|
||||
case AGVNavigationCore.Models.StationType.UnLoader:
|
||||
PUB.XBE.StepMC = Device.eDocStep.ReadyForEnter;
|
||||
break;
|
||||
|
||||
default:
|
||||
PUB.log.Add($"정의되지 않은 스테이션 입니다({target.StationType}) ");
|
||||
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_CHARGE_GO(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
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_CHARGE_CHECK(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_CHARGE_GOFF(isFirst, stepTime) == true)
|
||||
{
|
||||
//충전상태가 활성화되었으므로 대기상태로 전환한다
|
||||
PUB.sm.ClearRunStep();
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
PUB.log.AddAT("충전 해제로 대기상태로 전환 합니다");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.CLEANER_IN: //클리너도킹
|
||||
case ERunStep.UNLOADER_IN: //언로더도킹
|
||||
case ERunStep.LOADER_IN: //로더도킹
|
||||
if (_SM_RUN_ENTER(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.StepMC = Device.eDocStep.EnterComplete;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ERunStep.CLEANER_OUT: //클리너아웃
|
||||
case ERunStep.UNLOADER_OUT: //언로더아웃
|
||||
case ERunStep.LOADER_OUT: //로더아웃
|
||||
if (_SM_RUN_EXIT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹해제완료);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.StepMC = Device.eDocStep.ExitComplete;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.BUFFER_OUT: //버퍼아웃
|
||||
if (_SM_RUN_BUFFER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹해제완료);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.StepMC = Device.eDocStep.ExitComplete;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
else PUB.XBE.StepMC = Device.eDocStep.ExitIng;
|
||||
break;
|
||||
|
||||
case ERunStep.BUFFER_IN: //버퍼도킹
|
||||
if (_SM_RUN_BUFFER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.StepMC = Device.eDocStep.EnterComplete;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
else PUB.XBE.StepMC = Device.eDocStep.EnterIng;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}//cvass
|
||||
}
|
||||
286
HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs
Normal file
286
HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_IN.cs
Normal file
@@ -0,0 +1,286 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Net.Security;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
public Boolean _SM_RUN_BUFFER_IN(bool isFirst, TimeSpan seqtime)
|
||||
{
|
||||
var funcname = "_SM_RUN_BUFFER_IN";
|
||||
var idx = 1;
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, seqtime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
/*
|
||||
* 버퍼IN시퀀스
|
||||
* 1. 회전이 진행되지 않았다면 회전을 진행한다.
|
||||
* 2. LIFT DOWN
|
||||
* 3. 후진-저속-마크다운 실행
|
||||
*/
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add($"[{funcname}] 버퍼진입시작({PUB.NextWorkCmd}) Turn:{PUB._virtualAGV.Turn}");
|
||||
PUB.Speak(Lang.진입을작합니다);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//모션 전후진 제어
|
||||
if (PUB._virtualAGV.Turn != AGVNavigationCore.Models.AGVTurn.L90)
|
||||
{
|
||||
//동작중이면 동작을 멈춘다
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastStopCommandTime);
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
VAR.TIME.Update(eVarTime.LastStopCommandTime);
|
||||
}
|
||||
}
|
||||
else PUB.sm.UpdateRunStepSeq(); //agv가 멈춰있으므로 턴을 진행해야 한다
|
||||
}
|
||||
else PUB.sm.UpdateRunStepSeq(); //이미완료된상태이므로 다음으로 진행한다.
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이미 턴이 되어있는지 확인한다 (재진입 시 중복 실행 방지)
|
||||
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.L90)
|
||||
{
|
||||
PUB.log.Add($"[{funcname}] 이미 Left Turn 완료 상태입니다. 턴 명령을 건너뜁니다.");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else
|
||||
{
|
||||
//하드웨어 상태 확인
|
||||
var turnState = PUB.AGV.TurnInformation?.State ?? arDev.eNarumiTurn.None;
|
||||
|
||||
if (turnState == arDev.eNarumiTurn.Left || turnState == arDev.eNarumiTurn.LeftIng)
|
||||
{
|
||||
//이미 좌회전 중이거나 완료된 하드웨어 상태
|
||||
PUB.log.Add($"[{funcname}] 하드웨어 좌회전 상태 확인됨({turnState}). 명령을 건너뜁니다.");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else if (turnState == arDev.eNarumiTurn.Right || turnState == arDev.eNarumiTurn.RightIng)
|
||||
{
|
||||
//비정상 상태 (우회전 중?)
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}] 턴 방향 불일치(Current:{turnState}). 우회전 상태에서 좌회전을 시도할 수 없습니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//정상 (None) -> 턴 명령 실행
|
||||
PUB.AGV.AGVMoveLeft180Turn();
|
||||
PUB.log.Add("AGV Left Turn");
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
}
|
||||
PUB._mapCanvas.SetAlertMessage($"턴 진행 중");
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이미 완료된 상태라면 대기 과정을 건너뛴다.
|
||||
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.L90)
|
||||
{
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
//왼쪽턴이 완료되지 않은경우
|
||||
if (PUB.AGV.TurnInformation.State != arDev.eNarumiTurn.Left)
|
||||
{
|
||||
//움직임 확인을 위해 3초간은 검증을 유예한다
|
||||
if (PUB.AGV.TurnInformation.Runtime.TotalSeconds < 3) return false;
|
||||
|
||||
//턴 이동 상태가 확인되어야 한다.
|
||||
var overtime = 30;
|
||||
if (PUB.AGV.TurnInformation.Runtime.TotalSeconds > overtime)
|
||||
{
|
||||
//30초동안 AGV까 움직이지 않았다면 오류 처리한다.
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}] {overtime}초이내 턴 감지 안됨");
|
||||
return false;
|
||||
}
|
||||
else PUB._mapCanvas.SetAlertMessage($"턴 진행 중({PUB.AGV.TurnInformation.Runtime.TotalSeconds:N0}/{overtime})");
|
||||
return false;
|
||||
}
|
||||
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.L90; //턴완료
|
||||
PUB.log.Add($"[{funcname}] Turn(left) 완료");
|
||||
PUB.sm.UpdateRunStepSeq(); //이미완료된상태이므로 다음으로 진행한다.
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//버퍼에들어갈때에는 가져다 놓을때도 가지러 갈때에도 리프트는 내려서 들어간다
|
||||
var liftCmd = arDev.Narumi.LiftCommand.DN;
|
||||
PUB.AGV.LiftControl(liftCmd);
|
||||
PUB.log.Add($"[{funcname}] 리프트를 내립니다");
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트 센서 확인
|
||||
if (PUB.AGV.signal1.lift_down == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 20)
|
||||
{
|
||||
PUB.log.AddAT($"[{funcname}] 리프트가 내려가지 않아 1회 재시도 합니다");
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN);
|
||||
//재시도를 했으니 다음으로 진행하게한다
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB._mapCanvas.SetAlertMessage($"리프트 하강 확인 중({seqtime.TotalSeconds:N0}/20)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트 센서 확인
|
||||
if (PUB.AGV.signal1.lift_down == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 20)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, $"[{funcname}] 리프트가 내려가지 않습니다");
|
||||
}
|
||||
else PUB._mapCanvas.SetAlertMessage($"리프트 하강 확인 중({seqtime.TotalSeconds:N0}/20)");
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//저속이동 (후진 진입)
|
||||
|
||||
// [Smart Restart] 재시작 시 안전 검사
|
||||
// 이미 턴을 완료했고(L90), 현재 마크 센서가 감지된다면(ON),
|
||||
// 이미 목적지(Mark 2)에 도착한 것으로 간주하여 후진을 생략한다.
|
||||
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.L90 && PUB.AGV.signal1.mark_sensor == true)
|
||||
{
|
||||
PUB.log.Add($"[{funcname}] 이미 목적지 도착 확인됨(Turn:L90, Sensor:ON). 후진 이동을 생략합니다.");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
|
||||
//명령이 실패되었다면 재시도를 한다
|
||||
if (ret != arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
if (ret >= arDev.eNarumiCommandResult.Error)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//후진이동을한다
|
||||
PUB._mapCanvas.SetAlertMessage($"도킹을 위해 후진 이동 시작");
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이동확인을 한다.
|
||||
if(PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if(seqtime.TotalSeconds > 3)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑으로 이동
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB._mapCanvas.SetAlertMessage($"도킹을 위해 후진 이동 시작");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (PUB.AGV.data.Speed != 'S')
|
||||
{
|
||||
if (seqtime.TotalSeconds > 3)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_STOP_FAIL);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
if (seqtime.TotalSeconds < 2) return false;
|
||||
PUB.log.Add($"[{funcname}] 작업({PUB.NextWorkCmd}) 완료. 대기 상태로 전환 (퇴출 명령 대기)");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add($"[{funcname}] 버퍼 진입 및 작업 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 작업을 마치고 설비 안에 멈춰있는 상태.
|
||||
// ACS가 이 상태를 확인하고 NextWorkCmd로 퇴출(Out) 명령을 보내야 함.
|
||||
PUB.AddEEDB($"[{funcname}] 버퍼작업완료({PUB.Result.TargetPos})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
251
HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs
Normal file
251
HMI/Project/StateMachine/Step/_SM_RUN_BUFFER_OUT.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
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
|
||||
{
|
||||
public Boolean _SM_RUN_BUFFER_OUT(bool isFirst, TimeSpan seqtime)
|
||||
{
|
||||
var funcname = "_SM_RUN_BUFFER_IN";
|
||||
var idx = 1;
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, seqtime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
/*
|
||||
* 버퍼 OUT 시퀀스
|
||||
* 1-1. PickOn 라면 리프트를 Up 한다
|
||||
* 1-2. PickOff 라면 리프트를 Down 한다
|
||||
* 2.전진-저속-마크다운
|
||||
* 3.Turn-Right-180
|
||||
*/
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add($"[{funcname}] 버퍼진출시작({PUB.NextWorkCmd}) Turn:{PUB._virtualAGV.Turn}");
|
||||
PUB.Speak(Lang.진출을시작합니다);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
arDev.Narumi.LiftCommand lift = PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit ? arDev.Narumi.LiftCommand.UP : arDev.Narumi.LiftCommand.DN;
|
||||
PUB.log.Add($"[{funcname}] 리프트제어 {lift}");
|
||||
PUB.AGV.LiftControl(lift);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트 센서 확인
|
||||
var checksensor = PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit ? PUB.AGV.signal1.lift_up : PUB.AGV.signal1.lift_down;
|
||||
if (checksensor == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 20)
|
||||
{
|
||||
PUB.log.AddAT($"[{funcname}] 리프트가 완료되지 않아 1회 재시도 합니다");
|
||||
arDev.Narumi.LiftCommand lift = PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit ? arDev.Narumi.LiftCommand.UP : arDev.Narumi.LiftCommand.DN;
|
||||
PUB.AGV.LiftControl(lift);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트 센서 확인
|
||||
var checksensor = PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit ? PUB.AGV.signal1.lift_up : PUB.AGV.signal1.lift_down;
|
||||
if (checksensor == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 20)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, $"[{funcname}] 리프트가 동작하지 않습니다");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//빈 상태로 아웃해야한다.
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
//명령이 실패되었다면 재시도를 한다
|
||||
if (ret != arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
if (ret >= arDev.eNarumiCommandResult.Error)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV구동을 확인하고 마크스탑을 설정한다.
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 3)
|
||||
{
|
||||
//구동이확인되지 않으면 오류처리를 한다.
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//마크스탑설정
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (PUB.AGV.data.Speed != 'S')
|
||||
{
|
||||
if (seqtime.TotalSeconds > 3)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 15)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_STOP_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//우측으로 180도 턴
|
||||
//이미 턴이 되어있는지 확인한다 (재진입 시 중복 실행 방지)
|
||||
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.R90)
|
||||
{
|
||||
PUB.log.Add($"[{funcname}] 이미 Right Turn 완료 상태입니다. 턴 명령을 건너뜁니다.");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else
|
||||
{
|
||||
//하드웨어 상태 확인
|
||||
var turnState = PUB.AGV.TurnInformation?.State ?? arDev.eNarumiTurn.None;
|
||||
|
||||
if (turnState == arDev.eNarumiTurn.Right || turnState == arDev.eNarumiTurn.RightIng)
|
||||
{
|
||||
//이미 우회전 중이거나 완료된 하드웨어 상태
|
||||
PUB.log.Add($"[{funcname}] 하드웨어 우회전 상태 확인됨({turnState}). 명령을 건너뜁니다.");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else if (turnState == arDev.eNarumiTurn.Left || turnState == arDev.eNarumiTurn.LeftIng)
|
||||
{
|
||||
//비정상 상태 (좌회전 중?)
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}] 턴 방향 불일치(Current:{turnState}). 좌회전 상태에서 우회전을 시도할 수 없습니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//정상 (None) -> 턴 명령 실행
|
||||
PUB.AGV.AGVMoveRight180Turn();
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이동확인
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 3)
|
||||
{
|
||||
//만약 이미 완료된 상태라서 건너뛰었다면 run이 안될 수 있다.
|
||||
//하지만 위에서 건너뜀 -> UpdateRunStepSeq -> 바로 여기로 옴.
|
||||
//건너뛴 경우(Turn == R90), Run 확인을 할 필요가 없으므로...
|
||||
//로직 보완: 턴 상태가 이미 완료라면 이동확인도 스킵해야 함?
|
||||
//아니면 위 단계에서 완료 상태면 '다음 다음' 단계로 점프?
|
||||
//간단하게: Turn이 R90이면 그냥 통과시킴.
|
||||
|
||||
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.R90)
|
||||
{
|
||||
//이미 완료된 상태이므로 이동 확인 패스
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//멈춤확인
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
if (seqtime.TotalSeconds > 25)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//턴 완료 상태 업데이트
|
||||
if (PUB._virtualAGV.Turn != AGVNavigationCore.Models.AGVTurn.R90)
|
||||
{
|
||||
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.R90;
|
||||
PUB.log.Add($"[{funcname}] Turn State Updated to R90");
|
||||
}
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("BufferOut Complete");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.AddEEDB($"bufferout 완료({PUB.Result.TargetPos})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_CHECK.cs
Normal file
59
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_CHECK.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using COMM;
|
||||
using AR;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
public Boolean _SM_RUN_CHARGE_CHECK(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
//충전상태체크를 확인합니다
|
||||
//10초안에 충전 플래그가 활성화되지 않으면 QC상태로 이동한다
|
||||
if (PUB.AGV.system1.Battery_charging == false || VAR.BOOL[eVarBool.FLAG_CHARGEONA] == false)
|
||||
{
|
||||
if (PUB.AGV.error.Charger_pos_error)
|
||||
{
|
||||
PUB.Speak(Lang.충전기위치오류로작업을취소합니다, true);
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CHARGEOFF);
|
||||
PUB.sm.SetNewStep(eSMStep.RUN);
|
||||
}
|
||||
else if (PUB.AGV.error.Charger_run_error)
|
||||
{
|
||||
PUB.Speak(Lang.충전기위치오류로작업을취소합니다, true);
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CHARGEOFF);
|
||||
PUB.sm.SetNewStep(eSMStep.RUN);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tsCmd = DateTime.Now - LastCommandTime;
|
||||
if (tsCmd.TotalSeconds >= 30)
|
||||
{
|
||||
PUB.log.AddE( Lang.충전기작동확인이오버되어홈으로이동조치합니다);
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CHARGEOFF);
|
||||
PUB.sm.SetNewStep(eSMStep.RUN);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.Result.result_message = string.Format("충전기 활성화 수신 확인 중({0:N1}/{1})", tsCmd.TotalSeconds, 30);
|
||||
PUB.Result.result_progressmax = 15;
|
||||
PUB.Result.result_progressvalue = tsCmd.TotalSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_GO.cs
Normal file
128
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_GO.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
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 tm_gocharge_command = DateTime.Now;
|
||||
public Boolean _SM_RUN_CHARGE_GO(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var funcname = "GOCHARGE";
|
||||
if (runStepisFirst)
|
||||
{
|
||||
//홈을 찾도록 항상 위치를 지워버리자
|
||||
PUB.Result.CurrentPos = ePosition.NONE;
|
||||
}
|
||||
|
||||
//HW 연결오류
|
||||
if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
//이미 충전중이라면 바로 완료 처리한다 (사용자 요청)
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true || PUB.AGV.system1.Battery_charging == true ||
|
||||
VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.ALREADY_CHARGE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, stepTime) == false)
|
||||
return false;
|
||||
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다 200409
|
||||
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 false;
|
||||
}
|
||||
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
var targetnode = PUB.FindByRFID(PUB.setting.NodeMAP_RFID_Charger);
|
||||
if (targetnode == null)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.NOTSET_CHARGEPOINT);
|
||||
return false;
|
||||
}
|
||||
|
||||
//현재위치가 충전기위치이고 마크센서가 감지되었다면 충전기위치로 인지하고
|
||||
//그렇지 못하면 충전위치가 아니라는 오류를 발생한다
|
||||
var curnode = PUB._virtualAGV.CurrentNode;
|
||||
if (PUB.AGV.signal1.mark_sensor == false || curnode.Id != targetnode.Id)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.NO_CHARGEPOINT, $"충전기위치가 아니므로 충전을 시작할 수 없습니다(현재위치:{curnode.RfidId})");
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//충전시작 명령을 전송한다
|
||||
PUB.log.Add($"충전:충전명령전송");
|
||||
PUB.Speak(Lang.충전시작명령을전송합니다);
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, true);
|
||||
VAR.BOOL[eVarBool.WAIT_CHARGEACK] = true;
|
||||
LastCommandTime = DateTime.Now;
|
||||
VAR.BYTE[eVarByte.CHARGE_CMDCNT] = 0;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
//충전시작명령의 ACK를 체크합니다
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//충전시작 명령을 전송한다
|
||||
if (PUB.AGV.ACKData.Equals("CBT"))
|
||||
{
|
||||
PUB.log.Add($"충전명령 회신 확인");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - LastCommandTime;
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
if (VAR.BYTE[eVarByte.CHARGE_CMDCNT] > 5)
|
||||
{
|
||||
PUB.counter.CountChargeE += 1;
|
||||
PUB.counter.Save();
|
||||
VAR.BYTE[eVarByte.CHARGE_CMDCNT] = 0;
|
||||
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.CHARGE_RETRY_OVER);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.logagv.Add($"충전시작명령 재전송");
|
||||
VAR.BYTE.Add(eVarByte.CHARGE_CMDCNT, 1);
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, true);
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_GOFF.cs
Normal file
78
HMI/Project/StateMachine/Step/_SM_RUN_CHARGE_GOFF.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 충전시퀀스를 모두 해제하고 본래위치로 이동한다.
|
||||
/// </summary>
|
||||
/// <param name="isFirst"></param>
|
||||
/// <param name="stepTime"></param>
|
||||
/// <returns></returns>
|
||||
public Boolean _SM_RUN_CHARGE_GOFF(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
|
||||
//충전중인지 확인한다.
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true || PUB.AGV.system1.Battery_charging == true)
|
||||
{
|
||||
if (isFirst)
|
||||
{
|
||||
VAR.TIME.Update(eVarTime.ChargeEnd);
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA])
|
||||
{
|
||||
PUB.Speak(Lang.충전을해제합니다);
|
||||
}
|
||||
}
|
||||
|
||||
//AGV는 충전을 해제한 상태이다
|
||||
if (PUB.AGV.system1.Battery_charging == false)
|
||||
{
|
||||
//너무빨리 처리되지 않도록 5초후에 완료 처리를 한다
|
||||
var ts1 = VAR.TIME.RUN(eVarTime.ChargeEnd);
|
||||
var ts2 = VAR.TIME.RUN(eVarTime.SendChargeOff);
|
||||
if (ts1.TotalSeconds >= 5 && ts2.TotalSeconds > 5) VAR.BOOL[eVarBool.FLAG_CHARGEONA] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//OFF전송이 처음이라면 시간 설정
|
||||
if (VAR.TIME.IsSet(eVarTime.SendChargeOff)==false)
|
||||
VAR.TIME[eVarTime.SendChargeOff] = DateTime.Now.AddSeconds(-10);
|
||||
|
||||
var tsChgOff = VAR.TIME.RUN(eVarTime.SendChargeOff);
|
||||
if (tsChgOff.TotalSeconds >= 3)
|
||||
{
|
||||
PUB.log.Add("충전 해제 전송");
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
VAR.TIME.Update(eVarTime.SendChargeOff);
|
||||
}
|
||||
|
||||
|
||||
// 1분 타임아웃 체크
|
||||
if (stepTime.TotalMinutes >= 1)
|
||||
{
|
||||
PUB.XBE.ErrorMessage = $"충전해제가 실패되었습니다(1분)";
|
||||
PUB.log.AddE(PUB.XBE.ErrorMessage);
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//중전이 해제된 상태이다
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
209
HMI/Project/StateMachine/Step/_SM_RUN_ENTER.cs
Normal file
209
HMI/Project/StateMachine/Step/_SM_RUN_ENTER.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// 장비로 진입한다. -
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_ENTER(bool isFirst, TimeSpan seqTime)
|
||||
{
|
||||
var idx = 1;
|
||||
var funcname = PUB.sm.RunStep.ToString();
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, seqTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("IN작업-시작");
|
||||
PUB.Speak("작업을 시작합니다");
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크센서가 감지된상태여야 완전한위치로 가정한다
|
||||
if(PUB.AGV.signal1.mark_sensor == false)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_SENSOR_FAIL, $"[{funcname}] 마크센서가 감지되지 않습니다");
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//작업상태에 따라서 카트감지여부를 확인한ㄷ.
|
||||
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnEnter)
|
||||
{
|
||||
//가지러가야하는 경우이므로 카트가 없어야한다.
|
||||
if (PUB.AGV.signal2.cart_detect1 || PUB.AGV.signal2.cart_detect2)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.CART_EXIST, $"[{funcname}] 카트가 존재하여 진입을 할 수 없습니다");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOffEnter)
|
||||
{
|
||||
//가져다 놓아야하므로 카트가 존재해야 한다
|
||||
if (PUB.AGV.signal2.cart_detect1 == false || PUB.AGV.signal2.cart_detect2 == false)
|
||||
{
|
||||
var errmsg = $"[{funcname}] 카트감지센서가 인식되지 않았습니다";
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.CART_EXIST, errmsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var errmsg = $"[{funcname}] 알수없는 작업형태입니다({PUB.NextWorkCmd})";
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.UnknownCommand, errmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//pick off/on 상관없이 리프트는 내려서 이동한다
|
||||
var liftCmd = arDev.Narumi.LiftCommand.DN;
|
||||
PUB.AGV.LiftControl(liftCmd);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트 센서 확인
|
||||
if ((PUB.AGV.signal1.lift_down == true && PUB.AGV.signal1.lift_up == false) == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
var errmsg = $"[{funcname}] 리프트다운이 확인되지 않습니다";
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, errmsg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.log.Add("리프트 동작 확인 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//저속이동 (후진 진입)
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
//명령이 실패되었다면 재시도를 한다
|
||||
if (ret != arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
if (ret >= arDev.eNarumiCommandResult.Error)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV구동을 확인하고 마크스탑을 설정한다.
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if (seqTime.TotalMilliseconds > 1000)
|
||||
{
|
||||
//구동이확인되지 않으면 오류처리를 한다.
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//마크스탑설정
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (PUB.AGV.data.Speed != 'S')
|
||||
{
|
||||
if (seqTime.TotalMilliseconds > 3000)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
if (seqTime.TotalSeconds > 10)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_STOP_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크센서입력을 확인한다.
|
||||
if (PUB.AGV.signal1.mark_sensor == false)
|
||||
{
|
||||
if (seqTime.TotalSeconds > 5)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_SENSOR_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add("진입 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs
Normal file
177
HMI/Project/StateMachine/Step/_SM_RUN_EXIT.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// 장비엣 빠젼나온다.
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_EXIT(bool isFirst, TimeSpan seqTime)
|
||||
{
|
||||
var idx = 1;
|
||||
var funcname = PUB.sm.RunStep.ToString();
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, seqTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("OUT작업-시작");
|
||||
PUB.Speak("작업을 시작합니다");
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//작업형태에 따라서. 리프트를 제어한다.
|
||||
var liftCmd = arDev.Narumi.LiftCommand.DN;
|
||||
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit) liftCmd = arDev.Narumi.LiftCommand.UP;
|
||||
|
||||
PUB.AGV.LiftControl(liftCmd);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
var liftCmd = arDev.Narumi.LiftCommand.DN;
|
||||
if (PUB.NextWorkCmd == ENIGProtocol.AGVCommandHE.PickOnExit) liftCmd = arDev.Narumi.LiftCommand.UP;
|
||||
|
||||
//리프트 센서 확인
|
||||
var liftdnok = (PUB.AGV.signal1.lift_down == true && PUB.AGV.signal1.lift_up == false);
|
||||
var liiftupok = (PUB.AGV.signal1.lift_up == true && PUB.AGV.signal1.lift_down == false);
|
||||
|
||||
if (liftCmd == arDev.Narumi.LiftCommand.DN && liftdnok)
|
||||
{
|
||||
//정상조건
|
||||
}
|
||||
else if (liftCmd == arDev.Narumi.LiftCommand.UP && liftdnok)
|
||||
{
|
||||
//정상조건
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.LIFT_ERROR, $"[{funcname}] 리프트({liftCmd})이 확인되지 않습니다");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.log.Add("리프트 동작 확인 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//빈 상태로 아웃해야한다.
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
//명령이 실패되었다면 재시도를 한다
|
||||
if (ret != arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
if (ret >= arDev.eNarumiCommandResult.Error)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV구동을 확인하고 마크스탑을 설정한다.
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if (seqTime.TotalMilliseconds > 1000)
|
||||
{
|
||||
//구동이확인되지 않으면 오류처리를 한다.
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//마크스탑설정
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (PUB.AGV.data.Speed != 'S')
|
||||
{
|
||||
if (seqTime.TotalMilliseconds > 3000)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
if (seqTime.TotalSeconds > 10)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_STOP_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크센서입력을 확인한다.
|
||||
if (PUB.AGV.signal1.mark_sensor == false)
|
||||
{
|
||||
if (seqTime.TotalSeconds > 5)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_SENSOR_FAIL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add("진출 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
HMI/Project/StateMachine/Step/_SM_RUN_GOTO.cs
Normal file
79
HMI/Project/StateMachine/Step/_SM_RUN_GOTO.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
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
|
||||
{
|
||||
byte GotoTurnStep = 0;
|
||||
DateTime GotoTurnSetTime = DateTime.Now;
|
||||
public Boolean _SM_RUN_GOTO(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
///명령어 재전송 간격(기본 2초)
|
||||
var CommandInterval = 2;
|
||||
var funcName = "_SM_RUN_GOTO";
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, stepTime) == false)
|
||||
return false;
|
||||
|
||||
//최초시작이라면 시간변수 초기화
|
||||
if (isFirst)
|
||||
{
|
||||
PUB.log.Add($"[>>] _SM_RUN_GOTO");
|
||||
VAR.TIME.Update(eVarTime.CheckGotoTargetSet);
|
||||
}
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다 200409
|
||||
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 false;
|
||||
}
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
if(PUB._virtualAGV.TargetNode == null)
|
||||
{
|
||||
PUB.log.Add($"대상노드가 없어 이동을할 수 없습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//모션 전후진 제어
|
||||
if (UpdateMotionPositionForMark(funcName))
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcName);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//QC까지 모두 완료되었다.(완전히 정차할때까지 기다린다)
|
||||
PUB.Speak(Lang.이동완료, true);
|
||||
PUB.AddEEDB($"이동완료({PUB._virtualAGV.TargetNode.ID2})");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
84
HMI/Project/StateMachine/Step/_SM_RUN_GOTO_HOME.cs
Normal file
84
HMI/Project/StateMachine/Step/_SM_RUN_GOTO_HOME.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
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
|
||||
{
|
||||
public Boolean _SM_RUN_GOTO_HOME(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var funcName = "_SM_RUN_GOHOME";
|
||||
if (runStepisFirst)
|
||||
{
|
||||
VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;//);
|
||||
}
|
||||
|
||||
//HW 연결오류
|
||||
if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHARGE_GOFF(isFirst, stepTime) == false)
|
||||
return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다 200409
|
||||
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 false;
|
||||
}
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.Speak(Lang.홈으로이동합니다);
|
||||
|
||||
var homenode = PUB.FindByRFID(PUB.setting.NodeMAP_RFID_Home);
|
||||
if (homenode == null)
|
||||
{
|
||||
PUB.log.Add($"홈위치의 노드맵핑(환경설정)이 없습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
PUB._virtualAGV.TargetNode = homenode;
|
||||
PUB.AddEEDB($"홈검색시작({homenode.RfidId})");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//모션 전후진 제어
|
||||
if (UpdateMotionPositionForMark(funcName))
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcName);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//QC까지 모두 완료되었다.(완전히 정차할때까지 기다린다)
|
||||
PUB.Speak(Lang.이동완료, true);
|
||||
PUB.AddEEDB($"이동완료({PUB.Result.TargetPos})");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
HMI/Project/StateMachine/Step/_SM_RUN_INIT.cs
Normal file
120
HMI/Project/StateMachine/Step/_SM_RUN_INIT.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 웨이퍼를 집기 위해 지정된 위치로 이동을 합니다.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool _SM_RUN_INIT(Boolean firstRun, TimeSpan RunTime)
|
||||
{
|
||||
//result message
|
||||
int progress = 0;
|
||||
var ProgressMax = 13;
|
||||
|
||||
//setting socket
|
||||
UpdateProgressStatus(++progress, ProgressMax, "소켓 초기화"); System.Threading.Thread.Sleep(5);
|
||||
if (PUB.sock_debug.Listen(PUB.setting.listenPort))
|
||||
PUB.log.AddI("Socket Listen : " + PUB.setting.listenPort);
|
||||
else
|
||||
PUB.log.AddE("Socket Listen : " + PUB.sock_debug.errorMessage);
|
||||
|
||||
|
||||
//UpdateProgressStatus(++progress, ProgressMax, "PLC 확인"); System.Threading.Thread.Sleep(5);
|
||||
//if (PUB.setting.Port_PLC != "")
|
||||
//{
|
||||
// if (PUB.PLC.Init(PUB.setting.Port_PLC, PUB.setting.Baud_PLC))
|
||||
// {
|
||||
// //VAR.BOOL[eVarBool.FLAG_SETUP] = true;
|
||||
// PUB.log.Add("Entering Setup Mode (Main)");
|
||||
// }
|
||||
// else PUB.log.AddE("PLC Init error : " + PUB.PLC.GetErrorMessage());
|
||||
//}
|
||||
|
||||
//UpdateProgressStatus("PLC #2 확인", ++progress, ProgressMax); System.Threading.Thread.Sleep(5);
|
||||
//if (Pub.setting.Port_PLC2 != "")
|
||||
//{
|
||||
// if (Pub.plcS.Init(Pub.setting.Port_PLC2, Pub.setting.Baud_plc2))
|
||||
// {
|
||||
// Pub.plcS.SetFlag(Device.PLC2.PLCFlag.FLAG_SETUP, true);
|
||||
// Pub.log.Add("Entering Setup Mode (Sub)");
|
||||
// }
|
||||
// else Pub.log.AddE("DIO #S Init error : " + Pub.plcS.GetErrorMessage());
|
||||
//}
|
||||
|
||||
//setting Port_Xbee
|
||||
//UpdateProgressStatus(++progress, ProgressMax, "Port_Xbee 확인"); System.Threading.Thread.Sleep(5);
|
||||
//if (PUB.setting.Port_XBE.isEmpty() == false)
|
||||
//{
|
||||
// PUB.XBE.PortName = PUB.setting.Port_XBE;
|
||||
// if (PUB.XBE.Open() == false)
|
||||
// PUB.log.AddE(string.Format("Barcode Port({0}) Open Error: {1}", PUB.setting.Port_XBE, PUB.XBE.errorMessage));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// PUB.log.AddAT("NOT-SET Port_Xbee PORTNAME");
|
||||
// PUB.XBE.errorMessage = "NOT-SET Port_Xbee PORTNAME";
|
||||
//}
|
||||
|
||||
////setting Port_Xbee
|
||||
//UpdateProgressStatus(++progress, ProgressMax, "Port_AGV 확인"); System.Threading.Thread.Sleep(5);
|
||||
//if (PUB.setting.Port_AGV.isEmpty() == false)
|
||||
//{
|
||||
// PUB.AGV.PortName = PUB.setting.Port_AGV;
|
||||
// PUB.AGV.BaudRate = PUB.setting.Baud_AGV;
|
||||
// if (PUB.AGV.Open() == false)
|
||||
// PUB.log.AddE(string.Format("RFID Host:{0} Open Error: {1}", PUB.setting.Port_AGV, PUB.AGV.errorMessage));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// PUB.log.AddAT("NOT-SET Port_AGV PORTNAME");
|
||||
// PUB.AGV.errorMessage = "NOT-SET Port_AGV PORTNAME";
|
||||
//}
|
||||
|
||||
|
||||
////setting Port_Xbee
|
||||
//UpdateProgressStatus(++progress, ProgressMax, "Port_BMS 확인"); System.Threading.Thread.Sleep(5);
|
||||
//if (!PUB.setting.Port_BAT.isEmpty())
|
||||
//{
|
||||
// PUB.BAT.PortName = PUB.setting.Port_BAT;//.Port_BMS;
|
||||
// PUB.BAT.BaudRate = PUB.setting.Baud_BAT;//
|
||||
// PUB.BAT.ScanInterval = 1000;// Pub.setting.interval_bms;
|
||||
// var binit_bms = PUB.BAT.Open();
|
||||
// if (binit_bms == false) PUB.log.AddE(string.Format("binit_bms Port({0}) Open Error: {1}", PUB.setting.Port_BAT, PUB.BAT.errorMessage));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// PUB.log.AddAT("NOT-SET binit_bms PORTNAME");
|
||||
//}
|
||||
|
||||
//남은 공간
|
||||
UpdateProgressStatus(++progress, ProgressMax, "공간 확인"); System.Threading.Thread.Sleep(5);
|
||||
CheckFreeSpace(); //181225
|
||||
|
||||
//시스템 오류가 있다면 경고 메시지를 표싷ㄴ다.
|
||||
UpdateProgressStatus(++progress, ProgressMax, "오류 수집"); System.Threading.Thread.Sleep(5);
|
||||
//var AlertMessage = new System.Text.StringBuilder();
|
||||
//if (Pub.Xbee.IsInit == false) AlertMessage.AppendLine(string.Format("BARCODE : {0}", Pub.Xbee.errorMessage));
|
||||
if (freeSpaceRate < PUB.setting.AutoDeleteThreshold)
|
||||
{
|
||||
PUB.Speak(string.Format("디스크 용량이 {0:N0}% 남았습니다", freeSpaceRate));
|
||||
}
|
||||
|
||||
//if (AlertMessage.Length > 1)
|
||||
//{
|
||||
// AlertMessage.Insert(0, "SYSTEM ALERT\n");
|
||||
// Pub.popup.setMessage(AlertMessage.ToString());
|
||||
//}
|
||||
|
||||
UpdateProgressStatus(++progress, ProgressMax, "--"); System.Threading.Thread.Sleep(5);
|
||||
PUB.log.Add("초기화 완료");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs
Normal file
44
HMI/Project/StateMachine/Step/_SM_RUN_POSCHK.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AR;
|
||||
using COMM;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
public Boolean _SM_RUN_POSCHK(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
//현재위치가 설정되어있는지 확인한다, 현재위치값이 있는 경우 True 를 반환
|
||||
if (PUB._virtualAGV.CurrentNode != null && PUB._virtualAGV.PrevNode != null)
|
||||
return true;
|
||||
|
||||
//이동을 하지 않고있다면 전진을 진행한다
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastRunCommandTime);
|
||||
if (ts.TotalSeconds > 5)
|
||||
{
|
||||
PUB.log.Add($"현재위치를 몰라 전진 이동 합니다");
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 1,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if(ret == arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastRunCommandTime);
|
||||
}
|
||||
}
|
||||
VAR.STR[eVarString.StatusMessage] = "현재 위치를 알 수 없습니다";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
HMI/Project/StateMachine/Step/_SM_RUN_READY.cs
Normal file
77
HMI/Project/StateMachine/Step/_SM_RUN_READY.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AR;
|
||||
using COMM;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
public Boolean _SM_RUN_READY(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
////이동 불가 조건이 걸려있다면 충전을 하지 못하게 한다.
|
||||
//Boolean bAutoChageOn = true;
|
||||
//if (PUB.AGV.system1.stop_by_front_detect) bAutoChageOn = false;
|
||||
//else if (PUB.AGV.error.Emergency) bAutoChageOn = false;
|
||||
//else if (VAR.BOOL[eVarBool.FLAG_CHARGEONA]) bAutoChageOn = false;
|
||||
//else if (VAR.BOOL[eVarBool.FLAG_CHARGEONM]) bAutoChageOn = false;
|
||||
|
||||
|
||||
//자동 충전 중이라면 최대 충전시간과 레벨을 체크한다
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true)
|
||||
{
|
||||
if (VAR.TIME.IsSet(eVarTime.ChargeStart) == false)
|
||||
VAR.TIME.Update(eVarTime.ChargeStart);
|
||||
|
||||
//충전중이라면 최대 충전 시간을 체크한다.
|
||||
var tsChargeRunTime = VAR.TIME.RUN(eVarTime.ChargeStart);
|
||||
if (PUB.BMS.BMSInformation.rsoc >= PUB.setting.ChargeMaxLevel)
|
||||
{
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CHARGEOFF);
|
||||
PUB.sm.SetNewStep(eSMStep.RUN);
|
||||
PUB.log.Add($"최대충전레벨 OVER로 인한 자동 해제(레벨:{PUB.setting.ChargeMaxLevel})");
|
||||
PUB.AddEEDB($"최대충전레벨 OVER로 인한 자동 해제(레벨:{PUB.setting.ChargeMaxLevel})");
|
||||
PUB.Speak(Lang.충전완료로해제합니다);
|
||||
}
|
||||
else if (PUB.setting.ChargeMaxTime > 1 && tsChargeRunTime.TotalSeconds >= PUB.setting.ChargeMaxTime)
|
||||
{
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CHARGEOFF);
|
||||
PUB.sm.SetNewStep(eSMStep.RUN);
|
||||
PUB.log.Add($"최대충전시간 OVER로 인한 자동 해제(시간:{PUB.setting.ChargeMaxTime})");
|
||||
PUB.AddEEDB($"최대충전시간 OVER로 인한 자동 해제(시간:{PUB.setting.ChargeMaxTime})");
|
||||
PUB.Speak(Lang.충전완료로해제합니다);
|
||||
}
|
||||
VAR.STR[eVarString.ChargeCheckMsg] = "자동 충전 중";
|
||||
}
|
||||
else if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)
|
||||
{
|
||||
if (VAR.TIME.IsSet(eVarTime.ChargeStart) == false)
|
||||
VAR.TIME.Update(eVarTime.ChargeStart);
|
||||
VAR.STR[eVarString.ChargeCheckMsg] = "수동 충전";
|
||||
}
|
||||
|
||||
//대기모드에서는 움직이지 않게 한다
|
||||
if(PUB.AGV.system1.agv_run)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.IdleStopTime);
|
||||
if(ts.TotalSeconds > 1)
|
||||
{
|
||||
PUB.log.Add($"대기상태에서는 정차");
|
||||
PUB.AGV.AGVMoveStop("대기상태에서는 정차");
|
||||
VAR.TIME.Update(eVarTime.IdleStopTime);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
159
HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs
Normal file
159
HMI/Project/StateMachine/Step/_SM_RUN_RESET.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
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
|
||||
{
|
||||
public Boolean _SM_RUN_RESET(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
if (runStepisFirst)
|
||||
{
|
||||
PUB.Speak(Lang.장비상태초기화);
|
||||
|
||||
//충전기검색시퀀스 OFF
|
||||
//PUB.flag.set(EFlag.FLAG_GO_CHAGER_TEMP, false);
|
||||
}
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//충전중이라면 충전off코드를 넣는다
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false,PUB.setting.ChargetWaitSec);
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.AddEEDB($"초기화");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, "SYNC : 수동 모드 확인 중");
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
else
|
||||
{
|
||||
//일정시간동안 명령을 재전송한다
|
||||
var tsCmd = DateTime.Now - LastCommandTime;
|
||||
if (tsCmd.TotalMilliseconds >= 1999)
|
||||
{
|
||||
VAR.BOOL[eVarBool.FLAG_AUTORUN] = false;
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//모션을 멈춥니다
|
||||
//PUB.PLC.Move(Device.PLC.Rundirection.Stop,"RESET");
|
||||
PUB.AGV.AGVMoveStop("_sm_run_reset");
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//모션이 멈출때까지 기다린다
|
||||
if (PUB.AGV.system1.agv_stop == false)
|
||||
{
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else
|
||||
{
|
||||
//모션이 멈추지 않는다면 멈춤코드를 계속 넣는다
|
||||
var tsCmd = DateTime.Now - LastCommandTime;
|
||||
if (tsCmd.TotalMilliseconds >= 1999)
|
||||
{
|
||||
//PUB.PLC.Move(Device.PLC.Rundirection.Stop,"RESET(Re)");
|
||||
PUB.AGV.AGVMoveStop("_sm_run_reset");
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//대상위치 초기화
|
||||
PUB.Result.TargetPos = ePosition.NONE;
|
||||
PUB.Result.CurrentPos = ePosition.NONE;
|
||||
PUB.Result.CurrentPosCW = "0";
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//자동 스탑 플래그 해제
|
||||
//VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;//"reset #6");
|
||||
VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;
|
||||
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, "자동멈춤해제(ALIGN)");
|
||||
if (VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] == false)
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
else
|
||||
{
|
||||
//일정시간동안 명령을 재전송한다
|
||||
var tsCmd = DateTime.Now - LastCommandTime;
|
||||
if (tsCmd.TotalMilliseconds >= 1999)
|
||||
{
|
||||
VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;// "reset #7");
|
||||
//VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;//
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//자동 스탑 플래그 해제
|
||||
//VAR.BOOL[eVarBool.FLAG_NEXTSTOP_MARK] = false;// "reset #8");
|
||||
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//설정모드가 되어있다면 해제 해준다
|
||||
VAR.BOOL[eVarBool.FLAG_SETUP] = false;
|
||||
VAR.BOOL[eVarBool.ITEMON] = false;
|
||||
VAR.BOOL[eVarBool.WAIT_COVER_DOWN] = false;
|
||||
VAR.BOOL[eVarBool.WAIT_COVER_UP] = false;
|
||||
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, "설정모드해제(MARK)");
|
||||
|
||||
if (VAR.BOOL[eVarBool.FLAG_SETUP] == false)
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
else
|
||||
{
|
||||
//일정시간동안 명령을 재전송한다
|
||||
var tsCmd = DateTime.Now - LastCommandTime;
|
||||
if (tsCmd.TotalMilliseconds >= 1999)
|
||||
{
|
||||
VAR.BOOL[eVarBool.FLAG_SETUP] = false;
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
171
HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs
Normal file
171
HMI/Project/StateMachine/Step/_SM_RUN_SYNC.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using System.Diagnostics;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
Dictionary<string, string> synlist;
|
||||
int synidx;
|
||||
public Boolean _SM_RUN_SYNC(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
// return true;
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, "SYNC : 장치 연결(MAIN) 확인 중");
|
||||
if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
//agv connect
|
||||
var rlt = ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
|
||||
eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV);
|
||||
if (rlt == false)
|
||||
{
|
||||
//존재하지 않는 포트라면 sync를 벗어난다
|
||||
PUB.log.AddE($"AGV포트({PUB.setting.Port_AGV}) 가 존재하지않아 SYNC를 중단합니다");
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
}
|
||||
}
|
||||
else if (PUB.AGV.IsValid == true)
|
||||
{
|
||||
//설정모드 진입
|
||||
VAR.BOOL[eVarBool.FLAG_SETUP] = true;
|
||||
LastCommandTime = DateTime.Now;
|
||||
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateProgressStatus(stepTime.TotalMilliseconds, 10000.0, "wait");
|
||||
if (stepTime.TotalSeconds >= 10)
|
||||
{
|
||||
PUB.log.AddE("시간초과로 인해 Sync 작업이 실패되었습니다");
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//동기화 명령 생성
|
||||
synlist = new Dictionary<string, string>();
|
||||
synlist.Add("SSH", PUB.setting.SPD_H.ToString("0000")); // PUB.AGV.AGVCommand(item.Key, item.Value);
|
||||
synlist.Add("SSM", PUB.setting.SPD_M.ToString("0000"));
|
||||
synlist.Add("SSL", PUB.setting.SPD_L.ToString("0000"));
|
||||
|
||||
synlist.Add("SSS", PUB.setting.SPD_S.ToString("0000"));
|
||||
synlist.Add("SRS", PUB.setting.SPD_R.ToString("0000"));
|
||||
|
||||
synlist.Add("SPK", PUB.setting.PID_PH.ToString("0000"));
|
||||
synlist.Add("SPM", PUB.setting.PID_PM.ToString("0000"));
|
||||
synlist.Add("SPL", PUB.setting.PID_PL.ToString("0000"));
|
||||
|
||||
synlist.Add("SIK", PUB.setting.PID_IH.ToString("0000"));
|
||||
synlist.Add("SIM", PUB.setting.PID_IM.ToString("0000"));
|
||||
synlist.Add("SIL", PUB.setting.PID_IL.ToString("0000"));
|
||||
|
||||
synlist.Add("SDK", PUB.setting.PID_DH.ToString("0000"));
|
||||
synlist.Add("SDM", PUB.setting.PID_DM.ToString("0000"));
|
||||
synlist.Add("SDL", PUB.setting.PID_DL.ToString("0000"));
|
||||
|
||||
synlist.Add("SPS", PUB.setting.PID_PS.ToString("0000"));
|
||||
synlist.Add("SIS", PUB.setting.PID_IS.ToString("0000"));
|
||||
synlist.Add("SDS", PUB.setting.PID_DS.ToString("0000"));
|
||||
|
||||
//추가 230110
|
||||
synlist.Add("SCK", PUB.setting.SCK.ToString("0000"));
|
||||
synlist.Add("SSK", PUB.setting.SSK.ToString("0000"));
|
||||
synlist.Add("STT", PUB.setting.STT.ToString("0000"));
|
||||
//synlist.Add("SBN", PUB.setting.ChargerID.ToString("0000"));
|
||||
|
||||
synlist.Add("SGS", PUB.setting.GDSValue.ToString("0000"));
|
||||
VAR.I32[eVarInt32.SyncItemCount] = synlist.Count;
|
||||
|
||||
|
||||
PUB.AddEEDB($"SYNC시작({PUB.Result.TargetPos})");
|
||||
|
||||
synidx = 0;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//잠시 대기
|
||||
var ts = DateTime.Now - LastCommandTime;
|
||||
if (ts.TotalSeconds > 0.15)
|
||||
{
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//통신 확인되었으므로 설정값들을
|
||||
if (synidx < synlist.Count)
|
||||
{
|
||||
var item = synlist.ElementAt(synidx);
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, $"SYNC :{item.Key}");
|
||||
PUB.AGV.AGVCommand(item.Key, item.Value);
|
||||
|
||||
// 캔버스에 동기화 상태 표시
|
||||
if (PUB._mapCanvas != null)
|
||||
{
|
||||
float progress = (float)synidx / VAR.I32[eVarInt32.SyncItemCount];
|
||||
PUB._mapCanvas.SetSyncStatus("장비 설정 동기화 중...", progress, $"항목: {item.Key} ({synidx + 1}/{synlist.Count})");
|
||||
}
|
||||
}
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
if (synidx < synlist.Count)
|
||||
{
|
||||
var ts = DateTime.Now - LastCommandTime;
|
||||
var item = synlist.ElementAt(synidx);
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, $"SYNC 변경 확인 중 :{item.Key}");
|
||||
if (PUB.AGV.ACKData.Equals(item.Key))
|
||||
{
|
||||
synidx += 1;
|
||||
if (ts.TotalSeconds < 0.15) PUB.sm.UpdateRunStepSeq(-2); //싱크중에 추가 지연시간 확보
|
||||
else PUB.sm.UpdateRunStepSeq(-1);
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ts.TotalSeconds > 1)
|
||||
{
|
||||
PUB.AGV.AGVCommand(item.Key, item.Value);
|
||||
LastCommandTime = DateTime.Now;
|
||||
Console.WriteLine($"RE.send Sync : {item.Key}:{item.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.AddEEDB($"SYNC완료({PUB.Result.TargetPos})");
|
||||
UpdateProgressStatus(stepTime.TotalSeconds, 5, "SYNC : 완료");
|
||||
|
||||
// 동기화 완료 시 캔버스 모드 복귀
|
||||
if (PUB._mapCanvas != null)
|
||||
PUB._mapCanvas.SetSyncStatus("동기화 완료!", 1.0f, "잠시 후 메인 화면으로 이동합니다.");
|
||||
|
||||
LastCommandTime = DateTime.Now;
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
HMI/Project/StateMachine/Step/_STEP_CLOSE.cs
Normal file
56
HMI/Project/StateMachine/Step/_STEP_CLOSE.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 프로그램을 닫을때 1회 실행되는 함수
|
||||
/// File : /Step/_Step_Close.cs
|
||||
/// </summary>
|
||||
private void _STEP_CLOSING_START(eSMStep step)
|
||||
{
|
||||
PUB.bShutdown = true;
|
||||
|
||||
PUB.AddEEDB("프로그램 종료");
|
||||
PUB.log.Add("Program Close");
|
||||
PUB.LogFlush();
|
||||
}
|
||||
public StepResult _STEP_CLOSING(eSMStep step, TimeSpan stepTime, TimeSpan seqTime)
|
||||
{
|
||||
//############################
|
||||
//#### 사용자 전용 코드
|
||||
//############################
|
||||
|
||||
|
||||
//############################
|
||||
//#### 개발자 권장코드
|
||||
//############################
|
||||
PUB.sm.SetNewStep(eSMStep.CLOSED);
|
||||
return StepResult.Complete;
|
||||
}
|
||||
|
||||
public void _STEP_CLOSED_START(eSMStep step)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
//화면을 닫는다
|
||||
PUB.sm.Stop();
|
||||
this.Close();
|
||||
}));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
public StepResult _STEP_CLOSED(eSMStep step, TimeSpan stepTime, TimeSpan seqTime)
|
||||
{
|
||||
return StepResult.Wait;
|
||||
}
|
||||
}
|
||||
}
|
||||
432
HMI/Project/StateMachine/Step/_Util.cs
Normal file
432
HMI/Project/StateMachine/Step/_Util.cs
Normal file
@@ -0,0 +1,432 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
using AGVNavigationCore.Utils;
|
||||
using AGVNavigationCore.PathFinding.Core;
|
||||
using AGVNavigationCore.Models;
|
||||
using AGVNavigationCore.PathFinding.Planning;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
bool CheckStopCondition()
|
||||
{
|
||||
|
||||
//이머전시상태라면 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 false;
|
||||
}
|
||||
|
||||
//수동충전상태라면 이동하지 못한다
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM])
|
||||
{
|
||||
PUB.Speak("수동 충전중이라 사용할 수 없습니다");
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AGVPathResult CalcPath(MapNode startNode, MapNode targetNode)
|
||||
{
|
||||
var nodes = PUB._mapCanvas.Nodes;
|
||||
var _simulatorCanvas = PUB._mapCanvas;
|
||||
var _mapNodes = PUB._mapCanvas.Nodes;
|
||||
|
||||
// 현재 AGV 방향 가져오기
|
||||
var selectedAGV = PUB._virtualAGV;
|
||||
var currentDirection = selectedAGV.CurrentDirection;
|
||||
|
||||
// AGV의 이전 위치에서 가장 가까운 노드 찾기
|
||||
var prevNode = selectedAGV.PrevNode;
|
||||
var prevDir = selectedAGV.PrevDirection;
|
||||
|
||||
// Core Logic으로 이관됨
|
||||
var pathFinder = new AGVPathfinder(nodes);
|
||||
var result = pathFinder.CalculatePath(startNode, targetNode, prevNode, prevDir);
|
||||
|
||||
//게이트웨이노드를 하이라이트강조 한단
|
||||
_simulatorCanvas.HighlightNodeId = (result.Gateway?.Id ?? string.Empty);
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 실행스텝을 오류로 전환합니다.
|
||||
/// 로그메세지(에러)가 추가됩니다.
|
||||
/// 맵캔버스오류경고메세지가 설정됩니다
|
||||
/// </summary>
|
||||
/// <param name="ermsg"></param>
|
||||
/// <param name="ecode"></param>
|
||||
public void SetRunStepError(ENIGProtocol.AGVErrorCode ecode, string errmsg = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(errmsg))
|
||||
{
|
||||
errmsg = ENIGProtocol.AGVUtility.GetAGVErrorMessage(ecode);
|
||||
}
|
||||
|
||||
PUB.AGV.AGVMoveStop(errmsg);
|
||||
PUB.log.AddE(errmsg);
|
||||
PUB._mapCanvas.SetAlertMessage(errmsg);
|
||||
PUB.Result.RunStepErrorCode = ecode;
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool CheckLiderStop()
|
||||
{
|
||||
|
||||
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 false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 설정된 목적지까지 이동을 완료 한 후 True를 반환합니다.
|
||||
/// 목적지 : PUB._virtualAGV.TargetNode
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <returns></returns>
|
||||
Boolean UpdateMotionPositionForMark(string sender)
|
||||
{
|
||||
////현재위치를 모르는 상태라면 처리하지 않는다
|
||||
if (PUB._virtualAGV.CurrentNode == null || PUB._virtualAGV.PrevNode == null)
|
||||
return false;
|
||||
|
||||
//현재위치노드 오류
|
||||
var currentNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNode.Id);
|
||||
if (currentNode == null)
|
||||
{
|
||||
PUB.log.AddE($"현재위치노드가 없습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
|
||||
//시작노드값이 없다면 현재위치를 노드로 결정한다
|
||||
if (PUB._virtualAGV.StartNode == null)
|
||||
PUB._virtualAGV.StartNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNode.Id);
|
||||
|
||||
//시작노드가없다면 오류
|
||||
if (PUB._virtualAGV.StartNode == null)
|
||||
{
|
||||
PUB.log.AddE($"경로시작노드가 없습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
|
||||
//대상노드가 없다면 오류
|
||||
if (PUB._virtualAGV.TargetNode == null)
|
||||
{
|
||||
PUB.log.AddE($"경로종료노드가 없습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
|
||||
//경로 생성(경로정보가 없거나 현재노드가 경로에 없는경우)
|
||||
if (PUB._virtualAGV.HasPath() == false ||
|
||||
PUB._virtualAGV.CurrentPath.DetailedPath.Where(t => t.NodeId.Equals(currentNode.Id)).Any() == false)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run)
|
||||
{
|
||||
PUB.log.Add($"경로 재생성으로 인해 구동을 멈춥니다");
|
||||
PUB.AGV.AGVMoveStop("경로재생성");
|
||||
}
|
||||
|
||||
PUB._virtualAGV.StartNode = PUB._virtualAGV.CurrentNode;
|
||||
var PathResult = CalcPath(currentNode, PUB._virtualAGV.TargetNode);
|
||||
if (PathResult.Success == false)
|
||||
{
|
||||
PUB.log.AddE($"경로가 계산되지 않았습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB._mapCanvas.CurrentPath = PathResult;
|
||||
PUB._virtualAGV.SetPath(PathResult);
|
||||
PUB.log.AddI($"경로생성 {PUB._virtualAGV.StartNode.RfidId} -> {PUB._virtualAGV.TargetNode.RfidId}");
|
||||
}
|
||||
|
||||
//경로에 대한 무결성 검증
|
||||
if (CheckPathIntegrity(PUB._virtualAGV.CurrentPath) == false)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop("Path Integrity Fail");
|
||||
}
|
||||
PUB.log.AddE($"경로 무결성 오류로 인해 경로를 삭제 합니다");
|
||||
PUB._virtualAGV.SetPath(null);
|
||||
VAR.I32[eVarInt32.PathValidationError] += 1;
|
||||
if (VAR.I32[eVarInt32.PathValidationError] > 50)
|
||||
{
|
||||
SetRunStepError(ENIGProtocol.AGVErrorCode.PATH_INTEGRITY_FAIL, $"연속 경로 무결성 오류로 인해 중지 합니다");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else VAR.I32[eVarInt32.PathValidationError] = 0;
|
||||
|
||||
//현재위치 기준으로 재 계산하여. 더 최적화된 루트가 있다면 처리를 해준다.
|
||||
if (PUB._virtualAGV.CurrentPath.DetailedPath.Count > 5)
|
||||
{
|
||||
var PathResult2 = CalcPath(PUB._virtualAGV.CurrentNode, PUB._virtualAGV.TargetNode);
|
||||
if (PathResult2 != null && PathResult2.Success)
|
||||
{
|
||||
//절반이상 경로가 짧을때에는 재계산을 하게한다
|
||||
var halfcnt = (int)(PUB._virtualAGV.CurrentPath.DetailedPath.Count / 2.0);
|
||||
if (PathResult2.DetailedPath.Count < halfcnt)
|
||||
{
|
||||
var msg = $"단축경로가 확인되었습니다. 경로를 삭제 합니다";
|
||||
PUB.log.AddE(msg);
|
||||
Console.WriteLine(msg);
|
||||
PUB._virtualAGV.SetPath(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//predict 를 이용하여 다음 이동을 모두 확인한다.
|
||||
var nextAction = PUB._virtualAGV.Predict();
|
||||
if (nextAction.Reason == AGVNavigationCore.Models.eAGVCommandReason.PathOut)
|
||||
{
|
||||
//경로이탈
|
||||
var logmessage = $"경로이탈감지 시작노드를 현재위치로 설정합니다 START:{PUB._virtualAGV.StartNode},CURRENT:{PUB._virtualAGV.CurrentNode}";
|
||||
PUB.log.AddE(logmessage);
|
||||
Console.WriteLine(logmessage);
|
||||
PUB._virtualAGV.ClearPath();//.DetailedPath.Clear();
|
||||
PUB._virtualAGV.StartNode = PUB._virtualAGV.CurrentNode;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//모터에서 정지를 요청했다
|
||||
if (nextAction.Motor == AGVNavigationCore.Models.MotorCommand.Stop)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run)
|
||||
{
|
||||
// 완료(Complete) 상태라면 MarkStop 전송
|
||||
if (nextAction.Reason == AGVNavigationCore.Models.eAGVCommandReason.MarkStop)
|
||||
{
|
||||
PUB.log.Add("다음행동예측에서 MARK STOP이 확인되었습니다 (자동정지시퀀스)");
|
||||
PUB.AGV.AGVMoveStop(nextAction.Message, arDev.Narumi.eStopOpt.MarkStop);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.log.Add($"다음행동예측에서 장비 멈춤이 확인되었습니다({nextAction.Reason})");
|
||||
PUB.AGV.AGVMoveStop(nextAction.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// 목적지 도착 여부 확인
|
||||
// 현재 노드가 타겟 노드와 같고, 위치가 확정된 상태라면 도착으로 간주
|
||||
// 단, AGV가 실제로 멈췄는지 확인 (agv_run == false)
|
||||
if (PUB._virtualAGV.IsPositionConfirmed)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
// 경로가 존재한다면, 경로의 마지막 노드에 도착했는지 확인한다.
|
||||
if (PUB._virtualAGV.CurrentPath != null && PUB._virtualAGV.CurrentPath.DetailedPath.Any())
|
||||
{
|
||||
var lastInfo = PUB._virtualAGV.CurrentPath.DetailedPath.Last();
|
||||
// 위치와 방향이 모두 일치해야 완료된 것으로 본다.
|
||||
if (PUB._virtualAGV.CurrentNode.Id == lastInfo.NodeId &&
|
||||
PUB._virtualAGV.CurrentDirection == lastInfo.MotorDirection)
|
||||
{
|
||||
var node = PUB._mapCanvas.Nodes.Where(t => t.Id == PUB._virtualAGV.CurrentNodeId).FirstOrDefault();
|
||||
var rfid = node?.ID2 ?? "(X)";
|
||||
PUB.log.AddI($"목표 도착 및 정지 확인됨(MarkStop 완료) Node:{rfid}, Dir:{PUB._virtualAGV.CurrentDirection}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 경로 정보가 없다면 단순히 목적지 ID와 비교한다 (Fallback)
|
||||
if (PUB._virtualAGV.CurrentNode.Id == PUB._virtualAGV.TargetNode.Id)
|
||||
{
|
||||
var node = PUB._mapCanvas.Nodes.Where(t => t.Id == PUB._virtualAGV.CurrentNodeId).FirstOrDefault();
|
||||
var rfid = node?.ID2 ?? "(X)";
|
||||
PUB.log.AddI($"목표 도착 및 정지 확인됨(MarkStop 완료, No Path Info) Node:{rfid}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//아직 멈추지 않았다면 기다린다.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 이동 명령 변환 (AGVNavigationCore -> arDev.Narumi)
|
||||
var bunki = arDev.Narumi.eBunki.Strate;
|
||||
if (nextAction.Magnet == AGVNavigationCore.Models.MagnetPosition.L) bunki = arDev.Narumi.eBunki.Left;
|
||||
else if (nextAction.Magnet == AGVNavigationCore.Models.MagnetPosition.R) bunki = arDev.Narumi.eBunki.Right;
|
||||
|
||||
var dir = arDev.Narumi.eMoveDir.Forward;
|
||||
if (nextAction.Motor == AGVNavigationCore.Models.MotorCommand.Backward) dir = arDev.Narumi.eMoveDir.Backward;
|
||||
|
||||
var spd = arDev.Narumi.eMoveSpd.Low;
|
||||
if (nextAction.Speed == AGVNavigationCore.Models.SpeedLevel.M) spd = arDev.Narumi.eMoveSpd.Mid;
|
||||
else if (nextAction.Speed == AGVNavigationCore.Models.SpeedLevel.H) spd = arDev.Narumi.eMoveSpd.High;
|
||||
|
||||
// 명령 설정
|
||||
// 현재 상태와 다를 때만 전송 (불필요한 통신 부하 방지)
|
||||
if (PUB.AGV.data.Sts != bunki.ToString()[0] ||
|
||||
PUB.AGV.data.Direction != dir.ToString()[0] ||
|
||||
PUB.AGV.data.Speed != spd.ToString()[0])
|
||||
{
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = bunki,
|
||||
Direction = dir,
|
||||
PBSSensor = 1,
|
||||
Speed = spd,
|
||||
});
|
||||
if (ret == arDev.eNarumiCommandResult.Success)
|
||||
PUB.log.Add($"Predict Run Setting = bunki:{bunki},dir:{dir},pbs:1,spd:{spd}");
|
||||
else
|
||||
PUB.log.AddE($"Predict Run Setting = bunki:{bunki},dir:{dir},pbs:1,spd:{spd}");
|
||||
}
|
||||
|
||||
// AGV가 정지 상태라면 구동 시작
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
var runOpt = (dir == arDev.Narumi.eMoveDir.Forward) ? arDev.Narumi.eRunOpt.Forward : arDev.Narumi.eRunOpt.Backward;
|
||||
PUB.AGV.AGVMoveRun(runOpt);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 충전기검색시퀀스
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <returns></returns>
|
||||
Boolean UpdateMotionPositionForCharger(string sender)
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.AGVDIR_BACK] == 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)
|
||||
{
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 1,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if (ret == arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);//
|
||||
}
|
||||
|
||||
tm_gocharge_command = DateTime.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//현재위치가 충전위치이고, 움직이지 않았다면 완료된 경우라 할수 있따
|
||||
if (PUB._virtualAGV.CurrentNode.Id.Equals(PUB.setting.NodeMAP_RFID_Charger) &&
|
||||
VAR.BOOL[eVarBool.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)
|
||||
{
|
||||
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 1,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if (ret == arDev.eNarumiCommandResult.Success)
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);//
|
||||
LastCommandTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 경로 무결성(도킹방향 등) 검증
|
||||
/// </summary>
|
||||
/// <param name="pathResult"></param>
|
||||
/// <returns></returns>
|
||||
private bool CheckPathIntegrity(AGVNavigationCore.PathFinding.Core.AGVPathResult pathResult)
|
||||
{
|
||||
if (pathResult == null) return false;
|
||||
|
||||
// CalcPath에서 이미 DockingValidator를 수행했을 수 있음.
|
||||
// 만약 수행되지 않았다면 여기서 수행.
|
||||
if (pathResult.DockingValidation == null)
|
||||
{
|
||||
pathResult.DockingValidation = AGVNavigationCore.Utils.DockingValidator.ValidateDockingDirection(pathResult, PUB._mapCanvas.Nodes);
|
||||
}
|
||||
|
||||
// 검증 결과 확인
|
||||
if (pathResult.DockingValidation != null && pathResult.DockingValidation.IsValidationRequired)
|
||||
{
|
||||
if (pathResult.DockingValidation.IsValid == false)
|
||||
{
|
||||
PUB.log.AddE($"[경로무결성오류] {pathResult.DockingValidation.ValidationError}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}//cvass
|
||||
}
|
||||
280
HMI/Project/StateMachine/_AGV.cs
Normal file
280
HMI/Project/StateMachine/_AGV.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
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;
|
||||
using AGVNavigationCore.Controls;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
|
||||
public partial class fMain
|
||||
{
|
||||
private void AGV_Message(object sender, arDev.Narumi.MessageEventArgs e)
|
||||
{
|
||||
if (e.MsgType == arDev.NarumiSerialComm.MessageType.Normal)
|
||||
PUB.logagv.AddE(e.Message);
|
||||
else if (e.MsgType == arDev.NarumiSerialComm.MessageType.Normal)
|
||||
PUB.logagv.Add(e.Message);
|
||||
else if (e.MsgType == arDev.NarumiSerialComm.MessageType.Recv)
|
||||
{
|
||||
if (e.Message.Substring(1).StartsWith("STS") == false)
|
||||
PUB.logagv.Add("AGV-RX", e.Message);
|
||||
}
|
||||
else if (e.MsgType == arDev.NarumiSerialComm.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
|
||||
{
|
||||
VAR.TIME.Set(eVarTime.LastRecv_AGV, DateTime.Now);
|
||||
//데이터 파싱
|
||||
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.signal1.mark_sensor;
|
||||
|
||||
|
||||
//if (chg_run && PUB.AGV.system1.agv_run) PUB.Speak("이동을 시작 합니다");
|
||||
VAR.BOOL[eVarBool.AGVDIR_BACK] = PUB.AGV.data.Direction == 'B';
|
||||
var syncDir = PUB.AGV.data.Direction == 'B' ? AgvDirection.Backward : AgvDirection.Forward;
|
||||
|
||||
// [Sync] Update VirtualAGV Direction
|
||||
if (PUB._virtualAGV != null)
|
||||
{
|
||||
if (PUB._virtualAGV.CurrentDirection != syncDir)
|
||||
PUB.UpdateAGVDirection(syncDir);
|
||||
}
|
||||
|
||||
|
||||
// [Sync] Update VirtualAGV State
|
||||
AGVState syncState = AGVState.Idle;
|
||||
if (PUB.AGV.error.Value > 0) syncState = AGVState.Error;
|
||||
else if (PUB.AGV.system1.Battery_charging) syncState = AGVState.Charging;
|
||||
else if (PUB.AGV.system1.agv_run) syncState = AGVState.Moving;
|
||||
|
||||
if (PUB._virtualAGV != null && PUB._virtualAGV.GetCurrentState() != syncState)
|
||||
PUB.UpdateAGVState(syncState);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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.signal1.mark_sensor)
|
||||
{
|
||||
PUB.logagv.Add($"MARK_SENSOR 변경({PUB.AGV.signal1.mark_sensor})");
|
||||
VAR.BOOL[eVarBool.MARK_SENSOR] = PUB.AGV.signal1.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.Result.LastTAG = PUB.AGV.data.TagNo;//.ToString("0000");
|
||||
PUB.log.Add($"AGV 태그수신 : {PUB.AGV.data.TagNo} LastTag:{PUB.Result.LastTAG}");
|
||||
//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._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB.Result.LastTAG);
|
||||
if (CurrentNode == null)
|
||||
{
|
||||
//없는 노드는 자동으로 추가한다
|
||||
var newNodeId = $"AUTO_{PUB.Result.LastTAG}";
|
||||
var newNode = new MapNode
|
||||
{
|
||||
Id = newNodeId,
|
||||
RfidId = PUB.Result.LastTAG,
|
||||
Position = new Point(100, 100), // 기본 위치
|
||||
IsActive = true,
|
||||
CreatedDate = DateTime.Now,
|
||||
ModifiedDate = DateTime.Now
|
||||
};
|
||||
|
||||
// 맵 노드 리스트에 추가
|
||||
PUB._mapCanvas.Nodes.Add(newNode);
|
||||
|
||||
// 로그 기록
|
||||
PUB.log.AddI($"RFID:{PUB.Result.LastTAG} 노드를 자동 추가했습니다 (NodeId: {newNodeId})");
|
||||
|
||||
// CurrentNode에 새로 생성한 노드 할당
|
||||
CurrentNode = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//모터방향 확인해서 UI와 AGV클래스에 적용한다
|
||||
var MotDireciton = PUB.AGV.data.Direction == 'B' ? AgvDirection.Backward : 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 && PUB._virtualAGV != null)
|
||||
{
|
||||
var nextAction = PUB._virtualAGV.Predict();
|
||||
var message = $"[다음 행동 예측]\n\n";
|
||||
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
|
||||
message += "[X] 수동모드\n";
|
||||
|
||||
if (PUB._virtualAGV.TargetNode == null) message += "[X] 목표노드없음\n";
|
||||
if (PUB._virtualAGV.CurrentNode == null) message += "[X] 현재노드없음\n";
|
||||
else if (PUB._virtualAGV.HasPath() == false) message += "[X] 경로계산안됨\n";
|
||||
if (PUB._virtualAGV.PrevNode == null) message += "[X] 이전노드없음\n";
|
||||
else message += $"이전노드: {PUB._virtualAGV.PrevNode.ID2} : {PUB._virtualAGV.PrevDirection}\n";
|
||||
message += $"현재노드: {PUB._virtualAGV.CurrentNode.ID2} : {PUB._virtualAGV.CurrentDirection}\n";
|
||||
|
||||
message += "-------------\n";
|
||||
|
||||
var node = PUB._virtualAGV.CurrentNode;
|
||||
var curpos = PUB._virtualAGV.CurrentNodeID2;
|
||||
var targetpos = PUB._virtualAGV.TargetNode?.ID2 ?? "(X)";
|
||||
|
||||
|
||||
|
||||
var pathdetail = "";
|
||||
if (PUB._virtualAGV.CurrentPath != null && PUB._virtualAGV.CurrentPath.DetailedPath.Any())
|
||||
{
|
||||
var idx = 0;
|
||||
foreach (var item in PUB._virtualAGV.CurrentPath.DetailedPath)
|
||||
{
|
||||
idx += 1;
|
||||
if (pathdetail.isEmpty() == false) pathdetail += "->";
|
||||
if (idx % 6 == 0) pathdetail += "\n";
|
||||
pathdetail += $"{item.RfidId:0000}({item.MotorDirection.ToString().Substring(0, 1)}{item.MagnetDirection.ToString().Substring(0, 1)}{item.Speed.ToString().Substring(0, 1)})";
|
||||
if (item.IsPass) pathdetail += "(O)";
|
||||
}
|
||||
}
|
||||
|
||||
message += $"모터: {nextAction.Motor}\n" +
|
||||
$"마그넷: {nextAction.Magnet}\n" +
|
||||
$"속도: {nextAction.Speed}\n" +
|
||||
$"이유: {nextAction.Message}\n" +
|
||||
$"상태머신:{PUB.sm.Step}:{PUB.sm.RunStep}:{PUB.sm.RunStepSeq}\n" +
|
||||
$"---\n" +
|
||||
$"현재 상태: {PUB._virtualAGV.CurrentState}\n" +
|
||||
$"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" +
|
||||
$"턴: {PUB._virtualAGV.Turn}\n" +
|
||||
$"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" +
|
||||
|
||||
$"대상 노드: {targetpos}\n" +
|
||||
$"상세 경로: {pathdetail}";
|
||||
|
||||
PUB._mapCanvas.PredictMessage = message;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[AGV_DataReceive] {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
205
HMI/Project/StateMachine/_BMS.cs
Normal file
205
HMI/Project/StateMachine/_BMS.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
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;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
string lastbms03 = "";
|
||||
string lastbms04 = "";
|
||||
string lastbmsA03 = "";
|
||||
string lastbmsA04 = "";
|
||||
string lastbms = "";
|
||||
DateTime lastbmstime03 = DateTime.Now;
|
||||
DateTime lastbmstime04 = DateTime.Now;
|
||||
DateTime lastbmstimeA03 = DateTime.Now;
|
||||
DateTime lastbmstimeA04 = DateTime.Now;
|
||||
DateTime lastbmstime = DateTime.Now;
|
||||
private void Bms_Message(object sender, arDev.BMS.MessageEventArgs e)
|
||||
{
|
||||
|
||||
if (e.MsgType == arDev.BMSSerialComm.MessageType.Error) PUB.logbms.AddE(e.Message);
|
||||
else
|
||||
{
|
||||
VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now;
|
||||
|
||||
var hexstr = e.Data.GetHexString().Trim();
|
||||
bool addlog = false;
|
||||
var logtimesec = 30;
|
||||
if (hexstr.StartsWith("DD 04"))
|
||||
{
|
||||
if (lastbms04.Equals(hexstr.Substring(0, 5)) == false)
|
||||
{
|
||||
addlog = true;
|
||||
lastbms04 = "DD 04";
|
||||
lastbmstime04 = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - lastbmstime04;
|
||||
if (ts.TotalSeconds > logtimesec)
|
||||
{
|
||||
addlog = true;
|
||||
lastbms04 = "DD 04";
|
||||
lastbmstime04 = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (hexstr.StartsWith("DD 03"))
|
||||
{
|
||||
if (lastbms03.Equals(hexstr.Substring(0, 5)) == false)
|
||||
{
|
||||
addlog = true;
|
||||
lastbms03 = "DD 03";
|
||||
lastbmstime03 = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - lastbmstime03;
|
||||
if (ts.TotalSeconds > logtimesec)
|
||||
{
|
||||
addlog = true;
|
||||
lastbms03 = "DD 03";
|
||||
lastbmstime03 = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (hexstr.StartsWith("DD A5 04"))
|
||||
{
|
||||
if (lastbmsA04.Equals(hexstr.Substring(0, 8)) == false)
|
||||
{
|
||||
addlog = true;
|
||||
lastbmsA04 = "DD A5 04";
|
||||
lastbmstimeA04 = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - lastbmstimeA04;
|
||||
if (ts.TotalSeconds > logtimesec)
|
||||
{
|
||||
addlog = true;
|
||||
lastbmsA04 = "DD A5 04";
|
||||
lastbmstimeA04 = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (hexstr.StartsWith("DD A5 03"))
|
||||
{
|
||||
if (lastbmsA03.Equals(hexstr.Substring(0, 8)) == false)
|
||||
{
|
||||
addlog = true;
|
||||
lastbmsA03 = "DD A5 03";
|
||||
lastbmstimeA03 = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - lastbmstimeA03;
|
||||
if (ts.TotalSeconds > logtimesec)
|
||||
{
|
||||
addlog = true;
|
||||
lastbmsA03 = "DD A5 03";
|
||||
lastbmstimeA03 = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if (hexstr.isEmpty() == false)
|
||||
{
|
||||
if (lastbms.Equals(hexstr) == false)
|
||||
{
|
||||
lastbms = hexstr;
|
||||
lastbmstime = DateTime.Now;
|
||||
addlog = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - lastbmstime;
|
||||
if (ts.TotalSeconds > logtimesec)
|
||||
{
|
||||
addlog = true;
|
||||
lastbms = hexstr;
|
||||
lastbmstime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addlog)
|
||||
{
|
||||
//if (e.MsgType == arDev.arRS232.MessageType.Recv)
|
||||
// PUB.logbms.Add("RX", e.Data.GetHexString());
|
||||
//else if (e.MsgType == arDev.arRS232.MessageType.Send)
|
||||
// PUB.logbms.Add("TX", e.Data.GetHexString());
|
||||
//else
|
||||
{
|
||||
PUB.logbms.Add(e.MsgType.ToString(),e.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
private void BMS_ChargeDetect(object sender, arDev.ChargetDetectArgs e)
|
||||
{
|
||||
//자동충전중이아니고 멈춰있다면 수동 충전으로 전환한다
|
||||
VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now;
|
||||
if (e.Detected == true) //충전이 감지되었다.
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false && VAR.BOOL[eVarBool.FLAG_CHARGEONM] == false)
|
||||
{
|
||||
VAR.BOOL[eVarBool.FLAG_CHARGEONM] = true;
|
||||
PUB.Speak(Lang.충전이감지되어수동충전으로전환합니다);
|
||||
if (PUB.AGV.system1.agv_run == true) PUB.AGV.AGVMoveStop("수동충전감지");
|
||||
}
|
||||
}
|
||||
else PUB.logbms.AddI("Battery Charge Off");
|
||||
|
||||
}
|
||||
|
||||
private void Bms_BMSDataReceive(object sender, arDev.BMSInformationEventArgs e)
|
||||
{
|
||||
VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now;
|
||||
|
||||
PUB.UpdateAGVBattery(e.Data.rsoc);
|
||||
|
||||
if (e.Data.rsoc <= PUB.setting.ChargeStartLevel)
|
||||
{
|
||||
//배터리 레벨이 기준보다 낮다면 경고를 활성화 한다
|
||||
if (VAR.BOOL[eVarBool.BATTERY_LOW] == false)
|
||||
{
|
||||
VAR.BOOL[eVarBool.BATTERY_LOW] = true;
|
||||
PUB.log.AddAT("배터리 부족 경고 활성화");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//배터리 경고를 해제한다
|
||||
if (VAR.BOOL[eVarBool.BATTERY_LOW] == true)
|
||||
{
|
||||
VAR.BOOL[eVarBool.BATTERY_LOW] = false;
|
||||
PUB.log.AddAT("배터리 부족 경고 비활성화");
|
||||
}
|
||||
}
|
||||
EEMStatus.MakeBMSInformation_INFO();
|
||||
}
|
||||
private void BMS_BMSCellDataReceive(object sender, arDev.BMSCelvoltageEventArgs e)
|
||||
{
|
||||
VAR.TIME[eVarTime.LastRecv_BAT] = DateTime.Now;
|
||||
EEMStatus.MakeBMSInformation_Cell();
|
||||
}
|
||||
}
|
||||
}
|
||||
195
HMI/Project/StateMachine/_DIO.cs
Normal file
195
HMI/Project/StateMachine/_DIO.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AR;
|
||||
using arDev;
|
||||
using COMM;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
//private void PLC_DioChanged(object sender, arDev.FakePLC.IOValueEventArgs e)
|
||||
//{
|
||||
// if (e.Direction == arDev.Arduino.IODirection.Input)
|
||||
// {
|
||||
// var diName = (arDev.FakePLC.DIName)e.ArrIDX;
|
||||
// Console.WriteLine(string.Format("[DI:{1}]{0}=>{2}", diName, e.ArrIDX, e.NewValue));
|
||||
|
||||
// if (diName == arDev.FakePLC.DIName.PINI_BTN_1) //reset
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림(AGV_RESET)");
|
||||
// PUB.AGV.AGVErrorReset();
|
||||
|
||||
// //241203
|
||||
// if(PUB.AGV.system1.agv_run || PUB.AGV.system1.agv_run_manual)
|
||||
// {
|
||||
// PUB.AGV.AGVMoveStop("button1");
|
||||
// }
|
||||
// //PUB.XBE.NewMsgEvent('0', '1');
|
||||
// }
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_BTN_2) //auto -> QC //230424
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == true)
|
||||
// {
|
||||
// if (PUB.sm.RunStep == StateMachine.ERunStep.GOUP)
|
||||
// {
|
||||
// //zup을 자동으로 해준다
|
||||
// if (VAR.BOOL[eVarBool.WAIT_COVER_UP])
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.UP);
|
||||
// PUB.Result.NextPos = ePosition.QC;
|
||||
// }
|
||||
// else PUB.Speak(Lang.커버업대기상태가아닙니다);
|
||||
// }
|
||||
// else if (PUB.sm.RunStep == StateMachine.ERunStep.GODOWN)
|
||||
// {
|
||||
// //이미 하차진행중에 누른 경우이다
|
||||
// PUB.Result.NextPos = ePosition.QC;
|
||||
// PUB.Result.TargetPos = ePosition.QC;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// PUB.log.Add(Lang.QC이동버튼은상하차에서만사용가능합니다);
|
||||
// PUB.Speak(Lang.하차상태에서만사용가능합니다);
|
||||
// }
|
||||
// }
|
||||
// else PUB.Speak(Lang.자동운전상태가아닙니다);
|
||||
|
||||
// //if (VAR.BOOL[eVarBool.FLAG_AUTORUN]==false)
|
||||
// //{
|
||||
// // PUB.sm.ClearRunStep();
|
||||
// // PUB.sm.SetNewRunStep(StateMachine.ERunStep.READY);
|
||||
// // PUB.sm.SetNewStep(StateMachine.eSMStep.RUN);
|
||||
// // PUB.Speak("자동 상태로 전환 합니다");
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // PUB.Speak("현재 자동 상태 입니다");
|
||||
// //}
|
||||
// }
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_BTN_3) //z-down -> QA //230424
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// //Z-dn기능으로 업데이트 230119
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == true)
|
||||
// {
|
||||
// if (PUB.sm.RunStep == StateMachine.ERunStep.GOUP)
|
||||
// {
|
||||
// //zup.을 자동으로 해준다
|
||||
// if (VAR.BOOL[eVarBool.WAIT_COVER_UP])
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.UP);
|
||||
// PUB.Result.NextPos = ePosition.QA;
|
||||
// }
|
||||
// else PUB.Speak(Lang.커버업대기상태가아닙니다);
|
||||
// }
|
||||
// else if (PUB.sm.RunStep == StateMachine.ERunStep.GODOWN)
|
||||
// {
|
||||
// //이미 하차진행중에 누른 경우이다
|
||||
// PUB.Result.NextPos = ePosition.QA;
|
||||
// PUB.Result.TargetPos = ePosition.QA;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// PUB.log.Add($"QA이동 버튼은 상/하차에서만 사용 가능합니다");
|
||||
// PUB.Speak(Lang.하차상태에서만사용가능합니다);
|
||||
// }
|
||||
// }
|
||||
// else PUB.Speak(Lang.자동운전상태가아닙니다);
|
||||
|
||||
// //PUB.PLC.ZMot(FakePLC.ZMotDirection.Down);
|
||||
// }
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_BTN_4) //z-up
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// //Z-up기능으로 업데이트 230119
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.UP);
|
||||
// }
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_EMG)
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.Speak(Lang.비상정지);
|
||||
// }
|
||||
// //else Pub.Speak("비상 정지 해제");
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_OVERLOADL)
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.Speak(Lang.오버로드감지);
|
||||
// }
|
||||
// VAR.BOOL[eVarBool.OVERLOADL] = e.NewValue;
|
||||
// }
|
||||
// else if (diName == arDev.FakePLC.DIName.PINI_OVERLOADR)
|
||||
// {
|
||||
// if (e.NewValue == true)
|
||||
// {
|
||||
// PUB.log.Add($"버튼({diName}) 눌림");
|
||||
// PUB.Speak(Lang.오버로드감지);
|
||||
// }
|
||||
// VAR.BOOL[eVarBool.OVERLOADR] = e.NewValue;
|
||||
// }
|
||||
// //else if (diName == FakePLC.DIName.PINI_LIMIT_LU)
|
||||
// //{
|
||||
// // PUB.flag.set(EFlag.FLAG_LIMITHIGHL, e.NewValue);
|
||||
// //}
|
||||
// //else if (diName == FakePLC.DIName.PINI_LIMIT_RU)
|
||||
// //{
|
||||
// // PUB.flag.set(EFlag.FLAG_LIMITHIGHR, e.NewValue);
|
||||
// //}
|
||||
// //else if (diName == FakePLC.DIName.PINI_LIMIT_LD)
|
||||
// //{
|
||||
// // PUB.flag.set(EFlag.FLAG_LIMITLOWL, e.NewValue);
|
||||
// //}
|
||||
// //else if (diName == FakePLC.DIName.PINI_LIMIT_RD)
|
||||
// //{
|
||||
// // PUB.flag.set(EFlag.FLAG_LIMITLOWR, e.NewValue);
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // //처리하지 않음
|
||||
// //}
|
||||
// //PUB.flag.set(EFlag.FLAG_LIMITHIGH, (PUB.flag.get(EFlag.FLAG_LIMITHIGHL) && PUB.flag.get(EFlag.FLAG_LIMITHIGHR)));
|
||||
// //PUB.flag.set(EFlag.FLAG_LIMITLOW, (PUB.flag.get(EFlag.FLAG_LIMITLOWL) && PUB.flag.get(EFlag.FLAG_LIMITLOWR)));
|
||||
// VAR.BOOL[eVarBool.FLAG_LIMITHIGH] = false;// PUB.PLC.GetValueI(arDev.FakePLC.DIName.PINI_LIMIT_LU) || PUB.PLC.GetValueI(arDev.FakePLC.DIName.PINI_LIMIT_RU);
|
||||
// VAR.BOOL[eVarBool.FLAG_LIMITLOW] = false;//PUB.PLC.GetValueI(arDev.FakePLC.DIName.PINI_LIMIT_LD) || PUB.PLC.GetValueI(arDev.FakePLC.DIName.PINI_LIMIT_RD);
|
||||
// VAR.BOOL[eVarBool.OVERLOAD] = (VAR.BOOL[eVarBool.OVERLOADL] || VAR.BOOL[eVarBool.OVERLOADR]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //출력포트값 변경
|
||||
// var doName = (arDev.FakePLC.DOName)e.ArrIDX;
|
||||
// PUB.logplc.Add($"출력({doName}) {(e.NewValue ? "O" : "X")}");
|
||||
// }
|
||||
//}
|
||||
|
||||
//string oldflagmessage = string.Empty;
|
||||
// 사용하지 않는 필드들 제거
|
||||
// private string logmessage;
|
||||
// private string lastplclogmessage;
|
||||
// private string logerror;
|
||||
}
|
||||
}
|
||||
|
||||
108
HMI/Project/StateMachine/_Flag.cs
Normal file
108
HMI/Project/StateMachine/_Flag.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using AR;
|
||||
using COMM;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
void gridView2_ItemClick(object sender, arFrame.Control.GridView.ItemClickEventArgs e)
|
||||
{
|
||||
//메인화면 하단의 플래그 상태창에서 클릭된 경우
|
||||
//var gv = sender as arFrame.Control.GridView;
|
||||
//var flagIndex = gv.getNameItem(e.idx);
|
||||
//if(flagIndex != "")
|
||||
//{
|
||||
// var fidx = int.Parse(flagIndex);
|
||||
// var flag = (eFlag)fidx;
|
||||
// var curValue = Pub.flag.get(flag);
|
||||
// Pub.flag.set(flag, !curValue);
|
||||
//}
|
||||
}
|
||||
|
||||
private void BOOL_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var buf = e.PropertyName.Split('|');
|
||||
var flag = (COMM.eVarBool)int.Parse(buf[0]);
|
||||
var NewValue = buf[1].ToUpper() == "TRUE";
|
||||
if (flag == COMM.eVarBool.FLAG_AUTORUN)
|
||||
{
|
||||
//자동운전이 해제되면 현재위치값을 삭제한다
|
||||
if (NewValue == false && PUB.setting.AutoModeOffAndClearPosition == true)
|
||||
{
|
||||
if (PUB.Result.CurrentPos != ePosition.NONE)
|
||||
{
|
||||
PUB.log.AddAT($"자동운전이 해제되어 현재 위치를 제거합니다");
|
||||
PUB.Result.CurrentPos = ePosition.NONE;
|
||||
PUB.Result.CurrentPosCW = "1";
|
||||
}
|
||||
}
|
||||
// Pub.mplayer.Stop();
|
||||
//if (NewValue == true)
|
||||
//{
|
||||
// btAutoRun.BackColor = Color.Lime;
|
||||
// btAutoRun.BackColor2 = Color.Green;
|
||||
// btAutoRun.Text = "자동 실행 상태";
|
||||
|
||||
// //if (Pub.sm.Step >= StateMachine.eSMStep.IDLE) Pub.Speak("자동 실행 모드");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// btAutoRun.BackColor2 = Color.DimGray;
|
||||
// btAutoRun.BackColor = Color.FromArgb(100, 100, 100);
|
||||
// btAutoRun.Text = "수동 조작 상태";
|
||||
// //if (Pub.sm.Step >= StateMachine.eSMStep.IDLE) Pub.Speak("수동 조작 모드");
|
||||
//}
|
||||
}
|
||||
else if (flag == COMM.eVarBool.FLAG_CHARGEONA)
|
||||
{
|
||||
if (NewValue)
|
||||
{
|
||||
VAR.TIME.Update(eVarTime.ChargeStart);
|
||||
PUB.counter.CountChargeA += 1;
|
||||
PUB.counter.Save();
|
||||
PUB.Speak(Lang.충전을시작합니다);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.Speak(Lang.충전을해제합니다);
|
||||
}
|
||||
}
|
||||
else if (flag == COMM.eVarBool.FLAG_CHARGEONM)
|
||||
{
|
||||
if (NewValue)
|
||||
{
|
||||
VAR.TIME.Update(eVarTime.ChargeStart);
|
||||
PUB.counter.CountChargeM += 1;
|
||||
PUB.counter.Save();
|
||||
PUB.Speak(Lang.수동충전을시작합니다);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.Speak(Lang.수동충전을해제합니다);
|
||||
}
|
||||
}
|
||||
//else if (flag == COMM.eVarBool.NEXTSTOP_MARK)
|
||||
//{
|
||||
// if (NewValue)
|
||||
// {
|
||||
// //PUB.Speak("다음 위치에서 멈춥니다");
|
||||
// PUB.log.Add($"마크인식시 멈춤 신호 변경 : {NewValue}");
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
//void PLC_FlagChanged(object sender, arDev.Arduino.DIO.FlagValueEventArgs e)
|
||||
//{
|
||||
// //플래그 상태표시는 메인의 타이머를 이용한다
|
||||
// // var flag = (arDev.FakePLC.PLCFlag)e.ArrIDX;
|
||||
// PUB.log.Add($"PLC Flag Changed {e.ArrIDX} : {e.NewValue}");
|
||||
//}
|
||||
}
|
||||
}
|
||||
439
HMI/Project/StateMachine/_Loop.cs
Normal file
439
HMI/Project/StateMachine/_Loop.cs
Normal file
@@ -0,0 +1,439 @@
|
||||
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 System.Windows.Forms;
|
||||
using Project.ViewForm;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
|
||||
DateTime lastDeleteTime = DateTime.Now;
|
||||
DateTime startuptime = new DateTime(1982, 11, 23);
|
||||
enum EScreen
|
||||
{
|
||||
Auto = 0,
|
||||
Manual,
|
||||
IO,
|
||||
Flag
|
||||
}
|
||||
void SetScreen(System.Windows.Forms.Form newscreen)
|
||||
{
|
||||
if (newscreen == null)
|
||||
throw new Exception("화면전용용 폼이 Null 입니다. SM_RUN_INIT 에서 해당 폼이 초기화 되었는지 확인하세요");
|
||||
|
||||
//작업시작
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
SetScreen(newscreen);
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newscreen.GetType() == typeof(fManual))
|
||||
{
|
||||
|
||||
}
|
||||
else if (PUB.DriveSpeed)
|
||||
{
|
||||
var rlt = PUB.AGV.AGVCommand("SSH", PUB.setting.SPD_H.ToString("0000"));
|
||||
if (rlt == arDev.eNarumiCommandResult.Success)
|
||||
{
|
||||
PUB.DriveSpeed = false;
|
||||
PUB.log.Add($"Screen Change and DriveSpeed Off:{rlt}");
|
||||
} else
|
||||
{
|
||||
PUB.log.AddE($"Screen Change and DriveSpeed Off:{rlt}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MenuAuto.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuFlag.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuLift.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuLog.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuMAN.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuAGV.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
MenuBMS.ForeColor = Color.FromArgb(180, 180, 180);
|
||||
|
||||
|
||||
if (panDlg.Controls.Count > 0)
|
||||
{
|
||||
var f = panDlg.Controls[0] as System.Windows.Forms.Form;
|
||||
if (f.GetType() == newscreen.GetType()) return;
|
||||
else f.Hide(); //숨김처리
|
||||
}
|
||||
panDlg.Controls.Clear();
|
||||
panDlg.Controls.Add(newscreen);
|
||||
newscreen.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
newscreen.WindowState = System.Windows.Forms.FormWindowState.Maximized;
|
||||
newscreen.Show();
|
||||
}
|
||||
}
|
||||
|
||||
string lockstep = string.Empty;
|
||||
System.Threading.ManualResetEvent mreloop = new System.Threading.ManualResetEvent(true);
|
||||
void sm_Running(object sender, StateMachine.StateMachine.RunningEventArgs e)
|
||||
{
|
||||
|
||||
//창을 닫아야하는 상황에는 처리하지 않는다.
|
||||
if (PUB.popup.needClose)
|
||||
{
|
||||
System.Threading.Thread.Sleep(10); //팝업이 닫힐때까지 기다린다.
|
||||
PUB.sm.WaitFirstRun = true;
|
||||
return;
|
||||
}
|
||||
else PUB.sm.WaitFirstRun = false;
|
||||
|
||||
if (mreloop.WaitOne(1) == false) return;
|
||||
mreloop.Reset();
|
||||
|
||||
lockstep = e.Step.ToString();
|
||||
|
||||
//main loop
|
||||
switch (e.Step)
|
||||
{
|
||||
case eSMStep.CLOSING:
|
||||
_STEP_CLOSING_START(e.Step);
|
||||
PUB.sm.SetNewStep(eSMStep.CLOSED);
|
||||
break;
|
||||
case eSMStep.CLOSED:
|
||||
if (e.isFirst) _STEP_CLOSED_START(e.Step);
|
||||
else _STEP_CLOSED(e.Step, e.StepTime, e.StepTime);
|
||||
break;
|
||||
case eSMStep.NOTSET:
|
||||
PUB.log.Add("S/M Initialize Start");
|
||||
PUB.sm.SetNewStep(eSMStep.INIT);
|
||||
break;
|
||||
|
||||
case eSMStep.INIT: //최초실행이다.
|
||||
|
||||
if (_SM_RUN_INIT(e.isFirst, PUB.sm.StepRunTime))
|
||||
{
|
||||
//메인화면을 설정한다
|
||||
form_auto = new ViewForm.fAuto();
|
||||
form_manu = new ViewForm.fManual();
|
||||
form_zlift = new ViewForm.fIO();
|
||||
form_flag = new ViewForm.fFlag();
|
||||
form_bms = new ViewForm.fBms();
|
||||
form_agv = new ViewForm.fAgv();
|
||||
|
||||
|
||||
form_auto.TopLevel = false;
|
||||
form_manu.TopLevel = false;
|
||||
form_zlift.TopLevel = false;
|
||||
form_flag.TopLevel = false;
|
||||
form_bms.TopLevel = false;
|
||||
form_agv.TopLevel = false;
|
||||
|
||||
|
||||
form_auto.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
form_manu.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
form_zlift.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
form_flag.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
form_bms.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
form_agv.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
|
||||
SetScreen(form_auto);
|
||||
|
||||
PUB.sm.ResetRunStepSeq();
|
||||
PUB.sm.SetNewStep(eSMStep.SYNC);
|
||||
PUB.Speak(Lang.프로그램이초기화되었습니다);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case eSMStep.IDLE:
|
||||
|
||||
if (e.isFirst)
|
||||
{
|
||||
PUB.sm.bPause = false;
|
||||
//Pub.flag.set(eFlag.UserStepCheck, false);
|
||||
PUB.sm.ClearRunStep();
|
||||
// Util_DO.SetMGZMotor(false);
|
||||
PUB.Result.SMSG_ProgressEnable = false;
|
||||
UpdateStatusMessage("준비 완료", Color.Red, Color.Gold);
|
||||
if (startuptime.Year == 1982) startuptime = DateTime.Now;
|
||||
|
||||
|
||||
// 동기화 모드 종료 (혹시 남아있을 경우)
|
||||
if (PUB._mapCanvas != null)
|
||||
{
|
||||
this.Invoke(new Action(() => {
|
||||
PUB._mapCanvas.ExitSyncMode( AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run);
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//자동소거기능
|
||||
if (PUB.setting.AutoDeleteDay > 0)
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.MINSPACE] == true)
|
||||
{
|
||||
var ts = DateTime.Now - lastDeleteTime;
|
||||
if (ts.TotalSeconds > 1)
|
||||
{
|
||||
//파일을 찾아서 소거한다.
|
||||
if (System.IO.Directory.Exists(PUB.path.FullName))
|
||||
DeleteFile(PUB.path.FullName);
|
||||
|
||||
|
||||
lastDeleteTime = DateTime.Now;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case eSMStep.SYNC:
|
||||
if (e.isFirst)
|
||||
{
|
||||
// 동기화 완료 시 캔버스 모드 복귀
|
||||
this.Invoke(new Action(() => {
|
||||
if (PUB._mapCanvas != null)
|
||||
PUB._mapCanvas.SetSyncStatus("설정 동기화", 0f, "환경설정 값으로 AGV컨트롤러를 설정 합니다");
|
||||
}));
|
||||
|
||||
}
|
||||
if (_SM_RUN_SYNC(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
var b1 = PUB.XBE.IsOpen;
|
||||
var b2 = PUB.AGV.IsOpen;
|
||||
var b3 = true;// PUB.PLC.IsOpen;
|
||||
var b4 = PUB.BMS.IsOpen;
|
||||
|
||||
if (b1 == false || b2 == false || b3 == false || b4 == false)
|
||||
PUB.Speak(Lang.하드웨어오류발생);
|
||||
else
|
||||
PUB.Speak( Lang.초기화완료);
|
||||
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eSMStep.RUN:
|
||||
_SM_RUN(e.isFirst, e.StepTime);
|
||||
break;
|
||||
|
||||
case eSMStep.PAUSE:
|
||||
case eSMStep.EMERGENCY:
|
||||
case eSMStep.ERROR:
|
||||
|
||||
|
||||
//창을 닫아야하는 상황에는 처리하지 않는다.
|
||||
if (PUB.popup.needClose)
|
||||
{
|
||||
System.Threading.Thread.Sleep(10); //팝업이 닫힐때까지 기다린다.
|
||||
PUB.sm.WaitFirstRun = true;
|
||||
return;
|
||||
}
|
||||
else PUB.sm.WaitFirstRun = false;
|
||||
|
||||
if (e.isFirst)
|
||||
{
|
||||
|
||||
if (PUB.Result.ResultCode != eResult.NoError)
|
||||
{
|
||||
//에러메세지가 있는 경우에만 표시함
|
||||
if (PUB.Result.ResultMessage != "")
|
||||
PUB.popup.setMessage(PUB.Result.ResultMessage);
|
||||
|
||||
if (PUB.Result.ResultCode == eResult.Hardware)
|
||||
{
|
||||
PUB.Speak(Lang.하드웨어오류로인해진행할수없습니다);
|
||||
}
|
||||
else PUB.Speak(PUB.Result.ResultMessage);
|
||||
|
||||
}
|
||||
if (e.Step == eSMStep.EMERGENCY) PUB.log.AddE("Enter Emergency Step");
|
||||
else if (e.Step == eSMStep.PAUSE) PUB.log.AddE("Enter Pause Step : " + PUB.Result.ResultMessage);
|
||||
else PUB.log.AddE(string.Format("Enter Error Step : {0}", PUB.Result.ResultMessage));
|
||||
|
||||
|
||||
|
||||
PUB.sm.bPause = false;
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eSMStep.RESET:
|
||||
|
||||
if (e.isFirst)
|
||||
{
|
||||
Resultclear();
|
||||
PUB.sm.bPause = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_SM_RUN_RESET(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mreloop.Set();
|
||||
}
|
||||
|
||||
void DeleteFile(string path)
|
||||
{
|
||||
var basetime = DateTime.Now.AddDays(-1 * PUB.setting.AutoDeleteDay);
|
||||
var di = new System.IO.DirectoryInfo(path);
|
||||
if (di.Exists)
|
||||
{
|
||||
var dirYear = di.GetDirectories().OrderBy(t => t.Name).FirstOrDefault();
|
||||
if (dirYear != null)
|
||||
{
|
||||
var dirMon = dirYear.GetDirectories().OrderBy(t => t.Name).FirstOrDefault();
|
||||
if (dirMon != null)
|
||||
{
|
||||
var dirDay = dirMon.GetDirectories().OrderBy(t => t.Name).FirstOrDefault();
|
||||
if (dirDay != null)
|
||||
{
|
||||
var curDay = DateTime.Parse(string.Format("{0}-{1}-{2} 00:00:00", dirYear.ToString(), dirMon.ToString(), dirDay.ToString()));
|
||||
if (curDay < basetime)
|
||||
{
|
||||
var dirLot = dirDay.GetDirectories().OrderBy(t => t.Name).FirstOrDefault();
|
||||
if (dirLot != null)
|
||||
{
|
||||
var delfile = dirLot.GetFiles().FirstOrDefault();
|
||||
if (delfile != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
PUB.log.AddI("Remove Fle : " + delfile.FullName + ",time=" + delfile.LastWriteTime.ToString());
|
||||
delfile.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE("deleete error : " + ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string delpath = dirLot.FullName;
|
||||
try
|
||||
{
|
||||
dirLot.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE("remove dir" + ex.Message + "," + delpath);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//이 폴더아래에 다른 폴더가 하나도 없다 즉 비어 있따.
|
||||
string delpath = dirDay.FullName;
|
||||
try
|
||||
{
|
||||
dirDay.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE("remove dir" + ex.Message + "," + delpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//날짜에 해당하는 폴더가 하나도 없다. 월 폴더를 제거한다.
|
||||
string delpath = dirMon.FullName;
|
||||
try
|
||||
{
|
||||
dirMon.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE("remove dir" + ex.Message + "," + delpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//이 달에 해당하는 데이터가 없다. 이 년도를 삭제한다.
|
||||
string delpath = dirYear.FullName;
|
||||
try
|
||||
{
|
||||
dirYear.Delete(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE("remove dir" + ex.Message + "," + delpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
//년도별폴더목록을 정리함
|
||||
//가장작은 년도를 기준으로 파일을 검색해서 1개씩 삭제함
|
||||
}
|
||||
}
|
||||
|
||||
void sm_Message(object sender, StateMachine.StateMachine.StateMachineMessageEventArgs e)
|
||||
{
|
||||
//상태머신에서 발생한 메세지
|
||||
if (e.Header != "SM-STEP")
|
||||
PUB.log.Add(e.Header, e.Message);
|
||||
}
|
||||
|
||||
|
||||
void sm_StepChanged(object sender, StateMachine.StateMachine.StepChangeEventArgs e)
|
||||
{
|
||||
//상태머신의 스텝이 변경될때 발생함
|
||||
//Pub.log.Add(string.Format("SM:Step Changed {0} to {1}",e.Old,e.New));
|
||||
VAR.BOOL[eVarBool.FLAG_AUTORUN] = e.New == eSMStep.RUN;
|
||||
VAR.BOOL[eVarBool.FLAG_SYNC] = (e.New == eSMStep.SYNC);
|
||||
|
||||
//230313
|
||||
var n = (eSMStep)e.New;
|
||||
EEMStatus.AddStatusSQL(n, extrun: true);
|
||||
|
||||
if (e.New == eSMStep.IDLE)
|
||||
{
|
||||
VAR.TIME[eVarTime.IdleStart] = DateTime.Now;
|
||||
PUB.AGV.AGVMoveStop("_sm_stepchange", arDev.Narumi.eStopOpt.Stop);
|
||||
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] || VAR.BOOL[eVarBool.FLAG_CHARGEONM])
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN])
|
||||
{
|
||||
PUB.logagv.Add($"IDLE 전환으로인해 autorun 해제");
|
||||
VAR.BOOL[eVarBool.FLAG_AUTORUN] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void uploadForm_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
|
||||
//{
|
||||
// //이벤트 해제
|
||||
// if (uploadForm != null)
|
||||
// uploadForm.FormClosed -= uploadForm_FormClosed;
|
||||
|
||||
// //업로드 창이 닫히면 그 결과를 화면에 표시 해준다.
|
||||
// //foreach (System.Windows.Forms.ListViewItem lv in uploadForm.listView1.Items)
|
||||
// //{
|
||||
// // string slot = lv.SubItems[0].Text;
|
||||
// // string wafer = lv.SubItems[2].Text;
|
||||
// // string state = lv.SubItems[3].Text;
|
||||
|
||||
// //}
|
||||
//}
|
||||
}
|
||||
}
|
||||
228
HMI/Project/StateMachine/_SPS.cs
Normal file
228
HMI/Project/StateMachine/_SPS.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Media.Animation;
|
||||
using AR;
|
||||
using arCtl;
|
||||
using COMM;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
/// <summary>
|
||||
/// SPS (Scan Per Second) 이벤트 핸들러
|
||||
/// - 장치 연결 및 상태 전송 기능은 _DeviceManagement.cs로 분리됨
|
||||
/// </summary>
|
||||
public partial class fMain
|
||||
{
|
||||
DateTime chargesynctime = DateTime.Now;
|
||||
DateTime agvsendstarttime = DateTime.Now;
|
||||
DateTime lastXbeStatusSendTime = DateTime.Now;
|
||||
DateTime lastBmsQueryTime = DateTime.Now;
|
||||
object connectobj = new object();
|
||||
|
||||
void sm_SPS(object sender, EventArgs e)
|
||||
{
|
||||
if (PUB.sm == null || PUB.sm.Step < eSMStep.IDLE || PUB.sm.Step >= eSMStep.CLOSING || PUB.bShutdown == true) return;
|
||||
|
||||
// SPS는 이제 간단한 작업만 수행
|
||||
// 장치 연결 및 상태 전송은 별도 태스크(_DeviceManagement.cs)에서 처리
|
||||
// 장치 연결이 별도로 존재할때 1회 수신 후 통신이 전체 먹통되는 증상이 있어 우선 복귀 251215
|
||||
try
|
||||
{
|
||||
|
||||
// ========== 1. 장치 연결 관리 ==========
|
||||
// AGV 연결
|
||||
lock (connectobj)
|
||||
{
|
||||
ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
|
||||
eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV);
|
||||
}
|
||||
|
||||
|
||||
// XBee 연결
|
||||
lock (connectobj)
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.DISABLE_AUTOCONN_XBEE] == false)
|
||||
{
|
||||
ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE,
|
||||
eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// BMS 연결
|
||||
lock (connectobj)
|
||||
{
|
||||
if (PUB.BMS.IsOpen == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT);
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
PUB.log.Add($"BMS 연결 시도: {PUB.setting.Port_BAT}");
|
||||
PUB.BMS.PortName = PUB.setting.Port_BAT;
|
||||
if (PUB.BMS.Open())
|
||||
PUB.log.AddI($"BMS 연결 완료({PUB.setting.Port_BAT})");
|
||||
|
||||
VAR.TIME.Update(eVarTime.LastConn_BAT);
|
||||
VAR.TIME.Update(eVarTime.LastConnTry_BAT);
|
||||
}
|
||||
}
|
||||
else if (PUB.BMS.IsValid == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT);
|
||||
if (ts.TotalSeconds > (Math.Max(10, PUB.setting.interval_bms) * 2.5))
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
PUB.log.Add("BMS 자동 연결 해제 (응답 없음)");
|
||||
PUB.BMS.Close();
|
||||
}));
|
||||
VAR.TIME.Set(eVarTime.LastConn_BAT, DateTime.Now.AddSeconds(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 2. XBee 상태 전송 ==========
|
||||
if (PUB.XBE != null && PUB.XBE.IsOpen)
|
||||
{
|
||||
var tsXbe = DateTime.Now - lastXbeStatusSendTime;
|
||||
if (tsXbe.TotalSeconds >= PUB.setting.interval_xbe)
|
||||
{
|
||||
lastXbeStatusSendTime = DateTime.Now;
|
||||
ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
PUB.XBE.SendStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE($"XBee SendStatus 오류: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 3. BMS 쿼리 및 배터리 경고 ==========
|
||||
if (PUB.BMS != null && PUB.BMS.IsOpen)
|
||||
{
|
||||
var tsBms = DateTime.Now - lastBmsQueryTime;
|
||||
if (tsBms.TotalSeconds >= PUB.setting.interval_bms)
|
||||
{
|
||||
lastBmsQueryTime = DateTime.Now;
|
||||
ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
PUB.BMS.SendQuery();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE($"BMS SendQuery 오류: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 배터리 경고음
|
||||
try
|
||||
{
|
||||
Update_BatteryWarnSpeak();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE($"BatteryWarnSpeak 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE($"sm_SPS Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 시리얼 포트 연결 (arDev.arRS232)
|
||||
/// </summary>
|
||||
bool ConnectSerialPort(arDev.ISerialComm dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime? recvtime)
|
||||
{
|
||||
if (port.isEmpty()) return false;
|
||||
|
||||
if (dev.IsOpen == false && port.isEmpty() == false)
|
||||
{
|
||||
var tsPLC = VAR.TIME.RUN(conntry);
|
||||
if (tsPLC.TotalSeconds > 5)
|
||||
{
|
||||
VAR.TIME.Update(conntry);
|
||||
try
|
||||
{
|
||||
if (recvtime != null) VAR.TIME.Update(recvtime);
|
||||
dev.PortName = port;
|
||||
dev.BaudRate = baud;
|
||||
PUB.log.Add($"Connect to {port}:{baud}");
|
||||
if (dev.Open())
|
||||
{
|
||||
if (recvtime != null) VAR.TIME[recvtime] = DateTime.Now; //값을 수신한것처럼한다
|
||||
PUB.log.Add(port, $"[{port}:{baud}] 연결 완료");
|
||||
}
|
||||
else
|
||||
{
|
||||
//존재하지 않는 포트라면 sync를 벗어난다
|
||||
var ports = System.IO.Ports.SerialPort.GetPortNames().Select(t => t.ToLower()).ToList();
|
||||
if (ports.Contains(PUB.setting.Port_AGV.ToLower()) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var errmessage = dev.ErrorMessage;
|
||||
PUB.log.AddE($"[AGV:{port}:{baud}] {errmessage}");
|
||||
}
|
||||
}
|
||||
VAR.TIME.Update(conn);
|
||||
VAR.TIME.Update(conntry);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PUB.log.AddE(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dev.PortName.Equals(port) == false)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
|
||||
VAR.TIME.Set(conntry, DateTime.Now);
|
||||
dev.Close();
|
||||
}));
|
||||
|
||||
VAR.TIME.Update(conntry);
|
||||
}
|
||||
else if (dev.IsOpen && recvtime != null)
|
||||
{
|
||||
//연결은 되었으나 통신이 지난지 10초가 지났다면 자동종료한다
|
||||
var tsRecv = VAR.TIME.RUN(recvtime);
|
||||
var tsConn = VAR.TIME.RUN(conntry);
|
||||
if (tsRecv.TotalSeconds > 30 && tsConn.TotalSeconds > 5)
|
||||
{
|
||||
this.BeginInvoke(new Action(() =>
|
||||
{
|
||||
PUB.log.Add($"{port} 자동 연결 해제 (응답 없음)");
|
||||
dev.Close();
|
||||
}));
|
||||
VAR.TIME.Set(conntry, DateTime.Now);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
836
HMI/Project/StateMachine/_TMDisplay.cs
Normal file
836
HMI/Project/StateMachine/_TMDisplay.cs
Normal file
@@ -0,0 +1,836 @@
|
||||
using AR;
|
||||
using COMM;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
|
||||
|
||||
void BlinkGridViewItem(arFrame.Control.GridView ctl, int row, int col, int value1, int value2)
|
||||
{
|
||||
var curValue = ctl.getValue(row, col);
|
||||
ctl.setValue(row, col, (byte)(curValue == value1 ? value2 : value1)); //
|
||||
}
|
||||
|
||||
void BlinkLabel(arCtl.arLabel ctl, bool Statue
|
||||
, Color onColor1, Color onColor2, Color ofColor1, Color ofColor2,
|
||||
String onText = "", String OffText = "")
|
||||
{
|
||||
if (Statue == false)
|
||||
{
|
||||
ctl.BackColor2 = ofColor2;
|
||||
ctl.BackColor = ofColor1;
|
||||
if (OffText != "" && ctl.Text != OffText) ctl.Text = OffText;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (onText != "" && ctl.Text != onText) ctl.Text = onText;
|
||||
//깜박인다
|
||||
if (ctl.BackColor2 == Color.DimGray)
|
||||
{
|
||||
ctl.BackColor = onColor1;
|
||||
ctl.BackColor2 = onColor2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.BackColor2 = Color.DimGray;
|
||||
ctl.BackColor = Color.FromArgb(100, 100, 100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Boolean displayOn = false;
|
||||
private void tmDisplay_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (displayOn == false) displayOn = true;
|
||||
else
|
||||
{
|
||||
PUB.log.AddAT("Display Timer Overlab");// Console.WriteLine("display overlab");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PUB.sm.Step > eSMStep.INIT &&
|
||||
panTopMenu.Enabled == false) panTopMenu.Enabled = true;
|
||||
|
||||
//배터리정보표시
|
||||
var bmsinfo = PUB.BMS.BMSInformation;
|
||||
lbBat.VLevel = bmsinfo.rsoc;
|
||||
lbBat.Volt = bmsinfo.packVoltage;
|
||||
lbBat.MaxA = bmsinfo.fullCapacity;
|
||||
lbBat.CurA = bmsinfo.remainingCapacity;
|
||||
lbBat.IsOpen = PUB.BMS.IsOpen;
|
||||
|
||||
//쓰레드로인해서 메인에서 진행하게한다. SPS는 메인쓰레드에서 진행 됨
|
||||
//팝을 제거 혹은 표시하는 기능
|
||||
if (PUB.popup.needShow) PUB.popup.showMessage();
|
||||
else if (PUB.popup.needClose) PUB.popup.Visible = false; // .setVision(false)();
|
||||
|
||||
//자동 리부트 코드 실행 (230710)
|
||||
var chargeon = VAR.BOOL[eVarBool.FLAG_CHARGEONA] || VAR.BOOL[eVarBool.FLAG_CHARGEONM];
|
||||
if (PUB.sm.Step == eSMStep.RUN & PUB.sm.RunStep == ERunStep.READY && chargeon == false &&
|
||||
PUB.setting.AutoRebootTimeStart.isEmpty() == false && startuptime.Year != 1982 &&
|
||||
PUB.Automodeonreboot == false && PUB.setting.SetAutoModeOn == false && PUB.AutRebootAlreay == false)
|
||||
{
|
||||
var strbuf = PUB.setting.AutoRebootTimeStart.Split('~');
|
||||
if (strbuf.Length == 2)
|
||||
{
|
||||
strbuf[0] = strbuf[0].Trim();
|
||||
strbuf[1] = strbuf[1].Trim();
|
||||
|
||||
var btimes = DateTime.TryParse(DateTime.Now.ToString("yyyy-MM-dd ") + strbuf[0], out DateTime TimeS);
|
||||
var btimee = DateTime.TryParse(DateTime.Now.ToString("yyyy-MM-dd ") + strbuf[1], out DateTime TimeE);
|
||||
|
||||
//이미 재부팅을 했는지 확인한다
|
||||
if (PUB.setting.AutoRebootTimeStart.isEmpty() == false)
|
||||
{
|
||||
if (DateTime.TryParse(PUB.setting.AutoRebootTimeStart, out DateTime RebootLast))
|
||||
{
|
||||
//지정된 시간내에서 재부팅이 되었다
|
||||
if (RebootLast >= TimeS.AddMinutes(-1) && RebootLast <= TimeE.AddMinutes(1))
|
||||
{
|
||||
//재부팅이 완료됨
|
||||
PUB.log.Add($"이미 재부팅을 진행 했습니다");
|
||||
PUB.AutRebootAlreay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PUB.AutRebootAlreay == false && btimes && btimee && TimeS <= TimeE && DateTime.Now >= TimeS && DateTime.Now <= TimeE) //둘다시간조건에 맞아야한다
|
||||
{
|
||||
//기록을 남긴다.(확인용)
|
||||
EEMStatus.AddStatusSQL(eSMStep.IDLE, $"자동재부팅실행({strbuf[0]}~{strbuf[1]})", DateTime.Now, true);
|
||||
|
||||
//자동모드도 해제 해준다(다른 일이 발생하지 않도록)
|
||||
VAR.BOOL[eVarBool.FLAG_AUTORUN] = false;
|
||||
PUB.AGV.AGVCharge(PUB.setting.ChargerID, false);
|
||||
PUB.AGV.AGVMoveStop("autoreboot");
|
||||
PUB.sm.SetNewStep(eSMStep.IDLE);
|
||||
|
||||
if (System.Diagnostics.Debugger.IsAttached == false)
|
||||
{
|
||||
PUB.Speak(Lang.자동재부팅을실행합니다);
|
||||
PUB.SystemReboot(5, true);
|
||||
}
|
||||
else PUB.setting.SetAutoModeOn = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//자동실행-230710 - 프로그램이 켜진 후 5분안에만 동작한다
|
||||
if (startuptime.Year != 1982 && PUB.setting.SetAutoModeOn && PUB.sm.Step == eSMStep.IDLE && PUB.Automodeonreboot == false)
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == true) //이미 자동상태라면
|
||||
{
|
||||
//이미 켜져있으니 처리하지 않는다
|
||||
PUB.setting.SetAutoModeOn = false;
|
||||
PUB.setting.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
var tsStartup = DateTime.Now - startuptime;
|
||||
if (tsStartup.TotalMinutes < 3)
|
||||
{
|
||||
if (tsStartup.TotalSeconds > 10) //5초이전에는동작하지 말자
|
||||
{
|
||||
PUB.log.Add($"자동 오토런 실행");
|
||||
func_sw_start(false);
|
||||
PUB.setting.SetAutoModeOn = false;
|
||||
PUB.setting.Save();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//5분을 넘어선 데이터는 쓸모없다 폐기
|
||||
PUB.setting.SetAutoModeOn = false;
|
||||
PUB.setting.Save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbTime.Text = PUB.sm.UpdateTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
//자동충전중이다(프로그램에 의해 충전이 진행된 상태)
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true || VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)
|
||||
{
|
||||
lbStStep.Text = VAR.BOOL[eVarBool.FLAG_CHARGEONA] ? "자동충전" : "수동충전";
|
||||
lbIDLE.ProgressForeColor = Color.Tomato;
|
||||
if (lbIDLE.ProgressEnable == false)
|
||||
lbIDLE.ProgressEnable = true;
|
||||
|
||||
//lbIDLE.ForeColor = Color.Gold;
|
||||
lbIDLE.ProgressForeColor = Color.Gold;
|
||||
|
||||
if (PUB.sm.Step != eSMStep.RUN)
|
||||
{
|
||||
var tsIdle = VAR.TIME.RUN(eVarTime.ChargeStart);
|
||||
lbIDLE.ProgressMax = 100;// PUB.setting.ChargeMaxLevel;
|
||||
lbIDLE.ProgressMin = 0;
|
||||
lbIDLE.Text = $"{PUB.BMS.BMSInformation.rsoc}%";
|
||||
lbIDLE.ProgressValue = (float)PUB.BMS.BMSInformation.rsoc;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (PUB.setting.ChargeMaxTime < 1)
|
||||
//{/
|
||||
var tsIdle = VAR.TIME.RUN(eVarTime.ChargeStart);
|
||||
lbIDLE.ProgressMax = PUB.setting.ChargeMaxLevel;
|
||||
lbIDLE.ProgressMin = 0;
|
||||
lbIDLE.Text = $"({PUB.BMS.BMSInformation.rsoc}/{PUB.setting.ChargeMaxLevel})%";
|
||||
lbIDLE.ProgressValue = (float)PUB.BMS.BMSInformation.rsoc;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// var tsIdle = VAR.TIME.RUN(eVarTime.ChargeStart);
|
||||
// lbIDLE.ProgressMax = PUB.setting.ChargeMaxTime;
|
||||
// lbIDLE.ProgressMin = 0;
|
||||
// lbIDLE.Text = string.Format("{0:N0}/{1} 초 충전 중", tsIdle.TotalSeconds, PUB.setting.ChargeMaxTime);
|
||||
// lbIDLE.ProgressValue = (float)tsIdle.TotalSeconds;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeSpan timerun;
|
||||
if (PUB.sm.Step == eSMStep.RUN)
|
||||
{
|
||||
if (PUB.sm.RunStep == ERunStep.READY)
|
||||
{
|
||||
//대기시간
|
||||
lbStStep.Text = "대기중";
|
||||
timerun = VAR.TIME.RUN(eVarTime.ReadyStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
//가동시간
|
||||
lbStStep.Text = "가동중";
|
||||
timerun = VAR.TIME.RUN(eVarTime.RunStart);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lbStStep.Text = "장비멈춤";
|
||||
timerun = VAR.TIME.RUN(eVarTime.IdleStart);
|
||||
}
|
||||
lbIDLE.Text = string.Format("{0}일 {1}시 {2}분 {3}초", timerun.Days, timerun.Hours, timerun.Minutes, timerun.Seconds);
|
||||
if (lbIDLE.ProgressEnable == true)
|
||||
lbIDLE.ProgressEnable = false;
|
||||
}
|
||||
|
||||
//hw접속상태 표시
|
||||
MenuAGV.BackColor = PUB.AGV.IsValid ? Color.FromArgb(40, 40, 40) : Color.Brown;
|
||||
MenuBMS.BackColor = PUB.BMS.IsValid ? Color.FromArgb(40, 40, 40) : Color.Brown;
|
||||
MenuMAN.BackColor = PUB.AGV.IsValid ? Color.FromArgb(40, 40, 40) : Color.Brown;
|
||||
|
||||
|
||||
btChargeA.Enabled = !VAR.BOOL[eVarBool.FLAG_CHARGEONM];
|
||||
btHome.Enabled = btChargeA.Enabled;
|
||||
btAutoRun.Enabled = btChargeA.Enabled;
|
||||
|
||||
var bCharge =
|
||||
(PUB.sm.RunStep == ERunStep.GOCHARGE || PUB.sm.RunStep == ERunStep.CHARGECHECK || VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true);
|
||||
|
||||
//가동, 목적지가 충전기라면 홈 이동이다
|
||||
var bHome = PUB.sm.Step == eSMStep.RUN && (PUB.sm.RunStep == ERunStep.GOHOME);
|
||||
//var bChargeM = PUB.flag.get(EFlag.FLAG_CHARGEONM);
|
||||
var bAuto = VAR.BOOL[eVarBool.FLAG_AUTORUN];
|
||||
//if(batu)
|
||||
|
||||
var bChargeM = VAR.BOOL[eVarBool.FLAG_CHARGEONM];
|
||||
if (btHome.Enabled == false)
|
||||
{
|
||||
btHome.BackColor2 = Color.Gray;
|
||||
btHome.BackColor = Color.DimGray;
|
||||
}
|
||||
else BlinkLabel(this.btHome, bHome, Color.Aqua, Color.Teal, Color.Aqua, Color.Teal, "홈\n취소", "홈\n이동");
|
||||
if (btChargeA.Enabled == false)
|
||||
{
|
||||
btChargeA.BackColor2 = Color.Gray;
|
||||
btChargeA.BackColor = Color.DimGray;
|
||||
}
|
||||
else
|
||||
{
|
||||
//충전가능요건이라면 해당 시간을 표시해준다.
|
||||
BlinkLabel(this.btChargeA, bCharge, Color.LightSalmon, Color.Tomato, Color.LightSalmon, Color.Tomato, "자동충전취소", "자동충전\n실행(" + PUB.counter.CountChargeA.ToString() + ")");
|
||||
}
|
||||
BlinkLabel(this.btChargeM, bChargeM, Color.LightSalmon, Color.Tomato, Color.LightSalmon, Color.Tomato, "수동충전취소", "수동충전\n실행(" + PUB.counter.CountChargeM.ToString() + ")");
|
||||
//BlinkLabel(this.btChargeM, bChargeM, Color.LightSalmon, Color.Tomato, "수동충전취소", "수동충전\n실행(" + Pub.counter.CountChargeM.ToString() + ")");
|
||||
if (btAutoRun.Enabled == false)
|
||||
{
|
||||
btAutoRun.BackColor2 = Color.Gray;
|
||||
btAutoRun.BackColor = Color.DimGray;
|
||||
}
|
||||
else BlinkLabel(this.btAutoRun, bAuto == false, Color.DarkMagenta, Color.BlueViolet, Color.Lime, Color.Green, "수동\n조작중", "자동\n실행중");
|
||||
|
||||
//상태 표시
|
||||
Update_SSStatus();
|
||||
|
||||
//IO상태(상단줄) 표시
|
||||
Update_IOStatus();
|
||||
|
||||
//display mesasge
|
||||
Update_StatusMessage();
|
||||
|
||||
//음악 on/off 처리
|
||||
Update_Music();
|
||||
|
||||
//HWState.Invalidate();
|
||||
SSInfo.Invalidate();
|
||||
IOState.Invalidate();
|
||||
|
||||
#region retgion"1분 time 루틴"
|
||||
var ts = DateTime.Now - tm1minute;
|
||||
if (ts.TotalMinutes >= 1)
|
||||
{
|
||||
//리셋카운트
|
||||
_AutoResetCount();
|
||||
|
||||
//상태를 DB에 저장한다. 230314
|
||||
var tsrun = VAR.TIME.RUN(eVarTime.StatusReporttime);
|
||||
if (tsrun.TotalSeconds >= PUB.setting.StatusInterval) EEMStatus.UpdateStatusSQL(PUB.sm.Step, _extrun: true);
|
||||
|
||||
tm1minute = DateTime.Now;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region retgion"5분 time 루틴"
|
||||
ts = DateTime.Now - tm5minute;
|
||||
if (ts.TotalMinutes >= 5)
|
||||
{
|
||||
//남은디스크확인
|
||||
CheckFreeSpace();
|
||||
tm5minute = DateTime.Now;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//wat.Stop();
|
||||
//Console.WriteLine("disp time : " + wat.ElapsedMilliseconds.ToString() + "ms");
|
||||
displayOn = false;
|
||||
}
|
||||
|
||||
void Update_Count()
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.BeginInvoke(new System.Windows.Forms.MethodInvoker(Update_Count), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
lbCntDN.Text = PUB.counter.CountDn.ToString();
|
||||
lbCNtUP.Text = PUB.counter.CountUp.ToString();
|
||||
lbCntQA.Text = PUB.counter.CountQA.ToString();
|
||||
lbCntQC.Text = PUB.counter.CountQC.ToString();
|
||||
// lbCntPk.Text = PUB.counter.CountQa2.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
void Update_IOStatus()
|
||||
{
|
||||
int inputrow = 0;
|
||||
int inputcol = 0;
|
||||
|
||||
////비상정지는 깜박임으로 알려준다
|
||||
if (VAR.BOOL[eVarBool.EMERGENCY]) BlinkGridViewItem(IOState, inputrow, inputcol++, 2, 0);
|
||||
else IOState.setValue(inputrow, inputcol++, 0);
|
||||
|
||||
IOState.setTitle(inputrow, inputcol, "DIR:" + PUB.AGV.data.Direction.ToString()); IOState.setValue(inputrow, inputcol++, 0);
|
||||
IOState.setTitle(inputrow, inputcol, "MOV:" + PUB.AGV.data.Sts.ToString()); IOState.setValue(inputrow, inputcol++, 0);
|
||||
IOState.setTitle(inputrow, inputcol, "SPD:" + PUB.AGV.data.Speed.ToString()); IOState.setValue(inputrow, inputcol++, 0);
|
||||
IOState.setTitle(inputrow, inputcol, $"PBS:{PUB.AGV.data.guidesensor}"); IOState.setValue(inputrow, inputcol++, 0);
|
||||
|
||||
if (PUB.AGV.data.TagNo < 0)
|
||||
{
|
||||
IOState.setTitle(inputrow, inputcol, "(TAG)"); IOState.setValue(inputrow, inputcol++, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
IOState.setTitle(inputrow, inputcol, "T" + PUB.AGV.data.TagNo.ToString()); IOState.setValue(inputrow, inputcol++, 0);
|
||||
}
|
||||
if (PUB.AGV.data.CallNo < 0)
|
||||
{
|
||||
IOState.setTitle(inputrow, inputcol, "(CAL)");
|
||||
IOState.setValue(inputrow, inputcol++, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
IOState.setTitle(inputrow, inputcol, "CAL:" + PUB.AGV.data.CallNo.ToString());
|
||||
IOState.setValue(inputrow, inputcol++, 0);
|
||||
}
|
||||
|
||||
IOState.setTitle(inputrow, inputcol, "RUN"); IOState.setValue(inputrow, inputcol++, (PUB.AGV.system1.agv_run ? 1 : 0));
|
||||
IOState.setTitle(inputrow, inputcol, "MARK"); IOState.setValue(inputrow, inputcol++, (VAR.BOOL[eVarBool.MARK_SENSOR] ? 1 : 0));
|
||||
IOState.setTitle(inputrow, inputcol, "CHG"); IOState.setValue(inputrow, inputcol++, (PUB.AGV.system1.Battery_charging ? 1 : 0));
|
||||
IOState.setTitle(inputrow, inputcol, "ITM"); IOState.setValue(inputrow, inputcol++, (VAR.BOOL[eVarBool.ITEMON] ? 1 : 0));
|
||||
IOState.Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 가동중 40% 미만에서는 배터리 경고 메세지를 추가한다(리더)
|
||||
/// </summary>
|
||||
void Update_BatteryWarnSpeak()
|
||||
{
|
||||
if (PUB.BMS == null || PUB.BMS.BMSInformation.rsoc > 40) return;
|
||||
|
||||
//가동중이거나 수동모드에서는 메세지 알림한다
|
||||
if (PUB.AGV.system1.agv_run || VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
|
||||
{
|
||||
var timeoutsec = 15;
|
||||
if (PUB.BMS.IsValid == false) timeoutsec = 30;
|
||||
|
||||
var tswarnmsg = VAR.TIME.RUN(eVarTime.BatWarnTime);
|
||||
if (tswarnmsg.TotalSeconds >= timeoutsec)
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == false && VAR.BOOL[eVarBool.FLAG_CHARGEONA] == false)
|
||||
{
|
||||
if (PUB.BMS.IsValid == false)
|
||||
{
|
||||
PUB.Speak(Lang.배터리통신에문제가있습니다);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
|
||||
PUB.Speak(Lang.충전이필요합니다자동모드로전환하세요);
|
||||
else
|
||||
PUB.Speak(Lang.충전이필요합니다);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//충전중이므로 메세지처리를 하지 않는다
|
||||
}
|
||||
|
||||
|
||||
VAR.TIME.Update(eVarTime.BatWarnTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 가동중일때 음악이 나오게 한다
|
||||
/// </summary>
|
||||
void Update_Music()
|
||||
{
|
||||
if (PUB.mplayer == null) return;
|
||||
if (PUB.mplayer != null && !string.IsNullOrEmpty(PUB.mplayer.SoundLocation) && PUB.bPlayMusic)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
if (PUB.bPlayMusic)
|
||||
{
|
||||
PUB.mplayer.Stop();
|
||||
PUB.bPlayMusic = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (PUB.setting.Enable_Music && PUB.mplayer != null && !string.IsNullOrEmpty(PUB.mplayer.SoundLocation))
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
if (PUB.bPlayMusic == false)
|
||||
{
|
||||
PUB.mplayer.Play();
|
||||
PUB.bPlayMusic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update_SSStatus()
|
||||
{
|
||||
if (PUB.sm.IsThreadRun) SSInfo.setValue(0, 0, 0);
|
||||
else SSInfo.setValue(0, 0, 2);
|
||||
|
||||
var runspeed = PUB.sm.RunSpeed.TotalMilliseconds;
|
||||
SSInfo.setTitle(0, 0, $"{PUB.sm.Step}\n{runspeed:N1} ms");
|
||||
|
||||
if (runspeed > 9)
|
||||
SSInfo.setValue(0, 0, 2);
|
||||
else if (runspeed > 4)
|
||||
SSInfo.setValue(0, 0, 3);
|
||||
else
|
||||
SSInfo.setValue(0, 0, 0);
|
||||
|
||||
|
||||
SSInfo.setTitle(1, 0, string.Format("{0}({1})", PUB.sm.RunStep, PUB.sm.RunStepSeq));
|
||||
if (PUB.sm.Step == eSMStep.RUN)
|
||||
SSInfo.setTitle(1, 1, string.Format("{0:N1} sec", PUB.sm.GetRunSteptime.TotalSeconds));
|
||||
else
|
||||
SSInfo.setTitle(1, 1, "--");
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 환경설정에따른 카운트를 리셋처리한다. 171128
|
||||
/// </summary>
|
||||
void _AutoResetCount()
|
||||
{
|
||||
if (PUB.setting.datetime_Check_1 && PUB.setting.datetime_Reset_1 != "") //오전
|
||||
{
|
||||
try
|
||||
{
|
||||
DateTime SetTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + PUB.setting.datetime_Reset_1 + ":00");
|
||||
DateTime LastClearTime = PUB.counter.CountReset;
|
||||
|
||||
//현재 시간이 클리어대상 시간보다 크고, 마지막으로 클리어한 시간이 지정시간보다 작아야함
|
||||
if (DateTime.Now > SetTime && LastClearTime < SetTime)
|
||||
{
|
||||
PUB.log.AddI("Count Reset #1");
|
||||
PUB.counter.CountClear();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
if (PUB.setting.datetime_Check_2 && PUB.setting.datetime_Reset_2 != "") //오후
|
||||
{
|
||||
try
|
||||
{
|
||||
DateTime SetTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd") + " " + PUB.setting.datetime_Reset_2 + ":00");
|
||||
DateTime LastClearTime = PUB.counter.CountReset;
|
||||
|
||||
//현재 시간이 클리어대상 시간보다 크고, 마지막으로 클리어한 시간이 지정시간보다 작아야함
|
||||
if (DateTime.Now > SetTime && LastClearTime < SetTime)
|
||||
{
|
||||
PUB.log.AddI("Count Reset #2");
|
||||
PUB.counter.CountClear();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
DateTime tm1minute = DateTime.Now.AddDays(-1);
|
||||
DateTime tm5minute = DateTime.Now;
|
||||
|
||||
void UpdateProgressStatus(double value, double max, string title)
|
||||
{
|
||||
UpdateProgressStatus((float)value, (float)max, title);
|
||||
}
|
||||
|
||||
void UpdateProgressStatus(float value, float max, string title = "")
|
||||
{
|
||||
if (PUB.Result.SMSG_ProgressEnable == false) PUB.Result.SMSG_ProgressEnable = true;
|
||||
if (PUB.Result.SMSG_ProgressMax != max) PUB.Result.SMSG_ProgressMax = max;
|
||||
if (PUB.Result.SMSG_ProgressValue != value)
|
||||
{
|
||||
if (value < max) PUB.Result.SMSG_ProgressValue = value;
|
||||
else PUB.Result.SMSG_ProgressValue = max;
|
||||
}
|
||||
if (PUB.Result.SMSG_ProgressForeColor != Color.White)
|
||||
PUB.Result.SMSG_ProgressForeColor = Color.White;
|
||||
|
||||
if (title != "")
|
||||
if (VAR.STR[eVarString.StatusMessage].Equals(title) == false) VAR.STR[eVarString.StatusMessage] = title;
|
||||
}
|
||||
|
||||
void UpdateStatusMessage(string dispmsg, Color fcolor, Color shadow)
|
||||
{
|
||||
UpdateStatusMessage(dispmsg, Color.DimGray, Color.Gray, fcolor, shadow);
|
||||
}
|
||||
|
||||
void UpdateStatusMessage(string dispmsg, Color bColor, Color bColor2, Color fcolor, Color shadow, Boolean blank = false)
|
||||
{
|
||||
|
||||
//if (lbMsg.ProgressEnable == true) lbMsg.ProgressEnable = false;
|
||||
if (dispmsg != VAR.STR[eVarString.StatusMessage] || PUB.Result.SMSG_ForeColor != fcolor ||
|
||||
PUB.Result.SMSG_ShadowColor != shadow
|
||||
|| (PUB.Result.SMSG_BackColor != bColor && PUB.Result.SMSG_BackColor2 != bColor))
|
||||
{
|
||||
PUB.Result.SMSG_BackColor = bColor;
|
||||
PUB.Result.SMSG_BackColor2 = bColor2;
|
||||
PUB.Result.SMSG_ForeColor = fcolor;
|
||||
PUB.Result.SMSG_ShadowColor = shadow;
|
||||
VAR.STR[eVarString.StatusMessage] = dispmsg;
|
||||
if (blank) PUB.Result.SMSG_Tag = "BLANK";
|
||||
else PUB.Result.SMSG_Tag = null;
|
||||
//PUB.Result.UpdateStatusMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Update_StatusMessage()
|
||||
{
|
||||
//최우선 점검 사항 표시
|
||||
if (PUB.sm.Step > eSMStep.INIT)
|
||||
{
|
||||
//오류가 있다면 오류를 표시해준다.
|
||||
if (PUB.AGV.IsOpen == false )
|
||||
{
|
||||
UpdateStatusMessage("AGV 연결실패", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if(PUB.AGV.IsValid==false)
|
||||
{
|
||||
UpdateStatusMessage("AGV 통신상태 불량", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if (PUB.AGV.error.Emergency)
|
||||
{
|
||||
if (PUB.AGV.error.runerror_by_no_magent_line)
|
||||
{
|
||||
UpdateStatusMessage("마그넷이 감지 되지 않습니다", Color.Tomato, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateStatusMessage("비상 정지", Color.Tomato, Color.Black);
|
||||
}
|
||||
}
|
||||
else if (PUB.BMS != null || PUB.BMS.IsOpen==false)
|
||||
{
|
||||
UpdateStatusMessage("BMS가 연결되지 않았습니다", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if (PUB.BMS != null || PUB.BMS.IsValid == false)
|
||||
{
|
||||
UpdateStatusMessage("BMS 통신상태 불량", Color.Tomato, Color.Black);
|
||||
}
|
||||
//else if (PUB.PLC.IsOpen == false)
|
||||
//{
|
||||
// UpdateStatusMessage(Lang.PLC연결실패, Color.Tomato, Color.Black);
|
||||
//}
|
||||
//else if (PUB.PLC.IsValid == false)
|
||||
//{
|
||||
// UpdateStatusMessage(Lang.PLC통신실패, Color.Tomato, Color.Black);
|
||||
//}
|
||||
else if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] == true)
|
||||
{
|
||||
//남은 충전시간 계산
|
||||
string msg = string.Empty;
|
||||
if (PUB.BMS.BMSInformation.rsoc < PUB.setting.ChargeEmergencyLevel)
|
||||
{
|
||||
msg = $"충전 진행 중(이동 불가)\n저전압으로 인해 사용이 불가 합니다";
|
||||
}
|
||||
else
|
||||
{
|
||||
var remaintime = VAR.TIME.RUN(eVarTime.ChargeStart);
|
||||
var remainsec = PUB.setting.ChargeMaxTime - remaintime.TotalSeconds;
|
||||
msg = "충전 진행 중 (이동 불가) " + remainsec.ToString("N0") + "초 후 충전이 자동 OFF 됩니다";
|
||||
}
|
||||
UpdateStatusMessage(msg, Color.Orange, Color.Black);
|
||||
}
|
||||
else if (VAR.BOOL[eVarBool.FLAG_CHARGEONM] == true)// PUB.flag.get(EFlag.FLAG_CHARGEONM) == true)
|
||||
{
|
||||
UpdateStatusMessage("충전(수동) 진행 중 (이동 불가)", Color.Orange, Color.Black);
|
||||
}
|
||||
else if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
UpdateStatusMessage(Lang.AGV연결실패, Color.Tomato, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PUB.sm.Step == eSMStep.IDLE)
|
||||
{
|
||||
if (PUB.AGV.system1.agv_run)
|
||||
{
|
||||
if (PUB.AGV.system1.stop_by_front_detect)
|
||||
UpdateStatusMessage("장애물로 인한 일시 정지", Color.SkyBlue, Color.Black);
|
||||
else
|
||||
UpdateStatusMessage("AGV 이동 중", Color.SkyBlue, Color.Black);
|
||||
}
|
||||
else if (PUB.AGV.error.Emergency)
|
||||
{
|
||||
if (PUB.AGV.error.runerror_by_no_magent_line)
|
||||
{
|
||||
UpdateStatusMessage("비상 정지 : 마그넷 라인이 감지 안됨", Color.SkyBlue, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateStatusMessage("비상 정지", Color.SkyBlue, Color.Black);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var smg = "(작업을 시작 하려면 [AUTO]로 전환 하세요)";
|
||||
UpdateStatusMessage(smg, Color.SkyBlue, Color.Black);
|
||||
}
|
||||
}
|
||||
else if (PUB.sm.Step == eSMStep.RUN)
|
||||
{
|
||||
|
||||
string stMsg;
|
||||
if (PUB.AGV.system1.stop_by_front_detect)//.GetValueI(arDev.FakePLC.DIName.PINI_LIDAR_STOP))
|
||||
stMsg = Lang.전방에물체가감지되었습니다;
|
||||
//else if (PUB.PLC.GetValueI(arDev.FakePLC.DIName.PINI_EMG))
|
||||
// stMsg = Lang.비상정지신호가감지되었습니다;
|
||||
else if (PUB.AGV.signal1.front_gate_out == true)
|
||||
stMsg = Lang.선로를이탈했습니다;
|
||||
else if (PUB.AGV.error.runerror_by_no_magent_line)
|
||||
stMsg = "마그네틱 라인을 벗어났습니다";
|
||||
else
|
||||
{
|
||||
stMsg = "자동 대기";
|
||||
if (PUB.setting.Enable_AutoCharge)
|
||||
{
|
||||
var tsIdle = VAR.TIME.RUN(eVarTime.ReadyStart);
|
||||
var remainTry = (int)(PUB.setting.ChargeRetryTerm - tsIdle.TotalSeconds);
|
||||
var progMax = PUB.setting.ChargeRetryTerm;
|
||||
stMsg += " / (" + remainTry.ToString() + ") 초 후 충전을 시작 합니다";
|
||||
UpdateProgressStatus(tsIdle.TotalSeconds, progMax, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
stMsg += "(자동충전 해제됨)";
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatusMessage(stMsg, Color.SkyBlue, Color.Black);
|
||||
//자동 충전 대기상태를 프로그레시브로 표시한다
|
||||
|
||||
|
||||
if (PUB.AGV.system1.stop_by_front_detect == true)
|
||||
{
|
||||
UpdateStatusMessage("이동 방향 근접거리 물체 감지(이동 불가 - 일시정지)", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if (VAR.BOOL[eVarBool.OVERLOAD] == true)
|
||||
{
|
||||
UpdateStatusMessage("오버로드 감지(안전커버를 확인하세요)", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if (PUB.AGV.error.runerror_by_no_magent_line)
|
||||
{
|
||||
UpdateStatusMessage("마그네틱 라인을 벗어 났습니다", Color.Black, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VAR.BOOL[eVarBool.WAIT_COVER_DOWN] == true)
|
||||
{
|
||||
UpdateStatusMessage(Lang.안전커버를내려주세요, Color.Lime, Color.Black);
|
||||
}
|
||||
else if (VAR.BOOL[eVarBool.WAIT_COVER_UP] == true)
|
||||
{
|
||||
UpdateStatusMessage(Lang.안전커버를올려주세요, Color.Lime, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PUB.sm.RunStep == ERunStep.BUFFER_IN)
|
||||
{
|
||||
if (PUB.sm.RunStepSeq == 1)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("하차 이동 전 (현재 위치 검색)", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else UpdateStatusMessage(String.Format("하차 이동 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.BUFFER_OUT)
|
||||
{
|
||||
if (PUB.sm.RunStepSeq == 1)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("상차 이동 전 (현재 위치 검색)", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else UpdateStatusMessage(String.Format("상차 이동 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.LOADER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("로더 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.LOADER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("로더 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.UNLOADER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("언로더 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.UNLOADER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("언로더 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.CLEANER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("클리너 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.CLEANER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("클리너 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.GOCHARGE)
|
||||
{
|
||||
if (PUB.Result.result_message.isEmpty() == true)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("충전기로 이동 중"), Color.Lime, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PUB.Result.result_progressmax > 0)
|
||||
UpdateProgressStatus(PUB.Result.result_progressvalue, PUB.Result.result_progressmax, PUB.Result.result_message);
|
||||
else
|
||||
UpdateStatusMessage(PUB.Result.result_message, Color.Lime, Color.Black);
|
||||
}
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.CHARGECHECK)
|
||||
{
|
||||
if (PUB.Result.result_message.isEmpty() == true)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("충전기 작동 확인 중"), Color.Lime, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PUB.Result.result_progressmax > 0)
|
||||
UpdateProgressStatus(PUB.Result.result_progressvalue, PUB.Result.result_progressmax, PUB.Result.result_message);
|
||||
else
|
||||
UpdateStatusMessage(PUB.Result.result_message, Color.Lime, Color.Black);
|
||||
}
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.GOHOME)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("홈(QC) 이동 중", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
//충전준비상태라면 관련 정보를 표시한다 230117
|
||||
if (VAR.BOOL[eVarBool.CHARGE_READY])
|
||||
{
|
||||
var sec = VAR.I32[eVarInt32.ChargeWaitSec];
|
||||
UpdateStatusMessage($"{sec} 초 후 충전이 시작 됩니다", Color.Lime, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
var msg = $"대기상태(현재위치:{PUB.Result.CurrentPos}/대상위치:{PUB.Result.TargetPos})";
|
||||
if (PUB.setting.Enable_AutoCharge) msg += "(자동충전:ON)";
|
||||
else msg += "(자동충전:OFF)";
|
||||
UpdateStatusMessage(msg, Color.Lime, Color.Black);
|
||||
}
|
||||
|
||||
//UpdateStatusMessage(String.Format("--", Pub.Result.TargetPos), Color.White, Color.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (PUB.sm.Step == eSMStep.ERROR)
|
||||
{
|
||||
UpdateStatusMessage("오류 발생", Color.Red, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.Step == eSMStep.PAUSE)
|
||||
{
|
||||
UpdateStatusMessage("정지 됨", Color.Tomato, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.Step == eSMStep.FINISH)
|
||||
{
|
||||
UpdateStatusMessage("작업 완료", Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.bPause == true)
|
||||
{
|
||||
UpdateStatusMessage("[START]를 누르면 시작 됩니다", Color.Yellow, Color.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = "진행 중";
|
||||
UpdateStatusMessage(msg, Color.Lime, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
322
HMI/Project/StateMachine/_Xbee.cs
Normal file
322
HMI/Project/StateMachine/_Xbee.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AGVNavigationCore.Models;
|
||||
using AGVNavigationCore.PathFinding.Core;
|
||||
using AGVNavigationCore.PathFinding.Planning;
|
||||
using AGVNavigationCore.Utils;
|
||||
using AR;
|
||||
using arDev;
|
||||
using COMM;
|
||||
using Project.StateMachine;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
|
||||
private void XBE_ProtocReceived(object sender, ENIG.EEProtocol.DataEventArgs e)
|
||||
{
|
||||
//TODO : 기능 처리필요 (XBee 메세지 데이터처리)
|
||||
//PUB.CheckManualChargeMode() : 수동충전확인
|
||||
//VAR.BOOL[eVarBool.FLAG_AUTORUN] : 자동실행
|
||||
//PUB.Speak("현재 위치는 QA 입니다.") : 음성출력
|
||||
|
||||
//ACS 수신 데이터 처리(타 장비는 확인하지 않는다)
|
||||
if (e.ReceivedPacket.ID == 0)
|
||||
{
|
||||
var logPrefix = "ACS";
|
||||
var data = e.ReceivedPacket.Data;
|
||||
var cmd = (ENIGProtocol.AGVCommandHE)e.ReceivedPacket.Command;
|
||||
if (data.Length < 1)
|
||||
{
|
||||
PUB.log.Add($"ACS 데이터에서 TARGET ID가 없습니다(data : first byte)");
|
||||
return;
|
||||
}
|
||||
|
||||
//대상디바이스
|
||||
var TargetID = data[0];
|
||||
|
||||
//해당 패킷의 대상이 나라면 처리한다.
|
||||
if (PUB.setting.XBE_ID != TargetID) return;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.SetCurrent: //Set Current Position
|
||||
Resultclear();
|
||||
|
||||
if (data.Length > 4)
|
||||
{
|
||||
var currTag = System.Text.Encoding.Default.GetString(data, 1, data.Length - 1);
|
||||
if (ushort.TryParse(currTag, out ushort currtagValue))
|
||||
{
|
||||
var node = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currtagValue);
|
||||
if (node == null)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-SetCurrent] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUB.log.AddI($"XBEE:현재위치설정:[{node.RfidId}]{node.Id}");
|
||||
}
|
||||
|
||||
PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, node, PUB._virtualAGV.CurrentDirection);
|
||||
PUB._virtualAGV.SetPosition(node, PUB._virtualAGV.CurrentDirection);
|
||||
}
|
||||
else PUB.log.AddE($"[{logPrefix}-SetCurrent] TagString Value Errorr:{data}");
|
||||
}
|
||||
else PUB.log.AddE($"[{logPrefix}-SetCurrent] TagString Lenght Errorr:{data.Length}");
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.PickOnEnter: // 110
|
||||
case ENIGProtocol.AGVCommandHE.PickOffEnter: // 111
|
||||
{
|
||||
Resultclear();
|
||||
PUB.log.AddI($"XBEE:작업명령수신:{cmd}");
|
||||
|
||||
// 현재 위치 확인 (TargetNode가 아닌 CurrentNode 기준)
|
||||
var currNode = PUB._virtualAGV.CurrentNode;
|
||||
if (currNode == null)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Current Node");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetNode = PUB._virtualAGV.TargetNode;
|
||||
if (targetNode == null)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-{cmd}] 목표 노드를 알 수 없습니다");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Target Node");
|
||||
return;
|
||||
}
|
||||
|
||||
//버퍼의 경우 직전에 멈추기 때문에 스테이션종류를 보정해준다
|
||||
var StationType = currNode.StationType;
|
||||
if (StationType == StationType.Normal && targetNode.StationType == StationType.Buffer)
|
||||
StationType = StationType.Buffer;
|
||||
|
||||
ERunStep nextStep = ERunStep.READY;
|
||||
switch (StationType)
|
||||
{
|
||||
case StationType.Loader: nextStep = ERunStep.LOADER_IN; break;
|
||||
case StationType.UnLoader: nextStep = ERunStep.UNLOADER_IN; break;
|
||||
case StationType.Buffer: nextStep = ERunStep.BUFFER_IN; break;
|
||||
case StationType.Clearner: nextStep = ERunStep.CLEANER_IN; break;
|
||||
default:
|
||||
PUB.log.AddE($"[{logPrefix}-{cmd}] 해당 노드타입({StationType})은 작업을 지원하지 않습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
//다음명령처리
|
||||
PUB.NextWorkCmd = cmd;
|
||||
PUB.log.AddI($"작업 시작: {nextStep} (Type: {cmd})");
|
||||
PUB.sm.SetNewRunStep(nextStep);
|
||||
}
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.Charger: // 112
|
||||
{
|
||||
Resultclear();
|
||||
PUB.log.AddI($"XBEE:충전명령수신");
|
||||
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Charger;
|
||||
PUB.sm.SetNewRunStep(ERunStep.GOCHARGE);
|
||||
}
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.GotoAlias:
|
||||
case ENIGProtocol.AGVCommandHE.Goto: //move to tag
|
||||
Resultclear();
|
||||
var datalength = cmd == ENIGProtocol.AGVCommandHE.GotoAlias ? 2 : 1;
|
||||
if (data.Length > datalength)
|
||||
{
|
||||
var currTag = System.Text.Encoding.Default.GetString(data, 1, data.Length - 1).Trim();
|
||||
MapNode targetNode = null;
|
||||
if (cmd == ENIGProtocol.AGVCommandHE.GotoAlias)
|
||||
{
|
||||
targetNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.AliasName == currTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ushort.TryParse(currTag, out ushort currtagvalue))
|
||||
targetNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == currtagvalue);
|
||||
else PUB.log.Add($"targstring 이 숫자가 아니라서 대상을 설정할 수 없습니다 값:{currTag}");
|
||||
}
|
||||
|
||||
if (targetNode != null)
|
||||
{
|
||||
//자동상태가아니라면 처리하지 않는다.
|
||||
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-Goto] 자동실행상태가 아닙니다");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.ManualMode, $"{currTag}");
|
||||
return;
|
||||
}
|
||||
|
||||
//목적지
|
||||
PUB._virtualAGV.TargetNode = targetNode;
|
||||
if (targetNode == null)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-Goto] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
|
||||
return;
|
||||
}
|
||||
|
||||
///출발지
|
||||
var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB._virtualAGV.CurrentNode.RfidId);
|
||||
PUB._virtualAGV.StartNode = startNode;
|
||||
if (startNode == null)
|
||||
{
|
||||
PUB.log.AddE($"[{logPrefix}-Goto] 시작노드가 없습니다(현재위치 없음) NodeID:{PUB._virtualAGV.CurrentNode.Id}");
|
||||
}
|
||||
|
||||
//대상이동으로 처리한다.
|
||||
if (PUB.sm.RunStep != ERunStep.GOTO)
|
||||
{
|
||||
PUB.sm.SetNewRunStep(StateMachine.ERunStep.GOTO);
|
||||
PUB.sm.ResetRunStepSeq();
|
||||
}
|
||||
|
||||
|
||||
//Move to
|
||||
PUB.log.Add($"[{logPrefix}-{cmd}] {startNode.RfidId} -> {targetNode.RfidId}");
|
||||
}
|
||||
else PUB.log.AddE($"[{logPrefix}-{cmd}] 대상노드가 없습니다 {data}");
|
||||
}
|
||||
else PUB.log.AddE($"[{logPrefix}-{cmd}] Length Error:{data.Length}");
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.LTurn180:
|
||||
PUB.log.Add($"[{logPrefix}-LTurn180]");
|
||||
PUB.AGV.AGVMoveLeft180Turn();
|
||||
break;
|
||||
case ENIGProtocol.AGVCommandHE.RTurn180:
|
||||
PUB.log.Add($"[{logPrefix}-RTurn180]");
|
||||
PUB.AGV.AGVMoveRight180Turn();
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.LTurn:
|
||||
PUB.log.Add($"[{logPrefix}-LTurn]");
|
||||
PUB.AGV.AGVMoveManual(arDev.Narumi.ManulOpt.LT, arDev.Narumi.Speed.Low, arDev.Narumi.Sensor.AllOn);
|
||||
break;
|
||||
case ENIGProtocol.AGVCommandHE.RTurn:
|
||||
PUB.log.Add($"[{logPrefix}-RTurn]");
|
||||
PUB.AGV.AGVMoveManual(arDev.Narumi.ManulOpt.RT, arDev.Narumi.Speed.Low, arDev.Narumi.Sensor.AllOn);
|
||||
break;
|
||||
case ENIGProtocol.AGVCommandHE.Stop: //stop
|
||||
PUB.log.Add($"[{logPrefix}-Stop]");
|
||||
PUB.AGV.AGVMoveStop("xbee");
|
||||
break;
|
||||
case ENIGProtocol.AGVCommandHE.Reset: //Error Reset
|
||||
PUB.log.Add($"[{logPrefix}-Reset]");
|
||||
ResetSystemError();
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.Manual: //Manual Move (Direction, speed, runtime)
|
||||
Resultclear();
|
||||
var Direction = data[1]; //0=back, 1=forward, 2=left, 3=right
|
||||
var Speed = data[2]; //0=slow, 1=normal, 2=fast
|
||||
|
||||
arDev.Narumi.ManulOpt opt = arDev.Narumi.ManulOpt.BS;
|
||||
arDev.Narumi.Speed spd = arDev.Narumi.Speed.Low;
|
||||
if (Speed == 1) spd = arDev.Narumi.Speed.Mid;
|
||||
else if (Speed == 2) spd = arDev.Narumi.Speed.High;
|
||||
|
||||
//0.자동모드가 아니라면 실행하지 않는다
|
||||
//1.입력된 파라미터로 AGV를 이동한다
|
||||
if (Direction == 0) opt = arDev.Narumi.ManulOpt.BS;
|
||||
else if (Direction == 1) opt = arDev.Narumi.ManulOpt.FS;
|
||||
else if (Direction == 2) opt = arDev.Narumi.ManulOpt.LT;
|
||||
else if (Direction == 3) opt = arDev.Narumi.ManulOpt.RT;
|
||||
|
||||
PUB.log.Add($"[{logPrefix}-Manual] DIR:{opt},SPD:{spd}");
|
||||
PUB.AGV.AGVMoveManual(opt, spd, arDev.Narumi.Sensor.PBSOn);
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.AutoMove:
|
||||
Resultclear();
|
||||
var MotDirection = data[1]; //0=back, 1=forward
|
||||
var MagDirection = data[2]; //0=straight, 1=left, 2=right
|
||||
var AutSpeed = data[3]; //0=slow, 1=normal, 2=fast
|
||||
var Lidar = data[4]; //0=off, 1=on
|
||||
|
||||
var bunkidata = new arDev.Narumi.BunkiData();
|
||||
|
||||
//speed;
|
||||
if (AutSpeed == 1) bunkidata.Speed = arDev.Narumi.eMoveSpd.Mid;
|
||||
else if (AutSpeed == 2) bunkidata.Speed = arDev.Narumi.eMoveSpd.High;
|
||||
else bunkidata.Speed = arDev.Narumi.eMoveSpd.Low;
|
||||
|
||||
//motor direction
|
||||
if (MotDirection == 0) bunkidata.Direction = arDev.Narumi.eMoveDir.Backward;
|
||||
else bunkidata.Direction = arDev.Narumi.eMoveDir.Forward;
|
||||
|
||||
if (MagDirection == 2) bunkidata.Bunki = arDev.Narumi.eBunki.Right;
|
||||
else if (MagDirection == 1) bunkidata.Bunki = arDev.Narumi.eBunki.Left;
|
||||
else bunkidata.Bunki = arDev.Narumi.eBunki.Strate;
|
||||
|
||||
if (Lidar == 0) bunkidata.PBSSensor = 0;
|
||||
else bunkidata.PBSSensor = 2;
|
||||
|
||||
PUB.log.Add($"[{logPrefix}-AutoMove] DIR:{bunkidata.Direction}-{bunkidata.Bunki},SPD:{bunkidata.Speed}");
|
||||
|
||||
if (PUB.AGV.AGVMoveSet(bunkidata) != eNarumiCommandResult.Success)
|
||||
PUB.log.AddE($"AGV속도설정실패로 인해 자동전환이 실패되었습니다");
|
||||
else
|
||||
{
|
||||
PUB.log.Add($"XBE 에서 자동모드로 전환합니다");
|
||||
PUB.AGV.AGVMoveRun((MotDirection == 0 ? arDev.Narumi.eRunOpt.Backward : arDev.Narumi.eRunOpt.Forward));
|
||||
}
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.MarkStop: //Set MarkStop
|
||||
//마크센서에서 멈추게 한다
|
||||
PUB.log.Add($"[{logPrefix}-MarkStop]");
|
||||
PUB.AGV.AGVMoveStop("Xbee", arDev.Narumi.eStopOpt.MarkStop);
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.LiftControl: //Lift Control
|
||||
var LiftCommand = data[1]; //0=stop, 1=up, 2=down
|
||||
|
||||
arDev.Narumi.LiftCommand LCmd = arDev.Narumi.LiftCommand.STP;
|
||||
if (LiftCommand == 1) LCmd = arDev.Narumi.LiftCommand.UP;
|
||||
else if (LiftCommand == 2) LCmd = arDev.Narumi.LiftCommand.DN;
|
||||
|
||||
PUB.log.Add($"[{logPrefix}-LiftControl] {LCmd}");
|
||||
PUB.AGV.LiftControl(LCmd); //리프트제어
|
||||
break;
|
||||
|
||||
case ENIGProtocol.AGVCommandHE.ChargeControl: //충전을 제어한다
|
||||
var chargeAction = data[1] == 1; //0= off, 1=on
|
||||
|
||||
//충전시퀀스가 진행되지 않았다면 진행한다
|
||||
if (PUB.sm.RunStep == StateMachine.ERunStep.GOCHARGE && PUB.sm.RunStepNew != StateMachine.ERunStep.GOCHARGE)
|
||||
{
|
||||
PUB.sm.SetNewRunStep(StateMachine.ERunStep.GOCHARGE);
|
||||
PUB.log.AddI($"충전을 시작합니다");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PUB.logagv.AddE($"Unknown Command : {cmd} Sender:{e.ReceivedPacket.ID}, Target:{data[0]}");
|
||||
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.UnknownCommand, $"{cmd}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void XBE_MessageReceived(object sender, Device.Xbee.MessageArgs e)
|
||||
{
|
||||
if (e.IsError) PUB.log.AddE(e.Message);
|
||||
else PUB.log.Add(e.Message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user