添加 MX-PD-盘古 项目文件

将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
Shi.Ji
2026-05-18 11:43:09 +08:00
parent 03632a379d
commit e31d3560bb
739 changed files with 99783 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
using MainShell.AlgorithmCalib.Common;
using MainShell.AlgorithmCalib.Model;
using MainShell.Common;
using MainShell.Hardware;
using MainShell.Log;
using MainShell.Motion;
using SemiconductorVisionAlgorithm.SemiParams;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
namespace MainShell.AlgorithmCalib.Service
{
/// <summary>
/// 融合对位处理器
/// 3步对位流程
/// 1. 抓Pad点框选ROI识别Pad坐标
/// 2. Die网格飞拍首点+参数 → 蛇形扫描获取x*y个Die点
/// 3. 对位验证选择一个Die点 → 与Pad点对位 → 输出结果)
/// </summary>
public class FusionAlignProcessor
{
private readonly FusionCalibMotionService _motionService;
private readonly HardwareManager _hardware;
private readonly FusionCalibModuleItem _moduleItem;
private readonly ApproachAlignmentService _approachAlignmentService;
// 飞拍参数
private double _flyScanStartX;
private double _flyScanStartY;
private int _flyScanXCount;
private int _flyScanYCount;
private double _flyScanStep;
public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
private readonly Func<Rectangle1> _roiRectProvider; // ROI 提供者委托
public FusionAlignProcessor(
FusionCalibMotionService motionService,
HardwareManager hardware,
FusionCalibModuleItem moduleItem,
Func<Rectangle1> roiRectProvider)
{
_motionService = motionService;
_hardware = hardware;
_moduleItem = moduleItem;
_approachAlignmentService = IoC.Get<ApproachAlignmentService>();
_roiRectProvider = roiRectProvider;
}
/// <summary>
/// 设置飞拍参数
/// </summary>
public void SetFlyScanParams(double startX, double startY, int xCount, int yCount, double step)
{
_flyScanStartX = startX;
_flyScanStartY = startY;
_flyScanXCount = xCount;
_flyScanYCount = yCount;
_flyScanStep = step;
}
/// <summary>
/// 步骤1抓Pad点
/// 框选ROI区域识别Pad目标点坐标pad运动系X1,Y2
/// </summary>
public async Task CapturePadPointAsync(CancellationToken cancellationToken)
{
await Task.Run(async () =>
{
ReportProgress("抓Pad点...", 1, 3);
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
if (!success)
{
throw new InvalidOperationException($"逼近对齐失败");
}
_moduleItem.PadRealX = _hardware.Axis_X1.State.ActualPos;
_moduleItem.PadRealY = _hardware.Axis_Y2.State.ActualPos;
"抓Pad点完成".LogInfo();
}, cancellationToken);
}
/// <summary>
/// 步骤2a抓Die首点
/// 框选ROI区域识别Die首点坐标die运动系X2,Y1
/// </summary>
public async Task CaptureDieFirstPointAsync(CancellationToken cancellationToken)
{
await Task.Run(async() =>
{
ReportProgress("抓Die首点...", 1, 3);
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
if (!success)
{
throw new InvalidOperationException($"逼近对齐失败");
}
_moduleItem.DieRealX = _hardware.Axis_X2.State.ActualPos;
_moduleItem.DieRealY = _hardware.Axis_Y1.State.ActualPos;
"抓Die首点完成".LogInfo();
}, cancellationToken);
}
/// <summary>
/// 步骤2bDie网格飞拍
/// 以首点为起点按step和count执行蛇形网格飞拍获取x*y个Die点
/// </summary>
public async Task ExecuteDieGridFlyScanAsync(CancellationToken cancellationToken)
{
await Task.Run(async() =>
{
var sw = Stopwatch.StartNew();
int totalPoints = _flyScanXCount * _flyScanYCount;
int captured = 0;
ReportProgress($"开始飞拍,网格{_flyScanXCount}×{_flyScanYCount},共{totalPoints}点...", 0, totalPoints);
// 清空之前的数据
_moduleItem.DieGridPoints = new List<Tuple<int, int, SemiPoint>>();
for (int row = 0; row < _flyScanYCount; row++)
{
// 蛇形扫描:偶数行从左到右,奇数行从右到左
for (int col = 0; col < _flyScanXCount; col++)
{
cancellationToken.ThrowIfCancellationRequested();
int actualCol = row % 2 == 0 ? col : (_flyScanXCount - 1 - col);
// 计算目标位置
double targetX2 = _flyScanStartX + actualCol * _flyScanStep;
double targetY1 = _flyScanStartY + row * _flyScanStep;
// 移动轴到目标位置
_motionService.MoveWsAvoidance(targetX2, targetY1);
// 等待运动完成
Thread.Sleep(200);
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
if (!success)
{
throw new InvalidOperationException($"逼近对齐失败");
}
// 读取当前位置
double currentX2 = _hardware.Axis_X2.State.ActualPos;
double currentY1 = _hardware.Axis_Y1.State.ActualPos;
SemiPoint point = new SemiPoint(currentX2, currentY1);
_moduleItem.DieGridPoints.Add(Tuple.Create(row, actualCol, point));
captured++;
ReportProgress($"飞拍中... ({captured}/{totalPoints})", captured, totalPoints);
}
}
sw.Stop();
$"Die网格飞拍完成共{captured}点,耗时{sw.ElapsedMilliseconds}ms".LogInfo();
}, cancellationToken);
}
/// <summary>
/// 步骤3执行对位
/// 用户选择网格中的一个Die点row, col与Pad点执行对位
/// 对位流程Die X对齐Pad → Pad Y对齐Die → X2补偿
/// </summary>
public async Task ExecuteAlignAsync(CancellationToken ct, int selectedRow, int selectedCol)
{
await Task.Run(() =>
{
ReportProgress("执行对位...", 1, 6);
// 从网格中找到选中的Die点
SemiPoint selectedDie = null;
foreach (var pt in _moduleItem.DieGridPoints)
{
if (pt.Item1 == selectedRow && pt.Item2 == selectedCol)
{
selectedDie = pt.Item3;
break;
}
}
if (selectedDie == null)
{
throw new Exception($"未找到Die点[{selectedRow},{selectedCol}]");
}
// 使用选中的Die点作为对位基准
_moduleItem.DieRealX = selectedDie.X;
_moduleItem.DieRealY = selectedDie.Y;
_moduleItem.PadRealX = _moduleItem.PadRulerX;
_moduleItem.PadRealY = _moduleItem.PadRulerY;
ReportProgress("Die X方向对齐Pad...", 2, 6);
// === 步骤3aDie X方向对齐Pad ===
// 查die融合表将Die的X方向对齐到Pad的X方向
// 移动X2,Y1 → Y1会产生少许偏移
//
// TODO: 接入JM1融合表查询
// SemiPoint dieReal = new SemiPoint(_moduleItem.DieRealX, _moduleItem.DieRealY);
// SemiPoint padReal = new SemiPoint(_moduleItem.PadRealX, _moduleItem.PadRealY);
// SemiJM1Manager.Instance.get_ws_pos_die(dieReal, padReal, out SemiPoint wsTarget);
//
// 暂时模拟使用Die坐标作为目标
double wsTargetX = _moduleItem.DieRealX;
double wsTargetY = _moduleItem.DieRealY;
_motionService.MoveWsAvoidance(wsTargetX, wsTargetY);
// 读取此时Y1位置已产生偏移
double currentY1 = _hardware.Axis_Y1.State.ActualPos;
ReportProgress("Pad Y方向对齐Die...", 3, 6);
// === 步骤3bPad Y方向对齐Die ===
// 根据当前Y1值查pad融合表计算X1,Y2目标位置
// 移动X1,Y2 → X1会产生少许偏移
//
// TODO: 接入pad融合表查询
// SemiPoint padTarget = FusionTableLookupPad(padReal, currentY1);
//
// 暂时模拟
double padTargetX = _moduleItem.PadRealX;
double padTargetY = _moduleItem.PadRealY;
_motionService.MovePhsAvoidance(padTargetX, padTargetY);
// 读取此时X1位置已产生偏移
double currentX1 = _hardware.Axis_X1.State.ActualPos;
ReportProgress("X2补偿...", 4, 6);
// === 步骤3cX2补偿 ===
// X2跟上X1的移动量
double x1Delta = currentX1 - _moduleItem.PadRulerX;
double x2Target = wsTargetX + x1Delta;
_motionService.SafeMove(_hardware.Axis_X2, x2Target);
// 记录结果
_moduleItem.AlignResultX = currentX1;
_moduleItem.AlignResultY = currentY1;
_moduleItem.AlignResultX2 = x2Target;
ReportProgress("对位完成", 5, 6);
$"对位完成: Die[{selectedRow},{selectedCol}] → Pad, X1={currentX1:F4}, Y1={currentY1:F4}, X2 ={ x2Target: F4}".LogInfo();
}, ct);
}
private void ReportProgress(string message, int current, int total)
{
ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
{
Message = message,
Current = current,
Total = total
});
}
/// <summary>
/// 逼近对齐
/// </summary>
private async Task<bool> ApproachAtPointAsync(CancellationToken cancellationToken)
{
Rectangle1 roiRect = _roiRectProvider?.Invoke();
var request = new ApproachAlignmentRequest(
axes: new[]
{
new ApproachAlignmentAxis(_hardware.Axis_X2.Name, 0.005),
new ApproachAlignmentAxis(_hardware.Axis_Y1.Name, 0.005)
},
camera: CameraType.TopPositionCamera)
{
MaxIterations = 3,
RecognitionTimeoutMilliseconds = 5000,
RecognitionParameters = new CenterRecognitionParameters()
{
Type = CenterRecognitionType.EdgeCircle,
rectangle = roiRect
}
};
var result = await _approachAlignmentService.ApproachAlignmentAsync(request, cancellationToken).ConfigureAwait(false);
return result.Succeeded;
}
}
}

