添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using MXJM.FileWritable;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.Model
|
||||
{
|
||||
public static class OriginCalibModuleNames
|
||||
{
|
||||
public const string GantryX1Y1 = "X1Y1";
|
||||
public const string GantryX2 = "X2";
|
||||
public const string StageY2 = "StageY2";
|
||||
public const string WSX3 = "WSX3";
|
||||
public const string Z1 = "Z1";
|
||||
public const string Z3 = "Z3";
|
||||
public const string Z4 = "Z4";
|
||||
public const string Z5 = "Z5";
|
||||
public const string Z6 = "Z6";
|
||||
}
|
||||
|
||||
public class AvoidanceAxisItem
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
public double Position { get; set; }
|
||||
}
|
||||
|
||||
public class CalibrationAxisItem
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
public double TargetPosition { get; set; }
|
||||
public double LastPosition { get; set; }
|
||||
public double Offset { get; set; }
|
||||
public bool IsCalibrated { get; set; }
|
||||
}
|
||||
|
||||
public class OriginCalibModuleItem
|
||||
{
|
||||
public string ModuleName { get; set; }
|
||||
public bool IsIndependent { get; set; }
|
||||
public string TemplatePath { get; set; }
|
||||
public List<AvoidanceAxisItem> AvoidanceAxes { get; set; } = new List<AvoidanceAxisItem>();
|
||||
public List<CalibrationAxisItem> CalibrationAxes { get; set; } = new List<CalibrationAxisItem>();
|
||||
|
||||
[JsonIgnore]
|
||||
public ICalibrationPostProcessor PostProcessor { get; set; }
|
||||
|
||||
public void EnsureCollections()
|
||||
{
|
||||
if (AvoidanceAxes == null)
|
||||
{
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>();
|
||||
}
|
||||
|
||||
if (CalibrationAxes == null)
|
||||
{
|
||||
CalibrationAxes = new List<CalibrationAxisItem>();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TemplatePath))
|
||||
{
|
||||
TemplatePath = GetDefaultTemplatePath(ModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDefaultTemplatePath(string moduleName)
|
||||
{
|
||||
switch (moduleName)
|
||||
{
|
||||
case OriginCalibModuleNames.GantryX1Y1:
|
||||
return Paths.OriginCalibGantryX1Y1TemplatePath;
|
||||
|
||||
case OriginCalibModuleNames.GantryX2:
|
||||
return Paths.OriginCalibGantryX2TemplatePath;
|
||||
|
||||
case OriginCalibModuleNames.StageY2:
|
||||
return Paths.OriginCalibStageY2TemplatePath;
|
||||
|
||||
case OriginCalibModuleNames.WSX3:
|
||||
return Paths.OriginCalibWSX3TemplatePath;
|
||||
|
||||
default:
|
||||
return Paths.OriginCalibDefaultTemplatePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class OriginCalibSetting : JsonFileWritableBase
|
||||
{
|
||||
[JsonIgnore]
|
||||
public override string Dir => Paths.CalibSettingPath;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string FileName => "OriginCalibSetting.json";
|
||||
|
||||
public List<OriginCalibModuleItem> Modules { get; set; } = new List<OriginCalibModuleItem>();
|
||||
|
||||
public static OriginCalibSetting LoadOrCreate()
|
||||
{
|
||||
OriginCalibSetting setting = new OriginCalibSetting();
|
||||
string path = Path.Combine(setting.Dir, setting.FileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
setting.Read(path);
|
||||
setting.EnsureCollections();
|
||||
return setting;
|
||||
}
|
||||
|
||||
setting.Modules = CreateDefaultModules();
|
||||
setting.Write(path);
|
||||
return setting;
|
||||
}
|
||||
|
||||
public void EnsureCollections()
|
||||
{
|
||||
if (Modules == null)
|
||||
{
|
||||
Modules = new List<OriginCalibModuleItem>();
|
||||
}
|
||||
|
||||
foreach (OriginCalibModuleItem module in Modules)
|
||||
{
|
||||
if (module != null)
|
||||
{
|
||||
module.EnsureCollections();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<OriginCalibModuleItem> CreateDefaultModules()
|
||||
{
|
||||
List<OriginCalibModuleItem> modules = new List<OriginCalibModuleItem>
|
||||
{
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.GantryX1Y1,
|
||||
IsIndependent = true,
|
||||
TemplatePath = Paths.OriginCalibGantryX1Y1TemplatePath,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>
|
||||
{
|
||||
new AvoidanceAxisItem
|
||||
{
|
||||
AxisName=AxisName.Axis_Stage_Y3,
|
||||
Position=0
|
||||
}
|
||||
},
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_X1, TargetPosition = 0.0 },
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Y1, TargetPosition = 0.0 }
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.GantryX2,
|
||||
IsIndependent = true,
|
||||
TemplatePath = Paths.OriginCalibGantryX2TemplatePath,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>
|
||||
{
|
||||
new AvoidanceAxisItem{ AxisName=AxisName.Axis_Stage_Y3, Position= 0 },
|
||||
},
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_X2, TargetPosition = 0.0 },
|
||||
new CalibrationAxisItem { AxisName=AxisName.Axis_PHS_Y1, TargetPosition= 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.StageY2,
|
||||
IsIndependent = true,
|
||||
TemplatePath = Paths.OriginCalibStageY2TemplatePath,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_Stage_Y3, TargetPosition = 0.0 }
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.WSX3,
|
||||
IsIndependent = true,
|
||||
TemplatePath = Paths.OriginCalibWSX3TemplatePath,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_WS_X3, TargetPosition = 0.0 },
|
||||
new CalibrationAxisItem { AxisName=AxisName.Axis_PHS_Y1, TargetPosition= 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.Z1,
|
||||
IsIndependent = true,
|
||||
TemplatePath = string.Empty,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Z1, TargetPosition = 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.Z3,
|
||||
IsIndependent = true,
|
||||
TemplatePath = string.Empty,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Z3, TargetPosition = 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.Z4,
|
||||
IsIndependent = true,
|
||||
TemplatePath = string.Empty,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Z4, TargetPosition = 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.Z5,
|
||||
IsIndependent = true,
|
||||
TemplatePath = string.Empty,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Z5, TargetPosition = 0.0 },
|
||||
}
|
||||
},
|
||||
new OriginCalibModuleItem
|
||||
{
|
||||
ModuleName = OriginCalibModuleNames.Z6,
|
||||
IsIndependent = true,
|
||||
TemplatePath = string.Empty,
|
||||
AvoidanceAxes = new List<AvoidanceAxisItem>(),
|
||||
CalibrationAxes = new List<CalibrationAxisItem>
|
||||
{
|
||||
new CalibrationAxisItem { AxisName = AxisName.Axis_PHS_Z6, TargetPosition = 0.0 },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// ʾ<><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ궨<DAB1><EAB6A8><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class VisionCapturePostProcessor : ICalibrationPostProcessor
|
||||
{
|
||||
public string Name => "VisionCapture";
|
||||
|
||||
public async Task ExecuteAsync(OriginCalibrationExecutionResult calibrationResult, CancellationToken cancellationToken,object pars= null)
|
||||
{
|
||||
"ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD>պ<EFBFBD><D5BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...".LogInfo();
|
||||
|
||||
// <20>ڴ˴<DAB4><CBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD>磺await _visionService.CaptureAsync(cancellationToken);
|
||||
|
||||
await Task.Delay(100, cancellationToken);
|
||||
|
||||
"<22><><EFBFBD>պ<EFBFBD><D5BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD>".LogInfo();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ궨<DAB1><EAB6A8><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD>λ<EFBFBD><CEBB>ִ<EFBFBD>бƽ<D0B1><C6BD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class ApproachAlignmentPostProcessor : ICalibrationPostProcessor
|
||||
{
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private readonly IReadOnlyList<ApproachAlignmentAxis> _alignmentAxes;
|
||||
private readonly CameraType _camera;
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD>캯<EFBFBD><ECBAAF>
|
||||
/// </summary>
|
||||
/// <param name="approachAlignmentService"><3E>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
/// <param name="alignmentAxes"><3E><>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD></param>
|
||||
/// <param name="camera"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD>Ĭ<EFBFBD><C4AC>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
||||
public ApproachAlignmentPostProcessor(
|
||||
ApproachAlignmentService approachAlignmentService,
|
||||
IEnumerable<ApproachAlignmentAxis> alignmentAxes,
|
||||
CameraType camera = CameraType.TopPositionCamera)
|
||||
{
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
|
||||
if (alignmentAxes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(alignmentAxes));
|
||||
}
|
||||
|
||||
_alignmentAxes = alignmentAxes.ToList().AsReadOnly();
|
||||
|
||||
if (_alignmentAxes.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫһ<D2AA><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᡣ", nameof(alignmentAxes));
|
||||
}
|
||||
|
||||
_camera = camera;
|
||||
}
|
||||
|
||||
public string Name => "ApproachAlignment";
|
||||
|
||||
public async Task ExecuteAsync(OriginCalibrationExecutionResult calibrationResult, CancellationToken cancellationToken,object pars= null)
|
||||
{
|
||||
"ִ<>бƽ<D0B1><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...".LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
ApproachAlignmentRequest alignmentRequest = new ApproachAlignmentRequest(_alignmentAxes, _camera);
|
||||
if(pars is CenterRecognitionParameters centerRecognitionParameters)
|
||||
{
|
||||
alignmentRequest.RecognitionParameters = centerRecognitionParameters;
|
||||
}
|
||||
|
||||
ApproachAlignmentResult alignmentResult = await _approachAlignmentService.ApproachAlignmentAsync(
|
||||
alignmentRequest,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (alignmentResult.Succeeded)
|
||||
{
|
||||
string.Format("<22>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>{0}", alignmentResult.CompletedIterations).LogInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Format("<22>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD>{0}", alignmentResult.Message).LogInfo();
|
||||
throw alignmentResult.Exception ?? new InvalidOperationException(alignmentResult.Message);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"<22>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("<22>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><ECB3A3>{0}", ex.Message).LogInfo();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD>ζ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ궨<DAB1><EAB6A8><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD>λ<EFBFBD><CEBB>ִ<EFBFBD><D6B4>һ<EFBFBD><D2BB>ʶ<EFBFBD><CAB6><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD>
|
||||
/// </summary>
|
||||
public class SingleAlignmentPostProcessor : ICalibrationPostProcessor
|
||||
{
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private readonly IReadOnlyList<ApproachAlignmentAxis> _alignmentAxes;
|
||||
private readonly CameraType _camera;
|
||||
|
||||
public SingleAlignmentPostProcessor(
|
||||
ApproachAlignmentService approachAlignmentService,
|
||||
IEnumerable<ApproachAlignmentAxis> alignmentAxes,
|
||||
CameraType camera = CameraType.TopPositionCamera)
|
||||
{
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
|
||||
if (alignmentAxes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(alignmentAxes));
|
||||
}
|
||||
|
||||
_alignmentAxes = alignmentAxes.ToList().AsReadOnly();
|
||||
|
||||
if (_alignmentAxes.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫһ<D2AA><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ᡣ", nameof(alignmentAxes));
|
||||
}
|
||||
|
||||
_camera = camera;
|
||||
}
|
||||
|
||||
public string Name => "SingleAlignment";
|
||||
|
||||
public async Task ExecuteAsync(OriginCalibrationExecutionResult calibrationResult, CancellationToken cancellationToken, object pars = null)
|
||||
{
|
||||
"ִ<>е<EFBFBD><D0B5>ζ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...".LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
ApproachAlignmentRequest alignmentRequest = new ApproachAlignmentRequest(_alignmentAxes, _camera);
|
||||
if (pars is CenterRecognitionParameters centerRecognitionParameters)
|
||||
{
|
||||
alignmentRequest.RecognitionParameters = centerRecognitionParameters;
|
||||
}
|
||||
|
||||
ApproachAlignmentResult alignmentResult = await _approachAlignmentService.SingleAlignmentAsync(
|
||||
alignmentRequest,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (alignmentResult.Succeeded)
|
||||
{
|
||||
string.Format("<22><><EFBFBD>ζ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>ɣ<EFBFBD>ִ<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD>{0}", alignmentResult.CompletedIterations).LogInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Format("<22><><EFBFBD>ζ<EFBFBD>λʧ<CEBB>ܣ<EFBFBD>{0}", alignmentResult.Message).LogInfo();
|
||||
throw alignmentResult.Exception ?? new InvalidOperationException(alignmentResult.Message);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"<22><><EFBFBD>ζ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("<22><><EFBFBD>ζ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><ECB3A3>{0}", ex.Message).LogInfo();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 标定后处理接口,用于在避让轴和标定轴移动到位后执行模块特定的逻辑
|
||||
/// </summary>
|
||||
public interface ICalibrationPostProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理器名称,用于日志和诊断
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 在运动完成后、标定前执行处理逻辑
|
||||
/// </summary>
|
||||
/// <param name="calibrationResult">运动执行结果,包含各轴的实际位置</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <param name="pars">可选参数</param>
|
||||
/// <returns>异步任务</returns>
|
||||
Task ExecuteAsync(OriginCalibrationExecutionResult calibrationResult, CancellationToken cancellationToken,object pars=null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.Service
|
||||
{
|
||||
public sealed class OriginCalibrationExecutionResult
|
||||
{
|
||||
public OriginCalibrationExecutionResult(IDictionary<string, double> actualPositions)
|
||||
{
|
||||
var positions = actualPositions ?? new Dictionary<string, double>(StringComparer.Ordinal);
|
||||
ActualPositions = new ReadOnlyDictionary<string, double>(new Dictionary<string, double>(positions, StringComparer.Ordinal));
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, double> ActualPositions { get; private set; }
|
||||
}
|
||||
|
||||
[Singleton]
|
||||
public class OriginCalibrationMotionService
|
||||
{
|
||||
private const int PositionSettleDelayMilliseconds = 200;
|
||||
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly SafeAxisMotion _safeAxisMotion;
|
||||
|
||||
public OriginCalibrationMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion)
|
||||
{
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
|
||||
}
|
||||
|
||||
public async Task MoveAxisAsync(string axisName, double position, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
string.Format("原点标定正在移动轴“{0}”到位置 {1:F3}。", axisName, position).LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _safeAxisMotion.MoveAbsAsync(axisName, position, MotionController.DefaultTimeoutMilliseconds, cancellationToken).ConfigureAwait(false);
|
||||
result.EnsureSuccess();
|
||||
string.Format("原点标定轴“{0}”已到达目标位置 {1:F3}。", axisName, position).LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
string.Format("原点标定轴“{0}”移动已取消。", axisName).LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定轴“{0}”移动失败:{1}", axisName, ex.Message).LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<OriginCalibrationExecutionResult> ExecuteAsync(IEnumerable<AvoidanceAxisItem> avoidanceAxes, IEnumerable<CalibrationAxisItem> calibrationAxes, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var avoidanceAxisList = avoidanceAxes == null ? new List<AvoidanceAxisItem>() : avoidanceAxes.Where(item => item != null).ToList();
|
||||
var calibrationAxisList = calibrationAxes == null ? new List<CalibrationAxisItem>() : calibrationAxes.Where(item => item != null).ToList();
|
||||
|
||||
string.Format(
|
||||
"原点标定执行开始,避让轴数量:{0},标定轴数量:{1}。",
|
||||
avoidanceAxisList.Count,
|
||||
calibrationAxisList.Count).LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
await ExecuteBatchAsync(CreateRequests(avoidanceAxisList, item => item.AxisName, item => item.Position), cancellationToken).ConfigureAwait(false);
|
||||
await ExecuteBatchAsync(CreateRequests(calibrationAxisList, item => item.AxisName, item => item.TargetPosition), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
string.Format(
|
||||
"原点标定等待 {0} ms 以稳定轴反馈,再读取实际位置。",
|
||||
PositionSettleDelayMilliseconds).LogInfo();
|
||||
await Task.Delay(PositionSettleDelayMilliseconds, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var actualPositions = new Dictionary<string, double>(StringComparer.Ordinal);
|
||||
foreach (var calibrationAxis in calibrationAxisList)
|
||||
{
|
||||
if (calibrationAxis == null || string.IsNullOrWhiteSpace(calibrationAxis.AxisName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var axis = _hardware.GetAxisByName(calibrationAxis.AxisName);
|
||||
if (axis == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
actualPositions[calibrationAxis.AxisName] = Math.Round(GetActualPosition(axis), 3);
|
||||
string.Format(
|
||||
"原点标定已采集轴“{0}”的实际位置:{1:F3}。",
|
||||
calibrationAxis.AxisName,
|
||||
actualPositions[calibrationAxis.AxisName]).LogInfo();
|
||||
}
|
||||
|
||||
string.Format("原点标定执行完成,共采集 {0} 个标定轴的实际位置。", actualPositions.Count).LogInfo();
|
||||
return new OriginCalibrationExecutionResult(actualPositions);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"原点标定执行已取消。".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定执行失败:{0}", ex.Message).LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteBatchAsync(MotionMoveRequest[] requests, CancellationToken cancellationToken)
|
||||
{
|
||||
if (requests.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await _safeAxisMotion.SafeMoveAsync(cancellationToken, requests).ConfigureAwait(false);
|
||||
result.EnsureSuccess();
|
||||
}
|
||||
|
||||
private MotionMoveRequest[] CreateRequests<TItem>(IEnumerable<TItem> items, Func<TItem, string> axisNameAccessor, Func<TItem, double> positionAccessor)
|
||||
{
|
||||
if (items == null)
|
||||
{
|
||||
return new MotionMoveRequest[0];
|
||||
}
|
||||
|
||||
var requests = new List<MotionMoveRequest>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var axisName = axisNameAccessor(item);
|
||||
if (string.IsNullOrWhiteSpace(axisName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_hardware.GetAxisByName(axisName) == null)
|
||||
{
|
||||
string.Format("原点标定轴“{0}”在硬件管理器中不存在。", axisName).LogSysError();
|
||||
continue;
|
||||
}
|
||||
|
||||
requests.Add(MotionMoveRequest.ForAxisName(axisName, positionAccessor(item)));
|
||||
}
|
||||
|
||||
return requests.ToArray();
|
||||
}
|
||||
|
||||
private static double GetActualPosition(IAxis axis)
|
||||
{
|
||||
return axis.State != null ? axis.State.ActualPos : axis.GetPositionImmediate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
<UserControl x:Class="MainShell.PageCalib.OriginCalib.View.OriginCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800"
|
||||
d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AvoidanceAxisNameStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#E8821A"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TableHeaderStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CalibAxisNameStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Foreground" Value="#2D3748"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TargetValueStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="85"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="0,1"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallIconButtonStyle" TargetType="Button">
|
||||
<Setter Property="Width" Value="28"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Margin" Value="1,0"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F0F4F8"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AddAxisButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallIconButtonStyle}">
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Setter Property="Foreground" Value="#28A745"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleActionButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="4,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CalibStartButtonStyle" TargetType="Button" BasedOn="{StaticResource ModuleActionButtonStyle}">
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
<Setter Property="BorderBrush" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
<Setter Property="BorderBrush" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
<Setter Property="Cursor" Value="Arrow"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BadgeStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
<Setter Property="Padding" Value="5,1"/>
|
||||
<Setter Property="Margin" Value="3,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="{DynamicResource OriginCalibMonitorTitle}"
|
||||
Foreground="#7A8FA6"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModel}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="{DynamicResource OriginCalibSaveConfig}"
|
||||
Click="{mw:Action SaveConfig}"
|
||||
Style="{StaticResource SaveButtonStyle}"
|
||||
Width="160"
|
||||
Height="34"
|
||||
Margin="5,0"/>
|
||||
<Button Content="{DynamicResource OriginCalibResetAll}"
|
||||
Click="{mw:Action ResetAll}"
|
||||
Style="{StaticResource ResetButtonStyle}"
|
||||
Width="130"
|
||||
Height="34"
|
||||
Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
<ItemsControl ItemsSource="{Binding Modules}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{StaticResource ModuleCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="46"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="[] " Foreground="#8892A0" FontSize="14" VerticalAlignment="Center"/>
|
||||
<TextBlock FontWeight="SemiBold" FontSize="13" Foreground="#2D3748" VerticalAlignment="Center">
|
||||
<Run Text="{DynamicResource OriginCalibModuleLabel}"/>
|
||||
<Run Text=" "/>
|
||||
<Run Text="{Binding Index, StringFormat=D2}"/>
|
||||
<Run Text=": "/>
|
||||
<Run Text="{Binding ModuleName}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource BadgeStyle}"
|
||||
Background="#EDF2F7"
|
||||
Visibility="{Binding ShowIndependentBadge}">
|
||||
<TextBlock Text="{DynamicResource OriginCalibBadgeIndependent}" FontSize="10" Foreground="#718096"/>
|
||||
</Border>
|
||||
<Border Style="{StaticResource BadgeStyle}"
|
||||
Background="#FFF5EB"
|
||||
Visibility="{Binding ShowAvoidanceBadge}">
|
||||
<TextBlock Text="{DynamicResource OriginCalibBadgeAvoidance}" FontSize="10" Foreground="#E8821A"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Row="1" MinHeight="170">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="{DynamicResource OriginCalibAvoidanceHeader}"
|
||||
Foreground="#E8821A"
|
||||
FontWeight="SemiBold"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<Button Content="+"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource AddAxisButtonStyle}"
|
||||
IsEnabled="{Binding CanStartCalib}"
|
||||
Click="{mw:Action AddAvoidanceAxis}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
ToolTip="{DynamicResource OriginCalibAddAvoidanceAxis}"/>
|
||||
</Grid>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding AvoidanceAxes}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="30"/>
|
||||
<ColumnDefinition Width="30"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding AxisName}"
|
||||
Style="{StaticResource AvoidanceAxisNameStyle}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{DynamicResource OriginCalibAxisName}"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
IsEnabled="{Binding CanTeach}"
|
||||
Minimum="-99999"
|
||||
Maximum="99999"
|
||||
DecimalPlaces="2"
|
||||
Width="68"
|
||||
Height="26"
|
||||
Margin="0,1"
|
||||
HorizontalAlignment="Right"/>
|
||||
<Button Grid.Column="2"
|
||||
Style="{StaticResource SmallIconButtonStyle}"
|
||||
IsEnabled="{Binding CanTeach}"
|
||||
Click="{mw:Action TeachPosition}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
ToolTip="{DynamicResource OriginCalibTeachAvoidancePosition}">
|
||||
<TextBlock Text="T" FontSize="12" Foreground="#4A5568"/>
|
||||
</Button>
|
||||
<Button Grid.Column="3"
|
||||
Style="{StaticResource SmallIconButtonStyle}"
|
||||
IsEnabled="{Binding CanTeach}"
|
||||
Click="{mw:Action Remove}" mw:View.ActionTarget="{Binding}"
|
||||
ToolTip="{DynamicResource OriginCalibRemoveAxis}">
|
||||
<TextBlock Text="X" FontSize="11" Foreground="#A0AEC0"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Row="1" Margin="10,8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="26"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="65"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.ColumnSpan="5" Background="#F7F9FC" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1"/>
|
||||
<TextBlock Grid.Column="0" Text="{DynamicResource OriginCalibAxisHeader}" Style="{StaticResource TableHeaderStyle}" Margin="6,0"/>
|
||||
<TextBlock Grid.Column="1" Text="{DynamicResource OriginCalibTargetHeader}" Style="{StaticResource TableHeaderStyle}" HorizontalAlignment="Center"/>
|
||||
<TextBlock Grid.Column="2" Text="{DynamicResource OriginCalibActualHeader}" Style="{StaticResource TableHeaderStyle}" HorizontalAlignment="Center"/>
|
||||
<TextBlock Grid.Column="3" Text="{DynamicResource OriginCalibOffsetHeader}" Style="{StaticResource TableHeaderStyle}" HorizontalAlignment="Center"/>
|
||||
<TextBlock Grid.Column="4" Text="{DynamicResource OriginCalibStatusHeader}" Style="{StaticResource TableHeaderStyle}" HorizontalAlignment="Center"/>
|
||||
</Grid>
|
||||
|
||||
<ItemsControl Grid.Row="1" ItemsSource="{Binding CalibrationAxes}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid MinHeight="30">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="65"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.ColumnSpan="5" BorderBrush="#F0F4F8" BorderThickness="0,0,0,1"/>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding AxisName}"
|
||||
Style="{StaticResource CalibAxisNameStyle}"
|
||||
Margin="6,0"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding TargetPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding LastPosition, StringFormat=F3}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="#4A5568"/>
|
||||
<TextBlock Grid.Column="3"
|
||||
Text="{Binding OffsetText}"
|
||||
Foreground="{Binding OffsetBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"/>
|
||||
<Ellipse Grid.Column="4"
|
||||
Width="12"
|
||||
Height="12"
|
||||
Fill="{Binding StatusBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="2"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,1,0,0"
|
||||
Background="#FAFBFC"
|
||||
CornerRadius="0,0,6,6"
|
||||
Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Button Content="{DynamicResource OriginCalibTeachTarget}"
|
||||
Click="{mw:Action TeachCalibPositions}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource CommonButtonStyle}"
|
||||
Width="110"
|
||||
Height="32"
|
||||
Margin="0,0,6,0"/>
|
||||
<Button Content="{DynamicResource MakeModel}"
|
||||
Click="{mw:Action MakeTemplate}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource CommonButtonStyle}"
|
||||
Width="110"
|
||||
Height="32"
|
||||
Margin="0,0,6,0"/>
|
||||
<Button Content="{DynamicResource OriginCalibStartCalib}"
|
||||
Click="{mw:Action StartCalib}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource CalibStartButtonStyle}"
|
||||
IsEnabled="{Binding CanStartCalib}"
|
||||
Width="110"
|
||||
Height="32"
|
||||
Margin="0,0,6,0"/>
|
||||
</StackPanel>
|
||||
<Button HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource SmallIconButtonStyle}"
|
||||
ToolTip="{DynamicResource OriginCalibModuleSettings}">
|
||||
<TextBlock Text="..." FontSize="13" Foreground="#718096"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.View
|
||||
{
|
||||
public partial class OriginCalibView : UserControl
|
||||
{
|
||||
public OriginCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.ViewModel
|
||||
{
|
||||
public class AvoidanceAxisViewModel : PropertyChangedBase
|
||||
{
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly OriginCalibrationMotionService _motionService;
|
||||
private readonly AvoidanceAxisItem _item;
|
||||
private readonly Action<AvoidanceAxisViewModel> _removeCallback;
|
||||
private bool _canTeach = true;
|
||||
|
||||
private const string DialogCaption = "原点标定";
|
||||
|
||||
public AvoidanceAxisItem Item => _item;
|
||||
|
||||
public string AxisName
|
||||
{
|
||||
get { return _item.AxisName; }
|
||||
set { _item.AxisName = value; NotifyOfPropertyChange(nameof(AxisName)); }
|
||||
}
|
||||
|
||||
public double Position
|
||||
{
|
||||
get { return _item.Position; }
|
||||
set { _item.Position = value; NotifyOfPropertyChange(nameof(Position)); }
|
||||
}
|
||||
|
||||
public bool CanTeach
|
||||
{
|
||||
get { return _canTeach; }
|
||||
set { SetAndNotify(ref _canTeach, value); }
|
||||
}
|
||||
|
||||
public AvoidanceAxisViewModel(AvoidanceAxisItem item, HardwareManager hardware, OriginCalibrationMotionService motionService, Action<AvoidanceAxisViewModel> removeCallback)
|
||||
{
|
||||
_item = item ?? throw new ArgumentNullException(nameof(item));
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_removeCallback = removeCallback;
|
||||
}
|
||||
|
||||
public void TeachPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_hardware.AxesDic != null && _hardware.AxesDic.ContainsKey(AxisName))
|
||||
{
|
||||
Position = Math.Round(_hardware.AxesDic[AxisName].State.ActualPos, 3);
|
||||
string.Format("原点标定避让轴“{0}”示教位置成功:{1}", AxisName, Position).LogInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Format("原点标定示教避让位置时未找到轴“{0}”。", AxisName).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibAxisNotFound, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning, AxisName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定读取轴“{0}”位置失败:{1}", AxisName, ex.Message).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibReadPositionFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task MoveToPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_hardware.AxesDic != null && _hardware.AxesDic.ContainsKey(AxisName))
|
||||
{
|
||||
await _motionService.MoveAxisAsync(AxisName, Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Format("原点标定移动避让轴时未找到轴“{0}”。", AxisName).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibAxisNotFound, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning, AxisName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定移动避让轴“{0}”失败:{1}", AxisName, ex.Message).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibMoveFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_removeCallback != null)
|
||||
{
|
||||
string.Format("原点标定正在删除避让轴“{0}”。", AxisName).LogInfo();
|
||||
_removeCallback(this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定删除避让轴“{0}”失败:{1}", AxisName, ex.Message).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibDeleteAxisFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.ViewModel
|
||||
{
|
||||
public class CalibrationAxisViewModel : PropertyChangedBase
|
||||
{
|
||||
private static readonly double OffsetTolerance = 0.05;
|
||||
private static readonly Brush InactiveBrush = CreateFrozenBrush(0xCC, 0xCC, 0xCC);
|
||||
private static readonly Brush InToleranceBrush = CreateFrozenBrush(0x28, 0xA7, 0x45);
|
||||
private static readonly Brush WarningBrush = CreateFrozenBrush(0xFD, 0x7E, 0x14);
|
||||
|
||||
private readonly CalibrationAxisItem _item;
|
||||
|
||||
public CalibrationAxisItem Item => _item;
|
||||
|
||||
public string AxisName
|
||||
{
|
||||
get { return _item.AxisName; }
|
||||
set { _item.AxisName = value; NotifyOfPropertyChange(nameof(AxisName)); }
|
||||
}
|
||||
|
||||
public double TargetPosition
|
||||
{
|
||||
get { return _item.TargetPosition; }
|
||||
set
|
||||
{
|
||||
_item.TargetPosition = value;
|
||||
NotifyOfPropertyChange(nameof(TargetPosition));
|
||||
UpdateOffset();
|
||||
}
|
||||
}
|
||||
|
||||
public double LastPosition
|
||||
{
|
||||
get { return _item.LastPosition; }
|
||||
set
|
||||
{
|
||||
_item.LastPosition = value;
|
||||
NotifyOfPropertyChange(nameof(LastPosition));
|
||||
UpdateOffset();
|
||||
}
|
||||
}
|
||||
|
||||
public double Offset
|
||||
{
|
||||
get { return _item.Offset; }
|
||||
private set
|
||||
{
|
||||
_item.Offset = value;
|
||||
NotifyOfPropertyChange(nameof(Offset));
|
||||
NotifyOfPropertyChange(nameof(OffsetText));
|
||||
NotifyOfPropertyChange(nameof(OffsetBrush));
|
||||
NotifyOfPropertyChange(nameof(StatusBrush));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCalibrated
|
||||
{
|
||||
get { return _item.IsCalibrated; }
|
||||
set
|
||||
{
|
||||
_item.IsCalibrated = value;
|
||||
NotifyOfPropertyChange(nameof(IsCalibrated));
|
||||
NotifyOfPropertyChange(nameof(OffsetText));
|
||||
NotifyOfPropertyChange(nameof(OffsetBrush));
|
||||
NotifyOfPropertyChange(nameof(StatusBrush));
|
||||
}
|
||||
}
|
||||
|
||||
public string OffsetText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsCalibrated) return "-";
|
||||
return Offset >= 0 ? string.Format("+{0:F3}", Offset) : string.Format("{0:F3}", Offset);
|
||||
}
|
||||
}
|
||||
|
||||
public Brush OffsetBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsCalibrated) return Brushes.Gray;
|
||||
return Math.Abs(Offset) <= OffsetTolerance ? InToleranceBrush : WarningBrush;
|
||||
}
|
||||
}
|
||||
|
||||
public Brush StatusBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsCalibrated) return InactiveBrush;
|
||||
return Math.Abs(Offset) <= OffsetTolerance ? InToleranceBrush : WarningBrush;
|
||||
}
|
||||
}
|
||||
|
||||
public CalibrationAxisViewModel(CalibrationAxisItem item)
|
||||
{
|
||||
_item = item ?? throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
LastPosition = 0;
|
||||
IsCalibrated = false;
|
||||
}
|
||||
|
||||
private void UpdateOffset()
|
||||
{
|
||||
Offset = Math.Round(_item.LastPosition, 3);
|
||||
}
|
||||
|
||||
private static Brush CreateFrozenBrush(byte red, byte green, byte blue)
|
||||
{
|
||||
var brush = new SolidColorBrush(Color.FromRgb(red, green, blue));
|
||||
brush.Freeze();
|
||||
return brush;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.VisionTemple.ViewModel;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using MainShell.Resources.CustomControl;
|
||||
using MwFramework.Device;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.ViewModel
|
||||
{
|
||||
public class OriginCalibModuleViewModel : PropertyChangedBase
|
||||
{
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly OriginCalibrationMotionService _motionService;
|
||||
private readonly OriginCalibModuleItem _item;
|
||||
private readonly VisionTempleWindowViewModel _visionTempleWindowViewModel;
|
||||
|
||||
private int _index;
|
||||
private bool _isCalibrating;
|
||||
|
||||
public OriginCalibModuleItem Item => _item;
|
||||
|
||||
public int Index
|
||||
{
|
||||
get { return _index; }
|
||||
set { SetAndNotify(ref _index, value); }
|
||||
}
|
||||
|
||||
public string ModuleName
|
||||
{
|
||||
get { return _item.ModuleName; }
|
||||
set { _item.ModuleName = value; NotifyOfPropertyChange(nameof(ModuleName)); }
|
||||
}
|
||||
|
||||
public bool IsIndependent
|
||||
{
|
||||
get { return _item.IsIndependent; }
|
||||
set
|
||||
{
|
||||
_item.IsIndependent = value;
|
||||
NotifyOfPropertyChange(nameof(IsIndependent));
|
||||
NotifyOfPropertyChange(nameof(ShowIndependentBadge));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCalibrating
|
||||
{
|
||||
get { return _isCalibrating; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isCalibrating, value);
|
||||
NotifyOfPropertyChange(nameof(CanStartCalib));
|
||||
|
||||
// 标定进行中禁用避让示教和删除操作
|
||||
foreach (AvoidanceAxisViewModel axis in AvoidanceAxes)
|
||||
{
|
||||
axis.CanTeach = !value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanStartCalib
|
||||
{
|
||||
get { return !IsCalibrating; }
|
||||
}
|
||||
|
||||
public bool HasAvoidanceAxes
|
||||
{
|
||||
get { return AvoidanceAxes.Count > 0; }
|
||||
}
|
||||
|
||||
public System.Windows.Visibility ShowIndependentBadge
|
||||
{
|
||||
get { return IsIndependent ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed; }
|
||||
}
|
||||
|
||||
public System.Windows.Visibility ShowAvoidanceBadge
|
||||
{
|
||||
get { return HasAvoidanceAxes ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed; }
|
||||
}
|
||||
|
||||
public ObservableCollection<AvoidanceAxisViewModel> AvoidanceAxes { get; } = new ObservableCollection<AvoidanceAxisViewModel>();
|
||||
public ObservableCollection<CalibrationAxisViewModel> CalibrationAxes { get; } = new ObservableCollection<CalibrationAxisViewModel>();
|
||||
|
||||
public OriginCalibModuleViewModel(
|
||||
OriginCalibModuleItem item,
|
||||
HardwareManager hardware,
|
||||
OriginCalibrationMotionService motionService,
|
||||
VisionTempleWindowViewModel visionTempleWindowViewModel)
|
||||
{
|
||||
_item = item ?? throw new ArgumentNullException(nameof(item));
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_visionTempleWindowViewModel = visionTempleWindowViewModel ?? throw new ArgumentNullException(nameof(visionTempleWindowViewModel));
|
||||
|
||||
foreach (AvoidanceAxisItem axisItem in item.AvoidanceAxes)
|
||||
{
|
||||
AvoidanceAxes.Add(new AvoidanceAxisViewModel(axisItem, hardware, motionService, OnRemoveAvoidanceAxis));
|
||||
}
|
||||
|
||||
foreach (CalibrationAxisItem calibItem in item.CalibrationAxes)
|
||||
{
|
||||
CalibrationAxes.Add(new CalibrationAxisViewModel(calibItem));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAvoidanceAxis()
|
||||
{
|
||||
AvoidanceAxisItem newItem = new AvoidanceAxisItem { AxisName = "NewAxis", Position = 0.0 };
|
||||
_item.AvoidanceAxes.Add(newItem);
|
||||
AvoidanceAxisViewModel newVm = new AvoidanceAxisViewModel(newItem, _hardware, _motionService, OnRemoveAvoidanceAxis);
|
||||
newVm.CanTeach = !_isCalibrating;
|
||||
AvoidanceAxes.Add(newVm);
|
||||
NotifyOfPropertyChange(nameof(HasAvoidanceAxes));
|
||||
NotifyOfPropertyChange(nameof(ShowAvoidanceBadge));
|
||||
}
|
||||
|
||||
private void OnRemoveAvoidanceAxis(AvoidanceAxisViewModel vm)
|
||||
{
|
||||
if (_isCalibrating)
|
||||
{
|
||||
"原点标定进行中,无法删除避让轴。".LogSysError();
|
||||
LocalizedMessageBox.Show(MessageKey.OriginCalibDeleteAxisDuringCalibration, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string.Format("原点标定模块“{1}”准备删除避让轴“{0}”。", vm.AxisName, ModuleName).LogInfo();
|
||||
_item.AvoidanceAxes.Remove(vm.Item);
|
||||
AvoidanceAxes.Remove(vm);
|
||||
NotifyOfPropertyChange(nameof(HasAvoidanceAxes));
|
||||
NotifyOfPropertyChange(nameof(ShowAvoidanceBadge));
|
||||
string.Format("原点标定删除避让轴成功,当前剩余 {0} 个避让轴。", AvoidanceAxes.Count).LogInfo();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定删除避让轴“{0}”失败:{1}", vm.AxisName, ex.Message).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibDeleteAxisFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void TeachCalibPositions()
|
||||
{
|
||||
foreach (CalibrationAxisViewModel calibAxis in CalibrationAxes)
|
||||
{
|
||||
if (_hardware.AxesDic != null && _hardware.AxesDic.ContainsKey(calibAxis.AxisName))
|
||||
{
|
||||
calibAxis.TargetPosition = Math.Round(_hardware.AxesDic[calibAxis.AxisName].State.ActualPos, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeTemplate()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(Item.ModuleName== OriginCalibModuleNames.GantryX2)
|
||||
{
|
||||
_visionTempleWindowViewModel.SetCamera(CameraType.TopWideCamera);
|
||||
}
|
||||
else
|
||||
{
|
||||
_visionTempleWindowViewModel.SetCamera(CameraType.TopPositionCamera);
|
||||
}
|
||||
_visionTempleWindowViewModel.TemplatePath = _item.TemplatePath;
|
||||
$"原点标定模块“{ModuleName}”打开视觉模板制作窗口。".LogInfo();
|
||||
_visionTempleWindowViewModel.ShowWindow();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
$"原点标定模块“{ModuleName}”打开视觉模板制作窗口失败:{ex.Message}".LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(
|
||||
MessageKey.OriginCalibOpenVisionTemplateFailed,
|
||||
MessageKey.TitleError,
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error,
|
||||
ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartCalib()
|
||||
{
|
||||
if (IsCalibrating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsCalibrating = true;
|
||||
LoadingService.Instance.Show(string.Format("模块 {0} 正在标定...", ModuleName), true, true);
|
||||
try
|
||||
{
|
||||
string.Format(
|
||||
"原点标定模块“{0}”开始标定,避让轴数量:{1},标定轴数量:{2}。",
|
||||
ModuleName,
|
||||
AvoidanceAxes.Count,
|
||||
CalibrationAxes.Count).LogInfo();
|
||||
|
||||
var calibrationResult = await _motionService.ExecuteAsync(
|
||||
AvoidanceAxes.Select(x => x.Item),
|
||||
CalibrationAxes.Select(x => x.Item),
|
||||
LoadingService.Instance.Token);
|
||||
|
||||
// 执行模块特定的后处理逻辑,通常在运动完成后、标定写入前
|
||||
if (_item.PostProcessor != null)
|
||||
{
|
||||
string.Format(
|
||||
"原点标定模块“{0}”执行后处理“{1}”。",
|
||||
ModuleName,
|
||||
_item.PostProcessor.Name).LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
await _item.PostProcessor.ExecuteAsync(calibrationResult, LoadingService.Instance.Token, new CenterRecognitionParameters
|
||||
{
|
||||
TemplatePath = _item.TemplatePath,
|
||||
Type = CenterRecognitionType.Template
|
||||
});
|
||||
string.Format(
|
||||
"原点标定模块“{0}”后处理“{1}”完成。",
|
||||
ModuleName,
|
||||
_item.PostProcessor.Name).LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
string.Format(
|
||||
"原点标定模块“{0}”后处理“{1}”被取消。",
|
||||
ModuleName,
|
||||
_item.PostProcessor.Name).LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format(
|
||||
"原点标定模块“{0}”后处理“{1}”失败:{2}",
|
||||
ModuleName,
|
||||
_item.PostProcessor.Name,
|
||||
ex.Message).LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CalibrationAxisViewModel calibAxis in CalibrationAxes)
|
||||
{
|
||||
IAxis axis = ResolveCalibrationAxis(calibAxis.AxisName);
|
||||
if (axis != null)
|
||||
{
|
||||
calibAxis.LastPosition = Math.Round(GetActualPosition(axis), 3);
|
||||
calibAxis.IsCalibrated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
double lastPosition;
|
||||
if (calibrationResult.ActualPositions.TryGetValue(calibAxis.AxisName, out lastPosition))
|
||||
{
|
||||
calibAxis.LastPosition = lastPosition;
|
||||
calibAxis.IsCalibrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
string.Format("原点标定模块“{0}”标定完成。", ModuleName).LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
string.Format("原点标定模块“{0}”取消标定。", ModuleName).LogInfo();
|
||||
LocalizedMessageBox.Show(MessageKey.OriginCalibCalibrationCanceled, MessageKey.TitleWarning, MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("原点标定模块“{0}”标定失败:{1}", ModuleName, ex.Message).LogSysError();
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibCalibrationFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LoadingService.Instance.Hide();
|
||||
IsCalibrating = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetModule()
|
||||
{
|
||||
foreach (CalibrationAxisViewModel calibAxis in CalibrationAxes)
|
||||
{
|
||||
calibAxis.Reset();
|
||||
}
|
||||
|
||||
string.Format("原点标定模块“{0}”已复位。", ModuleName).LogInfo();
|
||||
}
|
||||
|
||||
private IAxis ResolveCalibrationAxis(string axisName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(axisName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_hardware.AxesDic != null && _hardware.AxesDic.ContainsKey(axisName))
|
||||
{
|
||||
return _hardware.AxesDic[axisName];
|
||||
}
|
||||
|
||||
if (string.Equals(axisName, "X1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _hardware.Axis_X1;
|
||||
}
|
||||
|
||||
if (string.Equals(axisName, "Y1", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _hardware.Axis_Y1;
|
||||
}
|
||||
|
||||
if (string.Equals(axisName, "X2", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _hardware.Axis_X2;
|
||||
}
|
||||
|
||||
if (string.Equals(axisName, "Y2", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _hardware.Axis_Y2;
|
||||
}
|
||||
|
||||
if (string.Equals(axisName, "WSX3", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _hardware.Axis_WS_X3;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static double GetActualPosition(IAxis axis)
|
||||
{
|
||||
if (axis == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return axis.State != null ? axis.State.ActualPos : axis.GetPositionImmediate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Common.VisionTemple.ViewModel;
|
||||
using MainShell.EventArgsFolder;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Models;
|
||||
using MainShell.Motion;
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Device;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.PageCalib.OriginCalib.ViewModel
|
||||
{
|
||||
public class OriginCalibViewModel : BaseScreen, IPage
|
||||
{
|
||||
public string Name { get; set; } = "OriginCalib";
|
||||
|
||||
private readonly OriginCalibSetting _setting;
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly OriginCalibrationMotionService _originCalibrationMotionService;
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private readonly VisionTempleWindowViewModel _visionTempleWindowViewModel;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private bool _isInitialized;
|
||||
|
||||
private const string DialogCaption = "原点标定";
|
||||
|
||||
public ObservableCollection<OriginCalibModuleViewModel> Modules { get; } = new ObservableCollection<OriginCalibModuleViewModel>();
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModel;
|
||||
public CameraAxisViewModel CameraAxisViewModel
|
||||
{
|
||||
get { return _cameraAxisViewModel; }
|
||||
private set { SetAndNotify(ref _cameraAxisViewModel, value); }
|
||||
}
|
||||
|
||||
public OriginCalibViewModel(
|
||||
HardwareManager hardware,
|
||||
OriginCalibrationMotionService originCalibrationMotionService,
|
||||
ApproachAlignmentService approachAlignmentService,
|
||||
VisionTempleWindowViewModel visionTempleWindowViewModel,
|
||||
IEventAggregator eventAggregator)
|
||||
{
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_originCalibrationMotionService = originCalibrationMotionService ?? throw new ArgumentNullException(nameof(originCalibrationMotionService));
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
_visionTempleWindowViewModel = visionTempleWindowViewModel ?? throw new ArgumentNullException(nameof(visionTempleWindowViewModel));
|
||||
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
||||
_setting = OriginCalibSetting.LoadOrCreate();
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
|
||||
if (_isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CameraAxisViewModel = IoC.Get<CameraAxisViewModel>();
|
||||
CameraAxisViewModel.CameraAxisDevices.HardwareDeviceList = _hardware.CameraAxisManager.TopPositionAndWideCameraAxisDevices;
|
||||
|
||||
InitializePostProcessors();
|
||||
RebuildModuleViewModels();
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
private void InitializePostProcessors()
|
||||
{
|
||||
foreach (OriginCalibModuleItem module in _setting.Modules)
|
||||
{
|
||||
if (module == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
module.PostProcessor = CreateDefaultPostProcessor(module);
|
||||
}
|
||||
}
|
||||
|
||||
private ICalibrationPostProcessor CreateDefaultPostProcessor(OriginCalibModuleItem module)
|
||||
{
|
||||
if (module == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(module.TemplatePath) || module.CalibrationAxes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ApproachAlignmentAxis> alignmentAxes = module.CalibrationAxes
|
||||
.Where(item => item != null)
|
||||
.Select(item => item.AxisName)
|
||||
.Where(axisName => !string.IsNullOrWhiteSpace(axisName))
|
||||
.Select(axisName => new ApproachAlignmentAxis(axisName, 0.005))
|
||||
.ToList();
|
||||
|
||||
if (alignmentAxes.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SingleAlignmentPostProcessor(
|
||||
_approachAlignmentService,
|
||||
alignmentAxes,
|
||||
CameraType.TopPositionCamera);
|
||||
}
|
||||
|
||||
|
||||
private void RebuildModuleViewModels()
|
||||
{
|
||||
Modules.Clear();
|
||||
for (int i = 0; i < _setting.Modules.Count; i++)
|
||||
{
|
||||
OriginCalibModuleViewModel moduleVm = new OriginCalibModuleViewModel(
|
||||
_setting.Modules[i],
|
||||
_hardware,
|
||||
_originCalibrationMotionService,
|
||||
_visionTempleWindowViewModel);
|
||||
moduleVm.Index = i + 1;
|
||||
Modules.Add(moduleVm);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
_setting.Write();
|
||||
_eventAggregator.Publish(CreateOriginCalibDataChangedEventArgs());
|
||||
LocalizedMessageBox.Show(MessageKey.OriginCalibConfigSaved, MessageKey.TitleInfo, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LocalizedMessageBox.ShowFormat(MessageKey.OriginCalibConfigSaveFailed, MessageKey.TitleError, MessageBoxButton.OK, MessageBoxImage.Error, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private OriginCalibDataChangedEventArgs CreateOriginCalibDataChangedEventArgs()
|
||||
{
|
||||
List<OriginCalibAxisOffsetChangedItem> axisOffsets = new List<OriginCalibAxisOffsetChangedItem>();
|
||||
|
||||
foreach (OriginCalibModuleItem module in _setting.Modules)
|
||||
{
|
||||
if (module == null || module.CalibrationAxes == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (CalibrationAxisItem calibrationAxis in module.CalibrationAxes)
|
||||
{
|
||||
if (calibrationAxis == null || string.IsNullOrWhiteSpace(calibrationAxis.AxisName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
axisOffsets.Add(new OriginCalibAxisOffsetChangedItem(calibrationAxis.AxisName, calibrationAxis.Offset));
|
||||
}
|
||||
}
|
||||
|
||||
return new OriginCalibDataChangedEventArgs(axisOffsets);
|
||||
}
|
||||
|
||||
public void ResetAll()
|
||||
{
|
||||
foreach (OriginCalibModuleViewModel module in Modules)
|
||||
{
|
||||
module.ResetModule();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user