This commit is contained in:
backuppc
2026-01-30 16:58:14 +09:00
parent 3a8cbd3283
commit faf13f5c37
22 changed files with 1137 additions and 417 deletions

View File

@@ -68,6 +68,7 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RemoteStatus.cs" />
<Compile Include="RS232.cs" />
<Compile Include="RunCode\_AGV.cs">
<SubType>Form</SubType>

View File

@@ -0,0 +1,37 @@
using System.Text;
namespace AGVEmulator
{
public class RemoteStatus
{
public byte Mode { get; set; } // 0=manual, 1=auto
public byte RunSt { get; set; } // 0=stop, 1=run, 2=error
public byte RunStep { get; set; }
public byte RunStepSeq { get; set; }
public byte MotorDir { get; set; } // 0=F, 1=B
public byte MagnetDir { get; set; } // 0=S, 1=L, 2=R
public byte ChargeSt { get; set; } // 0=off, 1=on
public byte CartSt { get; set; } // 0=off, 1=on, 2=unknown
public byte LiftSt { get; set; } // 0=down, 1=up, 2=unknown
public byte ErrorCode { get; set; }
public string LastTag { get; set; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Mode: {(Mode == 1 ? "Auto" : "Manual")}");
sb.AppendLine($"RunSt: {(RunSt == 0 ? "Stop" : (RunSt == 1 ? "Run" : "Error"))}");
sb.AppendLine($"Step: {RunStep}, Seq: {RunStepSeq}");
sb.AppendLine($"Dir: {(MotorDir == 1 ? "B" : "F")}, Mag: {(MagnetDir == 1 ? "L" : (MagnetDir == 2 ? "R" : "S"))}");
sb.AppendLine($"Charge: {(ChargeSt == 1 ? "ON" : "OFF")}");
sb.AppendLine($"Cart: {(CartSt == 1 ? "ON" : (CartSt == 0 ? "OFF" : "Unk"))}");
sb.AppendLine($"Lift: {(LiftSt == 1 ? "UP" : (LiftSt == 0 ? "DOWN" : "Unk"))}");
sb.Append($"Tag: {LastTag}");
return sb.ToString();
}
}
}

View File

@@ -80,6 +80,7 @@ namespace AGVEmulator
}
break;
}
UpdateUIStatus();
}
private void Agv_ValueChanged(object sender, DevAGV.ValueChangedArgs e)

View File

@@ -24,15 +24,41 @@ namespace AGVEmulator
}
private void CAL_ProtocReceived(object sender, ENIG.EEProtocol.DataEventArgs e)
{
//throw new NotImplementedException();
var dev = (DeviceType)e.ReceivedPacket.ID;
if (dev == DeviceType.AGV1 || dev == DeviceType.AGV2)
// HMI(Host)에서 호스트로 취급되는 HMI가 보낸 패킷은 ID가 0(ACS)임.
// 하지만 xbee.cs에서 CreatePacket 시 PUB.setting.XBE_ID를 사용함.
// 에뮬레이터에서는 이 패킷들을 수신하여 상태를 업데이트함.
var cmd = (ENIGProtocol.AGVCommandEH)e.ReceivedPacket.Command;
var data = e.ReceivedPacket.Data;
if (cmd == ENIGProtocol.AGVCommandEH.Status)
{
//agv에서 들어오는 데이터
var cmd = e.ReceivedPacket.Command;
if(cmd == 3)
if (data.Length >= 14)
{
//status
_remoteStatus.Mode = data[0];
_remoteStatus.RunSt = data[1];
_remoteStatus.RunStep = data[2];
_remoteStatus.RunStepSeq = data[3];
_remoteStatus.MotorDir = data[4];
_remoteStatus.MagnetDir = data[5];
_remoteStatus.ChargeSt = data[6];
_remoteStatus.CartSt = data[7];
_remoteStatus.LiftSt = data[8];
_remoteStatus.ErrorCode = data[9];
_remoteStatus.LastTag = Encoding.ASCII.GetString(data, 10, 4);
UpdateUIStatus();
}
}
else if (cmd == ENIGProtocol.AGVCommandEH.Error)
{
if (data.Length >= 1)
{
_remoteErrorCode = (ENIGProtocol.AGVErrorCode)data[0];
// _remoteErrorMessage = ... Error 메시지 자체는 패킷에 포함되지 않으므로 유틸리티 사용 가능
_remoteErrorMessage = ENIGProtocol.AGVUtility.GetAGVErrorMessage(_remoteErrorCode);
UpdateUIStatus();
}
}
}

View File

