..
This commit is contained in:
@@ -15,7 +15,8 @@ namespace AGVEmulator
|
|||||||
public UInt16 system0 = 0;
|
public UInt16 system0 = 0;
|
||||||
public UInt16 system1 = 0;
|
public UInt16 system1 = 0;
|
||||||
public UInt16 error = 0;
|
public UInt16 error = 0;
|
||||||
public byte signal = 0;
|
public byte signal1 = 0;
|
||||||
|
public byte signal2 = 0;
|
||||||
public char sts_bunki = 'S';
|
public char sts_bunki = 'S';
|
||||||
public char sts_speed = 'L';
|
public char sts_speed = 'L';
|
||||||
public char sts_dir = 'F';
|
public char sts_dir = 'F';
|
||||||
@@ -57,16 +58,22 @@ namespace AGVEmulator
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
cross_ctrl_comm_error,
|
cross_ctrl_comm_error,
|
||||||
}
|
}
|
||||||
public enum esignal
|
public enum esignal2
|
||||||
|
{
|
||||||
|
cart_detect1 = 0,
|
||||||
|
cart_detect2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum esignal1
|
||||||
{
|
{
|
||||||
front_gate_out = 0,
|
front_gate_out = 0,
|
||||||
rear_sensor_out,
|
rear_sensor_out,
|
||||||
mark_sensor_1,
|
mark_sensor_1,
|
||||||
mark_sensor_2,
|
mark_sensor_2,
|
||||||
front_left_sensor,
|
|
||||||
front_right_sensor,
|
|
||||||
front_center_sensor,
|
|
||||||
charger_align_sensor,
|
charger_align_sensor,
|
||||||
|
lift_up,
|
||||||
|
lift_down,
|
||||||
|
magnet_on
|
||||||
}
|
}
|
||||||
public enum esystemflag0
|
public enum esystemflag0
|
||||||
{
|
{
|
||||||
@@ -119,7 +126,8 @@ namespace AGVEmulator
|
|||||||
system0,
|
system0,
|
||||||
system1,
|
system1,
|
||||||
error,
|
error,
|
||||||
signal,
|
signal1,
|
||||||
|
signal2,
|
||||||
}
|
}
|
||||||
public enum estsvaluetype
|
public enum estsvaluetype
|
||||||
{
|
{
|
||||||
@@ -266,11 +274,17 @@ namespace AGVEmulator
|
|||||||
if (SetBit(ref error, idx, value))
|
if (SetBit(ref error, idx, value))
|
||||||
ValueChanged?.Invoke(this, new ValueChangedArgs(idx, value, evaluetype.error));
|
ValueChanged?.Invoke(this, new ValueChangedArgs(idx, value, evaluetype.error));
|
||||||
}
|
}
|
||||||
public void SetAGV(DevAGV.esignal flag, bool value)
|
public void SetAGV(DevAGV.esignal1 flag, bool value)
|
||||||
{
|
{
|
||||||
var idx = (int)flag;
|
var idx = (int)flag;
|
||||||
if (SetBit(ref signal, idx, value))
|
if (SetBit(ref signal1, idx, value))
|
||||||
ValueChanged?.Invoke(this, new ValueChangedArgs(idx, value, evaluetype.signal));
|
ValueChanged?.Invoke(this, new ValueChangedArgs(idx, value, evaluetype.signal1));
|
||||||
|
}
|
||||||
|
public void SetAGV(DevAGV.esignal2 flag, bool value)
|
||||||
|
{
|
||||||
|
var idx = (int)flag;
|
||||||
|
if (SetBit(ref signal2, idx, value))
|
||||||
|
ValueChanged?.Invoke(this, new ValueChangedArgs(idx, value, evaluetype.signal2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSTS(estsvaluetype target, char value)
|
public void SetSTS(estsvaluetype target, char value)
|
||||||
@@ -311,6 +325,29 @@ namespace AGVEmulator
|
|||||||
|
|
||||||
switch (frame.cmd)
|
switch (frame.cmd)
|
||||||
{
|
{
|
||||||
|
case "CLF"://마그넷 * 리프트
|
||||||
|
var cmd2 = frame.data.Substring(0, 2);
|
||||||
|
switch(cmd2)
|
||||||
|
{
|
||||||
|
case "ON":
|
||||||
|
SetAGV(esignal1.magnet_on, true);
|
||||||
|
break;
|
||||||
|
case "UP":
|
||||||
|
SetAGV(esignal1.lift_down, false);
|
||||||
|
SetAGV(esignal1.lift_up, true);
|
||||||
|
break;
|
||||||
|
case "DN":
|
||||||
|
SetAGV(esignal1.lift_up, false);
|
||||||
|
SetAGV(esignal1.lift_down, true);
|
||||||
|
break;
|
||||||
|
case "ST":
|
||||||
|
break;
|
||||||
|
case "OF":
|
||||||
|
SetAGV(esignal1.magnet_on, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "CRN": //기동명령
|
case "CRN": //기동명령
|
||||||
//sts_dir = frame.data[0];
|
//sts_dir = frame.data[0];
|
||||||
SetSTS(estsvaluetype.direction, frame.data[0]);
|
SetSTS(estsvaluetype.direction, frame.data[0]);
|
||||||
@@ -472,11 +509,12 @@ namespace AGVEmulator
|
|||||||
barr[20] = (byte)this.sts_bunki;
|
barr[20] = (byte)this.sts_bunki;
|
||||||
barr[21] = (byte)this.sts_dir;
|
barr[21] = (byte)this.sts_dir;
|
||||||
barr[22] = (byte)this.sts_sensor;
|
barr[22] = (byte)this.sts_sensor;
|
||||||
//bufarr = System.Text.Encoding.Default.GetBytes(p.sensor.ToString().PadLeft(2, '0'));
|
|
||||||
//Array.Copy(bufarr, 0, barr, 22, bufarr.Length);
|
bufarr = System.Text.Encoding.Default.GetBytes(signal1.ToString("X2").PadLeft(2, '0'));
|
||||||
bufarr = System.Text.Encoding.Default.GetBytes(signal.ToString("X2").PadLeft(2, '0'));
|
|
||||||
Array.Copy(bufarr, 0, barr, 23, bufarr.Length);
|
Array.Copy(bufarr, 0, barr, 23, bufarr.Length);
|
||||||
//barr[22] = (byte)'5';
|
|
||||||
|
bufarr = System.Text.Encoding.Default.GetBytes(signal2.ToString("X2").PadLeft(2, '0'));
|
||||||
|
Array.Copy(bufarr, 0, barr, 25, bufarr.Length);
|
||||||
|
|
||||||
barr[barr.Length - 3] = (byte)'*';
|
barr[barr.Length - 3] = (byte)'*';
|
||||||
barr[barr.Length - 2] = (byte)'*';
|
barr[barr.Length - 2] = (byte)'*';
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ namespace AGVEmulator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DevAGV.evaluetype.signal:
|
case DevAGV.evaluetype.signal1:
|
||||||
foreach (CheckBox c in panel8.Controls)
|
foreach (CheckBox c in panel8.Controls)
|
||||||
{
|
{
|
||||||
var idx = int.Parse(c.Tag.ToString());
|
var idx = int.Parse(c.Tag.ToString());
|
||||||
@@ -153,7 +153,17 @@ namespace AGVEmulator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DevAGV.evaluetype.signal2:
|
||||||
|
foreach (CheckBox c in panel2.Controls)
|
||||||
|
{
|
||||||
|
var idx = int.Parse(c.Tag.ToString());
|
||||||
|
if (idx == e.Idx)
|
||||||
|
{
|
||||||
|
c.Checked = e.Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +178,8 @@ namespace AGVEmulator
|
|||||||
aaplycheckboxbit(ref AGV.system0, panel6);
|
aaplycheckboxbit(ref AGV.system0, panel6);
|
||||||
aaplycheckboxbit(ref AGV.system1, panel7);
|
aaplycheckboxbit(ref AGV.system1, panel7);
|
||||||
aaplycheckboxbit(ref AGV.error, panel9);
|
aaplycheckboxbit(ref AGV.error, panel9);
|
||||||
aaplycheckboxbit(ref AGV.signal, panel8);
|
aaplycheckboxbit(ref AGV.signal1, panel8);
|
||||||
|
aaplycheckboxbit(ref AGV.signal2, panel2);
|
||||||
|
|
||||||
if (this.agvViewer1.StopbyMark) AGV.sts_speed = 'S';
|
if (this.agvViewer1.StopbyMark) AGV.sts_speed = 'S';
|
||||||
else AGV.sts_speed = GetGroupItemCheckbox(groupBox4);
|
else AGV.sts_speed = GetGroupItemCheckbox(groupBox4);
|
||||||
|
|||||||
458
AGVEmulator/fMain.Designer.cs
generated
458
AGVEmulator/fMain.Designer.cs
generated
@@ -32,35 +32,35 @@ namespace AGVEmulator
|
|||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.components = new System.ComponentModel.Container();
|
this.components = new System.ComponentModel.Container();
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata57 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata58 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata59 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata60 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata61 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata62 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata63 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata64 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata65 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata66 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata67 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata68 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata69 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata70 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata71 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata72 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata73 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata74 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata75 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata76 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata77 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata78 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata79 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata80 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata81 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata82 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata83 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
AGVEmulator.UC.AgvViewer.ptdata ptdata84 = new AGVEmulator.UC.AgvViewer.ptdata();
|
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fMain));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fMain));
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata1 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata2 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata3 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata4 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata5 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata6 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata7 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata8 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata9 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata10 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata11 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata12 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata13 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata14 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata15 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata16 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata17 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata18 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata19 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata20 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata21 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata22 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata23 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata24 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata25 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata26 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata27 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
|
AGVEmulator.UC.AgvViewer.ptdata ptdata28 = new AGVEmulator.UC.AgvViewer.ptdata();
|
||||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
this.rtBMS = new arCtl.LogTextBox();
|
this.rtBMS = new arCtl.LogTextBox();
|
||||||
this.panel1 = new System.Windows.Forms.Panel();
|
this.panel1 = new System.Windows.Forms.Panel();
|
||||||
@@ -86,11 +86,11 @@ namespace AGVEmulator
|
|||||||
this.label2 = new System.Windows.Forms.Label();
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
this.label1 = new System.Windows.Forms.Label();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.trackBar1 = new System.Windows.Forms.TrackBar();
|
this.trackBar1 = new System.Windows.Forms.TrackBar();
|
||||||
this.serBMS = new AGVEmulator.SerialConn();
|
|
||||||
this.rtAGV = new arCtl.LogTextBox();
|
this.rtAGV = new arCtl.LogTextBox();
|
||||||
this.panel4 = new System.Windows.Forms.Panel();
|
this.panel4 = new System.Windows.Forms.Panel();
|
||||||
this.groupBox9 = new System.Windows.Forms.GroupBox();
|
this.groupBox9 = new System.Windows.Forms.GroupBox();
|
||||||
this.groupBox10 = new System.Windows.Forms.GroupBox();
|
this.groupBox10 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.panel2 = new System.Windows.Forms.Panel();
|
||||||
this.panel8 = new System.Windows.Forms.Panel();
|
this.panel8 = new System.Windows.Forms.Panel();
|
||||||
this.groupBox11 = new System.Windows.Forms.GroupBox();
|
this.groupBox11 = new System.Windows.Forms.GroupBox();
|
||||||
this.panel9 = new System.Windows.Forms.Panel();
|
this.panel9 = new System.Windows.Forms.Panel();
|
||||||
@@ -128,7 +128,6 @@ namespace AGVEmulator
|
|||||||
this.button4 = new System.Windows.Forms.Button();
|
this.button4 = new System.Windows.Forms.Button();
|
||||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||||
this.rtCAL = new arCtl.LogTextBox();
|
this.rtCAL = new arCtl.LogTextBox();
|
||||||
this.serCAL = new AGVEmulator.SerialConn();
|
|
||||||
this.timer1 = new System.Windows.Forms.Timer(this.components);
|
this.timer1 = new System.Windows.Forms.Timer(this.components);
|
||||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||||
this.tabPage4 = new System.Windows.Forms.TabPage();
|
this.tabPage4 = new System.Windows.Forms.TabPage();
|
||||||
@@ -136,11 +135,11 @@ namespace AGVEmulator
|
|||||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||||
this.rtAGVPro = new arCtl.LogTextBox();
|
this.rtAGVPro = new arCtl.LogTextBox();
|
||||||
this.panel12 = new System.Windows.Forms.Panel();
|
this.panel12 = new System.Windows.Forms.Panel();
|
||||||
this.agvViewer1 = new AGVEmulator.UC.AgvViewer();
|
|
||||||
this.serAGV = new AGVEmulator.SerialConn();
|
|
||||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||||
this.tabPage3 = new System.Windows.Forms.TabPage();
|
this.tabPage3 = new System.Windows.Forms.TabPage();
|
||||||
this.panel3 = new System.Windows.Forms.Panel();
|
this.panel3 = new System.Windows.Forms.Panel();
|
||||||
|
this.button3 = new System.Windows.Forms.Button();
|
||||||
|
this.button2 = new System.Windows.Forms.Button();
|
||||||
this.nudIDAgv = new System.Windows.Forms.NumericUpDown();
|
this.nudIDAgv = new System.Windows.Forms.NumericUpDown();
|
||||||
this.label7 = new System.Windows.Forms.Label();
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
this.numericUpDown2 = new System.Windows.Forms.NumericUpDown();
|
this.numericUpDown2 = new System.Windows.Forms.NumericUpDown();
|
||||||
@@ -167,8 +166,10 @@ namespace AGVEmulator
|
|||||||
this.sbBMS = new System.Windows.Forms.ToolStripStatusLabel();
|
this.sbBMS = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
|
this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.sbCAL = new System.Windows.Forms.ToolStripStatusLabel();
|
this.sbCAL = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.button2 = new System.Windows.Forms.Button();
|
this.agvViewer1 = new AGVEmulator.UC.AgvViewer();
|
||||||
this.button3 = new System.Windows.Forms.Button();
|
this.serAGV = new AGVEmulator.SerialConn();
|
||||||
|
this.serBMS = new AGVEmulator.SerialConn();
|
||||||
|
this.serCAL = new AGVEmulator.SerialConn();
|
||||||
this.groupBox1.SuspendLayout();
|
this.groupBox1.SuspendLayout();
|
||||||
this.panel1.SuspendLayout();
|
this.panel1.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.trbT2)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.trbT2)).BeginInit();
|
||||||
@@ -503,18 +504,6 @@ namespace AGVEmulator
|
|||||||
this.trackBar1.Value = 7000;
|
this.trackBar1.Value = 7000;
|
||||||
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
|
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
|
||||||
//
|
//
|
||||||
// serBMS
|
|
||||||
//
|
|
||||||
this.serBMS.BaudRate = 9600;
|
|
||||||
this.serBMS.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
|
||||||
this.serBMS.dev = null;
|
|
||||||
this.serBMS.Dock = System.Windows.Forms.DockStyle.Top;
|
|
||||||
this.serBMS.Location = new System.Drawing.Point(3, 17);
|
|
||||||
this.serBMS.Name = "serBMS";
|
|
||||||
this.serBMS.PortName = "COM31";
|
|
||||||
this.serBMS.Size = new System.Drawing.Size(1134, 84);
|
|
||||||
this.serBMS.TabIndex = 1;
|
|
||||||
//
|
|
||||||
// rtAGV
|
// rtAGV
|
||||||
//
|
//
|
||||||
this.rtAGV.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24)))));
|
this.rtAGV.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24)))));
|
||||||
@@ -563,6 +552,7 @@ namespace AGVEmulator
|
|||||||
//
|
//
|
||||||
// groupBox10
|
// groupBox10
|
||||||
//
|
//
|
||||||
|
this.groupBox10.Controls.Add(this.panel2);
|
||||||
this.groupBox10.Controls.Add(this.panel8);
|
this.groupBox10.Controls.Add(this.panel8);
|
||||||
this.groupBox10.Dock = System.Windows.Forms.DockStyle.Left;
|
this.groupBox10.Dock = System.Windows.Forms.DockStyle.Left;
|
||||||
this.groupBox10.Location = new System.Drawing.Point(652, 44);
|
this.groupBox10.Location = new System.Drawing.Point(652, 44);
|
||||||
@@ -572,16 +562,25 @@ namespace AGVEmulator
|
|||||||
this.groupBox10.TabStop = false;
|
this.groupBox10.TabStop = false;
|
||||||
this.groupBox10.Text = "signal";
|
this.groupBox10.Text = "signal";
|
||||||
//
|
//
|
||||||
|
// panel2
|
||||||
|
//
|
||||||
|
this.panel2.AutoScroll = true;
|
||||||
|
this.panel2.AutoSize = true;
|
||||||
|
this.panel2.Location = new System.Drawing.Point(3, 162);
|
||||||
|
this.panel2.Name = "panel2";
|
||||||
|
this.panel2.Size = new System.Drawing.Size(183, 68);
|
||||||
|
this.panel2.TabIndex = 1;
|
||||||
|
this.panel2.Tag = "sg2";
|
||||||
|
//
|
||||||
// panel8
|
// panel8
|
||||||
//
|
//
|
||||||
this.panel8.AutoScroll = true;
|
this.panel8.AutoScroll = true;
|
||||||
this.panel8.AutoSize = true;
|
this.panel8.AutoSize = true;
|
||||||
this.panel8.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.panel8.Location = new System.Drawing.Point(5, 11);
|
||||||
this.panel8.Location = new System.Drawing.Point(3, 17);
|
|
||||||
this.panel8.Name = "panel8";
|
this.panel8.Name = "panel8";
|
||||||
this.panel8.Size = new System.Drawing.Size(183, 213);
|
this.panel8.Size = new System.Drawing.Size(180, 127);
|
||||||
this.panel8.TabIndex = 1;
|
this.panel8.TabIndex = 1;
|
||||||
this.panel8.Tag = "sg";
|
this.panel8.Tag = "sg1";
|
||||||
//
|
//
|
||||||
// groupBox11
|
// groupBox11
|
||||||
//
|
//
|
||||||
@@ -998,18 +997,6 @@ namespace AGVEmulator
|
|||||||
this.rtCAL.TabIndex = 2;
|
this.rtCAL.TabIndex = 2;
|
||||||
this.rtCAL.Text = "";
|
this.rtCAL.Text = "";
|
||||||
//
|
//
|
||||||
// serCAL
|
|
||||||
//
|
|
||||||
this.serCAL.BaudRate = 9600;
|
|
||||||
this.serCAL.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
|
||||||
this.serCAL.dev = null;
|
|
||||||
this.serCAL.Dock = System.Windows.Forms.DockStyle.Top;
|
|
||||||
this.serCAL.Location = new System.Drawing.Point(3, 17);
|
|
||||||
this.serCAL.Name = "serCAL";
|
|
||||||
this.serCAL.PortName = "COM41";
|
|
||||||
this.serCAL.Size = new System.Drawing.Size(776, 84);
|
|
||||||
this.serCAL.TabIndex = 1;
|
|
||||||
//
|
|
||||||
// timer1
|
// timer1
|
||||||
//
|
//
|
||||||
this.timer1.Interval = 200;
|
this.timer1.Interval = 200;
|
||||||
@@ -1095,149 +1082,6 @@ namespace AGVEmulator
|
|||||||
this.panel12.Size = new System.Drawing.Size(1140, 120);
|
this.panel12.Size = new System.Drawing.Size(1140, 120);
|
||||||
this.panel12.TabIndex = 5;
|
this.panel12.TabIndex = 5;
|
||||||
//
|
//
|
||||||
// agvViewer1
|
|
||||||
//
|
|
||||||
this.agvViewer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
this.agvViewer1.FontMrk = new System.Drawing.Font("Microsoft Sans Serif", 7F);
|
|
||||||
this.agvViewer1.FontTag = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.agvViewer1.lastmark = "";
|
|
||||||
this.agvViewer1.lastmarkdir = "";
|
|
||||||
this.agvViewer1.lasttag = "";
|
|
||||||
this.agvViewer1.lasttagdir = "";
|
|
||||||
ptdata57.active = false;
|
|
||||||
ptdata57.data = "NOT";
|
|
||||||
ptdata57.pos = 30F;
|
|
||||||
ptdata58.active = false;
|
|
||||||
ptdata58.data = "QA";
|
|
||||||
ptdata58.pos = 200F;
|
|
||||||
ptdata59.active = false;
|
|
||||||
ptdata59.data = "CHG";
|
|
||||||
ptdata59.pos = 300F;
|
|
||||||
ptdata60.active = false;
|
|
||||||
ptdata60.data = "QC";
|
|
||||||
ptdata60.pos = 400F;
|
|
||||||
ptdata61.active = false;
|
|
||||||
ptdata61.data = "#FVI-1";
|
|
||||||
ptdata61.pos = 500F;
|
|
||||||
ptdata62.active = false;
|
|
||||||
ptdata62.data = "#FVI-2";
|
|
||||||
ptdata62.pos = 600F;
|
|
||||||
ptdata63.active = false;
|
|
||||||
ptdata63.data = "#FVI-3";
|
|
||||||
ptdata63.pos = 700F;
|
|
||||||
ptdata64.active = false;
|
|
||||||
ptdata64.data = "#FVI-4";
|
|
||||||
ptdata64.pos = 800F;
|
|
||||||
ptdata65.active = false;
|
|
||||||
ptdata65.data = "#FVI-5";
|
|
||||||
ptdata65.pos = 900F;
|
|
||||||
ptdata66.active = false;
|
|
||||||
ptdata66.data = "POT";
|
|
||||||
ptdata66.pos = 970F;
|
|
||||||
this.agvViewer1.listMRK = new AGVEmulator.UC.AgvViewer.ptdata[] {
|
|
||||||
ptdata57,
|
|
||||||
ptdata58,
|
|
||||||
ptdata59,
|
|
||||||
ptdata60,
|
|
||||||
ptdata61,
|
|
||||||
ptdata62,
|
|
||||||
ptdata63,
|
|
||||||
ptdata64,
|
|
||||||
ptdata65,
|
|
||||||
ptdata66};
|
|
||||||
ptdata67.active = false;
|
|
||||||
ptdata67.data = "9000";
|
|
||||||
ptdata67.pos = 80F;
|
|
||||||
ptdata68.active = false;
|
|
||||||
ptdata68.data = "9001";
|
|
||||||
ptdata68.pos = 120F;
|
|
||||||
ptdata69.active = false;
|
|
||||||
ptdata69.data = "9010";
|
|
||||||
ptdata69.pos = 180F;
|
|
||||||
ptdata70.active = false;
|
|
||||||
ptdata70.data = "9011";
|
|
||||||
ptdata70.pos = 220F;
|
|
||||||
ptdata71.active = false;
|
|
||||||
ptdata71.data = "9020";
|
|
||||||
ptdata71.pos = 280F;
|
|
||||||
ptdata72.active = false;
|
|
||||||
ptdata72.data = "9021";
|
|
||||||
ptdata72.pos = 320F;
|
|
||||||
ptdata73.active = false;
|
|
||||||
ptdata73.data = "9030";
|
|
||||||
ptdata73.pos = 380F;
|
|
||||||
ptdata74.active = false;
|
|
||||||
ptdata74.data = "9031";
|
|
||||||
ptdata74.pos = 420F;
|
|
||||||
ptdata75.active = false;
|
|
||||||
ptdata75.data = "9040";
|
|
||||||
ptdata75.pos = 480F;
|
|
||||||
ptdata76.active = false;
|
|
||||||
ptdata76.data = "9041";
|
|
||||||
ptdata76.pos = 520F;
|
|
||||||
ptdata77.active = false;
|
|
||||||
ptdata77.data = "9050";
|
|
||||||
ptdata77.pos = 580F;
|
|
||||||
ptdata78.active = false;
|
|
||||||
ptdata78.data = "9051";
|
|
||||||
ptdata78.pos = 620F;
|
|
||||||
ptdata79.active = false;
|
|
||||||
ptdata79.data = "9060";
|
|
||||||
ptdata79.pos = 680F;
|
|
||||||
ptdata80.active = false;
|
|
||||||
ptdata80.data = "9061";
|
|
||||||
ptdata80.pos = 720F;
|
|
||||||
ptdata81.active = false;
|
|
||||||
ptdata81.data = "9070";
|
|
||||||
ptdata81.pos = 780F;
|
|
||||||
ptdata82.active = false;
|
|
||||||
ptdata82.data = "9071";
|
|
||||||
ptdata82.pos = 820F;
|
|
||||||
ptdata83.active = false;
|
|
||||||
ptdata83.data = "9000";
|
|
||||||
ptdata83.pos = 10F;
|
|
||||||
ptdata84.active = false;
|
|
||||||
ptdata84.data = "9001";
|
|
||||||
ptdata84.pos = 50F;
|
|
||||||
this.agvViewer1.listTAG = new AGVEmulator.UC.AgvViewer.ptdata[] {
|
|
||||||
ptdata67,
|
|
||||||
ptdata68,
|
|
||||||
ptdata69,
|
|
||||||
ptdata70,
|
|
||||||
ptdata71,
|
|
||||||
ptdata72,
|
|
||||||
ptdata73,
|
|
||||||
ptdata74,
|
|
||||||
ptdata75,
|
|
||||||
ptdata76,
|
|
||||||
ptdata77,
|
|
||||||
ptdata78,
|
|
||||||
ptdata79,
|
|
||||||
ptdata80,
|
|
||||||
ptdata81,
|
|
||||||
ptdata82,
|
|
||||||
ptdata83,
|
|
||||||
ptdata84};
|
|
||||||
this.agvViewer1.Location = new System.Drawing.Point(241, 0);
|
|
||||||
this.agvViewer1.Name = "agvViewer1";
|
|
||||||
this.agvViewer1.Size = new System.Drawing.Size(899, 120);
|
|
||||||
this.agvViewer1.StopbyMark = false;
|
|
||||||
this.agvViewer1.TabIndex = 0;
|
|
||||||
this.agvViewer1.Text = "agvViewer1";
|
|
||||||
this.agvViewer1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agvViewer1_MouseDown);
|
|
||||||
//
|
|
||||||
// serAGV
|
|
||||||
//
|
|
||||||
this.serAGV.BaudRate = 9600;
|
|
||||||
this.serAGV.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
|
||||||
this.serAGV.dev = null;
|
|
||||||
this.serAGV.Dock = System.Windows.Forms.DockStyle.Left;
|
|
||||||
this.serAGV.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.serAGV.Name = "serAGV";
|
|
||||||
this.serAGV.PortName = "COM21";
|
|
||||||
this.serAGV.Size = new System.Drawing.Size(241, 120);
|
|
||||||
this.serAGV.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// tabPage2
|
// tabPage2
|
||||||
//
|
//
|
||||||
this.tabPage2.Controls.Add(this.groupBox1);
|
this.tabPage2.Controls.Add(this.groupBox1);
|
||||||
@@ -1282,6 +1126,28 @@ namespace AGVEmulator
|
|||||||
this.panel3.Size = new System.Drawing.Size(364, 622);
|
this.panel3.Size = new System.Drawing.Size(364, 622);
|
||||||
this.panel3.TabIndex = 15;
|
this.panel3.TabIndex = 15;
|
||||||
//
|
//
|
||||||
|
// button3
|
||||||
|
//
|
||||||
|
this.button3.Location = new System.Drawing.Point(246, 339);
|
||||||
|
this.button3.Name = "button3";
|
||||||
|
this.button3.Size = new System.Drawing.Size(86, 38);
|
||||||
|
this.button3.TabIndex = 15;
|
||||||
|
this.button3.Tag = "--";
|
||||||
|
this.button3.Text = "Pick Off";
|
||||||
|
this.button3.UseVisualStyleBackColor = true;
|
||||||
|
this.button3.Click += new System.EventHandler(this.button3_Click);
|
||||||
|
//
|
||||||
|
// button2
|
||||||
|
//
|
||||||
|
this.button2.Location = new System.Drawing.Point(246, 295);
|
||||||
|
this.button2.Name = "button2";
|
||||||
|
this.button2.Size = new System.Drawing.Size(86, 38);
|
||||||
|
this.button2.TabIndex = 14;
|
||||||
|
this.button2.Tag = "--";
|
||||||
|
this.button2.Text = "Pick On";
|
||||||
|
this.button2.UseVisualStyleBackColor = true;
|
||||||
|
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||||
|
//
|
||||||
// nudIDAgv
|
// nudIDAgv
|
||||||
//
|
//
|
||||||
this.nudIDAgv.Font = new System.Drawing.Font("굴림", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
this.nudIDAgv.Font = new System.Drawing.Font("굴림", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
|
||||||
@@ -1542,27 +1408,172 @@ namespace AGVEmulator
|
|||||||
this.sbCAL.Size = new System.Drawing.Size(19, 17);
|
this.sbCAL.Size = new System.Drawing.Size(19, 17);
|
||||||
this.sbCAL.Text = "●";
|
this.sbCAL.Text = "●";
|
||||||
//
|
//
|
||||||
// button2
|
// agvViewer1
|
||||||
//
|
//
|
||||||
this.button2.Location = new System.Drawing.Point(246, 295);
|
this.agvViewer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.button2.Name = "button2";
|
this.agvViewer1.FontMrk = new System.Drawing.Font("Microsoft Sans Serif", 7F);
|
||||||
this.button2.Size = new System.Drawing.Size(86, 38);
|
this.agvViewer1.FontTag = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.button2.TabIndex = 14;
|
this.agvViewer1.lastmark = "";
|
||||||
this.button2.Tag = "--";
|
this.agvViewer1.lastmarkdir = "";
|
||||||
this.button2.Text = "Pick On";
|
this.agvViewer1.lasttag = "";
|
||||||
this.button2.UseVisualStyleBackColor = true;
|
this.agvViewer1.lasttagdir = "";
|
||||||
this.button2.Click += new System.EventHandler(this.button2_Click);
|
ptdata1.active = false;
|
||||||
|
ptdata1.data = "NOT";
|
||||||
|
ptdata1.pos = 30F;
|
||||||
|
ptdata2.active = false;
|
||||||
|
ptdata2.data = "QA";
|
||||||
|
ptdata2.pos = 200F;
|
||||||
|
ptdata3.active = false;
|
||||||
|
ptdata3.data = "CHG";
|
||||||
|
ptdata3.pos = 300F;
|
||||||
|
ptdata4.active = false;
|
||||||
|
ptdata4.data = "QC";
|
||||||
|
ptdata4.pos = 400F;
|
||||||
|
ptdata5.active = false;
|
||||||
|
ptdata5.data = "#FVI-1";
|
||||||
|
ptdata5.pos = 500F;
|
||||||
|
ptdata6.active = false;
|
||||||
|
ptdata6.data = "#FVI-2";
|
||||||
|
ptdata6.pos = 600F;
|
||||||
|
ptdata7.active = false;
|
||||||
|
ptdata7.data = "#FVI-3";
|
||||||
|
ptdata7.pos = 700F;
|
||||||
|
ptdata8.active = false;
|
||||||
|
ptdata8.data = "#FVI-4";
|
||||||
|
ptdata8.pos = 800F;
|
||||||
|
ptdata9.active = false;
|
||||||
|
ptdata9.data = "#FVI-5";
|
||||||
|
ptdata9.pos = 900F;
|
||||||
|
ptdata10.active = false;
|
||||||
|
ptdata10.data = "POT";
|
||||||
|
ptdata10.pos = 970F;
|
||||||
|
this.agvViewer1.listMRK = new AGVEmulator.UC.AgvViewer.ptdata[] {
|
||||||
|
ptdata1,
|
||||||
|
ptdata2,
|
||||||
|
ptdata3,
|
||||||
|
ptdata4,
|
||||||
|
ptdata5,
|
||||||
|
ptdata6,
|
||||||
|
ptdata7,
|
||||||
|
ptdata8,
|
||||||
|
ptdata9,
|
||||||
|
ptdata10};
|
||||||
|
ptdata11.active = false;
|
||||||
|
ptdata11.data = "9000";
|
||||||
|
ptdata11.pos = 80F;
|
||||||
|
ptdata12.active = false;
|
||||||
|
ptdata12.data = "9001";
|
||||||
|
ptdata12.pos = 120F;
|
||||||
|
ptdata13.active = false;
|
||||||
|
ptdata13.data = "9010";
|
||||||
|
ptdata13.pos = 180F;
|
||||||
|
ptdata14.active = false;
|
||||||
|
ptdata14.data = "9011";
|
||||||
|
ptdata14.pos = 220F;
|
||||||
|
ptdata15.active = false;
|
||||||
|
ptdata15.data = "9020";
|
||||||
|
ptdata15.pos = 280F;
|
||||||
|
ptdata16.active = false;
|
||||||
|
ptdata16.data = "9021";
|
||||||
|
ptdata16.pos = 320F;
|
||||||
|
ptdata17.active = false;
|
||||||
|
ptdata17.data = "9030";
|
||||||
|
ptdata17.pos = 380F;
|
||||||
|
ptdata18.active = false;
|
||||||
|
ptdata18.data = "9031";
|
||||||
|
ptdata18.pos = 420F;
|
||||||
|
ptdata19.active = false;
|
||||||
|
ptdata19.data = "9040";
|
||||||
|
ptdata19.pos = 480F;
|
||||||
|
ptdata20.active = false;
|
||||||
|
ptdata20.data = "9041";
|
||||||
|
ptdata20.pos = 520F;
|
||||||
|
ptdata21.active = false;
|
||||||
|
ptdata21.data = "9050";
|
||||||
|
ptdata21.pos = 580F;
|
||||||
|
ptdata22.active = false;
|
||||||
|
ptdata22.data = "9051";
|
||||||
|
ptdata22.pos = 620F;
|
||||||
|
ptdata23.active = false;
|
||||||
|
ptdata23.data = "9060";
|
||||||
|
ptdata23.pos = 680F;
|
||||||
|
ptdata24.active = false;
|
||||||
|
ptdata24.data = "9061";
|
||||||
|
ptdata24.pos = 720F;
|
||||||
|
ptdata25.active = false;
|
||||||
|
ptdata25.data = "9070";
|
||||||
|
ptdata25.pos = 780F;
|
||||||
|
ptdata26.active = false;
|
||||||
|
ptdata26.data = "9071";
|
||||||
|
ptdata26.pos = 820F;
|
||||||
|
ptdata27.active = false;
|
||||||
|
ptdata27.data = "9000";
|
||||||
|
ptdata27.pos = 10F;
|
||||||
|
ptdata28.active = false;
|
||||||
|
ptdata28.data = "9001";
|
||||||
|
ptdata28.pos = 50F;
|
||||||
|
this.agvViewer1.listTAG = new AGVEmulator.UC.AgvViewer.ptdata[] {
|
||||||
|
ptdata11,
|
||||||
|
ptdata12,
|
||||||
|
ptdata13,
|
||||||
|
ptdata14,
|
||||||
|
ptdata15,
|
||||||
|
ptdata16,
|
||||||
|
ptdata17,
|
||||||
|
ptdata18,
|
||||||
|
ptdata19,
|
||||||
|
ptdata20,
|
||||||
|
ptdata21,
|
||||||
|
ptdata22,
|
||||||
|
ptdata23,
|
||||||
|
ptdata24,
|
||||||
|
ptdata25,
|
||||||
|
ptdata26,
|
||||||
|
ptdata27,
|
||||||
|
ptdata28};
|
||||||
|
this.agvViewer1.Location = new System.Drawing.Point(241, 0);
|
||||||
|
this.agvViewer1.Name = "agvViewer1";
|
||||||
|
this.agvViewer1.Size = new System.Drawing.Size(899, 120);
|
||||||
|
this.agvViewer1.StopbyMark = false;
|
||||||
|
this.agvViewer1.TabIndex = 0;
|
||||||
|
this.agvViewer1.Text = "agvViewer1";
|
||||||
|
this.agvViewer1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agvViewer1_MouseDown);
|
||||||
//
|
//
|
||||||
// button3
|
// serAGV
|
||||||
//
|
//
|
||||||
this.button3.Location = new System.Drawing.Point(246, 339);
|
this.serAGV.BaudRate = 9600;
|
||||||
this.button3.Name = "button3";
|
this.serAGV.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
this.button3.Size = new System.Drawing.Size(86, 38);
|
this.serAGV.dev = null;
|
||||||
this.button3.TabIndex = 15;
|
this.serAGV.Dock = System.Windows.Forms.DockStyle.Left;
|
||||||
this.button3.Tag = "--";
|
this.serAGV.Location = new System.Drawing.Point(0, 0);
|
||||||
this.button3.Text = "Pick Off";
|
this.serAGV.Name = "serAGV";
|
||||||
this.button3.UseVisualStyleBackColor = true;
|
this.serAGV.PortName = "COM21";
|
||||||
this.button3.Click += new System.EventHandler(this.button3_Click);
|
this.serAGV.Size = new System.Drawing.Size(241, 120);
|
||||||
|
this.serAGV.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// serBMS
|
||||||
|
//
|
||||||
|
this.serBMS.BaudRate = 9600;
|
||||||
|
this.serBMS.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
|
this.serBMS.dev = null;
|
||||||
|
this.serBMS.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
|
this.serBMS.Location = new System.Drawing.Point(3, 17);
|
||||||
|
this.serBMS.Name = "serBMS";
|
||||||
|
this.serBMS.PortName = "COM31";
|
||||||
|
this.serBMS.Size = new System.Drawing.Size(1134, 84);
|
||||||
|
this.serBMS.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// serCAL
|
||||||
|
//
|
||||||
|
this.serCAL.BaudRate = 9600;
|
||||||
|
this.serCAL.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||||
|
this.serCAL.dev = null;
|
||||||
|
this.serCAL.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
|
this.serCAL.Location = new System.Drawing.Point(3, 17);
|
||||||
|
this.serCAL.Name = "serCAL";
|
||||||
|
this.serCAL.PortName = "COM41";
|
||||||
|
this.serCAL.Size = new System.Drawing.Size(776, 84);
|
||||||
|
this.serCAL.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// fMain
|
// fMain
|
||||||
//
|
//
|
||||||
@@ -1734,6 +1745,7 @@ namespace AGVEmulator
|
|||||||
private ToolStripButton toolStripButton5;
|
private ToolStripButton toolStripButton5;
|
||||||
private Button button3;
|
private Button button3;
|
||||||
private Button button2;
|
private Button button2;
|
||||||
|
private Panel panel2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,10 +153,10 @@ namespace AGVEmulator
|
|||||||
chk.CheckedChanged += Chk_CheckedChanged;
|
chk.CheckedChanged += Chk_CheckedChanged;
|
||||||
this.panel7.Controls.Add(chk);
|
this.panel7.Controls.Add(chk);
|
||||||
}
|
}
|
||||||
arrs = Enum.GetNames(typeof(DevAGV.esignal));
|
arrs = Enum.GetNames(typeof(DevAGV.esignal1));
|
||||||
foreach (var item in arrs)
|
foreach (var item in arrs)
|
||||||
{
|
{
|
||||||
var data = (DevAGV.esignal)Enum.Parse(typeof(DevAGV.esignal), item);
|
var data = (DevAGV.esignal1)Enum.Parse(typeof(DevAGV.esignal1), item);
|
||||||
|
|
||||||
var chk = new CheckBox();
|
var chk = new CheckBox();
|
||||||
chk.Text = $"[{(int)data:00}] {item}";
|
chk.Text = $"[{(int)data:00}] {item}";
|
||||||
@@ -167,6 +167,20 @@ namespace AGVEmulator
|
|||||||
chk.CheckedChanged += Chk_CheckedChanged;
|
chk.CheckedChanged += Chk_CheckedChanged;
|
||||||
this.panel8.Controls.Add(chk);
|
this.panel8.Controls.Add(chk);
|
||||||
}
|
}
|
||||||
|
arrs = Enum.GetNames(typeof(DevAGV.esignal2));
|
||||||
|
foreach (var item in arrs)
|
||||||
|
{
|
||||||
|
var data = (DevAGV.esignal2)Enum.Parse(typeof(DevAGV.esignal2), item);
|
||||||
|
|
||||||
|
var chk = new CheckBox();
|
||||||
|
chk.Text = $"[{(int)data:00}] {item}";
|
||||||
|
chk.AutoSize = true;
|
||||||
|
chk.Visible = true;
|
||||||
|
chk.Tag = (int)data;
|
||||||
|
chk.Dock = DockStyle.Top;
|
||||||
|
chk.CheckedChanged += Chk_CheckedChanged;
|
||||||
|
this.panel2.Controls.Add(chk);
|
||||||
|
}
|
||||||
arrs = Enum.GetNames(typeof(DevAGV.eerror));
|
arrs = Enum.GetNames(typeof(DevAGV.eerror));
|
||||||
foreach (var item in arrs)
|
foreach (var item in arrs)
|
||||||
{
|
{
|
||||||
@@ -344,7 +358,7 @@ namespace AGVEmulator
|
|||||||
private void AgvViewer1_MarkTouched(object sender, UC.AgvViewer.TagArgs e)
|
private void AgvViewer1_MarkTouched(object sender, UC.AgvViewer.TagArgs e)
|
||||||
{
|
{
|
||||||
// throw new NotImplementedException();
|
// throw new NotImplementedException();
|
||||||
AGV.SetAGV(esignal.mark_sensor_1, e.Active);
|
AGV.SetAGV(esignal1.mark_sensor_1, e.Active);
|
||||||
logAGV.Add($"mark {e.Data} touch:{e.Active}");
|
logAGV.Add($"mark {e.Data} touch:{e.Active}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,10 +744,14 @@ namespace AGVEmulator
|
|||||||
var v2 = (DevAGV.eerror)idx;
|
var v2 = (DevAGV.eerror)idx;
|
||||||
AGV.SetAGV(v2, chk.Checked);
|
AGV.SetAGV(v2, chk.Checked);
|
||||||
break;
|
break;
|
||||||
case "sg":
|
case "sg1":
|
||||||
var v3 = (DevAGV.esignal)idx;
|
var v3 = (DevAGV.esignal1)idx;
|
||||||
AGV.SetAGV(v3, chk.Checked);
|
AGV.SetAGV(v3, chk.Checked);
|
||||||
break;
|
break;
|
||||||
|
case "sg2":
|
||||||
|
var v4 = (DevAGV.esignal2)idx;
|
||||||
|
AGV.SetAGV(v4, chk.Checked);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
chk.BackColor = chk.Checked ? Color.Lime : SystemColors.Window;
|
chk.BackColor = chk.Checked ? Color.Lime : SystemColors.Window;
|
||||||
|
|||||||
@@ -810,11 +810,11 @@ namespace AGVNavigationCore.Controls
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 동기화 모드 종료
|
/// 동기화 모드 종료
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ExitSyncMode()
|
public void ExitSyncMode(CanvasMode newmode)
|
||||||
{
|
{
|
||||||
if (_canvasMode == CanvasMode.Sync)
|
if (_canvasMode == CanvasMode.Sync)
|
||||||
{
|
{
|
||||||
_canvasMode = CanvasMode.Edit; // 기본 모드로 복귀 (또는 이전 모드)
|
_canvasMode = newmode; // 기본 모드로 복귀 (또는 이전 모드)
|
||||||
UpdateModeUI();
|
UpdateModeUI();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ namespace AGVNavigationCore.PathFinding.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public AgvDirection PrevDirection { get; set; }
|
public AgvDirection PrevDirection { get; set; }
|
||||||
|
|
||||||
|
public MapNode Gateway { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 기본 생성자
|
/// 기본 생성자
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -194,5 +194,556 @@ namespace AGVNavigationCore.PathFinding.Planning
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 길목(Gateway) 기반 고급 경로 계산 (기존 SimulatorForm.CalcPath 이관)
|
||||||
|
/// </summary>
|
||||||
|
public AGVPathResult CalculatePath(MapNode startNode, MapNode targetNode, MapNode prevNode, AgvDirection prevDir)
|
||||||
|
{
|
||||||
|
AGVPathResult Retval;
|
||||||
|
// var o_StartNode = startNode;
|
||||||
|
// startNode, targetNode는 이미 인자로 받음
|
||||||
|
|
||||||
|
if (startNode == null || targetNode == null) return AGVPathResult.CreateFailure("시작/종료노드가 지정되지 않음");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 종료노드라면 이전위치로 이동시켜야한다. (Simulator Logic)
|
||||||
|
// 만약 시작노드가 끝단(ConnectedMapNodes.Count == 1)이라면,
|
||||||
|
// AGV가 해당 노드에 '도착'한 상태가 아니라 '작업' 중일 수 있으므로
|
||||||
|
// 이전 노드(진입점)로 위치를 보정하여 경로를 계산한다.
|
||||||
|
AGVPathResult LimitPath = null;
|
||||||
|
if (startNode.ConnectedMapNodes.Count == 1)
|
||||||
|
{
|
||||||
|
// 시작점 -> 이전점 경로 (보통 후진이나 전진 1칸)
|
||||||
|
LimitPath = this.FindPathAStar(startNode, prevNode);
|
||||||
|
if (LimitPath.Success)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < LimitPath.Path.Count; i++)
|
||||||
|
{
|
||||||
|
var nodeinfo = LimitPath.Path[i];
|
||||||
|
var dir = (prevDir == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
||||||
|
LimitPath.DetailedPath.Add(new NodeMotorInfo(i + 1, nodeinfo.Id, nodeinfo.RfidId, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시작 위치 및 방향 변경
|
||||||
|
// var org_start = startNode; // Unused
|
||||||
|
startNode = prevNode;
|
||||||
|
prevNode = LimitPath.Path.First(); // startNode (original)
|
||||||
|
prevDir = (prevDir == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 경로 생성 실패 시 보정 없이 진행하거나 에러 처리
|
||||||
|
// 여기서는 일단 기존 로직대로 진행
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Buffer-to-Buffer 예외 처리
|
||||||
|
// 05~31 구간 체크
|
||||||
|
var node05 = _mapNodes.FirstOrDefault(n => n.RfidId == 5);
|
||||||
|
var node31 = _mapNodes.FirstOrDefault(n => n.RfidId == 31);
|
||||||
|
|
||||||
|
bool fixpath = false;
|
||||||
|
Retval = null;
|
||||||
|
MapNode gatewayNode = null;
|
||||||
|
|
||||||
|
if (node05 != null && node31 != null)
|
||||||
|
{
|
||||||
|
// 버퍼 구간 경로 테스트
|
||||||
|
var rlt = this.FindPathAStar(node05, node31);
|
||||||
|
if (rlt.Success)
|
||||||
|
{
|
||||||
|
// 버퍼구간내에 시작과 종료가 모두 포함되어있다
|
||||||
|
if (rlt.Path.Find(n => n.Id == startNode.Id) != null &&
|
||||||
|
rlt.Path.Find(n => n.Id == targetNode.Id) != null)
|
||||||
|
{
|
||||||
|
Retval = CalcPathBufferToBuffer(startNode, targetNode, prevNode, prevDir);
|
||||||
|
fixpath = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fixpath)
|
||||||
|
{
|
||||||
|
// 3. 목적지별 Gateway 및 진입 조건 확인
|
||||||
|
gatewayNode = GetGatewayNode(targetNode);
|
||||||
|
|
||||||
|
if (gatewayNode == null)
|
||||||
|
{
|
||||||
|
// 게이트웨이가 없는 경우라면(일반 노드 등), Gateway 로직 없이 기본 경로 탐색
|
||||||
|
Retval = this.FindBasicPath(startNode, targetNode, prevNode, prevDir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Gateway Node 찾음
|
||||||
|
// 4. Start -> Gateway 경로 계산 (A*)
|
||||||
|
var pathToGateway = this.FindBasicPath(startNode, gatewayNode, prevNode, prevDir);
|
||||||
|
if (pathToGateway.Success == false)
|
||||||
|
return AGVPathResult.CreateFailure($"Gateway({gatewayNode.ID2})까지 경로 실패: {pathToGateway.Message}");
|
||||||
|
|
||||||
|
// 방향을 확인하여, 왔던 방향으로 되돌아가야 한다면 방향 반전
|
||||||
|
if (pathToGateway.Path.Count > 1)
|
||||||
|
{
|
||||||
|
var predictNext = pathToGateway.Path[1];
|
||||||
|
if (predictNext.Id == prevNode.Id)
|
||||||
|
{
|
||||||
|
var reverseDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||||
|
foreach (var item in pathToGateway.DetailedPath)
|
||||||
|
item.MotorDirection = reverseDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 마지막 경로는 게이트웨이이므로 제거 (Gateway 진입 후 처리는 GetPathFromGateway에서 담당)
|
||||||
|
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.LastOrDefault() ?? prevNode;
|
||||||
|
NodeMotorInfo GatePrevDetail = pathToGateway.DetailedPath.LastOrDefault();
|
||||||
|
|
||||||
|
var arrivalOrientation = GatePrevDetail?.MotorDirection ?? prevDir;
|
||||||
|
var gatewayPathResult = GetPathFromGateway(gatewayNode, targetNode, GateprevNode, arrivalOrientation);
|
||||||
|
|
||||||
|
if (!gatewayPathResult.Success)
|
||||||
|
return AGVPathResult.CreateFailure($"{gatewayPathResult.Message}");
|
||||||
|
|
||||||
|
Retval = CombinePaths(pathToGateway, gatewayPathResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//게이트웨이
|
||||||
|
Retval.Gateway = gatewayNode;
|
||||||
|
|
||||||
|
// 경로 오류 검사
|
||||||
|
if (Retval == null || Retval.Success == false) return Retval ?? AGVPathResult.CreateFailure("경로 계산 결과 없음");
|
||||||
|
|
||||||
|
if (LimitPath != null)
|
||||||
|
{
|
||||||
|
Retval = CombinePaths(LimitPath, Retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 해당 경로와 대상의 도킹포인트 방향 검사
|
||||||
|
if (targetNode.DockDirection != DockingDirection.DontCare)
|
||||||
|
{
|
||||||
|
var lastPath = Retval.DetailedPath.LastOrDefault();
|
||||||
|
if (lastPath != null)
|
||||||
|
{
|
||||||
|
if (targetNode.DockDirection == DockingDirection.Forward && lastPath.MotorDirection != AgvDirection.Forward)
|
||||||
|
{
|
||||||
|
return AGVPathResult.CreateFailure($"생성된 경로와 목적지의 도킹방향이 일치하지 않습니다(FWD) Target:{targetNode.DockDirection}");
|
||||||
|
}
|
||||||
|
if (targetNode.DockDirection == DockingDirection.Backward && lastPath.MotorDirection != AgvDirection.Backward)
|
||||||
|
{
|
||||||
|
return AGVPathResult.CreateFailure($"생성된 경로와 목적지의 도킹방향이 일치하지 않습니다(BWD) Target:{targetNode.DockDirection}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 경로 최적화: A -> B -> A 패턴 제거
|
||||||
|
// 6[F][R] → 13[B][L] → 6[F][L] 같은 경우 제거
|
||||||
|
while (fixpath == false)
|
||||||
|
{
|
||||||
|
var updatecount = 0;
|
||||||
|
for (int i = 0; i < Retval.DetailedPath.Count - 2; i++)
|
||||||
|
{
|
||||||
|
var n1 = Retval.DetailedPath[i];
|
||||||
|
var n2 = Retval.DetailedPath[i + 1];
|
||||||
|
var n3 = Retval.DetailedPath[i + 2];
|
||||||
|
|
||||||
|
if (n1.NodeId == n3.NodeId)
|
||||||
|
{
|
||||||
|
bool isInverse = false;
|
||||||
|
// 1. 모터 방향이 반대인가? (F <-> B)
|
||||||
|
bool isMotorInverse = (n1.MotorDirection != n2.MotorDirection) &&
|
||||||
|
(n1.MotorDirection == AgvDirection.Forward || n1.MotorDirection == AgvDirection.Backward) &&
|
||||||
|
(n2.MotorDirection == AgvDirection.Forward || n2.MotorDirection == AgvDirection.Backward);
|
||||||
|
|
||||||
|
if (isMotorInverse)
|
||||||
|
{
|
||||||
|
// 2. 마그넷 방향이 반대인가? (L <-> R, S <-> S)
|
||||||
|
bool isMagnetInverse = false;
|
||||||
|
if (n1.MagnetDirection == MagnetDirection.Straight && n2.MagnetDirection == MagnetDirection.Straight) isMagnetInverse = true;
|
||||||
|
else if (n1.MagnetDirection == MagnetDirection.Left && n2.MagnetDirection == MagnetDirection.Right) isMagnetInverse = true;
|
||||||
|
else if (n1.MagnetDirection == MagnetDirection.Right && n2.MagnetDirection == MagnetDirection.Left) isMagnetInverse = true;
|
||||||
|
|
||||||
|
if (isMagnetInverse) isInverse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInverse)
|
||||||
|
{
|
||||||
|
// 제자리 회귀 경로 발견 -> 앞의 두 노드(n1, n2)를 제거하여 n3만 남김
|
||||||
|
Retval.DetailedPath.RemoveAt(i);
|
||||||
|
Retval.DetailedPath.RemoveAt(i);
|
||||||
|
|
||||||
|
if (Retval.Path.Count > i + 1)
|
||||||
|
{
|
||||||
|
Retval.Path.RemoveAt(i);
|
||||||
|
Retval.Path.RemoveAt(i);
|
||||||
|
}
|
||||||
|
i--; // 인덱스 재조정
|
||||||
|
updatecount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (updatecount == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 불가능한 회전 경로 검사 (사용자 요청 로직 반영)
|
||||||
|
for (int i = 0; i < Retval.DetailedPath.Count - 2; i++)
|
||||||
|
{
|
||||||
|
var n1 = Retval.DetailedPath[i];
|
||||||
|
var n2 = Retval.DetailedPath[i + 1];
|
||||||
|
var n3 = Retval.DetailedPath[i + 2];
|
||||||
|
|
||||||
|
if (n1.NodeId == n3.NodeId &&
|
||||||
|
n1.MotorDirection == n3.MotorDirection &&
|
||||||
|
n1.MotorDirection == n2.MotorDirection) // Fix: 중간 노드 방향도 같을 때만 에러
|
||||||
|
{
|
||||||
|
return AGVPathResult.CreateFailure($"불가능한 회전 경로가 포함되어있습니다. {n1.RfidId}->{n2.RfidId}->{n3.RfidId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기타 검증 로직 (마지막 노드 도킹, 시작노드 일치 등)
|
||||||
|
var lastnode = Retval.Path.Last();
|
||||||
|
if (lastnode.StationType != StationType.Normal)
|
||||||
|
{
|
||||||
|
var lastnodePath = Retval.DetailedPath.Last();
|
||||||
|
if (lastnode.DockDirection == DockingDirection.Forward && lastnodePath.MotorDirection != AgvDirection.Forward)
|
||||||
|
return AGVPathResult.CreateFailure($"목적지의 모터방향({lastnode.DockDirection}) 불일치 경로방향({lastnodePath.MotorDirection})");
|
||||||
|
if (lastnode.DockDirection == DockingDirection.Backward && lastnodePath.MotorDirection != AgvDirection.Backward)
|
||||||
|
return AGVPathResult.CreateFailure($"목적지의 모터방향({lastnode.DockDirection}) 불일치 경로방향({lastnodePath.MotorDirection})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 첫번째 노드 일치 검사 - 필요시 수행 (startNode가 변경될 수 있어서 o_StartNode 등 필요할 수도 있음)
|
||||||
|
// 여기서는 생략 혹은 간단히 체크
|
||||||
|
|
||||||
|
// 되돌아가는 길 방향 일치 검사
|
||||||
|
if (Retval.DetailedPath.Count > 1)
|
||||||
|
{
|
||||||
|
var FirstDetailPath = Retval.DetailedPath[0];
|
||||||
|
var NextDetailPath = Retval.DetailedPath[1];
|
||||||
|
AgvDirection? PredictNextDir = null;
|
||||||
|
|
||||||
|
if (NextDetailPath.NodeId == prevNode.Id)
|
||||||
|
{
|
||||||
|
if (NextDetailPath.MagnetDirection == MagnetDirection.Straight)
|
||||||
|
PredictNextDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PredictNextDir != null && (FirstDetailPath.MotorDirection != (AgvDirection)PredictNextDir))
|
||||||
|
{
|
||||||
|
// return AGVPathResult.CreateFailure($"되돌아가는 길인데 방향이 일치하지않음");
|
||||||
|
// 경고 수준이나 무시 가능한 경우도 있음
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 연결성 검사
|
||||||
|
for (int i = 0; i < Retval.DetailedPath.Count - 1; i++)
|
||||||
|
{
|
||||||
|
var cnode = Retval.Path[i];
|
||||||
|
var nnode = Retval.Path[i + 1];
|
||||||
|
|
||||||
|
if (cnode.ConnectedNodes.Contains(nnode.Id) == false && cnode.Id != nnode.Id)
|
||||||
|
{
|
||||||
|
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드에 연결되지 않은 [{nnode.RfidId}]노드가 지정됨");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//각 도킹포인트별로 절대 움직이면 안되는 조건확인
|
||||||
|
var firstnode = Retval.Path.FirstOrDefault();
|
||||||
|
var firstDet = Retval.DetailedPath.First();
|
||||||
|
var failmessage = $"[{firstnode.ID2}] 노드의 시작모터 방향({firstDet.MotorDirection})이 올바르지 않습니다";
|
||||||
|
if (firstnode.StationType == StationType.Charger1 && firstDet.MotorDirection != AgvDirection.Forward)
|
||||||
|
return AGVPathResult.CreateFailure(failmessage);
|
||||||
|
else if (firstnode.StationType == StationType.Loader && firstDet.MotorDirection != AgvDirection.Backward)
|
||||||
|
return AGVPathResult.CreateFailure(failmessage);
|
||||||
|
else if (firstnode.StationType == StationType.UnLoader && firstDet.MotorDirection != AgvDirection.Backward)
|
||||||
|
return AGVPathResult.CreateFailure(failmessage);
|
||||||
|
else if (firstnode.StationType == StationType.Clearner && firstDet.MotorDirection != AgvDirection.Backward)
|
||||||
|
return AGVPathResult.CreateFailure(failmessage);
|
||||||
|
else if (firstnode.StationType == StationType.Buffer)
|
||||||
|
{
|
||||||
|
//버퍼는 도킹이되어잇느닞 확인하고. 그때 방향을 체크해야한다.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Retval;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return AGVPathResult.CreateFailure($"[계산오류] {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AGVPathResult CalcPathBufferToBuffer(MapNode start, MapNode target, MapNode prev, AgvDirection prevDir)
|
||||||
|
{
|
||||||
|
// Monitor Side 판단 및 Buffer 간 이동 로직
|
||||||
|
int deltaX = 0;
|
||||||
|
int deltaY = 0;
|
||||||
|
if (prev == null) return AGVPathResult.CreateFailure("이전 노드 정보가 없습니다");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deltaX = start.Position.X - prev.Position.X;
|
||||||
|
deltaY = -(start.Position.Y - prev.Position.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(deltaY) > Math.Abs(deltaX))
|
||||||
|
deltaX = deltaY;
|
||||||
|
|
||||||
|
bool isMonitorLeft = false;
|
||||||
|
|
||||||
|
if (deltaX > 0) // 오른쪽(Forward)으로 이동해 옴
|
||||||
|
isMonitorLeft = (prevDir == AgvDirection.Backward);
|
||||||
|
else if (deltaX < 0) // 왼쪽(Reverse)으로 이동해 옴
|
||||||
|
isMonitorLeft = (prevDir == AgvDirection.Forward);
|
||||||
|
else
|
||||||
|
return AGVPathResult.CreateFailure("이전 노드와의 방향을 알 수 없습니다");
|
||||||
|
|
||||||
|
if (isMonitorLeft)
|
||||||
|
{
|
||||||
|
// Monitor Left -> Gateway 탈출
|
||||||
|
var GateWayNode = _mapNodes.FirstOrDefault(n => n.RfidId == 6);
|
||||||
|
var reverseDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||||
|
|
||||||
|
AGVPathResult escPath = null;
|
||||||
|
if (start.Position.X > prev.Position.X)
|
||||||
|
escPath = this.FindBasicPath(start, GateWayNode, prev, prevDir);
|
||||||
|
else
|
||||||
|
escPath = this.FindBasicPath(start, GateWayNode, prev, reverseDir);
|
||||||
|
|
||||||
|
if (!escPath.Success) return AGVPathResult.CreateFailure("버퍼 탈출 경로 실패");
|
||||||
|
|
||||||
|
var lastNode = escPath.Path.Last();
|
||||||
|
var lastPrev = escPath.Path[escPath.Path.Count - 2];
|
||||||
|
var lastDir = escPath.DetailedPath.Last().MotorDirection;
|
||||||
|
|
||||||
|
var gateToTarget = GetPathFromGateway(GateWayNode, target, lastPrev, lastDir);
|
||||||
|
|
||||||
|
escPath.Path.RemoveAt(escPath.Path.Count - 1);
|
||||||
|
escPath.DetailedPath.RemoveAt(escPath.DetailedPath.Count - 1);
|
||||||
|
|
||||||
|
return CombinePaths(escPath, gateToTarget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Monitor Right -> 직접 진입 또는 Overshoot
|
||||||
|
bool isTargetLeft = target.Position.X < start.Position.X;
|
||||||
|
|
||||||
|
if (target == start)
|
||||||
|
{
|
||||||
|
// 제자리 재정렬 (Same as Simulator logic)
|
||||||
|
var list = new List<MapNode>();
|
||||||
|
var retval = AGVPathResult.CreateSuccess(list, new List<AgvDirection>(), 0, 0);
|
||||||
|
var resversedir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
||||||
|
|
||||||
|
retval.Path.Add(target);
|
||||||
|
|
||||||
|
if (deltaX < 0)
|
||||||
|
{
|
||||||
|
var nextNode = start.ConnectedMapNodes.Where(t => t.Id != prev.Id && t.StationType == StationType.Buffer).FirstOrDefault();
|
||||||
|
if (nextNode != null)
|
||||||
|
{
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, prevDir));
|
||||||
|
retval.Path.Add(nextNode);
|
||||||
|
var lastDefailt = retval.DetailedPath.Last();
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(lastDefailt.seq + 1, nextNode.Id, nextNode.RfidId, AgvDirection.Forward)
|
||||||
|
{
|
||||||
|
Speed = SpeedLevel.M,
|
||||||
|
});
|
||||||
|
retval.Path.Add(target);
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo((retval.DetailedPath.Max(t => t.seq) + 1), target.Id, target.RfidId, AgvDirection.Forward));
|
||||||
|
retval.Path.Add(target);
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, AgvDirection.Backward));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, resversedir));
|
||||||
|
retval.Path.Add(prev);
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Last().seq + 1, prev.Id, prev.RfidId, prevDir)
|
||||||
|
{
|
||||||
|
Speed = SpeedLevel.M,
|
||||||
|
});
|
||||||
|
retval.Path.Add(target);
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, prevDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, prevDir));
|
||||||
|
var nextNode = start.ConnectedMapNodes.Where(t => t.Id != prev.Id && t.StationType == StationType.Buffer).FirstOrDefault();
|
||||||
|
retval.Path.Add(nextNode);
|
||||||
|
var lastDefailt = retval.DetailedPath.Last();
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(lastDefailt.seq + 1, nextNode.Id, nextNode.RfidId, AgvDirection.Backward)
|
||||||
|
{
|
||||||
|
Speed = SpeedLevel.L,
|
||||||
|
});
|
||||||
|
retval.Path.Add(target);
|
||||||
|
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, AgvDirection.Backward));
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
else if (isTargetLeft)
|
||||||
|
{
|
||||||
|
return this.FindBasicPath(start, target, prev, AgvDirection.Backward);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Overshoot
|
||||||
|
var path1 = this.FindBasicPath(start, target, prev, AgvDirection.Forward);
|
||||||
|
if (path1.Path.Count < 2) return AGVPathResult.CreateFailure("Overshoot 경로 생성 실패");
|
||||||
|
|
||||||
|
var last = path1.Path.Last();
|
||||||
|
var lastD = path1.DetailedPath.Last();
|
||||||
|
path1.Path.RemoveAt(path1.Path.Count - 1);
|
||||||
|
path1.DetailedPath.RemoveAt(path1.DetailedPath.Count - 1);
|
||||||
|
|
||||||
|
path1.Path.Add(last);
|
||||||
|
path1.DetailedPath.Add(new NodeMotorInfo(lastD.seq + 1, lastD.NodeId, lastD.RfidId, AgvDirection.Backward)
|
||||||
|
{
|
||||||
|
Speed = SpeedLevel.L,
|
||||||
|
});
|
||||||
|
|
||||||
|
return path1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AGVPathResult GetPathFromGateway(MapNode GTNode, MapNode targetNode, MapNode PrevNode, AgvDirection PrevDirection)
|
||||||
|
{
|
||||||
|
AGVPathResult resultPath = null;
|
||||||
|
var deltaX = GTNode.Position.X - PrevNode.Position.X;
|
||||||
|
var isMonitorLeft = false;
|
||||||
|
|
||||||
|
if (deltaX > 0) isMonitorLeft = PrevDirection == AgvDirection.Backward;
|
||||||
|
else isMonitorLeft = PrevDirection == AgvDirection.Forward;
|
||||||
|
|
||||||
|
if (targetNode.StationType == StationType.Loader || targetNode.StationType == StationType.Charger2)
|
||||||
|
{
|
||||||
|
deltaX = GTNode.Position.Y - PrevNode.Position.Y;
|
||||||
|
if (deltaX < 0) isMonitorLeft = PrevDirection == AgvDirection.Backward;
|
||||||
|
else isMonitorLeft = PrevDirection == AgvDirection.Forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (targetNode.StationType)
|
||||||
|
{
|
||||||
|
case StationType.Loader:
|
||||||
|
case StationType.Charger2:
|
||||||
|
case StationType.Charger1:
|
||||||
|
case StationType.UnLoader:
|
||||||
|
case StationType.Clearner:
|
||||||
|
case StationType.Buffer:
|
||||||
|
var rlt1 = new AGVPathResult();
|
||||||
|
rlt1.Success = true;
|
||||||
|
|
||||||
|
var motdir = targetNode.DockDirection == DockingDirection.Backward ? AgvDirection.Backward : AgvDirection.Forward;
|
||||||
|
var pathtarget = this.FindBasicPath(GTNode, targetNode, PrevNode, motdir);
|
||||||
|
|
||||||
|
if ((targetNode.DockDirection == DockingDirection.Backward && isMonitorLeft) ||
|
||||||
|
(targetNode.DockDirection == DockingDirection.Forward && !isMonitorLeft))
|
||||||
|
{
|
||||||
|
var turnPatterns = GetTurnaroundPattern(GTNode, targetNode);
|
||||||
|
if (turnPatterns == null || !turnPatterns.Any()) return new AGVPathResult { Success = false, Message = $"회차 패턴 없음: Dir {PrevDirection}" };
|
||||||
|
|
||||||
|
foreach (var item in turnPatterns)
|
||||||
|
{
|
||||||
|
var rfidvalue = ushort.Parse(item.Substring(0, 4));
|
||||||
|
var node = _mapNodes.FirstOrDefault(t => t.RfidId == rfidvalue);
|
||||||
|
rlt1.Path.Add(node);
|
||||||
|
|
||||||
|
AgvDirection nodedir = item.Substring(4, 1) == "F" ? AgvDirection.Forward : AgvDirection.Backward;
|
||||||
|
MagnetDirection magnet = MagnetDirection.Straight;
|
||||||
|
var magchar = item.Substring(5, 1);
|
||||||
|
if (magchar == "L") magnet = MagnetDirection.Left;
|
||||||
|
else if (magchar == "R") magnet = MagnetDirection.Right;
|
||||||
|
|
||||||
|
rlt1.DetailedPath.Add(new NodeMotorInfo(rlt1.DetailedPath.Count, node.Id, node.RfidId, nodedir, null, magnet)
|
||||||
|
{
|
||||||
|
Speed = SpeedLevel.L,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathtarget.DetailedPath.First().NodeId != rlt1.DetailedPath.Last().NodeId ||
|
||||||
|
pathtarget.DetailedPath.First().MotorDirection != rlt1.DetailedPath.Last().MotorDirection)
|
||||||
|
{
|
||||||
|
// Gateway 턴 마지막 주소 불일치 경고 (로깅 등)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathtarget.Path.RemoveAt(0);
|
||||||
|
pathtarget.DetailedPath.RemoveAt(0);
|
||||||
|
}
|
||||||
|
return CombinePaths(rlt1, pathtarget);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return AGVPathResult.CreateFailure($"지원되지 않는 StationType: {targetNode.StationType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapNode GetGatewayNode(MapNode node)
|
||||||
|
{
|
||||||
|
var rfid = 0;
|
||||||
|
if (node.StationType == StationType.UnLoader) rfid = 10;
|
||||||
|
else if (node.StationType == StationType.Charger1) rfid = 9;
|
||||||
|
else if (node.StationType == StationType.Clearner) rfid = 6;
|
||||||
|
else if (node.StationType == StationType.Charger2) rfid = 13;
|
||||||
|
else if (node.StationType == StationType.Loader) rfid = 13;
|
||||||
|
else if (node.StationType == StationType.Buffer) rfid = 6;
|
||||||
|
|
||||||
|
if (rfid == 0) return null;
|
||||||
|
return _mapNodes.FirstOrDefault(t => t.RfidId == rfid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetTurnaroundPattern(MapNode gatewayNode, MapNode targetNode)
|
||||||
|
{
|
||||||
|
switch (gatewayNode.RfidId)
|
||||||
|
{
|
||||||
|
case 6:
|
||||||
|
if (targetNode.StationType == StationType.Buffer)
|
||||||
|
return new List<string> { "0006BL", "0007FS", "0013BL", "0006BL" };
|
||||||
|
else
|
||||||
|
return new List<string> { "0006BL", "0007FS", "0013BL", "0006BS" };
|
||||||
|
case 9: return new List<string> { "0009FL", "0010BS", "0007FL", "0009FS" };
|
||||||
|
case 10: return new List<string> { "0010BR", "0009FR", "0007BS", "0010BS" };
|
||||||
|
case 13: return new List<string> { "0013BL", "0006FL", "0007BS", "0013BS" };
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AGVPathResult CombinePaths(AGVPathResult p1, AGVPathResult p2)
|
||||||
|
{
|
||||||
|
var res = new AGVPathResult();
|
||||||
|
res.Success = true;
|
||||||
|
|
||||||
|
var p1last = p1.DetailedPath.LastOrDefault();
|
||||||
|
var p2fist = p2.DetailedPath.FirstOrDefault();
|
||||||
|
|
||||||
|
if (p1last != null && p2fist != null &&
|
||||||
|
(p1last.NodeId == p2fist.NodeId && p1last.MotorDirection == p2fist.MotorDirection && p1last.MagnetDirection == p2fist.MagnetDirection))
|
||||||
|
{
|
||||||
|
p1.Path.RemoveAt(p1.Path.Count - 1);
|
||||||
|
p1.DetailedPath.RemoveAt(p1.DetailedPath.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in p1.Path) res.Path.Add(item);
|
||||||
|
foreach (var item in p2.Path) res.Path.Add(item);
|
||||||
|
|
||||||
|
foreach (var item in p1.DetailedPath)
|
||||||
|
{
|
||||||
|
var maxseq = res.DetailedPath.Count == 0 ? 0 : res.DetailedPath.Max(t => t.seq);
|
||||||
|
item.seq = maxseq + 1;
|
||||||
|
res.DetailedPath.Add(item);
|
||||||
|
}
|
||||||
|
foreach (var item in p2.DetailedPath)
|
||||||
|
{
|
||||||
|
var maxseq = res.DetailedPath.Count == 0 ? 0 : res.DetailedPath.Max(t => t.seq);
|
||||||
|
item.seq = maxseq + 1;
|
||||||
|
res.DetailedPath.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2580,742 +2580,13 @@ namespace AGVSimulator.Forms
|
|||||||
public AGVPathResult CalcPath(MapNode startNode, MapNode targetNode, List<MapNode> nodes,
|
public AGVPathResult CalcPath(MapNode startNode, MapNode targetNode, List<MapNode> nodes,
|
||||||
MapNode prevNode, AgvDirection prevDir)
|
MapNode prevNode, AgvDirection prevDir)
|
||||||
{
|
{
|
||||||
AGVPathResult Retval;
|
// Core Logic으로 이관됨
|
||||||
var o_StartNode = startNode;
|
|
||||||
if (startNode == null || targetNode == null) return AGVPathResult.CreateFailure("시작/종료노드가 지정되지 않음");
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var pathFinder = new AGVPathfinder(nodes);
|
var pathFinder = new AGVPathfinder(nodes);
|
||||||
var selectedAGV = _agvListCombo.SelectedItem as VirtualAGV;
|
var result = pathFinder.CalculatePath(startNode, targetNode, prevNode, prevDir);
|
||||||
if (selectedAGV == null) return AGVPathResult.CreateFailure("Virtual AGV 없음");
|
|
||||||
|
|
||||||
//종료노드라면 이전위치로 이동시켜야한다.
|
//게이트웨이노드를 하이라이트강조 한단
|
||||||
AGVPathResult LimitPath = null;
|
this._simulatorCanvas.HighlightNodeId = (result.Gateway?.Id ?? string.Empty);
|
||||||
if (startNode.ConnectedMapNodes.Count == 1)
|
return result;
|
||||||
{
|
|
||||||
LimitPath = pathFinder.FindPathAStar(startNode, prevNode);
|
|
||||||
for (int i = 0; i < LimitPath.Path.Count; i++)
|
|
||||||
{
|
|
||||||
var nodeinfo = LimitPath.Path[i];
|
|
||||||
var dir = (prevDir == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
|
||||||
LimitPath.DetailedPath.Add(new NodeMotorInfo(i + 1, nodeinfo.Id, nodeinfo.RfidId, dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
//시작위치 및 방향을변경해준다
|
|
||||||
var org_start = startNode;
|
|
||||||
startNode = prevNode;
|
|
||||||
prevNode = org_start;
|
|
||||||
prevDir = (prevDir == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//var prevNode = selectedAGV.PrevNode;
|
|
||||||
//var prevDir = selectedAGV.PrevDirection;
|
|
||||||
|
|
||||||
// 2. Buffer-to-Buffer 예외 처리
|
|
||||||
var node05 = FindNode(5); //05~31사이의 노드는 모두 버퍼이다.
|
|
||||||
var node31 = FindNode(31);
|
|
||||||
if (node05 == null || node31 == null) return AGVPathResult.CreateFailure("버퍼구간 노드가 없습니다(05~31)");
|
|
||||||
|
|
||||||
var rlt = pathFinder.FindPathAStar(node05, node31);
|
|
||||||
if (rlt.Success == false) return AGVPathResult.CreateFailure("버퍼구간 노드경로 확인 실패(05~31)");
|
|
||||||
|
|
||||||
//하이라이트노드 해제
|
|
||||||
_simulatorCanvas.HighlightNodeId = null;
|
|
||||||
|
|
||||||
//버퍼구간내에 시작과 종료가 모두 포함되어있다
|
|
||||||
bool fixpath = false;
|
|
||||||
if (rlt.Path.Contains(startNode) && rlt.Path.Contains(targetNode))
|
|
||||||
{
|
|
||||||
Retval = CalcPathBufferToBuffer(pathFinder, startNode, targetNode, prevNode, prevDir, selectedAGV);
|
|
||||||
fixpath = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 3. 목적지별 Gateway 및 진입 조건 확인
|
|
||||||
var gatewayNode = GetGatewayNode(targetNode);
|
|
||||||
if (gatewayNode == null)
|
|
||||||
{
|
|
||||||
//게이트웨이가 없는 경우라면 목적지가 도킹포인트가 아니므로, a*알골리즘으로 진행 방향만 맟춰서 이동한다
|
|
||||||
Retval = pathFinder.FindBasicPath(startNode, targetNode, prevNode, prevDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 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}");
|
|
||||||
|
|
||||||
//방향을 확인하여, 왓던방향으로 가야하는디. 반대로 가야하느닞 체크한다.
|
|
||||||
if (pathToGateway.Path.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.LastOrDefault() ?? prevNode;
|
|
||||||
NodeMotorInfo GatePrevDetail = pathToGateway.DetailedPath.LastOrDefault();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//경로오류 검사
|
|
||||||
if (Retval.Success == false) return Retval;
|
|
||||||
|
|
||||||
if (LimitPath != null)
|
|
||||||
{
|
|
||||||
Retval = CombinePaths(LimitPath, Retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//해당경로와 대상의 도킹포인트의 방향을 검사합니다
|
|
||||||
if (targetNode.DockDirection != DockingDirection.DontCare)
|
|
||||||
{
|
|
||||||
var lastPath = Retval.DetailedPath.Last();
|
|
||||||
if (targetNode.DockDirection == DockingDirection.Forward && lastPath.MotorDirection != AgvDirection.Forward)
|
|
||||||
{
|
|
||||||
return AGVPathResult.CreateFailure($"생성된 경로와 목적지의 도킹방향이 일치하지 않습니다(FWD) Target:{targetNode.DockDirection}, Path:{Retval.GetDetailedPathInfo()}");
|
|
||||||
}
|
|
||||||
if (targetNode.DockDirection == DockingDirection.Backward && lastPath.MotorDirection != AgvDirection.Backward)
|
|
||||||
{
|
|
||||||
return AGVPathResult.CreateFailure($"생성된 경로와 목적지의 도킹방향이 일치하지 않습니다(BWD) Target:{targetNode.DockDirection}, Path:{Retval.GetDetailedPathInfo()}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//6[F][R] → 13[B][L] → 6[F][L] 이런경우를 찾아서 경로를 최적화한다.
|
|
||||||
//위 예제에서는 6FR 13BL 이 제자리로 오는 경로이므로 6FL만 남기면된다.
|
|
||||||
//단순히 ID만 같은게 아니라, 실제로 갔다가 되돌아오는 패턴(역방향)인지 확인해야 함.
|
|
||||||
while (fixpath == false && true)
|
|
||||||
{
|
|
||||||
var updatecount = 0;
|
|
||||||
for (int i = 0; i < Retval.DetailedPath.Count - 2; i++)
|
|
||||||
{
|
|
||||||
var n1 = Retval.DetailedPath[i];
|
|
||||||
var n2 = Retval.DetailedPath[i + 1];
|
|
||||||
var n3 = Retval.DetailedPath[i + 2];
|
|
||||||
|
|
||||||
if (n1.NodeId == n3.NodeId)
|
|
||||||
{
|
|
||||||
bool isInverse = false;
|
|
||||||
|
|
||||||
// 1. 모터 방향이 반대인가? (F <-> B)
|
|
||||||
bool isMotorInverse = (n1.MotorDirection != n2.MotorDirection) &&
|
|
||||||
(n1.MotorDirection == AgvDirection.Forward || n1.MotorDirection == AgvDirection.Backward) &&
|
|
||||||
(n2.MotorDirection == AgvDirection.Forward || n2.MotorDirection == AgvDirection.Backward);
|
|
||||||
|
|
||||||
if (isMotorInverse)
|
|
||||||
{
|
|
||||||
// 2. 마그넷 방향이 반대인가? (L <-> R, S <-> S)
|
|
||||||
bool isMagnetInverse = false;
|
|
||||||
if (n1.MagnetDirection == MagnetDirection.Straight && n2.MagnetDirection == MagnetDirection.Straight) isMagnetInverse = true;
|
|
||||||
else if (n1.MagnetDirection == MagnetDirection.Left && n2.MagnetDirection == MagnetDirection.Right) isMagnetInverse = true;
|
|
||||||
else if (n1.MagnetDirection == MagnetDirection.Right && n2.MagnetDirection == MagnetDirection.Left) isMagnetInverse = true;
|
|
||||||
|
|
||||||
if (isMagnetInverse) isInverse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInverse)
|
|
||||||
{
|
|
||||||
// 제자리 회귀 경로 발견 -> 앞의 두 노드(n1, n2)를 제거하여 n3만 남김
|
|
||||||
Retval.DetailedPath.RemoveAt(i);
|
|
||||||
Retval.DetailedPath.RemoveAt(i);
|
|
||||||
|
|
||||||
if (Retval.Path.Count > i + 1)
|
|
||||||
{
|
|
||||||
Retval.Path.RemoveAt(i);
|
|
||||||
Retval.Path.RemoveAt(i);
|
|
||||||
}
|
|
||||||
i--; // 인덱스 재조정
|
|
||||||
updatecount += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (updatecount == 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//detail 경로를 확인해서 왓던길에서 바로 방향이 전환되는 경우를 찾는다
|
|
||||||
for (int i = 0; i < Retval.DetailedPath.Count - 2; i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
var n1 = Retval.DetailedPath[i];
|
|
||||||
var n2 = Retval.DetailedPath[i + 1];
|
|
||||||
var n3 = Retval.DetailedPath[i + 2];
|
|
||||||
|
|
||||||
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()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//최종 목적지를 확인하여 도킹 노드라면 그 도킹노드방향과 모터방향을 체크한다.
|
|
||||||
var lastnode = Retval.Path.Last();
|
|
||||||
if (lastnode.StationType != StationType.Normal)
|
|
||||||
{
|
|
||||||
var lastnodePath = Retval.DetailedPath.Last();
|
|
||||||
if (lastnode.DockDirection == DockingDirection.Forward && lastnodePath.MotorDirection != AgvDirection.Forward)
|
|
||||||
return AGVPathResult.CreateFailure($"목적지의 모터방향({lastnode.DockDirection}) 불일치 경로방향({lastnodePath.MotorDirection}) {Retval.GetDetailedPathInfo(true)}");
|
|
||||||
if (lastnode.DockDirection == DockingDirection.Backward && lastnodePath.MotorDirection != AgvDirection.Backward)
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
var pnode = (i == 0 ? prevNode : Retval.Path[i - 1]);
|
|
||||||
var pdir = (i == 0 ? prevDir : Retval.DetailedPath[i - 1].MotorDirection);
|
|
||||||
var cnode = Retval.Path[i];
|
|
||||||
var nnode = Retval.Path[i + 1];
|
|
||||||
|
|
||||||
//연결된 노드에 다음노드 id가 포함되는지 확인한다
|
|
||||||
if (cnode.ConnectedNodes.Contains(nnode.Id) == false && cnode.Id != nnode.Id)
|
|
||||||
{
|
|
||||||
return AGVPathResult.CreateFailure($"[{cnode.RfidId}] 노드에 연결되지 않은 [{nnode.RfidId}]노드가 지정됨 {Retval.GetDetailedPathInfo(true)}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//최종결과 반환
|
|
||||||
return Retval;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return AGVPathResult.CreateFailure($"[계산오류] {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private AGVPathResult CalcPathBufferToBuffer(AGVPathfinder pathfinder, MapNode start, MapNode target, MapNode prev, AgvDirection prevDir, VirtualAGV agv)
|
|
||||||
{
|
|
||||||
// Monitor Side 판단 로직
|
|
||||||
// 현재 AGV의 물리적 방향(Monitor Side)이 "Right" 상태여야 버퍼 진입이 용이하다고 가정.
|
|
||||||
// Monitor Left 상태(부적절한 방향)라면 Gateway로 탈출해야 함.
|
|
||||||
|
|
||||||
// 이동 벡터 X 변화량
|
|
||||||
// prev가 없거나 start와 같으면 이동 방향을 알 수 없음 -> 이 경우 보수적으로 기존 로직(Backward면 탈출) 따름
|
|
||||||
int deltaX = 0;
|
|
||||||
int deltaY = 0;
|
|
||||||
if (prev == null) return AGVPathResult.CreateFailure("이전 노드 정보가 없습니다");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deltaX = start.Position.X - prev.Position.X;
|
|
||||||
deltaY = -(start.Position.Y - prev.Position.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.Abs(deltaY) > Math.Abs(deltaX))
|
|
||||||
deltaX = deltaY;
|
|
||||||
|
|
||||||
bool isMonitorLeft = false;
|
|
||||||
|
|
||||||
if (deltaX > 0) // 오른쪽(Forward)으로 이동해 옴 (예: 2 -> 4), 위로 이동함
|
|
||||||
{
|
|
||||||
// 이동방향(Right) + 전진(F) => Monitor Right (Good)
|
|
||||||
// 이동방향(Right) + 후진(B) => Monitor Left (Bad)
|
|
||||||
isMonitorLeft = (prevDir == AgvDirection.Backward);
|
|
||||||
}
|
|
||||||
else if (deltaX < 0) // 왼쪽(Reverse)으로 이동해 옴 (예: 4 -> 2), 아래로 이동함
|
|
||||||
{
|
|
||||||
// 이동방향(Left) + 전진(F) => Monitor Left (Bad)
|
|
||||||
// 이동방향(Left) + 후진(B) => Monitor Right (Good)
|
|
||||||
isMonitorLeft = (prevDir == AgvDirection.Forward);
|
|
||||||
}
|
|
||||||
else // 제자리 또는 수직 이동
|
|
||||||
{
|
|
||||||
// 판단 불가 시 기존 로직(Backward면 Gateway) 유지
|
|
||||||
return AGVPathResult.CreateFailure("이전 노드와의 방향을 알 수 없습니다");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMonitorLeft)
|
|
||||||
{
|
|
||||||
// Monitor Left 상태 (방향 불일치) -> Gateway로 탈출
|
|
||||||
var GateWayNode = FindNode(6);
|
|
||||||
var reverseDir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
|
||||||
|
|
||||||
//왼족에서 오른조긍로 이동하면 prevdir 을 그대로 쓰는데.. 오른쪽에서 왼쪽으로 이동했다면 방향을 변경해야한다
|
|
||||||
AGVPathResult escPath = null;
|
|
||||||
if (start.Position.X > prev.Position.X)
|
|
||||||
{
|
|
||||||
escPath = pathfinder.FindBasicPath(start, GateWayNode, prev, prevDir);
|
|
||||||
if (!escPath.Success) return AGVPathResult.CreateFailure("버퍼 탈출 경로 실패");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
escPath = pathfinder.FindBasicPath(start, GateWayNode, prev, reverseDir);
|
|
||||||
if (!escPath.Success) return AGVPathResult.CreateFailure("버퍼 탈출 경로 실패");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var lastNode = escPath.Path.Last(); // Should be GW6
|
|
||||||
var lastPrev = escPath.Path[escPath.Path.Count - 2];
|
|
||||||
var lastDir = escPath.DetailedPath.Last().MotorDirection;
|
|
||||||
|
|
||||||
// Gateway 도착 후, Target(Buffer)으로 이동
|
|
||||||
// 여기서부터는 "Monitor Right" 로직(즉, 적절한 방향 진입)을 적용합니다.
|
|
||||||
// 6번에서 Target이 왼쪽이면 Direct(Backward), 오른쪽이면 Overshoot(Forward->Backward)
|
|
||||||
|
|
||||||
|
|
||||||
bool isTargetLeftOfGW = target.Position.X < GateWayNode.Position.X;
|
|
||||||
AGVPathResult entryPath = null;
|
|
||||||
|
|
||||||
//게이트웨이까지 후진으로 이동했다면 모니터방향이 오른쪽이다 => 방향전환필요
|
|
||||||
var gateToTarget = GetPathFromGateway(pathfinder, GateWayNode, target, lastPrev, lastDir);
|
|
||||||
|
|
||||||
escPath.Path.RemoveAt(escPath.Path.Count - 1);
|
|
||||||
escPath.DetailedPath.RemoveAt(escPath.DetailedPath.Count - 1);
|
|
||||||
|
|
||||||
|
|
||||||
var final = CombinePaths(escPath, gateToTarget);
|
|
||||||
ApplyResultToSimulator(final, agv);
|
|
||||||
UpdateAdvancedPathDebugInfo(final);
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Monitor Right 상태 (방향 일치) -> 직접 진입 또는 Overshoot
|
|
||||||
|
|
||||||
bool isTargetLeft = target.Position.X < start.Position.X;
|
|
||||||
|
|
||||||
if (target == start)
|
|
||||||
{
|
|
||||||
//시작위치랑 종료위치랑 같고, 방향도 같다면 이동할 필요는 없는 조건이다
|
|
||||||
//오른쪽으로 한번더 이동해서그곳까지 이동한 후 역방향으로 MS 처리한다
|
|
||||||
//PREV 가 아닌 다른 노드가 이동할 대상이다
|
|
||||||
//현재위치에서 지정방향으로 이동한다.
|
|
||||||
var list = new List<MapNode>();
|
|
||||||
var retval = AGVPathResult.CreateSuccess(list, new List<AgvDirection>(), 0, 0);
|
|
||||||
var resversedir = prevDir == AgvDirection.Backward ? AgvDirection.Forward : AgvDirection.Backward;
|
|
||||||
|
|
||||||
//현재위치에서 반드시 시작해야하낟.
|
|
||||||
retval.Path.Add(target);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (deltaX < 0)
|
|
||||||
{
|
|
||||||
//장비가 오른쪽에서 왼쪽으로 오는 경우와
|
|
||||||
var nextNode = start.ConnectedMapNodes.Where(t => t.Id != prev.Id && t.StationType == StationType.Buffer).FirstOrDefault();
|
|
||||||
if (nextNode != null)
|
|
||||||
{
|
|
||||||
//방향결정
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, prevDir));
|
|
||||||
|
|
||||||
//다음노드로 이동을한다.
|
|
||||||
retval.Path.Add(nextNode);
|
|
||||||
var lastDefailt = retval.DetailedPath.Last();
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(lastDefailt.seq + 1, nextNode.Id, nextNode.RfidId, AgvDirection.Forward)
|
|
||||||
{
|
|
||||||
Speed = SpeedLevel.M,
|
|
||||||
IsPass = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
////다시원래노드로 이동을해야한다.(반대방향으로)
|
|
||||||
retval.Path.Add(target);
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo((retval.DetailedPath.Max(t => t.seq) + 1), target.Id, target.RfidId, AgvDirection.Forward));
|
|
||||||
|
|
||||||
//최종목적지로 간다
|
|
||||||
retval.Path.Add(target);
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, AgvDirection.Backward));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//방향결정(다음노드가 없으니 반대방향으로 들어가야한다)
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, resversedir));
|
|
||||||
|
|
||||||
//다음노드가 없으므로 이전노드로 처리를 해야한다.
|
|
||||||
retval.Path.Add(prev);
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Last().seq + 1, prev.Id, prev.RfidId, prevDir)
|
|
||||||
{
|
|
||||||
Speed = SpeedLevel.M,
|
|
||||||
IsPass = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
//최종목적지로 간다
|
|
||||||
retval.Path.Add(target);
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, prevDir));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//왼쪽에서 오른쪽으로 오는 경우가 서로 다르다
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(1, target.Id, target.RfidId, prevDir));
|
|
||||||
|
|
||||||
var nextNode = start.ConnectedMapNodes.Where(t => t.Id != prev.Id && t.StationType == StationType.Buffer).FirstOrDefault();
|
|
||||||
//한번더 이동을한다.(그리고는 반대로 저속 이동을 하게한다)
|
|
||||||
retval.Path.Add(nextNode);
|
|
||||||
var lastDefailt = retval.DetailedPath.Last();
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(lastDefailt.seq + 1, nextNode.Id, nextNode.RfidId, AgvDirection.Backward)
|
|
||||||
{
|
|
||||||
Speed = SpeedLevel.L,
|
|
||||||
IsPass = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
//최종목적지로 간다
|
|
||||||
retval.Path.Add(target);
|
|
||||||
retval.DetailedPath.Add(new NodeMotorInfo(retval.DetailedPath.Max(t => t.seq) + 1, target.Id, target.RfidId, AgvDirection.Backward));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
else if (isTargetLeft)
|
|
||||||
{
|
|
||||||
var directPath = pathfinder.FindBasicPath(start, target, prev, AgvDirection.Backward);
|
|
||||||
ApplyResultToSimulator(directPath, agv);
|
|
||||||
UpdateAdvancedPathDebugInfo(directPath);
|
|
||||||
return directPath;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//대상이 나보다 우측에 있으니 RFID값이 읽어지는 위치까지 이동후에 다시 반대방향으로 마크스탑 해야 함
|
|
||||||
//그냥 대상 노드까지 이동을 한다.. RFID값이 실제 멈추는 위치 이전에 있으니 그곳까지 이동하고 역방향 마크스탑하면 동일한 위치이다. 위 식은 그 이전노드까지 확실하게 이동하는 코드이다
|
|
||||||
//var overshootNode = target.ConnectedMapNodes.OrderByDescending(n => n.Position.X).FirstOrDefault();
|
|
||||||
//if (overshootNode == null || overshootNode.Position.X <= target.Position.X)
|
|
||||||
// return (false, "Overshoot 공간 부족");
|
|
||||||
|
|
||||||
var path1 = pathfinder.FindBasicPath(start, target, prev, AgvDirection.Forward);
|
|
||||||
if (path1.Path.Count < 2)
|
|
||||||
{
|
|
||||||
return AGVPathResult.CreateFailure("Overshoot 경로 생성 실패");
|
|
||||||
}
|
|
||||||
|
|
||||||
//마지막위치는 제거한다. 바로 방향을 전환하기 위함이다.
|
|
||||||
var last = path1.Path.Last();
|
|
||||||
var lastD = path1.DetailedPath.Last();
|
|
||||||
path1.Path.RemoveAt(path1.Path.Count - 1);
|
|
||||||
path1.DetailedPath.RemoveAt(path1.DetailedPath.Count - 1);
|
|
||||||
|
|
||||||
//목표에서 방향바꿔 마크스탑을 해야한다
|
|
||||||
path1.Path.Add(last);
|
|
||||||
|
|
||||||
//디테일은 방향바꿔서 추가 필요(속도는 저속처리해준다)
|
|
||||||
path1.DetailedPath.Add(new NodeMotorInfo(lastD.seq + 1, lastD.NodeId, lastD.RfidId, AgvDirection.Backward)
|
|
||||||
{
|
|
||||||
Speed = SpeedLevel.L,
|
|
||||||
IsPass = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
//var p1Last = path1.Path.Last();
|
|
||||||
//var p1Prev = path1.Path[path1.Path.Count > 1 ? path1.Path.Count - 2 : 0]; // Safety check
|
|
||||||
//var p1Dir = path1.DetailedPath.Last().MotorDirection;
|
|
||||||
|
|
||||||
//var path2 = _advancedPathfinder.FindPath(start, target, p1Last, p1Dir, AgvDirection.Backward);
|
|
||||||
|
|
||||||
//if (path2.Success && path2.DetailedPath.Last().NodeId == target.Id)
|
|
||||||
// path2.DetailedPath = path2.DetailedPath.Take(path2.DetailedPath.Count - 1).ToList();
|
|
||||||
|
|
||||||
//var final = CombinePaths(path1, path2);
|
|
||||||
ApplyResultToSimulator(path1, agv);
|
|
||||||
UpdateAdvancedPathDebugInfo(path1);
|
|
||||||
return path1;// (true, path1, "버퍼 우측(Overshoot)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 노드를 찾기위한 함수
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rfid"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private MapNode FindNode(ushort rfid)
|
|
||||||
{
|
|
||||||
return _simulatorCanvas.Nodes.FirstOrDefault(n => n.RfidId == rfid);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 노드를 찾기위한 함수
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="nodeid"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private MapNode FindNode(string nodeid)
|
|
||||||
{
|
|
||||||
return _simulatorCanvas.Nodes.FirstOrDefault(n => n.Id == nodeid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gateway 도착 후, Target까지의 경로(회차 및 최종진입 포함)를 계산합니다.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="GTNode">게이트웨이 노드값(현재노드값)</param>
|
|
||||||
/// <param name="targetNode">최종 목표값</param>
|
|
||||||
/// <param name="PrevNode">게이트웨이 진입 전 노드</param>
|
|
||||||
/// <param name="PrevDirection">게이트웨이 진입 전 모터방향</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private AGVPathResult GetPathFromGateway(AGVPathfinder pathFinder, MapNode GTNode, MapNode targetNode, MapNode PrevNode, AgvDirection PrevDirection)
|
|
||||||
{
|
|
||||||
AGVPathResult resultPath = null;
|
|
||||||
|
|
||||||
//게이트웨이 진입 한 방향을 보고. 목적지와 도킹방향이 일치하는지 결정한다.
|
|
||||||
var deltaX = GTNode.Position.X - PrevNode.Position.X;
|
|
||||||
var isMonitorLeft = false;
|
|
||||||
|
|
||||||
if (deltaX > 0) //게이트웨이가 우측에 있다
|
|
||||||
{
|
|
||||||
//이떄 모터방향이 후진이라면 모니터는 왼쪽이고, 반대는 오른쪽이다
|
|
||||||
isMonitorLeft = PrevDirection == AgvDirection.Backward;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isMonitorLeft = PrevDirection == AgvDirection.Forward;
|
|
||||||
}
|
|
||||||
|
|
||||||
//로더는 상/하 개념으로 처리해야한다.X축이아닌 Y축을 봐야한다.
|
|
||||||
if (targetNode.StationType == StationType.Loader || targetNode.StationType == StationType.Charger2)
|
|
||||||
{
|
|
||||||
deltaX = GTNode.Position.Y - PrevNode.Position.Y;
|
|
||||||
if (deltaX < 0) isMonitorLeft = PrevDirection == AgvDirection.Backward;
|
|
||||||
else isMonitorLeft = PrevDirection == AgvDirection.Forward;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (targetNode.StationType)
|
|
||||||
{
|
|
||||||
case StationType.Loader:
|
|
||||||
case StationType.Charger2:
|
|
||||||
case StationType.Charger1:
|
|
||||||
case StationType.UnLoader:
|
|
||||||
case StationType.Clearner:
|
|
||||||
case StationType.Buffer:
|
|
||||||
|
|
||||||
//버퍼는 모니터가 왼쪽에 있으면 안된다.
|
|
||||||
//충전기1만 전진 도킹을 한다.
|
|
||||||
List<string> turnPatterns = new List<string>();
|
|
||||||
AGVPathResult rlt1 = new AGVPathResult();
|
|
||||||
rlt1.Success = true;
|
|
||||||
|
|
||||||
//목적지까지 바로 계산한다
|
|
||||||
var motdir = targetNode.DockDirection == DockingDirection.Backward ? AgvDirection.Backward : AgvDirection.Forward;
|
|
||||||
var pathtarget = pathFinder.FindBasicPath(GTNode, targetNode, PrevNode, motdir);
|
|
||||||
|
|
||||||
if ((targetNode.DockDirection == DockingDirection.Backward && isMonitorLeft) ||
|
|
||||||
(targetNode.DockDirection == DockingDirection.Forward && !isMonitorLeft))
|
|
||||||
{
|
|
||||||
//턴을 하는
|
|
||||||
turnPatterns = GetTurnaroundPattern(GTNode, targetNode);
|
|
||||||
if (turnPatterns == null || turnPatterns.Any() == false) return new AGVPathResult { Success = false, Message = $"회차 패턴 없음: Dir {PrevDirection}" };
|
|
||||||
foreach (var item in turnPatterns)
|
|
||||||
{
|
|
||||||
var rfidvalue = ushort.Parse(item.Substring(0, 4));
|
|
||||||
var node = _simulatorCanvas.Nodes.FirstOrDefault(t => t.RfidId == rfidvalue);
|
|
||||||
|
|
||||||
//경로노드추가
|
|
||||||
rlt1.Path.Add(node);
|
|
||||||
|
|
||||||
//Detail 정보도 추가한다.
|
|
||||||
AgvDirection nodedir = item.Substring(4, 1) == "F" ? AgvDirection.Forward : AgvDirection.Backward;
|
|
||||||
MagnetDirection magnet = MagnetDirection.Straight;
|
|
||||||
var magchar = item.Substring(5, 1);
|
|
||||||
if (magchar == "L") magnet = MagnetDirection.Left;
|
|
||||||
else if (magchar == "R") magnet = MagnetDirection.Right;
|
|
||||||
rlt1.DetailedPath.Add(new NodeMotorInfo(rlt1.DetailedPath.Count, node.Id, node.RfidId, nodedir, null, magnet)
|
|
||||||
{
|
|
||||||
Speed = SpeedLevel.L,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//시작위치가 겹치므로 제거해줘야하낟.
|
|
||||||
if (pathtarget.DetailedPath.First().NodeId != rlt1.DetailedPath.Last().NodeId ||
|
|
||||||
pathtarget.DetailedPath.First().MotorDirection != rlt1.DetailedPath.Last().MotorDirection)
|
|
||||||
{
|
|
||||||
new AGVPathResult { Success = false, Message = $"게이트웨이 턴 마지막 주소와, 이 후 주소의 시작 노드ID가 일치하지 않습니다" };
|
|
||||||
}
|
|
||||||
|
|
||||||
pathtarget.Path.RemoveAt(0);
|
|
||||||
pathtarget.DetailedPath.RemoveAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastpath = CombinePaths(rlt1, pathtarget);
|
|
||||||
return lastpath;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Exception("ASdf");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 지정한 노드의 게이트웨이를 반환합니다.
|
|
||||||
/// 도킹노드가 아닐경우 NULL이 반환됩니다.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private MapNode GetGatewayNode(MapNode node)
|
|
||||||
{
|
|
||||||
var rfid = 0;
|
|
||||||
if (node.StationType == StationType.UnLoader) rfid = 10; //unloader
|
|
||||||
else if (node.StationType == StationType.Charger1) rfid = 9; //charger #1
|
|
||||||
else if (node.StationType == StationType.Clearner) rfid = 6; //cleaner
|
|
||||||
else if (node.StationType == StationType.Charger2) rfid = 13; //charger #2
|
|
||||||
else if (node.StationType == StationType.Loader) rfid = 13; //loader
|
|
||||||
else if (node.StationType == StationType.Buffer) rfid = 6;
|
|
||||||
|
|
||||||
if (rfid == 0) return null;
|
|
||||||
return this._simulatorCanvas.Nodes.FirstOrDefault(t => t.RfidId == rfid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AgvDirection GetRequiredGatewayDirection(string gatewayLogId)
|
|
||||||
{
|
|
||||||
switch (gatewayLogId)
|
|
||||||
{
|
|
||||||
case "0010": return AgvDirection.Backward;
|
|
||||||
case "0009": return AgvDirection.Forward;
|
|
||||||
case "0006": return AgvDirection.Backward;
|
|
||||||
case "0013": return AgvDirection.Backward;
|
|
||||||
default: return AgvDirection.Forward;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 대상노드와 게이트웨이노드를 가지고 턴 노드값을 반환합니다
|
|
||||||
/// (이 값은 하드코딩 되어있음)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="gatewayNode"></param>
|
|
||||||
/// <param name="targetNode"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private List<string> GetTurnaroundPattern(MapNode gatewayNode, MapNode targetNode)
|
|
||||||
{
|
|
||||||
switch (gatewayNode.RfidId)
|
|
||||||
{
|
|
||||||
case 6:
|
|
||||||
//버퍼와 11을 다르게하낟.
|
|
||||||
if (targetNode.StationType == StationType.Buffer)
|
|
||||||
{
|
|
||||||
return new List<string> { "0006BL", "0007FS", "0013BL", "0006BL" };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new List<string> { "0006BL", "0007FS", "0013BL", "0006BS" };
|
|
||||||
}
|
|
||||||
case 9: return new List<string> { "0009FL", "0010BS", "0007FL", "0009FS" };
|
|
||||||
case 10: return new List<string> { "0010BR", "0009FR", "0007BS", "0010BS" };
|
|
||||||
case 13: return new List<string> { "0013BL", "0006FL", "0007BS", "0013BS" };
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// p1+p2
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="p1"></param>
|
|
||||||
/// <param name="p2"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private AGVPathResult CombinePaths(AGVPathResult p1, AGVPathResult p2)
|
|
||||||
{
|
|
||||||
var res = new AGVPathResult();
|
|
||||||
res.Success = true;
|
|
||||||
|
|
||||||
var p1last = p1.DetailedPath.LastOrDefault();
|
|
||||||
var p2fist = p2.DetailedPath.FirstOrDefault();
|
|
||||||
|
|
||||||
//p1의 마지막과 p2의 시작이 같다면 p1의 마지막을 제거한다.
|
|
||||||
if (p1last != null && p2fist != null &&
|
|
||||||
(p1last.NodeId == p2fist.NodeId && p1last.MotorDirection == p2fist.MotorDirection && p1last.MagnetDirection == p2fist.MagnetDirection))
|
|
||||||
{
|
|
||||||
p1.Path.RemoveAt(p1.Path.Count - 1);
|
|
||||||
p1.DetailedPath.RemoveAt(p1.DetailedPath.Count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in p1.Path)
|
|
||||||
{
|
|
||||||
res.Path.Add(item);
|
|
||||||
}
|
|
||||||
foreach (var item in p2.Path)
|
|
||||||
{
|
|
||||||
res.Path.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in p1.DetailedPath)
|
|
||||||
{
|
|
||||||
var maxseq = res.DetailedPath.Count == 0 ? 0 : res.DetailedPath.Max(t => t.seq);
|
|
||||||
item.seq = maxseq + 1;
|
|
||||||
res.DetailedPath.Add(item);
|
|
||||||
}
|
|
||||||
foreach (var item in p2.DetailedPath)
|
|
||||||
{
|
|
||||||
var maxseq = res.DetailedPath.Count == 0 ? 0 : res.DetailedPath.Max(t => t.seq);
|
|
||||||
item.seq = maxseq + 1;
|
|
||||||
res.DetailedPath.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyResultToSimulator(AGVPathResult result, VirtualAGV agv)
|
private void ApplyResultToSimulator(AGVPathResult result, VirtualAGV agv)
|
||||||
|
|||||||
@@ -187,9 +187,6 @@ namespace Project
|
|||||||
// 맵 노드 리스트에 추가
|
// 맵 노드 리스트에 추가
|
||||||
PUB._mapCanvas.Nodes.Add(newNode);
|
PUB._mapCanvas.Nodes.Add(newNode);
|
||||||
|
|
||||||
// 캔버스에 노드 반영 (재설정)
|
|
||||||
PUB._mapCanvas.Nodes = PUB._mapCanvas.Nodes;
|
|
||||||
|
|
||||||
// 로그 기록
|
// 로그 기록
|
||||||
PUB.log.AddI($"RFID:{PUB.Result.LastTAG} 노드를 자동 추가했습니다 (NodeId: {newNodeId})");
|
PUB.log.AddI($"RFID:{PUB.Result.LastTAG} 노드를 자동 추가했습니다 (NodeId: {newNodeId})");
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ namespace Project
|
|||||||
if (PUB._mapCanvas != null)
|
if (PUB._mapCanvas != null)
|
||||||
{
|
{
|
||||||
this.Invoke(new Action(() => {
|
this.Invoke(new Action(() => {
|
||||||
PUB._mapCanvas.ExitSyncMode();
|
PUB._mapCanvas.ExitSyncMode( AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ namespace Project.ViewForm
|
|||||||
private void InitializeMapCanvas()
|
private void InitializeMapCanvas()
|
||||||
{
|
{
|
||||||
PUB._mapCanvas.NodeSelect += OnNodeSelected;;
|
PUB._mapCanvas.NodeSelect += OnNodeSelected;;
|
||||||
|
|
||||||
// 스플리터 패널에 맵 캔버스 추가
|
// 스플리터 패널에 맵 캔버스 추가
|
||||||
panel1.Controls.Add(PUB._mapCanvas);
|
panel1.Controls.Add(PUB._mapCanvas);
|
||||||
}
|
}
|
||||||
@@ -143,9 +142,6 @@ namespace Project.ViewForm
|
|||||||
PUB.AGV.DataReceive += AGV_DataReceive;
|
PUB.AGV.DataReceive += AGV_DataReceive;
|
||||||
|
|
||||||
this.timer1.Start();
|
this.timer1.Start();
|
||||||
|
|
||||||
// Set Run Mode
|
|
||||||
PUB._mapCanvas.Mode = AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run;
|
|
||||||
}
|
}
|
||||||
private void AGV_DataReceive(object sender, arDev.Narumi.DataEventArgs e)
|
private void AGV_DataReceive(object sender, arDev.Narumi.DataEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -182,9 +178,6 @@ namespace Project.ViewForm
|
|||||||
PUB.sm.StepChanged -= Sm_StepChanged;
|
PUB.sm.StepChanged -= Sm_StepChanged;
|
||||||
this.ctlAuto1.ButtonClick -= CtlAuto1_ButtonClick;
|
this.ctlAuto1.ButtonClick -= CtlAuto1_ButtonClick;
|
||||||
PUB.AGV.DataReceive -= AGV_DataReceive;
|
PUB.AGV.DataReceive -= AGV_DataReceive;
|
||||||
|
|
||||||
// Reset Mode to Edit
|
|
||||||
PUB._mapCanvas.Mode = AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Edit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tmrun = false;
|
bool tmrun = false;
|
||||||
@@ -195,11 +188,6 @@ namespace Project.ViewForm
|
|||||||
if (timer1.Enabled)
|
if (timer1.Enabled)
|
||||||
{
|
{
|
||||||
timer1.Start();
|
timer1.Start();
|
||||||
// 화면이 보일 때 Run 모드로 강제 설정
|
|
||||||
if (PUB._mapCanvas.Mode != AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run)
|
|
||||||
{
|
|
||||||
PUB._mapCanvas.Mode = AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else timer1.Stop();
|
else timer1.Stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ namespace Project
|
|||||||
PUB._mapCanvas.ShowGrid = false;
|
PUB._mapCanvas.ShowGrid = false;
|
||||||
PUB._mapCanvas.BackColor = Color.FromArgb(32, 32, 32);
|
PUB._mapCanvas.BackColor = Color.FromArgb(32, 32, 32);
|
||||||
PUB._mapCanvas.ForeColor = Color.White;
|
PUB._mapCanvas.ForeColor = Color.White;
|
||||||
|
PUB._mapCanvas.Mode = AGVNavigationCore.Controls.UnifiedAGVCanvas.CanvasMode.Run;
|
||||||
|
|
||||||
this.panTopMenu.MouseMove += LbTitle_MouseMove;
|
this.panTopMenu.MouseMove += LbTitle_MouseMove;
|
||||||
this.panTopMenu.MouseUp += LbTitle_MouseUp;
|
this.panTopMenu.MouseUp += LbTitle_MouseUp;
|
||||||
|
|||||||
Reference in New Issue
Block a user