"feat:Enable-hover-highlight-and-refactor"

This commit is contained in:
2025-12-14 17:20:50 +09:00
parent 34b038c4be
commit 764fbbd204
48 changed files with 3980 additions and 2750 deletions

View File

@@ -227,8 +227,10 @@ namespace Project
/// <summary>
/// 시리얼 포트 연결 (arDev.arRS232)
/// </summary>
void ConnectSerialPort(arDev.arRS232 dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
bool ConnectSerialPort(arDev.arRS232 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);
@@ -246,8 +248,17 @@ namespace Project
}
else
{
var errmessage = dev.errorMessage;
PUB.log.AddE($"[AGV:{port}:{baud}] {errmessage}");
//존재하지 않는 포트라면 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);
@@ -264,6 +275,7 @@ namespace Project
dev.Close();
VAR.TIME.Update(conntry);
}
return true;
}
/// <summary>

View File

@@ -614,7 +614,7 @@ namespace Project
{
if (_mapNodes == null || _mapNodes.Any() == false) return null;
if (nodeidx.isEmpty()) return null;
return _mapNodes.Where(t => t.NodeId.Equals(nodeidx)).FirstOrDefault();
return _mapNodes.Where(t => t.Id.Equals(nodeidx)).FirstOrDefault();
}
public static MapNode FindByRFID(string rfidValue)
{
@@ -626,7 +626,7 @@ namespace Project
{
if (_mapNodes == null || _mapNodes.Any() == false) return null;
if (alias.isEmpty()) return null;
var lst = _mapNodes.Where(t => t.NodeAlias.Equals(alias));
var lst = _mapNodes.Where(t => t.AliasName.Equals(alias));
if (lst.Any() == false) return null;
return lst.ToList();
}
@@ -654,7 +654,7 @@ namespace Project
_virtualAGV.SetPosition(node, motorDirection);
RefreshAGVCanvas();
log.Add($"[AGV] RFID {rfidId} 감지 → 노드 {node.NodeId} 위치 업데이트 (방향: {motorDirection})");
log.Add($"[AGV] RFID {rfidId} 감지 → 노드 {node.Id} 위치 업데이트 (방향: {motorDirection})");
return true;
}
@@ -672,7 +672,7 @@ namespace Project
{
if (_virtualAGV == null || _mapNodes == null) return false;
var node = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
var node = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
if (node != null)
{
_virtualAGV.SetPosition(node, motorDirection);
@@ -744,42 +744,7 @@ namespace Project
}
}
/// <summary>
/// 현재 AGV의 노드 ID 가져오기
/// </summary>
/// <returns>현재 노드 ID</returns>
public static string GetCurrentAGVNodeId()
{
return _virtualAGV?.CurrentNodeId ?? string.Empty;
}
/// <summary>
/// 현재 AGV 위치 가져오기
/// </summary>
/// <returns>현재 위치</returns>
public static Point GetCurrentAGVPosition()
{
return _virtualAGV?.CurrentPosition ?? Point.Empty;
}
/// <summary>
/// 현재 AGV 방향 가져오기
/// </summary>
/// <returns>현재 방향</returns>
public static AgvDirection GetCurrentAGVDirection()
{
return _virtualAGV?.CurrentDirection ?? AgvDirection.Forward;
}
/// <summary>
/// 현재 AGV 상태 가져오기
/// </summary>
/// <returns>현재 상태</returns>
public static AGVState GetCurrentAGVState()
{
return _virtualAGV?.CurrentState ?? AGVState.Idle;
}
#endregion
}

View File