@@ -32,34 +32,34 @@ namespace AGVEmulator
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
AGVEmulator.UC.AgvViewer.ptdata ptdata113 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata114 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata115 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata116 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata117 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata118 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata119 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata120 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata121 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata122 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata123 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata124 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata125 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata126 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata127 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata128 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata129 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata130 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata131 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata132 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata133 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata134 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata135 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata136 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata137 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata138 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata139 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata140 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata29 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata30 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata31 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata32 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata33 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata34 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata35 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata36 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata37 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata38 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata39 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata40 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata41 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata42 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata43 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata44 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata45 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata46 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata47 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata48 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata49 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata50 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata51 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata52 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata53 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata54 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata55 = new AGVEmulator.UC.AgvViewer.ptdata();
AGVEmulator.UC.AgvViewer.ptdata ptdata56 = new AGVEmulator.UC.AgvViewer.ptdata();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fMain));
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.rtBMS = new arCtl.LogTextBox();
@@ -142,6 +142,10 @@ namespace AGVEmulator
this.tabPage2 = new System.Windows.Forms.TabPage();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.panel3 = new System.Windows.Forms.Panel();
this.label13 = new System.Windows.Forms.Label();
this.button6 = new System.Windows.Forms.Button();
this.button13 = new System.Windows.Forms.Button();
this.label12 = new System.Windows.Forms.Label();
this.button3 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.nudIDAgv = new System.Windows.Forms.NumericUpDown();
@@ -170,10 +174,11 @@ namespace AGVEmulator
this.sbBMS = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
this.sbCAL = new System.Windows.Forms.ToolStripStatusLabel();
this.label12 = new System.Windows.Forms.Label();
this.label13 = new System.Windows.Forms.Label();
this.button6 = new System.Windows.Forms.Button();
this.button13 = new System.Windows.Forms.Button();
this.groupBox12 = new System.Windows.Forms.GroupBox();
this.groupBox13 = new System.Windows.Forms.GroupBox();
this.tbErmsg = new System.Windows.Forms.TextBox();
this.tbErCode = new System.Windows.Forms.TextBox();
this.rtStatus = new System.Windows.Forms.RichTextBox();
this.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trbT2)).BeginInit();
@@ -205,6 +210,8 @@ namespace AGVEmulator
((System.ComponentModel.ISupportInitialize)(this.nudTagNo)).BeginInit();
this.toolStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.groupBox12.SuspendLayout();
this.groupBox13.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
@@ -1119,120 +1126,120 @@ namespace AGVEmulator
this.agvViewer1.lastmarkdir = "";
this.agvViewer1.lasttag = "";
this.agvViewer1.lasttagdir = "";
ptdata113.active = false;
ptdata113.data = "NOT";
ptdata113.pos = 30F;
ptdata114.active = false;
ptdata114.data = "QA";
ptdata114.pos = 200F;
ptdata115.active = false;
ptdata115.data = "CHG";
ptdata115.pos = 300F;
ptdata116.active = false;
ptdata116.data = "QC";
ptdata116.pos = 400F;
ptdata117.active = false;
ptdata117.data = "#FVI-1";
ptdata117.pos = 500F;
ptdata118.active = false;
ptdata118.data = "#FVI-2";
ptdata118.pos = 600F;
ptdata119.active = false;
ptdata119.data = "#FVI-3";
ptdata119.pos = 700F;
ptdata120.active = false;
ptdata120.data = "#FVI-4";
ptdata120.pos = 800F;
ptdata121.active = false;
ptdata121.data = "#FVI-5";
ptdata121.pos = 900F;
ptdata122.active = false;
ptdata122.data = "POT";
ptdata122.pos = 970F;
ptdata29.active = false;
ptdata29.data = "NOT";
ptdata29.pos = 30F;
ptdata30.active = false;
ptdata30.data = "QA";
ptdata30.pos = 200F;
ptdata31.active = false;
ptdata31.data = "CHG";
ptdata31.pos = 300F;
ptdata32.active = false;
ptdata32.data = "QC";
ptdata32.pos = 400F;
ptdata33.active = false;
ptdata33.data = "#FVI-1";
ptdata33.pos = 500F;
ptdata34.active = false;
ptdata34.data = "#FVI-2";
ptdata34.pos = 600F;
ptdata35.active = false;
ptdata35.data = "#FVI-3";
ptdata35.pos = 700F;
ptdata36.active = false;
ptdata36.data = "#FVI-4";
ptdata36.pos = 800F;
ptdata37.active = false;
ptdata37.data = "#FVI-5";
ptdata37.pos = 900F;
ptdata38.active = false;
ptdata38.data = "POT";
ptdata38.pos = 970F;
this.agvViewer1.listMRK = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata113,
ptdata114,
ptdata115,
ptdata116,
ptdata117,
ptdata118,
ptdata119,
ptdata120,
ptdata121,
ptdata122};
ptdata123.active = false;
ptdata123.data = "9000";
ptdata123.pos = 80F;
ptdata124.active = false;
ptdata124.data = "9001";
ptdata124.pos = 120F;
ptdata125.active = false;
ptdata125.data = "9010";
ptdata125.pos = 180F;
ptdata126.active = false;
ptdata126.data = "9011";
ptdata126.pos = 220F;
ptdata127.active = false;
ptdata127.data = "9020";
ptdata127.pos = 280F;
ptdata128.active = false;
ptdata128.data = "9021";
ptdata128.pos = 320F;
ptdata129.active = false;
ptdata129.data = "9030";
ptdata129.pos = 380F;
ptdata130.active = false;
ptdata130.data = "9031";
ptdata130.pos = 420F;
ptdata131.active = false;
ptdata131.data = "9040";
ptdata131.pos = 480F;
ptdata132.active = false;
ptdata132.data = "9041";
ptdata132.pos = 520F;
ptdata133.active = false;
ptdata133.data = "9050";
ptdata133.pos = 580F;
ptdata134.active = false;
ptdata134.data = "9051";
ptdata134.pos = 620F;
ptdata135.active = false;
ptdata135.data = "9060";
ptdata135.pos = 680F;
ptdata136.active = false;
ptdata136.data = "9061";
ptdata136.pos = 720F;
ptdata137.active = false;
ptdata137.data = "9070";
ptdata137.pos = 780F;
ptdata138.active = false;
ptdata138.data = "9071";
ptdata138.pos = 820F;
ptdata139.active = false;
ptdata139.data = "9000";
ptdata139.pos = 10F;
ptdata140.active = false;
ptdata140.data = "9001";
ptdata140.pos = 50F;
ptdata29,
ptdata30,
ptdata31,
ptdata32,
ptdata33,
ptdata34,
ptdata35,
ptdata36,
ptdata37,
ptdata38};
ptdata39.active = false;
ptdata39.data = "9000";
ptdata39.pos = 80F;
ptdata40.active = false;
ptdata40.data = "9001";
ptdata40.pos = 120F;
ptdata41.active = false;
ptdata41.data = "9010";
ptdata41.pos = 180F;
ptdata42.active = false;
ptdata42.data = "9011";
ptdata42.pos = 220F;
ptdata43.active = false;
ptdata43.data = "9020";
ptdata43.pos = 280F;
ptdata44.active = false;
ptdata44.data = "9021";
ptdata44.pos = 320F;
ptdata45.active = false;
ptdata45.data = "9030";
ptdata45.pos = 380F;
ptdata46.active = false;
ptdata46.data = "9031";
ptdata46.pos = 420F;
ptdata47.active = false;
ptdata47.data = "9040";
ptdata47.pos = 480F;
ptdata48.active = false;
ptdata48.data = "9041";
ptdata48.pos = 520F;
ptdata49.active = false;
ptdata49.data = "9050";
ptdata49.pos = 580F;
ptdata50.active = false;
ptdata50.data = "9051";
ptdata50.pos = 620F;
ptdata51.active = false;
ptdata51.data = "9060";
ptdata51.pos = 680F;
ptdata52.active = false;
ptdata52.data = "9061";
ptdata52.pos = 720F;
ptdata53.active = false;
ptdata53.data = "9070";
ptdata53.pos = 780F;
ptdata54.active = false;
ptdata54.data = "9071";
ptdata54.pos = 820F;
ptdata55.active = false;
ptdata55.data = "9000";
ptdata55.pos = 10F;
ptdata56.active = false;
ptdata56.data = "9001";
ptdata56.pos = 50F;
this.agvViewer1.listTAG = new AGVEmulator.UC.AgvViewer.ptdata[] {
ptdata123,
ptdata124,
ptdata125,
ptdata126,
ptdata127,
ptdata128,
ptdata129,
ptdata130,
ptdata131,
ptdata132,
ptdata133,
ptdata134,
ptdata135,
ptdata136,
ptdata137,
ptdata138,
ptdata139,
ptdata140};
ptdata39,
ptdata40,
ptdata41,
ptdata42,
ptdata43,
ptdata44,
ptdata45,
ptdata46,
ptdata47,
ptdata48,
ptdata49,
ptdata50,
ptdata51,
ptdata52,
ptdata53,
ptdata54,
ptdata55,
ptdata56};
this.agvViewer1.Location = new System.Drawing.Point(241, 0);
this.agvViewer1.Name = "agvViewer1";
this.agvViewer1.Size = new System.Drawing.Size(899, 120);
@@ -1277,6 +1284,8 @@ namespace AGVEmulator
//
// panel3
//
this.panel3.Controls.Add(this.groupBox13);
this.panel3.Controls.Add(this.groupBox12);
this.panel3.Controls.Add(this.label13);
this.panel3.Controls.Add(this.button6);
this.panel3.Controls.Add(this.button13);
@@ -1301,6 +1310,46 @@ namespace AGVEmulator
this.panel3.Size = new System.Drawing.Size(364, 622);
this.panel3.TabIndex = 15;
//
// label13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(17, 362);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(26, 12);
this.label13.TabIndex = 19;
this.label13.Text = "Exit";
//
// button6
//
this.button6.Location = new System.Drawing.Point(204, 349);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(133, 38);
this.button6.TabIndex = 18;
this.button6.Tag = "--";
this.button6.Text = "Pick Off";
this.button6.UseVisualStyleBackColor = true;
this.button6.Click += new System.EventHandler(this.button6_Click_1);
//
// button13
//
this.button13.Location = new System.Drawing.Point(65, 349);
this.button13.Name = "button13";
this.button13.Size = new System.Drawing.Size(133, 38);
this.button13.TabIndex = 17;
this.button13.Tag = "--";
this.button13.Text = "Pick On";
this.button13.UseVisualStyleBackColor = true;
this.button13.Click += new System.EventHandler(this.button13_Click);
//
// label12
//
this.label12.AutoSize = true;
this.label12.Location = new System.Drawing.Point(17, 318);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(34, 12);
this.label12.TabIndex = 16;
this.label12.Text = "Enter";
//
// button3
//
this.button3.Location = new System.Drawing.Point(204, 305);
@@ -1583,45 +1632,50 @@ namespace AGVEmulator
this.sbCAL.Size = new System.Drawing.Size(19, 17);
this.sbCAL.Text = "●";
//
// label12
// groupBox12
//
this.label12.AutoSize = true;
this.label12.Location = new System.Drawing.Point(17, 318);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(34, 12);
this.label12.TabIndex = 16;
this.label12.Text = "Enter";
this.groupBox12.Controls.Add(this.rtStatus);
this.groupBox12.Location = new System.Drawing.Point(6, 393);
this.groupBox12.Name = "groupBox12";
this.groupBox12.Size = new System.Drawing.Size(355, 147);
this.groupBox12.TabIndex = 20;
this.groupBox12.TabStop = false;
this.groupBox12.Text = "status";
//
// label13
// groupBox13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(17, 362);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(26, 12);
this.label13.TabIndex = 19;
this.label13.Text = "Exit";
this.groupBox13.Controls.Add(this.tbErCode);
this.groupBox13.Controls.Add(this.tbErmsg);
this.groupBox13.Dock = System.Windows.Forms.DockStyle.Bottom;
this.groupBox13.Location = new System.Drawing.Point(0, 546);
this.groupBox13.Name = "groupBox13";
this.groupBox13.Size = new System.Drawing.Size(364, 76);
this.groupBox13.TabIndex = 21;
this.groupBox13.TabStop = false;
this.groupBox13.Text = "error";
//
// button6
// tbErmsg
//
this.button6.Location = new System.Drawing.Point(204, 349);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(133, 38);
this.button6.TabIndex = 18;
this.button6.Tag = "--";
this.button6.Text = "Pick Off";
this.button6.UseVisualStyleBackColor = true;
this.button6.Click += new System.EventHandler(this.button6_Click_1);
this.tbErmsg.Location = new System.Drawing.Point(13, 45);
this.tbErmsg.Name = "tbErmsg";
this.tbErmsg.Size = new System.Drawing.Size(287, 21);
this.tbErmsg.TabIndex = 0;
//
// button13
// tbErCode
//
this.button13.Location = new System.Drawing.Point(65, 349);
this.button13.Name = "button13";
this.button13.Size = new System.Drawing.Size(133, 38);
this.button13.TabIndex = 17;
this.button13.Tag = "--";
this.button13.Text = "Pick On";
this.button13.UseVisualStyleBackColor = true;
this.button13.Click += new System.EventHandler(this.button13_Click);
this.tbErCode.Location = new System.Drawing.Point(12, 18);
this.tbErCode.Name = "tbErCode";
this.tbErCode.Size = new System.Drawing.Size(287, 21);
this.tbErCode.TabIndex = 1;
//
// rtStatus
//
this.rtStatus.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtStatus.Location = new System.Drawing.Point(3, 17);
this.rtStatus.Name = "rtStatus";
this.rtStatus.Size = new System.Drawing.Size(349, 127);
this.rtStatus.TabIndex = 0;
this.rtStatus.Text = "";
//
// fMain
//
@@ -1678,6 +1732,9 @@ namespace AGVEmulator
this.toolStrip1.PerformLayout();
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.groupBox12.ResumeLayout(false);
this.groupBox13.ResumeLayout(false);
this.groupBox13.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -1798,6 +1855,11 @@ namespace AGVEmulator
private Label label13;
private Button button6;
private Button button13;
private GroupBox groupBox13;
private GroupBox groupBox12;
private TextBox tbErCode;
private TextBox tbErmsg;
private RichTextBox rtStatus;
}
}

