feat:260415 MOTF시퀸스(AutoRunScanner)관련 업데이트

This commit is contained in:
RnD_Welder 2026-04-15 16:34:49 +09:00
parent 1439479989
commit e98384906b
4 changed files with 151 additions and 56 deletions

View File

@ -69,13 +69,18 @@ namespace AuroraLaserScanner
public double MarkingOntheFlyOffsetY { get; set; }
public double MarkingOntheFlyParkingPositionX { get; set; }
public double MarkingOntheFlyParkingPositionY { get; set; }
public double MarkingStartX_1 { get; set; }
public double MarkingStartX_2 { get; set; }
public double XDiff_Page1and2 { get; set; }
public double XDiff_Page3and4 { get; set; }
public eWaitEncoderMode MarkingStartWaitMode { get; set; }
public eOntheFlyCoordinate OnTheFlyCoordinate { get; set; }
public double FlySpeedInterlock { get; set; }
public double RotaryEncoderOffset { get; set; }
public double MOTFStageSpeed { get; set; }
#region 26.04.08 NDY MOTF Limit(추적 오차 한계) 변수 추가 --- RTC5에 있는 보드num 과 x,y,z에 대한 limit bit수를 입력하면 해당 오차 벗어나면 알려주는 메소드가 존재합니다. 현재는 stop을 직접하니깐 변수 추가하고 메소드 추가추가해서 사용하는 방식으로 확인 부탁드립니다.
#region 26.04.08 NDY MOTF Limit(추적 오차 한계) 변수 추가 --- RTC5에 있는 보드num 과 x,y,z에 대한 limit bit수를 입력하면 해당 오차 벗어나면 알려주는 메소드가 존재합니다. 현재는 stop을 직접하니깐 변수 추가하고 메소드 추가추가해서 사용하는 방식으로 확인 부탁드립니다.
[DisplayName("Tracking Error Limit X (mm)")]
public double FlyLimitXmm { get; set; } = 28.0; // 60 FOV 기준 약 90% 지점 - bit로 자동 변환되는지를 확인 해야함.

View File

