feat: Implement AGV command prediction system for real-time control
- Add motor/magnet/speed enums and AGVCommand class for AGV control - Implement Predict() method for next action prediction based on path and state - Add RFID position tracking (requires 2 RFIDs for position confirmation) - Add SetPath() method to VirtualAGV for path management - Implement GetCommandFromPath() to extract motor/magnet/speed from DetailedPath - Add real-time prediction display in SimulatorForm (timer1_Tick) - Support automatic forward movement at low speed when position unconfirmed - Support stop command when destination reached or no destination set Key Features: - Position unconfirmed (RFID < 2): Forward + Straight + Low speed - Position confirmed + no destination: Stop (position found) - Position confirmed + destination reached: Stop (arrived) - Path execution: Motor/Magnet/Speed from DetailedPath NodeMotorInfo - Rotation nodes: Automatic low speed - Junction handling: Magnet direction (Left/Right/Straight) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,7 @@ namespace AGVSimulator.Forms
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SimulatorForm));
|
||||
this._menuStrip = new System.Windows.Forms.MenuStrip();
|
||||
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -77,6 +78,7 @@ namespace AGVSimulator.Forms
|
||||
this.resetZoomToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripButton1 = new System.Windows.Forms.ToolStripButton();
|
||||
this.btPredict = new System.Windows.Forms.ToolStripButton();
|
||||
this._statusStrip = new System.Windows.Forms.StatusStrip();
|
||||
this._statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this._coordLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
@@ -112,6 +114,8 @@ namespace AGVSimulator.Forms
|
||||
this._agvInfoTitleLabel = new System.Windows.Forms.Label();
|
||||
this._liftDirectionLabel = new System.Windows.Forms.Label();
|
||||
this._motorDirectionLabel = new System.Windows.Forms.Label();
|
||||
this.lbPredict = new System.Windows.Forms.RichTextBox();
|
||||
this.timer1 = new System.Windows.Forms.Timer(this.components);
|
||||
this._menuStrip.SuspendLayout();
|
||||
this._toolStrip.SuspendLayout();
|
||||
this._statusStrip.SuspendLayout();
|
||||
@@ -119,6 +123,7 @@ namespace AGVSimulator.Forms
|
||||
this._statusGroup.SuspendLayout();
|
||||
this._pathGroup.SuspendLayout();
|
||||
this._agvControlGroup.SuspendLayout();
|
||||
this._canvasPanel.SuspendLayout();
|
||||
this._agvInfoPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
@@ -131,7 +136,7 @@ namespace AGVSimulator.Forms
|
||||
this.helpToolStripMenuItem});
|
||||
this._menuStrip.Location = new System.Drawing.Point(0, 0);
|
||||
this._menuStrip.Name = "_menuStrip";
|
||||
this._menuStrip.Size = new System.Drawing.Size(1200, 24);
|
||||
this._menuStrip.Size = new System.Drawing.Size(1034, 24);
|
||||
this._menuStrip.TabIndex = 0;
|
||||
this._menuStrip.Text = "menuStrip";
|
||||
//
|
||||
@@ -279,10 +284,11 @@ namespace AGVSimulator.Forms
|
||||
this.fitToMapToolStripButton,
|
||||
this.resetZoomToolStripButton,
|
||||
this.toolStripSeparator5,
|
||||
this.toolStripButton1});
|
||||
this.toolStripButton1,
|
||||
this.btPredict});
|
||||
this._toolStrip.Location = new System.Drawing.Point(0, 24);
|
||||
this._toolStrip.Name = "_toolStrip";
|
||||
this._toolStrip.Size = new System.Drawing.Size(1200, 25);
|
||||
this._toolStrip.Size = new System.Drawing.Size(1034, 25);
|
||||
this._toolStrip.TabIndex = 1;
|
||||
this._toolStrip.Text = "toolStrip";
|
||||
//
|
||||
@@ -387,19 +393,28 @@ namespace AGVSimulator.Forms
|
||||
this.toolStripButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton1.Image")));
|
||||
this.toolStripButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.toolStripButton1.Name = "toolStripButton1";
|
||||
this.toolStripButton1.Size = new System.Drawing.Size(75, 22);
|
||||
this.toolStripButton1.Text = "경로예측";
|
||||
this.toolStripButton1.Size = new System.Drawing.Size(111, 22);
|
||||
this.toolStripButton1.Text = "전체경로테스트";
|
||||
this.toolStripButton1.Click += new System.EventHandler(this.toolStripButton1_Click);
|
||||
//
|
||||
// btPredict
|
||||
//
|
||||
this.btPredict.Image = ((System.Drawing.Image)(resources.GetObject("btPredict.Image")));
|
||||
this.btPredict.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btPredict.Name = "btPredict";
|
||||
this.btPredict.Size = new System.Drawing.Size(107, 22);
|
||||
this.btPredict.Text = "다음 행동 예측";
|
||||
this.btPredict.Click += new System.EventHandler(this.btPredict_Click);
|
||||
//
|
||||
// _statusStrip
|
||||
//
|
||||
this._statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this._statusLabel,
|
||||
this._coordLabel,
|
||||
this.prb1});
|
||||
this._statusStrip.Location = new System.Drawing.Point(0, 778);
|
||||
this._statusStrip.Location = new System.Drawing.Point(0, 689);
|
||||
this._statusStrip.Name = "_statusStrip";
|
||||
this._statusStrip.Size = new System.Drawing.Size(1200, 22);
|
||||
this._statusStrip.Size = new System.Drawing.Size(1034, 22);
|
||||
this._statusStrip.TabIndex = 2;
|
||||
this._statusStrip.Text = "statusStrip";
|
||||
//
|
||||
@@ -426,9 +441,9 @@ namespace AGVSimulator.Forms
|
||||
this._controlPanel.Controls.Add(this._pathGroup);
|
||||
this._controlPanel.Controls.Add(this._agvControlGroup);
|
||||
this._controlPanel.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
this._controlPanel.Location = new System.Drawing.Point(967, 49);
|
||||
this._controlPanel.Location = new System.Drawing.Point(801, 49);
|
||||
this._controlPanel.Name = "_controlPanel";
|
||||
this._controlPanel.Size = new System.Drawing.Size(233, 729);
|
||||
this._controlPanel.Size = new System.Drawing.Size(233, 640);
|
||||
this._controlPanel.TabIndex = 3;
|
||||
//
|
||||
// _statusGroup
|
||||
@@ -679,10 +694,11 @@ namespace AGVSimulator.Forms
|
||||
//
|
||||
// _canvasPanel
|
||||
//
|
||||
this._canvasPanel.Controls.Add(this.lbPredict);
|
||||
this._canvasPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this._canvasPanel.Location = new System.Drawing.Point(0, 129);
|
||||
this._canvasPanel.Name = "_canvasPanel";
|
||||
this._canvasPanel.Size = new System.Drawing.Size(967, 649);
|
||||
this._canvasPanel.Size = new System.Drawing.Size(801, 560);
|
||||
this._canvasPanel.TabIndex = 4;
|
||||
//
|
||||
// _agvInfoPanel
|
||||
@@ -696,7 +712,7 @@ namespace AGVSimulator.Forms
|
||||
this._agvInfoPanel.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this._agvInfoPanel.Location = new System.Drawing.Point(0, 49);
|
||||
this._agvInfoPanel.Name = "_agvInfoPanel";
|
||||
this._agvInfoPanel.Size = new System.Drawing.Size(967, 80);
|
||||
this._agvInfoPanel.Size = new System.Drawing.Size(801, 80);
|
||||
this._agvInfoPanel.TabIndex = 5;
|
||||
//
|
||||
// _pathDebugLabel
|
||||
@@ -741,11 +757,25 @@ namespace AGVSimulator.Forms
|
||||
this._motorDirectionLabel.TabIndex = 2;
|
||||
this._motorDirectionLabel.Text = "모터 방향: -";
|
||||
//
|
||||
// lbPredict
|
||||
//
|
||||
this.lbPredict.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.lbPredict.Location = new System.Drawing.Point(0, 513);
|
||||
this.lbPredict.Name = "lbPredict";
|
||||
this.lbPredict.Size = new System.Drawing.Size(801, 47);
|
||||
this.lbPredict.TabIndex = 0;
|
||||
this.lbPredict.Text = "";
|
||||
//
|
||||
// timer1
|
||||
//
|
||||
this.timer1.Interval = 500;
|
||||
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
|
||||
//
|
||||
// SimulatorForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1200, 800);
|
||||
this.ClientSize = new System.Drawing.Size(1034, 711);
|
||||
this.Controls.Add(this._canvasPanel);
|
||||
this.Controls.Add(this._agvInfoPanel);
|
||||
this.Controls.Add(this._controlPanel);
|
||||
@@ -770,6 +800,7 @@ namespace AGVSimulator.Forms
|
||||
this._pathGroup.PerformLayout();
|
||||
this._agvControlGroup.ResumeLayout(false);
|
||||
this._agvControlGroup.PerformLayout();
|
||||
this._canvasPanel.ResumeLayout(false);
|
||||
this._agvInfoPanel.ResumeLayout(false);
|
||||
this._agvInfoPanel.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
@@ -845,5 +876,8 @@ namespace AGVSimulator.Forms
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator5;
|
||||
private System.Windows.Forms.ToolStripButton toolStripButton1;
|
||||
private System.Windows.Forms.ToolStripProgressBar prb1;
|
||||
private System.Windows.Forms.ToolStripButton btPredict;
|
||||
private System.Windows.Forms.RichTextBox lbPredict;
|
||||
private System.Windows.Forms.Timer timer1;
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,8 @@ namespace AGVSimulator.Forms
|
||||
_statusLabel.Text = "시뮬레이션 실행 중";
|
||||
Console.WriteLine("시뮬레이션 실행");
|
||||
UpdateUI();
|
||||
|
||||
timer1.Start();
|
||||
}
|
||||
|
||||
private void OnStopSimulation_Click(object sender, EventArgs e)
|
||||
@@ -317,7 +319,7 @@ namespace AGVSimulator.Forms
|
||||
var prevDir = selectedAGV.PrevDirection;
|
||||
|
||||
// 고급 경로 계획 사용 (노드 객체 직접 전달)
|
||||
var advancedResult = _advancedPathfinder.FindPath_test(startNode, targetNode, prevNode, prevDir, currentDirection);
|
||||
var advancedResult = _advancedPathfinder.FindPath(startNode, targetNode, prevNode, prevDir, currentDirection);
|
||||
|
||||
_simulatorCanvas.FitToNodes();
|
||||
if (advancedResult.Success)
|
||||
@@ -325,10 +327,6 @@ namespace AGVSimulator.Forms
|
||||
// 도킹 검증이 없는 경우 추가 검증 수행
|
||||
if (advancedResult.DockingValidation == null || !advancedResult.DockingValidation.IsValidationRequired)
|
||||
{
|
||||
if (advancedResult.Path.Count < 1)
|
||||
{
|
||||
|
||||
}
|
||||
advancedResult.DockingValidation = DockingValidator.ValidateDockingDirection(advancedResult, _mapNodes);
|
||||
}
|
||||
|
||||
@@ -336,6 +334,9 @@ namespace AGVSimulator.Forms
|
||||
_pathLengthLabel.Text = $"경로 길이: {advancedResult.TotalDistance:F1}";
|
||||
_statusLabel.Text = $"경로 계산 완료 ({advancedResult.CalculationTimeMs}ms)";
|
||||
|
||||
// 🔥 VirtualAGV에도 경로 설정 (Predict()가 동작하려면 필요)
|
||||
selectedAGV.SetPath(advancedResult);
|
||||
|
||||
// 도킹 검증 결과 확인 및 UI 표시
|
||||
CheckAndDisplayDockingValidation(advancedResult);
|
||||
|
||||
@@ -357,6 +358,12 @@ namespace AGVSimulator.Forms
|
||||
_simulatorCanvas.CurrentPath = null;
|
||||
_pathLengthLabel.Text = "경로 길이: -";
|
||||
_statusLabel.Text = "경로 지움";
|
||||
|
||||
// 🔥 VirtualAGV의 경로도 정지
|
||||
if (_agvList != null && _agvList.Count > 0)
|
||||
{
|
||||
_agvList[0].StopPath();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTargetCalc_Click(object sender, EventArgs e)
|
||||
@@ -590,7 +597,6 @@ namespace AGVSimulator.Forms
|
||||
|
||||
// AGV 위치 및 방향 설정
|
||||
_simulatorCanvas.SetAGVPosition(selectedAGV.AgvId, targetNode, selectedDirection);
|
||||
_simulatorCanvas.UpdateAGVDirection(selectedAGV.AgvId, selectedDirection);
|
||||
|
||||
// VirtualAGV 객체의 위치와 방향 업데이트
|
||||
selectedAGV.SetPosition(targetNode, selectedDirection); // 이전 위치 기억하도록
|
||||
@@ -1576,6 +1582,49 @@ namespace AGVSimulator.Forms
|
||||
logForm.AppendLog($"성공률: {(double)successCount / totalTests * 100:F1}%");
|
||||
}
|
||||
|
||||
private void btPredict_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 다음 행동 예측
|
||||
if (_agvList == null || _agvList.Count == 0)
|
||||
{
|
||||
MessageBox.Show("AGV가 없습니다.", "예측 오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 첫 번째 AGV의 다음 행동 예측
|
||||
var agv = _agvList[0];
|
||||
var command = agv.Predict();
|
||||
|
||||
//this.lbPredict.Text = $"MOT:{command.Motor},MAG:{command.Magnet},SPD:{command.Speed}:{command.Reason}";
|
||||
|
||||
// 예측 결과 표시
|
||||
var message = $"[다음 행동 예측]\n\n" +
|
||||
$"모터: {command.Motor}\n" +
|
||||
$"마그넷: {command.Magnet}\n" +
|
||||
$"속도: {command.Speed}\n" +
|
||||
$"이유: {command.Reason}\n\n" +
|
||||
$"---\n" +
|
||||
$"현재 상태: {agv.CurrentState}\n" +
|
||||
$"현재 방향: {agv.CurrentDirection}\n" +
|
||||
$"위치 확정: {agv.IsPositionConfirmed} (RFID {agv.DetectedRfidCount}개)\n" +
|
||||
$"현재 노드: {agv.CurrentNodeId ?? "없음"}";
|
||||
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
private void timer1_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (_agvList == null || _agvList.Count == 0)
|
||||
{
|
||||
// MessageBox.Show("AGV가 없습니다.", "예측 오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 첫 번째 AGV의 다음 행동 예측
|
||||
var agv = _agvList[0];
|
||||
var command = agv.Predict();
|
||||
this.lbPredict.Text = $"Motor:{command.Motor},Magnet:{command.Magnet},Speed:{command.Speed} : {command.Reason}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -137,9 +137,27 @@
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btPredict.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="_statusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>237, 17</value>
|
||||
</metadata>
|
||||
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>352, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
Reference in New Issue
Block a user