View File

@@ -8,7 +8,6 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using static AGVEmulator.DevAGV;
@@ -24,6 +23,10 @@ namespace AGVEmulator
DevAGV AGV;
DevXBE XBE;
public RemoteStatus _remoteStatus = new RemoteStatus();
public ENIGProtocol.AGVErrorCode _remoteErrorCode = ENIGProtocol.AGVErrorCode.None;
public string _remoteErrorMessage = "";
// Map Control
private UnifiedAGVCanvas _agvCanvas;
private VirtualAGV _visualAgv;
@@ -980,6 +983,30 @@ namespace AGVEmulator
var target = (byte)nudIDAgv.Value;
this.XBE.SendPickOffExit(target);
}
public void UpdateUIStatus()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(UpdateUIStatus));
return;
}
rtStatus.Text = _remoteStatus.ToString();
tbErCode.Text = _remoteErrorCode.ToString();
tbErmsg.Text = _remoteErrorMessage;
if (_remoteErrorCode != ENIGProtocol.AGVErrorCode.None)
{
tbErCode.BackColor = Color.Red;
tbErCode.ForeColor = Color.White;
}
else
{
tbErCode.BackColor = SystemColors.Window;
tbErCode.ForeColor = SystemColors.WindowText;
}
}
}
}

View File

@@ -349,6 +349,20 @@ namespace AGVNavigationCore.Controls
public MapNode SelectedNode
{
get { return this._selectedNode as MapNode; }
set
{
_selectedNode = value;
if (value != null)
{
_selectedNodes.Clear();
_selectedNodes.Add(value);
}
else
{
_selectedNodes.Clear();
}
Invalidate();
}
}
/// <summary>
@@ -393,6 +407,19 @@ namespace AGVNavigationCore.Controls
this.FitToNodes();
}
/// <summary>
/// 맵 데이터를 셋팅합니다
/// </summary>
public void SetMapData(List<MapNode> nodes, List<MapLabel> labels = null, List<MapImage> images = null, List<MapMark> marks = null, List<MapMagnet> magnets = null)
{
this.Nodes = nodes;
this.Labels = labels ?? new List<MapLabel>();
this.Images = images ?? new List<MapImage>();
this.Marks = marks ?? new List<MapMark>();
this.Magnets = magnets ?? new List<MapMagnet>();
this.FitToNodes();
}
/// <summary>
/// 노드 목록
/// </summary>

View File

@@ -197,6 +197,12 @@
<Compile Include="Dialog\fCounter.Designer.cs">
<DependentUpon>fCounter.cs</DependentUpon>
</Compile>
<Compile Include="Dialog\fSetCurrentPosition.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Dialog\fSetCurrentPosition.Designer.cs">
<DependentUpon>fSetCurrentPosition.cs</DependentUpon>
</Compile>
<Compile Include="Dialog\fXbeeSetting.cs">
<SubType>Form</SubType>
</Compile>
@@ -412,6 +418,9 @@
<EmbeddedResource Include="Dialog\fCounter.resx">
<DependentUpon>fCounter.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Dialog\fSetCurrentPosition.resx">
<DependentUpon>fSetCurrentPosition.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Dialog\fXbeeSetting.resx">
<DependentUpon>fXbeeSetting.cs</DependentUpon>
</EmbeddedResource>
@@ -573,9 +582,7 @@
<Name>CommData</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="StateMachine\Display\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>

View File

