2026-06-05 13:44:39 +09:00

573 lines
26 KiB
C#

using Aurora.Api;
using AuroraLaserScanner;
using Hermes;
using MilUI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VisionCommon;
using WeldingCommon.Alarm;
using WeldingCommon.Data;
using WeldingCommon.Settings;
namespace WeldingCommon.Sequences
{
public class SeqScannerCalibration
{
static readonly Logger Log = new Logger("SeqScannerCalibration");
const string SEQ_ENTER = "[SeqScannerCalibration] SEQ_ENTER"; // inputParam 으로 받자.
const string SEQ_CHECK_INIT_CONDITION = "[SeqScannerCalibration] Check Init Condition"; // Check Init Condition
const string SEQ_CAPTURE_NEXT_POSITION = "[SeqScannerCalibration] Capture Next Position";
const string SEQ_FIND_PATTERN = "[SeqScannerCalibration] Find Pattern";
const string SEQ_DECISION_FIND_RESULT = "[SeqScannerCalibration] Decision Find Result";
const string SEQ_DECISION_CHECK_OFFSET = "[SeqScannerCalibration] Decision Check Offset";
const string SEQ_SET_VISION_POSITION = "[SeqScannerCalibration] Set Vision Position";
const string SEQ_SET_VISION_POSITION_FAILED = "[SeqScannerCalibration] Set Vision Position Failed";
const string SEQ_DECISION_CHECK_NEXT_POSITION_EXISTS = "[SeqScannerCalibration] Decision Check Next Postion Exists";
const string SEQ_SAVE_RESULT_DATA = "[SeqScannerCalibration] Save Result Data";
const string SEQ_WRITE_COMPLETION_PLC_BIT = "[SeqScannerCalibration] Write Completion PLC Bit";
const string SEQ_COMPLETE = "[SeqScannerCalibration] SEQ_COMPLETE"; // 완료
static class ContextKey
{
public const string KEY_SEQUENCE_RESULT = "KEY_SEQUENCE_RESULT_SeqScannerCalibration";
public const string KEY_SEQUENCE_START_TIME = "KEY_SEQUENCE_START_TIME_SeqScannerCalibration";
}
private SeqScannerCalibration_InitParam _InitParam;
private Scanner _Scanner;
private SystemParameter _SystemParameter;
private FieldScanParams _FieldScanParams;
private PatternResult _PatternResult;
private PatternAgentBase _PatternAgent;
private ProcPatternInfo _ProcPatternInfo;
private PatternInfo _PatternInfo;
private ICameraDisplay _CameraDisplay;
private CameraAgentBase _CameraAgent;
//private eListNo _MarkingGridScannerListNo;
//private double _JumpSpeed;
private List<PointF> _MarkingPositionList_MM; // MM 은 밀리미터 단위 인듯
private int _PositionIndex = 0;
private double _CurrentPositionX = 0;
private double _CurrentPositionY = 0;
private double _PatternOffsetX = 0;
private double _PatternOffsetY = 0;
private int _CheckOffsetCount = 0;
private int _FindPatternCount = 0;
private double _Score = 0;
private object _GrabImage;
private int _JumpSleepTime = 0;
public SequenceBuilder Builder()
{
var sb = new SequenceBuilder(1000, true);
////var sb = new SequenceBuilder(1000, false); // With log
sb.AddAction(SEQ_ENTER, Sequence_Enter);
sb.AddDecision(SEQ_CHECK_INIT_CONDITION, CheckInitCondition); //분기
sb.AddAction(SEQ_CAPTURE_NEXT_POSITION, CaptureNextPosition);
sb.AddAction(SEQ_FIND_PATTERN, FindPattern);
sb.AddDecision(SEQ_DECISION_FIND_RESULT, DecisionFindResult);
sb.AddDecision(SEQ_DECISION_CHECK_OFFSET, DecisionCheckOffset);
sb.AddAction(SEQ_SET_VISION_POSITION_FAILED, SetVisionPositionFailed);
sb.AddAction(SEQ_SET_VISION_POSITION, SetVisionPosition);
sb.AddDecision(SEQ_DECISION_CHECK_NEXT_POSITION_EXISTS, DecisionCheckNextPostionExists);
sb.AddAction(SEQ_SAVE_RESULT_DATA, SaveResultData); // 해당 공정의 정보를 기록 함.
sb.AddAction(SEQ_WRITE_COMPLETION_PLC_BIT, WriteCompletionPLCBit); // 정상적으로 종료 되면, complete bit write
sb.AddAction(SEQ_COMPLETE, Complete);
sb.Flows(sb.Init > sb[SEQ_ENTER] > sb[SEQ_CHECK_INIT_CONDITION]
> sb[SEQ_CAPTURE_NEXT_POSITION] > sb[SEQ_FIND_PATTERN]
> sb[SEQ_DECISION_FIND_RESULT] > sb[SEQ_DECISION_CHECK_OFFSET]
> sb[SEQ_SET_VISION_POSITION] > sb[SEQ_DECISION_CHECK_NEXT_POSITION_EXISTS]
> sb[SEQ_SAVE_RESULT_DATA] > sb[SEQ_WRITE_COMPLETION_PLC_BIT] > sb[SEQ_COMPLETE]);
sb.Flows(sb[SEQ_DECISION_FIND_RESULT] > sb[SEQ_SET_VISION_POSITION_FAILED] > sb[SEQ_DECISION_CHECK_NEXT_POSITION_EXISTS]);
sb.Flows(sb[SEQ_DECISION_FIND_RESULT] > sb[SEQ_FIND_PATTERN]);
sb.Flows(sb[SEQ_DECISION_CHECK_OFFSET] > sb[SEQ_SET_VISION_POSITION_FAILED]);
sb.Flows(sb[SEQ_DECISION_CHECK_OFFSET] > sb[SEQ_FIND_PATTERN]);
sb.Flows(sb[SEQ_DECISION_CHECK_NEXT_POSITION_EXISTS] > sb[SEQ_CAPTURE_NEXT_POSITION]);
sb.Flows(sb[SEQ_CHECK_INIT_CONDITION] > sb[SEQ_COMPLETE] > sb.Final);
sb.OnStopped(OnStopped);
sb.OnForceError(OnForceError);
//sb.Draw("SeqScannerCalibration.pdf");
return sb;
}
private SequenceActionResult Sequence_Enter(SequenceContext context, string id, SequenceActionResult param)
{
Log.I("ScannerCalibration Start");
_InitParam = param.Param as SeqScannerCalibration_InitParam;
_SystemParameter = context.GetSetting<SystemParameter>(CommonSettingIds.SystemParameter);
InitDev(context);
if (!CheckDeviceReady(context)) { //Check Device
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ScannerCalibration_DeviceNotReady);
Log.E("The devices are not active.");
return null;
}
if (InitSequenceVariable(context) == false) {
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ScannerCalibration_InitVariableError);
return null;
}
return SequenceAction.Ok();
}
private bool InitSequenceVariable(SequenceContext context)
{
_FieldScanParams = FieldScanParams.GetInstance();
// 1Step 여부에 따른 position index 값 변경
if (_InitParam.Is1StepCalibration) _PositionIndex = _InitParam.oneStepCalibrationIndex;
else _PositionIndex = 0;
_FindPatternCount = 0;
_JumpSleepTime = 400;
// Initialize MasterPos
_MarkingPositionList_MM = new List<PointF>();
float tempX = 0, tempY = 0;
float posX = 0;
float posY = 0;
for (int column = 0; column < _InitParam.ColumnCount; column++) {
tempX = _InitParam.UnitLength * ((column % _InitParam.ColumnCount) - (_InitParam.ColumnCount - 1) / 2f);
for (int row = 0; row < _InitParam.RowCount; row++) {
tempY = _InitParam.UnitLength * ((row % _InitParam.RowCount) - (_InitParam.RowCount - 1) / 2f);
posX = tempX * (float)Math.Cos(_InitParam.TiltingDegree * Math.PI / 180) - tempY * (float)Math.Sin(_InitParam.TiltingDegree * Math.PI / 180);
posY = tempX * (float)Math.Sin(_InitParam.TiltingDegree * Math.PI / 180) + tempY * (float)Math.Cos(_InitParam.TiltingDegree * Math.PI / 180);
_MarkingPositionList_MM.Add(new PointF(posX, posY));
}
}
// InitializeCameraDevice
//FovInfo는 UI 생성자를 통해 전달된 Params의 FovInfo를 사용한다.
_PatternAgent = FovPatternAgentManager.GetAgent(_InitParam.FovInfo.ToSubSysInfo());
//VisionRecipe - FovRecipes - PatternRecipe에 ProcPatternInfos를 수동으로 추가줘야 Pattern Apply시 ProcPatternInfo가 생성됨
//// Case.1. Aurora Common SW Version
////ProcPatternInfos는 Recipe에 1개만 등록해두고 필요 시 패턴의 apply를 변경하도록 하자
//_ProcPatternInfo = VisionRecipeManager.GetProcPatternInfo(_InitParam.FovInfo, "Align1", eProcPatternId.ProcPattern1);
////ProcPatternInfo로 등록한 PatternInfo(패턴 정보)를 받아오자
//_PatternInfo = _PatternAgent.GetPatternInfo(_InitParam.FovInfo, _ProcPatternInfo.PatternId);
// Case.2. Prismatics SW Version
List<PatternInfo> patterns = _PatternAgent.GetMainPatterns(_InitParam.FovInfo);
_PatternInfo = patterns[1];
// 패턴을 찾는 공정이 있으므로 eDisplayType을 반드시 Pattern으로 해야 한다.
_CameraDisplay = CameraDisplayManager.GetDisplay(_InitParam.FovInfo, eDisplayType.Pattern);
//카메라 에이전트 가져오기
_CameraAgent = CameraAgentManager.GetCameraAgent(_InitParam.FovInfo);
// InitGrabImageBuffer
try {
//GrabImageBuffer를 Update할 필요가 있으면 아래 코드 사용
//IpAdapter.Instance.IpEnvironment.FreeImage(_GrabImage);
_GrabImage = _CameraAgent.CloneImageBuffer();
} catch (Exception e) {
Log.E(e.Message);
}
// ClearCameraDisplay
ClearCameraDisplay();
return true;
}
public void ClearCameraDisplay()
{
if (_CameraAgent != null) {
_CameraDisplay.ClearAllGraphics();
}
}
private void InitDev(SequenceContext context)
{
//Device Init
_Scanner = context.GetLaserScanner();
}
private bool CheckDeviceReady(SequenceContext context)
{
List<string> deviceListToCheck = new List<string>() { CommonDeviceIds.Scanner };
bool isAllDeviceActivated = true;
foreach (string item in deviceListToCheck) {
if (!context.Devices[item].IsActivated) {
isAllDeviceActivated = isAllDeviceActivated && false;
}
}
return isAllDeviceActivated;
}
private bool CheckCondition()
{
if (CheckCondition_Interlock()) {
if (InitializeDeviceStatus()) {
return true;
}
}
return false;
}
private bool CheckCondition_Interlock()
{
// PLC, Data, IO 등 Interlock checking
return true;
}
private bool InitializeDeviceStatus()
{
// Device 의 status 를 맞추자. ScannerCalibration 는 Scanner 를 설정 한다. 초기 설정 해야 하는 값으로
//_scanner._scannerObj.SetJumpSpeed(_systemParameter.FieldScanJumpSpeed);
_Scanner.SetJumpSpeed(_SystemParameter.FieldScanJumpSpeed);
return true;
}
private string CheckInitCondition(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
if (!CheckCondition()) {
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ScannerCalibration_CheckInitCondition);
Log.E("Condition is not in state to start sequence.");
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, false);
return SEQ_COMPLETE;
}
var startTime = DateTime.Now;
context.PutValue(ContextKey.KEY_SEQUENCE_START_TIME, startTime);
Log.D("DoCrossLaserShot Sequence CheckInitCondition");
return SEQ_CAPTURE_NEXT_POSITION;
}
private SequenceActionResult CaptureNextPosition(SequenceContext context, string id, SequenceActionResult param)
{
_CurrentPositionX = _MarkingPositionList_MM[_PositionIndex].X + _InitParam.MasterPosOffsetX;
_CurrentPositionY = _MarkingPositionList_MM[_PositionIndex].Y + _InitParam.MasterPosOffsetY;
//1.스캐너 필드 위치 이동(Jump이동)
_Scanner.JumpAbs(_CurrentPositionX, _CurrentPositionY);
Thread.Sleep(_JumpSleepTime); // 스캐너 점프 이동 후 안정화 시간 추가
Log.I(string.Format($"Move Next Position [{_CurrentPositionX},{_CurrentPositionY}"));
_CheckOffsetCount = 0;
return SequenceAction.Ok();
}
private SequenceActionResult FindPattern(SequenceContext context, string id, SequenceActionResult param)
{
try {
_GrabImage = DoGrab();
_PatternResult = _PatternAgent.Find(_PatternInfo, _GrabImage, _CameraDisplay);
} catch (Exception e) {
Log.E(e.Message);
}
return SequenceAction.Ok();
}
public object DoGrab()
{
_CameraAgent.StopLive();
var image = _GrabImage;
_CameraAgent.GrabSync(_CameraDisplay, ref image);
_GrabImage = image;
return _GrabImage;
}
private string DecisionFindResult(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
double offsetX = 0;
double offsetY = 0;
if (_PatternResult.Status == eFoundStatus.FoundOK) {
Log.I($"PatternResult : {_PatternResult}");
_PatternAgent.Draw(_PatternInfo, _PatternResult, _CameraDisplay);
//patternResult의 X,Y 좌표값을 받아서 Image의 센터와의 차이만큼 계산하여 스캐너 구동 후 다시 매칭
var patternRsultInfo = _PatternResult.MoreInfo as FixtureResult;
offsetX = patternRsultInfo.Origin.X;
offsetY = patternRsultInfo.Origin.Y;
TranslateImageToField(offsetX, offsetY, out _PatternOffsetX, out _PatternOffsetY);
Log.I($"PatternOffsetX : {_PatternOffsetX}, PatternOffsetY : {_PatternOffsetY}");
//스캐너 구동 후 다시 한번 FindPattern후 DecisioCheckOffset으로 넘어감
if (_FindPatternCount < 1) {
_FindPatternCount++;
//_scanner._scannerObj.JumpRel(patternOffsetX, patternOffsetY);
_Scanner.JumpRel(_PatternOffsetX, _PatternOffsetY);
Log.I(string.Format($"Move Rel Position [{_PatternOffsetX},{_PatternOffsetY}"));
Thread.Sleep(_JumpSleepTime); //스캐너 점프 이동 후 안정화 시간 추가
ClearCameraDisplay();
return SEQ_FIND_PATTERN;
} else {
_FindPatternCount = 0;
return SEQ_DECISION_CHECK_OFFSET;
}
} else {
return SEQ_SET_VISION_POSITION_FAILED;
}
}
private void TranslateImageToField(double imgPosX, double imgPosY, out double realPosX, out double realPosY)
{
//여기 수정 필요.. 하드 코딩 되어있으면 안되겠네..
var camConfig = VisionEnv.AuroraEnv.DeviceManager.GetDeviceConfig(eCamId.CAM1.ToString()) as CamConfig;
//var imageWidthChild = camConfig.ImageSize.Width / 2;
//var imageHeightChild = camConfig.ImageSize.Height / 2;
var imageWidthChild = _FieldScanParams.GetimageSizeWidthChild();
var imageHeightChild = _FieldScanParams.GetimageSizeHeightChild();
double moveOffsetX = 0;
double moveOffsetY = 0;
var cameraROIWidth = ((imageWidthChild * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0;
var cameraROIHeight = ((imageHeightChild * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0;
moveOffsetX = ((imgPosX * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0 - cameraROIWidth * 0.5;
moveOffsetY = cameraROIHeight * 0.5 - ((imgPosY * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0;
//Jin : X Filp, Y Flip에 따라서 Offset 수식을 변경해줄 필요 없을 듯.. Flip을 사용하던 안하던 Scanner 입장에서는 동일할테니깐
//if (camConfig.FlipAndRotation.ImageFlip == eImageFlip.LeftToRight) {
// //X Flip
// moveOffsetX = cameraROIWidth * 0.5 - ((imgPosX * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0;
//} else {
// moveOffsetX = ((imgPosX * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0 - cameraROIWidth * 0.5;
//}
//if (camConfig.FlipAndRotation.ImageFlip == eImageFlip.TopToBottom) {
// //Y Flip
// moveOffsetY = ((imgPosY * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0 - cameraROIHeight * 0.5;
//} else {
// moveOffsetY = cameraROIHeight * 0.5 - ((imgPosY * _SystemParameter.CameraPixelSize) / _SystemParameter.LensMagnification) / 1000.0;
//}
//angle은 현재 사용하지 않네..
//double angle = GrabAngle * Math.PI / 180;
double angle = 0;
realPosX = moveOffsetX * Math.Cos(angle) + moveOffsetY * Math.Sin(angle);
realPosY = -moveOffsetX * Math.Sin(angle) + moveOffsetY * Math.Cos(angle);
}
private string DecisionCheckOffset(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
Log.I(string.Format($"Find Pattern Result Offset:[{_PatternOffsetX},{_PatternOffsetY}] Score:[{_Score}]"));
if (Math.Max(Math.Abs(_PatternOffsetX), Math.Abs(_PatternOffsetY)) < _InitParam.CheckOffset) {
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;
} else if (_CheckOffsetCount < 10) {
_CheckOffsetCount++;
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;
} else {
Log.E(String.Format("ERROR_CHECK_OFFSET_COUNT_OVER"));
return SEQ_SET_VISION_POSITION_FAILED;
}
}
private SequenceActionResult SetVisionPosition(SequenceContext context, string id, SequenceActionResult param)
{
double currentX, currentY;
//_scanner._scannerObj.GetXYPos(out currentX, out currentY);
_Scanner.GetXYPos(out currentX, out currentY);
if (_InitParam.IsVisionCalibration) {
// Vision Scanner Calibration인 경우
int visionBitX = (int)(currentX * _Scanner.Config.ScaleXYFactor);
int visionBitY = (int)(currentY * _Scanner.Config.ScaleXYFactor);
//DataGrid에 Vision 좌표 업데이트
//ViewModel에서 이벤트 생성하고 시퀀스에서 이벤트로 주고 TreadSleep 줘보자.. 몇초 줘야하는지는 확인해보자
var updateDataGridItem = new UpdateDataGridItem(_PositionIndex, visionBitX, visionBitY);
context.EventPublisher.Publish(new EventMessage(context.SequenceId, context.SequenceId, updateDataGridItem));
Thread.Sleep(100);
Log.I(string.Format($"UPDATE_VISION_CORRECTION_TABLE;{_PositionIndex};{visionBitX};{visionBitY}"));
} else {
// Laser Scanner Calibration인 경우
int visionBitX = (int)(((_CurrentPositionX - _InitParam.MasterPosOffsetX) * 2 - currentX) * _Scanner.Config.ScaleXYFactor);
int visionBitY = (int)(((_CurrentPositionY - _InitParam.MasterPosOffsetY) * 2 - currentY) * _Scanner.Config.ScaleXYFactor);
var updateDataGridItem = new UpdateDataGridItem(_PositionIndex, (int)visionBitX, (int)visionBitY);
context.EventPublisher.Publish(new EventMessage(context.SequenceId, context.SequenceId, updateDataGridItem));
Thread.Sleep(100);
Log.I(string.Format($"UPDATE_LASER_CORRECTION_TABLE;{_PositionIndex};{visionBitX};{visionBitY}"));
}
return SequenceAction.Ok();
}
private SequenceActionResult SetVisionPositionFailed(SequenceContext context, string id, SequenceActionResult param)
{
if (_InitParam.IsVisionCalibration) {
//DataGrid에 Vision 좌표 업데이트
//ViewModel에서 이벤트 생성하고 시퀀스에서 이벤트로 주고 TreadSleep 줘보자.. 몇초 줘야하는지는 확인해보자
var updateDataGridItem = new UpdateDataGridItem(_PositionIndex, 0, 0);
context.EventPublisher.Publish(new EventMessage(context.SequenceId, context.SequenceId, updateDataGridItem));
Thread.Sleep(100);
Log.I(string.Format($"UPDATE_VISION_CORRECTION_TABLE;{_PositionIndex};{0};{0}"));
} else {
// Laser Scanner Calibration인 경우
var updateDataGridItem = new UpdateDataGridItem(_PositionIndex, 0, 0);
context.EventPublisher.Publish(new EventMessage(context.SequenceId, context.SequenceId, updateDataGridItem));
Thread.Sleep(100);
Log.I(string.Format($"UPDATE_VISION_CORRECTION_TABLE;{_PositionIndex};{0};{0}"));
}
return SequenceAction.Ok();
}
private string DecisionCheckNextPostionExists(SequenceContext context, string id, ICollection<string> branches, SequenceActionResult param)
{
if (_InitParam.Is1StepCalibration) return SEQ_SAVE_RESULT_DATA;
_PositionIndex++;
if (_PositionIndex < _MarkingPositionList_MM.Count) {
return SEQ_CAPTURE_NEXT_POSITION;
} else {
return SEQ_SAVE_RESULT_DATA;
}
}
private SequenceActionResult SaveResultData(SequenceContext context, string id, SequenceActionResult param)
{
// 결과 Data 를 업데이트 함. format 유지, ScannerCalibration 없음
context.PutValue(ContextKey.KEY_SEQUENCE_RESULT, true);
return SequenceAction.Ok();
}
private SequenceActionResult WriteCompletionPLCBit(SequenceContext context, string id, SequenceActionResult param)
{
// 완료 비트 write 하는 Node 추가 필요. format 유지, ScannerCalibration 없음
Log.D("ScannerCalibration Sequence WriteCompletionPLCBit");
return SequenceAction.Ok();
}
private SequenceActionResult Complete(SequenceContext context, string id, SequenceActionResult param)
{
RestoreDeviceStatus();
Log.I("ScannerCalibration Complete");
context.TryGetValue(ContextKey.KEY_SEQUENCE_RESULT, out bool seqResult);
SeqScannerCalibration_OutParam result = new SeqScannerCalibration_OutParam() { Success = seqResult };
if (seqResult == false) {
AlarmManager.Alarm(AlarmCode.ALARM_SEQUENCE_ScannerCalibration_ResultFailed);
}
Log.D("ScannerCalibration Sequence Complete");
_CameraAgent.StartLive(_CameraDisplay);
return SequenceAction.Ok(result);
}
private bool RestoreDeviceStatus()
{
//vision correctiontable로 원복
_Scanner.SelectCorrectionTable(1);
//Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND);
//Scanner 원점 복귀
_Scanner.JumpAbs(0, 0, eFunctionType.COMMAND);
return true;
}
private void OnForceError(SequenceContext arg1, string arg2)
{
//List 실행 종료
_Scanner.StopExecution();
//Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND);
//Scanner 원점 복귀
_Scanner.JumpAbs(0, 0, eFunctionType.COMMAND);
Log.E("ScannerCalibration Sequence is stopped");
}
private void OnStopped(SequenceContext obj)
{
//List 실행 종료
_Scanner.StopExecution();
//Anlog 출력 0으로 변경, efunctiontype을 command로 변경해주면 list가 아니라 직접 변경됨
_Scanner.WriteDA((uint)eAnalogPortOut.DA1, 0, eFunctionType.COMMAND);
//Scanner 원점 복귀
_Scanner.JumpAbs(0, 0, eFunctionType.COMMAND);
Log.E("ScannerCalibration Sequence is stopped");
}
}
public class SeqScannerCalibration_InitParam : InitParam
{
public FovInfo FovInfo { get; set; }
//public eDisplayType _DisplayType { get; set; }
public bool IsVisionCalibration { get; set; }
public int ColumnCount { get; set; }
public int RowCount { get; set; }
public float UnitLength { get; set; }
public float TiltingDegree { get; set; }
public double CheckOffset { get; set; }
public double MasterPosOffsetX { get; set; }
public double MasterPosOffsetY { get; set; }
public bool Is1StepCalibration { get; set; }
public int oneStepCalibrationIndex { get;set;}
}
public class SeqScannerCalibration_OutParam : OutParam
{
// TODO: 몇개가 Vision Fail 되었는지가 나오면 좋음.
}
}