ing...
This commit is contained in:
@@ -1775,6 +1775,11 @@ namespace AGVNavigationCore.Controls
|
||||
/// </summary>
|
||||
private Color GetAGVCenterColor(AGVState state)
|
||||
{
|
||||
// Stop-Mark 상태 (Error 상태와 유사하게 처리하거나 별도 처리)
|
||||
// 여기서는 AGVState에 StopMark가 없으므로, 외부에서 상태를 Error로 설정하거나
|
||||
// 별도의 플래그를 확인해야 함. 하지만 IAGV 인터페이스에는 플래그가 없음.
|
||||
// 따라서 fMain에서 상태를 Error로 설정하는 것을 권장.
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AGVState.Moving: return Color.White;
|
||||
@@ -1794,7 +1799,7 @@ namespace AGVNavigationCore.Controls
|
||||
{
|
||||
case AGVState.Moving: return Color.DarkGreen;
|
||||
case AGVState.Charging: return Color.DarkBlue;
|
||||
case AGVState.Error: return Color.DarkRed;
|
||||
case AGVState.Error: return Color.DarkRed; // Stop-Mark 시 Error 상태 사용
|
||||
case AGVState.Docking: return Color.DarkOrange;
|
||||
default: return Color.DarkGray;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,16 @@ namespace AGVNavigationCore.Controls
|
||||
var worldPoint = ScreenToWorld(e.Location);
|
||||
var hitNode = GetNodeAt(worldPoint);
|
||||
|
||||
// 에뮬레이터 모드 처리
|
||||
if (_canvasMode == CanvasMode.Emulator)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right && hitNode != null)
|
||||
{
|
||||
NodeRightClicked?.Invoke(this, hitNode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 🔥 어떤 모드에서든 노드/빈 공간 클릭 시 선택 이벤트 발생 (속성창 업데이트)
|
||||
bool ctrlPressed = (ModifierKeys & Keys.Control) == Keys.Control;
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace AGVNavigationCore.Controls
|
||||
public enum CanvasMode
|
||||
{
|
||||
Edit, // 편집 가능 (맵 에디터)
|
||||
Sync // 동기화 모드 (장비 설정 동기화)
|
||||
Sync, // 동기화 모드 (장비 설정 동기화)
|
||||
Emulator // 에뮬레이터 모드
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,6 +147,9 @@ namespace AGVNavigationCore.Controls
|
||||
// 컨텍스트 메뉴
|
||||
private ContextMenuStrip _contextMenu;
|
||||
|
||||
// 이벤트
|
||||
public event EventHandler<MapNode> NodeRightClicked;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
@@ -81,6 +81,13 @@ namespace AGVNavigationCore.Models
|
||||
private List<string> _detectedRfids = new List<string>(); // 감지된 RFID 목록
|
||||
private bool _isPositionConfirmed = false; // 위치 확정 여부 (RFID 2개 이상 감지)
|
||||
|
||||
// 에뮬레이터용 추가 속성
|
||||
public double Angle { get; set; } = 0; // 0 = Right, 90 = Down, 180 = Left, 270 = Up (Standard Math)
|
||||
// But AGV Direction: Forward usually means "Front of AGV".
|
||||
// Let's assume Angle is the orientation of the AGV in degrees.
|
||||
|
||||
public bool IsStopMarkOn { get; set; } = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
@@ -433,6 +440,27 @@ namespace AGVNavigationCore.Models
|
||||
OnError("긴급 정지가 실행되었습니다.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 일시 정지 (경로 유지)
|
||||
/// </summary>
|
||||
public void Pause()
|
||||
{
|
||||
_isMoving = false;
|
||||
_currentSpeed = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이동 재개
|
||||
/// </summary>
|
||||
public void Resume()
|
||||
{
|
||||
if (_currentPath != null && _remainingNodes != null && _remainingNodes.Count > 0)
|
||||
{
|
||||
_isMoving = true;
|
||||
SetState(AGVState.Moving);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods - 프레임 업데이트 (외부에서 정기적으로 호출)
|
||||
|
||||
@@ -15,6 +15,8 @@ using Newtonsoft.Json;
|
||||
using AGVNavigationCore.PathFinding.Planning;
|
||||
using AGVNavigationCore.PathFinding.Core;
|
||||
using AGVSimulator.Models;
|
||||
using System.IO.Ports;
|
||||
using System.Text;
|
||||
|
||||
namespace AGVSimulator.Forms
|
||||
{
|
||||
@@ -25,6 +27,86 @@ namespace AGVSimulator.Forms
|
||||
{
|
||||
#region Fields
|
||||
|
||||
// Emulator Fields
|
||||
private SerialPort _emulatorPort;
|
||||
private ComboBox _portCombo;
|
||||
private Button _connectButton;
|
||||
private bool _isEmulatorConnected = false;
|
||||
|
||||
// Emulator State Fields
|
||||
private UInt16 _emu_system0 = 0;
|
||||
private UInt16 _emu_system1 = 0;
|
||||
private UInt16 _emu_error = 0;
|
||||
private byte _emu_signal = 0;
|
||||
private char _emu_sts_bunki = 'S';
|
||||
private char _emu_sts_speed = 'L';
|
||||
private char _emu_sts_dir = 'F';
|
||||
private char _emu_sts_sensor = '1';
|
||||
private string _lastSentNodeId = null;
|
||||
|
||||
public enum esystemflag0
|
||||
{
|
||||
Memory_RW_State = 5,
|
||||
EXT_IO_Conn_State,
|
||||
RFID_Conn_State,
|
||||
M5E_Module_Run_State = 8,
|
||||
Front_Ultrasonic_Conn_State,
|
||||
Front_Untrasonic_Sensor_State,
|
||||
Side_Ultrasonic_Conn_State,
|
||||
Side_Ultrasonic_Sensor_State = 12,
|
||||
Front_Guide_Sensor_State,
|
||||
Rear_Guide_Sensor_State,
|
||||
Battery_Level_Check
|
||||
}
|
||||
public enum esystemflag1
|
||||
{
|
||||
Side_Detect_Ignore = 3,
|
||||
Melody_check,
|
||||
Mark2_check,
|
||||
Mark1_check,
|
||||
gateout_check,
|
||||
Battery_charging = 8,
|
||||
re_Start,
|
||||
front_detect_ignore,
|
||||
front_detect_check,
|
||||
stop_by_front_detect = 12,
|
||||
stop_by_cross_in,
|
||||
agv_stop,
|
||||
agv_run
|
||||
}
|
||||
public enum eerror
|
||||
{
|
||||
Emergency = 0,
|
||||
Overcurrent,
|
||||
Charger_run_error,
|
||||
Charger_pos_error,
|
||||
line_out_error = 4,
|
||||
runerror_by_no_magent_line,
|
||||
controller_comm_error = 11,
|
||||
arrive_ctl_comm_error,
|
||||
door_ctl_comm_error,
|
||||
charger_comm_error,
|
||||
cross_ctrl_comm_error,
|
||||
}
|
||||
public enum esignal
|
||||
{
|
||||
front_gate_out = 0,
|
||||
rear_sensor_out,
|
||||
mark_sensor_1,
|
||||
mark_sensor_2,
|
||||
front_left_sensor,
|
||||
front_right_sensor,
|
||||
front_center_sensor,
|
||||
charger_align_sensor,
|
||||
}
|
||||
public enum estsvaluetype
|
||||
{
|
||||
bunki,
|
||||
speed,
|
||||
direction,
|
||||
sensor
|
||||
}
|
||||
|
||||
private UnifiedAGVCanvas _simulatorCanvas;
|
||||
private List<MapNode> _mapNodes;
|
||||
private AGVPathfinder _advancedPathfinder;
|
||||
@@ -92,6 +174,9 @@ namespace AGVSimulator.Forms
|
||||
// 방향 콤보박스 초기화
|
||||
InitializeDirectionCombo();
|
||||
|
||||
// 에뮬레이터 UI 초기화
|
||||
InitializeEmulatorUI();
|
||||
|
||||
// 초기 상태 설정
|
||||
UpdateUI();
|
||||
|
||||
@@ -716,12 +801,32 @@ namespace AGVSimulator.Forms
|
||||
foreach (var agv in _agvList)
|
||||
{
|
||||
agv.Update(100); // 100ms 간격으로 업데이트
|
||||
|
||||
// Emulator Tag Logic
|
||||
if (_isEmulatorConnected && agv == _agvList.FirstOrDefault())
|
||||
{
|
||||
if (agv.CurrentNodeId != null && agv.CurrentNodeId != _lastSentNodeId)
|
||||
{
|
||||
var rfid = GetRfidByNodeId(agv.CurrentNodeId);
|
||||
if (!string.IsNullOrEmpty(rfid))
|
||||
{
|
||||
SendTag(rfid);
|
||||
_lastSentNodeId = agv.CurrentNodeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UI 업데이트
|
||||
UpdateUI();
|
||||
_simulatorCanvas.Invalidate(); // 화면 다시 그리기
|
||||
|
||||
// 에뮬레이터 상태 전송
|
||||
if (_isEmulatorConnected)
|
||||
{
|
||||
SendEmulatorStatus();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -2005,6 +2110,412 @@ namespace AGVSimulator.Forms
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#region Emulator Logic
|
||||
|
||||
private void InitializeEmulatorUI()
|
||||
{
|
||||
// 에뮬레이터 제어 패널 생성
|
||||
var emulatorPanel = new GroupBox();
|
||||
emulatorPanel.Text = "AGV Emulator (RS232)";
|
||||
emulatorPanel.Height = 60;
|
||||
emulatorPanel.Dock = DockStyle.Top;
|
||||
|
||||
var layout = new FlowLayoutPanel();
|
||||
layout.Dock = DockStyle.Fill;
|
||||
layout.Padding = new Padding(5);
|
||||
layout.AutoSize = true;
|
||||
|
||||
// 포트 선택 콤보박스
|
||||
_portCombo = new ComboBox();
|
||||
_portCombo.Width = 100;
|
||||
_portCombo.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
_portCombo.DropDown += (s, e) => {
|
||||
_portCombo.Items.Clear();
|
||||
_portCombo.Items.AddRange(SerialPort.GetPortNames());
|
||||
};
|
||||
_portCombo.Items.AddRange(SerialPort.GetPortNames());
|
||||
if (_portCombo.Items.Count > 0) _portCombo.SelectedIndex = 0;
|
||||
|
||||
// 연결 버튼
|
||||
_connectButton = new Button();
|
||||
_connectButton.Text = "Connect";
|
||||
_connectButton.Click += OnConnectEmulator_Click;
|
||||
|
||||
layout.Controls.Add(new Label { Text = "Port:", AutoSize = true, Margin = new Padding(3, 8, 3, 3) });
|
||||
layout.Controls.Add(_portCombo);
|
||||
layout.Controls.Add(_connectButton);
|
||||
|
||||
emulatorPanel.Controls.Add(layout);
|
||||
|
||||
// 폼의 최상단에 추가
|
||||
this.Controls.Add(emulatorPanel);
|
||||
emulatorPanel.BringToFront();
|
||||
}
|
||||
|
||||
private void OnConnectEmulator_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_isEmulatorConnected)
|
||||
{
|
||||
DisconnectEmulator();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_portCombo.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("포트를 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
ConnectEmulator(_portCombo.SelectedItem.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectEmulator(string portName)
|
||||
{
|
||||
try
|
||||
{
|
||||
_emulatorPort = new SerialPort(portName, 115200, Parity.None, 8, StopBits.One);
|
||||
_emulatorPort.DataReceived += OnEmulatorDataReceived;
|
||||
_emulatorPort.Open();
|
||||
_isEmulatorConnected = true;
|
||||
_connectButton.Text = "Disconnect";
|
||||
_portCombo.Enabled = false;
|
||||
MessageBox.Show($"에뮬레이터 시작: {portName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"연결 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectEmulator()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_emulatorPort != null && _emulatorPort.IsOpen)
|
||||
{
|
||||
_emulatorPort.Close();
|
||||
}
|
||||
_isEmulatorConnected = false;
|
||||
_connectButton.Text = "Connect";
|
||||
_portCombo.Enabled = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"해제 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private StringBuilder _recvBuffer = new StringBuilder();
|
||||
|
||||
private void OnEmulatorDataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string data = _emulatorPort.ReadExisting();
|
||||
_recvBuffer.Append(data);
|
||||
|
||||
string buffer = _recvBuffer.ToString();
|
||||
int stxIndex = buffer.IndexOf((char)0x02);
|
||||
|
||||
while (stxIndex >= 0)
|
||||
{
|
||||
int etxIndex = buffer.IndexOf((char)0x03, stxIndex);
|
||||
if (etxIndex > stxIndex)
|
||||
{
|
||||
string packet = buffer.Substring(stxIndex + 1, etxIndex - stxIndex - 1);
|
||||
ProcessEmulatorPacket(packet);
|
||||
|
||||
// 처리된 패킷 제거
|
||||
buffer = buffer.Substring(etxIndex + 1);
|
||||
stxIndex = buffer.IndexOf((char)0x02);
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // ETX 아직 안옴
|
||||
}
|
||||
}
|
||||
|
||||
_recvBuffer.Clear();
|
||||
_recvBuffer.Append(buffer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Emulator Recv Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#region Emulator Helpers
|
||||
private bool GetBit(ref UInt16 _value, int idx)
|
||||
{
|
||||
var offset = (UInt16)(1 << idx);
|
||||
return (_value & offset) != 0;
|
||||
}
|
||||
|
||||
private bool SetBit(ref UInt16 _value, int idx, bool value)
|
||||
{
|
||||
var oldvalue = GetBit(ref _value, idx);
|
||||
if (value)
|
||||
{
|
||||
var offset = (UInt16)(1 << idx);
|
||||
_value = (UInt16)(_value | offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
var offset = (UInt16)(~(1 << idx));
|
||||
_value = (UInt16)(_value & offset);
|
||||
}
|
||||
return oldvalue != value;
|
||||
}
|
||||
|
||||
private bool SetBit(ref byte _value, int idx, bool value)
|
||||
{
|
||||
var offset = (byte)(1 << idx);
|
||||
if (value) _value |= offset;
|
||||
else _value &= (byte)~offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetAGV(esystemflag0 flag, bool value)
|
||||
{
|
||||
SetBit(ref _emu_system0, (int)flag, value);
|
||||
}
|
||||
private void SetAGV(esystemflag1 flag, bool value)
|
||||
{
|
||||
SetBit(ref _emu_system1, (int)flag, value);
|
||||
}
|
||||
private void SetAGV(eerror flag, bool value)
|
||||
{
|
||||
SetBit(ref _emu_error, (int)flag, value);
|
||||
}
|
||||
private void SetAGV(esignal flag, bool value)
|
||||
{
|
||||
SetBit(ref _emu_signal, (int)flag, value);
|
||||
}
|
||||
private void SetSTS(estsvaluetype target, char value)
|
||||
{
|
||||
switch (target)
|
||||
{
|
||||
case estsvaluetype.sensor: _emu_sts_sensor = value; break;
|
||||
case estsvaluetype.direction: _emu_sts_dir = value; break;
|
||||
case estsvaluetype.speed: _emu_sts_speed = value; break;
|
||||
case estsvaluetype.bunki: _emu_sts_bunki = value; break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void ProcessEmulatorPacket(string packet)
|
||||
{
|
||||
// Packet: CMD(3) + DATA(...) + Checksum(2)
|
||||
// But here packet is substring between STX and ETX.
|
||||
// Example: STS...Checksum
|
||||
|
||||
if (packet.Length < 3) return;
|
||||
string cmd = packet.Substring(0, 3);
|
||||
string data = "";
|
||||
if (packet.Length > 5) // CMD + Checksum(2)
|
||||
{
|
||||
data = packet.Substring(3, packet.Length - 5);
|
||||
}
|
||||
|
||||
// AGV 제어 (첫 번째 AGV 대상)
|
||||
var agv = _agvList.FirstOrDefault();
|
||||
|
||||
this.Invoke(new Action(() => {
|
||||
switch (cmd)
|
||||
{
|
||||
case "CRN": // 기동명령
|
||||
if (data.Length > 0) SetSTS(estsvaluetype.direction, data[0]);
|
||||
SetAGV(esystemflag1.agv_stop, false);
|
||||
SetAGV(esystemflag1.agv_run, true);
|
||||
if (agv != null) agv.Resume();
|
||||
break;
|
||||
|
||||
case "CST": // 중지명령
|
||||
if (data.StartsWith("M"))
|
||||
{
|
||||
// Mark Stop
|
||||
// TODO: Implement Mark Stop logic in VirtualAGV if needed
|
||||
// For now, just log it
|
||||
Console.WriteLine("Mark Stop Command Received");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAGV(esystemflag1.agv_run, false);
|
||||
SetAGV(esystemflag1.agv_stop, true);
|
||||
if (agv != null) agv.Pause();
|
||||
}
|
||||
break;
|
||||
|
||||
case "CBR": // 분기명령
|
||||
// FSL1
|
||||
if (data.Length >= 4)
|
||||
{
|
||||
SetSTS(estsvaluetype.direction, data[0]);
|
||||
SetSTS(estsvaluetype.bunki, data[1]);
|
||||
SetSTS(estsvaluetype.speed, data[2]);
|
||||
SetSTS(estsvaluetype.sensor, data[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "CRT": // 수동제어
|
||||
if (data.Length >= 4)
|
||||
{
|
||||
_emu_sts_dir = data[0];
|
||||
_emu_sts_bunki = data[1];
|
||||
_emu_sts_speed = data[2];
|
||||
_emu_sts_sensor = data[3];
|
||||
SetAGV(esystemflag1.agv_stop, false);
|
||||
SetAGV(esystemflag1.agv_run, true);
|
||||
if (agv != null) agv.Resume();
|
||||
}
|
||||
break;
|
||||
|
||||
case "SFR": // Reset
|
||||
SetAGV(eerror.Emergency, false);
|
||||
SetAGV(eerror.line_out_error, false);
|
||||
SetAGV(eerror.Overcurrent, false);
|
||||
SetAGV(esystemflag1.agv_run, false);
|
||||
SetAGV(esystemflag1.agv_stop, true);
|
||||
if (agv != null) agv.Pause();
|
||||
break;
|
||||
|
||||
case "CBT": // 충전
|
||||
SetAGV(esystemflag1.Battery_charging, true);
|
||||
if (data.Length >= 5)
|
||||
{
|
||||
var cmdChar = data[4];
|
||||
if (cmdChar == 'I') SetAGV(esystemflag1.Battery_charging, true);
|
||||
else SetAGV(esystemflag1.Battery_charging, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case "ACK":
|
||||
// Log ACK
|
||||
break;
|
||||
|
||||
default:
|
||||
// Send ACK for other commands
|
||||
SendCmd("ACK", cmd);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void SendCmd(string cmd, string value)
|
||||
{
|
||||
if (_emulatorPort == null || !_emulatorPort.IsOpen) return;
|
||||
|
||||
var barr = new List<byte>();
|
||||
barr.Add(0x02);
|
||||
barr.AddRange(System.Text.Encoding.Default.GetBytes(cmd));
|
||||
barr.AddRange(System.Text.Encoding.Default.GetBytes(value));
|
||||
barr.Add((byte)'*');
|
||||
barr.Add((byte)'*');
|
||||
barr.Add(0x03);
|
||||
|
||||
try
|
||||
{
|
||||
_emulatorPort.Write(barr.ToArray(), 0, barr.Count);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void SendTag(string tagno)
|
||||
{
|
||||
if (_emulatorPort == null || !_emulatorPort.IsOpen) return;
|
||||
|
||||
tagno = tagno.PadLeft(6, '0');
|
||||
if (tagno.Length > 6) tagno = tagno.Substring(0, 6);
|
||||
|
||||
var barr = new List<byte>();
|
||||
barr.Add(0x02);
|
||||
barr.Add((byte)'T');
|
||||
barr.Add((byte)'A');
|
||||
barr.Add((byte)'G');
|
||||
barr.AddRange(System.Text.Encoding.Default.GetBytes(tagno));
|
||||
barr.Add((byte)'*');
|
||||
barr.Add((byte)'*');
|
||||
barr.Add(0x03);
|
||||
|
||||
try
|
||||
{
|
||||
_emulatorPort.Write(barr.ToArray(), 0, barr.Count);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void SendEmulatorStatus()
|
||||
{
|
||||
if (_emulatorPort == null || !_emulatorPort.IsOpen) return;
|
||||
|
||||
var agv = _agvList.FirstOrDefault();
|
||||
|
||||
// Sync state from VirtualAGV
|
||||
if (agv != null)
|
||||
{
|
||||
// Update Battery
|
||||
// Update Position/Tag?
|
||||
}
|
||||
|
||||
// STS Packet Construction
|
||||
// STS(3) + Volt(3) + Sys0(4) + Sys1(4) + Err(4) + Spd(1) + Bunki(1) + Dir(1) + Sensor(1) + Signal(2) + Checksum(2)
|
||||
|
||||
// Default buffer
|
||||
var sample = "02 53 54 53 32 35 38 46 46 46 46 34 30 30 30 30 30 30 30 4C 53 46 30 30 30 30 30 30 33 41 03";
|
||||
var barr = sample.Split(' ').Select(t => Convert.ToByte(t, 16)).ToArray();
|
||||
|
||||
// Volt (255 for now)
|
||||
var voltstr = "255";
|
||||
var bufarr = System.Text.Encoding.Default.GetBytes(voltstr);
|
||||
Array.Copy(bufarr, 0, barr, 4, bufarr.Length);
|
||||
|
||||
// System0
|
||||
bufarr = System.Text.Encoding.Default.GetBytes(_emu_system0.ToString("X2").PadLeft(4, '0'));
|
||||
Array.Copy(bufarr, 0, barr, 7, bufarr.Length);
|
||||
|
||||
// System1
|
||||
bufarr = System.Text.Encoding.Default.GetBytes(_emu_system1.ToString("X2").PadLeft(4, '0'));
|
||||
Array.Copy(bufarr, 0, barr, 11, bufarr.Length);
|
||||
|
||||
// Error
|
||||
bufarr = System.Text.Encoding.Default.GetBytes(_emu_error.ToString("X2").PadLeft(4, '0'));
|
||||
Array.Copy(bufarr, 0, barr, 15, bufarr.Length);
|
||||
|
||||
// Status Chars
|
||||
barr[19] = (byte)_emu_sts_speed;
|
||||
barr[20] = (byte)_emu_sts_bunki;
|
||||
barr[21] = (byte)_emu_sts_dir;
|
||||
barr[22] = (byte)_emu_sts_sensor;
|
||||
|
||||
// Signal
|
||||
bufarr = System.Text.Encoding.Default.GetBytes(_emu_signal.ToString("X2").PadLeft(2, '0'));
|
||||
Array.Copy(bufarr, 0, barr, 23, bufarr.Length);
|
||||
|
||||
// Checksum (**)
|
||||
barr[barr.Length - 3] = (byte)'*';
|
||||
barr[barr.Length - 2] = (byte)'*';
|
||||
|
||||
try
|
||||
{
|
||||
_emulatorPort.Write(barr, 0, barr.Length);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private string CalculateChecksum(string data)
|
||||
{
|
||||
int sum = 0;
|
||||
foreach (char c in data) sum += c;
|
||||
|
||||
// 16진수 변환 후 뒤 2자리
|
||||
string hex = sum.ToString("X");
|
||||
if (hex.Length >= 2) return hex.Substring(hex.Length - 2);
|
||||
return hex.PadLeft(2, '0');
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -284,6 +284,24 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PUB.cs" />
|
||||
<Compile Include="CSetting.cs" />
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_CLEANER_IN.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_CLEANER_OUT.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_LOADER_IN.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_LOADER_OUT.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_UNLOADER_IN.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_SM_RUN_UNLOADER_OUT.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="StateMachine\Step\_Util.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -159,6 +159,13 @@ namespace Project.Device
|
||||
public bool BufferOutComplete { get; set; }
|
||||
public bool BufferReadyError { get; set; }
|
||||
|
||||
public bool LoaderInComplete { get; set; }
|
||||
public bool LoaderOutComplete { get; set; }
|
||||
public bool UnloaderInComplete { get; set; }
|
||||
public bool UnloaderOutComplete { get; set; }
|
||||
public bool CleanerInComplete { get; set; }
|
||||
public bool CleanerOutComplete { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AGV상태를 Xbee 로 전송한다
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Project
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.MARKSTROPB: //후진방향으로 마크스탑
|
||||
case ERunStep.MARKSTOPB: //후진방향으로 마크스탑
|
||||
case ERunStep.MARKSTOPF: //전진방향으로 마크스탑
|
||||
|
||||
//이동중이지 않다면 먼저 이동을 진행한다
|
||||
@@ -249,6 +249,96 @@ namespace Project
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ERunStep.LOADER_OUT: //로더아웃
|
||||
if (_SM_RUN_LOADER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹해제완료);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.LoaderInComplete = false;
|
||||
PUB.XBE.LoaderOutComplete = true;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.LOADER_IN: //로더도킹
|
||||
if (_SM_RUN_LOADER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.LoaderInComplete = true;
|
||||
|
||||
//로더아웃으로 자동 진행 합니다
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.LOADER_OUT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.UNLOADER_OUT: //언로더아웃
|
||||
if (_SM_RUN_UNLOADER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹해제완료);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.UnloaderInComplete = false;
|
||||
PUB.XBE.UnloaderOutComplete = true;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.UNLOADER_IN: //언로더도킹
|
||||
if (_SM_RUN_UNLOADER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.UnloaderInComplete = true;
|
||||
|
||||
//언로더아웃으로 자동 진행 합니다
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.UNLOADER_OUT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.CLEANER_OUT: //클리너아웃
|
||||
if (_SM_RUN_CLEANER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹해제완료);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.CleanerInComplete = false;
|
||||
PUB.XBE.CleanerOutComplete = true;
|
||||
|
||||
//대기상태로 전환
|
||||
PUB.sm.SetNewRunStep(ERunStep.READY);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.CLEANER_IN: //클리너도킹
|
||||
if (_SM_RUN_CLEANER_IN(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
PUB.Speak(Lang.버퍼도킹이완료되었습니다);
|
||||
|
||||
//도킹완료상태를 업데이트한다.
|
||||
PUB.XBE.CleanerInComplete = true;
|
||||
|
||||
//클리너아웃으로 자동 진행 합니다
|
||||
PUB.sm.ClearRunStep();
|
||||
PUB.sm.SetNewRunStep(ERunStep.CLEANER_OUT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ERunStep.BUFFER_OUT: //버퍼아웃
|
||||
if (_SM_RUN_BUFFER_OUT(runStepisFirst, PUB.sm.GetRunSteptime))
|
||||
{
|
||||
|
||||
@@ -22,40 +22,14 @@ namespace Project
|
||||
var funcname = "_SM_RUN_BUFFER_IN";
|
||||
var idx = 1;
|
||||
|
||||
if (runStepisFirst)
|
||||
{
|
||||
//PUB.flag.set(EFlag.FLAG_NEXTSTOP_ALIGN, false);
|
||||
VAR.BOOL[eVarBool.FLAG_NEXTSTOP_ALIGN] = false;//
|
||||
//VAR.BOOL[eVarBool.FLAG_NEXTSTOP_MARK] = false;//);
|
||||
}
|
||||
|
||||
//HW 연결오류
|
||||
if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false)
|
||||
return false;
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다 200409
|
||||
if (PUB.AGV.system1.stop_by_front_detect == true)
|
||||
{
|
||||
var tsSpeak = DateTime.Now - LastSpeakTime;
|
||||
if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm)
|
||||
{
|
||||
PUB.Speak(Lang.전방에물체가감지되었습니다);
|
||||
LastSpeakTime = DateTime.Now;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false)
|
||||
return false;
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
/*
|
||||
* 버퍼IN시퀀스
|
||||
|
||||
@@ -14,37 +14,15 @@ namespace Project
|
||||
|
||||
public Boolean _SM_RUN_BUFFER_OUT(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
if (runStepisFirst)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//HW 연결오류
|
||||
if (PUB.AGV.IsOpen == false)
|
||||
{
|
||||
PUB.Result.SetResultMessage(eResult.Hardware, eECode.AGVCONN, eNextStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false)
|
||||
return false;
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다 200409
|
||||
if (PUB.AGV.system1.stop_by_front_detect == true)
|
||||
{
|
||||
var tsSpeak = DateTime.Now - LastSpeakTime;
|
||||
if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm)
|
||||
{
|
||||
PUB.Speak(Lang.전방에물체가감지되었습니다);
|
||||
LastSpeakTime = DateTime.Now;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false)
|
||||
return false;
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
|
||||
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_CLEANER_IN.cs
Normal file
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_CLEANER_IN.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 클리너 진입
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_CLEANER_IN(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var funcname = "_SM_RUN_CLEANER_IN";
|
||||
var idx = 1;
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
/*
|
||||
* 클리너 IN 시퀀스 (버퍼 복사 - 턴 제거)
|
||||
* 1. LIFT DOWN
|
||||
* 2. 후진-저속-마크다운 실행
|
||||
*/
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("클리너진입시작");
|
||||
PUB.Speak("클리너 작업을 시작합니다");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트를 내린다.
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트다운센서를 확인한다.
|
||||
var liftdown = true;
|
||||
if (liftdown == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.STP);
|
||||
PUB.log.AddE("리프트 하강이 확인되지 않습니다(10초)");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.log.Add("리프트 하강 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑셋팅
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//저속이동
|
||||
var moveset = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if (moveset == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV속도설정이 완료되지 않았습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("MARK STOP신호가 확인되지 않습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV가 멈추지 않아 강제종료 합니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add("클리너진입완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.AddEEDB($"클리너진입완료({PUB.Result.TargetPos})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Cs_HMI/Project/StateMachine/Step/_SM_RUN_CLEANER_OUT.cs
Normal file
80
Cs_HMI/Project/StateMachine/Step/_SM_RUN_CLEANER_OUT.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 클리너 배출
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_CLEANER_OUT(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//빈 상태로 아웃해야한다.
|
||||
PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑
|
||||
PUB.AGV.AGVMoveStop("cleaner out", arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이동확인
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//멈춤확인
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_LOADER_IN.cs
Normal file
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_LOADER_IN.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 로더 진입
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_LOADER_IN(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var funcname = "_SM_RUN_LOADER_IN";
|
||||
var idx = 1;
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
/*
|
||||
* 로더 IN 시퀀스 (버퍼 복사 - 턴 제거)
|
||||
* 1. LIFT DOWN
|
||||
* 2. 후진-저속-마크다운 실행
|
||||
*/
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("로더진입시작");
|
||||
PUB.Speak("로더 작업을 시작합니다"); // Lang resource might not exist, using string
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트를 내린다.
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트다운센서를 확인한다.
|
||||
var liftdown = true; // 센서 확인 로직이 주석처리되어 있거나 하드코딩되어 있었음 (버퍼 코드 참조)
|
||||
if (liftdown == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.STP);
|
||||
PUB.log.AddE("리프트 하강이 확인되지 않습니다(10초)");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.log.Add("리프트 하강 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑셋팅
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//저속이동
|
||||
var moveset = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if (moveset == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV속도설정이 완료되지 않았습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("MARK STOP신호가 확인되지 않습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV가 멈추지 않아 강제종료 합니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add("로더진입완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.AddEEDB($"로더진입완료({PUB.Result.TargetPos})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Cs_HMI/Project/StateMachine/Step/_SM_RUN_LOADER_OUT.cs
Normal file
82
Cs_HMI/Project/StateMachine/Step/_SM_RUN_LOADER_OUT.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 로더 배출
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_LOADER_OUT(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//빈 상태로 아웃해야한다.
|
||||
PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑
|
||||
PUB.AGV.AGVMoveStop("loader out", arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이동확인
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//멈춤확인
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
// 턴 제거됨
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_UNLOADER_IN.cs
Normal file
155
Cs_HMI/Project/StateMachine/Step/_SM_RUN_UNLOADER_IN.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 언로더 진입
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_UNLOADER_IN(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
var funcname = "_SM_RUN_UNLOADER_IN";
|
||||
var idx = 1;
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
/*
|
||||
* 언로더 IN 시퀀스 (버퍼 복사 - 턴 제거)
|
||||
* 1. LIFT DOWN
|
||||
* 2. 후진-저속-마크다운 실행
|
||||
*/
|
||||
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
PUB.log.Add("언로더진입시작");
|
||||
PUB.Speak("언로더 작업을 시작합니다");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트를 내린다.
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.DN);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//리프트다운센서를 확인한다.
|
||||
var liftdown = true;
|
||||
if (liftdown == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.LiftControl(arDev.Narumi.LiftCommand.STP);
|
||||
PUB.log.AddE("리프트 하강이 확인되지 않습니다(10초)");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.log.Add("리프트 하강 완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑셋팅
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//저속이동
|
||||
var moveset = PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Backward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
if (moveset == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV속도설정이 완료되지 않았습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Backward);
|
||||
PUB.AGV.AGVMoveStop(funcname, arDev.Narumi.eStopOpt.MarkStop);
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑신호가 3초이내로 들어와야 한다
|
||||
if (VAR.BOOL[eVarBool.NEXTSTOP_MARK] == false)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 3)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("MARK STOP신호가 확인되지 않습니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//AGV가 멈출때까지 기다린다.
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
var ts = VAR.TIME.RUN(eVarTime.LastTurnCommandTime);
|
||||
if (ts.TotalSeconds > 10)
|
||||
{
|
||||
PUB.AGV.AGVMoveStop(funcname);
|
||||
PUB.log.AddE("AGV가 멈추지 않아 강제종료 합니다");
|
||||
PUB.sm.SetNewRunStep(ERunStep.ERROR);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
VAR.TIME.Update(eVarTime.LastTurnCommandTime);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//완료되었다.
|
||||
PUB.log.Add("언로더진입완료");
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
PUB.AddEEDB($"언로더진입완료({PUB.Result.TargetPos})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Cs_HMI/Project/StateMachine/Step/_SM_RUN_UNLOADER_OUT.cs
Normal file
81
Cs_HMI/Project/StateMachine/Step/_SM_RUN_UNLOADER_OUT.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Project.StateMachine;
|
||||
using COMM;
|
||||
using AR;
|
||||
|
||||
namespace Project
|
||||
{
|
||||
public partial class fMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 언로더 배출
|
||||
/// </summary>
|
||||
public Boolean _SM_RUN_UNLOADER_OUT(bool isFirst, TimeSpan stepTime)
|
||||
{
|
||||
|
||||
//충전 상태가 OFF되어야 동작하게한다
|
||||
if (_SM_RUN_CHGOFF(isFirst, stepTime) == false) return false;
|
||||
|
||||
//라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
if (CheckLiderStop() == false) return false;
|
||||
|
||||
//현재 위치가 결정되어있는지 체크한다
|
||||
if (_SM_RUN_POSCHK(isFirst, stepTime) == false) return false;
|
||||
|
||||
var idx = 1;
|
||||
if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//빈 상태로 아웃해야한다.
|
||||
PUB.AGV.AGVMoveSet(new arDev.Narumi.BunkiData
|
||||
{
|
||||
Bunki = arDev.Narumi.eBunki.Strate,
|
||||
Direction = arDev.Narumi.eMoveDir.Forward,
|
||||
PBSSensor = 0,
|
||||
Speed = arDev.Narumi.eMoveSpd.Low,
|
||||
});
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//전진이동
|
||||
PUB.AGV.AGVMoveRun(arDev.Narumi.eRunOpt.Forward);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//마크스탑
|
||||
PUB.AGV.AGVMoveStop("unloader out", arDev.Narumi.eStopOpt.MarkStop);
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//이동확인
|
||||
if (PUB.AGV.system1.agv_run == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
else if (PUB.sm.RunStepSeq == idx++)
|
||||
{
|
||||
//멈춤확인
|
||||
if (PUB.AGV.system1.agv_run == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PUB.sm.UpdateRunStepSeq();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,26 @@ namespace Project
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 라이더멈춤이 설정되어있다면 음성으로 알려준다
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool CheckLiderStop()
|
||||
{
|
||||
|
||||
if (PUB.AGV.system1.stop_by_front_detect == true)
|
||||
{
|
||||
var tsSpeak = DateTime.Now - LastSpeakTime;
|
||||
if (tsSpeak.TotalSeconds >= PUB.setting.alarmSoundTerm)
|
||||
{
|
||||
PUB.Speak(Lang.전방에물체가감지되었습니다);
|
||||
LastSpeakTime = DateTime.Now;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 설정된 목적지까지 이동을 완료 한 후 True를 반환합니다.
|
||||
/// 목적지 : PUB._virtualAGV.TargetNode
|
||||
|
||||
@@ -714,6 +714,30 @@ namespace Project
|
||||
}
|
||||
else UpdateStatusMessage(String.Format("상차 이동 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.LOADER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("로더 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.LOADER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("로더 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.UNLOADER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("언로더 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.UNLOADER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("언로더 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.CLEANER_IN)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("클리너 진입 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.CLEANER_OUT)
|
||||
{
|
||||
UpdateStatusMessage(String.Format("클리너 배출 중 ({0})", PUB.Result.TargetPos), Color.Lime, Color.Black);
|
||||
}
|
||||
else if (PUB.sm.RunStep == ERunStep.GOCHARGE)
|
||||
{
|
||||
if (PUB.Result.result_message.isEmpty() == true)
|
||||
|
||||
@@ -78,7 +78,12 @@ namespace Project.StateMachine
|
||||
/// </summary>
|
||||
BUFFER_IN,
|
||||
|
||||
|
||||
LOADER_IN,
|
||||
LOADER_OUT,
|
||||
UNLOADER_IN,
|
||||
UNLOADER_OUT,
|
||||
CLEANER_IN,
|
||||
CLEANER_OUT,
|
||||
|
||||
/// <summary>
|
||||
/// 목적지로 이동합니다
|
||||
@@ -93,7 +98,7 @@ namespace Project.StateMachine
|
||||
/// <summary>
|
||||
/// 후진방향으로 마크스탑진행
|
||||
/// </summary>
|
||||
MARKSTROPB,
|
||||
MARKSTOPB,
|
||||
|
||||
/// <summary>
|
||||
/// 에러발생
|
||||
|
||||
Reference in New Issue
Block a user