@@ -181,20 +181,20 @@ namespace Project.Device
/// 오류코드를 호스트에 전송합니다
/// </summary>
/// <param name="errcode"></param>
public void SendError(ENIGProtocol.AGVErrorCode errcode, string errormessage)
public void SendError(ENIGProtocol.AGVErrorCode errcode)
{
// Update global error state so it persists in Status messages
PUB.Result.RunStepErrorCode = errcode;
PUB.Result.ResultMessage = errormessage;
//PUB.Result.ResultMessage = errormessage;
var id = PUB.setting.XBE_ID;
byte cmd = (byte)ENIGProtocol.AGVCommandEH.Error;
if (errormessage.Length > 30) errormessage = errormessage.Substring(0, 29);
// if (errormessage.Length > 30) errormessage = errormessage.Substring(0, 29);
var data = new List<byte>();
data.Add((byte)errcode);
var datamsg = System.Text.Encoding.Default.GetBytes(errormessage);
data.AddRange(datamsg);
//var datamsg = System.Text.Encoding.Default.GetBytes(errormessage);
// data.AddRange(datamsg);
var packet = proto.CreatePacket(id, cmd, data.ToArray());
Send(packet);

View File

@@ -0,0 +1,230 @@
namespace Project.Dialog
{
partial class fSetCurrentPosition
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mainLayout = new System.Windows.Forms.TableLayoutPanel();
this.controlPanel = new System.Windows.Forms.Panel();
this._lblStatus = new System.Windows.Forms.Label();
this.btnForward = new System.Windows.Forms.Button();
this.btnBackward = new System.Windows.Forms.Button();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.btnTurnR90 = new System.Windows.Forms.Button();
this.lblTurn = new System.Windows.Forms.Label();
this.btnTurnNone = new System.Windows.Forms.Button();
this.btnTurnL90 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.mainLayout.SuspendLayout();
this.controlPanel.SuspendLayout();
this.SuspendLayout();
//
// mainLayout
//
this.mainLayout.ColumnCount = 1;
this.mainLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.mainLayout.Controls.Add(this.controlPanel, 0, 2);
this.mainLayout.Controls.Add(this.label1, 0, 0);
this.mainLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.mainLayout.Location = new System.Drawing.Point(0, 0);
this.mainLayout.Name = "mainLayout";
this.mainLayout.RowCount = 3;
this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 84.60411F));
this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 15.39589F));
this.mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.mainLayout.Size = new System.Drawing.Size(1264, 761);
this.mainLayout.TabIndex = 0;
//
// controlPanel
//
this.controlPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30)))));
this.controlPanel.Controls.Add(this._lblStatus);
this.controlPanel.Controls.Add(this.btnForward);
this.controlPanel.Controls.Add(this.btnBackward);
this.controlPanel.Controls.Add(this.btnOK);
this.controlPanel.Controls.Add(this.btnCancel);
this.controlPanel.Controls.Add(this.btnTurnR90);
this.controlPanel.Controls.Add(this.lblTurn);
this.controlPanel.Controls.Add(this.btnTurnNone);
this.controlPanel.Controls.Add(this.btnTurnL90);
this.controlPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.controlPanel.Location = new System.Drawing.Point(3, 652);
this.controlPanel.Name = "controlPanel";
this.controlPanel.Padding = new System.Windows.Forms.Padding(10);
this.controlPanel.Size = new System.Drawing.Size(1258, 106);
this.controlPanel.TabIndex = 1;
//
// _lblStatus
//
this._lblStatus.Font = new System.Drawing.Font("맑은 고딕", 12F, System.Drawing.FontStyle.Bold);
this._lblStatus.ForeColor = System.Drawing.Color.White;
this._lblStatus.Location = new System.Drawing.Point(7, 7);
this._lblStatus.Margin = new System.Windows.Forms.Padding(3, 10, 20, 0);
this._lblStatus.Name = "_lblStatus";
this._lblStatus.Size = new System.Drawing.Size(653, 42);
this._lblStatus.TabIndex = 0;
this._lblStatus.Text = "위치를 선택해 주세요.";
this._lblStatus.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// btnForward
//
this.btnForward.BackColor = System.Drawing.Color.DarkSlateGray;
this.btnForward.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnForward.ForeColor = System.Drawing.Color.White;
this.btnForward.Location = new System.Drawing.Point(721, 51);
this.btnForward.Name = "btnForward";
this.btnForward.Size = new System.Drawing.Size(120, 38);
this.btnForward.TabIndex = 1;
this.btnForward.Text = "전진 (Forward)";
this.btnForward.UseVisualStyleBackColor = false;
//
// btnBackward
//
this.btnBackward.BackColor = System.Drawing.Color.DarkSlateGray;
this.btnBackward.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnBackward.ForeColor = System.Drawing.Color.White;
this.btnBackward.Location = new System.Drawing.Point(847, 51);
this.btnBackward.Name = "btnBackward";
this.btnBackward.Size = new System.Drawing.Size(126, 38);
this.btnBackward.TabIndex = 2;
this.btnBackward.Text = "후진 (Backward)";
this.btnBackward.UseVisualStyleBackColor = false;
//
// btnOK
//
this.btnOK.BackColor = System.Drawing.Color.DarkGreen;
this.btnOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnOK.ForeColor = System.Drawing.Color.White;
this.btnOK.Location = new System.Drawing.Point(7, 51);
this.btnOK.Margin = new System.Windows.Forms.Padding(50, 3, 3, 3);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(150, 38);
this.btnOK.TabIndex = 7;
this.btnOK.Text = "설정 완료";
this.btnOK.UseVisualStyleBackColor = false;
//
// btnCancel
//
this.btnCancel.BackColor = System.Drawing.Color.Maroon;
this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnCancel.ForeColor = System.Drawing.Color.White;
this.btnCancel.Location = new System.Drawing.Point(163, 51);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(100, 38);
this.btnCancel.TabIndex = 8;
this.btnCancel.Text = "취소";
this.btnCancel.UseVisualStyleBackColor = false;
//
// btnTurnR90
//
this.btnTurnR90.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(60)))), ((int)(((byte)(60)))));
this.btnTurnR90.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnTurnR90.ForeColor = System.Drawing.Color.White;
this.btnTurnR90.Location = new System.Drawing.Point(893, 7);
this.btnTurnR90.Name = "btnTurnR90";
this.btnTurnR90.Size = new System.Drawing.Size(80, 40);
this.btnTurnR90.TabIndex = 6;
this.btnTurnR90.Text = "R90";
this.btnTurnR90.UseVisualStyleBackColor = false;
//
// lblTurn
//
this.lblTurn.AutoSize = true;
this.lblTurn.ForeColor = System.Drawing.Color.White;
this.lblTurn.Location = new System.Drawing.Point(677, 20);
this.lblTurn.Margin = new System.Windows.Forms.Padding(20, 10, 5, 0);
this.lblTurn.Name = "lblTurn";
this.lblTurn.Size = new System.Drawing.Size(35, 12);
this.lblTurn.TabIndex = 3;
this.lblTurn.Text = "Turn:";
//
// btnTurnNone
//
this.btnTurnNone.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(60)))), ((int)(((byte)(60)))));
this.btnTurnNone.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnTurnNone.ForeColor = System.Drawing.Color.White;
this.btnTurnNone.Location = new System.Drawing.Point(721, 7);
this.btnTurnNone.Name = "btnTurnNone";
this.btnTurnNone.Size = new System.Drawing.Size(80, 40);
this.btnTurnNone.TabIndex = 4;
this.btnTurnNone.Text = "None";
this.btnTurnNone.UseVisualStyleBackColor = false;
//
// btnTurnL90
//
this.btnTurnL90.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(60)))), ((int)(((byte)(60)))));
this.btnTurnL90.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnTurnL90.ForeColor = System.Drawing.Color.White;
this.btnTurnL90.Location = new System.Drawing.Point(807, 7);
this.btnTurnL90.Name = "btnTurnL90";
this.btnTurnL90.Size = new System.Drawing.Size(80, 40);
this.btnTurnL90.TabIndex = 5;
this.btnTurnL90.Text = "L90";
this.btnTurnL90.UseVisualStyleBackColor = false;
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Font = new System.Drawing.Font("맑은 고딕", 12F, System.Drawing.FontStyle.Bold);
this.label1.Location = new System.Drawing.Point(3, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(1258, 40);
this.label1.TabIndex = 2;
this.label1.Text = "현재 위치에 해당하는 노드를 선택하세요";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// fSetCurrentPosition
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1264, 761);
this.Controls.Add(this.mainLayout);
this.Name = "fSetCurrentPosition";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "AGV 시작 위치 및 방향 설정";
this.mainLayout.ResumeLayout(false);
this.controlPanel.ResumeLayout(false);
this.controlPanel.PerformLayout();
this.ResumeLayout(false);
}
private System.Windows.Forms.TableLayoutPanel mainLayout;
private System.Windows.Forms.Panel controlPanel;
private System.Windows.Forms.Label _lblStatus;
private System.Windows.Forms.Button btnForward;
private System.Windows.Forms.Button btnBackward;
private System.Windows.Forms.Label lblTurn;
private System.Windows.Forms.Button btnTurnNone;
private System.Windows.Forms.Button btnTurnL90;
private System.Windows.Forms.Button btnTurnR90;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Label label1;
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AGVNavigationCore.Models;
using AGVNavigationCore.Controls;
namespace Project.Dialog
{
public partial class fSetCurrentPosition : Form
{
private UnifiedAGVCanvas _canvas;
private MapNode _selectedNode;
private AgvDirection _selectedDirection = AgvDirection.Forward;
private AGVTurn _selectedTurn = AGVTurn.None;
public MapNode SelectedNode => _selectedNode;
public AgvDirection SelectedDirection => _selectedDirection;
public AGVTurn SelectedTurn => _selectedTurn;
public fSetCurrentPosition()
{
InitializeComponent();
if (PUB.setting.FullScreen) this.WindowState = FormWindowState.Maximized;
SetupCanvas();
WireEvents();
this.Load += FSetCurrentPosition_Load;
}
private void SetupCanvas()
{
_canvas = new UnifiedAGVCanvas
{
Dock = DockStyle.Fill,
Mode = UnifiedAGVCanvas.CanvasMode.Run,
BackColor = Color.FromArgb(45, 45, 48),
ShowGrid=false,
};
mainLayout.Controls.Add(_canvas, 1, 0);
}
private void WireEvents()
{
_canvas.NodeSelect += _canvas_NodeSelect;
btnForward.Click += (s, e) => { _selectedDirection = AgvDirection.Forward; UpdateStatus(); };
btnBackward.Click += (s, e) => { _selectedDirection = AgvDirection.Backward; UpdateStatus(); };
btnTurnNone.Click += (s, e) => { _selectedTurn = AGVTurn.None; UpdateStatus(); };
btnTurnL90.Click += (s, e) => { _selectedTurn = AGVTurn.L90; UpdateStatus(); };
btnTurnR90.Click += (s, e) => { _selectedTurn = AGVTurn.R90; UpdateStatus(); };
btnOK.Click += BtnOK_Click;
btnCancel.Click += (s, e) => { this.DialogResult = DialogResult.Cancel; this.Close(); };
}
private void FSetCurrentPosition_Load(object sender, EventArgs e)
{
// 맵 데이터 강제 복사 (PUB과 동일한 맵 사용)
if (PUB._mapCanvas != null)
{
_canvas.SetMapData(PUB._mapCanvas.Nodes, PUB._mapCanvas.Labels, PUB._mapCanvas.Images, PUB._mapCanvas.Marks, PUB._mapCanvas.Magnets);
}
// 마지막 위치 로드
var lastPos = PUB.LoadLastPosition();
if (lastPos != null)
{
_selectedNode = _canvas.Nodes.FirstOrDefault(n => n.Id == lastPos.NodeId);
_selectedDirection = lastPos.Direction;
_selectedTurn = lastPos.Turn;
if (_selectedNode != null)
{
_canvas.SelectedNode = _selectedNode;
_canvas.PanToNode(_selectedNode.Id);
UpdateStatus(isRestore: true);
}
}
this.Show();
_canvas.ResetZoom();
}
private void _canvas_NodeSelect(object sender, NodeBase node, MouseEventArgs e)
{
if (node is MapNode mapNode && mapNode.IsNavigationNode())
{
_selectedNode = mapNode;
_canvas.SelectedNode = mapNode;
UpdateStatus();
}
}
private void UpdateStatus(bool isRestore = false)
{
if (_selectedNode == null)
{
_lblStatus.Text = "위치를 선택해 주세요.";
_lblStatus.ForeColor = Color.White;
return;
}
string dirStr = _selectedDirection == AgvDirection.Forward ? "전진" : "후진";
_lblStatus.Text = $"{(isRestore ? "[] " : "")}위치: {_selectedNode.Id} ({_selectedNode.ID2}) | 방향: {dirStr} | Turn: {_selectedTurn}";
_lblStatus.ForeColor = isRestore ? Color.Yellow : Color.Cyan;
// 캔버스에 가상 AGV 미리보기 (선택 사항)
_canvas.Invalidate();
}
private void BtnOK_Click(object sender, EventArgs e)
{
if (_selectedNode == null)
{
MessageBox.Show("AGV의 현재 위치를 맵에서 클릭하여 선택해 주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -8,6 +8,8 @@ using System.Media;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System;
using System.IO;
using Newtonsoft.Json;
#if SPEECH
using Microsoft.Speech.Synthesis;
@@ -23,6 +25,14 @@ using System.Drawing;
namespace Project
{
public class LastPositionData
{
public string NodeId { get; set; }
public AgvDirection Direction { get; set; }
public AGVTurn Turn { get; set; }
public DateTime SaveTime { get; set; }
}
public static class PUB
{
//public static Device.CFlag flag;
@@ -633,72 +643,8 @@ namespace Project
if (rfidValue.isEmpty()) return null;
return _mapNodes.Where(t => t.RfidId.Equals(rfidValue)).FirstOrDefault();
}
public static List<MapNode> FindByNodeAlias(string alias)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_mapNodes == null || _mapNodes.Any() == false) return null;
if (alias.isEmpty()) return null;
var lst = _mapNodes.Where(t => t.AliasName.Equals(alias));
if (lst.Any() == false) return null;
return lst.ToList();
}
public static List<MapNode> FindByNodeType(AGVNavigationCore.Models.MapNode type)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_mapNodes == null || _mapNodes.Any() == false) return null;
var lst = _mapNodes.Where(t => t.Type.Equals(type));
if (lst.Any() == false) return null;
return lst.ToList();
}
/// <summary>
/// RFID 읽기 시 해당 노드 위치로 AGV 업데이트
/// </summary>
/// <param name="rfidId">읽은 RFID ID</param>
/// <param name="motorDirection">모터 방향 (Forward/Backward)</param>
/// <returns>업데이트 성공 여부</returns>
public static bool UpdateAGVFromRFID(ushort rfidId, AgvDirection motorDirection = AgvDirection.Forward)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_virtualAGV == null || _mapNodes == null) return false;
// RFID에 해당하는 노드 찾기
var node = _mapNodes.FirstOrDefault(n => n.RfidId == rfidId);
if (node != null)
{
_virtualAGV.SetPosition(node, motorDirection);
RefreshAGVCanvas();
log.Add($"[AGV] RFID {rfidId} 감지 → 노드 {node.Id} 위치 업데이트 (방향: {motorDirection})");
return true;
}
log.Add($"[AGV] RFID {rfidId}에 해당하는 노드를 찾을 수 없음");
return false;
}
/// <summary>
/// 노드ID로 AGV 위치 업데이트
/// </summary>
/// <param name="nodeId">노드 ID</param>
/// <param name="motorDirection">모터 방향 (Forward/Backward)</param>
/// <returns>업데이트 성공 여부</returns>
public static bool UpdateAGVToNode(string nodeId, AgvDirection motorDirection = AgvDirection.Forward)
{
var _mapNodes = PUB._mapCanvas.Nodes;
if (_virtualAGV == null || _mapNodes == null) return false;
var node = _mapNodes.FirstOrDefault(n => n.Id == nodeId);
if (node != null)
{
_virtualAGV.SetPosition(node, motorDirection);
RefreshAGVCanvas();
log.Add($"[AGV] 노드 {nodeId} 위치로 이동 (방향: {motorDirection})");
return true;
}
return false;
}
/// <summary>
/// 모든 로그를 플러시 합니다.
@@ -718,10 +664,14 @@ namespace Project
/// <param name="direction">새로운 방향</param>
public static void UpdateAGVDirection(AgvDirection direction)
{
if (_virtualAGV == null) return;
_virtualAGV.CurrentDirection = direction;
RefreshAGVCanvas();
if (_virtualAGV == null) return;
if(_virtualAGV.CurrentDirection != direction)
{
PUB.log.Add($"[PUB] AGV Direction Change {_virtualAGV.CurrentDirection}->{direction}");
_virtualAGV.CurrentDirection = direction;
RefreshAGVCanvas();
}
}
/// <summary>
@@ -732,8 +682,13 @@ namespace Project
{
if (_virtualAGV == null) return;
_virtualAGV.CurrentState = state;
RefreshAGVCanvas();
if(_virtualAGV.CurrentState != state)
{
PUB.log.Add($"[PUB] AGV State Change {_virtualAGV.CurrentState}->{state}");
_virtualAGV.CurrentState = state;
RefreshAGVCanvas();
}
}
/// <summary>
@@ -760,6 +715,51 @@ namespace Project
}
#region "Starting Position Persistence"
private static string LastPosFilePath => Path.Combine(UTIL.CurrentPath, "Data", "last_pos.json");
public static void SaveLastPosition()
{
if (_virtualAGV == null || _virtualAGV.CurrentNode == null) return;
try
{
var data = new LastPositionData
{
NodeId = _virtualAGV.CurrentNode.Id,
Direction = _virtualAGV.CurrentDirection,
Turn = _virtualAGV.Turn,
SaveTime = DateTime.Now
};
string json = JsonConvert.SerializeObject(data, Formatting.Indented);
File.WriteAllText(LastPosFilePath, json);
}
catch (Exception ex)
{
log.AddE($"[PUB] Failed to save last position: {ex.Message}");
}
}
public static LastPositionData LoadLastPosition()
{
try
{
if (!File.Exists(LastPosFilePath)) return null;
string json = File.ReadAllText(LastPosFilePath);
return JsonConvert.DeserializeObject<LastPositionData>(json);
}
catch (Exception ex)
{
log.AddE($"[PUB] Failed to load last position: {ex.Message}");
return null;
}
}
#endregion
#endregion
}