@ -48,6 +48,7 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms.VisualStyles;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using VisionCommon;
using WeldingCommon;
using WeldingCommon.Alarm;
@ -80,9 +81,11 @@ namespace ILSOS_PrismaticScanner.Sequences
const string SEQ_ENTER = "SEQ_ENTER"; // inputParam 으로 받자.
const string SEQ_CHECK_INIT_CONDITION = "Check Init Condition"; // Check Init Condition
const string SEQ_SET_BEFORE_UPLOAD = "Set Before Upload";
const string SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ = "Set Sequence Param (UploadWeldingList Seq)";
const string SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ = "Process (UploadWeldingList Seq)";
const string SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ = "Get Sequence Result (UploadWeldingList Seq)";
const string SEQ_CHECK_AFTER_UPLOAD = "Check After Upload";
const string SEQ_COMPLETE = "SEQ_COMPLETE"; // 완료
@ -133,6 +136,10 @@ namespace ILSOS_PrismaticScanner.Sequences
private static TimeSpan _ScannerSaveLogTime;
private static DateTime _partialWeldingStartTime;
private int _PageNum;
private double lastX, lastY; // 저장용 값
private double _LastX, _LastY; // 진짜로 UploadWeldingList에 들어갈 값
public SequenceBuilder Builder()
{
var sb = new SequenceBuilder(1000, true);
@ -145,9 +152,11 @@ namespace ILSOS_PrismaticScanner.Sequences
sb.AddAction(SEQ_STANDBY_SCANNER, SetStandbyScanner);
#endregion
sb.AddAction(SEQ_SET_BEFORE_UPLOAD, SetBeforeUpload);
sb.AddAction(SEQ_SET_PARAMS_UPLOAD_WELDING_LIST_SEQ, SetUploadWeldingList_SeqParams);
sb.AddSubsequence(SEQ_DO_ID_UPLOAD_WELDING_LIST_SEQ, CommonSequenceManager.GetSeqBuilder_SeqUploadWeldingList());
sb.AddAction(SEQ_GET_RESULT_UPLOAD_WELDING_LIST_SEQ, GetUploadWeldingList_SeqResult);
sb.AddDecision(SEQ_CHECK_AFTER_UPLOAD, CheckAfterUpload);
sb.AddAction(SEQ_DO_COMPONENT_WELDING, DoComponentWelding);
sb.AddAction(SEQ_ACS_MOTION_SET, SetMotion);
sb.AddAction(SEQ_ACS_MOTION_START, StartMotion);
@ -160,9 +169,11 @@ namespace ILSOS_PrismaticScanner.Sequences
> sb[SEQ_CHECK_INIT_CONDITION]
> sb[SEQ_STANDBY_MOTION]
> sb[SEQ_STANDBY_SCANNER]
> sb[SEQ_SET_BEFORE_UPLOAD]
> 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_CHECK_AFTER_UPLOAD]
> sb[SEQ_DO_COMPONENT_WELDING]
> sb[SEQ_ACS_MOTION_SET]
> sb[SEQ_ACS_MOTION_START]
@ -170,6 +181,9 @@ namespace ILSOS_PrismaticScanner.Sequences
> sb[SEQ_COMPLETE]
> sb.Final);
sb.Flows(sb[SEQ_CHECK_AFTER_UPLOAD]
> sb[SEQ_SET_BEFORE_UPLOAD]);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
@ -238,7 +252,7 @@ namespace ILSOS_PrismaticScanner.Sequences
}
_ScannerSaveLogTime = TimeSpan.Zero;
_PageNum = 2;
var startTime = DateTime.Now;
context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime);
@ -302,15 +316,17 @@ namespace ILSOS_PrismaticScanner.Sequences
Log.I("[EncoderReset] 시작");
// SeqUploadWeldingList.MarkingOnTheFlyOn 패턴
_Scanner.SetStartList(_WeldingScannerListNo);
_Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX);
Log.I($"[EncoderReset] SetFlyX: {_Scanner.Config.MarkingOnTheFlyEncoderResolutionX}");
_Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX);
Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartEncoderPositionX}");
// _Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX);
// Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartEncoderPositionX}");
_Scanner.StoreEncoder(0);
_Scanner.SaveAndRestartTimer();
Log.I("[EncoderReset] 완료 - Stage(0) = Scanner(0) 동기화");
return SequenceAction.Ok();
}
@ -333,7 +349,34 @@ namespace ILSOS_PrismaticScanner.Sequences
}
#endregion
private SequenceActionResult SetBeforeUpload(SequenceContext context, string id, SequenceActionResult param)
{
var mainPage = CommonHelper.GetMainPage();
_ScannerCanvasUserCtrl = mainPage.ScannerCanvasCtrlTeaching;
_SelectedObjectList = _ScannerCanvasUserCtrl.Model.Layers[_PageNum-1].Objects;
_LastX = lastX;
_LastY = lastY;
if (_PageNum == 2 || _PageNum == 4) {
if (_PageNum == 0) {
_Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartX_1);
Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartX_1}");
} else {
_Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartX_2);
Log.I($"[EncoderReset] WaitForEncoderX: {_Scanner.Config.MarkingStartX_2}");
}
foreach (IDrawObject obj in _SelectedObjectList) {
if (obj is Line) {
lastX = obj.PF2.X;
lastY = obj.PF2.Y;
}
}
}
Log.D(string.Format($"[SetBeforeUpload] Set Before UploadWeldingList"));
return SequenceAction.Ok();
}
private SequenceActionResult SetUploadWeldingList_SeqParams(SequenceContext context, string id, SequenceActionResult param)
{
Status.SetWorkingPosition(eWorkingPosition.UPLOADING_WELD_LIST);
@ -342,11 +385,14 @@ namespace ILSOS_PrismaticScanner.Sequences
SeqUploadWeldingList_InitParam seqParams = new SeqUploadWeldingList_InitParam()
{
NeedSetLaserTiming = _InitParam.NeedSetLaserTiming,
IncludeListStartEnd = true,
IncludeListStartEnd = false,
CellMeasureCenterOffsetX = _SystemParameter.CellPosMeasureCenterOffsetX + _InitParam.CellCenterOffsetX,
CellMeasureCenterOffsetY = _SystemParameter.CellPosMeasureCenterOffsetY + _InitParam.CellCenterOffsetY,
SelectedDrawObjectList = _SelectedObjectList,
WeldingScannerListNo = _WeldingScannerListNo,
PageNum = _PageNum,
LastX = _LastX,
LastY = _LastY
};
Log.D(string.Format($"[ComponentTeachingRun] Set UploadWelindList Seq Param"));
@ -367,6 +413,13 @@ namespace ILSOS_PrismaticScanner.Sequences
return SequenceAction.Ok();
}
private string CheckAfterUpload(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
_PageNum += 1;
if (_PageNum == 5) _PageNum = 1;
if (_PageNum == 2) return SEQ_DO_COMPONENT_WELDING;
else return SEQ_SET_BEFORE_UPLOAD;
}
private SequenceActionResult DoComponentWelding(SequenceContext context, string id, SequenceActionResult param)
{
@ -445,6 +498,8 @@ namespace ILSOS_PrismaticScanner.Sequences
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND);
_Scanner.WriteDA((uint)eAnalogPortOut.DA2, 0, eFunctionType.COMMAND);
_Scanner.JumpAbs(0, 0, eFunctionType.COMMAND);
_Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY);
_Scanner.SetEndList();
var mesurementTime = DateTime.Now;

