241 lines
8.5 KiB
C#
241 lines
8.5 KiB
C#
|
|
using MainShell.Common;
|
|||
|
|
using MainShell.Hardware;
|
|||
|
|
using MainShell.Log;
|
|||
|
|
using MainShell.ParaSetting.Model;
|
|||
|
|
using MainShell.Vision;
|
|||
|
|
using MaxwellFramework.Core.Interfaces;
|
|||
|
|
using MwFramework.Device;
|
|||
|
|
using MwFramework.ManagerService;
|
|||
|
|
using System;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.Reflection;
|
|||
|
|
using System.Windows;
|
|||
|
|
|
|||
|
|
namespace MainShell.Process
|
|||
|
|
{
|
|||
|
|
public class DefaultWaferMachineAdapter : IWaferMachineAdapter
|
|||
|
|
{
|
|||
|
|
private readonly HardwareManager _hardwareManager;
|
|||
|
|
private readonly IParamList _parameterList;
|
|||
|
|
|
|||
|
|
public DefaultWaferMachineAdapter(HardwareManager hardwareManager, IParameterManager parameterManager)
|
|||
|
|
{
|
|||
|
|
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
|
|||
|
|
_parameterList = parameterManager as IParamList;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public CameraType GetCameraSource(WaferDiePositionContext context)
|
|||
|
|
{
|
|||
|
|
return CameraType.TopPositionCamera;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public MwCamera GetCamera(WaferDiePositionContext context)
|
|||
|
|
{
|
|||
|
|
return ResolveCamera(GetCameraSource(context));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Point GetCameraFieldOfView(WaferDiePositionContext context)
|
|||
|
|
{
|
|||
|
|
DeviceFoundationSetting deviceFoundationSetting = GetDeviceFoundationSetting();
|
|||
|
|
CameraFovSettingItem cameraFovSettingItem = GetCameraFovSettingItem(deviceFoundationSetting, GetCameraSource(context));
|
|||
|
|
if (cameraFovSettingItem == null || cameraFovSettingItem.FovX <= 0d || cameraFovSettingItem.FovY <= 0d)
|
|||
|
|
{
|
|||
|
|
LogManager.LogProcessInfo("晶圆定位:DefaultWaferMachineAdapter 正在使用相机视野默认回退值。");
|
|||
|
|
return new Point(1.0d, 1.0d);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new Point(cameraFovSettingItem.FovX, cameraFovSettingItem.FovY);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public double GetExposureTimeMilliseconds(WaferDiePositionContext context)
|
|||
|
|
{
|
|||
|
|
MwCamera camera = GetCamera(context);
|
|||
|
|
if (camera == null)
|
|||
|
|
{
|
|||
|
|
return 0d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
double exposureTime = 0d;
|
|||
|
|
DriverLibResult result = camera.GetExposureTime(ref exposureTime);
|
|||
|
|
if (result != DriverLibResult.DriverLibNoError || double.IsNaN(exposureTime) || double.IsInfinity(exposureTime) || exposureTime < 0d)
|
|||
|
|
{
|
|||
|
|
return 0d;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return exposureTime;
|
|||
|
|
}
|
|||
|
|
catch (Exception)
|
|||
|
|
{
|
|||
|
|
return 0d;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public CameraCaptureOptions CreateSoftTriggerCaptureOptions(WaferDiePositionContext context)
|
|||
|
|
{
|
|||
|
|
CameraCaptureOptions options = CameraCaptureOptions.CreateSoftTrigger(5000);
|
|||
|
|
options.TriggerDelay = 20d;
|
|||
|
|
return options;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Point AdjustPointWithinSoftLimit(Point candidatePoint, WaferDiePositionContext context, double offsetMm, out bool adjusted, out string reason)
|
|||
|
|
{
|
|||
|
|
IAxis axisX = _hardwareManager.Axis_PHS_X1;
|
|||
|
|
IAxis axisY = _hardwareManager.Axis_Stage_Y3;
|
|||
|
|
double adjustedX = candidatePoint.X;
|
|||
|
|
double adjustedY = candidatePoint.Y;
|
|||
|
|
bool adjustedXFlag = TryClampByAxisSoftLimit(axisX, adjustedX, offsetMm, out adjustedX, out string adjustedXReason);
|
|||
|
|
bool adjustedYFlag = TryClampByAxisSoftLimit(axisY, adjustedY, offsetMm, out adjustedY, out string adjustedYReason);
|
|||
|
|
|
|||
|
|
adjusted = adjustedXFlag || adjustedYFlag;
|
|||
|
|
if (!adjusted)
|
|||
|
|
{
|
|||
|
|
reason = string.Empty;
|
|||
|
|
return candidatePoint;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
reason = BuildAdjustmentReason(adjustedXReason, adjustedYReason);
|
|||
|
|
return new Point(adjustedX, adjustedY);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private DeviceFoundationSetting GetDeviceFoundationSetting()
|
|||
|
|
{
|
|||
|
|
return _parameterList == null ? null : _parameterList.GetParameter<DeviceFoundationSetting>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private MwCamera ResolveCamera(CameraType cameraType)
|
|||
|
|
{
|
|||
|
|
MwCameraExtend cameraExtend = GetCameraExtend(cameraType);
|
|||
|
|
if (cameraExtend == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return cameraExtend.Camera;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private MwCameraExtend GetCameraExtend(CameraType cameraType)
|
|||
|
|
{
|
|||
|
|
return _hardwareManager.GetCamera(cameraType);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static CameraFovSettingItem GetCameraFovSettingItem(DeviceFoundationSetting deviceFoundationSetting, CameraType cameraType)
|
|||
|
|
{
|
|||
|
|
if (deviceFoundationSetting == null || deviceFoundationSetting.CameraSettingItem == null)
|
|||
|
|
{
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
deviceFoundationSetting.CameraSettingItem.EnsureDefaultCameras();
|
|||
|
|
switch (cameraType)
|
|||
|
|
{
|
|||
|
|
case CameraType.TopWideCamera:
|
|||
|
|
return deviceFoundationSetting.CameraSettingItem.DownCamera;
|
|||
|
|
|
|||
|
|
case CameraType.MapCamera:
|
|||
|
|
return deviceFoundationSetting.CameraSettingItem.MapCamera;
|
|||
|
|
|
|||
|
|
case CameraType.TopPositionCamera:
|
|||
|
|
default:
|
|||
|
|
return deviceFoundationSetting.CameraSettingItem.UpCamera;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static bool TryClampByAxisSoftLimit(IAxis axis, double candidateValue, double offsetMm, out double adjustedValue, out string reason)
|
|||
|
|
{
|
|||
|
|
adjustedValue = candidateValue;
|
|||
|
|
reason = string.Empty;
|
|||
|
|
|
|||
|
|
if (axis == null)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool hasNegativeLimit = TryGetAxisLimit(axis, true, out double negativeLimit);
|
|||
|
|
bool hasPositiveLimit = TryGetAxisLimit(axis, false, out double positiveLimit);
|
|||
|
|
if (!hasNegativeLimit && !hasPositiveLimit)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double minLimit = hasNegativeLimit && hasPositiveLimit ? Math.Min(negativeLimit, positiveLimit) : negativeLimit;
|
|||
|
|
double maxLimit = hasNegativeLimit && hasPositiveLimit ? Math.Max(negativeLimit, positiveLimit) : positiveLimit;
|
|||
|
|
double minAllowed = hasNegativeLimit ? minLimit + Math.Max(0d, offsetMm) : double.NegativeInfinity;
|
|||
|
|
double maxAllowed = hasPositiveLimit ? maxLimit - Math.Max(0d, offsetMm) : double.PositiveInfinity;
|
|||
|
|
|
|||
|
|
if (candidateValue < minAllowed)
|
|||
|
|
{
|
|||
|
|
adjustedValue = minAllowed;
|
|||
|
|
reason = string.Format(
|
|||
|
|
CultureInfo.InvariantCulture,
|
|||
|
|
"{0}: clamp to negative soft limit {1:F3} with offset {2:F3}.",
|
|||
|
|
axis.Name,
|
|||
|
|
adjustedValue,
|
|||
|
|
offsetMm);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (candidateValue > maxAllowed)
|
|||
|
|
{
|
|||
|
|
adjustedValue = maxAllowed;
|
|||
|
|
reason = string.Format(
|
|||
|
|
CultureInfo.InvariantCulture,
|
|||
|
|
"{0}: clamp to positive soft limit {1:F3} with offset {2:F3}.",
|
|||
|
|
axis.Name,
|
|||
|
|
adjustedValue,
|
|||
|
|
offsetMm);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static bool TryGetAxisLimit(IAxis axis, bool isNegativeLimit, out double limitValue)
|
|||
|
|
{
|
|||
|
|
limitValue = 0d;
|
|||
|
|
if (axis == null)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
double axisLimit = 0d;
|
|||
|
|
MotionErrorCode errorCode = isNegativeLimit ? axis.GetSoftMel(ref axisLimit) : axis.GetSoftPel(ref axisLimit);
|
|||
|
|
if (errorCode != MotionErrorCode.NoError)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
limitValue = axisLimit;
|
|||
|
|
if (double.IsNaN(limitValue) || double.IsInfinity(limitValue))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string BuildAdjustmentReason(string adjustedXReason, string adjustedYReason)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrWhiteSpace(adjustedXReason))
|
|||
|
|
{
|
|||
|
|
return adjustedYReason ?? string.Empty;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (string.IsNullOrWhiteSpace(adjustedYReason))
|
|||
|
|
{
|
|||
|
|
return adjustedXReason;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return adjustedXReason + " | " + adjustedYReason;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|