View File

@@ -39,6 +39,21 @@ namespace Project
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}-{PUB.sm.RunStepSeq}] 이미 카트가 감지되어 진입할 수 없습니다");
return false;
}
}
PUB.sm.UpdateRunStepSeq();
return false;
}
else if (PUB.sm.RunStepSeq == idx++)
{
//모션 전후진 제어
if (PUB._virtualAGV.Turn != AGVNavigationCore.Models.AGVTurn.L90)
@@ -69,27 +84,27 @@ namespace Project
else
{
//하드웨어 상태 확인
var turnState = PUB.AGV.TurnInformation?.State ?? arDev.eNarumiTurn.None;
//var turnState = PUB.AGV.TurnInformation?.StateNew ?? arDev.eNarumiTurn.None;
if (turnState == arDev.eNarumiTurn.Left || turnState == arDev.eNarumiTurn.LeftIng)
{
//이미 좌회전 중이거나 완료된 하드웨어 상태
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 하드웨어 좌회전 상태 확인됨({turnState}). 명령을 건너뜁니다.");
PUB.sm.UpdateRunStepSeq();
}
else if (turnState == arDev.eNarumiTurn.Right || turnState == arDev.eNarumiTurn.RightIng)
{
//비정상 상태 (우회전 중?)
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 우회전 상태에서 좌회전을 시도할 수 없습니다.");
}
else
{
//정상 (None) -> 턴 명령 실행
PUB.AGV.AGVMoveLeft180Turn();
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Left Turn");
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
PUB.sm.UpdateRunStepSeq();
}
//if (turnState == arDev.eNarumiTurn.Left || turnState == arDev.eNarumiTurn.LeftIng)
//{
// //이미 좌회전 중이거나 완료된 하드웨어 상태
// PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 하드웨어 좌회전 상태 확인됨({turnState}). 명령을 건너뜁니다.");
// PUB.sm.UpdateRunStepSeq();
//}
//else if (turnState == arDev.eNarumiTurn.Right || turnState == arDev.eNarumiTurn.RightIng)
//{
// //비정상 상태 (우회전 중?)
// SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 우회전 상태에서 좌회전을 시도할 수 없습니다.");
//}
//else
//{
//정상 (None) -> 턴 명령 실행
PUB.AGV.AGVMoveLeft180Turn();
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Left Turn");
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
PUB.sm.UpdateRunStepSeq();
//}
}
PUB._mapCanvas.SetAlertMessage($"턴 진행 중");
return false;
@@ -99,29 +114,31 @@ namespace Project
//이미 완료된 상태라면 대기 과정을 건너뛴다.
if (PUB._virtualAGV.Turn == AGVNavigationCore.Models.AGVTurn.L90)
{
PUB.sm.UpdateRunStepSeq();
return false;
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 이미 턴이완료된 상태입니다");
}
//왼쪽턴이 완료되지 않은경우
if (PUB.AGV.TurnInformation.State != arDev.eNarumiTurn.Left)
else
{
//움직임 확인을 위해 3초간은 검증을 유예한다
if (PUB.AGV.TurnInformation.Runtime.TotalSeconds < 3) return false;
//턴 이동 상태가 확인되어야 한다.
var overtime = 30;
if (PUB.AGV.TurnInformation.Runtime.TotalSeconds > overtime)
//왼쪽턴이 완료되지 않은경우
if (PUB.AGV.TurnInformation.State != arDev.eNarumiTurn.Left)
{
//30초동안 AGV까 움직이지 않았다면 오류 처리한다.
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}] {overtime}초이내 턴 감지 안됨");
//움직임 확인을 위해 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;
}
else PUB._mapCanvas.SetAlertMessage($"턴 진행 중({PUB.AGV.TurnInformation.Runtime.TotalSeconds:N0}/{overtime})");
return false;
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.L90; //턴완료
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] Turn(left) 완료");
}
PUB._virtualAGV.Turn = AGVNavigationCore.Models.AGVTurn.L90; //턴완료
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] Turn(left) 완료");
PUB.sm.UpdateRunStepSeq(); //이미완료된상태이므로 다음으로 진행한다.
return false;
}
@@ -174,7 +191,7 @@ namespace Project
else if (PUB.sm.RunStepSeq == idx++)
{
//저속이동 (후진 진입)
// [Smart Restart] 재시작 시 안전 검사
// 이미 턴을 완료했고(L90), 현재 마크 센서가 감지된다면(ON),
// 이미 목적지(Mark 2)에 도착한 것으로 간주하여 후진을 생략한다.
@@ -203,7 +220,13 @@ namespace Project
return false;
}
//후진이동을한다
//후진이동을한다
PUB.sm.UpdateRunStepSeq();
return false;
}
else if (PUB.sm.RunStepSeq == idx++)
{
//이동확인을 한다.
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] 도킹을 위해 후진 이동 시작 (Dir:Backward, Spd:Low)");
PUB._mapCanvas.SetAlertMessage($"도킹을 위해 후진 이동 시작");
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
@@ -213,9 +236,9 @@ namespace Project
else if (PUB.sm.RunStepSeq == idx++)
{
//이동확인을 한다.
if(PUB.AGV.system1.agv_run == false)
if (PUB.AGV.system1.agv_run == false)
{
if(seqtime.TotalSeconds > 3)
if (seqtime.TotalSeconds > 10)
{
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
}

View File

@@ -80,69 +80,85 @@ namespace Project
}
else if (PUB.sm.RunStepSeq == idx++)
{
//빈 상태로 아웃해야한다.
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
if (PUB.AGV.signal1.mark_sensor == false)
{
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)
//빈 상태로 아웃해야한다.
var ret = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
{
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_SPEED_SET_FAIL);
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;
}
return false;
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 이동 설정 완료 (Dir:Forward, Spd:Low)");
}
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 이동 설정 완료 (Dir:Forward, Spd:Low)");
PUB.sm.UpdateRunStepSeq();
return false;
}
else if (PUB.sm.RunStepSeq == idx++)
{
//전진이동
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 전진 구동 시작");
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
if (PUB.AGV.signal1.mark_sensor == false)
{
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 전진 구동 시작");
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 (PUB.AGV.signal1.mark_sensor == false)
{
if (seqtime.TotalSeconds > 3)
if (PUB.AGV.system1.agv_run == false)
{
//구동이확인되지 않으면 오류처리를 한다.
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
if (seqtime.TotalSeconds > 3)
{
//구동이확인되지 않으면 오류처리를 한다.
SetRunStepError(ENIGProtocol.AGVErrorCode.AGV_RUN_FAIL);
}
return false;
}
return false;
}
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 구동 확인 완료");
//마크스탑설정
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 명령 전송 (진출 정지 장소)");
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV 구동 확인 완료");
//마크스탑설정
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 명령 전송 (진출 정지 장소)");
}
PUB.sm.UpdateRunStepSeq();
return false;
}
else if (PUB.sm.RunStepSeq == idx++)
{
//마크스탑신호가 3초이내로 들어와야 한다
if (PUB.AGV.data.Speed != 'S')
if (PUB.AGV.signal1.mark_sensor == false)
{
if (seqtime.TotalSeconds > 3)
//마크스탑신호가 3초이내로 들어와야 한다
if (PUB.AGV.data.Speed != 'S')
{
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
if (seqtime.TotalSeconds > 3)
{
SetRunStepError(ENIGProtocol.AGVErrorCode.MARK_TIMEOUT);
return false;
}
return false;
}
return false;
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 신구 확인 완료");
}
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] MarkStop 신구 확인 완료");
else PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}]마크스탑이 미리 들어와있어. 이동및 스탑을 하지 않습니다");
PUB.sm.UpdateRunStepSeq();
return false;
}
@@ -173,18 +189,18 @@ namespace Project
else
{
//하드웨어 상태 확인
var turnState = PUB.AGV.TurnInformation?.State ?? arDev.eNarumiTurn.None;
if (turnState == arDev.eNarumiTurn.Right)
{
SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 버퍼진출시에는 LEFT-TURN 상태여야 합니다");
return false;
}
else
{
//정상 (None) -> 턴 명령 실행
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Right Turn 명령 전송");
PUB.AGV.AGVMoveRight180Turn();
}
//var turnState = PUB.AGV.TurnInformation?.StateOld ?? arDev.eNarumiTurn.None;
//if (turnState == arDev.eNarumiTurn.Right)
//{
// SetRunStepError(ENIGProtocol.AGVErrorCode.TURN_FAIL, $"[{funcname}-{PUB.sm.RunStepSeq}] 턴 방향 불일치(Current:{turnState}). 버퍼진출시에는 LEFT-TURN 상태여야 합니다");
// return false;
//}
//else
//{
//정상 (None) -> 턴 명령 실행
PUB.log.Add($"[{funcname}-{PUB.sm.RunStepSeq}] AGV Right Turn 명령 전송");
PUB.AGV.AGVMoveRight180Turn();
//}
}
PUB.sm.UpdateRunStepSeq();
return false;

