|
|
@@ -33,12 +33,14 @@ using System.Collections.Concurrent;
|
|
|
namespace TeamAAS_VP.Services
|
|
|
{
|
|
|
/// <summary>
|
|
|
- /// Lightweight migration of Management.ExecuteRemoteCommand into a dedicated service.
|
|
|
- /// This service depends on existing domain services and will call into them.
|
|
|
- /// Only the core helpers used by the old ExecuteRemoteCommand are migrated (LoadProduct, GetCurrentProductName, GetCurrentProductID, GetCurrentProductSpeed, etc.).
|
|
|
+ /// 远程命令服务:
|
|
|
+ /// 负责解析并执行外部传入的命令字符串(例如 LoadProduct、视觉流程触发、清料任务等)。
|
|
|
+ /// 该类封装了原 Management.ExecuteRemoteCommand 的精简迁移实现,依赖于领域服务(产品、配置、校准、Feeder、相机、机器人、系统数据库等)。
|
|
|
+ /// 线程安全:通过内部计数器和 ConcurrentDictionary 跟踪正在运行的任务。
|
|
|
/// </summary>
|
|
|
public class RemoteCommandService : IRemoteCommandService, INotifyPropertyChanged
|
|
|
{
|
|
|
+ // 依赖服务,由构造函数注入
|
|
|
private readonly IEventAggregator _eventAggregator;
|
|
|
private readonly IProductService _productService;
|
|
|
private readonly IConfigService _configService;
|
|
|
@@ -51,35 +53,60 @@ namespace TeamAAS_VP.Services
|
|
|
private readonly ISystemDatabaseService _systemDatabaseService;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 计时器任务取消令牌
|
|
|
+ /// 节拍计时任务的取消令牌,用于 StartCycleTiming/StopCycleTiming。
|
|
|
/// </summary>
|
|
|
private CancellationTokenSource _cycleTimingCts;
|
|
|
+
|
|
|
/// <summary>
|
|
|
- /// 清料任务取消令牌字典,Key为任务编号
|
|
|
+ /// 清料任务的取消令牌字典,Key 为任务编号(TaskCode)。
|
|
|
+ /// 当需要取消特定清料任务时,通过该字典查找并调用 Cancel。
|
|
|
/// </summary>
|
|
|
private readonly ConcurrentDictionary<int, CancellationTokenSource> _clearMaterialCtsDict = new ConcurrentDictionary<int, CancellationTokenSource>();
|
|
|
|
|
|
- // 字段
|
|
|
+ // 内部执行状态计数器和任务跟踪集合
|
|
|
private int _activeCount;
|
|
|
private int _visionActiveCount;
|
|
|
private readonly ConcurrentDictionary<Guid, Task> _runningTasks = new ConcurrentDictionary<Guid, Task>();
|
|
|
|
|
|
- // 实现 INotifyPropertyChanged
|
|
|
+ // INotifyPropertyChanged 实现
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
private void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
|
|
|
|
|
- // 公开属性(只读)
|
|
|
+ /// <summary>
|
|
|
+ /// 标识是否存在任意正在执行的命令(非视觉与视觉命令)。
|
|
|
+ /// 由 TrackExecutionAsync 自动维护。
|
|
|
+ /// </summary>
|
|
|
public bool IsExecuting => Volatile.Read(ref _activeCount) > 0;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 标识是否存在正在执行的视觉指令。
|
|
|
+ /// 由 TrackExecutionAsync 在 isVision 参数为 true 时自动维护。
|
|
|
+ /// </summary>
|
|
|
public bool IsExecutingVisionCommand => Volatile.Read(ref _visionActiveCount) > 0;
|
|
|
|
|
|
- // 可选事件(如果不想用 INotifyPropertyChanged)
|
|
|
+ /// <summary>
|
|
|
+ /// 当执行状态发生变化(开始/结束)时触发(便于传统事件订阅)。
|
|
|
+ /// </summary>
|
|
|
public event EventHandler ExecutionStateChanged;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 计时器计时通知事件
|
|
|
+ /// 节拍计时的定时回调事件,通知订阅者当前已用时。
|
|
|
/// </summary>
|
|
|
public event EventHandler<TimeSpan> CycleTimingTicked;
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 构造函数,注入必要的系统服务。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="eventAggregator">事件聚合器,用于发布 UI 渲染/消息等事件。</param>
|
|
|
+ /// <param name="regionManager">区域管理器,用于 UI 区域导航(在脚本中可能使用)。</param>
|
|
|
+ /// <param name="productService">产品服务,用于加载/查询产品信息。</param>
|
|
|
+ /// <param name="configService">配置服务,用于读取机器人/任务/Feeder 等配置。</param>
|
|
|
+ /// <param name="calibrationService">校准服务,用于像素到机器人坐标的转换。</param>
|
|
|
+ /// <param name="feederService">Feeder 服务,控制料仓/振动等。</param>
|
|
|
+ /// <param name="cameraService">相机服务,用于图像采集。</param>
|
|
|
+ /// <param name="robotService">机器人服务,提供机器人状态码/调试模式等信息。</param>
|
|
|
+ /// <param name="container">IOC 容器提供者,用于脚本执行时解析依赖。</param>
|
|
|
+ /// <param name="systemDatabaseService">系统数据库服务,用于记录产量/报警等。</param>
|
|
|
public RemoteCommandService(IEventAggregator eventAggregator, IRegionManager regionManager, IProductService productService, IConfigService configService, ICalibrationService calibrationService,
|
|
|
IFeederService feederService, ICameraService cameraService, IRobotService robotService, IContainerProvider container, ISystemDatabaseService systemDatabaseService)
|
|
|
{
|
|
|
@@ -95,15 +122,27 @@ namespace TeamAAS_VP.Services
|
|
|
_systemDatabaseService = systemDatabaseService;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 占位 Dispose 方法(当前无资源释放逻辑)。
|
|
|
+ /// </summary>
|
|
|
public void Dispose() { }
|
|
|
|
|
|
- // 通用包裹器:包装并追踪任意异步工作
|
|
|
+ /// <summary>
|
|
|
+ /// 通用的异步执行包装器。该方法:
|
|
|
+ /// - 为每次执行生成唯一 id 并加入运行任务集合以便跟踪
|
|
|
+ /// - 维护 _activeCount 和 _visionActiveCount
|
|
|
+ /// - 在任务开始/结束时触发属性变化和 ExecutionStateChanged 事件
|
|
|
+ /// - 返回工作 delegate 的结果
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T">工作返回类型</typeparam>
|
|
|
+ /// <param name="work">以 CancellationToken 为参数的异步工作委托</param>
|
|
|
+ /// <param name="isVision">指示该工作是否为视觉命令(影响视觉计数器)</param>
|
|
|
+ /// <param name="ct">外部取消令牌,传递给工作委托</param>
|
|
|
+ /// <returns>工作委托的返回值</returns>
|
|
|
private async Task<T> TrackExecutionAsync<T>(Func<CancellationToken, Task<T>> work, bool isVision, CancellationToken ct)
|
|
|
{
|
|
|
- // create id for this run (可用于日志/诊断)
|
|
|
var id = Guid.NewGuid();
|
|
|
|
|
|
- // 增加计数器并通知
|
|
|
Interlocked.Increment(ref _activeCount);
|
|
|
if (isVision) Interlocked.Increment(ref _visionActiveCount);
|
|
|
OnPropertyChanged(nameof(IsExecuting));
|
|
|
@@ -112,7 +151,6 @@ namespace TeamAAS_VP.Services
|
|
|
|
|
|
try
|
|
|
{
|
|
|
- // 记录 task(便于外部查询)
|
|
|
var task = work(ct);
|
|
|
_runningTasks.TryAdd(id, task);
|
|
|
var result = await task.ConfigureAwait(false);
|
|
|
@@ -120,32 +158,32 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
- // 减少计数器并通知
|
|
|
Interlocked.Decrement(ref _activeCount);
|
|
|
if (isVision) Interlocked.Decrement(ref _visionActiveCount);
|
|
|
-
|
|
|
- // 移除记录(如果仍存在)
|
|
|
_runningTasks.TryRemove(id, out _);
|
|
|
-
|
|
|
OnPropertyChanged(nameof(IsExecuting));
|
|
|
OnPropertyChanged(nameof(IsExecutingVisionCommand));
|
|
|
ExecutionStateChanged?.Invoke(this, EventArgs.Empty);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ /// <summary>
|
|
|
+ /// 解析并执行传入的命令字符串。命令以逗号分隔,第一个字段为命令名称,后续为参数。
|
|
|
+ /// 支持多种内建命令(示例:LoadProduct、GetProductName、CycleTime、Record、StartClearMaterial 等),以及映射到产品 CameraProcedures 的自定义视觉触发命令。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="command">原始命令字符串</param>
|
|
|
+ /// <param name="cancellationToken">外部取消令牌</param>
|
|
|
+ /// <param name="callback">用于将执行结果回传(比如发送到调用方)的回调,参数为单行响应字符串</param>
|
|
|
+ /// <returns>完成任务</returns>
|
|
|
public async Task ExecuteAsync(string command, CancellationToken cancellationToken, Action<string> callback)
|
|
|
{
|
|
|
var items = (command ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.None).Select(s => s.Trim()).ToArray();
|
|
|
if (items.Length == 0) return;
|
|
|
|
|
|
- //触发命令的第一个参数作为命令类型
|
|
|
string triggerCommand = items[0];
|
|
|
- //剩余参数作为命令参数
|
|
|
string[] commandParams = items.Skip(1).ToArray();
|
|
|
|
|
|
string response = string.Empty;
|
|
|
- //根据命令类型执行不同的命令
|
|
|
switch (triggerCommand)
|
|
|
{
|
|
|
case "LoadProduct":
|
|
|
@@ -162,7 +200,6 @@ namespace TeamAAS_VP.Services
|
|
|
callback?.Invoke($"LoadProduct,{response}");
|
|
|
break;
|
|
|
case "GetProductName":
|
|
|
- //如果没有参数,则获取当前产品名称
|
|
|
if (commandParams.Length < 1)
|
|
|
{
|
|
|
response = await TrackExecutionAsync(async ct =>
|
|
|
@@ -179,7 +216,6 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- //如果有参数,则通过产品编号获取产品名称
|
|
|
else if (commandParams.Length == 1)
|
|
|
{
|
|
|
if (!int.TryParse(commandParams[0], out int productNumber))
|
|
|
@@ -207,7 +243,6 @@ namespace TeamAAS_VP.Services
|
|
|
return;
|
|
|
}
|
|
|
case "GetProductID":
|
|
|
- //如果没有参数,则获取当前产品编号
|
|
|
if (commandParams.Length < 1)
|
|
|
{
|
|
|
response = await TrackExecutionAsync(async ct =>
|
|
|
@@ -225,7 +260,6 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- //如果有参数,则通过产品名称获取产品编号
|
|
|
else if (commandParams.Length == 1)
|
|
|
{
|
|
|
response = await TrackExecutionAsync(async ct =>
|
|
|
@@ -490,7 +524,6 @@ namespace TeamAAS_VP.Services
|
|
|
}, isVision: false, cancellationToken);
|
|
|
callback?.Invoke($"StopClearMaterial,{response}");
|
|
|
break;
|
|
|
- //获取机器人是否进入调试模式
|
|
|
case "RobotIsDebugMode":
|
|
|
if (commandParams.Length < 1)
|
|
|
{
|
|
|
@@ -505,21 +538,17 @@ namespace TeamAAS_VP.Services
|
|
|
callback?.Invoke($"RobotIsDebugMode,{response}");
|
|
|
break;
|
|
|
default:
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return;
|
|
|
|
|
|
- // 查找对应的流程
|
|
|
var procedure = currentProduct.CameraProcedures
|
|
|
.SelectMany(cp => cp.ProcedureModels)
|
|
|
.FirstOrDefault(p => p.TriggerCommand == triggerCommand);
|
|
|
if (procedure == null) return;
|
|
|
|
|
|
- // 假设 ExecuteFeederVisionTaskAsync 返回 (bool, string[])
|
|
|
var visionResult = await TrackExecutionAsync(async ct =>
|
|
|
{
|
|
|
var r = await ExecuteVisionTaskAsync(procedure, commandParams, ct);
|
|
|
- // 如果需要转换类型,包装成 Tuple<bool, string[]>
|
|
|
return Tuple.Create(r.IsSucceed, r.Response);
|
|
|
}, isVision: true, cancellationToken);
|
|
|
if (visionResult.Item1)
|
|
|
@@ -532,7 +561,7 @@ namespace TeamAAS_VP.Services
|
|
|
else
|
|
|
{
|
|
|
string msg = string.Empty;
|
|
|
- if (visionResult.Item2 != null && visionResult.Item2.Length>0)
|
|
|
+ if (visionResult.Item2 != null && visionResult.Item2.Length > 0)
|
|
|
{
|
|
|
msg = visionResult.Item2[0];
|
|
|
}
|
|
|
@@ -543,30 +572,29 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- //加载产品
|
|
|
+ /// <summary>
|
|
|
+ /// 根据产品名称或编号加载并设置当前产品。
|
|
|
+ /// 若传入字符串可解析为 int,则先按编号查找产品,否则按名称查找。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="productName">产品名称或编号字符串</param>
|
|
|
+ /// <param name="cancellationToken">取消令牌</param>
|
|
|
+ /// <returns>加载成功返回 true,否则 false</returns>
|
|
|
public async Task<bool> LoadProductAsync(string productName, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //检查是否存在该名称的产品
|
|
|
bool exists = _productService.ContainsProductByName(productName);
|
|
|
if (exists)
|
|
|
{
|
|
|
- //获取产品名称对应的产品
|
|
|
var product = _productService.GetAllProducts().FirstOrDefault(p => p.Name == productName);
|
|
|
- //加载产品
|
|
|
await _productService.LoadProductAsync(product.ID);
|
|
|
- //设置为当前产品
|
|
|
_productService.SetCurrentProduct(product.ID);
|
|
|
return true;
|
|
|
}
|
|
|
- //获取产品编号对应的产品
|
|
|
if (int.TryParse(productName, out int productNumber))
|
|
|
{
|
|
|
var product = _productService.GetAllProducts().FirstOrDefault(p => p.NumberCode == productNumber);
|
|
|
if (product != null)
|
|
|
{
|
|
|
- //加载产品
|
|
|
await _productService.LoadProductAsync(product.ID);
|
|
|
- //设置为当前产品
|
|
|
_productService.SetCurrentProduct(product.ID);
|
|
|
return true;
|
|
|
}
|
|
|
@@ -574,7 +602,9 @@ namespace TeamAAS_VP.Services
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //通过产品编号获取产品名称
|
|
|
+ /// <summary>
|
|
|
+ /// 通过产品编号获取产品名称。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetProductNameByNumberAsync(int productNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
var product = _productService.GetAllProducts().FirstOrDefault(p => p.NumberCode == productNumber);
|
|
|
@@ -586,7 +616,9 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(string.Empty);
|
|
|
}
|
|
|
|
|
|
- //获取当前的产品名称
|
|
|
+ /// <summary>
|
|
|
+ /// 获取当前被设置为活动的产品名称。如果没有则返回空字符串。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetCurrentProductNameAsync(CancellationToken cancellationToken)
|
|
|
{
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
@@ -597,21 +629,23 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(string.Empty);
|
|
|
}
|
|
|
|
|
|
- //通过产品名称获取产品编号
|
|
|
+ /// <summary>
|
|
|
+ /// 通过产品名称获取其编号(NumberCode)。找不到则返回 -1。
|
|
|
+ /// </summary>
|
|
|
public Task<int> GetProductNumberByNameAsync(string productName, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //检查是否存在该名称的产品
|
|
|
bool exists = _productService.ContainsProductByName(productName);
|
|
|
if (exists)
|
|
|
{
|
|
|
- //获取产品名称对应的产品
|
|
|
var product = _productService.GetAllProducts().FirstOrDefault(p => p.Name == productName);
|
|
|
return Task.FromResult(product.NumberCode);
|
|
|
}
|
|
|
return Task.FromResult(-1);
|
|
|
}
|
|
|
|
|
|
- //获取当前的产品编号
|
|
|
+ /// <summary>
|
|
|
+ /// 获取当前产品编号(NumberCode)。找不到则返回 -1。
|
|
|
+ /// </summary>
|
|
|
public Task<int> GetCurrentProductNumberAsync(CancellationToken cancellationToken)
|
|
|
{
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
@@ -622,44 +656,33 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(-1);
|
|
|
}
|
|
|
|
|
|
- //通过机器人编号和点位编号获取机器人点位信息
|
|
|
+ /// <summary>
|
|
|
+ /// 根据机器人编号和点位编号获取点位信息(字符串表示),查找逻辑基于当前产品的 RobotPoint 配置。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetRobotPointInfoAsync(int robotNumber, int pointNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
- //获取机器人编号对应的机器人信息
|
|
|
var robot = _configService.GetAllRobots().FirstOrDefault(r => r.RobotNo == robotNumber);
|
|
|
if (robot == null) return Task.FromResult(string.Empty);
|
|
|
- //获取机器人点位信息
|
|
|
var robotPoint = currentProduct.RobotPoint.Robots.FirstOrDefault(rp => rp.Id == robot.Id);
|
|
|
if (robotPoint == null) return Task.FromResult(string.Empty);
|
|
|
- //获取点位信息
|
|
|
var point = robotPoint.Points.FirstOrDefault(p => p.Number == pointNumber);
|
|
|
if (point == null) return Task.FromResult(string.Empty);
|
|
|
return Task.FromResult(point.ToString());
|
|
|
}
|
|
|
|
|
|
- // <summary>
|
|
|
- /// 通过机器人编号和托盘编号、点编号获取机器人托盘点位信息
|
|
|
+ /// <summary>
|
|
|
+ /// 通过机器人编号、托盘编号和点编号获取托盘点位信息,返回格式化字符串。
|
|
|
/// </summary>
|
|
|
- /// <param name="robotNumber">机器人编号</param>
|
|
|
- /// <param name="palletNumber">托盘编号</param>
|
|
|
- /// <param name="pointNumber">点编号</param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public Task<string> GetRobotPalletPointInfoAsync(int robotNumber, int palletNumber, int pointNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- // 获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
- //获取机器人编号对应的机器人信息
|
|
|
var robot = _configService.GetAllRobots().FirstOrDefault(r => r.RobotNo == robotNumber);
|
|
|
if (robot == null) return Task.FromResult(string.Empty);
|
|
|
- //获取机器人点位信息
|
|
|
var robotPoint = currentProduct.RobotPoint.Robots.FirstOrDefault(rp => rp.Id == robot.Id);
|
|
|
if (robotPoint == null) return Task.FromResult(string.Empty);
|
|
|
- //获取托盘
|
|
|
var pallet = robotPoint.Pallets.FirstOrDefault(p => p.PalletNo == palletNumber);
|
|
|
if (pallet == null) return Task.FromResult(string.Empty);
|
|
|
PalletTool palletTool = new PalletTool(pallet);
|
|
|
@@ -669,11 +692,12 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(response);
|
|
|
}
|
|
|
|
|
|
- //开始节拍计时
|
|
|
+ /// <summary>
|
|
|
+ /// 开始节拍计时。返回是否成功(始终 true)。
|
|
|
+ /// 会启动后台定时任务并周期性触发 CycleTimingTicked 事件。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> StartCycleTimingAsync(CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //TODO: 实现节拍计时开始逻辑
|
|
|
- //如果当前已经在计时,则取消之前的计时,然后重新开始计时
|
|
|
if (_cycleTimingCts != null)
|
|
|
{
|
|
|
_cycleTimingCts.Cancel();
|
|
|
@@ -688,13 +712,15 @@ namespace TeamAAS_VP.Services
|
|
|
{
|
|
|
var elapsed = DateTime.UtcNow - startTime;
|
|
|
OnCycleTimingTicked(elapsed);
|
|
|
- await Task.Delay(100, token); // 每100毫秒更新一次
|
|
|
+ await Task.Delay(100, token);
|
|
|
}
|
|
|
}, token);
|
|
|
return Task.FromResult(true);
|
|
|
}
|
|
|
|
|
|
- //停止节拍计时
|
|
|
+ /// <summary>
|
|
|
+ /// 停止节拍计时并清理取消令牌。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> StopCycleTimingAsync(CancellationToken cancellationToken)
|
|
|
{
|
|
|
if (_cycleTimingCts != null)
|
|
|
@@ -706,7 +732,9 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(true);
|
|
|
}
|
|
|
|
|
|
- //创建一条生产计数,传入计数项
|
|
|
+ /// <summary>
|
|
|
+ /// 新增一条生产计数记录,数量固定为 1。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> CreateProductionCountAsync(string countItem, CancellationToken cancellationToken)
|
|
|
{
|
|
|
_systemDatabaseService.RecordProductionAsync(new ProductionRecord
|
|
|
@@ -719,30 +747,32 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(true);
|
|
|
}
|
|
|
|
|
|
- //获取当前生产计数
|
|
|
+ /// <summary>
|
|
|
+ /// 查询当前产品在指定分类下的累计产量。
|
|
|
+ /// </summary>
|
|
|
public async Task<int> GetCurrentProductionCountAsync(string countItem, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return 0;
|
|
|
- //获取分类集合
|
|
|
var records = _systemDatabaseService.GetProductCategoriesAsync(currentProduct.Name);
|
|
|
- //计算指定分类的总产能
|
|
|
- int totalCount =await _systemDatabaseService.GetTotalProductionAsync(currentProduct.Name, new List<string> { countItem });
|
|
|
+ int totalCount = await _systemDatabaseService.GetTotalProductionAsync(currentProduct.Name, new List<string> { countItem });
|
|
|
return totalCount;
|
|
|
}
|
|
|
|
|
|
- //重置生产计数
|
|
|
+ /// <summary>
|
|
|
+ /// 重置当前产品的生产统计(通过系统 DB 服务)。
|
|
|
+ /// </summary>
|
|
|
public async Task<bool> ResetProductionCountAsync(string countItem, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return false;
|
|
|
await _systemDatabaseService.ResetProductionAsync(currentProduct.Name);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- //创建一条报警记录
|
|
|
+ /// <summary>
|
|
|
+ /// 记录一条报警信息到系统数据库,并通过事件发布错误级别的任务消息。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> CreateAlarmRecordAsync(string alarmCode, string alarmDescription, CancellationToken cancellationToken)
|
|
|
{
|
|
|
SendTaskMessage(alarmDescription, MessageLevel.Error);
|
|
|
@@ -756,21 +786,23 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(true);
|
|
|
}
|
|
|
|
|
|
- //创建一条运行信息记录
|
|
|
+ /// <summary>
|
|
|
+ /// 发布运行信息日志(仅消息推送,不持久化)。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> CreateOperationLogAsync(string logMessage, CancellationToken cancellationToken)
|
|
|
{
|
|
|
SendTaskMessage(logMessage, MessageLevel.Info);
|
|
|
return Task.FromResult(true);
|
|
|
}
|
|
|
|
|
|
- //获取当前产品指定编号的全局参数
|
|
|
+ /// <summary>
|
|
|
+ /// 获取当前产品的全局参数,支持按索引(1-4)返回指定子项,或返回完整 ToString。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetGlobalParameterAsync(int parameterNumber, int itemIndex, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
if (currentProduct.GlobalParamListCollection == null) return Task.FromResult(string.Empty);
|
|
|
- //获取产品全局参数
|
|
|
var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == parameterNumber);
|
|
|
if (globalParam == null) return Task.FromResult(string.Empty);
|
|
|
string response = string.Empty;
|
|
|
@@ -797,28 +829,28 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(response);
|
|
|
}
|
|
|
|
|
|
- //获取当前产品的运行速度
|
|
|
+ /// <summary>
|
|
|
+ /// 返回当前产品的速度/加速度等运行参数的格式化字符串。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetOperationSpeedAsync(CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
string response = $"{currentProduct.Speed},{currentProduct.Accel},{currentProduct.Speeds},{currentProduct.Accels},{Convert.ToInt16(currentProduct.Power)},{Convert.ToInt16(currentProduct.IsUserUpCamera)}";
|
|
|
return Task.FromResult(response);
|
|
|
}
|
|
|
|
|
|
- //获取末端工具信息,传入流程触发命令和工具编号
|
|
|
+ /// <summary>
|
|
|
+ /// 获取某流程指定工具编号的工具参数(格式化字符串),找不到返回空字符串。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetToolParamAsync(string triggerCommand, int toolNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
- //查找对应的流程
|
|
|
ProcedureModel procedure = currentProduct.CameraProcedures
|
|
|
.SelectMany(cp => cp.ProcedureModels)
|
|
|
.FirstOrDefault(p => p.TriggerCommand == triggerCommand);
|
|
|
if (procedure == null || procedure.ToolInfo == null) return Task.FromResult(string.Empty);
|
|
|
- //查找对应的工具
|
|
|
var tool = procedure.ToolInfo.FirstOrDefault(t => t.Number == toolNumber);
|
|
|
if (tool == null) return Task.FromResult(string.Empty);
|
|
|
if (tool.Tool == null) return Task.FromResult(string.Empty);
|
|
|
@@ -826,13 +858,13 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(response);
|
|
|
}
|
|
|
|
|
|
- //获取流程参数信息,传入流程触发命令
|
|
|
+ /// <summary>
|
|
|
+ /// 获取流程参数(例如 WaitPhoto 与用户自定义参数等),以逗号分隔的字符串返回。
|
|
|
+ /// </summary>
|
|
|
public Task<string> GetProcessParamAsync(string triggerCommand, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
if (currentProduct == null) return Task.FromResult(string.Empty);
|
|
|
- //查找对应的流程
|
|
|
ProcedureModel procedure = currentProduct.CameraProcedures
|
|
|
.SelectMany(cp => cp.ProcedureModels)
|
|
|
.FirstOrDefault(p => p.TriggerCommand == triggerCommand);
|
|
|
@@ -841,8 +873,6 @@ namespace TeamAAS_VP.Services
|
|
|
response.Append($"{procedure.WaitPhoto}");
|
|
|
if (procedure.UserDefineParameters != null)
|
|
|
{
|
|
|
- //附加用户自定义参数
|
|
|
- //遍历所有用户自定义参数,以分号分隔
|
|
|
foreach (var param in procedure.UserDefineParameters)
|
|
|
{
|
|
|
response.Append("," + param.ToString());
|
|
|
@@ -851,11 +881,16 @@ namespace TeamAAS_VP.Services
|
|
|
return Task.FromResult(response.ToString());
|
|
|
}
|
|
|
|
|
|
- //执行清料任务
|
|
|
+ /// <summary>
|
|
|
+ /// 执行指定编号的清料任务(异步)。流程:
|
|
|
+ /// - 根据配置获取任务
|
|
|
+ /// - 检查 Feeder 连接性
|
|
|
+ /// - 使用专用 CancellationTokenSource 跟踪任务并支持停止
|
|
|
+ /// - 循环执行开挡板、振动、关闭挡板等步骤,检查取消状态
|
|
|
+ /// </summary>
|
|
|
public async Task<bool> ExecuteClearMaterialTaskAsync(int taskNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取清料任务
|
|
|
- var feederClearWork=_configService.GetClearanceTaskByNumber(taskNumber);
|
|
|
+ var feederClearWork = _configService.GetClearanceTaskByNumber(taskNumber);
|
|
|
if (feederClearWork == null)
|
|
|
{
|
|
|
return false;
|
|
|
@@ -867,7 +902,6 @@ namespace TeamAAS_VP.Services
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
- //如果当前已有该任务在执行,则返回失败
|
|
|
if (_clearMaterialCtsDict.ContainsKey(feederClearWork.TaskCode))
|
|
|
{
|
|
|
return false;
|
|
|
@@ -876,7 +910,6 @@ namespace TeamAAS_VP.Services
|
|
|
_clearMaterialCtsDict[feederClearWork.TaskCode] = new CancellationTokenSource();
|
|
|
if (cancellationToken != null)
|
|
|
{
|
|
|
- //将外部取消令牌与内部取消令牌关联
|
|
|
cancellationToken.Register(() =>
|
|
|
{
|
|
|
if (_clearMaterialCtsDict.ContainsKey(feederClearWork.TaskCode))
|
|
|
@@ -889,10 +922,9 @@ namespace TeamAAS_VP.Services
|
|
|
|
|
|
for (int i = 0; i < feederClearWork.ClearCount; i++)
|
|
|
{
|
|
|
- //1.Feeder振动之前,打开挡板
|
|
|
await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
|
|
|
await Task.Delay(200, token);
|
|
|
- if ((cancellationToken != null && cancellationToken.IsCancellationRequested) || (token!=null && token.IsCancellationRequested))
|
|
|
+ if ((cancellationToken != null && cancellationToken.IsCancellationRequested) || (token != null && token.IsCancellationRequested))
|
|
|
{
|
|
|
await Feeder.StopOutputAsync();
|
|
|
if (_clearMaterialCtsDict.ContainsKey(feederClearWork.TaskCode))
|
|
|
@@ -903,7 +935,6 @@ namespace TeamAAS_VP.Services
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //2.执行配置的Feeder振动任务
|
|
|
for (int j = 0; j < feederClearWork.VibrationCount; j++)
|
|
|
{
|
|
|
await ExecuteFeederWorks(Feeder, feederClearWork.FeederWorks, token, true);
|
|
|
@@ -918,7 +949,6 @@ namespace TeamAAS_VP.Services
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //如果料仓停止了,则打开料仓运动
|
|
|
if (!await Feeder.GetOutputStatusAsync())
|
|
|
{
|
|
|
await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
|
|
|
@@ -946,7 +976,6 @@ namespace TeamAAS_VP.Services
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- //3.Feeder振动之后,关闭挡板
|
|
|
await Feeder.StopOutputAsync();
|
|
|
await Task.Delay(300, token);
|
|
|
if ((cancellationToken != null && cancellationToken.IsCancellationRequested) || (token != null && token.IsCancellationRequested))
|
|
|
@@ -960,7 +989,7 @@ namespace TeamAAS_VP.Services
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
- //3.Feeder振动之后,关闭挡板
|
|
|
+
|
|
|
await Feeder.StopOutputAsync();
|
|
|
await Task.Delay(300, token);
|
|
|
if ((cancellationToken != null && cancellationToken.IsCancellationRequested) || (token != null && token.IsCancellationRequested))
|
|
|
@@ -981,10 +1010,11 @@ namespace TeamAAS_VP.Services
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- //终止清料任务
|
|
|
+ /// <summary>
|
|
|
+ /// 停止指定编号的清料任务(如果正在运行)。
|
|
|
+ /// </summary>
|
|
|
public Task<bool> StopClearMaterialTaskAsync(int taskNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取清料任务
|
|
|
var feederClearWork = _configService.GetClearanceTaskByNumber(taskNumber);
|
|
|
if (feederClearWork == null)
|
|
|
{
|
|
|
@@ -1000,10 +1030,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 获取机器人是否进入调试模式
|
|
|
+ /// 判断指定编号的机器人是否处于调试模式。
|
|
|
/// </summary>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public Task<bool> IsRobotInDebugModeAsync(int robotNumber, CancellationToken cancellationToken)
|
|
|
{
|
|
|
var robotInfo = _configService.GetAllRobots().FirstOrDefault(r => r.RobotNo == robotNumber);
|
|
|
@@ -1017,25 +1045,17 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行视觉任务
|
|
|
+ /// 执行视觉任务的统一入口:
|
|
|
+ /// - 如果为产品局部脚本存在,则调用脚本
|
|
|
+ /// - 否则根据 procedure.FeederId 调用 Feeder 引导的视觉任务或普通视觉任务
|
|
|
+ /// 返回是否成功以及字符串数组形式的响应(用于发送多条结果)。
|
|
|
/// </summary>
|
|
|
- /// <param name="triggerCommand">流程触发命令</param>
|
|
|
- /// <param name="doVibrateFirst">是否先振动</param>
|
|
|
- /// <param name="doCaptureFirst">是否先拍照</param>
|
|
|
- /// <param name="robotCurrentPosition">机器人当前点位</param>
|
|
|
- /// <param name="visionToolInputParams">视觉工具输入参数</param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task<(bool IsSucceed, string[] Response)> ExecuteVisionTaskAsync(ProcedureModel procedure, string[] items, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- //获取当前产品
|
|
|
var currentProduct = _productService.GetCurrentProduct();
|
|
|
-
|
|
|
- //检测当前流程的本地是否存在流程执行脚本文件,如果存在则调用脚本执行视觉任务
|
|
|
string scriptFilePath = FilePath.ProductsPath + "//" + currentProduct.Name + "//" + procedure.CameraName + "//" + procedure.Name + ".cs";
|
|
|
if (File.Exists(scriptFilePath))
|
|
|
{
|
|
|
- //调用脚本执行视觉任务
|
|
|
try
|
|
|
{
|
|
|
string script = FileHelper.ReadFile(scriptFilePath);
|
|
|
@@ -1065,7 +1085,6 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- //正常执行模块,每次拍照,会返回所有的结果数据
|
|
|
IVoiceCoilMotorFeeder Feeder = null;
|
|
|
if (procedure.FeederId != Guid.Empty)
|
|
|
{
|
|
|
@@ -1081,14 +1100,16 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 更新计时器通知
|
|
|
+ /// 内部:触发节拍计时回调。
|
|
|
/// </summary>
|
|
|
- /// <param name="elapsed"></param>
|
|
|
private void OnCycleTimingTicked(TimeSpan elapsed)
|
|
|
{
|
|
|
CycleTimingTicked?.Invoke(this, elapsed);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 发布任务消息到事件聚合器(通过 UI Dispatcher 保证线程安全)。
|
|
|
+ /// </summary>
|
|
|
private void SendTaskMessage(string msg, MessageLevel level)
|
|
|
{
|
|
|
App.Current.Dispatcher.Invoke(() =>
|
|
|
@@ -1100,13 +1121,12 @@ namespace TeamAAS_VP.Services
|
|
|
#region 执行视觉任务辅助方法
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行Feeder视觉引导任务
|
|
|
+ /// 执行 Feeder 引导的视觉任务。负责:
|
|
|
+ /// - 解析输入命令(是否先振动/先拍照、SetInputs)
|
|
|
+ /// - 在拍照前后执行对应的 Feeder 操作(开灯、振动、供料等)
|
|
|
+ /// - 多次尝试拍照并运行视觉工具,直到成功或达到失败次数上限
|
|
|
+ /// - 返回布尔成功标记及字符串数组形式的响应项
|
|
|
/// </summary>
|
|
|
- /// <param name="Feeder"></param>
|
|
|
- /// <param name="procedure"></param>
|
|
|
- /// <param name="items"></param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task<(bool IsSucceed, string[] Response)> ExecuteFeederVisionTaskAsync(IVoiceCoilMotorFeeder feeder, ProcedureModel procedure, string[] items, CancellationToken cancellationToken)
|
|
|
{
|
|
|
// 如果输入的items中是否包含Vibration和NoVibration,这两个分别对应是否先振动和是否先拍照
|
|
|
@@ -1307,12 +1327,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行普通视觉任务
|
|
|
+ /// 执行非 Feeder 引导的普通视觉任务,返回单字符串响应。
|
|
|
/// </summary>
|
|
|
- /// <param name="procedure"></param>
|
|
|
- /// <param name="items"></param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task<(bool IsSucceed, string Response)> ExecuteNormalVisionTaskAsync(ProcedureModel procedure, string[] items, CancellationToken cancellationToken)
|
|
|
{
|
|
|
// 开始执行前的时间点
|
|
|
@@ -1324,7 +1340,7 @@ namespace TeamAAS_VP.Services
|
|
|
|
|
|
// 解析触发命令传入的输入终端参数
|
|
|
//判断传入参数中是否存在“SetInputs”
|
|
|
- if (items != null && items.Length>1 && items[0] == "SetInputs")
|
|
|
+ if (items != null && items.Length > 1 && items[0] == "SetInputs")
|
|
|
{
|
|
|
InputTerminal = items.Skip(1)
|
|
|
.Select(x => x.Split('='))
|
|
|
@@ -1387,14 +1403,10 @@ namespace TeamAAS_VP.Services
|
|
|
var (IsPoint, Value) = Output[output.Name];
|
|
|
if (IsPoint)
|
|
|
{
|
|
|
- //Value是点位数据,类型:List<string[]>,string[]是一个点位,里面是X、Y,U等数据
|
|
|
-
|
|
|
- //将所有点位数据和单个点位数据中的坐标之间都用逗号分隔,多个点位之间用逗号分隔
|
|
|
List<string[]> points = Value as List<string[]>;
|
|
|
List<string> allpoints = new List<string>();
|
|
|
for (int j = 0; j < points.Count; j++)
|
|
|
{
|
|
|
- //单个点位内坐标之间逗号分隔
|
|
|
allpoints.Add(string.Join(",", points[j]));
|
|
|
}
|
|
|
//多个点位之间逗号分隔
|
|
|
@@ -1424,12 +1436,9 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行相机拍照
|
|
|
+ /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
|
|
|
+ /// 该方法会发布 RenderUpdateNotification 以更新 UI。
|
|
|
/// </summary>
|
|
|
- /// <param name="procedure"></param>
|
|
|
- /// <param name="InputTerminal">输入终端参数</param>
|
|
|
- /// <param name="outputCollection">输出终端结果</param>
|
|
|
- /// <returns></returns>
|
|
|
public bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection)
|
|
|
{
|
|
|
try
|
|
|
@@ -1541,12 +1550,9 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 获取需要输出项
|
|
|
+ /// 从 ToolBlock 的输出集合中根据 Procedure 配置提取需要发送的输出项并做必要的坐标转换。
|
|
|
+ /// 返回元组:是否成功、错误信息(失败时)和名称->(是否点位, 值) 的字典。
|
|
|
/// </summary>
|
|
|
- /// <param name="procedure"></param>
|
|
|
- /// <param name="outputCollection"></param>
|
|
|
- /// <param name="IsCheckLastPoints"></param>
|
|
|
- /// <returns>是否成功,错误返回内容,<项的名称,<是否是点位数据,值>></returns>
|
|
|
public (bool IsSucceed, string ErrMsg, Dictionary<string, (bool IsPoint, object Value)> Output) GetVisionOutput(ProcedureModel procedure, CogToolBlockTerminalCollection outputCollection, double[] robotPos)
|
|
|
{
|
|
|
RobotBrand robotBrand = RobotBrand.Default;
|
|
|
@@ -1556,9 +1562,8 @@ namespace TeamAAS_VP.Services
|
|
|
robotBrand = robot.RobotBrand;
|
|
|
}
|
|
|
List<string> SendResults = new List<string>();
|
|
|
- //<输出项的名称,<是否点位,每项输出集合值>>
|
|
|
Dictionary<string, (bool IsPoint, object Value)> ResultCollection = new Dictionary<string, (bool IsPoint, object Value)>();
|
|
|
- foreach (var output in procedure.ProcedureOutputs) //遍历配置的所有需要输出项
|
|
|
+ foreach (var output in procedure.ProcedureOutputs)
|
|
|
{
|
|
|
//根据输出类型进行区分输出
|
|
|
if (output.ValueType == typeof(string))
|
|
|
@@ -1663,14 +1668,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Feeder拍照前,执行Feeder
|
|
|
+ /// 拍照前针对 Feeder 的准备动作:设置灯、必要时供料或振动等。
|
|
|
/// </summary>
|
|
|
- /// <param name="Feeder">Feeder</param>
|
|
|
- /// <param name="procedure">流程</param>
|
|
|
- /// <param name="doVibrateFirst">是否先振动</param>
|
|
|
- /// <param name="doCaptureFirst">是否先拍照</param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederForPhotoBefore(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, bool doVibrateFirst, bool doCaptureFirst, CancellationToken cancellationToken)
|
|
|
{
|
|
|
// 1. 设置Feeder光源亮度、打开光源
|
|
|
@@ -1748,11 +1747,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Feeder拍照后,拍照失败时,执行Feeder
|
|
|
+ /// 拍照后在 NG 情况下的 Feeder 后处理,例如供料或振动。
|
|
|
/// </summary>
|
|
|
- /// <param name="Feeder"></param>
|
|
|
- /// <param name="procedure"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederForPhotoLater(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, CancellationToken cancellationToken)
|
|
|
{
|
|
|
//根据斑点面积决定是否料仓供料
|
|
|
@@ -1779,11 +1775,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行Feeder料仓供料及振动集合
|
|
|
+ /// 并行执行料仓供料和振动任务。
|
|
|
/// </summary>
|
|
|
- /// <param name="feeder"></param>
|
|
|
- /// <param name="works"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederStockWorks(IVoiceCoilMotorFeeder feeder, FeederStockWorks works, CancellationToken cancellationToken, bool isUpdateParame = true)
|
|
|
{
|
|
|
//同时执行料仓供料和Feeder振动任务
|
|
|
@@ -1793,12 +1786,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行料仓振动任务
|
|
|
+ /// 执行料仓振动任务序列(仅料仓相关动作)。
|
|
|
/// </summary>
|
|
|
- /// <param name="feeder"></param>
|
|
|
- /// <param name="works"></param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederStockWorksOnly(IVoiceCoilMotorFeeder feeder, FeederStockWork[] works, CancellationToken cancellationToken)
|
|
|
{
|
|
|
//执行配置的料仓振动任务
|
|
|
@@ -1813,12 +1802,7 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
else if (stockwork.RegisterIndex == 1)
|
|
|
{
|
|
|
- //if (BgModbusTcpCommunicate != null)
|
|
|
- //{
|
|
|
- // BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 1;
|
|
|
- // await Task.Delay(stockwork.Duration);
|
|
|
- // BgModbusTcpCommunicate.Slave.DataStore.HoldingRegisters[stockwork.Address] = 0;
|
|
|
- //}
|
|
|
+ // 保留原注释的位置给 Modbus 操作
|
|
|
}
|
|
|
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
|
|
|
{
|
|
|
@@ -1848,13 +1832,8 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行Feeder振动任务
|
|
|
+ /// 执行单独的 Feeder 振动动作序列(仅振动相关)。
|
|
|
/// </summary>
|
|
|
- /// <param name="feeder"></param>
|
|
|
- /// <param name="feederwork"></param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <param name="isUpdateParame"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederWorkOnly(IVoiceCoilMotorFeeder feeder, FeederWork[] works, CancellationToken cancellationToken, bool isUpdateParame = true)
|
|
|
{
|
|
|
if (works == null)
|
|
|
@@ -1919,16 +1898,10 @@ namespace TeamAAS_VP.Services
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 执行Feeder振动集合
|
|
|
+ /// 执行 Feeder 振动集合(逐个执行 FeederWorkList 中的动作)。
|
|
|
/// </summary>
|
|
|
- /// <param name="feeder"></param>
|
|
|
- /// <param name="works"></param>
|
|
|
- /// <param name="cancellationToken"></param>
|
|
|
- /// <param name="isUpdateParame"></param>
|
|
|
- /// <returns></returns>
|
|
|
public async Task ExecuteFeederWorks(IVoiceCoilMotorFeeder feeder, FeederWorks works, CancellationToken cancellationToken, bool isUpdateParame = true)
|
|
|
{
|
|
|
- //执行配置的Feeder振动任务
|
|
|
if (feeder.FeederBrand == FeederBrand.AFAG)
|
|
|
{
|
|
|
foreach (var feederwork in works.FeederWorkList)
|