Files
test_demo/MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/DeviceMaintance/ViewModel/LaserCompensationViewModel.cs
Shi.Ji e31d3560bb 添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
2026-05-18 11:43:09 +08:00

447 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using MainShell.Common;
using MainShell.Hardware;
using MainShell.DeviceMaintance.Model;
using MainShell.Log;
using MainShell.Motion;
using MaxwellFramework.Core.Interfaces;
using Stylet;
using StyletIoC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MwFramework.Device;
namespace MainShell.DeviceMaintance.ViewModel
{
public class LaserCompensationViewModel : DeviceMaintanceBaseViewModel, IPage
{
private const string ProjectPageName = "激光补偿";
private const int MinimumMoveTimeoutMilliseconds = 15000;
private const double MoveTimeoutScaleFactor = 3d;
private const int MoveTimeoutExtraMilliseconds = 2000;
private readonly SafeAxisMotion _safeAxisMotion;
private readonly AxisSpeedManager _axisSpeedManager;
private readonly HardwareManager _hardwareManager;
private CancellationTokenSource _cancellationTokenSource;
private bool _uiEnable = true;
private bool _isRunning;
private string _statusMessage;
private int _currentLoopIndex;
private int _currentPointIndex;
private double _currentTargetPosition;
private string _selectedAxisName;
public LaserCompensationViewModel(SafeAxisMotion safeAxisMotion, AxisSpeedManager axisSpeedManager, HardwareManager hardwareManager)
{
_safeAxisMotion = safeAxisMotion;
_axisSpeedManager = axisSpeedManager;
_hardwareManager = hardwareManager;
Setting = new LaserCompensationSetting();
Setting.LoadFromFile();
AxisNames = new System.Collections.ObjectModel.ObservableCollection<string>(BuildAxisNames());
if (!string.IsNullOrWhiteSpace(Setting.AxisName) && AxisNames.Contains(Setting.AxisName))
{
SelectedAxisName = Setting.AxisName;
}
else
{
SelectedAxisName = AxisNames.FirstOrDefault();
}
StatusMessage = "待机";
}
public string Name => "LaserCompensationMaint";
public LaserCompensationSetting Setting { get; }
public System.Collections.ObjectModel.ObservableCollection<string> AxisNames { get; }
public string SelectedAxisName
{
get { return _selectedAxisName; }
set
{
if (SetAndNotify(ref _selectedAxisName, value))
{
Setting.AxisName = value;
}
}
}
public bool UiEnable
{
get { return _uiEnable; }
set
{
if (SetAndNotify(ref _uiEnable, value))
{
OnUiStateChanged(value);
}
}
}
public bool IsRunning
{
get { return _isRunning; }
set { SetAndNotify(ref _isRunning, value); }
}
public string StatusMessage
{
get { return _statusMessage; }
set { SetAndNotify(ref _statusMessage, value); }
}
public int CurrentLoopIndex
{
get { return _currentLoopIndex; }
set { SetAndNotify(ref _currentLoopIndex, value); }
}
public int CurrentPointIndex
{
get { return _currentPointIndex; }
set { SetAndNotify(ref _currentPointIndex, value); }
}
public double CurrentTargetPosition
{
get { return _currentTargetPosition; }
set { SetAndNotify(ref _currentTargetPosition, value); }
}
public async Task StartAsync()
{
if (IsRunning)
{
return;
}
string validationMessage = ValidateSetting();
if (!string.IsNullOrWhiteSpace(validationMessage))
{
StatusMessage = validationMessage;
LocalizedMessageBox.Show(MessageKey.ParamInvalid, MessageKey.TitleError, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
return;
}
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = new CancellationTokenSource();
UiEnable = false;
IsRunning = true;
CurrentLoopIndex = 0;
CurrentPointIndex = 0;
CurrentTargetPosition = 0d;
Setting.AxisName = SelectedAxisName;
StatusMessage = "激光补偿运行中";
IoC.Get<IProjectManager>().EnablePageAndDisableOther(ProjectPageName);
BuildStartLogMessage().LogInfo();
try
{
CancellationToken cancellationToken = _cancellationTokenSource.Token;
await ExecuteCompensationAsync(cancellationToken).ConfigureAwait(true);
StatusMessage = "激光补偿执行完成";
BuildFinishLogMessage("完成").LogInfo();
}
catch (OperationCanceledException)
{
StatusMessage = "激光补偿已停止";
BuildFinishLogMessage("已停止").LogInfo();
}
catch (Exception ex)
{
StatusMessage = $"激光补偿异常:{ex.Message}";
LogManager.LogSysError(ex, true);
}
finally
{
IsRunning = false;
UiEnable = true;
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
IoC.Get<IProjectManager>().SwitchState();
}
}
public void Stop()
{
if (!IsRunning)
{
return;
}
StatusMessage = "正在停止激光补偿";
"激光补偿收到停止请求".LogInfo();
_cancellationTokenSource?.Cancel();
}
public void Save()
{
try
{
Setting.SaveToFile();
StatusMessage = "参数已保存";
"激光补偿参数已保存".LogInfo();
LocalizedMessageBox.Show(MessageKey.CommonSaveSucceeded, MessageKey.TitleInfo, System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
}
catch (Exception ex)
{
StatusMessage = $"参数保存失败:{ex.Message}";
LogManager.LogSysError(ex, true);
}
}
private async Task ExecuteCompensationAsync(CancellationToken cancellationToken)
{
IReadOnlyList<double> trajectory = BuildTrajectory();
ApplyAxisSpeedIfPossible();
for (int workIndex = 0; workIndex < Setting.WorkCount; workIndex++)
{
cancellationToken.ThrowIfCancellationRequested();
CurrentLoopIndex = workIndex + 1;
$"激光补偿开始第{CurrentLoopIndex}次循环,总点数={trajectory.Count}".LogInfo();
for (int pointIndex = 0; pointIndex < trajectory.Count; pointIndex++)
{
cancellationToken.ThrowIfCancellationRequested();
double targetPosition = trajectory[pointIndex];
CurrentPointIndex = pointIndex + 1;
CurrentTargetPosition = targetPosition;
StatusMessage = $"循环 {CurrentLoopIndex}/{Setting.WorkCount},点位 {CurrentPointIndex}/{trajectory.Count}";
int timeoutMilliseconds = CalculateMoveTimeoutMilliseconds(targetPosition, trajectory, pointIndex);
$"激光补偿移动开始:轴={Setting.AxisName},循环={CurrentLoopIndex},点位={CurrentPointIndex},目标={targetPosition:F4},超时={timeoutMilliseconds}ms".LogInfo();
MotionResult motionResult = await _safeAxisMotion.MoveAbsAsync(
Setting.AxisName,
targetPosition,
timeoutMilliseconds,
cancellationToken,
alarmId: null).ConfigureAwait(false);
motionResult.EnsureSuccess();
$"激光补偿移动完成:轴={Setting.AxisName},循环={CurrentLoopIndex},点位={CurrentPointIndex},目标={targetPosition:F4},到位={motionResult.EndPosition:F4}".LogInfo();
if (Setting.DwellTime > 0d)
{
int dwellMilliseconds = (int)Math.Ceiling(Setting.DwellTime * 1000d);
$"激光补偿延时采样:{dwellMilliseconds}ms".LogInfo();
await Task.Delay(dwellMilliseconds, cancellationToken).ConfigureAwait(false);
}
}
}
}
private void ApplyAxisSpeedIfPossible()
{
try
{
if (!string.IsNullOrWhiteSpace(Setting.AxisName) && Setting.Speed > 0d)
{
_axisSpeedManager.SetAxisSpeed(Setting.AxisName, Setting.Speed);
$"激光补偿轴速度已设置:轴={Setting.AxisName}Speed={Setting.Speed:F4}".LogInfo();
}
}
catch (Exception ex)
{
$"激光补偿轴速度设置失败:{ex}".LogSysError();
throw;
}
}
private IReadOnlyList<double> BuildTrajectory()
{
List<double> measurePoints = Enumerable.Range(0, Setting.StepsCount)
.Select(index => Setting.StartPos + index * Setting.Steps)
.ToList();
double readyPosition = Setting.StartPos - Setting.JumpPos;
double overshootPosition = measurePoints[measurePoints.Count - 1] + Setting.JumpPos;
List<double> trajectory = new List<double>(measurePoints.Count * 2 + 3)
{
readyPosition
};
trajectory.AddRange(measurePoints);
trajectory.Add(overshootPosition);
trajectory.AddRange(measurePoints.AsEnumerable().Reverse());
trajectory.Add(readyPosition);
return trajectory;
}
private int CalculateMoveTimeoutMilliseconds(double targetPosition, IReadOnlyList<double> trajectory, int pointIndex)
{
IAxis axis = _hardwareManager.GetAxisByName(Setting.AxisName);
double startPosition = GetMoveStartPosition(axis, trajectory, pointIndex, targetPosition);
double distance = Math.Abs(targetPosition - startPosition);
double speed = ResolvePositiveMotionParameter(axis != null ? axis.Param.Velocity : 0d, Math.Abs(Setting.Speed));
if (speed <= 0d)
{
return MinimumMoveTimeoutMilliseconds;
}
double acceleration = ResolvePositiveMotionParameter(axis != null ? axis.Param.Accelerate : 0d, 0d);
double deceleration = ResolvePositiveMotionParameter(axis != null ? axis.Param.Decelerate : 0d, acceleration);
double expectedMilliseconds = CalculateExpectedMoveMilliseconds(distance, speed, acceleration, deceleration);
return Math.Max(MinimumMoveTimeoutMilliseconds, (int)Math.Ceiling(expectedMilliseconds * MoveTimeoutScaleFactor + MoveTimeoutExtraMilliseconds));
}
private static double GetMoveStartPosition(IAxis axis, IReadOnlyList<double> trajectory, int pointIndex, double targetPosition)
{
if (pointIndex > 0)
{
return trajectory[pointIndex - 1];
}
if (axis != null)
{
return axis.State != null ? axis.State.ActualPos : axis.GetPositionImmediate();
}
return targetPosition;
}
private static double ResolvePositiveMotionParameter(double primaryValue, double fallbackValue)
{
if (!double.IsNaN(primaryValue) && !double.IsInfinity(primaryValue) && primaryValue > 0d)
{
return primaryValue;
}
if (!double.IsNaN(fallbackValue) && !double.IsInfinity(fallbackValue) && fallbackValue > 0d)
{
return fallbackValue;
}
return 0d;
}
private static double CalculateExpectedMoveMilliseconds(double distance, double speed, double acceleration, double deceleration)
{
if (distance <= 0d)
{
return 0d;
}
if (speed <= 0d)
{
return 0d;
}
if (acceleration <= 0d || deceleration <= 0d)
{
return distance / speed * 1000d;
}
double accelerateDistance = speed * speed / (2d * acceleration);
double decelerateDistance = speed * speed / (2d * deceleration);
double criticalDistance = accelerateDistance + decelerateDistance;
double expectedSeconds;
if (distance >= criticalDistance)
{
expectedSeconds = speed / acceleration + speed / deceleration + (distance - criticalDistance) / speed;
}
else
{
double peakSpeed = Math.Sqrt(2d * distance * acceleration * deceleration / (acceleration + deceleration));
expectedSeconds = peakSpeed / acceleration + peakSpeed / deceleration;
}
return expectedSeconds * 1000d;
}
private string ValidateSetting()
{
if (string.IsNullOrWhiteSpace(Setting.AxisName))
{
return "轴名称不能为空";
}
if (!AxisNames.Contains(Setting.AxisName))
{
return "请选择有效的轴名称";
}
if (Setting.StepsCount <= 0)
{
return "步距次数必须大于0";
}
if (Setting.WorkCount <= 0)
{
return "循环次数必须大于0";
}
if (Math.Abs(Setting.Steps) <= 0d)
{
return "步距必须非0";
}
if (Setting.JumpPos < 0d)
{
return "跃程不能小于0";
}
if (Setting.Speed <= 0d)
{
return "速度必须大于0";
}
if (Setting.DwellTime < 0d)
{
return "延时时间不能小于0";
}
return null;
}
private string BuildStartLogMessage()
{
return $"激光补偿启动:轴={Setting.AxisName}StartPos={Setting.StartPos:F4}Steps={Setting.Steps:F4}StepsCount={Setting.StepsCount}JumpPos={Setting.JumpPos:F4}WorkCount={Setting.WorkCount}Speed={Setting.Speed:F4}DwellTime={Setting.DwellTime:F3}s";
}
private string BuildFinishLogMessage(string state)
{
return $"激光补偿结束:状态={state},轴={Setting.AxisName},已执行循环={CurrentLoopIndex},最后点位={CurrentPointIndex},最后目标={CurrentTargetPosition:F4}";
}
private IEnumerable<string> BuildAxisNames()
{
return new[]
{
GetAxisName(_hardwareManager?.Axis_PHS_X1, MainShell.Hardware.AxisName.Axis_PHS_X1),
GetAxisName(_hardwareManager?.Axis_PHS_X2, MainShell.Hardware.AxisName.Axis_PHS_X2),
GetAxisName(_hardwareManager?.Axis_PHS_Y1, MainShell.Hardware.AxisName.Axis_PHS_Y1),
GetAxisName(_hardwareManager?.Axis_WS_X3, MainShell.Hardware.AxisName.Axis_WS_X3),
GetAxisName(_hardwareManager?.Axis_Stage_Y3, MainShell.Hardware.AxisName.Axis_Stage_Y3),
GetAxisName(_hardwareManager?.Axis_WS_R, MainShell.Hardware.AxisName.Axis_WS_R),
}.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct().ToArray();
}
private static string GetAxisName(IAxis axis, string fallbackName)
{
if (axis == null || string.IsNullOrWhiteSpace(axis.Name))
{
return fallbackName;
}
return axis.Name;
}
}
}