View File

@@ -80,6 +80,8 @@ namespace Project
{
errmsg = ENIGProtocol.AGVUtility.GetAGVErrorMessage(ecode);
}
PUB.Result.ResultMessage = errmsg;
PUB.XBE.SendError(ecode);
PUB.AGV.AGVMoveStop(errmsg);
PUB.log.AddE(errmsg);

View File

@@ -61,12 +61,8 @@ namespace Project
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);
}
if (PUB._virtualAGV != null && PUB._virtualAGV.CurrentDirection != syncDir)
PUB.UpdateAGVDirection(syncDir);
// [Sync] Update VirtualAGV State
AGVState syncState = AGVState.Idle;
@@ -107,7 +103,7 @@ namespace Project
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)
@@ -117,15 +113,6 @@ namespace Project
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)
@@ -155,9 +142,9 @@ namespace Project
case arDev.Narumi.DataType.TAG:
{
//자동 실행 중이다.
PUB.Result.LastTAG = PUB.AGV.data.TagNo;//.ToString("0000");
PUB.log.Add($"[_AGV] AGV 태그수신 : {PUB.AGV.data.TagNo} LastTag:{PUB.Result.LastTAG}");
//POT/NOT 보면 일단 바로 멈추게한다
if (PUB.Result.CurrentPos == ePosition.POT || PUB.Result.CurrentPos == ePosition.NOT)
{
@@ -197,8 +184,7 @@ namespace Project
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.SaveLastPosition();
}
//태그를 읽었다면 상태를 바로 전송한다
@@ -264,7 +250,6 @@ namespace Project
$"S/W 턴 상태: {PUB._virtualAGV.Turn}\n" +
$"H/W 턴 상태: {PUB.AGV.TurnInformation?.State}\n" +
$"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" +
$"대상 노드: {targetpos}\n" +
$"상세 경로: {pathdetail}";

View File

@@ -206,7 +206,6 @@ namespace Project
if (PUB._mapCanvas != null)
PUB._mapCanvas.SetSyncStatus("설정 동기화", 0f, "환경설정 값으로 AGV컨트롤러를 설정 합니다");
}));
}
if (_SM_RUN_SYNC(runStepisFirst, PUB.sm.GetRunSteptime))
{

View File

@@ -39,9 +39,17 @@ namespace Project
//대상디바이스
var TargetID = data[0];
//해당 패킷의 대상이 나라면 처리한다.
//해당 패킷의 대상이 내가아니면 처리하지 않는다
if (PUB.setting.XBE_ID != TargetID) return;
//자동실행모드가 아니라면 무조건 에러를 반환한다
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
{
SetRunStepError(ENIGProtocol.AGVErrorCode.ManualMode, "현재 자동실행 모드가 아닙니다");
return;
}
switch (cmd)
{
@@ -56,8 +64,8 @@ namespace Project
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}");
var ermsg = ($"[{logPrefix}-SetCurrent] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, ermsg);
return;
}
else
@@ -83,16 +91,16 @@ namespace Project
var currNode = PUB._virtualAGV.CurrentNode;
if (currNode == null)
{
PUB.log.AddE($"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Current Node");
var msg = $"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다";
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, msg);
return;
}
var targetNode = PUB._virtualAGV.TargetNode;
if (targetNode == null)
{
PUB.log.AddE($"[{logPrefix}-{cmd}] 목표 노드를 알 수 없습니다");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Target Node");
var msg = $"[{logPrefix}-{cmd}] 목표 노드를 알 수 없습니다";
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, msg);
return;
}
@@ -119,7 +127,7 @@ namespace Project
PUB.sm.SetNewRunStep(nextStep);
}
break;
case ENIGProtocol.AGVCommandHE.PickOnExit:
case ENIGProtocol.AGVCommandHE.PickOnExit:
case ENIGProtocol.AGVCommandHE.PickOffExit:
{
Resultclear();
@@ -129,16 +137,16 @@ namespace Project
var currNode = PUB._virtualAGV.CurrentNode;
if (currNode == null)
{
PUB.log.AddE($"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Current Node");
var msg = $"[{logPrefix}-{cmd}] 현재 노드를 알 수 없습니다";
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, msg);
return;
}
var targetNode = PUB._virtualAGV.TargetNode;
if (targetNode == null)
{
PUB.log.AddE($"[{logPrefix}-{cmd}] 목표 노드를 알 수 없습니다");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, "Unknown Target Node");
var msg = $"[{logPrefix}-{cmd}] 목표 노드를 알 수 없습니다";
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, msg);
return;
}
@@ -198,8 +206,7 @@ namespace Project
//자동상태가아니라면 처리하지 않는다.
if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
{
PUB.log.AddE($"[{logPrefix}-Goto] 자동실행상태가 아닙니다");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.ManualMode, $"{currTag}");
SetRunStepError(ENIGProtocol.AGVErrorCode.ManualMode, $"[{logPrefix}-Goto] 자동실행상태가 아닙니다");
return;
}
@@ -207,8 +214,7 @@ namespace Project
PUB._virtualAGV.TargetNode = targetNode;
if (targetNode == null)
{
PUB.log.AddE($"[{logPrefix}-Goto] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.EmptyNode, $"{currTag}");
SetRunStepError(ENIGProtocol.AGVErrorCode.EmptyNode, $"[{logPrefix}-Goto] 노드정보를 찾을 수 없습니다 RFID:{currTag}");
return;
}
@@ -348,8 +354,7 @@ namespace Project
break;
default:
PUB.logagv.AddE($"Unknown Command : {cmd} Sender:{e.ReceivedPacket.ID}, Target:{data[0]}");
PUB.XBE.SendError(ENIGProtocol.AGVErrorCode.UnknownCommand, $"{cmd}");
SetRunStepError(ENIGProtocol.AGVErrorCode.UnknownCommand, $"Unknown Command : {cmd} Sender:{e.ReceivedPacket.ID}, Target:{data[0]}");
break;
}
}

