using MainShell.Common; using MainShell.DeviceMaintance.Model; using MainShell.Hardware; using MainShell.Motion; using MainShell.Parameter; using MainShell.ParaSetting.Model; using MaxwellFramework.Core.Attributes; using MaxwellFramework.Core.Interfaces; using MW.WorkFlow; using MwFramework.ManagerService; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace MainShell.Process { [Singleton] public class NeedleZCalibrationService { private const double Precision = 0.001; private readonly HardwareManager _hardwareManager; private readonly SafeAxisMotion _safeAxisMotion; private readonly IParamList _paramList; private readonly IDeviceIoMonitorService _deviceIoMonitorService; public NeedleZCalibrationService(HardwareManager hardwareManager, SafeAxisMotion safeAxisMotion, IParameterManager parameterManager, IDeviceIoMonitorService deviceIoMonitorService) { _hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager)); _safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion)); _paramList = parameterManager as IParamList; _deviceIoMonitorService = deviceIoMonitorService ?? throw new ArgumentNullException(nameof(deviceIoMonitorService)); } public NeedleZCalibrationExecutionContext GetExecutionContext(int? inputTouchCount, bool? inputAutoRaiseZ1) { NeedleCalibrationSetting needleCalibrationSetting = _paramList?.GetParameter(); EquipmentParaSysSetting equipmentParaSysSetting = _paramList?.GetParameter(); return CreateExecutionContext(needleCalibrationSetting, equipmentParaSysSetting, inputTouchCount, inputAutoRaiseZ1); } public NeedleZCalibrationExecutionContext CreateExecutionContext(NeedleCalibrationSetting needleCalibrationSetting, EquipmentParaSysSetting equipmentParaSysSetting, int? inputTouchCount, bool? inputAutoRaiseZ1) { ValidateCalibrationSetting(needleCalibrationSetting); NeedleZCalibrationItem item = needleCalibrationSetting.NeedleZCalibrationItem; ValidateCalibrationItem(item); int touchCount = Math.Max(1, inputTouchCount ?? item.NeedleTouchCount); bool autoRaiseZ1 = inputAutoRaiseZ1 ?? true; double safeHeight = ResolveSafeHeight(equipmentParaSysSetting); return new NeedleZCalibrationExecutionContext(needleCalibrationSetting, item, touchCount, autoRaiseZ1, safeHeight); } public async Task ExecuteSingleTouchAsync(bool autoRaiseZ1, CancellationToken cancellationToken) { return await ExecuteSingleTouchAsync(autoRaiseZ1, cancellationToken, null); } public async Task ExecuteSingleTouchAsync(bool autoRaiseZ1, CancellationToken cancellationToken, Action onResult) { NeedleZCalibrationExecutionContext executionContext = GetExecutionContext(1, autoRaiseZ1); IReadOnlyList results = await ExecuteCalibrationAsync(executionContext, null, cancellationToken, onResult); if (results == null || results.Count == 0) { throw new InvalidOperationException("单次对刀未返回结果。"); } return results[0]; } public async Task> ExecuteCalibrationAsync(NeedleZCalibrationExecutionContext executionContext, ActivityControl activityControl, CancellationToken cancellationToken, Action onResult) { if (executionContext == null) { throw new ArgumentNullException(nameof(executionContext)); } List results = new List(); for (int i = 0; i < executionContext.TouchCount; i++) { await CheckControlAsync(activityControl, cancellationToken); double result = await ExecuteSingleCalibrationAsync(executionContext, activityControl, cancellationToken); results.Add(result); onResult?.Invoke(result); } if (executionContext.AutoRaiseZ1) { await CheckControlAsync(activityControl, cancellationToken); _safeAxisMotion.MoveAbs(_hardwareManager.Axis_Z1, executionContext.Item.Z1StartPosition, cancellationToken); } return results; } private async Task ExecuteSingleCalibrationAsync(NeedleZCalibrationExecutionContext executionContext, ActivityControl activityControl, CancellationToken cancellationToken) { bool foundSignal = false; double start = executionContext.Item.Z1StartPosition; double end = start - executionContext.Item.Z1DropMaxPosition; await CheckControlAsync(activityControl, cancellationToken); _safeAxisMotion.MoveAbs(_hardwareManager.Axis_Z1, start, cancellationToken); while (Math.Abs(end - start) > Precision) { await CheckControlAsync(activityControl, cancellationToken); double mid = (start + end) / 2.0; if (mid < executionContext.SafeHeight) { throw new InvalidOperationException(string.Format("目标位置[{0}]低于Z1对刀安全高度[{1}],运动不安全。", mid, executionContext.SafeHeight)); } _safeAxisMotion.MoveAbs(_hardwareManager.Axis_Z1, mid, cancellationToken); if (IsToolSetterTriggered()) { end = mid; foundSignal = true; } else { start = mid; } } if (!foundSignal) { throw new InvalidOperationException("在范围内未找到对刀信号,对刀失败。\r\n请检查对刀块位置与感测信号状态。"); } return _hardwareManager.Axis_Z1.State != null ? _hardwareManager.Axis_Z1.State.ActualPos : _hardwareManager.Axis_Z1.GetPositionImmediate(); } private static async Task CheckControlAsync(ActivityControl activityControl, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (activityControl == null) { return; } activityControl.CancellationToken.ThrowIfCancellationRequested(); await activityControl.CheckPauseAsync(); cancellationToken.ThrowIfCancellationRequested(); activityControl.CancellationToken.ThrowIfCancellationRequested(); } private bool IsToolSetterTriggered() { return _deviceIoMonitorService.IsPointOn(DeviceIoNames.Stage.ToolSetterSignal); } private static void ValidateCalibrationSetting(NeedleCalibrationSetting needleCalibrationSetting) { if (needleCalibrationSetting == null || needleCalibrationSetting.NeedleZCalibrationItem == null) { throw new InvalidOperationException("未获取到针头对刀参数。"); } } private static void ValidateCalibrationItem(NeedleZCalibrationItem item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (item.Z1Speed <= 0) { throw new InvalidOperationException("Z1速度必须大于0。"); } if (item.Z1DropMaxPosition <= 0) { throw new InvalidOperationException("Z1下降最大位置必须大于0。"); } } private static double ResolveSafeHeight(EquipmentParaSysSetting equipmentParaSysSetting) { if (equipmentParaSysSetting == null || equipmentParaSysSetting.SafeParaSysItem == null) { return 0; } return equipmentParaSysSetting.SafeParaSysItem.NeedleCalibSafeHeight; } } public class NeedleZCalibrationExecutionContext { public NeedleZCalibrationExecutionContext(NeedleCalibrationSetting needleCalibrationSetting, NeedleZCalibrationItem item, int touchCount, bool autoRaiseZ1, double safeHeight) { NeedleCalibrationSetting = needleCalibrationSetting ?? throw new ArgumentNullException(nameof(needleCalibrationSetting)); Item = item ?? throw new ArgumentNullException(nameof(item)); TouchCount = touchCount; AutoRaiseZ1 = autoRaiseZ1; SafeHeight = safeHeight; } public NeedleCalibrationSetting NeedleCalibrationSetting { get; private set; } public NeedleZCalibrationItem Item { get; private set; } public int TouchCount { get; private set; } public bool AutoRaiseZ1 { get; private set; } public double SafeHeight { get; private set; } } }