Implement ACS Command Handlers (PickOn, PickOff, Charge), Manual Mode Safety, and Map UI Commands

This commit is contained in:
2025-12-13 02:40:55 +09:00
parent 703e1387bf
commit 34b038c4be
25 changed files with 1992 additions and 295 deletions

View File

@@ -49,7 +49,9 @@ namespace Project.ViewForm
// 이벤트 연결
//PUB._mapCanvas.NodeAdded += OnNodeAdded;
//PUB._mapCanvas.NodeSelected += OnNodeSelected;
// 이벤트 연결
//PUB._mapCanvas.NodeAdded += OnNodeAdded;
PUB._mapCanvas.NodesSelected += OnNodeSelected;
//PUB._mapCanvas.NodeMoved += OnNodeMoved;
//PUB._mapCanvas.NodeDeleted += OnNodeDeleted;
//PUB._mapCanvas.ConnectionDeleted += OnConnectionDeleted;
@@ -58,6 +60,85 @@ namespace Project.ViewForm
// 스플리터 패널에 맵 캔버스 추가
panel1.Controls.Add(PUB._mapCanvas);
}
private void OnNodeSelected(object sender, List<MapNode> nodes, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
var node = nodes.FirstOrDefault();
if (nodes == null) return;
// 도킹 가능한 노드인지 또는 작업 노드인지 확인
bool isDockingNode = node.Type == NodeType.Loader || node.Type == NodeType.UnLoader
|| node.Type == NodeType.Buffer || node.Type == NodeType.Clearner
|| node.Type == NodeType.Charging;
if (!isDockingNode) return;
ContextMenuStrip menu = new ContextMenuStrip();
// PickOn
var pickOn = new ToolStripMenuItem("Pick On (Move & Pick)");
pickOn.Click += (s, args) => ExecuteManualCommand(node, ENIGProtocol.AGVCommandHE.PickOn);
menu.Items.Add(pickOn);
// PickOff
var pickOff = new ToolStripMenuItem("Pick Off (Move & Drop)");
pickOff.Click += (s, args) => ExecuteManualCommand(node, ENIGProtocol.AGVCommandHE.PickOff);
menu.Items.Add(pickOff);
// Charge
if (node.Type == NodeType.Charging)
{
var charge = new ToolStripMenuItem("Charge (Move & Charge)");
charge.Click += (s, args) => ExecuteManualCommand(node, ENIGProtocol.AGVCommandHE.Charger);
menu.Items.Add(charge);
}
menu.Show(Cursor.Position);
}
private void ExecuteManualCommand(MapNode targetNode, ENIGProtocol.AGVCommandHE cmd)
{
if (PUB._virtualAGV.CurrentNode == null)
{
MessageBox.Show("AGV의 현재 위치를 알 수 없습니다.");
return;
}
if (PUB.sm.RunStep != eSMStep.IDLE && PUB.sm.RunStep != eSMStep.READY)
{
if (MessageBox.Show("현재 대기상태가 아닙니다. 강제로 실행하시겠습니까?", "Warning", MessageBoxButtons.YesNo) == DialogResult.No) return;
}
// 1. 경로 생성
var pathFinder = new AGVNavigationCore.PathFinding.Planning.AGVPathfinder(PUB._mapNodes);
// 현재위치에서 목표위치까지
var result = pathFinder.FindPath(PUB._virtualAGV.CurrentNode, targetNode);
if (!result.Success || result.Path == null || result.Path.Count == 0)
{
MessageBox.Show("경로를 찾을 수 없습니다.");
return;
}
// 2. 상태 설정
PUB.log.AddI($"[Manual Command] {cmd} to {targetNode.Name}({targetNode.NodeId})");
// Path 변환 (Node 리스트 -> AGVPathResult)
// VirtualAGV.SetPath가 필요할 수 있음. 혹은 Goto 로직을 수동으로 구성.
// _SM_RUN_GOTO에서는 PUB._virtualAGV.CurrentPath를 사용함.
// AGVPathResult 생성 필요.
var detailedPath = AGVNavigationCore.PathFinding.Planning.AGVPathfinder.MakeDetailData(result.Path, PUB._mapNodes);
PUB._virtualAGV.SetPath(result.Path, detailedPath);
PUB._virtualAGV.TargetNode = targetNode;
// 3. 작업 설정
PUB.NextWorkCmd = cmd;
// 4. 실행
PUB.sm.SetNewRunStep(ERunStep.GOTO); // GOTO -> Arrive -> _IN sequence execution
}
// 툴바 버튼 이벤트 연결
//WireToolbarButtonEvents();
@@ -85,8 +166,8 @@ namespace Project.ViewForm
//맵파일로딩
if (PUB.setting.LastMapFile.isEmpty()) PUB.setting.LastMapFile = System.IO.Path.Combine(mapPath.FullName, "default.agvmap");
System.IO.FileInfo filePath = new System.IO.FileInfo(PUB.setting.LastMapFile);
if (filePath.Exists == false) filePath = new System.IO.FileInfo(System.IO.Path.Combine(mapPath.FullName,"default.agvmap"));
if(filePath.Exists==false) //그래도없다면 맵폴더에서 파일을 찾아본다.
if (filePath.Exists == false) filePath = new System.IO.FileInfo(System.IO.Path.Combine(mapPath.FullName, "default.agvmap"));
if (filePath.Exists == false) //그래도없다면 맵폴더에서 파일을 찾아본다.
{
var files = mapPath.GetFiles("*.agvmap");
if (files.Any()) filePath = files[0];
@@ -105,7 +186,7 @@ namespace Project.ViewForm
// 맵 캔버스에 데이터 설정
PUB._mapCanvas.Nodes = PUB._mapNodes;
PUB._mapCanvas.MapFileName = filePath.FullName;
// 🔥 맵 설정 적용 (배경색, 그리드 표시)
if (result.Settings != null)
{
@@ -120,6 +201,7 @@ namespace Project.ViewForm
if (startNode != null)
{
PUB._virtualAGV = new VirtualAGV(PUB.setting.MCID, startNode.Position, AgvDirection.Forward);
PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
PUB._virtualAGV.SetPosition(startNode, AgvDirection.Forward);
// 캔버스에 AGV 리스트 설정
@@ -131,6 +213,7 @@ namespace Project.ViewForm
}
else if (PUB._virtualAGV != null)
{
PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
// 기존 AGV가 있으면 캔버스에 다시 연결
var agvList = new System.Collections.Generic.List<AGVNavigationCore.Controls.IAGV> { PUB._virtualAGV };
PUB._mapCanvas.AGVList = agvList;