CellInfoScheduler 프로그램 최초 업로드
This commit is contained in:
parent
54b6b6ccdc
commit
614b5f1a5b
123
Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs
Normal file
123
Machines/ILSOS_CCW_H52A/Datas/CellInfoScheduler.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ILSOS_CCW_H52A.Sequences;
|
||||
using ILSOS_CCW_H52A.Data;
|
||||
|
||||
namespace ILSOS_CCW_H52A.Data
|
||||
{
|
||||
// 물리 지그 번호 (0-based enum, 1-based 변환: (eJigNo)(jigNo - 1))
|
||||
public enum eJigNo
|
||||
{
|
||||
Jig1, Jig2, Jig3, Jig4,
|
||||
Jig5, Jig6, Jig7, Jig8,
|
||||
Jig9, Jig10, Jig11, Jig12,
|
||||
Jig13, Jig14, Jig15, Jig16,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary<eJigNo, JigInfo> 상속으로 물리 지그 번호 직접 접근과
|
||||
/// 파이프라인 단계 접근을 동시에 지원하는 셀 스케줄러.
|
||||
///
|
||||
/// - 물리 지그 접근: scheduler[eJigNo.Jig5]
|
||||
/// - 파이프라인 접근: scheduler.Prefetch1, scheduler.Prefetch2
|
||||
///
|
||||
/// 3단계 파이프라인: Prefetch2 → Prefetch1 → ReportTarget
|
||||
/// Prefetch2 : 셀 정보 수신 완료, 스캐너 리스트 업로드 전
|
||||
/// Prefetch1 : 업로드 완료, 실행 중 — EncoderMonitor 감시 + 완료 체크 대상
|
||||
/// ReportTarget: 완료, 보고 대기
|
||||
///
|
||||
/// Shift()는 Prefetch2→Prefetch1만 전진. GC 할당 없음.
|
||||
/// Prefetch1 ← Prefetch2 ← this[nextJig]
|
||||
/// </summary>
|
||||
public class CellInfoScheduler : Dictionary<eJigNo, JigInfo>
|
||||
{
|
||||
public JigInfo Prefetch2 { get; private set; } // 전전 셀: 셀 정보 수신, 업로드 전
|
||||
public JigInfo Prefetch1 { get; private set; } // 전 셀: 업로드 완료, 실행 중 / 완료 체크 대상
|
||||
|
||||
/// 현재 보고 대상 JigInfo (CheckScannerListComplete에서 지정, 보고 완료 후 null)
|
||||
public JigInfo ReportTarget { get; set; }
|
||||
|
||||
// 재시작 보존용 독립 슬롯 — Reset()에서 건드리지 않음
|
||||
private readonly JigInfo _pendingSlot = new JigInfo();
|
||||
|
||||
// 재시작 전 미완료 보고 슬롯 (유효 시 non-null)
|
||||
public JigInfo PendingComplete => HasPendingComplete ? _pendingSlot : null;
|
||||
|
||||
// 재시작 보존 보고가 있는지
|
||||
public bool HasPendingComplete
|
||||
=> _pendingSlot.IsCanExist && !_pendingSlot.ReportComplete;
|
||||
|
||||
// 현재 활성 보고 슬롯 — 재시작 pending 우선
|
||||
public JigInfo ActiveReportSlot
|
||||
=> HasPendingComplete ? _pendingSlot : ReportTarget;
|
||||
|
||||
// 보고가 필요한 상태인지 (정상 + 재시작 모두 포함)
|
||||
public bool HasReport
|
||||
=> HasPendingComplete
|
||||
|| (ReportTarget != null && !ReportTarget.ReportComplete);
|
||||
|
||||
public CellInfoScheduler()
|
||||
{
|
||||
foreach (eJigNo no in Enum.GetValues(typeof(eJigNo)))
|
||||
Add(no, new JigInfo());
|
||||
}
|
||||
|
||||
// 1-based jigNo (_WeldingJigNo 등) → 0-based eJigNo 변환 편의 인덱서
|
||||
public JigInfo this[int jigNo] {
|
||||
get => base[(eJigNo)(jigNo - 1)];
|
||||
}
|
||||
|
||||
// Reset() 전에 호출 — 미완료 보고가 있으면 보류 슬롯(_pendingSlot)에 복사하여 보존.
|
||||
public void SavePendingComplete()
|
||||
{
|
||||
if (ReportTarget != null && ReportTarget.IsCanExist
|
||||
&& ReportTarget.WeldComplete && !ReportTarget.ReportComplete)
|
||||
_pendingSlot.CopyFrom(ReportTarget);
|
||||
}
|
||||
|
||||
// 보고 완료 처리 — ReportTarget 마킹 및 _pendingSlot 클리어.
|
||||
// GetReportCellResult_SeqResult 성공 시 호출.
|
||||
public void CompleteReport()
|
||||
{
|
||||
ReportTarget?.SetReportComplete(true);
|
||||
ReportTarget = null;
|
||||
_pendingSlot.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefetch2→Prefetch1 한 칸 전진. GC 할당 없음.
|
||||
/// 새 Prefetch2 슬롯은 Clear 후 반환 — 호출자가 셀 정보를 채워야 한다.
|
||||
/// </summary>
|
||||
/// <param name="nextJig">새 Prefetch2로 지정할 물리 지그 (eJigNo)</param>
|
||||
public void Shift(eJigNo nextJig)
|
||||
{
|
||||
Prefetch1 = Prefetch2;
|
||||
Prefetch2 = this[nextJig];
|
||||
Prefetch2.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 전체 초기화 (AutoRun 시작 시 호출).
|
||||
/// SavePendingComplete() 호출 후 이 메서드를 호출할 것.
|
||||
/// _pendingSlot은 재시작 보고 보존을 위해 건드리지 않음.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
foreach (var info in Values)
|
||||
info.Clear();
|
||||
|
||||
Prefetch2 = null;
|
||||
Prefetch1 = null;
|
||||
ReportTarget = null;
|
||||
// _pendingSlot: SavePendingComplete()가 복사해 둔 데이터를 유지
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 스케줄러 자체는 Clear 할 수 없도록 함
|
||||
/// </summary>
|
||||
public new void Clear()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
150
Machines/ILSOS_CCW_H52A/Datas/JigInfo.cs
Normal file
150
Machines/ILSOS_CCW_H52A/Datas/JigInfo.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using AuroraLaserScanner;
|
||||
using System;
|
||||
using WeldingCommon.Data;
|
||||
|
||||
namespace ILSOS_CCW_H52A.Data
|
||||
{
|
||||
public class JigInfo
|
||||
{
|
||||
// --- 지그 식별 ---
|
||||
public int JigNo; // 물리 지그 번호 (1-based, -1: 미설정)
|
||||
|
||||
// --- 스캐너 리스트 파라미터 (ReadyScannerList에서 채워짐) ---
|
||||
public eListNo ListNo;
|
||||
public DateTime WriteTime;
|
||||
public double StartAngle;
|
||||
public int WeldingCount;
|
||||
|
||||
// --- 캔 유무 / 용접 상태 ---
|
||||
public bool IsCanExist;
|
||||
public bool IsWelding;
|
||||
public bool WeldComplete;
|
||||
public DateTime WeldStartTime;
|
||||
public DateTime WeldEndTime;
|
||||
public TimeSpan WeldingSpanTime; // 스캐너 리스트 실행 시간 (GetTime() 결과)
|
||||
|
||||
// --- CellTracker 수신 정보 (GetReceiveCellInfo_SeqResult에서 채워짐) ---
|
||||
public string LotId;
|
||||
public string CellId;
|
||||
|
||||
// --- 플래그 ---
|
||||
public bool CheckSendCellinfo;
|
||||
public bool CheckSendPLCLaserPower;
|
||||
public bool ReportComplete;
|
||||
|
||||
// --- 리포팅/뷰 용 상세 정보 ---
|
||||
public WeldingData InnerCellInfo;
|
||||
|
||||
public JigInfo()
|
||||
{
|
||||
InnerCellInfo = new WeldingData();
|
||||
Clear();
|
||||
}
|
||||
|
||||
public void SetReportComplete(bool comp) => ReportComplete = comp;
|
||||
|
||||
/// <summary>
|
||||
/// 다른 JigInfo의 모든 필드를 이 슬롯에 복사 (재시작 보존용 pendingSlot에 사용)
|
||||
/// </summary>
|
||||
public void CopyFrom(JigInfo src)
|
||||
{
|
||||
JigNo = src.JigNo;
|
||||
ListNo = src.ListNo;
|
||||
WriteTime = src.WriteTime;
|
||||
StartAngle = src.StartAngle;
|
||||
WeldingCount = src.WeldingCount;
|
||||
IsCanExist = src.IsCanExist;
|
||||
IsWelding = src.IsWelding;
|
||||
WeldComplete = src.WeldComplete;
|
||||
WeldStartTime = src.WeldStartTime;
|
||||
WeldEndTime = src.WeldEndTime;
|
||||
WeldingSpanTime = src.WeldingSpanTime;
|
||||
LotId = src.LotId;
|
||||
CellId = src.CellId;
|
||||
CheckSendCellinfo = src.CheckSendCellinfo;
|
||||
CheckSendPLCLaserPower = src.CheckSendPLCLaserPower;
|
||||
ReportComplete = src.ReportComplete;
|
||||
UpdateCellInfo(src.InnerCellInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 슬롯 전체 초기화 (Shift 시 새 Prefetch2 슬롯에 자동 호출됨)
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
JigNo = -1;
|
||||
ListNo = 0;
|
||||
WriteTime = DateTime.MinValue;
|
||||
StartAngle = 0.0;
|
||||
WeldingCount = -1;
|
||||
|
||||
IsCanExist = false;
|
||||
IsWelding = false;
|
||||
WeldComplete = false;
|
||||
WeldStartTime = DateTime.MinValue;
|
||||
WeldEndTime = DateTime.MinValue;
|
||||
WeldingSpanTime = TimeSpan.Zero;
|
||||
|
||||
LotId = string.Empty;
|
||||
CellId = string.Empty;
|
||||
|
||||
CheckSendCellinfo = false;
|
||||
CheckSendPLCLaserPower = false;
|
||||
ReportComplete = false;
|
||||
|
||||
InnerCellInfo.CellId = string.Empty;
|
||||
InnerCellInfo.LotId = string.Empty;
|
||||
InnerCellInfo.AutoRunStartTime = DateTime.MinValue;
|
||||
InnerCellInfo.WeldingStartTime = DateTime.MinValue;
|
||||
InnerCellInfo.WeldingEndTime = DateTime.MinValue;
|
||||
InnerCellInfo.WeldingSpanTimeMilliseconds = string.Empty;
|
||||
InnerCellInfo.TodayProduct = 0;
|
||||
InnerCellInfo.TotalProduct = 0;
|
||||
InnerCellInfo.RecipeNo = 0;
|
||||
InnerCellInfo.WeldStartTime = string.Empty;
|
||||
InnerCellInfo.WeldTime = string.Empty;
|
||||
InnerCellInfo.WorkCellId = string.Empty;
|
||||
InnerCellInfo.WorkLotId = string.Empty;
|
||||
InnerCellInfo.LBAD_Judge = string.Empty;
|
||||
InnerCellInfo.LDD_Judge = string.Empty;
|
||||
InnerCellInfo.LaserPowerCore = string.Empty;
|
||||
InnerCellInfo.LaserPowerRing = string.Empty;
|
||||
InnerCellInfo.MarkSpeed = string.Empty;
|
||||
InnerCellInfo.FocalLength = string.Empty;
|
||||
InnerCellInfo.WeldingJigNo = string.Empty;
|
||||
InnerCellInfo.LaserPowerByLBAD = string.Empty;
|
||||
InnerCellInfo.CheckCanExist = false;
|
||||
InnerCellInfo.CheckScannerListEnd = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// InnerCellInfo를 WeldingData 로부터 필드 단위로 복사 (GC 할당 없음)
|
||||
/// </summary>
|
||||
public void UpdateCellInfo(WeldingData data)
|
||||
{
|
||||
InnerCellInfo.CellId = data.CellId;
|
||||
InnerCellInfo.LotId = data.LotId;
|
||||
InnerCellInfo.AutoRunStartTime = data.AutoRunStartTime;
|
||||
InnerCellInfo.WeldingStartTime = data.WeldingStartTime;
|
||||
InnerCellInfo.WeldingEndTime = data.WeldingEndTime;
|
||||
InnerCellInfo.WeldingSpanTimeMilliseconds = data.WeldingSpanTimeMilliseconds;
|
||||
InnerCellInfo.TodayProduct = data.TodayProduct;
|
||||
InnerCellInfo.TotalProduct = data.TotalProduct;
|
||||
InnerCellInfo.RecipeNo = data.RecipeNo;
|
||||
InnerCellInfo.WeldStartTime = data.WeldStartTime;
|
||||
InnerCellInfo.WeldTime = data.WeldTime;
|
||||
InnerCellInfo.WorkCellId = data.WorkCellId;
|
||||
InnerCellInfo.WorkLotId = data.WorkLotId;
|
||||
InnerCellInfo.LBAD_Judge = data.LBAD_Judge;
|
||||
InnerCellInfo.LDD_Judge = data.LDD_Judge;
|
||||
InnerCellInfo.LaserPowerCore = data.LaserPowerCore;
|
||||
InnerCellInfo.LaserPowerRing = data.LaserPowerRing;
|
||||
InnerCellInfo.MarkSpeed = data.MarkSpeed;
|
||||
InnerCellInfo.FocalLength = data.FocalLength;
|
||||
InnerCellInfo.WeldingJigNo = data.WeldingJigNo;
|
||||
InnerCellInfo.LaserPowerByLBAD = data.LaserPowerByLBAD;
|
||||
InnerCellInfo.CheckCanExist = data.CheckCanExist;
|
||||
InnerCellInfo.CheckScannerListEnd = data.CheckScannerListEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,15 @@
|
||||
using WeldingCommon;
|
||||
using Aurora;
|
||||
using Aurora.Api;
|
||||
using ILSOS_CCW_H52A.Sequences.ProcessObjects;
|
||||
using WeldingCommon;
|
||||
|
||||
namespace ILSOS_CCW_H52A
|
||||
{
|
||||
public static class AuroraEnvironmentExt
|
||||
{
|
||||
public static ProcessManager GetProcessManager(this IAuroraEnvironment _) => ProcessManager.Instance;
|
||||
public static ProcessManager GetProcessManager(this SequenceContext _) => ProcessManager.Instance;
|
||||
}
|
||||
internal class EquipDef
|
||||
{
|
||||
}
|
||||
|
||||
@ -76,6 +76,8 @@ namespace ILSOS_CCW_H52A
|
||||
base.OnStartUp();
|
||||
|
||||
AuroraEnv.SequenceEntry[SequenceIds.AlarmMonitoring].Start();
|
||||
|
||||
AuroraEnv.GetProcessManager().Init(AuroraEnv);
|
||||
}
|
||||
|
||||
// For Selection LaserDevice
|
||||
|
||||
@ -92,6 +92,8 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Alarm\AlarmHelper.cs" />
|
||||
<Compile Include="Alarm\AlarmManager.cs" />
|
||||
<Compile Include="Datas\CellInfoScheduler.cs" />
|
||||
<Compile Include="Datas\JigInfo.cs" />
|
||||
<Compile Include="Device\IO\IOController.Address.cs" />
|
||||
<Compile Include="Device\IO\IOController.Logic.cs" />
|
||||
<Compile Include="Device\Laser\LaserCoherentArm_IO.cs" />
|
||||
|
||||
@ -3,12 +3,14 @@ using Aurora.Api;
|
||||
using Aurora.Util.HislogPlus;
|
||||
using AuroraLaserScanner;
|
||||
using AuroraPLC;
|
||||
using ILSOS_CCW_H52A.Data;
|
||||
using ILSOS_CCW_H52A.Device;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@ -29,12 +31,15 @@ namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
|
||||
return _Instance;
|
||||
}
|
||||
}
|
||||
private bool usedAnalyzerLog = false;
|
||||
private readonly Logger _log = new Logger("ProcessManager");
|
||||
|
||||
|
||||
private IAuroraEnvironment _env;
|
||||
private PLCControllerCCWH52A _plc;
|
||||
private ScannerCCWH52A _scanner;
|
||||
|
||||
private bool usedAnalyzerLog = false;
|
||||
private readonly Logger _log = new Logger("ProcessManager");
|
||||
public CellInfoScheduler cellScheduler { get; set; }
|
||||
|
||||
public const double compensateEncoderReset = 0.015; // 엔코더 리셋 보상 각도 설정(70도/sec 기준 약 0.015도)
|
||||
public const int RotaryJigCount = 16;
|
||||
@ -48,6 +53,7 @@ namespace ILSOS_CCW_H52A.Sequences.ProcessObjects
|
||||
_env = env;
|
||||
_plc = _env.DeviceManager[DeviceIds.PLCDevice] as PLCControllerCCWH52A;
|
||||
_scanner = _env.DeviceManager[DeviceIds.Scanner] as ScannerCCWH52A;
|
||||
cellScheduler = new CellInfoScheduler();
|
||||
}
|
||||
public IEnumerable<bool> CheckRotaryState()
|
||||
{
|
||||
|
||||
@ -14,9 +14,11 @@ using CoreUnit.Control.UserControl.Canvas;
|
||||
using CoreUnit.Scanner.UserControl.ScannerCanvas;
|
||||
using DB;
|
||||
using Hermes;
|
||||
using ILSOS_CCW_H52A.Data;
|
||||
using ILSOS_CCW_H52A.Device;
|
||||
using ILSOS_CCW_H52A.Models;
|
||||
using ILSOS_CCW_H52A.RMS;
|
||||
using ILSOS_CCW_H52A.Sequences.ProcessObjects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -52,10 +54,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
// TODO: [장비구현필요] 실제 공정 추가
|
||||
const string SEQ_CHECK_LOAD_COMPLETE = "[SeqAutoRunCCWH52A] Check Load Complete";
|
||||
|
||||
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (UploadWeldingList Seq)";
|
||||
const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Process (UploadWeldingList Seq)";
|
||||
const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (UploadWeldingList Seq)";
|
||||
|
||||
public const string SEQ_CHECK_SCANNER_LIST_COMPLETE = "[SeqAutoRunCCWH52A] Check Scanner List Complete";
|
||||
const string SEQ_READY_SCANNER_LIST = "[SeqAutoRunCCWH52A] Ready ScannerList";
|
||||
|
||||
@ -63,6 +61,10 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
const string SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Process (ReceiveCellInfo Seq)";
|
||||
const string SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (ReceiveCellInfo Seq)";
|
||||
|
||||
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Set Sequence Param (UploadWeldingList Seq)";
|
||||
const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Process (UploadWeldingList Seq)";
|
||||
const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "[SeqAutoRunCCWH52A] Get Sequence Result (UploadWeldingList Seq)";
|
||||
|
||||
const string SEQ_EXECUTE_WELDING = "[SeqAutoRunCCWH52A] Execute Welding";
|
||||
const string SEQ_REQUEST_UNLOAD_CELL = "[SeqAutoRunCCWH52A] Request Unload Cell";
|
||||
//const string SEQ_WAIT_LBAD_JUDGE = "[SeqAutoRunCCWH52A] Wait LBAD Judge";
|
||||
@ -101,8 +103,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private SystemParameter _SystemParameter;
|
||||
private ScannerCanvasUserCtrl _ScannerCanvasUserCtrl; //스캐너 동작관련 객체 선언
|
||||
|
||||
private string _LotId = "N/A";
|
||||
private string _CellId = "N/A";
|
||||
private int _ModelNo;
|
||||
|
||||
private IRecipeManager _RecipeManager;
|
||||
@ -117,25 +117,13 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private uint _TotalProduct;
|
||||
|
||||
private double _LaserPowerByLBAD;
|
||||
private int _CompletedJigNo;
|
||||
private static bool isWeled;
|
||||
|
||||
private bool _ModulationMode;
|
||||
|
||||
private DateTime _AutoRunStartTime;
|
||||
private DateTime _WeldingStartTime;
|
||||
private TimeSpan _WeldingSpanTime;
|
||||
private DateTime _WeldEndTime;
|
||||
private TimeSpan _InterfaceSpanTime;
|
||||
private DateTime _InterfaceStartTime;
|
||||
// 연속 지그 간 용접 간격 계산 전용 (보고 데이터 아님 — 인터벌 로그용)
|
||||
private DateTime _prevWeldEndTime;
|
||||
|
||||
private double _CellMeasureCenterOffsetX;
|
||||
private double _CellMeasureCenterOffsetY;
|
||||
|
||||
// MOTF
|
||||
private TimeSpan _WeldInterval;
|
||||
|
||||
private int _LastScannerParamNo = -1; //마지막 작업한 스캔 변수값들이 현재 작업하려는 스캔 변수값과 같은지 판단함(같으면 설정작업을 skip함)
|
||||
private int _EncoderOverflowCount = 0;
|
||||
|
||||
private double _RotaryEncoderOffset = 0;
|
||||
@ -143,10 +131,11 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
private int _WeldingCount = 0;
|
||||
private int _RotaryJigCount = 16;
|
||||
|
||||
// 전전 셀/전 셀/대기 셀/완료 셀 파이프라인 스케줄러 (16개 JigInfo 풀, GC-free)
|
||||
private CellInfoScheduler _CellScheduler;
|
||||
|
||||
private double _WeldingStartAngle;
|
||||
|
||||
private bool isTheFirstListWrite;
|
||||
private bool isTheSecondListWrite;
|
||||
private bool isTheFirstListExecute;
|
||||
private int _RecipeNo;
|
||||
|
||||
@ -176,13 +165,13 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
sb.AddAction(SEQ_CHECK_LOAD_COMPLETE, CheckLoadComplete);
|
||||
|
||||
sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete);
|
||||
sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList);
|
||||
|
||||
sb.AddAction(SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ, SetReceiveCellInfo_SeqParams); // Cell 정보를 받아와 입력한다.
|
||||
sb.AddSubsequence(SEQ_DO_ID_RECEIVE_CELL_INFO_SEQ, SequenceManager.GetSeqBuilder_SeqReceiveCellInfo()); // cell 정보를 받아오는 Sub Seq 실행
|
||||
sb.AddAction(SEQ_GET_PARAMS_RECEIVE_CELL_INFO_SEQ, GetReceiveCellInfo_SeqResult); // Cell 정보를 가져온다
|
||||
|
||||
sb.AddAction(SEQ_CHECK_SCANNER_LIST_COMPLETE, CheckScannerListComplete);
|
||||
sb.AddDecision(SEQ_READY_SCANNER_LIST, ReadyScannerList);
|
||||
|
||||
sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams);
|
||||
sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, SequenceManager.GetSeqBuilder_SeqUploadWeldingList());
|
||||
sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult);
|
||||
@ -203,8 +192,8 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
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[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_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_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_SET_PARAMS_REPORT_CELL_RESULT_SEQ] > sb[SEQ_DO_ID_REPORT_CELL_RESULT_SEQ] > sb[SEQ_GET_RESULT_REPORT_CELL_RESULT_SEQ]
|
||||
@ -299,9 +288,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
_WeldingScannerListNo = eListNo.LIST1;
|
||||
|
||||
_CellMeasureCenterOffsetX = 0.0;
|
||||
_CellMeasureCenterOffsetY = 0.0;
|
||||
|
||||
var currentModelName = context.Recipes.ActivatedModelName();
|
||||
var modelItem = context.GetModel<EquipmentSpecificModel_CCW_H52A>(currentModelName, CommonModelIds.EquipmentSpecificModel);
|
||||
_ModelNo = modelItem.Model_No;
|
||||
@ -322,6 +308,8 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
_CellTracker = context.GetCellTracker();
|
||||
_PLC = context.Devices[DeviceIds.PLCDevice] as PLCControllerCCWH52A;
|
||||
_IO = context.GetIOUnit();
|
||||
_CellScheduler = ProcessManager.Instance.cellScheduler;
|
||||
|
||||
}
|
||||
|
||||
private bool CheckDeviceReady(SequenceContext context)
|
||||
@ -403,15 +391,13 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
_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 상태 체크
|
||||
{
|
||||
///// AutoRun Bit가 OFF인 경우
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_STATUS).data == false) {
|
||||
// AutoRun Request 상태 체크
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_AUTO_REQ).data == false) {
|
||||
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를 켜지 않음.
|
||||
return (int)InitErrorList.PLC_AUTORUN_BIT_OFF;
|
||||
}
|
||||
@ -433,10 +419,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
string[] strArr = Dao.SystemRecipe.WorkRecipeFile.Split('\\');
|
||||
RecipeFileName = strArr[strArr.Length - 1];
|
||||
|
||||
_LastScannerParamNo = -1;
|
||||
|
||||
// 트럼프 TruDisk를 쓰기 위해서는 SetFirstPulseKiller를 사용해야 함.
|
||||
|
||||
// Rotary는 시작 트리거 미사용
|
||||
_Scanner.SetControlMode(0);
|
||||
UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, "[AutoRun] 외부 시작 트리거 DISABLE");
|
||||
@ -455,13 +437,15 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
Log.I(string.Format($"ScannerUnit.InitRotaryOnTheFlyWeldingCount : m_abwRotaryEncoderOffset({_RotaryEncoderOffset}), weldingCount({_WeldingCount}), weldingJigNo({_WeldingJigNo}), rotaryJigCount({_RotaryJigCount})"));
|
||||
|
||||
// 용접 완료 대기 스캐너 List 리셋
|
||||
ResetInputScannerList();
|
||||
WaitingScannerList.Reset();
|
||||
CompleteScannerList.Reset();
|
||||
// JigInfo 풀 스케줄러 초기화 (전전/전/대기/완료 셀 파이프라인)
|
||||
// ── 재시작 전 미완료 보고 보존 ───────────────────────────────────────────────
|
||||
// ReportTarget이 있는 상태로 정지가 들어오면 Reset() 후 슬롯이 Clear()되어 보고 불가.
|
||||
// SavePendingComplete()로 _pendingSlot에 복사한 뒤 Reset()을 호출한다.
|
||||
|
||||
_CellScheduler.SavePendingComplete();
|
||||
_CellScheduler.Reset();
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
isTheFirstListWrite = true; // 작업 시작 시 처음 2개의 List는 입력하고 시작한다
|
||||
isTheSecondListWrite = true;
|
||||
isTheFirstListExecute = true; // 제일 첫 List는 ExecuteList 필요. 이후는 AutoChange
|
||||
|
||||
_PLC.WriteBit(eBitOutput.PC_AUTO_STATUS, true);
|
||||
@ -559,100 +543,80 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
private SequenceActionResult CheckScannerListComplete(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
if (isTheFirstListWrite) // 작업 시작 시, 첫번째 리스트는 바로 쓰고, 바로 시작한다(ExecuteList). 다만 List 명령에 의해 Encoder가 들어올 때까지 대기.
|
||||
{
|
||||
isTheFirstListWrite = false;
|
||||
Log.I("Write the 1st scanner list");
|
||||
|
||||
// Prefetch1 = 2회 전 업로드된 지그 = 현재 물리적으로 레이저 통과 중 = 완료 체크 대상.
|
||||
// Shift()는 이 메서드 이후 ReadyScannerList에서 실행되므로, 이 시점의 Prefetch1이
|
||||
// 원본 코드의 InputScannerList[(listNo-1)]과 동일 대상이다.
|
||||
// 예열 구간: iter 1~2(Pf1=null) → 통과. iter 3~: Pf1=Jig1 → 실제 처리.
|
||||
var jigComplete = _CellScheduler.Prefetch1;
|
||||
if (jigComplete == null) {
|
||||
Log.I($"[Warmup] ScannerList {_WeldingCount}: pipeline not ready, skip complete check");
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
if (!CheckCurrentEncoderAngle(jigComplete.StartAngle)) {
|
||||
// IsCanExist=false(공 지그)는 리스트 실행은 하지만 용접이 없으므로
|
||||
// 엔코더 범위를 벗어나도 에러가 아님
|
||||
if (jigComplete.IsCanExist) {
|
||||
Log.I("ERR_SCANNER_LIST_PROCESSING_TIMEOVER");
|
||||
return SequenceAction.Error();
|
||||
}
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
else {
|
||||
if (isTheSecondListWrite) // 두번째 리스트는 바로 쓰지만, 첫번째 리스트 실행이 완료되면 자동으로 이어서 실행된다(AutoChange)
|
||||
{
|
||||
isTheSecondListWrite = false;
|
||||
Log.I("Write the 2nd scanner list");
|
||||
if (jigComplete.IsCanExist) {
|
||||
#region 용접 시간, 엔코더 측정/기록
|
||||
double elaspedTime = _Scanner.GetTime();
|
||||
|
||||
}
|
||||
else {
|
||||
isWeled = false;
|
||||
// 첫번째나 두번째가 아니라면, 실제 리스트 실행이 끝난 것이기 때문에 완료 처리가 필요
|
||||
CompleteScannerList = InputScannerList[(int)_WeldingScannerListNo - 1];
|
||||
if (jigComplete.WeldComplete) {
|
||||
jigComplete.WeldEndTime = DateTime.Now;
|
||||
jigComplete.WeldingSpanTime = TimeSpan.FromSeconds(elaspedTime);
|
||||
TimeSpan weldInterval = jigComplete.WeldEndTime - _prevWeldEndTime;
|
||||
_prevWeldEndTime = jigComplete.WeldEndTime;
|
||||
|
||||
if (!CheckCurrentEncoderAngle(CompleteScannerList.StartAngle)) {
|
||||
// 에러 상황(현재 Rotary Encoder 값이 정상적인 스캐너 리스트 각도 범위를 벗어남)
|
||||
Log.I("ERR_SCANNER_LIST_PROCESSING_TIMEOVER");
|
||||
// 보고 대상 슬롯 지정 (스케줄러가 관리)
|
||||
_CellScheduler.ReportTarget = jigComplete;
|
||||
|
||||
return SequenceAction.Error();
|
||||
Log.I(string.Format("JigNo : {0}, Weld start : {1}, Weld End : {2}, WeldTime : {3}, interval : {4:F3}",
|
||||
jigComplete.JigNo,
|
||||
jigComplete.WeldStartTime.ToString("HH:mm:ss.fff"),
|
||||
jigComplete.WeldEndTime.ToString("HH:mm:ss.fff"),
|
||||
jigComplete.WeldingSpanTime.TotalMilliseconds,
|
||||
weldInterval.TotalSeconds));
|
||||
|
||||
// WON : 2칸 전에 용접을 진행하지 않아 현재 Angle이 CompleteScannerList.StartAngle + 45 범위를 벗어난 경우라면 에러 상황이 아니므로 에러로 처리 할 필요가 없다
|
||||
// 위에 CheckCurrentEncoderAngle if문 조건 대신 아래 내용으로 테스트 해본 뒤에 적용 필요
|
||||
//if (!CheckCurrentEncoderAngle(CompleteScannerList.StartAngle)) {
|
||||
// // 에러 상황(현재 Rotary Encoder 값이 정상적인 스캐너 리스트 각도 범위를 벗어남)
|
||||
// if (CompleteScannerList.CanExist) {
|
||||
// Log.I("ERR_SCANNER_LIST_PROCESSING_TIMEOVER");
|
||||
// return SequenceAction.Error();
|
||||
// }
|
||||
// return SequenceAction.Ok();
|
||||
}
|
||||
else {
|
||||
if (CompleteScannerList.CanExist) {
|
||||
isWeled = true;
|
||||
#region 용접 시간, 엔코더 측정/기록
|
||||
//_WeldInterval = DateTime.Now - _WeldEndTime;
|
||||
//_WeldEndTime = DateTime.Now;
|
||||
//double elapsedTime = _Scanner.GetTime();
|
||||
//_WeldingSpanTime = TimeSpan.FromSeconds(elapsedTime); // Encoder 대기 넘어간 후의, 실제 스캐너 리스트 실행 시간
|
||||
//_WeldingStartTime = _WeldEndTime.Subtract(_WeldingSpanTime);
|
||||
|
||||
double elaspedTime = _Scanner.GetTime();
|
||||
|
||||
if (CompleteScannerList.WeldComplete) {
|
||||
_WeldInterval = DateTime.Now - _WeldEndTime;
|
||||
_WeldEndTime = DateTime.Now;
|
||||
_WeldingStartTime = CompleteScannerList.WeldStartTime;
|
||||
_WeldingSpanTime = TimeSpan.FromSeconds(elaspedTime);
|
||||
_LotId = CompleteScannerList.LotId;
|
||||
_CellId = CompleteScannerList.CellId;
|
||||
|
||||
Log.I(string.Format("JigNo : {0}, Weld start : {1}, Weld End : {2}, WeldTime : {3}, interval : {4:F3}",
|
||||
CompleteScannerList.JigNo, _WeldingStartTime.ToString("HH:mm:ss.fff"), _WeldEndTime.ToString("HH:mm:ss.fff"), _WeldingSpanTime.TotalMilliseconds, _WeldInterval.TotalSeconds));
|
||||
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + CompleteScannerList.JigNo - 1).data) {
|
||||
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + CompleteScannerList.JigNo - 1, true);
|
||||
Log.I(string.Format($"PC_WELD_COMPLETE_{CompleteScannerList.JigNo} -> true)"));
|
||||
}
|
||||
UpdateProductCount(context);
|
||||
UpdateProductInfoForView();
|
||||
SaveCellAPD();
|
||||
}
|
||||
|
||||
//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_PRODUCT_COUNT;" + _WeldEndTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
double encoder0_0, encoder1_0, encoder0_1, encoder1_1;
|
||||
_Scanner.ReadEncoder(out encoder0_0, out encoder1_0, out encoder0_1, out encoder1_1, true);
|
||||
|
||||
double startEncoderCount = encoder0_0;
|
||||
double endEncoderCount = encoder0_1;
|
||||
double angularVelocity = (endEncoderCount - startEncoderCount) / elaspedTime; // 단위는 [degree/sec]
|
||||
|
||||
Log.I(string.Format("Encoder start : {0:F4}, end : {1:F4}, vel : {2:F2}", startEncoderCount, endEncoderCount, angularVelocity));
|
||||
#endregion
|
||||
#region 스캐너 리스트 Record 파일 기록
|
||||
if (_Scanner.Config.UseRecordSignal) {
|
||||
String RecordFileName = _RecipeManager.ActivatedRecipe().Name + "_Jig#" + CompleteScannerList.JigNo.ToString();
|
||||
string DataFilePath = ProjectUtil.GetDataLogSetting().GetFilePath_ScannerRecordLog(RecordFileName, true);
|
||||
_Scanner.SaveRecord(DataFilePath);
|
||||
}
|
||||
#endregion
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + jigComplete.JigNo - 1).data) {
|
||||
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + jigComplete.JigNo - 1, true);
|
||||
Log.I(string.Format($"PC_WELD_COMPLETE_{jigComplete.JigNo} -> true)"));
|
||||
}
|
||||
UpdateProductCount(context);
|
||||
UpdateProductInfoForView();
|
||||
SaveCellAPD();
|
||||
}
|
||||
|
||||
//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;" + jigComplete.WeldingSpanTime.TotalMilliseconds);
|
||||
UtilUnit.logUnit.SetLog(LogUnit.eLogType.PRODUCT, MethodBase.GetCurrentMethod().Name, "UPDATE_PRODUCT_COUNT;" + jigComplete.WeldEndTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
double encoder0_0, encoder1_0, encoder0_1, encoder1_1;
|
||||
_Scanner.ReadEncoder(out encoder0_0, out encoder1_0, out encoder0_1, out encoder1_1, true);
|
||||
|
||||
double startEncoderCount = encoder0_0;
|
||||
double endEncoderCount = encoder0_1;
|
||||
double angularVelocity = (endEncoderCount - startEncoderCount) / elaspedTime; // 단위는 [degree/sec]
|
||||
|
||||
Log.I(string.Format("Encoder start : {0:F4}, end : {1:F4}, vel : {2:F2}", startEncoderCount, endEncoderCount, angularVelocity));
|
||||
#endregion
|
||||
#region 스캐너 리스트 Record 파일 기록
|
||||
if (_Scanner.Config.UseRecordSignal) {
|
||||
String RecordFileName = _RecipeManager.ActivatedRecipe().Name + "_Jig#" + jigComplete.JigNo.ToString();
|
||||
string DataFilePath = ProjectUtil.GetDataLogSetting().GetFilePath_ScannerRecordLog(RecordFileName, true);
|
||||
_Scanner.SaveRecord(DataFilePath);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
return SequenceAction.Ok();
|
||||
@ -668,14 +632,15 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
// Encoder 반전되는 순간이며, 이 때만 인터락 무시
|
||||
}
|
||||
else if (startAngle <= currentAngle) {
|
||||
if (currentAngle < startAngle + 45)// 다음 리스트 구간이 끝나기 전까지는 완료가 되어야 한다
|
||||
{
|
||||
// 다음 리스트 구간이 끝나기 전까지는 완료가 되어야 한다
|
||||
if (currentAngle < startAngle + 45) {
|
||||
Log.I(string.Format("Current encoder check OK, startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
return true;
|
||||
}
|
||||
else Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
} else
|
||||
Log.W(string.Format("Current encoder check NG(Too late), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
}
|
||||
else Log.W(string.Format("Current encoder check NG(Too early), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
else
|
||||
Log.W(string.Format("Current encoder check NG(Too early), startAngle : {0}, currentAngle : {1})", startAngle, currentAngle));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -727,6 +692,17 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
|
||||
Log.I("Can Exist : " + canExist.ToString() + ", JigNo " + _WeldingJigNo + " ,CountNo " + _WeldingCount + ", StartAngle(Y) : " + _WeldingStartAngle);
|
||||
|
||||
// canExist 여부와 무관하게 매 지그마다 파이프라인 전진
|
||||
// canExist=false 지그도 Shift()해야 Prefetch1 타이밍이 올바르게 유지됨.
|
||||
_CellScheduler.Shift((eJigNo)(_WeldingJigNo - 1));
|
||||
|
||||
_CellScheduler.Prefetch2.JigNo = _WeldingJigNo;
|
||||
_CellScheduler.Prefetch2.ListNo = _WeldingScannerListNo;
|
||||
_CellScheduler.Prefetch2.WriteTime = DateTime.Now;
|
||||
_CellScheduler.Prefetch2.StartAngle = _WeldingStartAngle;
|
||||
_CellScheduler.Prefetch2.WeldingCount = _WeldingCount;
|
||||
_CellScheduler.Prefetch2.IsCanExist = canExist;
|
||||
|
||||
if (canExist) {
|
||||
#region 용접할 Objects 선택
|
||||
if (_WeldingJigNo - 1 < _ScannerCanvasUserCtrl.Model.Layers.Length) {
|
||||
@ -738,16 +714,11 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
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();
|
||||
return SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ;
|
||||
return SEQ_SET_PARAMS_RECEIVE_CELL_INFO_SEQ;
|
||||
}
|
||||
else {
|
||||
return SEQ_EXECUTE_WELDING;
|
||||
@ -814,22 +785,22 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
public bool GetRotaryCanExist(int jigNo)
|
||||
{
|
||||
#region 지그 16개 요청기록 로그 남기기, 빠져나간 캔에 대한 Complete Bit 초기화
|
||||
string result = "";
|
||||
//string result = "";
|
||||
|
||||
for (int i = 1; i <= _RotaryJigCount; i++) {
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data)
|
||||
result += "1, ";
|
||||
else {
|
||||
result += "0, ";
|
||||
//for (int i = 1; i <= _RotaryJigCount; i++) {
|
||||
// if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data)
|
||||
// result += "1, ";
|
||||
// else {
|
||||
// result += "0, ";
|
||||
|
||||
string outId = string.Format("PC_WELD_COMPLETE_{0}", i);
|
||||
// string outId = string.Format("PC_WELD_COMPLETE_{0}", i);
|
||||
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) {
|
||||
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false);
|
||||
Log.I(string.Format($"PC_WELD_COMPLETE_{1 + i} -> FALSE)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data) {
|
||||
// _PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false);
|
||||
// Log.I(string.Format($"PC_WELD_COMPLETE_{1 + i} -> FALSE)"));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//UtilUnit.logUnit.SetLog(LogUnit.eLogType.DEBUG, MethodBase.GetCurrentMethod().Name, string.Format("PLC -> PC 용접 Cmd : ({0})", result));
|
||||
#endregion
|
||||
|
||||
@ -846,8 +817,8 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam() {
|
||||
NeedSetLaserTiming = _ModulationMode,
|
||||
IncludeListStartEnd = false,
|
||||
CellMeasureCenterOffsetX = _CellMeasureCenterOffsetX,
|
||||
CellMeasureCenterOffsetY = _CellMeasureCenterOffsetY,
|
||||
CellMeasureCenterOffsetX = 0,
|
||||
CellMeasureCenterOffsetY = 0,
|
||||
SelectedDrawObjectList = _SelectedDrawObjectList,
|
||||
WeldingScannerListNo = _WeldingScannerListNo,
|
||||
Rotation_Degree = 11.25,
|
||||
@ -864,7 +835,15 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
return SequenceAction.ForceStopByAlarm(AlarmCode.ALARM_SEQUENCE_UploadWeldingList_ResultFailed);
|
||||
//return null;
|
||||
}
|
||||
// 입력한 Scanner List를 완료대기열에 추가
|
||||
// Won : GetProcessingWeldingData().WorkLotId 는 CellTrakcer로 부터 받은 상태의 LotId
|
||||
// GetProcessingWeldingData().LotId 는 AutorunView에 표기할 용접이 완료 된 LotID
|
||||
string LotId = Status.GetProcessingWeldingData().WorkLotId; // CellTracker로 부터 WorkLotID, WorkCellID 받는 구문 추가 후 해당 데이터로 입력 필요
|
||||
string CellId = Status.GetProcessingWeldingData().WorkCellId;
|
||||
|
||||
_CellScheduler.Prefetch2.LotId = LotId;
|
||||
_CellScheduler.Prefetch2.CellId = CellId;
|
||||
Log.FuncI("CellTracker Load");
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
|
||||
@ -919,7 +898,6 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
}
|
||||
private SequenceActionResult EncoderMonitor(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
int EncoderLogCount = 0;
|
||||
double send_time_offset = 0.1;
|
||||
string LotID = "", CellID = "";
|
||||
|
||||
@ -929,40 +907,46 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
double CurrentPosPLC = GetRotaryCurrentPosition();
|
||||
bool WeldingInPosition = encoderX > _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset - 0.1 && encoderX < _Scanner.Config.MarkingRangeMinRotate + 11.25 - send_time_offset + 0.1;
|
||||
|
||||
if (WeldingInPosition) {
|
||||
if (InputScannerList[(int)_WeldingScannerListNo - 1].CanExist) {
|
||||
Log.I($"Fork Before Min Rotate Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {_WeldingScannerListNo}, JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})");
|
||||
if (!_SystemParameter.BypassModeLBAD) {
|
||||
if (InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo == false) {
|
||||
LotID = InputScannerList[(int)_WeldingScannerListNo - 1].LotId;
|
||||
CellID = InputScannerList[(int)_WeldingScannerListNo - 1].CellId;
|
||||
if (currentAngle > InputScannerList[(int)_WeldingScannerListNo - 1].StartAngle) {
|
||||
InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(LotID, CellID, _RecipeNo, _ModelNo, InputScannerList[(int)_WeldingScannerListNo - 1].JigNo);
|
||||
// ── JigScheduler: 포크 내에서 참조 캡처 (Shift와의 경합 방지) ──────
|
||||
// Prefetch1: 2회 전 업로드된 지그 = 현재 물리적으로 실행 중인 지그.
|
||||
// 원본 코드의 InputScannerList[(listNo-1)]과 동일 대상.
|
||||
// Shift()는 메인 시퀀스에서만 호출되므로 루프 시작 시 캡처해도 안전.
|
||||
var executeTarget = _CellScheduler.Prefetch1;
|
||||
|
||||
if (InputScannerList[(int)_WeldingScannerListNo - 1].CheckSendCellinfo == false)
|
||||
Log.I($"[LBAD Interface]SendCellInfo null, LotID [{LotID}], CellID [{CellID}], JigNo [{InputScannerList[(int)_WeldingScannerListNo - 1].JigNo}]");
|
||||
if (WeldingInPosition) {
|
||||
if (executeTarget != null && executeTarget.IsCanExist) {
|
||||
Log.I($"Fork Before Min Rotate Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget.ListNo}, JigNo : ({executeTarget.JigNo})");
|
||||
if (!_SystemParameter.BypassModeLBAD) {
|
||||
if (!executeTarget.CheckSendCellinfo) {
|
||||
LotID = executeTarget.LotId;
|
||||
CellID = executeTarget.CellId;
|
||||
if (currentAngle > executeTarget.StartAngle) {
|
||||
executeTarget.CheckSendCellinfo = _StreamLightLBAD.SendCellInfo(LotID, CellID, _RecipeNo, _ModelNo, executeTarget.JigNo);
|
||||
|
||||
if (!executeTarget.CheckSendCellinfo)
|
||||
Log.I($"[LBAD Interface]SendCellInfo null, LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]");
|
||||
else
|
||||
Log.I($"[StreamLight]SendCellInfo LotID [{LotID}], CellID [{CellID}], JigNo [{InputScannerList[(int)_WeldingScannerListNo - 1].JigNo}]");
|
||||
Log.I($"[StreamLight]SendCellInfo LotID [{LotID}], CellID [{CellID}], JigNo [{executeTarget.JigNo}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserOn))) {
|
||||
if (InputScannerList[(int)_WeldingScannerListNo - 1].WeldStartTime == DateTime.MinValue && InputScannerList[(int)_WeldingScannerListNo - 1].CanExist) {
|
||||
InputScannerList[(int)_WeldingScannerListNo - 1].WeldStartTime = DateTime.Now;
|
||||
InputScannerList[(int)_WeldingScannerListNo - 1].WeldComplete = true;
|
||||
EncoderLogCount = 0;
|
||||
Log.I($"Laser On, Welding Complete. JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})");
|
||||
var LaserIO = _IO._iOUnit.ReadDiBit(Convert.ToInt32(eADIAddress.LaserOn));
|
||||
var IsLaserOn = ChangeChecker.IsChangedBoolMonitoring("LaserOn", LaserIO, true);
|
||||
if (IsLaserOn) {
|
||||
if (executeTarget != null && executeTarget.IsCanExist && executeTarget.WeldStartTime == DateTime.MinValue) {
|
||||
executeTarget.WeldStartTime = DateTime.Now;
|
||||
executeTarget.WeldComplete = true;
|
||||
Log.I($"Laser On, Welding Complete. JigNo : ({executeTarget.JigNo})");
|
||||
}
|
||||
|
||||
if (EncoderLogCount == 0) {
|
||||
Log.I($"Fork Laser On Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {_WeldingScannerListNo}, JigNo : ({InputScannerList[(int)_WeldingScannerListNo - 1].JigNo})");
|
||||
}
|
||||
EncoderLogCount = (EncoderLogCount + 1) % 7;
|
||||
}
|
||||
|
||||
var IsLaserToggle = ChangeChecker.IsChangedBool("LaserToggle", LaserIO);
|
||||
if (IsLaserToggle)
|
||||
Log.I($"Fork Laser On({IsLaserToggle}) Encoder X : ({encoderX}), Encoder Y : ({currentAngle}), PLC Rotary : ({CurrentPosPLC}), List {executeTarget?.ListNo}, JigNo : ({executeTarget?.JigNo})");
|
||||
|
||||
for (int i = 0; i < _RotaryJigCount; i++) {
|
||||
if (_PLC.ReadBit((int)eBitInput.PLC_USE_WELD_JIG_1 + i).data == false) {
|
||||
_PLC.WriteBit((int)eBitOutput.PC_WELD_COMPLETE_1 + i, false);
|
||||
@ -999,22 +983,20 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
{
|
||||
Status.GetProcessingWeldingData().TotalProduct = _TotalProduct;
|
||||
Status.GetProcessingWeldingData().TodayProduct = _TodayProduct;
|
||||
|
||||
Status.GetProcessingWeldingData().AutoRunStartTime = _AutoRunStartTime;
|
||||
|
||||
Status.GetProcessingWeldingData().WeldingStartTime = _WeldingStartTime;
|
||||
Status.GetProcessingWeldingData().WeldingEndTime = _WeldEndTime;
|
||||
Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = _WeldingSpanTime.TotalMilliseconds.ToString();
|
||||
|
||||
// Status.GetProcessingWeldingData().LotId 는 Autorun View에 표기할 용접이 완료 된 LotId 이므로 WorkLotID 와의 구분 확인
|
||||
Status.GetProcessingWeldingData().LotId = _LotId;
|
||||
Status.GetProcessingWeldingData().CellId = _CellId;
|
||||
|
||||
Status.GetProcessingWeldingData().RecipeNo = _RecipeNo;
|
||||
Status.GetProcessingWeldingData().LaserPowerByLBAD = _LaserPowerByLBAD.ToString();
|
||||
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = _CompletedJigNo.ToString();
|
||||
|
||||
// 보고 데이터는 스케줄러의 ActiveReportSlot(ReportTarget 또는 PendingComplete)에서 읽음
|
||||
var report = _CellScheduler.ActiveReportSlot;
|
||||
if (report != null) {
|
||||
Status.GetProcessingWeldingData().LotId = report.LotId;
|
||||
Status.GetProcessingWeldingData().CellId = report.CellId;
|
||||
Status.GetProcessingWeldingData().WeldingStartTime = report.WeldStartTime;
|
||||
Status.GetProcessingWeldingData().WeldingEndTime = report.WeldEndTime;
|
||||
Status.GetProcessingWeldingData().WeldingSpanTimeMilliseconds = report.WeldingSpanTime.TotalMilliseconds.ToString();
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = report.JigNo.ToString();
|
||||
}
|
||||
}
|
||||
private SequenceActionResult SetReportCellResult_SeqParams(SequenceContext context, string id, SequenceActionResult param)
|
||||
{
|
||||
@ -1034,9 +1016,8 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
return null;
|
||||
}
|
||||
|
||||
// 중복 보고 방지 플래그 세팅
|
||||
CompleteScannerList.SetReportComplete(true);
|
||||
isWeled = false;
|
||||
// 보고 완료: ReportTarget.ReportComplete=true 설정 + pendingSlot 클리어
|
||||
_CellScheduler.CompleteReport();
|
||||
|
||||
return SequenceAction.Ok();
|
||||
}
|
||||
@ -1063,18 +1044,19 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
#endregion
|
||||
private string CheckCanWelded(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
|
||||
{
|
||||
// 중복 보고 방지:
|
||||
// - CanExist=false (skip 대상) 는 보고하지 않음(미사용)
|
||||
// - WeldComplete=false (레이저 ON 감지/완료 처리 전) 는 보고하지 않음(미사용)
|
||||
// - ReportComplete=true (이미 보고 완료) 는 다시 보고하지 않음
|
||||
// .시퀀스가 너무 빨리 내려가서 보고하는 케이스로 예상
|
||||
// ── 재시작 전 미완료 보고 우선 처리 ─────────────────────────────────────────
|
||||
// SavePendingComplete()로 보존된 슬롯이 있으면 정상 파이프라인(ReportTarget)보다 우선.
|
||||
if (_CellScheduler.HasPendingComplete) {
|
||||
var p = _CellScheduler.PendingComplete;
|
||||
Log.I($"[PendingReport] 재시작 전 미완료 보고: LotId={p.LotId}, CellId={p.CellId}, JigNo={p.JigNo}");
|
||||
return SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ;
|
||||
}
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// 보고 누락:
|
||||
// - 첫번째, 두번째는 UploadWeldingList를 해야하기 때문에 일단 넘긴다.
|
||||
if (isWeled
|
||||
//CompleteScannerList.CanExist &&
|
||||
//CompleteScannerList.WeldComplete &&
|
||||
&& !CompleteScannerList.ReportComplete)
|
||||
// 정상 보고 경로:
|
||||
// - ReportTarget이 설정돼 있고 아직 보고 완료되지 않은 경우
|
||||
// - 첫번째, 두번째 반복은 SetReportTarget이 호출되지 않으므로 자연스럽게 통과
|
||||
if (_CellScheduler.HasReport)
|
||||
return SEQ_SET_PARAMS_REPORT_CELL_RESULT_SEQ;
|
||||
|
||||
return SEQ_CHECK_CYCLE_STOP;
|
||||
|
||||
@ -760,6 +760,7 @@ namespace ILSOS_CCW_H52A.Sequences
|
||||
if (laserParam != null) {
|
||||
// EDC 보내는 용도
|
||||
Status.GetProcessingWeldingData().LaserPowerCore = laserParam.LaserPower1.ToString();
|
||||
Status.GetProcessingWeldingData().LaserPowerRing = laserParam.LaserPower2.ToString();
|
||||
Status.GetProcessingWeldingData().MarkSpeed = laserParam.MarkSpeed.ToString();
|
||||
Status.GetProcessingWeldingData().FocalLength = (_PLC.ReadDWord((int)eWordInput.PLC_WELDING_FOCAL_LENGTH).data / 1000f).ToString();
|
||||
Status.GetProcessingWeldingData().WeldingJigNo = _WeldingJigNo.ToString();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user