View File

@@ -0,0 +1,60 @@
using MainShell.Hardware;
using MainShell.Motion;
using MaxwellFramework.Core.Attributes;
using MwFramework.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MainShell.AlgorithmCalib.Service
{
[Singleton]
public class FusionCalibMotionService
{
private readonly HardwareManager _hardware;
private readonly SafeAxisMotion _safeAxisMotion;
public FusionCalibMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion)
{
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
_safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
}
public void SafeMove(IAxis axis, double position)
{
_safeAxisMotion.SafeMove(
MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)), position));
}
public void MoveWsAvoidance(double xPosition, double yPosition)
{
_safeAxisMotion.SafeMove(
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2, nameof(_hardware.Axis_X2)), xPosition),
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1, nameof(_hardware.Axis_Y1)), yPosition));
}
public void MovePhsAvoidance(double xPosition, double yPosition)
{
_safeAxisMotion.SafeMove(
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X1, nameof(_hardware.Axis_X1)), xPosition),
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y2, nameof(_hardware.Axis_Y2)), yPosition));
}
public void RotatePos(double rotatePosition)
{
_safeAxisMotion.SafeMove(
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R, nameof(_hardware.Axis_WS_R)), rotatePosition));
}
private static MwFramework.Device.IAxis GetRequiredAxis(MwFramework.Device.IAxis axis, string axisPropertyName)
{
if (axis == null)
{
throw new InvalidOperationException(string.Format("Axis '{0}' is not available.", axisPropertyName));
}
return axis;
}
}
}