@@ -108,49 +108,30 @@ namespace Project
//목적지가 BUFFER라면 버퍼투입대기위치까지 완료했다는 시그널을 보낸다.
var target = PUB._virtualAGV.TargetNode;
PUB.log.Add($"목적지({target.RfidId}) 도착완료 타입:{target.Type}, 출발지:{PUB._virtualAGV.StartNode.RfidId}");
if (target.Type == AGVNavigationCore.Models.NodeType.Buffer)
switch(target.StationType)
{
//현재위치가 마지막경로의 NODEID와 일치해야한다
var lastPath = PUB._virtualAGV.CurrentPath.DetailedPath.LastOrDefault();
if (lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNodeId))
{
//버퍼진입전 노드에 도착완료했따
PUB.XBE.BufferInReady = true;
PUB.XBE.BufferReadyError = false;
}
else
{
//마지막위치가 아닌 다른 위치에 있으니 버퍼 작업을 할 수없다
PUB.log.AddAT("목적지 버퍼이동완료 했지만 마지막 노드가 아닙니다");
PUB.XBE.BufferInReady = false;
PUB.XBE.BufferReadyError = true;
}
PUB.XBE.BufferInComplete = false;
PUB.XBE.BufferOutComplete = false;
}
else if (target.Type == AGVNavigationCore.Models.NodeType.Charging)
{
}
else if (target.Type == AGVNavigationCore.Models.NodeType.Loader)
{
}
else if (target.Type == AGVNavigationCore.Models.NodeType.Clearner)
{
}
else if (target.Type == AGVNavigationCore.Models.NodeType.UnLoader)
{
}
else
{
//목적지다 다른 형태이다
case AGVNavigationCore.Models.StationType.Buffer:
//현재위치가 마지막경로의 NODEID와 일치해야한다
var lastPath = PUB._virtualAGV.CurrentPath.DetailedPath.LastOrDefault();
if (lastPath.NodeId.Equals(PUB._virtualAGV.CurrentNode.Id))
{
//버퍼진입전 노드에 도착완료했따
PUB.XBE.BufferInReady = true;
PUB.XBE.BufferReadyError = false;
}
else
{
//마지막위치가 아닌 다른 위치에 있으니 버퍼 작업을 할 수없다
PUB.log.AddAT("목적지 버퍼이동완료 했지만 마지막 노드가 아닙니다");
PUB.XBE.BufferInReady = false;
PUB.XBE.BufferReadyError = true;
}
PUB.XBE.BufferInComplete = false;
PUB.XBE.BufferOutComplete = false;
break;
}
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.None;
PUB.sm.SetNewRunStep(ERunStep.READY);
}

View File

@@ -13,7 +13,7 @@ namespace Project
public Boolean _SM_RUN_POSCHK(bool isFirst, TimeSpan stepTime)
{
//현재위치가 설정되어있는지 확인한다, 현재위치값이 있는 경우 True 를 반환
var currentnode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId);
var currentnode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNode.Id);
if (currentnode != null) return true;
//이동을 하지 않고있다면 전진을 진행한다

View File