View File

@ -116,6 +116,10 @@ namespace CoreUnit.Scanner
double m_markingOntheFlyParkingPositionX;
double m_markingOntheFlyParkingPositionY;
double m_markingStartX_1;
double m_markingStartX_2;
double m_XDiff_Page1and2;
double m_XDiff_Page3and4;
double m_flySpeedInterlock;
double m_rotaryEncoderOffset;
@ -522,6 +526,45 @@ namespace CoreUnit.Scanner
get { return m_markingOntheFlyParkingPositionY; }
}
[Browsable(true)]
[ReadOnly(false)]
[Category("Marking On The Fly(MOTF)")]
[DisplayName("Marking Start X 1 (mm)")]
[Description("Marking Start X 1 (mm)")]
public double MarkingStartX_1 {
set { m_markingStartX_1 = value; }
get { return m_markingStartX_1; }
}
[Browsable(true)]
[ReadOnly(false)]
[Category("Marking On The Fly(MOTF)")]
[DisplayName("Marking Start X 2 (mm)")]
[Description("Marking Start X 2 (mm)")]
public double MarkingStartX_2 {
set { m_markingStartX_2 = value; }
get { return m_markingStartX_2; }
}
[Browsable(true)]
[ReadOnly(false)]
[Category("Marking On The Fly(MOTF)")]
[DisplayName("X Diff Page 1 & 2 (mm)")]
[Description("X Diff Page 1 & 2 (mm)")]
public double XDiff_Page1and2 {
set { m_XDiff_Page1and2 = value; }
get { return m_XDiff_Page1and2; }
}
[Browsable(true)]
[ReadOnly(false)]
[Category("Marking On The Fly(MOTF)")]
[DisplayName("X Diff Page 3 & 4 (mm)")]
[Description("X Diff Page 3 & 4 (mm)")]
public double XDiff_Page3and4 {
set { m_XDiff_Page3and4 = value; }
get { return m_XDiff_Page3and4; }
}
[Browsable(true)]
[ReadOnly(false)]
[Category("Marking On The Fly(MOTF)")]

View File

