경로시뮬레이션완료
This commit is contained in:
@@ -177,6 +177,10 @@ namespace AGVSimulator.Forms
|
||||
SaveToCSV(saveDialog.FileName);
|
||||
MessageBox.Show($"CSV 파일이 저장되었습니다.\n{saveDialog.FileName}",
|
||||
"저장 완료", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
var prc = new System.Diagnostics.Process();
|
||||
prc.StartInfo = new System.Diagnostics.ProcessStartInfo("explorer", saveDialog.FileName);
|
||||
prc.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -2581,7 +2581,7 @@ namespace AGVSimulator.Forms
|
||||
MapNode prevNode, AgvDirection prevDir)
|
||||
{
|
||||
AGVPathResult Retval;
|
||||
|
||||
var o_StartNode = startNode;
|
||||
if (startNode == null || targetNode == null) return AGVPathResult.CreateFailure("시작/종료노드가 지정되지 않음");
|
||||
|
||||
|
||||
@@ -2646,23 +2646,43 @@ namespace AGVSimulator.Forms
|
||||
// Gateway Node 찾음
|
||||
_simulatorCanvas.HighlightNodeId = gatewayNode.Id; // Gateway 강조 설정
|
||||
|
||||
|
||||
// 4. Start -> Gateway 경로 계산 (A*)
|
||||
var pathToGateway = pathFinder.FindBasicPath(startNode, gatewayNode, prevNode, prevDir);
|
||||
if (pathToGateway.Success == false)
|
||||
AGVPathResult.CreateFailure($"Gateway({gatewayNode.ID2})까지 경로 실패: {pathToGateway.Message}");
|
||||
|
||||
//마지막경로는 게이트웨이이므로 제거하낟.(260113)
|
||||
if (pathToGateway.Path.Count > 1 && pathToGateway.Path.Last().Id == gatewayNode.Id)
|
||||
//방향을 확인하여, 왓던방향으로 가야하는디. 반대로 가야하느닞 체크한다.
|
||||
if (pathToGateway.Path.Count > 1)
|
||||
{
|
||||
pathToGateway.Path.RemoveAt(pathToGateway.Path.Count - 1);
|
||||
pathToGateway.DetailedPath.RemoveAt(pathToGateway.DetailedPath.Count - 1);
|
||||
var predictNext = pathToGateway.Path[1]; //다음으로 찍어야할 노드값
|
||||
|
||||
//이전노드id와 다음노드id가 같다면 왓던 방향으로 되돌아가야 하므로 방향을 반전시켜야한다.
|
||||
var GateyatoDIR = prevDir;
|
||||
if (predictNext.Id == prevNode.Id)
|
||||
{
|
||||
var reverseDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||
foreach (var item in pathToGateway.DetailedPath)
|
||||
item.MotorDirection = reverseDir;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//마지막경로는 게이트웨이이므로 제거하낟.(260113)
|
||||
if (pathToGateway.Path.Count > 0 && pathToGateway.Path.Last().Id == gatewayNode.Id)
|
||||
{
|
||||
var idx = pathToGateway.Path.Count - 1;
|
||||
pathToGateway.Path.RemoveAt(idx);
|
||||
pathToGateway.DetailedPath.RemoveAt(idx);
|
||||
}
|
||||
|
||||
// 5. Gateway -> Target 경로 계산 (회차 패턴 및 최종 진입 포함)
|
||||
MapNode GateprevNode = pathToGateway.Path.Last();
|
||||
NodeMotorInfo GatePrevDetail = pathToGateway.DetailedPath.Last();
|
||||
MapNode GateprevNode = pathToGateway.Path.LastOrDefault() ?? prevNode;
|
||||
NodeMotorInfo GatePrevDetail = pathToGateway.DetailedPath.LastOrDefault();
|
||||
|
||||
var arrivalOrientation = GatePrevDetail.MotorDirection;
|
||||
var arrivalOrientation = GatePrevDetail?.MotorDirection ?? prevDir;
|
||||
var gatewayPathResult = GetPathFromGateway(pathFinder, gatewayNode, targetNode, GateprevNode, arrivalOrientation);
|
||||
if (!gatewayPathResult.Success) return AGVPathResult.CreateFailure($"{gatewayPathResult.Message}");
|
||||
Retval = CombinePaths(pathToGateway, gatewayPathResult);
|
||||
@@ -2756,7 +2776,7 @@ namespace AGVSimulator.Forms
|
||||
var n2 = Retval.DetailedPath[i + 1];
|
||||
var n3 = Retval.DetailedPath[i + 2];
|
||||
|
||||
if (n1.NodeId == n3.NodeId && n1.MotorDirection == n3.MotorDirection)
|
||||
if (n1.NodeId == n3.NodeId && n1.MotorDirection == n3.MotorDirection && n1.MotorDirection == n2.MotorDirection)
|
||||
{
|
||||
return AGVPathResult.CreateFailure($"불가능한 회전 경로가 포함되어있습니다. {n1.RfidId}->{n2.RfidId}->{n3.RfidId}\n{Retval.GetDetailedPathInfo()}");
|
||||
}
|
||||
@@ -2774,6 +2794,41 @@ namespace AGVSimulator.Forms
|
||||
return AGVPathResult.CreateFailure($"목적지의 모터방향({lastnode.DockDirection}) 불일치 경로방향({lastnodePath.MotorDirection}) {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
|
||||
//계산된노드와 시작노드 ID를 체크한다.
|
||||
if (o_StartNode.ID2 != Retval.Path.First().ID2)
|
||||
{
|
||||
return AGVPathResult.CreateFailure($"첫번째노드({Retval.Path.First().ID2})가 시작노드({o_StartNode.ID2})와 일치하지 않습니다. {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
|
||||
//이전진행방향을 체크하여.. 지정된 다음노드가 올바른지 확인한다.
|
||||
if (Retval.DetailedPath.Count > 1)
|
||||
{
|
||||
var FirstDetailPath = Retval.DetailedPath[0];//.First();
|
||||
var NextDetailPath = Retval.DetailedPath[1];
|
||||
|
||||
AgvDirection? PredictNextDir = null;// = prevDir;//== AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||
if (NextDetailPath.NodeId == prevNode.Id)
|
||||
{
|
||||
//다음노드와 이전노드 ID가 일치하다면. 왓던 방향으로 되돌아 가는 경우이다
|
||||
if (NextDetailPath.MagnetDirection == MagnetDirection.Straight)
|
||||
PredictNextDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||
else
|
||||
PredictNextDir = null; //이경우는 모두 정의하지 못해서 skip 한다
|
||||
}
|
||||
else
|
||||
{
|
||||
//다음노드와 이전노드가 일치하지 않으므로 이전 진행방향으로 이동하는 경우이다
|
||||
//if (FirstDetailPath.MagnetDirection == MagnetDirection.Straight)
|
||||
// PredictNextDir = prevDir;
|
||||
//else
|
||||
PredictNextDir = null; //이경우는 모두 정의하지 못해서 skip 한다
|
||||
}
|
||||
if (PredictNextDir != null && (FirstDetailPath.MotorDirection != (AgvDirection)PredictNextDir))
|
||||
{
|
||||
return AGVPathResult.CreateFailure($"되돌아가는 길인데 방향이 일치하지않음(예상:{PredictNextDir}, 계산값:{FirstDetailPath.MotorDirection}) {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
}
|
||||
|
||||
//모든 디테일데이터의 실제 위치를 기반으로 전체 노드를 추정한다
|
||||
for (int i = 0; i < Retval.DetailedPath.Count - 1; i++)
|
||||
{
|
||||
@@ -2783,105 +2838,10 @@ namespace AGVSimulator.Forms
|
||||
var nnode = Retval.Path[i + 1];
|
||||
|
||||
//연결된 노드에 다음노드 id가 포함되는지 확인한다
|
||||
if (cnode.ConnectedNodes.Contains(nnode.Id) == false)
|
||||
if (cnode.ConnectedNodes.Contains(nnode.Id) == false && cnode.Id != nnode.Id)
|
||||
{
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드에 연결되지 않은 [{nnode.RfidId}]노드가 지정됨 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
//왔던방향을 제외한 다른 방향에 다음노드가 있는지
|
||||
var detail = Retval.DetailedPath[i];
|
||||
|
||||
//연결된 모두를 찾아서 온곳
|
||||
bool existconnnode = false;
|
||||
|
||||
//왓던방향을고려해서 다음 노드를 찾아서 일치하는지 본다.
|
||||
var deltaX = nnode.Position.X - cnode.Position.X;
|
||||
var deltaY = nnode.Position.Y - cnode.Position.Y;
|
||||
if (Math.Abs(deltaX) > Math.Abs(deltaY))
|
||||
{
|
||||
//x축으로 많이 움직임
|
||||
if (nnode.Position.X > pnode.Position.X)
|
||||
{
|
||||
//장비가 오른쪽으로 움직였다
|
||||
if (pdir == detail.MotorDirection)
|
||||
{
|
||||
//왓던방향으로 게속 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.X > cnode.Position.X).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//반대방향으로 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.X < cnode.Position.X).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//장비가 왼쪽으로 움직였다
|
||||
if (pdir == detail.MotorDirection) //후진으로 왼쪽이동했으니 모니터가 왼쪽에 있다.
|
||||
{
|
||||
|
||||
//왓던방향으로 게속 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.X < cnode.Position.X).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//반대방향으로 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.X > cnode.Position.X).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//y축으로 많이 움직임
|
||||
if (nnode.Position.Y < pnode.Position.Y)
|
||||
{
|
||||
//장비가 위로 움직였다
|
||||
if (pdir == detail.MotorDirection)
|
||||
{
|
||||
|
||||
//왓던방향으로 게속 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.Y > cnode.Position.Y).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//반대방향으로 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.Y < cnode.Position.Y).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//장비가 아래로 움직였다
|
||||
if (pdir == detail.MotorDirection) //후진으로 아래로 이동했으니 모니터가 위에 있다.
|
||||
{
|
||||
|
||||
//왓던방향으로 게속 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.Y > cnode.Position.Y).Select(t => t.Id).ToList();
|
||||
if (nextpredictnode.Contains(nnode.Id) == false)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
//반대방향으로 이동한다
|
||||
var nextpredictnode = cnode.ConnectedMapNodes.Where(t => t.Position.Y > cnode.Position.Y).FirstOrDefault();
|
||||
if (nextpredictnode.Id != nnode.Id)
|
||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드의 다음[{nnode.RfidId}]노드가 올바르지 않음 {Retval.GetDetailedPathInfo(true)}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user