View File

@@ -289,21 +289,17 @@ namespace Project
PUB._mapCanvas.MapFileName = filePath.FullName;
// 🔥 가상 AGV 초기화 (첫 노드 위치에 생성)
if (PUB._virtualAGV == null && PUB._mapCanvas.Nodes.Count > 0)
if (PUB._virtualAGV == null)
{
var startNode = PUB._mapCanvas.Nodes.FirstOrDefault(n => n.IsNavigationNode());
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);
PUB._virtualAGV = new VirtualAGV(PUB.setting.MCID, Point.Empty, AgvDirection.Forward);
PUB._virtualAGV.LowBatteryThreshold = PUB.setting.BatteryLimit_Low;
//PUB._virtualAGV.SetPosition(startNode, AgvDirection.Forward);
// 캔버스에 AGV 리스트 설정
var agvList = new System.Collections.Generic.List<AGVNavigationCore.Controls.IAGV> { PUB._virtualAGV };
PUB._mapCanvas.AGVList = agvList;
// 캔버스에 AGV 리스트 설정
var agvList = new System.Collections.Generic.List<AGVNavigationCore.Controls.IAGV> { PUB._virtualAGV };
PUB._mapCanvas.AGVList = agvList;
PUB.log.Add($"가상 AGV 생성: {startNode.Id} 위치");
}
PUB.log.Add($"가상 AGV 생성: PointZero 위치");
}
else if (PUB._virtualAGV != null)
{
@@ -313,6 +309,25 @@ namespace Project
PUB._mapCanvas.AGVList = agvList;
}
PUB.log.Add($"맵 파일 로드 완료: {filePath.Name}, 노드 수: {result.Nodes.Count}");
// 🔥 초기 위치 설정 및 확인 화면 표시
this.BeginInvoke(new Action(() =>
{
using (var f = new Dialog.fSetCurrentPosition())
{
if (f.ShowDialog() == DialogResult.OK)
{
if (f.SelectedNode != null)
{
PUB._virtualAGV.Turn = f.SelectedTurn;
PUB._virtualAGV.SetPosition(f.SelectedNode, f.SelectedDirection);
PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, f.SelectedNode, f.SelectedDirection);
PUB.SaveLastPosition();
PUB.log.Add($"[초기위치] 설정 완료: {f.SelectedNode.Id}, {f.SelectedDirection}, Turn:{f.SelectedTurn}");
}
}
}
}));
}
else
{

View File

@@ -34,6 +34,7 @@ namespace arDev
}
}
public eNarumiTurn State { get; set; }
//public eNarumiTurn StateNew { get; set; }
public NarumiTurnInfo()
{
Start = new DateTime(1982, 11, 23);

View File

@@ -160,11 +160,19 @@ namespace arDev
// [Turn Completion Check]
if (frame.DataString.Contains("LEFT-TURN OK"))
{
if (TurnInformation != null) { TurnInformation.State = eNarumiTurn.Left; TurnInformation.End = DateTime.Now; }
if (TurnInformation != null)
{
TurnInformation.State = eNarumiTurn.Left;
TurnInformation.End = DateTime.Now;
}
}
else if (frame.DataString.Contains("RIGHT-TURN OK"))
{
if (TurnInformation != null) { TurnInformation.State = eNarumiTurn.Right; TurnInformation.End = DateTime.Now; }
if (TurnInformation != null)
{
TurnInformation.State = eNarumiTurn.Right;
TurnInformation.End = DateTime.Now;
}
}
// $로 시작되는 AGV 상태 표시
//var text_Sts_Etc = Encoding.Default.GetString(bRcvData, 3, bRcvData.Length - 2).TrimStart(' '); //20210311 김정만 - SmartX FrameWork 사용 안함으로 주석처리
@@ -278,23 +286,23 @@ namespace arDev
//agv가 멈춰있고 들어온경우, 턴 작업이었다면 턴 셋팅을 한다
// [REMOVED] Logic replaced by message-based check ($AGV...TURN OK)
if (false && system1.agv_run == false && system1.agv_stop == true &&
TurnInformation != null)
{
if (TurnInformation.Start.Year > 2000)
{
if (TurnInformation.State == eNarumiTurn.LeftIng || TurnInformation.State == eNarumiTurn.RightIng)
{
TurnInformation.End = DateTime.Now;
if (TurnInformation.State == eNarumiTurn.LeftIng) TurnInformation.State = eNarumiTurn.Left;
if (TurnInformation.State == eNarumiTurn.RightIng) TurnInformation.State = eNarumiTurn.Right;
}
}
else
{
//시작시간이 설정되지 않았다면 처리하지 않는다.
}
}
//if (false && system1.agv_run == false && system1.agv_stop == true &&
// TurnInformation != null)
//{
// if (TurnInformation.Start.Year > 2000)
// {
// if (TurnInformation.StateNew == eNarumiTurn.LeftIng || TurnInformation.StateNew == eNarumiTurn.RightIng)
// {
// TurnInformation.End = DateTime.Now;
// if (TurnInformation.State == eNarumiTurn.LeftIng) TurnInformation.State = eNarumiTurn.Left;
// if (TurnInformation.State == eNarumiTurn.RightIng) TurnInformation.State = eNarumiTurn.Right;
// }
// }
// else
// {
// //시작시간이 설정되지 않았다면 처리하지 않는다.
// }
//}
if (idx <= rcvdNow.Length - 2)
{