Compare commits
2 Commits
main
...
CellRecevi
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f82f7256b | |||
| 9ce42d24d7 |
@ -26,7 +26,7 @@ namespace AuroraCellTracker
|
|||||||
public class CellTracker : Device
|
public class CellTracker : Device
|
||||||
{
|
{
|
||||||
Logger _Logger = new Logger("CellTracker");
|
Logger _Logger = new Logger("CellTracker");
|
||||||
public ICellTracker _CellTracker;
|
ICellTracker _CellTracker;
|
||||||
public CellTrackerConfig _CellTrackerConfig { get; set; }
|
public CellTrackerConfig _CellTrackerConfig { get; set; }
|
||||||
|
|
||||||
private ICellTracker[] _MultiCellTrackerObj = new ICellTracker[4];
|
private ICellTracker[] _MultiCellTrackerObj = new ICellTracker[4];
|
||||||
|
|||||||
@ -149,8 +149,6 @@ namespace AuroraCellTracker.DaekhonCoporation
|
|||||||
{
|
{
|
||||||
string lotId = "", cellId = "";
|
string lotId = "", cellId = "";
|
||||||
|
|
||||||
bool gotNew = false;
|
|
||||||
|
|
||||||
if (selectedMode == eMode.Queue) {
|
if (selectedMode == eMode.Queue) {
|
||||||
if (null != dllSocketCtrl) {
|
if (null != dllSocketCtrl) {
|
||||||
string str = dllSocketCtrl.DllSocket_GetReceiveMessageInQueue(true, true);
|
string str = dllSocketCtrl.DllSocket_GetReceiveMessageInQueue(true, true);
|
||||||
@ -160,7 +158,6 @@ namespace AuroraCellTracker.DaekhonCoporation
|
|||||||
|
|
||||||
CalcCellInfo(str, out lotId, out cellId);
|
CalcCellInfo(str, out lotId, out cellId);
|
||||||
SetCellInfo(lotId, cellId);
|
SetCellInfo(lotId, cellId);
|
||||||
gotNew = true;
|
|
||||||
} else
|
} else
|
||||||
CellInfoStrings.ReceiveStrInQueue = "Receive Length is 0";
|
CellInfoStrings.ReceiveStrInQueue = "Receive Length is 0";
|
||||||
} else
|
} else
|
||||||
@ -170,32 +167,26 @@ namespace AuroraCellTracker.DaekhonCoporation
|
|||||||
} else if (selectedMode == eMode.Callback) {
|
} else if (selectedMode == eMode.Callback) {
|
||||||
// Callback 방식의 경우, 자체 ConcurrentQueue에서 Deque해서 가져와야 함
|
// Callback 방식의 경우, 자체 ConcurrentQueue에서 Deque해서 가져와야 함
|
||||||
CellInfoStr info;
|
CellInfoStr info;
|
||||||
|
|
||||||
if (CellInfoQueue.TryDequeue(out info)) {
|
if (CellInfoQueue.TryDequeue(out info)) {
|
||||||
SetCellInfo(info.LotID, info.CellID);
|
SetCellInfo(info.LotID, info.CellID);
|
||||||
gotNew = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue 방식인데 Cell Tracker에서 메세지가 안 왔거나,
|
// Queue 방식인데 Cell Tracker에서 메세지가 안 왔거나, Callback 방식인데 Cell Tracker API 함수가 Callback 안 된 경우(ex : ECS 오프라인 모드),
|
||||||
// Callback 방식인데 실제 수신이 없거나(또는 같은 값이 연속으로 들어오는 경우),
|
|
||||||
// Lot ID/Cell ID를 ES 지정사양에 맞추어 생성
|
// Lot ID/Cell ID를 ES 지정사양에 맞추어 생성
|
||||||
if (!gotNew || (OldLotId == CellInfoStrings.LotID && OldCellId == CellInfoStrings.CellID)) {
|
if (OldLotId == CellInfoStrings.LotID && OldCellId == CellInfoStrings.CellID) {
|
||||||
CalcCellInfo("", out lotId, out cellId);
|
CalcCellInfo("", out lotId, out cellId);
|
||||||
AddCellInfo(lotId, cellId);
|
AddCellInfo(lotId, cellId);
|
||||||
|
|
||||||
CellInfoStr info;
|
CellInfoStr info;
|
||||||
if (CellInfoQueue.TryDequeue(out info)) {
|
if (CellInfoQueue.TryDequeue(out info))
|
||||||
|
{
|
||||||
SetCellInfo(info.LotID, info.CellID);
|
SetCellInfo(info.LotID, info.CellID);
|
||||||
} else {
|
|
||||||
// 새로운 값이 안들어와도 일단 보여줌
|
|
||||||
SetCellInfo(lotId, cellId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OldLotId = CellInfoStrings.LotID;
|
OldLotId = CellInfoStrings.LotID;
|
||||||
OldCellId = CellInfoStrings.CellID;
|
OldCellId = CellInfoStrings.CellID;
|
||||||
|
|
||||||
_Logger.I($"Received CellInfo >> count({CellInfoQueue.Count})");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendData(string str, bool isSendToUpperSystem = false)
|
public void SendData(string str, bool isSendToUpperSystem = false)
|
||||||
|
|||||||
@ -505,7 +505,7 @@ namespace AuroraIO.AJINEXTEK
|
|||||||
int err = (int)CAXD.AxdiReadInport(index, ref data);
|
int err = (int)CAXD.AxdiReadInport(index, ref data);
|
||||||
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
|
if (err != (int)AXT_FUNC_RESULT.AXT_RT_SUCCESS)
|
||||||
{
|
{
|
||||||
return false;
|
throw new Exception(string.Format("ERR_IO_FAIL_TO_GET_BIT;ERROR CODE:{0}", err));
|
||||||
}
|
}
|
||||||
return Convert.ToBoolean(data);
|
return Convert.ToBoolean(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace AuroraLBAD.Service
|
namespace AuroraLBAD.Service
|
||||||
{
|
{
|
||||||
@ -130,9 +129,6 @@ namespace AuroraLBAD.Service
|
|||||||
|
|
||||||
public bool SendReadyStatus(eRequestData data)
|
public bool SendReadyStatus(eRequestData data)
|
||||||
{
|
{
|
||||||
if (ApplicationExt.IsSimulation)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
//int requestData = 1001;
|
//int requestData = 1001;
|
||||||
Log.I($"StreamLight {MESSAGE_PC_LBAD_READY_STATUS} Request");
|
Log.I($"StreamLight {MESSAGE_PC_LBAD_READY_STATUS} Request");
|
||||||
@ -153,9 +149,6 @@ namespace AuroraLBAD.Service
|
|||||||
|
|
||||||
public bool SendCellInfo(string lotID, string cellID, int recipeNo, int modelID, int jigNo)
|
public bool SendCellInfo(string lotID, string cellID, int recipeNo, int modelID, int jigNo)
|
||||||
{
|
{
|
||||||
if (ApplicationExt.IsSimulation)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
byte[] arrCellinfo = null;
|
byte[] arrCellinfo = null;
|
||||||
int sendresult = MakeInfoData(lotID, cellID, recipeNo, modelID, jigNo, out arrCellinfo);
|
int sendresult = MakeInfoData(lotID, cellID, recipeNo, modelID, jigNo, out arrCellinfo);
|
||||||
@ -197,9 +190,6 @@ namespace AuroraLBAD.Service
|
|||||||
}
|
}
|
||||||
public bool SendWeldingStop()
|
public bool SendWeldingStop()
|
||||||
{
|
{
|
||||||
if (ApplicationExt.IsSimulation)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
//Welding Stop On
|
//Welding Stop On
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
//int requestData = 5000;
|
//int requestData = 5000;
|
||||||
|
|||||||
@ -143,10 +143,6 @@
|
|||||||
<Project>{E7E68E54-43D2-4413-9510-43D25F13CD80}</Project>
|
<Project>{E7E68E54-43D2-4413-9510-43D25F13CD80}</Project>
|
||||||
<Name>AuroraLaser</Name>
|
<Name>AuroraLaser</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\AuroraPLC\AuroraPLC.csproj">
|
|
||||||
<Project>{1A47B1F3-5BDE-41DF-8F4D-25298AD4F6DE}</Project>
|
|
||||||
<Name>AuroraPLC</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@ -22,7 +22,7 @@ namespace AuroraLaserScanner
|
|||||||
public ScannerConfig Config { get; set; }
|
public ScannerConfig Config { get; set; }
|
||||||
|
|
||||||
//public ScannerObj _scannerObj { get; set; }
|
//public ScannerObj _scannerObj { get; set; }
|
||||||
protected ScannerObj _scannerObj { get; set; }
|
private ScannerObj _scannerObj { get; set; }
|
||||||
|
|
||||||
public Scanner(string deviceId)
|
public Scanner(string deviceId)
|
||||||
{
|
{
|
||||||
@ -37,9 +37,9 @@ namespace AuroraLaserScanner
|
|||||||
Config = config as ScannerConfig;
|
Config = config as ScannerConfig;
|
||||||
if (IsSimul) {
|
if (IsSimul) {
|
||||||
_scannerObj = new ScannerSimul();
|
_scannerObj = new ScannerSimul();
|
||||||
//return E1.OK;
|
return E1.OK;
|
||||||
}
|
}
|
||||||
else if (Config.Type == eRTCType.RTC5) {
|
if (Config.Type == eRTCType.RTC5) {
|
||||||
_scannerObj = new ScannerRTC5();
|
_scannerObj = new ScannerRTC5();
|
||||||
} else if (Config.Type == eRTCType.RTC6) {
|
} else if (Config.Type == eRTCType.RTC6) {
|
||||||
_scannerObj = new ScannerRTC6();
|
_scannerObj = new ScannerRTC6();
|
||||||
|
|||||||
@ -91,7 +91,7 @@ namespace AuroraLaserScanner
|
|||||||
RealImage = 0,
|
RealImage = 0,
|
||||||
VirtualImage = 1
|
VirtualImage = 1
|
||||||
}
|
}
|
||||||
public enum eListNo { NONE = 0, LIST1 = 1, LIST2 = 2 };
|
public enum eListNo { LIST1 = 1, LIST2 = 2, };
|
||||||
|
|
||||||
public enum eAutoControlParameter
|
public enum eAutoControlParameter
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
using Aurora.Api;
|
using Aurora.Api;
|
||||||
using Hermes;
|
using Hermes;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
using static AuroraPLC.PLCBase;
|
|
||||||
|
|
||||||
namespace AuroraLaserScanner
|
namespace AuroraLaserScanner
|
||||||
{
|
{
|
||||||
public class ScannerSimul : ScannerObj
|
internal class ScannerSimul : ScannerObj
|
||||||
{
|
{
|
||||||
static new readonly Logger Log = new Logger("Scanner");
|
static new readonly Logger Log = new Logger("Scanner");
|
||||||
|
|
||||||
@ -18,154 +14,7 @@ namespace AuroraLaserScanner
|
|||||||
//set_trigger 관련 추가, get_waveform 에서 얻어올 포인터 추가, 최대 크기로 설정 (2^20 = 1,048,576)
|
//set_trigger 관련 추가, get_waveform 에서 얻어올 포인터 추가, 최대 크기로 설정 (2^20 = 1,048,576)
|
||||||
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1048576)] int[] m_getWaveformPtr = new int[1048576];
|
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1048576)] int[] m_getWaveformPtr = new int[1048576];
|
||||||
private bool _ModulationMode;
|
private bool _ModulationMode;
|
||||||
private ScannerConfig _config;
|
|
||||||
|
|
||||||
// -----------------------------
|
|
||||||
// MOTF Simulation state
|
|
||||||
// -----------------------------
|
|
||||||
public Func<int, ePLCDevice, bool, (int err, bool data)> PLCReadBit;
|
|
||||||
public Func<int, ePLCDevice, bool, (int err, short data)> PLCReadWord;
|
|
||||||
public Func<int, ePLCDevice, bool, (int err, int data)> PLCReadDWord;
|
|
||||||
public Func<double> PLCGetAbsDeg;
|
|
||||||
|
|
||||||
private const int PLC_CURRENT_POS_1_ADDR = 4;
|
|
||||||
|
|
||||||
public Stopwatch sw = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
// encoder가 반환할 값
|
|
||||||
public volatile int _simEncXCount = 0; //랩핑 각도(0~360
|
|
||||||
public volatile int _simEncYCount = 0; //누적 각도
|
|
||||||
|
|
||||||
public volatile bool LastWaitMissedRange = false;
|
|
||||||
|
|
||||||
private const int RotaryJigCount = 16;
|
|
||||||
private const double JigPerMsec = 300;
|
|
||||||
private const double DegreePerRev = 360.0;
|
|
||||||
private const double OneCycleMsec = JigPerMsec * RotaryJigCount;
|
|
||||||
|
|
||||||
// 누적각을 scanner 내부에서 유지
|
|
||||||
public double _angleAbsDeg = 0.0;
|
|
||||||
private bool _listClosed = false;
|
|
||||||
private bool _list1Busy = false;
|
|
||||||
private bool _list2Busy = false;
|
|
||||||
private eListNo _currentExecutingList = eListNo.NONE;
|
|
||||||
private bool _autoChangeRequested = false;
|
|
||||||
|
|
||||||
private long _listStartMs = 0; // ← 이게 executionStartTime 역할
|
|
||||||
|
|
||||||
private const int MinListTimeMs = 30; // 너무 빠른 완료 방지
|
|
||||||
private const int MaxListTimeMs = 800; // 너무 느린 완료 방지
|
|
||||||
private int SimulatedListTimeMs = 250; // 리스트 실행 시간
|
|
||||||
|
|
||||||
private const double RecommendWindowDeg = 45.0;
|
|
||||||
private const double RecommendUseRatio = 0.35; // 45도 중 실제 마킹이 차지하는 비율(가볍게)
|
|
||||||
|
|
||||||
public void EquipmentSimulator()
|
|
||||||
{
|
|
||||||
PullEncoderFromPlcOnce();
|
|
||||||
UpdateListExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int DegToCount(double deg)
|
|
||||||
{
|
|
||||||
double c = deg * _config.MarkingOnTheFlyEncoderResolutionRotate / DegreePerRev;
|
|
||||||
return (int)System.Math.Round(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int DegToCountAbs(double absDeg)
|
|
||||||
{
|
|
||||||
double c = absDeg * _config.MarkingOnTheFlyEncoderResolutionRotate / DegreePerRev;
|
|
||||||
long lc = (long)System.Math.Round(c);
|
|
||||||
return unchecked((int)lc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateListExecution()
|
|
||||||
{
|
|
||||||
if (_currentExecutingList == eListNo.NONE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
long now = sw.ElapsedMilliseconds;
|
|
||||||
long elapsed = now - _listStartMs;
|
|
||||||
|
|
||||||
int doneTime = GetEffectiveListTimeMs();
|
|
||||||
|
|
||||||
// 최소 현실 가드: elapsed가 음수인 경우 방지
|
|
||||||
if (elapsed < 0) {
|
|
||||||
_listStartMs = now;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elapsed >= doneTime) {
|
|
||||||
// 현재 리스트 실행 완료
|
|
||||||
if (_currentExecutingList == eListNo.LIST1)
|
|
||||||
_list1Busy = false;
|
|
||||||
else
|
|
||||||
_list2Busy = false;
|
|
||||||
|
|
||||||
if (_autoChangeRequested) {
|
|
||||||
// 반대 리스트 자동 실행
|
|
||||||
_currentExecutingList =
|
|
||||||
(_currentExecutingList == eListNo.LIST1) ? eListNo.LIST2 : eListNo.LIST1;
|
|
||||||
|
|
||||||
if (_currentExecutingList == eListNo.LIST1) {
|
|
||||||
_list1Busy = true;
|
|
||||||
_list2Busy = false;
|
|
||||||
} else {
|
|
||||||
_list2Busy = true;
|
|
||||||
_list1Busy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_listStartMs = now;
|
|
||||||
_autoChangeRequested = false;
|
|
||||||
} else {
|
|
||||||
_currentExecutingList = eListNo.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private int GetEffectiveListTimeMs()
|
|
||||||
{
|
|
||||||
int t = SimulatedListTimeMs;
|
|
||||||
|
|
||||||
// 4800msec / 360 * 45 * ratio
|
|
||||||
int recommendedListRunTime = (int)Math.Round((OneCycleMsec / DegreePerRev) * RecommendWindowDeg * RecommendUseRatio);
|
|
||||||
|
|
||||||
// recommended가 너무 작거나 0이 되는 경우 방지
|
|
||||||
if (recommendedListRunTime < MinListTimeMs)
|
|
||||||
recommendedListRunTime = MinListTimeMs;
|
|
||||||
|
|
||||||
if (t < MinListTimeMs)
|
|
||||||
t = MinListTimeMs;
|
|
||||||
|
|
||||||
if (t > MaxListTimeMs)
|
|
||||||
t = MaxListTimeMs;
|
|
||||||
|
|
||||||
if (recommendedListRunTime > MaxListTimeMs)
|
|
||||||
recommendedListRunTime = MaxListTimeMs;
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
public void TrySyncAbsAngleToPlcNow()
|
|
||||||
{
|
|
||||||
_angleAbsDeg = PLCGetAbsDeg();
|
|
||||||
|
|
||||||
// mod 동기화도 같이
|
|
||||||
int modRaw = PLCReadDWord(PLC_CURRENT_POS_1_ADDR, ePLCDevice.W, false).data;
|
|
||||||
double modDeg = (modRaw / 100_000.0) % DegreePerRev;
|
|
||||||
if (modDeg < 0)
|
|
||||||
modDeg += DegreePerRev;
|
|
||||||
|
|
||||||
LastWaitMissedRange = false;
|
|
||||||
}
|
|
||||||
public void ResetSim()
|
|
||||||
{
|
|
||||||
_angleAbsDeg = 0.0;
|
|
||||||
|
|
||||||
_simEncXCount = 0;
|
|
||||||
_simEncYCount = 0;
|
|
||||||
|
|
||||||
StopExecution(); // 리스트 상태 리셋
|
|
||||||
LastWaitMissedRange = false;
|
|
||||||
}
|
|
||||||
public override uint Open()
|
public override uint Open()
|
||||||
{
|
{
|
||||||
IsOpenUnit = true;
|
IsOpenUnit = true;
|
||||||
@ -184,7 +33,6 @@ namespace AuroraLaserScanner
|
|||||||
CommandPosZ = 0;
|
CommandPosZ = 0;
|
||||||
|
|
||||||
_ModulationMode = config.Modulation;
|
_ModulationMode = config.Modulation;
|
||||||
_config = config;
|
|
||||||
|
|
||||||
return E1.OK;
|
return E1.OK;
|
||||||
}
|
}
|
||||||
@ -259,17 +107,12 @@ namespace AuroraLaserScanner
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void GetEncoder(out double encoderX, out double encoderY, bool rotateMode = false)
|
public override void GetEncoder(out double encoderX, out double encoderY, bool rotateMode = false)
|
||||||
{
|
{
|
||||||
int valueX = _simEncXCount;
|
// simulation 할때 값 반영 검토 필요
|
||||||
int valueY = _simEncYCount;
|
encoderX = 0;
|
||||||
|
encoderY = 0;
|
||||||
// 너가 쓰는 변환식 그대로
|
|
||||||
encoderX = (valueX * DegreePerRev) / _config.MarkingOnTheFlyEncoderResolutionRotate;
|
|
||||||
encoderY = _angleAbsDeg;
|
|
||||||
if (encoderY > -0.5 && encoderY < 0)
|
|
||||||
encoderY = 0; // 시뮬 안정화
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override uint GetMarkingInfo()
|
public override uint GetMarkingInfo()
|
||||||
@ -344,62 +187,9 @@ namespace AuroraLaserScanner
|
|||||||
|
|
||||||
public override void WaitForEncoderRotateRange(double minX, double maxX, double minY, double maxY)
|
public override void WaitForEncoderRotateRange(double minX, double maxX, double minY, double maxY)
|
||||||
{
|
{
|
||||||
LastWaitMissedRange = false;
|
// simulation 할때 값 반영 검토 필요
|
||||||
|
|
||||||
long t0 = sw.ElapsedMilliseconds;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// 블로킹 대기 중에도 PLC에서 최신값을 직접 당겨온다
|
|
||||||
PullEncoderFromPlcOnce();
|
|
||||||
|
|
||||||
// GetEncoder는 _simEncYCount를 deg로 바꿔줄 것
|
|
||||||
GetEncoder(out _, out double curY, true);
|
|
||||||
|
|
||||||
// 정상 진입
|
|
||||||
if (curY >= minY && curY <= maxY)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 최소 현실 가드: 구간을 지나쳤으면 TIMEOUT까지 끌지 말고 즉시 종료
|
|
||||||
// (실장에서도 "놓치면" 의미 없고 다음 로직이 꼬임)
|
|
||||||
if (curY > maxY) {
|
|
||||||
LastWaitMissedRange = true;
|
|
||||||
Log.W($"[SIM] WaitForEncoderRotateRange MISSED. curY={curY:F3}, range=[{minY:F3}..{maxY:F3}]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 최후 안전장치
|
|
||||||
if (sw.ElapsedMilliseconds - t0 > 5000) {
|
|
||||||
LastWaitMissedRange = true;
|
|
||||||
Log.W($"[SIM] WaitForEncoderRotateRange TIMEOUT. curY={curY:F3}, range=[{minY:F3}..{maxY:F3}]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private void PullEncoderFromPlcOnce()
|
|
||||||
{
|
|
||||||
// 방어: delegate 미설정이면 아무 것도 못함
|
|
||||||
if (PLCReadDWord == null || _config == null || _config.MarkingOnTheFlyEncoderResolutionRotate == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 1) 랩핑각 (0~360)
|
|
||||||
int modRaw = PLCReadDWord(PLC_CURRENT_POS_1_ADDR, ePLCDevice.W, true).data;
|
|
||||||
double angleModDeg = (modRaw / 100_000.0) % 360.0;
|
|
||||||
if (angleModDeg < 0)
|
|
||||||
angleModDeg += 360.0;
|
|
||||||
|
|
||||||
// 2) 누적각 (계속 증가)
|
|
||||||
//int absRaw = PLCReadDWord(PLC_CURRENT_POS_ABS_ADDR, ePLCDevice.W, true).data;
|
|
||||||
//double angleAbsDeg = absRaw / 100_000.0;
|
|
||||||
if (PLCGetAbsDeg != null) {
|
|
||||||
_angleAbsDeg = PLCGetAbsDeg();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) count로 변환 (n_get_encoder가 반환한다고 가정하는 값)
|
|
||||||
_simEncXCount = DegToCount(angleModDeg);
|
|
||||||
_simEncYCount = DegToCountAbs(_angleAbsDeg);
|
|
||||||
}
|
|
||||||
public override void SetFlyX(double encoderResolution)
|
public override void SetFlyX(double encoderResolution)
|
||||||
{
|
{
|
||||||
// simulation 할때 값 반영 검토 필요
|
// simulation 할때 값 반영 검토 필요
|
||||||
@ -493,34 +283,16 @@ namespace AuroraLaserScanner
|
|||||||
}
|
}
|
||||||
public override uint LoadList(eListNo no)
|
public override uint LoadList(eListNo no)
|
||||||
{
|
{
|
||||||
bool busy = (no == eListNo.LIST1) ? _list1Busy : _list2Busy;
|
// simulation 할때 값 반영 검토 필요
|
||||||
|
return 0;
|
||||||
if (busy)
|
|
||||||
return 0; // 실행 중 → Load 불가
|
|
||||||
|
|
||||||
return (uint)no; // Load 가능
|
|
||||||
}
|
}
|
||||||
public override void SetEndList()
|
public override void SetEndList()
|
||||||
{
|
{
|
||||||
_listClosed = true;
|
// simulation 할때 값 반영 검토 필요
|
||||||
}
|
}
|
||||||
public override void ExecuteList(eListNo no)
|
public override void ExecuteList(eListNo no)
|
||||||
{
|
{
|
||||||
if (!_listClosed)
|
// simulation 할때 값 반영 검토 필요
|
||||||
Log.W("ExecuteList called without SetEndList");
|
|
||||||
_listClosed = false; // 실행 시작하면서 다시 열림 상태로
|
|
||||||
|
|
||||||
_currentExecutingList = no;
|
|
||||||
|
|
||||||
if (no == eListNo.LIST1) {
|
|
||||||
_list1Busy = true;
|
|
||||||
_list2Busy = false;
|
|
||||||
} else {
|
|
||||||
_list2Busy = true;
|
|
||||||
_list1Busy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_listStartMs = sw.ElapsedMilliseconds;
|
|
||||||
}
|
}
|
||||||
public override void StartLoop()
|
public override void StartLoop()
|
||||||
{
|
{
|
||||||
@ -532,28 +304,16 @@ namespace AuroraLaserScanner
|
|||||||
}
|
}
|
||||||
public override void AutoChange()
|
public override void AutoChange()
|
||||||
{
|
{
|
||||||
if (_currentExecutingList == eListNo.NONE)
|
// simulation 할때 값 반영 검토 필요
|
||||||
return;
|
|
||||||
|
|
||||||
_autoChangeRequested = true;
|
|
||||||
}
|
}
|
||||||
public override bool GetBusyStatus()
|
public override bool GetBusyStatus()
|
||||||
{
|
{
|
||||||
return _list1Busy || _list2Busy || _currentExecutingList != eListNo.NONE;
|
// simulation 할때 값 반영 검토 필요
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
public override void StopExecution()
|
public override void StopExecution()
|
||||||
{
|
{
|
||||||
_list1Busy = false;
|
// simulation 할때 값 반영 검토 필요
|
||||||
_list2Busy = false;
|
|
||||||
_currentExecutingList = eListNo.NONE;
|
|
||||||
_autoChangeRequested = false;
|
|
||||||
_listStartMs = 0;
|
|
||||||
_listClosed = false;
|
|
||||||
|
|
||||||
_angleAbsDeg = 0.0;
|
|
||||||
|
|
||||||
_simEncXCount = 0;
|
|
||||||
_simEncYCount = 0;
|
|
||||||
}
|
}
|
||||||
public override uint GetRTCVersion()
|
public override uint GetRTCVersion()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,6 +51,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
|
|
||||||
public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "[SeqAutoRunACWH52A] Check Scanner List Complete";
|
public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "[SeqAutoRunACWH52A] Check Scanner List Complete";
|
||||||
|
|
||||||
|
const string SEQ_CHECK_CAN_EXIST = "[SeqAutoRunACWH52A] Check Can Exist";
|
||||||
const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunACWH52A] Ready ScannerList";
|
const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunACWH52A] Ready ScannerList";
|
||||||
|
|
||||||
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunACWH52A] Set Sequence Param (UploadWeldingList Seq)";
|
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunACWH52A] Set Sequence Param (UploadWeldingList Seq)";
|
||||||
@ -69,6 +70,8 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunACWH52A] Process (ReportCellResult Seq)";
|
const string SEQ_DO_ID_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunACWH52A] Process (ReportCellResult Seq)";
|
||||||
const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunACWH52A] Get Sequence Result (ReportCellResult Seq)";
|
const string SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ = "[SeqAutoRunACWH52A] Get Sequence Result (ReportCellResult Seq)";
|
||||||
|
|
||||||
|
const string SEQ_APD_DATA_SAVE = "[SeqAutoRunACWH52A] APD Data Save";
|
||||||
|
|
||||||
//const string SEQ_REPORT_CELLINFO_TO_PLC = "[SeqAutoRunACWH52A] ReportCellInfoToPLC";
|
//const string SEQ_REPORT_CELLINFO_TO_PLC = "[SeqAutoRunACWH52A] ReportCellInfoToPLC";
|
||||||
const string SEQ_CHECK_CYCLE_STOP = "[SeqAutoRunACWH52A] Check Cycle Stop";
|
const string SEQ_CHECK_CYCLE_STOP = "[SeqAutoRunACWH52A] Check Cycle Stop";
|
||||||
const string SEQ_CHECK_CAN_WELDED = "[SeqAutoRunACWH52A] Check Can Welded";
|
const string SEQ_CHECK_CAN_WELDED = "[SeqAutoRunACWH52A] Check Can Welded";
|
||||||
@ -105,7 +108,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
|
|
||||||
private IRecipeManager _RecipeManager;
|
private IRecipeManager _RecipeManager;
|
||||||
|
|
||||||
private eListNo _WeldingScannerListNo;
|
private eListNo _WeldingScannerListNo = eListNo.LIST1;
|
||||||
|
|
||||||
private List<IDrawObject> _SelectedDrawObjectList;
|
private List<IDrawObject> _SelectedDrawObjectList;
|
||||||
|
|
||||||
@ -139,12 +142,13 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
private double _RotaryEncoderOffset = 0;
|
private double _RotaryEncoderOffset = 0;
|
||||||
private int _WeldingJigNo = -1;
|
private int _WeldingJigNo = -1;
|
||||||
private int _WeldingCount = 0;
|
private int _WeldingCount = 0;
|
||||||
private int _RotaryJigCount = 16;
|
private const int _RotaryJigCount = 16;
|
||||||
|
|
||||||
private double _WeldingStartAngle;
|
private double _WeldingStartAngle;
|
||||||
|
|
||||||
private bool isTheFirstListWrite;
|
private bool isTheFirstListWrite = false;
|
||||||
private bool isTheSecondListWrite;
|
private bool isTheSecondListWrite = false;
|
||||||
|
|
||||||
private bool isTheFirstListExecute;
|
private bool isTheFirstListExecute;
|
||||||
private int _RecipeNo;
|
private int _RecipeNo;
|
||||||
|
|
||||||
@ -174,7 +178,8 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
|
|
||||||
sb.AddAction(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete);
|
sb.AddAction(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete);
|
||||||
sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete);
|
sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete);
|
||||||
sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList);
|
sb.AddDecision(SEQ_CHECK_CAN_EXIST, CheckCanExist);
|
||||||
|
sb.AddAction(SEQ_READY_SCANNER_LIST, ReadyScannerList);
|
||||||
|
|
||||||
sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams);
|
sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams);
|
||||||
sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList());
|
sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList());
|
||||||
@ -195,20 +200,23 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
sb.AddDecision(SEQ_CHECK_CAN_WELDED, CheckCanWelded);
|
sb.AddDecision(SEQ_CHECK_CAN_WELDED, CheckCanWelded);
|
||||||
|
|
||||||
sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함.
|
sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함.
|
||||||
|
|
||||||
|
//sb.AddAction(SEQ_APD_DATA_SAVE, SaveCellAPDData); // 용접 완료 시 Cell의 정보를 저장함
|
||||||
sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write
|
sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write
|
||||||
sb.AddAction(SEQ_INIT_CONDITION_ERROR, InitConditionError);
|
sb.AddAction(SEQ_INIT_CONDITION_ERROR, InitConditionError);
|
||||||
sb.AddAction(SEQ_COMPLETE, Complete);
|
sb.AddAction(SEQ_COMPLETE, Complete);
|
||||||
|
|
||||||
sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE]
|
sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_FORK_ENCODER_MONITOR] > sb[SEQ_CHECK_LOAD_COMPLETE]
|
||||||
|
> sb[SEQ_CHECK_CAN_EXIST]
|
||||||
> sb[SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ]
|
> sb[SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ] > sb[SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ]
|
||||||
> sb[SEQ_CHECK_SCANNER_LIST_COMPLETE] > sb[SEQ_READY_SCANNER_LIST]
|
> sb[SEQ_READY_SCANNER_LIST]
|
||||||
> sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ]
|
> sb[SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ] > sb[SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ]
|
||||||
> sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_CAN_WELDED]
|
> sb[SEQ_EXECUTE_WELDING] > sb[SEQ_REQUEST_UNLOAD_CELL] > sb[SEQ_CHECK_SCANNER_LIST_COMPLETE]> sb[SEQ_CHECK_CAN_WELDED]
|
||||||
> sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ]
|
> sb[SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ]
|
||||||
> sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_CHECK_CYCLE_STOP]
|
> sb[SEQ_CHECK_CYCLE_STOP]
|
||||||
> sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]);
|
> sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_JOIN_ENCODER_MONITOR] > sb[SEQ_COMPLETE]);
|
||||||
|
|
||||||
sb.Flows(sb[SEQ_READY_SCANNER_LIST] > sb[SEQ_EXECUTE_WELDING]);
|
sb.Flows(sb[SEQ_CHECK_CAN_EXIST] > sb[SEQ_EXECUTE_WELDING]);
|
||||||
|
|
||||||
sb.Flows(sb[SEQ_CHECK_CAN_WELDED] > sb[SEQ_CHECK_CYCLE_STOP]); // 용접을 하지 않은 Cell은 상위보고 하지 않는다.
|
sb.Flows(sb[SEQ_CHECK_CAN_WELDED] > sb[SEQ_CHECK_CYCLE_STOP]); // 용접을 하지 않은 Cell은 상위보고 하지 않는다.
|
||||||
sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]);
|
sb.Flows(sb[SEQ_CHECK_CYCLE_STOP] > sb[SEQ_CHECK_LOAD_COMPLETE]);
|
||||||
@ -269,6 +277,8 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
_RecipeManager = Application.Current.AuroraEnv().RecipeManager;
|
_RecipeManager = Application.Current.AuroraEnv().RecipeManager;
|
||||||
_SystemParameter = context.GetSetting<SystemParameter>(CommonSettingIds.SystemParameter);
|
_SystemParameter = context.GetSetting<SystemParameter>(CommonSettingIds.SystemParameter);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
InitDev(context);
|
InitDev(context);
|
||||||
if (!CheckDeviceReady(context))
|
if (!CheckDeviceReady(context))
|
||||||
{ //Check Device
|
{ //Check Device
|
||||||
@ -300,7 +310,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
var mainPage = WeldingRecipeManager.GetWeldingPage();
|
var mainPage = WeldingRecipeManager.GetWeldingPage();
|
||||||
_ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlAutoPage;
|
_ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlAutoPage;
|
||||||
|
|
||||||
_WeldingScannerListNo = eListNo.LIST1;
|
//_WeldingScannerListNo = eListNo.LIST1;
|
||||||
|
|
||||||
_CellMeasureCenterOffsetX = 0.0;
|
_CellMeasureCenterOffsetX = 0.0;
|
||||||
_CellMeasureCenterOffsetY = 0.0;
|
_CellMeasureCenterOffsetY = 0.0;
|
||||||
@ -384,118 +394,118 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
//InitAutoRunBit();
|
//InitAutoRunBit();
|
||||||
// LBAD Initialize
|
// LBAD Initialize
|
||||||
// LBAD 는 server 이기 때문에, 만약 끊어졌으면 다시 접속이 필요함
|
// LBAD 는 server 이기 때문에, 만약 끊어졌으면 다시 접속이 필요함
|
||||||
if (_SystemParameter.BypassModeLBAD == false)
|
if (_SystemParameter.BypassModeLBAD == false)
|
||||||
{
|
|
||||||
if (!_StreamLightLBAD._Client.IsActivated)
|
|
||||||
{
|
{
|
||||||
int ret = _StreamLightLBAD._Client.Activate();
|
if (!_StreamLightLBAD._Client.IsActivated)
|
||||||
Thread.Sleep(500);
|
|
||||||
if (ret != E1.OK)
|
|
||||||
{
|
{
|
||||||
Log.E($"StreamLightClient activate failed");
|
int ret = _StreamLightLBAD._Client.Activate();
|
||||||
return (int)InitErrorList.LBAD_CLIENT_ACTIVATE_FAILED;
|
Thread.Sleep(500);
|
||||||
|
if (ret != E1.OK)
|
||||||
|
{
|
||||||
|
Log.E($"StreamLightClient activate failed");
|
||||||
|
return (int)InitErrorList.LBAD_CLIENT_ACTIVATE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_StreamLightLBAD._Sub.IsActivated == false)
|
||||||
|
{
|
||||||
|
int ret = _StreamLightLBAD._Sub.Activate();
|
||||||
|
Thread.Sleep(500);
|
||||||
|
if (ret != E1.OK)
|
||||||
|
{
|
||||||
|
Log.E($"StreamLightSub activate failed");
|
||||||
|
return (int)InitErrorList.LBAD_SUB_ACTIVATE_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_StreamLightLBAD.Initialize();
|
||||||
|
if (_StreamLightLBAD.SendReadyStatus(eRequestData.Ready_On) == false)
|
||||||
|
{
|
||||||
|
Log.I(string.Format($"[LBAD Interface]CheckReadyStatus null"));
|
||||||
|
//return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_StreamLightLBAD._Sub.IsActivated == false)
|
// Laser Initialize
|
||||||
|
_Laser.PilotLaserOff();
|
||||||
|
_Laser.LaserOn();
|
||||||
|
Thread.Sleep(500);
|
||||||
|
if (!_Laser.GetLaserReady())
|
||||||
{
|
{
|
||||||
int ret = _StreamLightLBAD._Sub.Activate();
|
Log.E("ERROR Initialize Laser");
|
||||||
Thread.Sleep(500);
|
return (int)InitErrorList.LASER_INIT_ERROR;
|
||||||
if (ret != E1.OK)
|
|
||||||
{
|
|
||||||
Log.E($"StreamLightSub activate failed");
|
|
||||||
return (int)InitErrorList.LBAD_SUB_ACTIVATE_FAILED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_StreamLightLBAD.Initialize();
|
// Scanner Initialize
|
||||||
if (_StreamLightLBAD.SendReadyStatus(eRequestData.Ready_On) == false)
|
if (_Scanner.GetModulationMode())
|
||||||
{
|
{
|
||||||
Log.I(string.Format($"[LBAD Interface]CheckReadyStatus null"));
|
_ModulationMode = true;
|
||||||
//return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Laser Initialize
|
|
||||||
_Laser.PilotLaserOff();
|
|
||||||
_Laser.LaserOn();
|
|
||||||
Thread.Sleep(500);
|
|
||||||
if (!_Laser.GetLaserReady())
|
|
||||||
{
|
|
||||||
Log.E("ERROR Initialize Laser");
|
|
||||||
return (int)InitErrorList.LASER_INIT_ERROR;
|
|
||||||
}
|
|
||||||
// Scanner Initialize
|
|
||||||
if (_Scanner.GetModulationMode())
|
|
||||||
{
|
|
||||||
_ModulationMode = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ModulationMode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// PLC Initialize AutoRun Bit 최소화 작업 진행
|
|
||||||
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_STATUS).data == false) // AutoRun Bit가 OFF인 경우
|
|
||||||
{
|
|
||||||
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_REQ).data == false) // AutoRun Request 상태 체크
|
|
||||||
{
|
|
||||||
Log.E(string.Format("ERROR Initialize PLC, PLC Alarm ON")); // AutoRun Request와 AutoRun Bit 모두 OFF인 경우, PLC 측에서 Alarm 발생함.
|
|
||||||
return (int)InitErrorList.PLC_ALARM;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.E(string.Format("ERROR Initialize PLC, Bit Off PLC_AUTO_STATUS")); // AutoRun Request가 ON인데 AutoRun Bit 모두 OFF인 경우, PLC에서 AutoRun Bit를 켜지 않음.
|
_ModulationMode = false;
|
||||||
return (int)InitErrorList.PLC_AUTORUN_BIT_OFF;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Marking On The Flying Off
|
//// PLC Initialize AutoRun Bit 최소화 작업 진행
|
||||||
if (_Scanner.Config.UseMarkingOnTheFly == false)
|
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_STATUS).data == false) // AutoRun Bit가 OFF인 경우
|
||||||
{
|
{
|
||||||
Log.E("ERROR Config Setting : Scanner Marking on the fly (OFF)");
|
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_REQ).data == false) // AutoRun Request 상태 체크
|
||||||
return (int)InitErrorList.MOTF_OFF;
|
{
|
||||||
}
|
Log.E(string.Format("ERROR Initialize PLC, PLC Alarm ON")); // AutoRun Request와 AutoRun Bit 모두 OFF인 경우, PLC 측에서 Alarm 발생함.
|
||||||
|
return (int)InitErrorList.PLC_ALARM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.E(string.Format("ERROR Initialize PLC, Bit Off PLC_AUTO_STATUS")); // AutoRun Request가 ON인데 AutoRun Bit 모두 OFF인 경우, PLC에서 AutoRun Bit를 켜지 않음.
|
||||||
|
return (int)InitErrorList.PLC_AUTORUN_BIT_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MOTF Set Scanner List
|
// Marking On The Flying Off
|
||||||
_Scanner.SelectCorrectionTable(2);
|
if (_Scanner.Config.UseMarkingOnTheFly == false)
|
||||||
Log.I(string.Format("Normal, Select Laser Correction File"));
|
{
|
||||||
|
Log.E("ERROR Config Setting : Scanner Marking on the fly (OFF)");
|
||||||
|
return (int)InitErrorList.MOTF_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
// Aurora 내부에서 찾아야할 듯 함
|
// MOTF Set Scanner List
|
||||||
//UsePlcShotThemAll = Dao.SystemRecipe.PlcShotThemAll;
|
_Scanner.SelectCorrectionTable(2);
|
||||||
//UsePlcPositionCompensation = Dao.SystemRecipe.PlcPositionCompensationUse;
|
Log.I(string.Format("Normal, Select Laser Correction File"));
|
||||||
string[] strArr = Dao.SystemRecipe.WorkRecipeFile.Split('\\');
|
|
||||||
RecipeFileName = strArr[strArr.Length - 1];
|
|
||||||
|
|
||||||
_LastScannerParamNo = -1;
|
// Aurora 내부에서 찾아야할 듯 함
|
||||||
|
//UsePlcShotThemAll = Dao.SystemRecipe.PlcShotThemAll;
|
||||||
|
//UsePlcPositionCompensation = Dao.SystemRecipe.PlcPositionCompensationUse;
|
||||||
|
string[] strArr = Dao.SystemRecipe.WorkRecipeFile.Split('\\');
|
||||||
|
RecipeFileName = strArr[strArr.Length - 1];
|
||||||
|
|
||||||
// 트럼프 TruDisk를 쓰기 위해서는 SetFirstPulseKiller를 사용해야 함.
|
_LastScannerParamNo = -1;
|
||||||
|
|
||||||
// Rotary는 시작 트리거 미사용
|
// 트럼프 TruDisk를 쓰기 위해서는 SetFirstPulseKiller를 사용해야 함.
|
||||||
_Scanner.SetControlMode(0);
|
|
||||||
UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, "[AutoRun] 외부 시작 트리거 DISABLE");
|
|
||||||
|
|
||||||
#region MOTF Absolute Encoder 기준으로 초기화
|
// Rotary는 시작 트리거 미사용
|
||||||
// Set Rotate Center는 Ctrl명령, 처음 한번만 실행
|
_Scanner.SetControlMode(0);
|
||||||
_Scanner.SetRotateCenter(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY);
|
UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, "[AutoRun] 외부 시작 트리거 DISABLE");
|
||||||
|
|
||||||
_Scanner.InitFly2D(); // X, Y 엔코더 리셋
|
#region MOTF Absolute Encoder 기준으로 초기화
|
||||||
_EncoderOverflowCount = 0;
|
// Set Rotate Center는 Ctrl명령, 처음 한번만 실행
|
||||||
|
_Scanner.SetRotateCenter(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY);
|
||||||
|
|
||||||
// 현재 정지상태의 Rotary 엔코더 값을 읽어와서 저장
|
_Scanner.InitFly2D(); // X, Y 엔코더 리셋
|
||||||
_RotaryEncoderOffset = GetRotaryCurrentPosition(); // m_abwRotaryEncoderOffset의 범위는 0 이상 360 미만
|
_EncoderOverflowCount = 0;
|
||||||
|
|
||||||
InitRotaryOnTheFlyWeldingCount(_RotaryEncoderOffset, _RotaryJigCount, out _WeldingCount, out _WeldingJigNo);
|
// 현재 정지상태의 Rotary 엔코더 값을 읽어와서 저장
|
||||||
|
_RotaryEncoderOffset = GetRotaryCurrentPosition(); // m_abwRotaryEncoderOffset의 범위는 0 이상 360 미만
|
||||||
|
|
||||||
Log.I(string.Format($"ScannerUnit.InitRotaryOnTheFlyWeldingCount : m_abwRotaryEncoderOffset({_RotaryEncoderOffset}), weldingCount({_WeldingCount}), weldingJigNo({_WeldingJigNo}), rotaryJigCount({_RotaryJigCount})"));
|
InitRotaryOnTheFlyWeldingCount(_RotaryEncoderOffset, _RotaryJigCount, out _WeldingCount, out _WeldingJigNo);
|
||||||
|
|
||||||
|
Log.I(string.Format($"ScannerUnit.InitRotaryOnTheFlyWeldingCount : m_abwRotaryEncoderOffset({_RotaryEncoderOffset}), weldingCount({_WeldingCount}), weldingJigNo({_WeldingJigNo}), rotaryJigCount({_RotaryJigCount})"));
|
||||||
|
|
||||||
// 용접 완료 대기 스캐너 List 리셋
|
// 용접 완료 대기 스캐너 List 리셋
|
||||||
ResetInputScannerList();
|
//ResetInputScannerList();
|
||||||
WaitingScannerList.Reset();
|
//WaitingScannerList.Reset();
|
||||||
CompleteScannerList.Reset();
|
//CompleteScannerList.Reset();
|
||||||
|
|
||||||
isTheFirstListWrite = false; // 작업 시작 시 처음 2개의 List는 입력하고 시작한다
|
//isTheFirstListWrite = true; // 작업 시작 시 처음 2개의 List는 입력하고 시작한다
|
||||||
isTheSecondListWrite = false;
|
//isTheSecondListWrite = true;
|
||||||
isTheFirstListExecute = true; // 제일 첫 List는 ExecuteList 필요. 이후는 AutoChange
|
//isTheFirstListExecute = true; // 제일 첫 List는 ExecuteList 필요. 이후는 AutoChange
|
||||||
|
|
||||||
InitAutoRunBit(); // GetRotaryCurrentPosition() 호출 이후 AutoStatus True 변경
|
InitAutoRunBit(); // GetRotaryCurrentPosition() 호출 이후 AutoStatus True 변경
|
||||||
#endregion
|
#endregion
|
||||||
@ -567,7 +577,6 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false);
|
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false);
|
||||||
return SEQ_INIT_CONDITION_ERROR;
|
return SEQ_INIT_CONDITION_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status.EquipmentMode = eEquipmentMode.AUTO;
|
Status.EquipmentMode = eEquipmentMode.AUTO;
|
||||||
|
|
||||||
var startTime = DateTime.Now;
|
var startTime = DateTime.Now;
|
||||||
@ -590,6 +599,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
// List가 실행 중이라면(ex : 엔코더 대기 상태 등), 반환값은 0, LoadList 할 수 없는 상태(List 실행 중이거나, 엔코더 대기 상태)
|
// List가 실행 중이라면(ex : 엔코더 대기 상태 등), 반환값은 0, LoadList 할 수 없는 상태(List 실행 중이거나, 엔코더 대기 상태)
|
||||||
// LoadList가 0보다 크면 다음 시퀀스 진행해야 함
|
// LoadList가 0보다 크면 다음 시퀀스 진행해야 함
|
||||||
_InterfaceStartTime = DateTime.Now;
|
_InterfaceStartTime = DateTime.Now;
|
||||||
|
|
||||||
while (!context.Stopped)
|
while (!context.Stopped)
|
||||||
{
|
{
|
||||||
if (_Scanner.LoadList(_WeldingScannerListNo) > 0)
|
if (_Scanner.LoadList(_WeldingScannerListNo) > 0)
|
||||||
@ -618,7 +628,6 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
{
|
{
|
||||||
isTheFirstListWrite = false;
|
isTheFirstListWrite = false;
|
||||||
Log.I("Write the 1st scanner list");
|
Log.I("Write the 1st scanner list");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -626,7 +635,6 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
{
|
{
|
||||||
isTheSecondListWrite = false;
|
isTheSecondListWrite = false;
|
||||||
Log.I("Write the 2nd scanner list");
|
Log.I("Write the 2nd scanner list");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -656,13 +664,8 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
if (CompleteScannerList.CanExist)
|
if (CompleteScannerList.CanExist)
|
||||||
{
|
{
|
||||||
isWeled = true;
|
isWeled = true;
|
||||||
#region 용접 시간, 엔코더 측정/기록
|
|
||||||
//_WeldInterval = DateTime.Now - _WeldEndTime;
|
|
||||||
//_WeldEndTime = DateTime.Now;
|
|
||||||
//double elapsedTime = _Scanner.GetTime();
|
|
||||||
//_WeldingSpanTime = TimeSpan.FromSeconds(elapsedTime); // Encoder 대기 넘어간 후의, 실제 스캐너 리스트 실행 시간
|
|
||||||
//_WeldingStartTime = _WeldEndTime.Subtract(_WeldingSpanTime);
|
|
||||||
|
|
||||||
|
#region 용접 시간, 엔코더 측정/기록
|
||||||
double elaspedTime = _Scanner.GetTime();
|
double elaspedTime = _Scanner.GetTime();
|
||||||
|
|
||||||
if (CompleteScannerList.WeldComplete)
|
if (CompleteScannerList.WeldComplete)
|
||||||
@ -684,16 +687,9 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
}
|
}
|
||||||
UpdateProductCount(context);
|
UpdateProductCount(context);
|
||||||
UpdateProductInfoForView();
|
UpdateProductInfoForView();
|
||||||
SaveCellAPD();
|
SaveCellAPDData();
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (_SystemParameter.BypassModeLBAD == false) {
|
|
||||||
// if (_StreamLightLBAD.SendWeldingStop() == false) {
|
|
||||||
// Log.I(string.Format($"[LBAD Interface]SendWeldingStop null"));
|
|
||||||
// //return null;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_WELDING_TIME;" + _WeldingSpanTime.TotalMilliseconds);
|
UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_WELDING_TIME;" + _WeldingSpanTime.TotalMilliseconds);
|
||||||
UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_PRODUCT_COUNT;" + _WeldEndTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_PRODUCT_COUNT;" + _WeldEndTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
|
||||||
@ -714,6 +710,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
_Scanner.SaveRecord(DataFilePath);
|
_Scanner.SaveRecord(DataFilePath);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -745,7 +742,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ReadyScannerList(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
private string CheckCanExist(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
||||||
{
|
{
|
||||||
Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST);
|
Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST);
|
||||||
|
|
||||||
@ -776,23 +773,36 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
|
|
||||||
// 3개임으로 3으로 작성
|
// 3개임으로 3으로 작성
|
||||||
#region List 입력(용접 좌표 입력)
|
#region List 입력(용접 좌표 입력)
|
||||||
if (_WeldingJigNo == _RotaryJigCount)
|
//if (_WeldingJigNo == _RotaryJigCount)
|
||||||
_WeldingJigNo = 1;
|
// _WeldingJigNo = 1;
|
||||||
else
|
//else
|
||||||
_WeldingJigNo++;
|
// _WeldingJigNo++;
|
||||||
|
|
||||||
bool canExist; // 지그 용접 수행 여부 확인
|
Log.I($"Welding Jig No : {_WeldingJigNo}");
|
||||||
|
|
||||||
if (UsePlcShotThemAll)
|
(bool exist,int targetjigNo) canExist; // 지그 용접 수행 여부 확인
|
||||||
{
|
|
||||||
canExist = true;
|
if (UsePlcShotThemAll) {
|
||||||
|
canExist = (true, _WeldingJigNo);
|
||||||
Log.I("Settings - PLC : Shot Them All Mode");
|
Log.I("Settings - PLC : Shot Them All Mode");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
canExist = GetRotaryCanExist(_WeldingJigNo);
|
canExist = GetRotaryCanExist(_WeldingJigNo);
|
||||||
|
_WeldingJigNo = canExist.targetjigNo;
|
||||||
|
}
|
||||||
|
|
||||||
Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle);
|
Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle);
|
||||||
|
|
||||||
|
if (canExist.exist)
|
||||||
|
return SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ;
|
||||||
|
else
|
||||||
|
return SEQ_EXECUTE_WELDING;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
private SequenceActionResult ReadyScannerList(SequenceContext context, string id, SequenceActionResult param)
|
||||||
|
{
|
||||||
|
#region 이력
|
||||||
// 입력한 Scanner List를 완료대기열에 추가
|
// 입력한 Scanner List를 완료대기열에 추가
|
||||||
//SetInputScannerList(_WeldingScannerListNo, DateTime.Now, _WeldingCount, _WeldingStartAngle, _WeldingJigNo, _RotaryJigCount, canExist);
|
//SetInputScannerList(_WeldingScannerListNo, DateTime.Now, _WeldingCount, _WeldingStartAngle, _WeldingJigNo, _RotaryJigCount, canExist);
|
||||||
|
|
||||||
@ -816,36 +826,31 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
//// SEQ_WAIT_WELDING_START 의 기능이 어떻게 되는 지 확인 후
|
//// SEQ_WAIT_WELDING_START 의 기능이 어떻게 되는 지 확인 후
|
||||||
//// 건너뛰어도 되면 SEQ_EXECUTE_WELDING 으로 변경 해도 됨
|
//// 건너뛰어도 되면 SEQ_EXECUTE_WELDING 으로 변경 해도 됨
|
||||||
//return SEQ_WAIT_WELDING_START;
|
//return SEQ_WAIT_WELDING_START;
|
||||||
|
#endregion
|
||||||
|
|
||||||
if (canExist)
|
#region 용접할 Objects 선택
|
||||||
|
if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length)
|
||||||
{
|
{
|
||||||
#region 용접할 Objects 선택
|
_SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[_WeldingJigNo - 1].Objects;
|
||||||
if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length)
|
Log.I(string.Format("Page 불러오기 : [{0}])", _WeldingJigNo - 1));
|
||||||
{
|
|
||||||
_SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[_WeldingJigNo - 1].Objects;
|
|
||||||
Log.I(string.Format("Page 불러오기 : [{0}])", _WeldingJigNo - 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[0].Objects;
|
|
||||||
Log.I(string.Format("Page 불러오기 : [0])"));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
// 입력한 Scanner List를 완료대기열에 추가
|
|
||||||
// Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId
|
|
||||||
// GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID
|
|
||||||
string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요
|
|
||||||
string CellId = Status.GetProcessingWeldingData().WorkCellId;
|
|
||||||
SetInputScannerList(_WeldingScannerListNo, DateTime.Now, _WeldingCount, _WeldingStartAngle, _WeldingJigNo, _RotaryJigCount, canExist, LotId, CellId);
|
|
||||||
_RecipeNo = _RecipeManager.ActivatedRecipe().Id;
|
|
||||||
|
|
||||||
SetWeldingData();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return SEQ_EXECUTE_WELDING;
|
_SelectedDrawObjectList = _ScannerCanvasUserCtrl.Model.Layers[0].Objects;
|
||||||
|
Log.I(string.Format("Page 불러오기 : [0])"));
|
||||||
}
|
}
|
||||||
return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ;
|
#endregion
|
||||||
|
// 입력한 Scanner List를 완료대기열에 추가
|
||||||
|
// Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId
|
||||||
|
// GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID
|
||||||
|
string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요
|
||||||
|
string CellId = Status.GetProcessingWeldingData().WorkCellId;
|
||||||
|
SetInputScannerList(_WeldingScannerListNo, DateTime.Now, _WeldingCount, _WeldingStartAngle, _WeldingJigNo, _RotaryJigCount, true, LotId, CellId);
|
||||||
|
_RecipeNo = _RecipeManager.ActivatedRecipe().Id;
|
||||||
|
|
||||||
|
SetWeldingData();
|
||||||
|
|
||||||
|
return SequenceAction.Ok();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,6 +880,7 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void WaitForEncoderNextRotarySection(int weldingCount, int rotaryJigCount, double rotaryAngleOffset, double encoderResetOffset, out double sectionStartAngle)
|
public void WaitForEncoderNextRotarySection(int weldingCount, int rotaryJigCount, double rotaryAngleOffset, double encoderResetOffset, out double sectionStartAngle)
|
||||||
{
|
{
|
||||||
// 한 바퀴당 지그 숫자에 따른 변경
|
// 한 바퀴당 지그 숫자에 따른 변경
|
||||||
@ -906,8 +912,18 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
_Scanner.WaitForEncoderRotateRange(encoderAllowedMinDegree, encoderAllowedMaxDegree, sectionStartAngle, sectionEndAngle);
|
_Scanner.WaitForEncoderRotateRange(encoderAllowedMinDegree, encoderAllowedMaxDegree, sectionStartAngle, sectionEndAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetRotaryCanExist(int jigNo)
|
public (bool isExist, int targetJigNo) GetRotaryCanExist(int JigNo)
|
||||||
{
|
{
|
||||||
|
// PLC 용접 대상 비트를 확인한다.
|
||||||
|
for (int offset = 1; offset <= _RotaryJigCount; offset++) {
|
||||||
|
int checkJigNo = (JigNo + offset) % _RotaryJigCount; // 0~15번 비트를 확인하기 위함
|
||||||
|
|
||||||
|
// 비트가 켜져있는 것이 확인이 된다면,
|
||||||
|
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + checkJigNo).data) {
|
||||||
|
return (true, checkJigNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (false, 0);
|
||||||
#region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화
|
#region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화
|
||||||
string result = "";
|
string result = "";
|
||||||
|
|
||||||
@ -1156,11 +1172,10 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
|
|
||||||
return SequenceAction.Ok();
|
return SequenceAction.Ok();
|
||||||
}
|
}
|
||||||
|
public static bool CycleStopTest = false;
|
||||||
private static string CheckCycleStop(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
private string CheckCycleStop(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
||||||
{
|
{
|
||||||
Status.SetWorkingPosition(eWorkingPosition.CHECKING_CYCLE);
|
Status.SetWorkingPosition(eWorkingPosition.CHECKING_CYCLE);
|
||||||
|
|
||||||
// TODO: 확인 필요, CybleStop 에 대한 내용, cycle stop 여부 가져오기
|
// TODO: 확인 필요, CybleStop 에 대한 내용, cycle stop 여부 가져오기
|
||||||
//bCycleStop = GetCycleStopRequest();
|
//bCycleStop = GetCycleStopRequest();
|
||||||
|
|
||||||
@ -1168,17 +1183,13 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
//Jin : cycleStop 명령을 용접 프로그램에서 할 경우가 현재는 없음..
|
//Jin : cycleStop 명령을 용접 프로그램에서 할 경우가 현재는 없음..
|
||||||
// CheckCycleStop 노드와 Complete 노드 사이 다른 노드가 필요하다면 해당 노드를 CheckCycleStop 노드 위로 올리자
|
// CheckCycleStop 노드와 Complete 노드 사이 다른 노드가 필요하다면 해당 노드를 CheckCycleStop 노드 위로 올리자
|
||||||
bool cycleStop = false;
|
bool cycleStop = false;
|
||||||
if (cycleStop)
|
if (cycleStop || CycleStopTest)
|
||||||
{
|
|
||||||
return SEQ_SAVE_RESULT_DATA;
|
return SEQ_SAVE_RESULT_DATA;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return SEQ_CHECK_LOAD_COMPLETE;
|
return SEQ_CHECK_LOAD_COMPLETE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// END ALL
|
// END ALL
|
||||||
#endregion
|
|
||||||
private static string CheckCanWelded(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
private static string CheckCanWelded(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
||||||
{
|
{
|
||||||
if (isWeled)
|
if (isWeled)
|
||||||
@ -1187,19 +1198,19 @@ namespace ILSOS_ACW_H52A.Sequences
|
|||||||
return SEQ_CHECK_CYCLE_STOP;
|
return SEQ_CHECK_CYCLE_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveCellAPD()
|
private void SaveCellAPDData()
|
||||||
{
|
{
|
||||||
if (Status.GetProcessingWeldingData().APD.Count > 0)
|
if (Status.GetProcessingWeldingData().APD.Count > 0)
|
||||||
{
|
{
|
||||||
string directoryPath = "D:\\ILSOSConfig\\APD_History";
|
string directoryPath = "D:\\ILSOSConfig\\APD_History";
|
||||||
string fileName = DateTime.Now.ToString("HH") + "_CellAPD";
|
string fileName = DateTime.Now.ToString("HHmmss.fff") + "_" + Status.GetProcessingWeldingData().APD.First().CellID;
|
||||||
string fullPath = Path.Combine(directoryPath, Status.GetProcessingWeldingData().APD.First().Date.ToString("yyyy-MM-dd"), fileName);
|
string fullPath = Path.Combine(directoryPath, Status.GetProcessingWeldingData().APD.First().Date.ToString("yyyy-MM-dd"), fileName);
|
||||||
Status.GetProcessingWeldingData().APD.CreateFiles(fullPath);
|
Status.GetProcessingWeldingData().APD.CreateFiles(fullPath);
|
||||||
|
Log.I($"Save Cell APD Data. File Name : {fileName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param)
|
private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param)
|
||||||
{
|
{
|
||||||
|
|
||||||
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true);
|
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true);
|
||||||
return SequenceAction.Ok();
|
return SequenceAction.Ok();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,11 @@
|
|||||||
using Aurora;
|
using Aurora;
|
||||||
using Aurora.Api;
|
|
||||||
using AuroraPLC;
|
using AuroraPLC;
|
||||||
using Hermes;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using WeldingCommon.Devices;
|
using WeldingCommon.Devices;
|
||||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;
|
|
||||||
|
|
||||||
namespace ILSOS_CCW_H52A.Device
|
namespace ILSOS_CCW_H52A.Device
|
||||||
{
|
{
|
||||||
@ -17,183 +13,7 @@ namespace ILSOS_CCW_H52A.Device
|
|||||||
{
|
{
|
||||||
public PLCControllerCCWH52A(string deviceId, ePLCNetType plcNetType, PLCMMapFileType fileType, IAuroraEnvironment aurora) : base(deviceId, plcNetType, fileType, aurora)
|
public PLCControllerCCWH52A(string deviceId, ePLCNetType plcNetType, PLCMMapFileType fileType, IAuroraEnvironment aurora) : base(deviceId, plcNetType, fileType, aurora)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
protected override int DoActivate(IDeviceConfig config)
|
|
||||||
{
|
|
||||||
var ret = base.DoActivate(config);
|
|
||||||
if (ret == E1.OK && IsSimul) {
|
|
||||||
//WriteBit((int)eBitInput.PLC_AUTO_STATUS, true, ePLCDevice.B, false);
|
|
||||||
//WriteBit((int)eBitInput.PLC_AUTO_REQ, true, ePLCDevice.B, false);
|
|
||||||
SetMonitoringService(EquipmentSimulator, 1);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override int DoDeactivate()
|
|
||||||
{
|
|
||||||
StopMonitoringService();
|
|
||||||
|
|
||||||
var res = base.DoDeactivate();
|
|
||||||
|
|
||||||
if (res != E1.OK) {
|
|
||||||
Log.E("Deactivate is failed");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------
|
|
||||||
// Simulation state
|
|
||||||
// -----------------------------
|
|
||||||
private const int PLC_CURRENT_POS_1_ADDR = 4; // 기존 (mod 0~360)
|
|
||||||
|
|
||||||
private readonly Random _rand = new Random();
|
|
||||||
|
|
||||||
private readonly Stopwatch _sw = Stopwatch.StartNew();
|
|
||||||
private long _lastMs = -1;
|
|
||||||
|
|
||||||
private const int RotaryJigCount = 16;
|
|
||||||
private const double JigPerMsec = 300;
|
|
||||||
private const double DegreePerRev = 360.0;
|
|
||||||
private const double OneCycleMsec = JigPerMsec * RotaryJigCount;
|
|
||||||
private const double DegreePerMsec = DegreePerRev / OneCycleMsec;
|
|
||||||
private const double DegreePerJig = DegreePerRev / RotaryJigCount; // 22.5
|
|
||||||
private const double HalfDegreePerJig = DegreePerJig / 2.0; // 11.25
|
|
||||||
|
|
||||||
// PLC_CURRENT_POS_1 = degree * 100000
|
|
||||||
private const double PlcAngleScale = 100_000.0;
|
|
||||||
|
|
||||||
// 시퀀스가 "다음 지그"를 미리 읽으므로 안전하게 2칸 선행(권장)
|
|
||||||
private const int LeadSectors = 2;
|
|
||||||
|
|
||||||
// Motor position
|
|
||||||
private readonly object _absLock = new object();
|
|
||||||
public double GetSimAbsDeg()
|
|
||||||
{
|
|
||||||
long value = System.Threading.Interlocked.Read(ref _angleAbsDeg);
|
|
||||||
return value / 100000.0;
|
|
||||||
}
|
|
||||||
private long _angleAbsDeg = 0; // 누적 각도(계속 증가)
|
|
||||||
|
|
||||||
private double _angleModDeg = 0.0; // 0~360 랩핑 각도
|
|
||||||
|
|
||||||
// PLC USE_WELD_JIG bits
|
|
||||||
private readonly bool[] _canExist = new bool[RotaryJigCount];
|
|
||||||
private readonly bool[] _decided = new bool[RotaryJigCount]; // 이번 회전에서 해당 섹터가 결정됐는지
|
|
||||||
private int _prevSector = -1;
|
|
||||||
|
|
||||||
private static void FillBool(bool[] arr, bool value)
|
|
||||||
{
|
|
||||||
if (arr == null)
|
|
||||||
return;
|
|
||||||
for (int i = 0; i < arr.Length; i++)
|
|
||||||
arr[i] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int Mod(int x, int m)
|
|
||||||
{
|
|
||||||
int r = x % m;
|
|
||||||
return (r < 0) ? (r + m) : r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetSectorFromAngle(double angleDeg)
|
|
||||||
{
|
|
||||||
// 시퀀스의 (angle + half)/per와 동일한 기준으로 섹터 결정
|
|
||||||
return (int)((angleDeg + HalfDegreePerJig) / DegreePerJig) % RotaryJigCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSectorChanged(int prev, int curr)
|
|
||||||
{
|
|
||||||
// 첫 진입
|
|
||||||
if (prev < 0) {
|
|
||||||
// 처음 시작 시에는 전부 OFF 상태에서 시작
|
|
||||||
FillBool(_canExist, false);
|
|
||||||
FillBool(_decided, false);
|
|
||||||
} else {
|
|
||||||
// 랩(15 -> 0) 감지: 새 바퀴 시작으로 보고 "지나간 영역 OFF"를 강하게 반영
|
|
||||||
if (prev == RotaryJigCount - 1 && curr == 0) {
|
|
||||||
FillBool(_canExist, false);
|
|
||||||
FillBool(_decided, false);
|
|
||||||
} else {
|
|
||||||
// 지나간 섹터(prev)는 OFF 처리
|
|
||||||
_canExist[prev] = false;
|
|
||||||
_decided[prev] = false; // 다음 회전에서 다시 결정되도록
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 시퀀스는 "다음 지그"를 읽으므로 curr+1부터 선행 결정
|
|
||||||
for (int k = 1; k <= LeadSectors; k++) {
|
|
||||||
int s = Mod(curr + k, RotaryJigCount);
|
|
||||||
|
|
||||||
if (!_decided[s]) {
|
|
||||||
// 7/8 확률 ON (0~7 중 0만 OFF로 만들려면 >0)
|
|
||||||
bool isCanExist = true;// (_rand.Next(0, 8) > 0);
|
|
||||||
_canExist[s] = isCanExist;
|
|
||||||
_decided[s] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 현재 섹터(curr)도 켜고 싶다면 여기서 결정 가능
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EquipmentSimulator()
|
|
||||||
{
|
|
||||||
if (!ReadBit((int)eBitOutput.PC_AUTO_STATUS, ePLCDevice.B, false).data)
|
|
||||||
return;
|
|
||||||
|
|
||||||
long now = _sw.ElapsedMilliseconds;
|
|
||||||
if (_lastMs < 0)
|
|
||||||
_lastMs = now;
|
|
||||||
|
|
||||||
long dtMs = now - _lastMs;
|
|
||||||
if (dtMs < 0)
|
|
||||||
dtMs = 0;
|
|
||||||
|
|
||||||
if (dtMs > 100)
|
|
||||||
dtMs = 100;
|
|
||||||
|
|
||||||
_lastMs = now;
|
|
||||||
|
|
||||||
// abs 누적각 (시뮬 전용)
|
|
||||||
long deltaScaled = (long)Math.Round(DegreePerMsec * dtMs * 100000.0);
|
|
||||||
System.Threading.Interlocked.Add(ref _angleAbsDeg, deltaScaled);
|
|
||||||
|
|
||||||
double absDeg = GetSimAbsDeg();
|
|
||||||
_angleModDeg = absDeg % DegreePerRev;
|
|
||||||
if (_angleModDeg < 0)
|
|
||||||
_angleModDeg += DegreePerRev;
|
|
||||||
|
|
||||||
// mod 각도
|
|
||||||
int plcAngleMod = (int)Math.Round(_angleModDeg * PlcAngleScale);
|
|
||||||
WriteDWord(PLC_CURRENT_POS_1_ADDR, plcAngleMod, ePLCDevice.W, false);
|
|
||||||
|
|
||||||
// 섹터 변경/비트 처리 로직은 기존 그대로
|
|
||||||
int sectorNow = GetSectorFromAngle(_angleModDeg);
|
|
||||||
if (sectorNow != _prevSector) {
|
|
||||||
OnSectorChanged(_prevSector, sectorNow);
|
|
||||||
_prevSector = sectorNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteBitBlock((int)eBitInput.PLC_USE_WELD_JIG_1, RotaryJigCount, _canExist, ePLCDevice.B, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetSimulator()
|
|
||||||
{
|
|
||||||
_lastMs = -1;
|
|
||||||
System.Threading.Interlocked.Exchange(ref _angleAbsDeg, 0);
|
|
||||||
_angleModDeg = 0.0;
|
|
||||||
|
|
||||||
FillBool(_canExist, false);
|
|
||||||
FillBool(_decided, false);
|
|
||||||
_prevSector = -1;
|
|
||||||
|
|
||||||
// 각도 초기화 반영
|
|
||||||
WriteDWord(PLC_CURRENT_POS_1_ADDR, 0, ePLCDevice.W, false);
|
|
||||||
|
|
||||||
// 지그 비트 초기화 반영
|
|
||||||
WriteBitBlock((int)eBitInput.PLC_USE_WELD_JIG_1, RotaryJigCount, _canExist, ePLCDevice.B, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
using Aurora.Util.HislogPlus;
|
using Hermes;
|
||||||
using AuroraPLC;
|
|
||||||
using Hermes;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -12,60 +10,6 @@ namespace ILSOS_CCW_H52A.Device
|
|||||||
{
|
{
|
||||||
partial class PLCControllerCCWH52A
|
partial class PLCControllerCCWH52A
|
||||||
{
|
{
|
||||||
public (int err, bool data) ReadBit(eBitInput inputAddr, ePLCDevice device = ePLCDevice.B, bool isInput = true) => base.ReadBit((int)inputAddr, device, isInput);
|
|
||||||
public int WriteBit(eBitOutput outputAddr, bool onOff, ePLCDevice device = ePLCDevice.B, bool isOutput = true) => base.WriteBit((int)outputAddr, onOff, device, isOutput);
|
|
||||||
|
|
||||||
public (int err, short data) ReadWord(eWordInput inputAddr, ePLCDevice device = ePLCDevice.W, bool isInput = true) => base.ReadWord((int)inputAddr, device, isInput);
|
|
||||||
public int WriteWord(eWordOutput outputAddr, short shData, ePLCDevice device = ePLCDevice.W, bool isOutput = true) => base.WriteWord((int)outputAddr, shData, device, isOutput);
|
|
||||||
|
|
||||||
public (int err, int data) ReadDWord(eWordInput inputAddr, ePLCDevice device = ePLCDevice.W, bool isInput = true) => base.ReadDWord((int)inputAddr, device, isInput);
|
|
||||||
public int WriteDWord(eWordOutput outputAddr, int iVal, ePLCDevice device = ePLCDevice.W, bool isOutput = true) => base.WriteDWord((int)outputAddr, iVal, device, isOutput);
|
|
||||||
|
|
||||||
public (int err, short[] datas) ReadWords(eWordInput startAddress, eWordInput endAddress, ePLCDevice device = ePLCDevice.W, bool isInput = true) => base.ReadWordBlock((int)startAddress, endAddress - startAddress + 1, device, isInput);
|
|
||||||
public int WriteWords(eWordOutput startAddress, eWordOutput endAddress, short[] data, ePLCDevice device = ePLCDevice.W, bool isOutput = true) => base.WriteWordBlock((int)startAddress, endAddress - startAddress, data, device, isOutput);
|
|
||||||
|
|
||||||
public string ReadASCII(eWordInput start, eWordInput end)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
var words = ReadWords(start, end);
|
|
||||||
foreach (var word in words.datas)
|
|
||||||
sb.Append(Conv_ReadData(PLCBase.eDataType.Type_Ascii, word, 0, false, false));
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
public int WriteWordToBit((eWordOutput addrOffset, int bitNo) address, bool on)
|
|
||||||
{
|
|
||||||
var value = base.ReadWord((int)address.addrOffset, ePLCDevice.W, false);
|
|
||||||
short current = value.data;
|
|
||||||
|
|
||||||
if (on) {
|
|
||||||
current |= (short)(1 << address.bitNo);
|
|
||||||
} else {
|
|
||||||
current &= (short)~(1 << address.bitNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.WriteWord((int)address.addrOffset, current, ePLCDevice.W);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ReadWordToBit((eWordInput addrOffset, int bitNo) address)
|
|
||||||
{
|
|
||||||
short current = ReadWord(address.addrOffset).data;
|
|
||||||
return (current & (1 << address.bitNo)) != 0;
|
|
||||||
}
|
|
||||||
public IEnumerable<bool> ReadWordToBits(eWordInput address, bool isLowerFirst = true)
|
|
||||||
{
|
|
||||||
var ret = new List<bool>();
|
|
||||||
int word = ReadWord(address).data;
|
|
||||||
if (isLowerFirst) {
|
|
||||||
for (int idx = 0; idx < 15; idx++)
|
|
||||||
ret.Add((word & (1 << idx)) != 0);
|
|
||||||
} else {
|
|
||||||
for (int idx = 15; idx > 0; idx--)
|
|
||||||
ret.Add((word & (1 << idx)) != 0);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void MappingPLCAddr()
|
public override void MappingPLCAddr()
|
||||||
{
|
{
|
||||||
PLC_AUTO_REQAddr = (int)eBitInput.PLC_AUTO_REQ;
|
PLC_AUTO_REQAddr = (int)eBitInput.PLC_AUTO_REQ;
|
||||||
@ -148,17 +92,5 @@ namespace ILSOS_CCW_H52A.Device
|
|||||||
else
|
else
|
||||||
return 1000;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ToggleBit(eBitInput readBit, eBitOutput writeBit)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
if (ReadBit(readBit).data)
|
|
||||||
ret = WriteBit(writeBit, false);
|
|
||||||
else
|
|
||||||
ret = WriteBit(writeBit, true);
|
|
||||||
|
|
||||||
Log.I($"{Enum.GetName(typeof(eBitOutput), writeBit)} -> {!ReadBit(readBit).data}");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,66 +0,0 @@
|
|||||||
using Aurora;
|
|
||||||
using Aurora.Api;
|
|
||||||
using AuroraLaserScanner;
|
|
||||||
using Hermes;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using WeldingCommon;
|
|
||||||
using static ILSOS_CCW_H52A.Device.PLCControllerCCWH52A;
|
|
||||||
|
|
||||||
namespace ILSOS_CCW_H52A.Device
|
|
||||||
{
|
|
||||||
public class ScannerCCWH52A : Scanner
|
|
||||||
{
|
|
||||||
// -----------------------------
|
|
||||||
// Simulation state
|
|
||||||
// -----------------------------
|
|
||||||
private PLCControllerCCWH52A _plc;
|
|
||||||
|
|
||||||
public ScannerCCWH52A(string deviceId) : base(deviceId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override int DoActivate(IDeviceConfig config)
|
|
||||||
{
|
|
||||||
var ret = base.DoActivate(config);
|
|
||||||
if (ret == E1.OK && IsSimul) {
|
|
||||||
if (_plc == null) {
|
|
||||||
_plc = Application.Current.AuroraEnv().DeviceManager[CommonDeviceIds.PLCDevice] as PLCControllerCCWH52A;
|
|
||||||
return E2.ABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 값의 동기화가 필요해서 추가 함
|
|
||||||
if (!_plc.IsConnected && !_plc.IsSimul)
|
|
||||||
return E2.ABORTED;
|
|
||||||
|
|
||||||
var core = _scannerObj as ScannerSimul;
|
|
||||||
core.PLCReadBit = _plc.ReadBit;
|
|
||||||
core.PLCReadWord = _plc.ReadWord;
|
|
||||||
core.PLCReadDWord = _plc.ReadDWord;
|
|
||||||
core.PLCGetAbsDeg = _plc.GetSimAbsDeg;
|
|
||||||
//_plc.ResetSimulator();
|
|
||||||
core.ResetSim();
|
|
||||||
core.TrySyncAbsAngleToPlcNow();
|
|
||||||
|
|
||||||
SetMonitoringService((_scannerObj as ScannerSimul).EquipmentSimulator, 1);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override int DoDeactivate()
|
|
||||||
{
|
|
||||||
var ret = base.DoDeactivate();
|
|
||||||
if (ret == E1.OK && IsSimul){
|
|
||||||
var core = _scannerObj as ScannerSimul;
|
|
||||||
StopMonitoringService();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -66,7 +66,6 @@ namespace ILSOS_CCW_H52A.Device
|
|||||||
public bool CheckSendCellinfo { get; set; }
|
public bool CheckSendCellinfo { get; set; }
|
||||||
public bool CheckSendPLCLaserPower { get; set; }
|
public bool CheckSendPLCLaserPower { get; set; }
|
||||||
public bool ReportComplete { get; set; }
|
public bool ReportComplete { get; set; }
|
||||||
public void SetReportComplete(bool comp) => ReportComplete = comp;
|
|
||||||
|
|
||||||
public override string ToString() => string.Format("{0},WriteTime({1}),WeldingCount({2}),StartAngle({3}),JigNo({4}),CanExist({5}),LotId({6}),CellId({7})",
|
public override string ToString() => string.Format("{0},WriteTime({1}),WeldingCount({2}),StartAngle({3}),JigNo({4}),CanExist({5}),LotId({6}),CellId({7})",
|
||||||
ListNo, WriteTime.ToString("HHmmss.fff"), WeldingCount, StartAngle, JigNo, CanExist, LotId, CellId);
|
ListNo, WriteTime.ToString("HHmmss.fff"), WeldingCount, StartAngle, JigNo, CanExist, LotId, CellId);
|
||||||
|
|||||||
@ -11,7 +11,6 @@ using AuroraCellTracker.Views;
|
|||||||
using AuroraIO;
|
using AuroraIO;
|
||||||
using AuroraIO.View;
|
using AuroraIO.View;
|
||||||
using AuroraLaser;
|
using AuroraLaser;
|
||||||
using AuroraLaserScanner;
|
|
||||||
using AuroraLBAD;
|
using AuroraLBAD;
|
||||||
using AuroraLBAD.Services;
|
using AuroraLBAD.Services;
|
||||||
using AuroraOCT;
|
using AuroraOCT;
|
||||||
@ -141,7 +140,6 @@ namespace ILSOS_CCW_H52A
|
|||||||
|
|
||||||
public override void RegisterDevices(IDeviceRegistry registry)
|
public override void RegisterDevices(IDeviceRegistry registry)
|
||||||
{
|
{
|
||||||
registry.Register(CommonDeviceIds.Scanner, () => new ScannerCCWH52A(CommonDeviceIds.Scanner), new ScannerConfig());
|
|
||||||
base.RegisterDevices(registry);
|
base.RegisterDevices(registry);
|
||||||
|
|
||||||
var isSimul = ApplicationExt.IsSimulation;
|
var isSimul = ApplicationExt.IsSimulation;
|
||||||
|
|||||||
@ -98,7 +98,6 @@
|
|||||||
<Compile Include="Device\PLC\PLCContoller.Config.cs" />
|
<Compile Include="Device\PLC\PLCContoller.Config.cs" />
|
||||||
<Compile Include="Device\PLC\PLCController.Address.cs" />
|
<Compile Include="Device\PLC\PLCController.Address.cs" />
|
||||||
<Compile Include="Device\PLC\PLCController.Logic.cs" />
|
<Compile Include="Device\PLC\PLCController.Logic.cs" />
|
||||||
<Compile Include="Device\Scanner\ScannerCCWH52A.cs" />
|
|
||||||
<Compile Include="Device\Scanner\ScannerList.cs" />
|
<Compile Include="Device\Scanner\ScannerList.cs" />
|
||||||
<Compile Include="EquipDef.cs" />
|
<Compile Include="EquipDef.cs" />
|
||||||
<Compile Include="EquipmentSetup.cs" />
|
<Compile Include="EquipmentSetup.cs" />
|
||||||
@ -106,10 +105,7 @@
|
|||||||
<Compile Include="Recipes\RecipeEventHelper.cs" />
|
<Compile Include="Recipes\RecipeEventHelper.cs" />
|
||||||
<Compile Include="RMS\EDC.cs" />
|
<Compile Include="RMS\EDC.cs" />
|
||||||
<Compile Include="Sequences\Monitoring\AlarmMonitoring.cs" />
|
<Compile Include="Sequences\Monitoring\AlarmMonitoring.cs" />
|
||||||
<Compile Include="Sequences\ProcessObjects\ProcessManager.cs" />
|
|
||||||
<Compile Include="Sequences\ProcessObjects\ReceivedCellInfo.cs" />
|
|
||||||
<Compile Include="Sequences\SeqAutoRunCCWH52A.cs" />
|
<Compile Include="Sequences\SeqAutoRunCCWH52A.cs" />
|
||||||
<Compile Include="Sequences\SeqAutoRunRMOTF.cs" />
|
|
||||||
<Compile Include="Sequences\SequenceContextEx.cs" />
|
<Compile Include="Sequences\SequenceContextEx.cs" />
|
||||||
<Compile Include="Views\Main\UCMainAutoRun.xaml.cs">
|
<Compile Include="Views\Main\UCMainAutoRun.xaml.cs">
|
||||||
<DependentUpon>UCMainAutoRun.xaml</DependentUpon>
|
<DependentUpon>UCMainAutoRun.xaml</DependentUpon>
|
||||||
|
|||||||
@ -1,126 +0,0 @@
|
|||||||
using Aurora;
|
|
||||||
using Aurora.Api;
|
|
||||||
using Aurora.Util.HislogPlus;
|
|
||||||
using AuroraLaserScanner;
|
|
||||||
using AuroraPLC;
|
|
||||||
using ILSOS_CCW_H52A.Device;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using WeldingCommon;
|
|
||||||
using WeldingCommon.Data;
|
|
||||||
using static ILSOS_CCW_H52A.Device.PLCControllerCCWH52A;
|
|
||||||
|
|
||||||
namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
|
|
||||||
{
|
|
||||||
public class ProcessManager
|
|
||||||
{
|
|
||||||
private static ProcessManager _Instance;
|
|
||||||
public static ProcessManager Instance {
|
|
||||||
get {
|
|
||||||
if (_Instance is null) {
|
|
||||||
_Instance = new ProcessManager();
|
|
||||||
}
|
|
||||||
return _Instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private IAuroraEnvironment _env;
|
|
||||||
private PLCControllerCCWH52A _plc;
|
|
||||||
private ScannerCCWH52A _scanner;
|
|
||||||
|
|
||||||
private bool usedAnalyzerLog = false;
|
|
||||||
private readonly Logger _log = new Logger("ProcessManager");
|
|
||||||
|
|
||||||
public const double compensateEncoderReset = 0.015; // 엔코더 리셋 보상 각도 설정(70도/sec 기준 약 0.015도)
|
|
||||||
public const int RotaryJigCount = 16;
|
|
||||||
public const int RotaryMaxAngle = 360;
|
|
||||||
public double DegreePerJig { get => RotaryMaxAngle / RotaryJigCount; }
|
|
||||||
public double HalfDegreePerJig { get => DegreePerJig / 2; }
|
|
||||||
|
|
||||||
//public ConcurrentQueue<ReceivedCellInfo>
|
|
||||||
public void Init(IAuroraEnvironment env)
|
|
||||||
{
|
|
||||||
_env = env;
|
|
||||||
_plc = _env.DeviceManager[DeviceIds.PLCDevice] as PLCControllerCCWH52A;
|
|
||||||
_scanner = _env.DeviceManager[DeviceIds.Scanner] as ScannerCCWH52A;
|
|
||||||
}
|
|
||||||
public IEnumerable<bool> CheckRotaryState()
|
|
||||||
{
|
|
||||||
List<bool> rotaryStates = new List<bool>();
|
|
||||||
for (int i = 0; i < RotaryJigCount; i++) {
|
|
||||||
var rotaryProcessState = _plc.ReadBit(eBitInput.PLC_USE_WELD_JIG_1 + i).data;
|
|
||||||
rotaryStates.Add(rotaryProcessState);
|
|
||||||
//if (rotaryProcessState == false)
|
|
||||||
// _plc.ToggleBit(eBitInput.PLC_USE_WELD_JIG_1 + i, eBitOutput.PC_WELD_COMPLETE_1 + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usedAnalyzerLog) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
rotaryStates.ForEach(x => sb.Append($"{x} "));
|
|
||||||
_log.D($"Check Rotary State : {sb.ToString()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return rotaryStates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetRotaryCanExist(int jigNo)
|
|
||||||
{
|
|
||||||
if (jigNo == 0)
|
|
||||||
jigNo = 1;
|
|
||||||
|
|
||||||
if (jigNo <= RotaryJigCount)
|
|
||||||
return _plc.ReadBit(eBitInput.PLC_USE_WELD_JIG_1 + (jigNo - 1)).data;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotary의 현재 위치정보를 0~360로 전달함
|
|
||||||
/// </summary>
|
|
||||||
public double GetRotaryCurrentPosition(bool isView360 = true)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
double finalValue = Convert.ToDouble(_plc.ReadDWord(eWordInput.PLC_CURRENT_POS_1).data / 100_000f);
|
|
||||||
finalValue += _scanner.Config.RotaryEncoderOffset;
|
|
||||||
|
|
||||||
if (isView360) {
|
|
||||||
if (RotaryMaxAngle <= finalValue) {
|
|
||||||
while (RotaryMaxAngle <= finalValue) {
|
|
||||||
finalValue -= RotaryMaxAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (finalValue < 0) {
|
|
||||||
while (finalValue < 0) {
|
|
||||||
finalValue += RotaryMaxAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalValue;
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return -9999.9999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 중심 기준 가장 가까운 지그 번호(내림 연산)
|
|
||||||
/// <param name="HalfDegreePerJig">내림 카운팅을 중심 기준 값</param>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int getCurrentJigNo() => (int)((GetRotaryCurrentPosition(isView360:true) + HalfDegreePerJig) / DegreePerJig) + 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 360도 이상으로 준다고하면 Welding Count를 가져올 수 있음 2word = 2147483.647 / 3600 = 596 >> 596*16 = 9_536까지 카운팅 가능함
|
|
||||||
/// <param name="HalfDegreePerJig">내림 카운팅을 중심 기준 값</param>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int getWeldingCount() => (int)((GetRotaryCurrentPosition(isView360:false) + HalfDegreePerJig) / DegreePerJig);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
|
|
||||||
{
|
|
||||||
public class ReceivedCellInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
public ReceivedCellInfo() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -236,7 +236,7 @@ namespace WeldingCommon
|
|||||||
//registry.Register(CommonDeviceIds.Laser, () => new Laser(CommonDeviceIds.Laser, isSimul), new LaserConfig(),
|
//registry.Register(CommonDeviceIds.Laser, () => new Laser(CommonDeviceIds.Laser, isSimul), new LaserConfig(),
|
||||||
// device => new UCLaserDevice() { DataContext = new UCLaserDeviceViewModel(AuroraEnv, CommonDeviceIds.Laser) });
|
// device => new UCLaserDevice() { DataContext = new UCLaserDeviceViewModel(AuroraEnv, CommonDeviceIds.Laser) });
|
||||||
|
|
||||||
//registry.Register(CommonDeviceIds.Scanner, () => new Scanner(CommonDeviceIds.Scanner), new ScannerConfig());
|
registry.Register(CommonDeviceIds.Scanner, () => new Scanner(CommonDeviceIds.Scanner), new ScannerConfig());
|
||||||
//registry.Register(CommonDeviceIds.SmcChiller, () => new SmcChiller(CommonDeviceIds.SmcChiller, 0, isSimul), new SmcChiller.Config(),
|
//registry.Register(CommonDeviceIds.SmcChiller, () => new SmcChiller(CommonDeviceIds.SmcChiller, 0, isSimul), new SmcChiller.Config(),
|
||||||
// device => new UCSMCChillerDevice() { DataContext = new UCSMCChillerDeviceViewModel(AuroraEnv, CommonDeviceIds.SmcChiller) });
|
// device => new UCSMCChillerDevice() { DataContext = new UCSMCChillerDeviceViewModel(AuroraEnv, CommonDeviceIds.SmcChiller) });
|
||||||
registry.Register(CommonDeviceIds.SmcChiller, () => new SmcChiller(CommonDeviceIds.SmcChiller), new SmcChillerConfig(),
|
registry.Register(CommonDeviceIds.SmcChiller, () => new SmcChiller(CommonDeviceIds.SmcChiller), new SmcChillerConfig(),
|
||||||
|
|||||||
@ -26,10 +26,9 @@ namespace WeldingCommon.Data
|
|||||||
{
|
{
|
||||||
table.Columns.Add("Date", typeof(string));
|
table.Columns.Add("Date", typeof(string));
|
||||||
table.Columns.Add("Time", typeof(string));
|
table.Columns.Add("Time", typeof(string));
|
||||||
|
table.Columns.Add(nameof(ActualProcessUnit.WeldType), typeof(string));
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.LotID), typeof(string));
|
table.Columns.Add(nameof(ActualProcessUnit.LotID), typeof(string));
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.CellID), typeof(string));
|
table.Columns.Add(nameof(ActualProcessUnit.CellID), typeof(string));
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.HeadNo), typeof(string));
|
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.WeldType), typeof(string));
|
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.EncoderCheck), typeof(bool));
|
table.Columns.Add(nameof(ActualProcessUnit.EncoderCheck), typeof(bool));
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.StartPointX), typeof(double));
|
table.Columns.Add(nameof(ActualProcessUnit.StartPointX), typeof(double));
|
||||||
table.Columns.Add(nameof(ActualProcessUnit.StartPointY), typeof(double));
|
table.Columns.Add(nameof(ActualProcessUnit.StartPointY), typeof(double));
|
||||||
@ -62,7 +61,7 @@ namespace WeldingCommon.Data
|
|||||||
protected override void InsertItem(int index, ActualProcessUnit item)
|
protected override void InsertItem(int index, ActualProcessUnit item)
|
||||||
{
|
{
|
||||||
base.InsertItem(index, item);
|
base.InsertItem(index, item);
|
||||||
table.Rows.Add(item.Date.ToString("yyyy-MM-dd"), item.Date.ToString("HH:mm:ss.fff"), item.LotID, item.CellID, item.HeadNo, item.WeldType, item.EncoderCheck,
|
table.Rows.Add(item.Date.ToString("yyyy-MM-dd"), item.Date.ToString("HH:mm:ss.fff"),item.WeldType, item.LotID, item.CellID, item.EncoderCheck,
|
||||||
item.StartPointX, item.StartPointY, item.EndPointX, item.EndPointY,
|
item.StartPointX, item.StartPointY, item.EndPointX, item.EndPointY,
|
||||||
item.WeldCondition, item.LaserOnDelay, item.LaserOffDelay, item.JumpDelay, item.MarkDelay,
|
item.WeldCondition, item.LaserOnDelay, item.LaserOffDelay, item.JumpDelay, item.MarkDelay,
|
||||||
item.PolygonDelay, item.Power, item.JumpSpeed, item.MarkSpeed, item.JumpX,
|
item.PolygonDelay, item.Power, item.JumpSpeed, item.MarkSpeed, item.JumpX,
|
||||||
@ -80,14 +79,12 @@ namespace WeldingCommon.Data
|
|||||||
{
|
{
|
||||||
public DateTime Date { get => _Date; set => SetProperty(ref _Date, value); }
|
public DateTime Date { get => _Date; set => SetProperty(ref _Date, value); }
|
||||||
private DateTime _Date;
|
private DateTime _Date;
|
||||||
public string LotID { get => _LodID; set => SetProperty(ref _LodID, value); }
|
public string LotID { get => Status.GetProcessingWeldingData().LotId; }
|
||||||
private string _LodID;
|
public string CellID { get => Status.GetProcessingWeldingData().CellId; }
|
||||||
public string CellID { get => _CellID; set => SetProperty(ref _CellID, value); }
|
|
||||||
private string _CellID;
|
|
||||||
public string HeadNo { get => _HeadNo; set => SetProperty(ref _HeadNo, value); }
|
|
||||||
private string _HeadNo;
|
|
||||||
public string WeldType { get => _WeldType; set => SetProperty(ref _WeldType, value); }
|
public string WeldType { get => _WeldType; set => SetProperty(ref _WeldType, value); }
|
||||||
private string _WeldType;
|
private string _WeldType;
|
||||||
|
|
||||||
public bool EncoderCheck { get => _EncoderCheck; set => SetProperty(ref _EncoderCheck, value); }
|
public bool EncoderCheck { get => _EncoderCheck; set => SetProperty(ref _EncoderCheck, value); }
|
||||||
private bool _EncoderCheck;
|
private bool _EncoderCheck;
|
||||||
public double StartPointX { get => _StartPointX; set => SetProperty(ref _StartPointX, value); }
|
public double StartPointX { get => _StartPointX; set => SetProperty(ref _StartPointX, value); }
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace WeldingCommon.Devices
|
|||||||
public abstract partial class PLCController : PLCBase
|
public abstract partial class PLCController : PLCBase
|
||||||
{
|
{
|
||||||
// Log 사용 방법
|
// Log 사용 방법
|
||||||
protected static Logger Log = new Logger("PLCController");
|
static Logger Log = new Logger("PLCController");
|
||||||
|
|
||||||
//static Logger EventLog = new Logger(eMsg_TYPE.PLC.ToString(), "Event");
|
//static Logger EventLog = new Logger(eMsg_TYPE.PLC.ToString(), "Event");
|
||||||
|
|
||||||
|
|||||||
@ -108,11 +108,11 @@
|
|||||||
public const string Laser = "Laser";
|
public const string Laser = "Laser";
|
||||||
public const string LaserIO = "LaserIO";
|
public const string LaserIO = "LaserIO";
|
||||||
|
|
||||||
|
public const string Scanner = "Scanner";
|
||||||
public const string SmcChiller = "SmcChiller";
|
public const string SmcChiller = "SmcChiller";
|
||||||
public const string PowerMeter = "PowerMeter";
|
public const string PowerMeter = "PowerMeter";
|
||||||
public const string Light = "Light"; // Camera Light Controller
|
public const string Light = "Light"; // Camera Light Controller
|
||||||
public const string PLCDevice = "PLC";
|
public const string PLCDevice = "PLC";
|
||||||
public const string Scanner = "Scanner";
|
|
||||||
public const string IODevice = "IO_Board";
|
public const string IODevice = "IO_Board";
|
||||||
|
|
||||||
public const string CellTracker = "CellTracker";
|
public const string CellTracker = "CellTracker";
|
||||||
|
|||||||
@ -345,22 +345,27 @@ namespace WeldingCommon.Sequences
|
|||||||
_FindPatternCount = 0;
|
_FindPatternCount = 0;
|
||||||
return SEQ_DECISION_CHECK_OFFSET;
|
return SEQ_DECISION_CHECK_OFFSET;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
if (_InitParam.Is1StepCalibration)
|
||||||
if (_InitParam.Is1StepCalibration) {
|
{
|
||||||
_Is1stepCount++;
|
_Is1stepCount++;
|
||||||
Log.I(string.Format($"Is1stepCount : {_Is1stepCount} "));
|
Log.I(string.Format($"Is1stepCount : {_Is1stepCount} "));
|
||||||
return SEQ_FIND_PATTERN;
|
return SEQ_FIND_PATTERN;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (_NotFoundCount > 5) {
|
{
|
||||||
Log.I(string.Format($"Pattern Not Found. NotFoundCount OverFlow. Next Sequnece : SetVisionPositionFailed."));
|
if(_NotFoundCount > 5)
|
||||||
|
{
|
||||||
|
Log.I(string.Format($"Pattern Not Found. NotFoundCount OverFlow. Next Sequnece : SetVisionPositionFailed."));
|
||||||
return SEQ_SET_VISION_POSITION_FAILED;
|
return SEQ_SET_VISION_POSITION_FAILED;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
_NotFoundCount++;
|
{
|
||||||
Log.I(string.Format($"NotFoundCount : {_NotFoundCount} "));
|
_NotFoundCount++;
|
||||||
return SEQ_FIND_PATTERN;
|
Log.I(string.Format($"NotFoundCount : {_NotFoundCount} "));
|
||||||
|
return SEQ_FIND_PATTERN;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,15 +412,12 @@ namespace WeldingCommon.Sequences
|
|||||||
{
|
{
|
||||||
Log.I(string.Format($"Find Pattern Result Offset:[{_PatternOffsetX},{_PatternOffsetY}] Score:[{_Score}]"));
|
Log.I(string.Format($"Find Pattern Result Offset:[{_PatternOffsetX},{_PatternOffsetY}] Score:[{_Score}]"));
|
||||||
|
|
||||||
// Pattern Find OK
|
|
||||||
if (Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY)) < _InitParam.CheckOffset) {
|
if (Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY)) < _InitParam.CheckOffset) {
|
||||||
Log.FuncI(string.Format($"Check Offset Result True Criteria:[{_InitParam.CheckOffset}] Max Offset:[{Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY))}"));
|
Log.I(string.Format($"Check Offset Result True Criteria:[{_InitParam.CheckOffset}] Max Offset:[{Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY))}"));
|
||||||
return SEQ_SET_VISION_POSITION;
|
return SEQ_SET_VISION_POSITION;
|
||||||
}
|
} else if (_FindPatternCount < 10) {
|
||||||
// Pattern Find nOK >> 설정 범위 넘어감
|
|
||||||
else if (_FindPatternCount < 10) {
|
|
||||||
_CheckOffsetCount++;
|
_CheckOffsetCount++;
|
||||||
Log.FuncI(string.Format($"Find Pattern Count[{_FindPatternCount}]"));
|
Log.I(string.Format($"Check Offset Result True Criteria:[{_InitParam.CheckOffset}] Max Offset:[{Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY))}"));
|
||||||
return SEQ_FIND_PATTERN;
|
return SEQ_FIND_PATTERN;
|
||||||
} else {
|
} else {
|
||||||
Log.E(String.Format("ERROR_CHECK_OFFSET_COUNT_OVER"));
|
Log.E(String.Format("ERROR_CHECK_OFFSET_COUNT_OVER"));
|
||||||
|
|||||||
@ -409,7 +409,6 @@ namespace WeldingCommon.Sequences {
|
|||||||
|
|
||||||
//CSV Laser Log 추가
|
//CSV Laser Log 추가
|
||||||
laserLog.Date = DateTime.Now;
|
laserLog.Date = DateTime.Now;
|
||||||
laserLog.WeldType = "Line";
|
|
||||||
laserLog.WeldCondition = param.No + 1;
|
laserLog.WeldCondition = param.No + 1;
|
||||||
laserLog.LaserOnDelay = param.LaserOnDelay;
|
laserLog.LaserOnDelay = param.LaserOnDelay;
|
||||||
laserLog.LaserOffDelay = param.LaserOffDelay;
|
laserLog.LaserOffDelay = param.LaserOffDelay;
|
||||||
@ -419,6 +418,7 @@ namespace WeldingCommon.Sequences {
|
|||||||
laserLog.Power = param.LaserPower1;
|
laserLog.Power = param.LaserPower1;
|
||||||
laserLog.JumpSpeed = param.JumpSpeed;
|
laserLog.JumpSpeed = param.JumpSpeed;
|
||||||
laserLog.MarkSpeed = param.MarkSpeed;
|
laserLog.MarkSpeed = param.MarkSpeed;
|
||||||
|
laserLog.WeldType = "Line";
|
||||||
|
|
||||||
// 2. 스캐너 가공 작업
|
// 2. 스캐너 가공 작업
|
||||||
// 2.1. Wobbel 관련 설정
|
// 2.1. Wobbel 관련 설정
|
||||||
@ -724,9 +724,6 @@ namespace WeldingCommon.Sequences {
|
|||||||
laserLog.StartPointY = obj.PF1.Y;
|
laserLog.StartPointY = obj.PF1.Y;
|
||||||
laserLog.EndPointX = obj.PF2.X;
|
laserLog.EndPointX = obj.PF2.X;
|
||||||
laserLog.EndPointY = obj.PF2.Y;
|
laserLog.EndPointY = obj.PF2.Y;
|
||||||
laserLog.LotID = Status.GetProcessingWeldingData().WorkLotId;
|
|
||||||
laserLog.CellID = Status.GetProcessingWeldingData().WorkCellId;
|
|
||||||
laserLog.HeadNo = Status.GetProcessingWeldingData().WeldingJigNo;
|
|
||||||
Status.GetProcessingWeldingData().APD.Add(laserLog);
|
Status.GetProcessingWeldingData().APD.Add(laserLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,16 +1409,13 @@ namespace WeldingCommon.Sequences {
|
|||||||
|
|
||||||
// 1.스캐너 가공조건 설정
|
// 1.스캐너 가공조건 설정
|
||||||
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
||||||
var laserLog = new ActualProcessUnit();
|
|
||||||
float percentLaser1 = 0;
|
float percentLaser1 = 0;
|
||||||
float percentLaser2 = 0;
|
float percentLaser2 = 0;
|
||||||
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
||||||
|
|
||||||
Log.I(string.Format($"[Arc Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
|
||||||
|
|
||||||
//CSV Laser Log 추가
|
//CSV Laser Log 추가
|
||||||
|
var laserLog = new ActualProcessUnit();
|
||||||
laserLog.Date = DateTime.Now;
|
laserLog.Date = DateTime.Now;
|
||||||
laserLog.WeldType = "Arc";
|
|
||||||
laserLog.WeldCondition = param.No + 1;
|
laserLog.WeldCondition = param.No + 1;
|
||||||
laserLog.LaserOnDelay = param.LaserOnDelay;
|
laserLog.LaserOnDelay = param.LaserOnDelay;
|
||||||
laserLog.LaserOffDelay = param.LaserOffDelay;
|
laserLog.LaserOffDelay = param.LaserOffDelay;
|
||||||
@ -1431,6 +1425,9 @@ namespace WeldingCommon.Sequences {
|
|||||||
laserLog.Power = param.LaserPower1;
|
laserLog.Power = param.LaserPower1;
|
||||||
laserLog.JumpSpeed = param.JumpSpeed;
|
laserLog.JumpSpeed = param.JumpSpeed;
|
||||||
laserLog.MarkSpeed = param.MarkSpeed;
|
laserLog.MarkSpeed = param.MarkSpeed;
|
||||||
|
laserLog.WeldType = "Arc";
|
||||||
|
|
||||||
|
Log.I(string.Format($"[Arc Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
||||||
|
|
||||||
// 2. 스캐너 가공 작업
|
// 2. 스캐너 가공 작업
|
||||||
// 2.1. Wobbel 관련 설정
|
// 2.1. Wobbel 관련 설정
|
||||||
@ -1461,6 +1458,10 @@ namespace WeldingCommon.Sequences {
|
|||||||
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST);
|
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.LIST);
|
||||||
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
_Scanner.JumpAbs(obj.PF1.X + xOffset, obj.PF1.Y + yOffset, eFunctionType.LIST);
|
||||||
Log.I(string.Format($"[Arc Weld] Jump ({obj.PF1.X + xOffset},{obj.PF1.Y + yOffset})"));
|
Log.I(string.Format($"[Arc Weld] Jump ({obj.PF1.X + xOffset},{obj.PF1.Y + yOffset})"));
|
||||||
|
|
||||||
|
//CSV Laser Log 추가
|
||||||
|
laserLog.JumpX = obj.PF1.X + xOffset;
|
||||||
|
laserLog.JumpY = obj.PF1.Y + yOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -1655,22 +1656,19 @@ namespace WeldingCommon.Sequences {
|
|||||||
|
|
||||||
_LastX = obj.PF2.X + xOffset;
|
_LastX = obj.PF2.X + xOffset;
|
||||||
_LastY = obj.PF2.Y + yOffset;
|
_LastY = obj.PF2.Y + yOffset;
|
||||||
|
if (obj.MadebyRCC) {
|
||||||
|
Log.I(string.Format($"[RCC SubPath Arc Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
||||||
|
} else {
|
||||||
|
Log.I(string.Format($"[Arc Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
||||||
|
}
|
||||||
|
|
||||||
//CSV Laser Log 추가
|
//CSV Laser Log 추가
|
||||||
laserLog.StartPointX = obj.PF1.X;
|
laserLog.StartPointX = obj.PF1.X;
|
||||||
laserLog.StartPointY = obj.PF1.Y;
|
laserLog.StartPointY = obj.PF1.Y;
|
||||||
laserLog.EndPointX = obj.PF2.X;
|
laserLog.EndPointX = obj.PF2.X;
|
||||||
laserLog.EndPointY = obj.PF2.Y;
|
laserLog.EndPointY = obj.PF2.Y;
|
||||||
laserLog.LotID = Status.GetProcessingWeldingData().WorkLotId;
|
|
||||||
laserLog.CellID = Status.GetProcessingWeldingData().WorkCellId;
|
|
||||||
Status.GetProcessingWeldingData().APD.Add(laserLog);
|
Status.GetProcessingWeldingData().APD.Add(laserLog);
|
||||||
|
|
||||||
if (obj.MadebyRCC) {
|
|
||||||
Log.I(string.Format($"[RCC SubPath Arc Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
|
||||||
} else {
|
|
||||||
Log.I(string.Format($"[Arc Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadArc3PScannerParam(Arc3Point obj)
|
private void LoadArc3PScannerParam(Arc3Point obj)
|
||||||
@ -1681,26 +1679,12 @@ namespace WeldingCommon.Sequences {
|
|||||||
|
|
||||||
// 1.스캐너 가공조건 설정
|
// 1.스캐너 가공조건 설정
|
||||||
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
ScannerParam param = ScannerCanvasUserCtrl.ScannerParams[obj.ScannerParamNo];
|
||||||
var laserLog = new ActualProcessUnit();
|
|
||||||
float percentLaser1 = 0;
|
float percentLaser1 = 0;
|
||||||
float percentLaser2 = 0;
|
float percentLaser2 = 0;
|
||||||
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
SetScannerProcessCondition(param, out percentLaser1, out percentLaser2);
|
||||||
|
|
||||||
Log.I(string.Format($"[Arc3P Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
Log.I(string.Format($"[Arc3P Weld] Weld Condition(No:{param.No + 1}) Setting(LaserOnDelay:{param.LaserOnDelay},LaserOffDelay:{param.LaserOffDelay},JumpDelay:{param.JumpDelay},MarkDelay:{param.MarkDelay},PolygonDelay:{param.PolygonDelay},Power:{param.LaserPower1},JumpSpeed:{param.JumpSpeed},MarkSpeed:{param.MarkSpeed})"));
|
||||||
|
|
||||||
//CSV Laser Log 추가
|
|
||||||
laserLog.Date = DateTime.Now;
|
|
||||||
laserLog.WeldType = "Arc3";
|
|
||||||
laserLog.WeldCondition = param.No + 1;
|
|
||||||
laserLog.LaserOnDelay = param.LaserOnDelay;
|
|
||||||
laserLog.LaserOffDelay = param.LaserOffDelay;
|
|
||||||
laserLog.JumpDelay = param.JumpDelay;
|
|
||||||
laserLog.MarkDelay = param.MarkDelay;
|
|
||||||
laserLog.PolygonDelay = param.PolygonDelay;
|
|
||||||
laserLog.Power = param.LaserPower1;
|
|
||||||
laserLog.JumpSpeed = param.JumpSpeed;
|
|
||||||
laserLog.MarkSpeed = param.MarkSpeed;
|
|
||||||
|
|
||||||
// 2. 스캐너 가공 작업
|
// 2. 스캐너 가공 작업
|
||||||
// 2.1. Wobbel 관련 설정
|
// 2.1. Wobbel 관련 설정
|
||||||
// Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행
|
// Snowman 사용 모드가 아닐 경우 Wobbel 모드 실행
|
||||||
@ -1925,16 +1909,6 @@ namespace WeldingCommon.Sequences {
|
|||||||
|
|
||||||
_LastX = obj.PF2.X + xOffset;
|
_LastX = obj.PF2.X + xOffset;
|
||||||
_LastY = obj.PF2.Y + yOffset;
|
_LastY = obj.PF2.Y + yOffset;
|
||||||
|
|
||||||
//CSV Laser Log 추가
|
|
||||||
laserLog.StartPointX = obj.PF1.X;
|
|
||||||
laserLog.StartPointY = obj.PF1.Y;
|
|
||||||
laserLog.EndPointX = obj.PF2.X;
|
|
||||||
laserLog.EndPointY = obj.PF2.Y;
|
|
||||||
laserLog.LotID = Status.GetProcessingWeldingData().WorkLotId;
|
|
||||||
laserLog.CellID = Status.GetProcessingWeldingData().WorkCellId;
|
|
||||||
Status.GetProcessingWeldingData().APD.Add(laserLog);
|
|
||||||
|
|
||||||
if (obj.MadebyRCC) {
|
if (obj.MadebyRCC) {
|
||||||
Log.I(string.Format($"[RCC SubPath Arc3P Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
Log.I(string.Format($"[RCC SubPath Arc3P Weld] Arc center ({obj.CenterPointF.X + xOffset},{obj.CenterPointF.Y + yOffset}), Sweep angle : ({obj.SweepAngle})"));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -52,14 +52,12 @@ namespace WeldingCommon.Settings
|
|||||||
var forRecipes = VisionRecipeManager.GetFovRecipes(forInfos);
|
var forRecipes = VisionRecipeManager.GetFovRecipes(forInfos);
|
||||||
if (forRecipes == null)
|
if (forRecipes == null)
|
||||||
return;
|
return;
|
||||||
|
foreach (var forRecipe in forRecipes) {
|
||||||
#warning 여기서 이거 왜 새로 저장하는건지 확인 필요함
|
// PixelSize
|
||||||
//foreach (var forRecipe in forRecipes) {
|
forRecipe.CalFovRecipe.PixelSize.X = SysParam.CameraPixelSize;
|
||||||
// // PixelSize
|
forRecipe.CalFovRecipe.PixelSize.Y = SysParam.CameraPixelSize;
|
||||||
// forRecipe.CalFovRecipe.PixelSize.X = SysParam.CameraPixelSize;
|
}
|
||||||
// forRecipe.CalFovRecipe.PixelSize.Y = SysParam.CameraPixelSize;
|
RecipeFileManager.SaveVisionRecipe();
|
||||||
//}
|
|
||||||
//RecipeFileManager.SaveVisionRecipe();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace WeldingCommon.Utils
|
|
||||||
{
|
|
||||||
public class ChangeChecker
|
|
||||||
{
|
|
||||||
private static Dictionary<string, bool> mapping = new Dictionary<string, bool>();
|
|
||||||
public static bool IsChangedBool(string Resource, bool value, bool defaultVal = false)
|
|
||||||
{
|
|
||||||
if (mapping.ContainsKey(Resource) == false) {
|
|
||||||
mapping[Resource] = defaultVal;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping[Resource] == value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping[Resource] = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static bool IsChangedBoolMonitoring(string Resource, bool value, bool MonitoringValue, bool defaultVal = false)
|
|
||||||
{
|
|
||||||
if (mapping.ContainsKey(Resource) == false) {
|
|
||||||
mapping[Resource] = defaultVal;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping[Resource] == value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping[Resource] = value;
|
|
||||||
|
|
||||||
if(mapping[Resource] == MonitoringValue)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -61,15 +61,6 @@
|
|||||||
<DataGridTextColumn Header="Master Y" Binding="{Binding MasterY}"/>
|
<DataGridTextColumn Header="Master Y" Binding="{Binding MasterY}"/>
|
||||||
<DataGridTextColumn Header="Vision X" Binding="{Binding VisionX}"/>
|
<DataGridTextColumn Header="Vision X" Binding="{Binding VisionX}"/>
|
||||||
<DataGridTextColumn Header="Vision Y" Binding="{Binding VisionY}"/>
|
<DataGridTextColumn Header="Vision Y" Binding="{Binding VisionY}"/>
|
||||||
<DataGridTemplateColumn Header="Get Center Count">
|
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Button Content="Click"
|
|
||||||
Command="{Binding DataContext.CMD_GetCenterCnt, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
|
||||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
|
||||||
</DataTemplate>
|
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
|
||||||
</DataGridTemplateColumn>
|
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|||||||
@ -44,7 +44,6 @@ namespace WeldingCommon.Views
|
|||||||
public ICommand CMD_StopScannerCalibration { get; }
|
public ICommand CMD_StopScannerCalibration { get; }
|
||||||
public ICommand CMD_FindPattern { get; }
|
public ICommand CMD_FindPattern { get; }
|
||||||
public ICommand CMD_CalculateDistance { get; }
|
public ICommand CMD_CalculateDistance { get; }
|
||||||
public ICommand CMD_GetCenterCnt { get; }
|
|
||||||
|
|
||||||
//public ICommand CMD_ChangedCaltype { get; }
|
//public ICommand CMD_ChangedCaltype { get; }
|
||||||
//public ICommand CMD_SeqStop { get; }
|
//public ICommand CMD_SeqStop { get; }
|
||||||
@ -183,7 +182,6 @@ namespace WeldingCommon.Views
|
|||||||
CMD_StopScannerCalibration = new DelegateCommand(PerformCmdStopScannerCalibration);
|
CMD_StopScannerCalibration = new DelegateCommand(PerformCmdStopScannerCalibration);
|
||||||
CMD_FindPattern = new DelegateCommand(PerformCmdFindPattern);
|
CMD_FindPattern = new DelegateCommand(PerformCmdFindPattern);
|
||||||
CMD_CalculateDistance = new DelegateCommand(PerformCmdCalculateDistance);
|
CMD_CalculateDistance = new DelegateCommand(PerformCmdCalculateDistance);
|
||||||
CMD_GetCenterCnt = new DelegateCommand(PerformCmdGetCenterCount);
|
|
||||||
|
|
||||||
_MonitorTimer = new DispatcherTimer();
|
_MonitorTimer = new DispatcherTimer();
|
||||||
_MonitorTimer.Tick += OnMonitoring;
|
_MonitorTimer.Tick += OnMonitoring;
|
||||||
@ -193,7 +191,6 @@ namespace WeldingCommon.Views
|
|||||||
_Aurora.EventObservable.AsObservable(CommonSequenceIds.SeqScannerCalibration)
|
_Aurora.EventObservable.AsObservable(CommonSequenceIds.SeqScannerCalibration)
|
||||||
.ObserveOnDispatcher().Subscribe(x => OnUpdateCorrectionTable(x));
|
.ObserveOnDispatcher().Subscribe(x => OnUpdateCorrectionTable(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitVariable()
|
private void InitVariable()
|
||||||
{
|
{
|
||||||
GridRowCount = 13;
|
GridRowCount = 13;
|
||||||
@ -621,19 +618,6 @@ namespace WeldingCommon.Views
|
|||||||
Log.W($"{e.Message}");
|
Log.W($"{e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PerformCmdGetCenterCount(object obj)
|
|
||||||
{
|
|
||||||
_Scanner.GetXYPos(out double currentX, out double currentY);
|
|
||||||
|
|
||||||
// Vision Scanner Calibration인 경우
|
|
||||||
int visionBitX = (int)(currentX * _Scanner.Config.ScaleXYFactor);
|
|
||||||
int visionBitY = (int)(currentY * _Scanner.Config.ScaleXYFactor);
|
|
||||||
|
|
||||||
VisionCorrectionList[SelectedRowIndex].VisionX = visionBitX;
|
|
||||||
VisionCorrectionList[SelectedRowIndex].VisionY = visionBitY;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public class CorrectionUnit : NotifyPropertyChangedBase
|
public class CorrectionUnit : NotifyPropertyChangedBase
|
||||||
{
|
{
|
||||||
@ -663,4 +647,5 @@ namespace WeldingCommon.Views
|
|||||||
private double _Distance;
|
private double _Distance;
|
||||||
public double Distance { get => _Distance; set => SetProperty(ref _Distance, value); }
|
public double Distance { get => _Distance; set => SetProperty(ref _Distance, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -248,7 +248,6 @@
|
|||||||
<Compile Include="Settings\SystemParameter.cs" />
|
<Compile Include="Settings\SystemParameter.cs" />
|
||||||
<Compile Include="Settings\SystemParameterManager.cs" />
|
<Compile Include="Settings\SystemParameterManager.cs" />
|
||||||
<Compile Include="Status.cs" />
|
<Compile Include="Status.cs" />
|
||||||
<Compile Include="Utils\ChangeChecker.cs" />
|
|
||||||
<Compile Include="Utils\CSV_Manager.cs" />
|
<Compile Include="Utils\CSV_Manager.cs" />
|
||||||
<Compile Include="Utils\ExcelManagementUnit.cs" />
|
<Compile Include="Utils\ExcelManagementUnit.cs" />
|
||||||
<Compile Include="Utils\ImageUtil.cs" />
|
<Compile Include="Utils\ImageUtil.cs" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user