@@ -24,8 +24,14 @@ namespace Project
if (PUB.AGV.IsOpen == false)
{
//agv connect
ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
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)
{
@@ -81,7 +87,7 @@ namespace Project
synlist.Add("SGS", PUB.setting.GDSValue.ToString("0000"));
VAR.I32[eVarInt32.SyncItemCount] = synlist.Count;
PUB.AddEEDB($"SYNC시작({PUB.Result.TargetPos})");
@@ -129,7 +135,7 @@ namespace Project
if (PUB.AGV.ACKData.Equals(item.Key))
{
synidx += 1;
if(ts.TotalSeconds < 0.15) PUB.sm.UpdateRunStepSeq(-2); //싱크중에 추가 지연시간 확보
if (ts.TotalSeconds < 0.15) PUB.sm.UpdateRunStepSeq(-2); //싱크중에 추가 지연시간 확보
else PUB.sm.UpdateRunStepSeq(-1);
LastCommandTime = DateTime.Now;
}
@@ -150,11 +156,11 @@ namespace Project
{
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;

View File

@@ -71,7 +71,7 @@ namespace Project
if (_SM_RUN_POSCHK(false, new TimeSpan()) == false) return false;
//현재위치노드 오류
var currentNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId);
var currentNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNode.Id);
if (currentNode == null)
{
PUB.log.AddE($"현재위치노드가 없습니다");
@@ -81,7 +81,7 @@ namespace Project
//시작노드값이 없다면 현재위치를 노드로 결정한다
if (PUB._virtualAGV.StartNode == null)
PUB._virtualAGV.StartNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNodeId);
PUB._virtualAGV.StartNode = PUB.FindByNodeID(PUB._virtualAGV.CurrentNode.Id);
//시작노드가없다면 오류
if (PUB._virtualAGV.StartNode == null)
@@ -102,7 +102,7 @@ namespace Project
//경로 생성(경로정보가 없거나 현재노드가 경로에 없는경우)
if (PUB._virtualAGV.CurrentPath == null ||
PUB._virtualAGV.CurrentPath.DetailedPath.Any() == false ||
PUB._virtualAGV.CurrentPath.DetailedPath.Where(t => t.NodeId.Equals(currentNode.NodeId)).Any() == false)
PUB._virtualAGV.CurrentPath.DetailedPath.Where(t => t.NodeId.Equals(currentNode.Id)).Any() == false)
{
if (PUB.AGV.system1.agv_run)
{
@@ -145,7 +145,7 @@ namespace Project
$"현재 상태: {PUB._virtualAGV.CurrentState}\n" +
$"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" +
$"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" +
$"현재 노드: {PUB._virtualAGV.CurrentNodeId ?? ""}";
$"현재 노드: {PUB._virtualAGV.CurrentNode.Id ?? ""}";
//모터에서 정지를 요청했다
if (nextAction.Motor == AGVNavigationCore.Models.MotorCommand.Stop)
@@ -169,11 +169,11 @@ namespace Project
// 현재 노드가 타겟 노드와 같고, 위치가 확정된 상태라면 도착으로 간주
// 단, AGV가 실제로 멈췄는지 확인 (agv_run == false)
if (PUB._virtualAGV.IsPositionConfirmed &&
PUB._virtualAGV.CurrentNodeId == PUB._virtualAGV.TargetNode.NodeId)
PUB._virtualAGV.CurrentNode.Id == PUB._virtualAGV.TargetNode.Id)
{
if (PUB.AGV.system1.agv_run == false)
{
PUB.log.AddI($"목표 도착 및 정지 확인됨(MarkStop 완료). Node:{PUB._virtualAGV.CurrentNodeId}");
PUB.log.AddI($"목표 도착 및 정지 확인됨(MarkStop 완료). Node:{PUB._virtualAGV.CurrentNode.Id}");
return true;
}
}
@@ -251,7 +251,7 @@ namespace Project
else
{
//현재위치가 충전위치이고, 움직이지 않았다면 완료된 경우라 할수 있따
if (PUB._virtualAGV.CurrentNodeId.Equals(PUB.setting.NodeMAP_RFID_Charger) &&
if (PUB._virtualAGV.CurrentNode.Id.Equals(PUB.setting.NodeMAP_RFID_Charger) &&
VAR.BOOL[eVarBool.MARK_SENSOR] == true)
{
PUB.log.AddI("충전위치 검색 완료");

View File

@@ -175,13 +175,10 @@ namespace Project
var newNodeId = $"AUTO_{PUB.Result.LastTAG}";
var newNode = new MapNode
{
NodeId = newNodeId,
Id = newNodeId,
RfidId = PUB.Result.LastTAG,
Name = $"자동추가_{PUB.Result.LastTAG}",
Type = NodeType.Normal,
Position = new Point(100, 100), // 기본 위치
IsActive = true,
DisplayColor = Color.Orange, // 자동 추가된 노드는 오렌지색으로 표시
CreatedDate = DateTime.Now,
ModifiedDate = DateTime.Now
};
@@ -232,7 +229,7 @@ namespace Project
$"현재 상태: {PUB._virtualAGV.CurrentState}\n" +
$"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" +
$"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" +
$"현재 노드: {PUB._virtualAGV.CurrentNodeId ?? ""}";
$"현재 노드: {PUB._virtualAGV.CurrentNode.Id ?? ""}";
PUB._mapCanvas.PredictMessage = message;
}

View File

@@ -8,6 +8,7 @@ using AGVNavigationCore.Utils;
using AR;
using arDev;
using COMM;
using Project.StateMachine;
namespace Project
{
@@ -56,7 +57,7 @@ namespace Project
}
else
{
PUB.log.AddI($"XBEE:현재위치설정:[{node.RfidId}]{node.NodeId}");
PUB.log.AddI($"XBEE:현재위치설정:[{node.RfidId}]{node.Id}");
}
PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, node, PUB._virtualAGV.CurrentDirection);
@@ -69,25 +70,25 @@ namespace Project
case ENIGProtocol.AGVCommandHE.PickOff: // 111
{
PUB.log.AddI($"XBEE:작업명령수신:{cmd}");
// 현재 위치 확인 (TargetNode가 아닌 CurrentNode 기준)
var currNode = PUB._virtualAGV.CurrentNode;
if (currNode == null)
{
PUB.log.AddE($"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다 NodeID:{PUB._virtualAGV.CurrentNodeId}");
PUB.log.AddE($"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다 NodeID:{PUB._virtualAGV.CurrentNode.Id}");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Node");
return;
}
PUB.NextWorkCmd = cmd;
ERunStep nextStep = ERunStep.IDLE;
ERunStep nextStep = ERunStep.READY;
switch (currNode.Type)
switch (currNode.StationType)
{
case NodeType.Loader: nextStep = ERunStep.LOADER_IN; break;
case NodeType.UnLoader: nextStep = ERunStep.UNLOADER_IN; break;
case NodeType.Buffer: nextStep = ERunStep.BUFFER_IN; break;
case NodeType.Clearner: nextStep = ERunStep.CLEANER_IN; break;
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}] 해당 노드타입({currNode.Type})은 작업을 지원하지 않습니다.");
return;
@@ -130,11 +131,11 @@ namespace Project
}
///출발지
var startNode = PUB._mapNodes.FirstOrDefault(t => t.RfidId == PUB._virtualAGV.CurrentNodeId);
var startNode = PUB._mapNodes.FirstOrDefault(t => t.RfidId == PUB._virtualAGV.CurrentNode.Id);
PUB._virtualAGV.StartNode = startNode;
if (startNode == null)
{
PUB.log.AddE($"[{logPrefix}-Goto] 시작노드가 없습니다(현재위치 없음) NodeID:{PUB._virtualAGV.CurrentNodeId}");
PUB.log.AddE($"[{logPrefix}-Goto] 시작노드가 없습니다(현재위치 없음) NodeID:{PUB._virtualAGV.CurrentNode.Id}");
}
if (startNode != null)

View File

@@ -51,7 +51,7 @@ namespace Project.ViewForm
//PUB._mapCanvas.NodeAdded += OnNodeAdded;
// 이벤트 연결
//PUB._mapCanvas.NodeAdded += OnNodeAdded;
PUB._mapCanvas.NodesSelected += OnNodeSelected;
PUB._mapCanvas.NodeSelect += OnNodeSelected;
//PUB._mapCanvas.NodeMoved += OnNodeMoved;
//PUB._mapCanvas.NodeDeleted += OnNodeDeleted;
//PUB._mapCanvas.ConnectionDeleted += OnConnectionDeleted;
@@ -62,40 +62,40 @@ namespace Project.ViewForm
panel1.Controls.Add(PUB._mapCanvas);
}
private void OnNodeSelected(object sender, List<MapNode> nodes, MouseEventArgs e)
private void OnNodeSelected(object sender, NodeBase node, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
var node = nodes.FirstOrDefault();
if (nodes == null) return;
if (node == null) return;
if ((node is MapNode mapnode) == false) 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;
if (mapnode.isDockingNode == false) return;
ContextMenuStrip menu = new ContextMenuStrip();
// PickOn
var pickOn = new ToolStripMenuItem("Pick On (Move & Pick)");
pickOn.Click += (s, args) => ExecuteManualCommand(node, ENIGProtocol.AGVCommandHE.PickOn);
pickOn.Click += (s, args) => ExecuteManualCommand(mapnode, 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);
pickOff.Click += (s, args) => ExecuteManualCommand(mapnode, ENIGProtocol.AGVCommandHE.PickOff);
menu.Items.Add(pickOff);
// Charge
if (node.Type == NodeType.Charging)
if (mapnode.StationType == StationType.Charger)
{
var charge = new ToolStripMenuItem("Charge (Move & Charge)");
charge.Click += (s, args) => ExecuteManualCommand(node, ENIGProtocol.AGVCommandHE.Charger);
charge.Click += (s, args) => ExecuteManualCommand(mapnode, ENIGProtocol.AGVCommandHE.Charger);
menu.Items.Add(charge);
}
menu.Show(Cursor.Position);
}
private void ExecuteManualCommand(MapNode targetNode, ENIGProtocol.AGVCommandHE cmd)
@@ -105,13 +105,19 @@ namespace Project.ViewForm
MessageBox.Show("AGV의 현재 위치를 알 수 없습니다.");
return;
}
if (PUB.sm.RunStep != eSMStep.IDLE && PUB.sm.RunStep != eSMStep.READY)
if (PUB.sm.Step == eSMStep.IDLE)
{
if (MessageBox.Show("현재 대기상태가 아닙니다. 강제로 실행하시겠습니까?", "Warning", MessageBoxButtons.YesNo) == DialogResult.No) return;
}
if (targetNode.isDockingNode == false)
{
UTIL.MsgE("이동 가능한 노드가 아닙니다");
}
// 1. 경로 생성
var pathFinder = new AGVNavigationCore.PathFinding.Planning.AGVPathfinder(PUB._mapNodes);
// 현재위치에서 목표위치까지
var result = pathFinder.FindPath(PUB._virtualAGV.CurrentNode, targetNode);
@@ -122,29 +128,22 @@ namespace Project.ViewForm
}
// 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 생성 필요.
// 2. 상태 설정
if (targetNode is MapNode mapno)
PUB.log.AddI($"[Manual Command] {cmd} to {mapno.RfidId}({targetNode.Id})");
else
PUB.log.AddI($"[Manual Command] {cmd} to ({targetNode.Id})");
var detailedPath = AGVNavigationCore.PathFinding.Planning.AGVPathfinder.MakeDetailData(result.Path, PUB._mapNodes);
PUB._virtualAGV.SetPath(result.Path, detailedPath);
PUB._virtualAGV.TargetNode = targetNode;
// FindPathResult contains DetailedPath already.
PUB._virtualAGV.SetPath(result);
PUB._virtualAGV.TargetNode = targetNode as MapNode;
// 3. 작업 설정
PUB.NextWorkCmd = cmd;
// 4. 실행
PUB.sm.SetNewRunStep(ERunStep.GOTO); // GOTO -> Arrive -> _IN sequence execution
}
// 툴바 버튼 이벤트 연결
//WireToolbarButtonEvents();
}
@@ -208,7 +207,7 @@ namespace Project.ViewForm
var agvList = new System.Collections.Generic.List<AGVNavigationCore.Controls.IAGV> { PUB._virtualAGV };
PUB._mapCanvas.AGVList = agvList;
PUB.log.Add($"가상 AGV 생성: {startNode.NodeId} 위치");
PUB.log.Add($"가상 AGV 생성: {startNode.Id} 위치");
}
}
else if (PUB._virtualAGV != null)