@ -8,6 +8,7 @@ using DB;
using Hermes;
using Matrox.MatroxImagingLibrary;
using Newtonsoft.Json;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Configuration;
@ -72,7 +73,7 @@ namespace WeldingCommon.Sequences
private static int _CenterRingRatio; // Center Ring의 파워 비율
private static float _LaserPowerRatio; // Laser에서 출력 파워 비율
private bool isFirst = true;
private static SeqUploadWeldingList_OutParam result;
const int ROTATION_DEGREE = 15; // 15도 설정, 하나의 지그가 30도 이므로, 15도부터 돌도록 설정됨.
@ -87,7 +88,7 @@ namespace WeldingCommon.Sequences
sb.AddAction(SEQ_ENTER, Sequence_Enter);
sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기
sb.AddAction(SEQ_MARKING_ON_THE_FLY_ON, MarkingOnTheFlyOn);
sb.AddAction(SEQ_MARKING_ON_THE_FLY_ON, MarkingOnTheFlyOn);
sb.AddAction(SEQ_RECORD_SIGNAL_ON, RecordSignalOn);
sb.AddAction(SEQ_LOAD_DRAW_OBJECT_SCANNER_PARAM, LoadDrawObjectScannerParam);
sb.AddAction(SEQ_MARKING_ON_THE_FLY_OFF, MarkingOnTheFlyOff);
@ -149,8 +150,13 @@ namespace WeldingCommon.Sequences
_LaserPowerCalParam.Initialize(_LaserPowerCalParam.PowerCalibrationCenterBeamCSVFile, _LaserPowerCalParam.PowerCalibrationRingBeamCSVFile);
_FlyOffsetX = 0;
_FlyOffsetY = 0;
_FlyOffsetY = 0;
if (_InitParam.PageNum == 1 || _InitParam.PageNum == 2)
_FlyOffsetY += _Scanner.Config.XDiff_Page1and2;
else
_FlyOffsetY += _Scanner.Config.XDiff_Page3and4;
return true;
}
@ -225,41 +231,9 @@ namespace WeldingCommon.Sequences
return SEQ_MARKING_ON_THE_FLY_ON;
}
// MOTF 지원 중
// MOTF 지원 중
private SequenceActionResult MarkingOnTheFlyOn(SequenceContext context, string id, SequenceActionResult param)
{
if (_Scanner.Config.UseMarkingOnTheFly) {
if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) {
// 1. Linear Track OTF 활성화 및 엔코더 초기화
_Scanner.SetFlyX(_Scanner.Config.MarkingOnTheFlyEncoderResolutionX);
// 2. 엔코더 특정 위치갈 때까지 대기
_Scanner.WaitForEncoderX(_Scanner.Config.MarkingStartEncoderPositionX);
_FlyOffsetX = _Scanner.Config.MarkingOntheFlyOffsetX;
_FlyOffsetY = _Scanner.Config.MarkingOntheFlyOffsetY;
} else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) {
Log.I(string.Format("MOTF 사용, Rotate 보상"));
// 1. 엔코더 값이 들어오면 바로 X(Rotary) Encoder 리셋
_Scanner.SetFlyRotate(_Scanner.Config.MarkingOnTheFlyEncoderResolutionRotate);
// 2. 일괄 회전.(OTW 세팅시, Encoder가 0부터 시작하므로)
foreach (IDrawObject obj in _InitParam.SelectedDrawObjectList) {
obj.Rotate(ROTATION_DEGREE, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // +15도 회전
}
// 3. 원하는 용접 시작 각도 올 때까지 기다리기.
double weldingAngle = _Scanner.Config.MarkingRangeMinRotate + ROTATION_DEGREE;
_Scanner.WaitForEncoderRotateX(weldingAngle); // -5도부터 용접시작하고 싶으면 10도 넣으면 됨
// _FlyOffsetX, _FlyOffsetY 값 설정 불필요, 0-0 이면 됨.
}
// 엔코더 기록(용접 시작)
_Scanner.StoreEncoder(0);
_Scanner.SaveAndRestartTimer(); // 이전 용접의 T/T을 가져가고 싶으면 여기서 Reset 하기 전에 GetTime으로 읽어가야 함
}
return SequenceAction.Ok();
}
@ -363,6 +337,20 @@ namespace WeldingCommon.Sequences
}
if (obj is Line) {
if (isFirst && (_InitParam.PageNum==2)) { // 이전 Point 정보가 있고 첫번째 Line인 경우 긴 Line 만들어 Upload
Line LongLine = new Line();
LongLine.PF1 = new PointF((float)_InitParam.LastX, (float)_InitParam.LastY - (float)(_Scanner.Config.XDiff_Page3and4 - _Scanner.Config.XDiff_Page1and2));
LongLine.PF2 = obj.PF1;
LoadLineScannerParam(LongLine);
isFirst = false;
}
if (isFirst && (_InitParam.PageNum == 4)) { // 이전 Point 정보가 있고 첫번째 Line인 경우 긴 Line 만들어 Upload
Line LongLine = new Line();
LongLine.PF1 = new PointF((float)_InitParam.LastX, (float)_InitParam.LastY + (float)(_Scanner.Config.XDiff_Page3and4 - _Scanner.Config.XDiff_Page1and2));
LongLine.PF2 = obj.PF1;
LoadLineScannerParam(LongLine);
isFirst = false;
}
LoadLineScannerParam((Line)obj);
count++;
} else if (obj is Dot) {
@ -1497,24 +1485,24 @@ namespace WeldingCommon.Sequences
private SequenceActionResult MarkingOnTheFlyOff(SequenceContext context, string id, SequenceActionResult param)
{
if (_Scanner.Config.UseMarkingOnTheFly) {
if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) {
// Linear OTW의 경우, 각 Draw Tool에서 좌표 오프셋을 해 주고 있음
//if (_Scanner.Config.UseMarkingOnTheFly) {
// if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.XY) {
// // Linear OTW의 경우, 각 Draw Tool에서 좌표 오프셋을 해 주고 있음
} else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) {
// 여기서 원래 레시피로 돌려주기
foreach (IDrawObject obj in _InitParam.SelectedDrawObjectList) {
obj.Rotate(ROTATION_DEGREE * -1, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // -15도 회전
}
}
// } else if (_Scanner.Config.OnTheFlyCoordinate == eOntheFlyCoordinate.Rotate) {
// // 여기서 원래 레시피로 돌려주기
// foreach (IDrawObject obj in _InitParam.SelectedDrawObjectList) {
// obj.Rotate(ROTATION_DEGREE * -1, new UnitPoint(_Scanner.Config.MarkingOnTheFlyRotateCenterX, _Scanner.Config.MarkingOnTheFlyRotateCenterY)); // -15도 회전
// }
// }
// 추후, Parking Position 을 용접 시작 위치로 자동으로 계산되어 들어가게 개선 필요
_Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY);
// // 추후, Parking Position 을 용접 시작 위치로 자동으로 계산되어 들어가게 개선 필요
// _Scanner.Fly_Return(_Scanner.Config.MarkingOntheFlyParkingPositionX, _Scanner.Config.MarkingOntheFlyParkingPositionY);
// 엔코더 기록(용접 완료)
_Scanner.StoreEncoder(1);
_Scanner.SaveAndRestartTimer();
}
// // 엔코더 기록(용접 완료)
// _Scanner.StoreEncoder(1);
// _Scanner.SaveAndRestartTimer();
//}
return SequenceAction.Ok();
}
@ -1600,6 +1588,10 @@ namespace WeldingCommon.Sequences
public List<IDrawObject> SelectedDrawObjectList { get; set; }
public eListNo WeldingScannerListNo { get; set; }
public double PageNum { get; set; }
public double LastX { get; set; }
public double LastY { get; set; }
}
public class SeqUploadWeldingList_OutParam : OutParam