View File

@@ -0,0 +1,229 @@
using MainShell.AlgorithmCalib.Common;
using MainShell.AlgorithmCalib.Model;
using MainShell.Hardware;
using MainShell.Log;
using SemiconductorVisionAlgorithm.SemiParams;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.AlgorithmCalib.Service
{
/// <summary>
/// 融合标定后处理器Die/Pad共用
/// 通过 IsWaferCalib 内部区分行为
/// </summary>
public class FusionCalibPostProcessor : IAlgorithmCalibrationPostProcessor
{
private readonly FusionCalibMotionService _motionService;
private readonly HardwareManager _hardware;
private readonly FusionCalibModuleItem _moduleItem;
private readonly Func<Rectangle1> _roiRectProvider;
public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
private Point[,] _initialwsPos;
private Dictionary<int, Point[,]> _calibResultPointData = new Dictionary<int, Point[,]>();
private List<double> _calibPosList = new List<double>();
public string Name => "FusionCalib";
public FusionCalibPostProcessor(
FusionCalibMotionService motionService,
HardwareManager hardware,
FusionCalibModuleItem moduleItem,
Func<Rectangle1> roiRectProvider)
{
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
_moduleItem = moduleItem ?? throw new ArgumentNullException(nameof(moduleItem));
_roiRectProvider = roiRectProvider;
}
public async Task ExecuteAsync(AlgorithmCalibExecutionResult calibrationResult, CancellationToken cancellationToken)
{
$"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定开始。".LogInfo();
try
{
_calibResultPointData.Clear();
_calibPosList.Clear();
double waferStep = _moduleItem.CalibStep;
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _moduleItem.ModelPath);
int totalSteps = _moduleItem.Count + 1;
ReportProgress("采集初始网格点...", 0, totalSteps);
// 1. 初始网格
_initialwsPos = await Task.Run(() =>
ApprochTable(waferStep,
_moduleItem.MoveAxisPos,
GetCurrentY1(),
_moduleItem.ApproachXPos,
_moduleItem.ApproachYPos,
0, path, cancellationToken),
cancellationToken);
// 2. 循环采集
for (int i = 0; i < _moduleItem.Count; i++)
{
cancellationToken.ThrowIfCancellationRequested();
ReportProgress($"采集第 {i + 1}/{_moduleItem.Count} 组...", i + 1, totalSteps);
double x1, y1, x2, y2;
CalculatePositions(i, out x1, out y1, out x2, out y2);
Point[,] points = await Task.Run(() =>
ApprochTable(waferStep, x1, y1, x2, y2, i + 1, path, cancellationToken),
cancellationToken);
_calibResultPointData[i] = points;
_calibPosList.Add(GetCurrentMoveAxisPos());
}
// 3. 调用平台算法
ReportProgress("计算融合矩阵...", totalSteps, totalSteps);
await Task.Run(() =>
{
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CalibData");
if (_moduleItem.IsWaferCalib)
{
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_die(
_calibResultPointData, _calibPosList, _initialwsPos,
_moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
}
else
{
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_pad(
_moduleItem.Index, _calibResultPointData, _calibPosList, _initialwsPos,
_moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
SemiJM1Vision.SemiJM1Manager.Instance.set_center(new Point(0, 0));
}
SemiJM1Vision.SemiJM1Manager.Instance.Save(filePath);
}, cancellationToken);
$"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定完成。".LogInfo();
}
catch (OperationCanceledException)
{
"融合标定已取消。".LogInfo();
throw;
}
catch (Exception ex)
{
$"融合标定失败:{ex.Message}".LogSysError();
throw;
}
}
public async Task VerifyAsync(CancellationToken cancellationToken)
{
// TODO: 验证流程
await Task.CompletedTask;
}
#region Die/Pad分支
private void CalculatePositions(int stepIndex, out double x1, out double y1, out double x2, out double y2)
{
if (_moduleItem.IsWaferCalib)
{
// Die: 移动X1逼近X2+Y1
x1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
y1 = _moduleItem.StartY;
x2 = _moduleItem.StartX + _moduleItem.Step * stepIndex;
y2 = _hardware.Axis_Y2.State.ActualPos;
}
else
{
// Pad: 移动Y1逼近X1+Y2
x1 = _moduleItem.StartX;
y1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
x2 = _hardware.Axis_X2.State.ActualPos;
y2 = _moduleItem.StartY + _moduleItem.Step * stepIndex;
}
}
private double GetCurrentY1()
{
return _hardware.Axis_Y1.State.ActualPos;
}
private double GetCurrentMoveAxisPos()
{
return _moduleItem.IsWaferCalib
? _hardware.Axis_X1.State.ActualPos
: _hardware.Axis_Y1.State.ActualPos;
}
#endregion
#region
private Point[,] ApprochTable(double calibStep, double x1, double y1, double x2, double y2,
int count, string path, CancellationToken ct)
{
int calibCount = _moduleItem.CalibCount;
Point[,] pointArray = new Point[calibCount, calibCount];
// 先移到起始位置
if (_moduleItem.IsWaferCalib)
_motionService.MoveWsAvoidance(x2, y1);
else
_motionService.MovePhsAvoidance(x1, y2);
for (int y = 0; y < calibCount; y++)
{
double Y1 = y * calibStep + y1;
double Y2 = y * calibStep + y2;
for (int x = 0; x < calibCount; x++)
{
ct.ThrowIfCancellationRequested();
int index = y % 2 == 0 ? x : calibCount - 1 - x;
double X2 = index * calibStep + x2;
double X1 = index * calibStep + x1;
if (_moduleItem.IsWaferCalib)
{
_motionService.MoveWsAvoidance(X2, Y1);
// TODO: 调用逼近识别
pointArray[index, y] = new Point(
_hardware.Axis_X2.State.ActualPos,
_hardware.Axis_Y1.State.ActualPos);
}
else
{
_motionService.MovePhsAvoidance(X1, Y2);
// TODO: 调用逼近识别
pointArray[index, y] = new Point(
_hardware.Axis_X1.State.ActualPos,
_hardware.Axis_Y2.State.ActualPos);
}
}
}
return pointArray;
}
#endregion
private void ReportProgress(string message, int current, int total)
{
ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
{
Message = message,
Current = current,
Total = total
});
}
}
}