View File

@@ -88,7 +88,7 @@ namespace Project.ViewForm
// [Manual Safety] Clear previous auto-task state
PUB._virtualAGV.TargetNode = null;
PUB._virtualAGV.CurrentPath = null;
PUB._virtualAGV.StopPath();
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop; // Clear ACS Command
PUB.sm.ClearRunStep(); // Clear RunStep sequence
}
@@ -117,7 +117,7 @@ namespace Project.ViewForm
// [Manual Safety] Clear previous auto-task state
PUB._virtualAGV.TargetNode = null;
PUB._virtualAGV.CurrentPath = null;
PUB._virtualAGV.StopPath();
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
PUB.sm.ClearRunStep();
}
@@ -146,7 +146,7 @@ namespace Project.ViewForm
// [Manual Safety] Clear previous auto-task state
PUB._virtualAGV.TargetNode = null;
PUB._virtualAGV.CurrentPath = null;
PUB._virtualAGV.StopPath();
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
PUB.sm.ClearRunStep();
}
@@ -175,7 +175,7 @@ namespace Project.ViewForm
// [Manual Safety] Clear previous auto-task state
PUB._virtualAGV.TargetNode = null;
PUB._virtualAGV.CurrentPath = null;
PUB._virtualAGV.StopPath();
PUB.NextWorkCmd = ENIGProtocol.AGVCommandHE.Stop;
PUB.sm.ClearRunStep();
}

View File

@@ -806,6 +806,10 @@ namespace Project
// 맵 캔버스에 데이터 설정
_mapCanvas.Nodes = result.Nodes;
_mapCanvas.Labels = result.Labels;
_mapCanvas.Images = result.Images;
_mapCanvas.Marks = result.Marks;
_mapCanvas.Magnets = result.Magnets;
// RfidMappings 제거됨 - MapNode에 통합
// 🔥 맵 설정 적용 (배경색, 그리드 표시)
@@ -865,7 +869,7 @@ namespace Project
ShowGrid = _mapCanvas.ShowGrid
};
if (MapLoader.SaveMapToFile(filePath, _mapNodes, settings))
if (MapLoader.SaveMapToFile(filePath, _mapNodes, _mapCanvas.Labels, _mapCanvas.Images, _mapCanvas.Marks, _mapCanvas.Magnets, settings))
{
// 설정에 마지막 맵 파일 경로 저장
PUB.setting.LastMapFile = filePath;