using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.RootFinding;
using NPOI.SS.Formula.Functions;
using NPOI.Util;
using OpenCvSharp;
using OpenCvSharp.Flann;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using Team.FFFeederService;
using Team.FFFeederService.Interfaces;
using TeamAAS_VP.Data;
using TeamAAS_VP.Enums;
using TeamAAS_VP.Events;
using TeamAAS_VP.Models;
using TeamAAS_VP.ViewModels.Home;
using TeamAAS_VP;
using TouchSocket.Core;
using TouchSocket.Sockets;
using static MaterialDesignThemes.Wpf.Theme.ToolBar;
using System.ComponentModel;
using System.Collections;
using System.Reflection.Metadata;
using TeamAAS_VP.Resources.Languages;
using TeamAAS_VP.Core.PLCs;
using TeamAAS_VP.Interfaces;
using Opc.Ua;
using TeamAAS_VP.Core.Robots;
using TeamAAS_VP.Core.RFID;
using TeamAAS_VP.Controls;
using TeamAAS_VP.Core.Sfis;
namespace TeamAAS_VP.Core
{
public class Management : BindableBase
{
/// EthernetIP 底栏状态项固定 Id(与设备 Id 无关)
public static readonly Guid EthernetIpStatusId = new Guid("E4E10000-0001-4000-8000-000000000001");
#region 字段
IRegionManager _regionManager;
IEventAggregator _eventAggregator;
IContainerProvider _container;
System.Threading.Timer cTtimer;
System.Threading.Timer yieldtimer;
private bool IsStart = false;
private DateTime StartTime = DateTime.Now;
#endregion
#region 属性
///
/// 当前用户
///
public User CurrentUser { get; set; } = new User() { UserName = "操作员", UserPassword = "", IsRemember = false, userPart = Enums.UserPart.Operator, CreateTime = DateTime.Now };
///
/// 设备参数
///
public DeviceConfiguration DeviceConfig { get; set; } = new DeviceConfiguration();
private Language _CurrentLanguage = Language.ChineseSimplified;
///
/// 当前软件使用的语言
///
public Language CurrentLanguage
{
get { return _CurrentLanguage; }
set { SetProperty(ref _CurrentLanguage, value); }
}
private ObservableCollection _Renders;
///
/// 显示界面
///
public ObservableCollection Renders
{
get { return _Renders; }
set { SetProperty(ref _Renders, value); }
}
private Dictionary _plcTrigger = new Dictionary();
///
/// 当前plc触发监控
///
public Dictionary PlcTrigger { get => _plcTrigger; set => _plcTrigger = value; }
private ObservableCollection _Products;
///
/// 产品列表
///
public ObservableCollection Products
{
get { return _Products; }
set { SetProperty(ref _Products, value); }
}
private ProductModel _CurrentProduct;
///
/// 当前产品
///
public ProductModel CurrentProduct
{
get { return _CurrentProduct; }
set { SetProperty(ref _CurrentProduct, value); }
}
public FeederService FeederService { get; set; }
public RobotService RobotService { get; set; }
public CameraService CameraService { get; set; }
public PlcService PlcService { get; set; }
public BgCommunicate BgCommunicate { get; private set; }
public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
private CancellationTokenSource _handshakeCts;
private Task _handshakeTask;
private CancellationTokenSource _heartbeatCts;
private Task _heartbeatTask;
private CancellationTokenSource _sfisSignalCts;
private Task _sfisSignalTask;
private SfisWorkflowService _sfisWorkflow;
private RFIDTagData _lastRfidTag;
private readonly object _sync = new object();
public SIG350RFIDClient BgEipCommunicate { get; private set; }
private CancellationTokenSource _mcReconnectCts;
private Task _mcReconnectTask;
private readonly object _mcReconnectSync = new object();
private DateTime _mcLastReconnectAttempt = DateTime.MinValue;
private const int McReconnectIntervalMs = 3000;
private Action _mcPlcLogHandler;
private volatile bool _mcMonitorLoopsStarted;
public ModbusTcpMasterCommunicate ModbusTcpMasterCommunicate { get; private set; }
///
/// Modbus TCP 主站配置(连接电批等设备)
///
public ModbusTcpMasterConfig ModbusTcpMasterConfig { get; set; } = new ModbusTcpMasterConfig();
private ObservableCollection _Status = new ObservableCollection();
///
/// 状态栏集合
///
public ObservableCollection Status
{
get { return _Status; }
set { SetProperty(ref _Status, value); }
}
private TimeSpan _CT;
public TimeSpan CT
{
get { return _CT; }
set { SetProperty(ref _CT, value); }
}
private Int64 _TotalQuantity;
///
/// 总产量
///
public Int64 TotalQuantity
{
get { return _TotalQuantity; }
set { SetProperty(ref _TotalQuantity, value); }
}
private Int64 _TotalQuantityToday;
///
/// 当天的总产量
///
public Int64 TotalQuantityToday
{
get { return _TotalQuantityToday; }
set { SetProperty(ref _TotalQuantityToday, value); }
}
private Int64 _CurrentUPH;
///
/// 当前的UPH
///
public Int64 CurrentUPH
{
get { return _CurrentUPH; }
set { SetProperty(ref _CurrentUPH, value); }
}
public Dictionary BackupObject { get; set; } = new Dictionary();
#endregion
#region 命令
#endregion
#region 事件
#endregion
public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container)
{
_regionManager = regionManager;
_eventAggregator = ea;
_container = container;
cTtimer = new Timer(DoCycleTime, null, 5000, 100);
yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
Renders = new ObservableCollection();
}
#region 配置参数读写操作
///
/// 读取配置参数
///
public void ReadConfig()
{
ReadCamerasDeviceConfig();
ReadRobotsDeviceConfig();
ReadFeedersDeviceConfig();
ReadPlcDeviceConfig();
ReadBgTcpIpDeviceConfig();
ReadBgModbusTcpDeviceConfig();
ReadModbusTcpMasterDeviceConfig();
ReadBgEthernetIPDeviceConfig();
ReadBgSfisDeviceConfig();
}
///
/// 读取相机设备配置参数
///
public void ReadCamerasDeviceConfig()
{
try
{
if (File.Exists(FilePath.CamerasConfigurationPath))
{
DeviceConfig.Cameras = FileHelper.ReadJsonFile>(FilePath.CamerasConfigurationPath);
}
else
{
DeviceConfig.Cameras = new ObservableCollection();
}
}
catch (Exception ex)
{
DeviceConfig.Robots = new ObservableCollection();
LogHelper.WriteLogError("加载相机配置文件时出错!", ex);
}
}
///
/// 保存相机设备配置参数
///
public void SaveCamerasDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.Cameras, FilePath.CamerasConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存相机配置参数至文件时出错!", ex);
}
}
///
/// 读取机器人设备配置参数
///
public void ReadRobotsDeviceConfig()
{
try
{
if (File.Exists(FilePath.RobotsConfigurationPath))
{
DeviceConfig.Robots = FileHelper.ReadJsonFile>(FilePath.RobotsConfigurationPath);
}
else
{
DeviceConfig.Robots = new ObservableCollection();
}
}
catch (Exception ex)
{
DeviceConfig.Robots = new ObservableCollection();
LogHelper.WriteLogError("加载机器人配置文件时出错!", ex);
}
}
///
/// 保存机器人设备配置参数
///
public void SaveRobotsDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.Robots, FilePath.RobotsConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存机器人配置参数至文件时出错!", ex);
}
}
///
/// 读取Feeder设备配置参数
///
public void ReadFeedersDeviceConfig()
{
try
{
if (File.Exists(FilePath.FeedersConfigurationPath))
{
DeviceConfig.Feeders = FileHelper.ReadJsonFile>(FilePath.FeedersConfigurationPath);
}
else
{
DeviceConfig.Feeders = new ObservableCollection();
}
}
catch (Exception ex)
{
DeviceConfig.Feeders = new ObservableCollection();
LogHelper.WriteLogError("加载Feeder配置文件时出错!", ex);
}
}
///
/// 保存Feeder设备配置参数
///
public void SaveFeederDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.Feeders, FilePath.FeedersConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存Feeder配置参数至文件时出错!", ex);
}
}
///
/// 读取PLC设备配置参数
///
public void ReadPlcDeviceConfig()
{
try
{
if (File.Exists(FilePath.PlcConfigurationPath))
{
DeviceConfig.Plcs = FileHelper.ReadJsonFile>(FilePath.PlcConfigurationPath);
}
else
{
DeviceConfig.Plcs = new ObservableCollection();
}
}
catch (Exception ex)
{
DeviceConfig.Plcs = new ObservableCollection();
LogHelper.WriteLogError("加载PLC配置文件时出错!", ex);
}
TryMigrateLegacyMcConfig();
}
private void TryMigrateLegacyMcConfig()
{
if (DeviceConfig.Plcs.Any(p => p.CommunicationType == CommunicationType.Mitsubishi_MC))
return;
try
{
if (!File.Exists(FilePath.BgMCToPcCommunicatePath))
return;
var legacy = FileHelper.ReadJsonFile(FilePath.BgMCToPcCommunicatePath);
if (legacy == null)
return;
var mcPlc = new PlcInfo
{
Id = Guid.NewGuid(),
Name = "Mitsubishi MC",
CommunicationType = CommunicationType.Mitsubishi_MC
};
mcPlc.ApplyMcInfo(legacy);
DeviceConfig.Plcs.Add(mcPlc);
SavePlcDeviceConfig();
}
catch (Exception ex)
{
LogHelper.WriteLogError("迁移旧版 MC 配置至 PLC 列表时出错!", ex);
}
}
///
/// 保存PLC设备配置参数
///
public void SavePlcDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.Plcs, FilePath.PlcConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存PLC配置参数至文件时出错!", ex);
}
}
///
/// 读取语言配置参数
///
public void ReadLanguageDeviceConfig()
{
try
{
if (File.Exists(FilePath.LanguageConfigurationPath))
{
CurrentLanguage = FileHelper.ReadJsonFile(FilePath.LanguageConfigurationPath);
}
else
{
CurrentLanguage = Language.ChineseSimplified;
}
}
catch (Exception ex)
{
CurrentLanguage = Language.ChineseSimplified;
LogHelper.WriteLogError("加载Language配置文件时出错!", ex);
}
}
///
/// 保存语言配置参数
///
public void SaveLanguageDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(CurrentLanguage, FilePath.LanguageConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存Language配置参数至文件时出错!", ex);
}
}
///
/// 读取后台TCPIP通讯配置参数
///
public void ReadBgTcpIpDeviceConfig()
{
try
{
if (File.Exists(FilePath.BgTcpIpConfigurationPath))
{
DeviceConfig.BgCommunicate = FileHelper.ReadJsonFile(FilePath.BgTcpIpConfigurationPath);
}
else
{
DeviceConfig.BgCommunicate = new BgTcpIP();
}
}
catch (Exception ex)
{
DeviceConfig.BgCommunicate = new BgTcpIP();
LogHelper.WriteLogError("加载后台TCPIP通讯配置文件时出错!", ex);
}
}
///
/// 保存后台TCPIP通讯配置参数
///
public void SaveBgTcpIpDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.BgCommunicate, FilePath.BgTcpIpConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存后台TCPIP通讯配置参数至文件时出错!", ex);
}
}
///
/// 读取后台ModbusTcp通讯配置参数
///
public void ReadBgModbusTcpDeviceConfig()
{
try
{
if (File.Exists(FilePath.BgModbusTcpConfigurationPath))
{
DeviceConfig.BgModbusCommunicate = FileHelper.ReadJsonFile(FilePath.BgModbusTcpConfigurationPath);
}
else
{
DeviceConfig.BgModbusCommunicate = new BgModbusTcp();
}
}
catch (Exception ex)
{
DeviceConfig.BgModbusCommunicate = new BgModbusTcp();
LogHelper.WriteLogError("加载后台Modbus TCP通讯配置文件时出错!", ex);
}
}
///
/// 保存后台ModbusTcp通讯配置参数
///
public void SaveBgModbusTcpDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.BgModbusCommunicate, FilePath.BgModbusTcpConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存后台ModbusTcp通讯配置参数至文件时出错!", ex);
}
}
///
/// 读取后台EthernetIP通讯配置参数
///
public void ReadBgEthernetIPDeviceConfig()
{
try
{
if (File.Exists(FilePath.BgEthernetIPCommunicatePath))
{
DeviceConfig.BgEthernetIPCommunicate = FileHelper.ReadJsonFile(FilePath.BgEthernetIPCommunicatePath);
}
else
{
DeviceConfig.BgEthernetIPCommunicate = new BgEthernetIP();
FileHelper.WriteJsonFile(DeviceConfig.BgEthernetIPCommunicate, FilePath.BgEthernetIPCommunicatePath);
}
}
catch (Exception ex)
{
DeviceConfig.BgEthernetIPCommunicate = new BgEthernetIP();
LogHelper.WriteLogError("加载后台Eip通讯配置文件时出错!", ex);
}
}
public void ReadBgSfisDeviceConfig()
{
try
{
if (File.Exists(FilePath.BgSfisCommunicatePath))
{
DeviceConfig.BgSfisCommunicate = FileHelper.ReadJsonFile(FilePath.BgSfisCommunicatePath);
}
else
{
DeviceConfig.BgSfisCommunicate = new BgSfisConfig();
FileHelper.WriteJsonFile(DeviceConfig.BgSfisCommunicate, FilePath.BgSfisCommunicatePath);
}
}
catch (Exception ex)
{
DeviceConfig.BgSfisCommunicate = new BgSfisConfig();
LogHelper.WriteLogError("加载 SFIS 配置文件时出错!", ex);
}
}
///
/// 保存EIP配置
///
public void SaveBgEthernetIPDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.BgEthernetIPCommunicate, FilePath.BgEthernetIPCommunicatePath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存后台Eip通讯配置参数至文件时出错!", ex);
}
}
public void SaveBgSfisDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(DeviceConfig.BgSfisCommunicate, FilePath.BgSfisCommunicatePath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存 SFIS 配置参数至文件时出错!", ex);
}
}
#endregion
#region 初始化硬件模块
///
/// 初始化视觉
///
public Tuple InitVision()
{
try
{
return new Tuple(true, "");
}
catch (Exception ex)
{
LogHelper.WriteLogError("初始化VM视觉方式时出错!", ex);
return new Tuple(false, ex.Message);
}
}
///
/// 初始化Feeder
///
///
public async Task> InitFeeders()
{
FeederService = new FeederService();
StringBuilder sb = new StringBuilder();
foreach (var item in DeviceConfig.Feeders)
{
FeederService.CreateFeeder(item.Id, item.IP, item.Port, item.FeederBrand);
Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
try
{
FeederService.GetFeeder(item.Id).FeederConnectedEvent += Management_FeederConnectedEvent;
FeederService.GetFeeder(item.Id).FeederDisconnectedEvent += Management_FeederDisconnectedEvent;
await FeederService.GetFeeder(item.Id).ConnectAsync(); //连接Feeder
//SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug);
}
catch (Exception ex)
{
sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]");
SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm);
}
}
if (sb.Length == 0)
{
return new Tuple(true, "");
}
else
{
return new Tuple(false, sb.ToString());
}
}
///
/// 初始化机器人
///
///
public async Task> InitRobots()
{
RobotService = new RobotService();
StringBuilder sb = new StringBuilder();
foreach (var item in DeviceConfig.Robots)
{
RobotService.CreateRobot(item.Id, item);
if (item.RobotBrand == RobotBrand.XYZ_Platform || item.RobotBrand == RobotBrand.XYZU_Platform)
{
RobotService.GetRobot(item.Id).TrggerChangeEvent += Management_TrggerChangeEvent;
continue;
}
try
{
Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
RobotService.GetRobot(item.Id).ReceivedEvent += Management_ReceivedEvent;
RobotService.GetRobot(item.Id).SendEvent += Management_SendEvent;
RobotService.GetRobot(item.Id).ConnectedEvent += Management_ConnectedEvent;
RobotService.GetRobot(item.Id).DisconnectedEvent += Management_DisconnectedEvent;
await RobotService.GetRobot(item.Id).ConnectAsync(); //连接Robot
SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug);
}
catch (Exception ex)
{
sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]");
SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm);
}
}
if (sb.Length == 0)
{
return new Tuple(true, "");
}
else
{
return new Tuple(false, sb.ToString());
}
}
///
/// 初始化PLC
///
///
public async Task> InitPlc()
{
PlcService = new PlcService();
StringBuilder sb = new StringBuilder();
foreach (var item in DeviceConfig.Plcs)
{
try
{
if (!PlcService.CreatePlc(item.Id, item))
{
sb.AppendLine($"{item.Name}: 不支持的 PLC 通讯类型 [{item.CommunicationType}]");
continue;
}
var plc = PlcService.GetPlc(item.Id);
if (plc == null)
{
sb.AppendLine($"{item.Name}: 创建 PLC 失败");
continue;
}
Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
await plc.ConnectAsync();
}
catch (Exception ex)
{
sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
}
}
if (sb.Length == 0)
{
return new Tuple(true, "");
}
else
{
return new Tuple(false, sb.ToString());
}
}
///
/// 初始化相机
///
///
public Task> InitCameras()
{
CameraService = new CameraService();
StringBuilder sb = new StringBuilder();
foreach (var item in DeviceConfig.Cameras)
{
try
{
Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
CameraService.CreateCamera(item.Id, item);
Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
CameraService.GetCamera(item.Id).CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
if (CameraService.GetCamera(item.Id).OpenDevice())
{
SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
}
else
{
SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
}
}
catch (Exception ex)
{
SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}");
}
}
_container.Resolve().Renders = Renders;
if (sb.Length == 0)
{
return Task.FromResult(new Tuple(true, ""));
}
else
{
return Task.FromResult(new Tuple(false, sb.ToString()));
}
}
///
/// 初始化后台TCP服务器通讯
///
public void InitBgTcp()
{
try
{
BgCommunicate = new BgCommunicate(DeviceConfig.BgCommunicate);
BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
BgCommunicate.SendEvent += BgCommunicate_SendEvent;
BgCommunicate.StartListening();
SendTaskMessage($"{Lang.已开启监听端口}:{DeviceConfig.BgCommunicate.Port}", MessageLevel.Debug);
}
catch (Exception ex)
{
SendTaskMessage($"{Lang.未开启监听端口}:{DeviceConfig.BgCommunicate.Port}", MessageLevel.Error);
LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex);
}
}
///
/// 初始化后台ModbusTCP从站
///
public void InitModbusTcp()
{
try
{
BgModbusTcpCommunicate = new BgModbusTcpCommunicate(DeviceConfig.BgModbusCommunicate);
if (DeviceConfig.BgModbusCommunicate.IsEnabled)
{
BgModbusTcpCommunicate.Listen();
SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug);
}
}
catch (Exception ex)
{
SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm);
LogHelper.WriteLogError("开启后台Modbus TCP通讯时出错!", ex);
}
}
///
/// 读取 Modbus TCP 主站配置
///
public void ReadModbusTcpMasterDeviceConfig()
{
try
{
if (File.Exists(FilePath.ModbusTcpMasterConfigurationPath))
{
ModbusTcpMasterConfig = FileHelper.ReadJsonFile(FilePath.ModbusTcpMasterConfigurationPath);
}
else
{
ModbusTcpMasterConfig = new ModbusTcpMasterConfig();
}
}
catch (Exception ex)
{
ModbusTcpMasterConfig = new ModbusTcpMasterConfig();
LogHelper.WriteLogError("加载 Modbus TCP 主站配置文件时出错!", ex);
}
}
///
/// 保存 Modbus TCP 主站配置
///
public void SaveModbusTcpMasterDeviceConfig()
{
try
{
FileHelper.WriteJsonFile(ModbusTcpMasterConfig, FilePath.ModbusTcpMasterConfigurationPath);
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存 Modbus TCP 主站配置时出错!", ex);
}
}
///
/// 初始化 Modbus TCP 主站(轮询电批/扭矩控制器)
///
public void InitModbusTcpMaster()
{
try
{
ModbusTcpMasterCommunicate?.Stop();
ModbusTcpMasterCommunicate = new ModbusTcpMasterCommunicate(ModbusTcpMasterConfig, _eventAggregator);
if (!ModbusTcpMasterConfig.IsEnabled)
{
return;
}
ModbusTcpMasterCommunicate.Start();
SendTaskMessage($"Start Modbus Tcp Master:{ModbusTcpMasterConfig.IP}:{ModbusTcpMasterConfig.Port}:{ModbusTcpMasterConfig.SlaveID}", MessageLevel.Debug);
}
catch (Exception ex)
{
SendTaskMessage($"No Start Modbus Tcp Master:{ex.Message}", MessageLevel.Alarm);
LogHelper.WriteLogError("开启 Modbus TCP 主站通讯时出错!", ex);
}
}
///
/// 初始化 EthernetIP
///
public void InitEthernetIP()
{
try
{
EnsureEthernetIpStatusEntry();
DisposeRfidClient();
BgEipCommunicate = new SIG350RFIDClient(DeviceConfig.BgEthernetIPCommunicate);
BgEipCommunicate.BeforeStartRfidReading = ApplyEthernetIpRfidConfiguration;
BgEipCommunicate.OnLog += BgEipCommunicate_OnLog;
BgEipCommunicate.OnTagDataReceived += RfidClient_OnTagDataReceived;
BgEipCommunicate.OnConnectReceive += Management_EipConnectChangedEvent;
if (!DeviceConfig.BgEthernetIPCommunicate.IsEnabled)
{
UpdateEthernetIpStatus(false);
return;
}
if (BgEipCommunicate.Connect())
{
UpdateEthernetIpStatus(true);
SendTaskMessage($"EthernetIP:{DeviceConfig.BgEthernetIPCommunicate.IP}", MessageLevel.Debug);
StartEthernetIpRfidIO();
}
else
{
UpdateEthernetIpStatus(false);
// Connect 失败时会触发 OnConnectReceive(false),内部自动重连
}
}
catch (Exception ex)
{
UpdateEthernetIpStatus(false);
SendTaskMessage($"EthernetIP err:{ex.Message}", MessageLevel.Alarm);
LogHelper.WriteLogError("开启 EthernetIP通讯时出错!", ex);
}
}
private void EnsureEthernetIpStatusEntry()
{
if (Status.Any(s => s.ID == EthernetIpStatusId))
return;
App.Current.Dispatcher.Invoke(() =>
{
if (!Status.Any(s => s.ID == EthernetIpStatusId))
{
Status.Add(new StatusInfo(
EthernetIpStatusId,
$"{Lang.EthernetIP}{Lang.未连接}",
new SolidColorBrush(Colors.Red)));
}
});
}
private void UpdateEthernetIpStatus(bool isConnected)
{
var sta = Status.FirstOrDefault(s => s.ID == EthernetIpStatusId);
if (sta == null)
return;
App.Current.Dispatcher.Invoke(() =>
{
if (isConnected)
{
sta.Message = $"{Lang.EthernetIP}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}
else
{
sta.Message = $"{Lang.EthernetIP}{Lang.未连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}
});
}
private void Management_EipConnectChangedEvent(bool isConnected)
{
if (isConnected)
{
SendTaskMessage($"{Lang.EthernetIP}{Lang.已连接}!", MessageLevel.Debug);
TryStartHandshakeAfterEipReady();
}
else
{
SendTaskMessage($"{Lang.EthernetIP}{Lang.断开连接}!", MessageLevel.Error);
}
UpdateEthernetIpStatus(isConnected);
}
/// 配置 RFID 端口(1..N)并固定为 UID 读模式。
private void ApplyEthernetIpRfidConfiguration()
{
if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected)
return;
var eipConfig = DeviceConfig.BgEthernetIPCommunicate;
var ports = eipConfig.GetEnabledPortNumbers();
BgEipCommunicate.ConfigureRFIDPorts(ports, PortMode.IOLAutostart);
BgEipCommunicate.ConfigureReadOptions(eipConfig.ToRfh5xxReadOptions());
SendTaskMessage($"RFID 已配置端口 1–{eipConfig.RfidPortCount},读 UID", MessageLevel.Debug);
}
private void StartEthernetIpRfidIO()
{
if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected)
return;
try
{
ApplyEthernetIpRfidConfiguration();
}
catch (Exception ex)
{
SendTaskMessage("RFID 端口配置失败: " + ex.Message, MessageLevel.Alarm);
LogHelper.WriteLogError("RFID 端口配置失败", ex);
}
BgEipCommunicate.StartRFIDReading(DeviceConfig.BgEthernetIPCommunicate.CycleTime);
TryStartHandshakeAfterEipReady();
}
/// EIP 就绪后尝试启动 Ready 握手;MC 未连接则跳过,由 MC 重连循环补启。
private void TryStartHandshakeAfterEipReady()
{
var mcPlc = GetMcPlcInfo();
if (mcPlc == null)
return;
var client = GetMcPlcClient();
if (client == null || !client.IsConnected)
return;
TryStartHandshakeLoop(mcPlc);
}
///
/// 初始化三菱 MC PLC:自动连接、心跳、Ready 握手、SFIS 信号监听
///
public void InitMcCommunicate()
{
var mcPlc = GetMcPlcInfo();
if (mcPlc == null)
{
SendTaskMessage("未配置三菱 MC PLC,跳过 MC 通讯初始化", MessageLevel.Debug);
return;
}
try
{
StopMcCommunicateLoops();
var mcWrapper = PlcService?.GetPlc(mcPlc.Id) as MitsubishiMcPLC;
if (mcWrapper == null)
{
SendTaskMessage("MC PLC 未通过 PlcService 创建,请检查 PLC 配置", MessageLevel.Alarm);
return;
}
var client = mcWrapper.Client;
if (_mcPlcLogHandler == null)
_mcPlcLogHandler = msg => SendTaskMessage($"PLC {msg}", MessageLevel.Info);
client.OnLog -= _mcPlcLogHandler;
client.OnLog += _mcPlcLogHandler;
client.ConnectionLost -= McPlcConnectionLost;
client.ConnectionLost += McPlcConnectionLost;
if (!client.IsConnected)
{
mcWrapper.Connect();
}
if (!client.IsConnected)
{
SendTaskMessage("PLC 连接失败,将自动重连", MessageLevel.Alarm);
StartMcReconnectLoop();
return;
}
SendTaskMessage("PLC TCP 连接成功,正在测试 MC 读写...", MessageLevel.Info);
string testDev = string.IsNullOrWhiteSpace(mcPlc.PlcDataStartDevice) ? "D110" : mcPlc.PlcDataStartDevice.Trim();
if (testDev == "0")
testDev = "D110";
if (!client.TestCommunication(testDev))
{
SendTaskMessage("MC 通讯测试失败,请检查:二进制3E、端口、允许RUN中写入", MessageLevel.Alarm);
}
else
{
SendTaskMessage("连接成功,MC 字通讯正常", MessageLevel.Info);
}
string bitTestDev = ResolveBitTestDevice(mcPlc);
if (bitTestDev != null)
{
if (!client.TestBitCommunication(bitTestDev))
SendTaskMessage("MC 位通讯测试失败,请检查 OK/NG 位地址及 RUN 中写入", MessageLevel.Alarm);
}
else
{
SendTaskMessage("MC 位通讯测试跳过:请配置读OK或读NG位地址", MessageLevel.Debug);
}
client.ResetHeartbeatState();
EnsureMcCommunicateLoopsRunning(mcPlc, client);
StartMcReconnectLoop();
}
catch (Exception ex)
{
SendTaskMessage("PLC 连接失败: " + ex.Message, MessageLevel.Alarm);
LogHelper.WriteLogError("PLC 连接失败", ex);
StopMcCommunicateLoops();
}
}
private void McPlcConnectionLost()
{
_mcMonitorLoopsStarted = false;
SendTaskMessage("MC PLC 连接中断", MessageLevel.Alarm);
}
/// MC 连接可用时确保心跳 / SFIS / Ready 握手循环已启动。
private void EnsureMcCommunicateLoopsRunning(PlcInfo mcPlc, MitsubishiPLC client)
{
if (mcPlc == null || client == null || !client.IsConnected)
return;
client.ResetHeartbeatState();
StartHeartbeatLoop(mcPlc);
StartSfisSignalLoop();
TryStartHandshakeLoop(mcPlc);
_mcMonitorLoopsStarted = true;
}
private void TryStartHandshakeLoop(PlcInfo mcPlc)
{
if (mcPlc == null || !mcPlc.PlcForwardEnabled || !CanStartHandshake(mcPlc))
return;
StartHandshakeLoop();
}
private PlcInfo GetMcPlcInfo()
{
return DeviceConfig?.Plcs?.FirstOrDefault(p => p.CommunicationType == CommunicationType.Mitsubishi_MC);
}
private MitsubishiPLC GetMcPlcClient()
{
var mcInfo = GetMcPlcInfo();
if (mcInfo == null || PlcService == null)
return null;
return (PlcService.GetPlc(mcInfo.Id) as MitsubishiMcPLC)?.Client;
}
private bool CanStartHandshake(PlcInfo mcPlc)
{
if (BgEipCommunicate == null || !BgEipCommunicate.IsConnected || !BgEipCommunicate.IsIOModeActive)
return false;
var mapping = mcPlc.ToPlcMapping();
return MitsubishiPLC.IsDeviceEnabled(mapping.ReadyBitDevice)
&& MitsubishiPLC.IsDeviceEnabled(mapping.PortDevice)
&& MitsubishiPLC.IsDeviceEnabled(mapping.DataStartDevice);
}
private string ResolveBitTestDevice(PlcInfo mcPlc)
{
if (mcPlc == null) return null;
if (MitsubishiPLC.IsDeviceEnabled(mcPlc.PlcOkBitDevice))
return mcPlc.PlcOkBitDevice.Trim();
if (MitsubishiPLC.IsDeviceEnabled(mcPlc.PlcNgBitDevice))
return mcPlc.PlcNgBitDevice.Trim();
return null;
}
private void StopMcCommunicateLoops()
{
try
{
_mcMonitorLoopsStarted = false;
StopMcReconnectLoop();
StopHandshakeLoop();
StopHeartbeatLoop();
StopSfisSignalLoop();
ResetSfisWorkflow();
}
catch { /* ignore */ }
}
private void StartMcReconnectLoop()
{
StopMcReconnectLoop();
_mcReconnectCts = new CancellationTokenSource();
var token = _mcReconnectCts.Token;
_mcReconnectTask = Task.Run(() => McReconnectLoop(token), token);
}
private void StopMcReconnectLoop()
{
try
{
if (_mcReconnectCts != null)
{
_mcReconnectCts.Cancel();
try
{
if (_mcReconnectTask != null)
_mcReconnectTask.Wait(2000);
}
catch (AggregateException) { /* ignore */ }
_mcReconnectCts.Dispose();
}
}
catch { /* ignore */ }
finally
{
_mcReconnectCts = null;
_mcReconnectTask = null;
}
}
private void McReconnectLoop(CancellationToken token)
{
int attempt = 0;
while (!token.IsCancellationRequested)
{
try
{
var mcPlc = GetMcPlcInfo();
if (mcPlc == null)
{
Thread.Sleep(1000);
continue;
}
var mcWrapper = PlcService?.GetPlc(mcPlc.Id) as MitsubishiMcPLC;
var client = mcWrapper?.Client;
if (client == null)
{
Thread.Sleep(1000);
continue;
}
if (client.IsConnected)
{
if (!_mcMonitorLoopsStarted)
EnsureMcCommunicateLoopsRunning(mcPlc, client);
attempt = 0;
Thread.Sleep(500);
continue;
}
if ((DateTime.UtcNow - _mcLastReconnectAttempt).TotalMilliseconds < McReconnectIntervalMs)
{
Thread.Sleep(500);
continue;
}
_mcLastReconnectAttempt = DateTime.UtcNow;
attempt++;
SendTaskMessage($"MC PLC 连接断开,正在重连(第 {attempt} 次)...", MessageLevel.Info);
bool connected;
lock (_mcReconnectSync)
{
if (client.IsConnected)
{
connected = true;
}
else
{
mcWrapper.Connect();
connected = client.IsConnected;
}
}
if (connected)
{
EnsureMcCommunicateLoopsRunning(mcPlc, client);
SendTaskMessage("MC PLC 重连成功", MessageLevel.Info);
attempt = 0;
}
else
{
SendTaskMessage("MC PLC 重连失败,将继续重试", MessageLevel.Alarm);
}
}
catch (Exception ex)
{
if (token.IsCancellationRequested)
break;
LogHelper.WriteLogError("MC 重连循环异常", ex);
Thread.Sleep(McReconnectIntervalMs);
}
}
}
private void StartHeartbeatLoop(PlcInfo mcPlc)
{
StopHeartbeatLoop();
if (mcPlc == null) return;
string device = mcPlc.PlcHeartbeatDevice;
if (!MitsubishiPLC.IsDeviceEnabled(device))
return;
PlcHeartbeatKind kind;
try
{
kind = MitsubishiPLC.ResolveHeartbeatKind(device);
}
catch (Exception ex)
{
SendTaskMessage("PLC 心跳地址无效", MessageLevel.Alarm);
LogHelper.WriteLogError("PLC 心跳地址无效", ex);
return;
}
if (kind == PlcHeartbeatKind.Disabled)
return;
int intervalMs = Math.Max(200, mcPlc.PlcHeartbeatIntervalMs);
_heartbeatCts = new CancellationTokenSource();
var token = _heartbeatCts.Token;
_heartbeatTask = Task.Run(() => HeartbeatLoop(token, device.Trim(), intervalMs), token);
SendTaskMessage("PLC 已启动心跳 " + device.Trim()
+ (kind == PlcHeartbeatKind.Bit ? "(位翻转)" : "(字递增)")
+ " 间隔=" + intervalMs + "ms", MessageLevel.Info);
}
private void StopHeartbeatLoop()
{
try
{
if (_heartbeatCts != null)
{
_heartbeatCts.Cancel();
try
{
if (_heartbeatTask != null)
_heartbeatTask.Wait(2000);
}
catch (AggregateException) { /* ignore */ }
_heartbeatCts.Dispose();
}
}
catch { /* ignore */ }
finally
{
_heartbeatCts = null;
_heartbeatTask = null;
}
}
private void HeartbeatLoop(CancellationToken token, string device, int intervalMs)
{
while (!token.IsCancellationRequested)
{
try
{
MitsubishiPLC plc;
lock (_sync)
plc = GetMcPlcClient();
if (plc == null || !plc.IsConnected)
{
Thread.Sleep(100);
continue;
}
plc.PulseHeartbeat(device);
}
catch (Exception ex)
{
if (!token.IsCancellationRequested)
{
SendTaskMessage("心跳异常: " + ex.Message, MessageLevel.Alarm);
LogHelper.WriteLogError("心跳异常", ex);
}
}
Thread.Sleep(intervalMs);
}
}
private void StartHandshakeLoop()
{
StopHandshakeLoop();
_handshakeCts = new CancellationTokenSource();
var token = _handshakeCts.Token;
_handshakeTask = Task.Run(() => HandshakeLoop(token), token);
SendTaskMessage("已启动 Ready 握手循环", MessageLevel.Info);
}
private void HandshakeLoop(CancellationToken token)
{
bool lastReady = false;
while (!token.IsCancellationRequested)
{
try
{
MitsubishiPLC plc;
SIG350RFIDClient rfid;
lock (_sync)
{
plc = GetMcPlcClient();
rfid = BgEipCommunicate;
}
if (plc == null || !plc.IsConnected || rfid == null || !rfid.IsConnected || !rfid.IsIOModeActive)
{
Thread.Sleep(50);
continue;
}
PlcRfidMapping mapping = SnapshotMapping();
if (!MitsubishiPLC.IsDeviceEnabled(mapping.ReadyBitDevice))
{
Thread.Sleep(100);
continue;
}
bool ready = plc.ReadReadyBit(mapping);
if (ready && !lastReady)
{
SendTaskMessage("PLC 检测到 Ready=ON,开始读卡", MessageLevel.Info);
ProcessReadyRequest(plc, rfid, mapping, token);
while (!token.IsCancellationRequested)
{
if (!plc.IsConnected)
break;
if (!plc.ReadReadyBit(mapping))
break;
Thread.Sleep(20);
}
if (!token.IsCancellationRequested && plc.IsConnected)
{
plc.ClearReceiveBit(mapping);
SendTaskMessage("PLC Ready=OFF,已清除 Receive", MessageLevel.Info);
}
lastReady = false;
continue;
}
lastReady = ready;
Thread.Sleep(20);
}
catch (Exception ex)
{
if (token.IsCancellationRequested)
break;
SendTaskMessage("PLC 握手异常", MessageLevel.Alarm);
LogHelper.WriteLogError("PLC 握手异常", ex);
Thread.Sleep(100);
lastReady = false;
}
}
}
private PlcRfidMapping SnapshotMapping()
{
lock (_sync)
{
var mcPlc = GetMcPlcInfo();
return mcPlc?.ToPlcMapping() ?? new PlcRfidMapping();
}
}
private void ProcessReadyRequest(MitsubishiPLC plc, SIG350RFIDClient rfid, PlcRfidMapping mapping, CancellationToken token)
{
int port;
try
{
port = plc.ReadRequestPort(mapping);
}
catch (Exception ex)
{
SendTaskMessage("PLC 读端口号失败", MessageLevel.Alarm);
LogHelper.WriteLogError("PLC 读端口号失败", ex);
try { plc.WriteReadFailure(mapping); } catch { /* ignore */ }
return;
}
SendTaskMessage("PLC 请求端口 " + port, MessageLevel.Info);
if (port < 1 || port > 8)
{
SendTaskMessage("端口号无效: " + port, MessageLevel.Alarm);
try { plc.WriteReadFailure(mapping); } catch { /* ignore */ }
return;
}
if (token.IsCancellationRequested)
return;
RFIDTagData tag = null;
try
{
int timeout = mapping.ReadTimeoutMs > 0 ? mapping.ReadTimeoutMs : 2000;
var readOpts = DeviceConfig.BgEthernetIPCommunicate.ToRfh5xxReadOptions();
tag = rfid.ReadRFIDTag(port, timeout, readOpts);
}
catch (Exception ex)
{
SendTaskMessage("RFID 读卡异常", MessageLevel.Alarm);
LogHelper.WriteLogError("RFID 读卡异常", ex);
}
if (tag != null && tag.Data != null && tag.Data.Length > 0)
{
lock (_sync)
_lastRfidTag = CloneTag(tag);
try
{
plc.WriteReadSuccess(mapping, tag);
}
catch (Exception ex)
{
SendTaskMessage("RFID 写 OK/数据失败", MessageLevel.Alarm);
LogHelper.WriteLogError("RFID 写 OK/数据失败", ex);
}
}
else
{
SendTaskMessage("RFID 端口 " + port + " 未读到标签", MessageLevel.Alarm);
try { plc.WriteReadFailure(mapping); }
catch (Exception ex)
{
SendTaskMessage("RFID 写 NG 失败", MessageLevel.Alarm);
LogHelper.WriteLogError("RFID 写 NG 失败", ex);
}
}
}
private bool SnapshotSfisEnabled()
{
lock (_sync)
return DeviceConfig.BgSfisCommunicate?.IsEnabled == true;
}
private SfisConfig SnapshotSfisConfig()
{
lock (_sync)
return DeviceConfig.BgSfisCommunicate?.ToSfisConfig() ?? new SfisConfig();
}
private PlcSfisFeedback SnapshotSfisPlcFeedback()
{
lock (_sync)
return DeviceConfig.BgSfisCommunicate?.ToPlcSfisFeedback() ?? new PlcSfisFeedback();
}
private SfisWorkflowService CreateSfisWorkflow()
{
var workflow = new SfisWorkflowService(SnapshotSfisConfig());
workflow.OnLog += msg => SendTaskMessage("SFIS " + msg, MessageLevel.Info);
return workflow;
}
private SfisWorkflowService GetOrCreateSfisWorkflow()
{
lock (_sync)
{
if (_sfisWorkflow != null)
return _sfisWorkflow;
}
var workflow = CreateSfisWorkflow();
lock (_sync)
{
if (_sfisWorkflow == null)
_sfisWorkflow = workflow;
else
{
try { workflow.Dispose(); }
catch { /* ignore */ }
}
return _sfisWorkflow;
}
}
private void ResetSfisWorkflow()
{
lock (_sync)
{
if (_sfisWorkflow != null)
{
try { _sfisWorkflow.Dispose(); }
catch { /* ignore */ }
_sfisWorkflow = null;
}
}
}
private void StartSfisSignalLoop()
{
StopSfisSignalLoop();
var sfis = DeviceConfig.BgSfisCommunicate;
if (sfis == null || !sfis.IsEnabled)
return;
bool passReady = sfis.PassEnabled && MitsubishiPLC.IsDeviceEnabled(sfis.PlcSfisPassSignalDevice);
bool uploadReady = sfis.UploadEnabled && MitsubishiPLC.IsDeviceEnabled(sfis.PlcSfisUploadSignalDevice);
if (!passReady && !uploadReady)
return;
_sfisSignalCts = new CancellationTokenSource();
var token = _sfisSignalCts.Token;
_sfisSignalTask = Task.Run(() => SfisSignalLoop(token), token);
SendTaskMessage("SFIS 已启动信号监听"
+ (passReady ? " 过站=" + sfis.PlcSfisPassSignalDevice.Trim() : string.Empty)
+ (uploadReady ? " 上传=" + sfis.PlcSfisUploadSignalDevice.Trim() : string.Empty), MessageLevel.Info);
}
private void StopSfisSignalLoop()
{
try
{
if (_sfisSignalCts != null)
{
_sfisSignalCts.Cancel();
try
{
if (_sfisSignalTask != null)
_sfisSignalTask.Wait(2000);
}
catch (AggregateException) { /* ignore */ }
_sfisSignalCts.Dispose();
}
}
catch { /* ignore */ }
finally
{
_sfisSignalCts = null;
_sfisSignalTask = null;
}
}
private void SfisSignalLoop(CancellationToken token)
{
bool lastPass = false;
bool lastUpload = false;
while (!token.IsCancellationRequested)
{
try
{
if (!SnapshotSfisEnabled())
{
lastPass = false;
lastUpload = false;
Thread.Sleep(200);
continue;
}
MitsubishiPLC plc;
lock (_sync)
plc = GetMcPlcClient();
if (plc == null || !plc.IsConnected)
{
Thread.Sleep(100);
continue;
}
var sfis = DeviceConfig.BgSfisCommunicate;
bool passEnabled = sfis.PassEnabled;
bool uploadEnabled = sfis.UploadEnabled;
string passDev = sfis.PlcSfisPassSignalDevice;
string uploadDev = sfis.PlcSfisUploadSignalDevice;
bool passOn = passEnabled && MitsubishiPLC.IsDeviceEnabled(passDev) && plc.ReadBit(passDev);
bool uploadOn = uploadEnabled && MitsubishiPLC.IsDeviceEnabled(uploadDev) && plc.ReadBit(uploadDev);
if (passEnabled && passOn && !lastPass)
{
SendTaskMessage("SFIS 过站信号上升沿 " + passDev.Trim(), MessageLevel.Info);
RunSfisOnSignal(plc, runPass: true, runUpload: false);
}
else if (passEnabled && !passOn && lastPass)
{
try
{
plc.ClearSfisReceiveBit(SnapshotSfisPlcFeedback(), isPassStation: true);
SendTaskMessage("过站信号 OFF,已清除 Receive", MessageLevel.Info);
}
catch (Exception ex)
{
SendTaskMessage("清除过站 Receive 失败: " + ex.Message, MessageLevel.Alarm);
}
}
if (uploadEnabled && uploadOn && !lastUpload)
{
SendTaskMessage("SFIS 上传信号上升沿 " + uploadDev.Trim(), MessageLevel.Info);
RunSfisOnSignal(plc, runPass: false, runUpload: true);
}
else if (uploadEnabled && !uploadOn && lastUpload)
{
try
{
plc.ClearSfisReceiveBit(SnapshotSfisPlcFeedback(), isPassStation: false);
SendTaskMessage("上传信号 OFF,已清除 Receive", MessageLevel.Info);
}
catch (Exception ex)
{
SendTaskMessage("清除上传 Receive 失败: " + ex.Message, MessageLevel.Alarm);
}
}
lastPass = passOn;
lastUpload = uploadOn;
Thread.Sleep(50);
}
catch (Exception ex)
{
if (token.IsCancellationRequested)
break;
SendTaskMessage("SFIS 信号监听异常: " + ex.Message, MessageLevel.Alarm);
Thread.Sleep(200);
lastPass = false;
lastUpload = false;
}
}
}
private struct SfisRunPlan
{
public bool RunPass;
public bool RunUpload;
}
private void RunSfisOnSignal(MitsubishiPLC plc, bool runPass, bool runUpload)
{
bool isPassStation = runPass;
PlcSfisFeedback feedback = SnapshotSfisPlcFeedback();
bool success = false;
try
{
RFIDTagData tag = TryLoadTagForSfis(plc);
if (tag == null)
{
SendTaskMessage("SFIS 无可用 RFID 数据,写 PLC NG", MessageLevel.Alarm);
WriteSfisPlcResult(plc, feedback, isPassStation, false);
return;
}
success = TryRunSfisWorkflow(tag, new SfisRunPlan { RunPass = runPass, RunUpload = runUpload });
}
catch (Exception ex)
{
SendTaskMessage("SFIS 流程异常: " + ex.Message, MessageLevel.Alarm);
success = false;
}
WriteSfisPlcResult(plc, feedback, isPassStation, success);
}
private void WriteSfisPlcResult(MitsubishiPLC plc, PlcSfisFeedback feedback, bool isPassStation, bool success)
{
try
{
plc.WriteSfisResult(feedback, isPassStation, success);
}
catch (Exception ex)
{
SendTaskMessage((isPassStation ? "过站" : "上传") + " 回写失败: " + ex.Message, MessageLevel.Alarm);
}
}
private RFIDTagData TryLoadTagForSfis(MitsubishiPLC plc)
{
PlcRfidMapping mapping = SnapshotMapping();
var readOpts = DeviceConfig.BgEthernetIPCommunicate.ToRfh5xxReadOptions();
if (MitsubishiPLC.IsDeviceEnabled(mapping.DataStartDevice))
{
try
{
byte[] data = plc.ReadDeviceBytes(mapping.DataStartDevice, mapping.MaxDataBytes);
data = TrimTrailingZeros(data);
if (data.Length > 0)
{
int port = 0;
if (MitsubishiPLC.IsDeviceEnabled(mapping.PortDevice))
port = plc.ReadRequestPort(mapping);
return new RFIDTagData
{
Port = port,
Data = data,
Timestamp = DateTime.Now,
PayloadKind = readOpts.Kind
};
}
}
catch (Exception ex)
{
SendTaskMessage("SFIS 从 PLC 读取 RFID 数据失败: " + ex.Message, MessageLevel.Alarm);
}
}
lock (_sync)
{
if (_lastRfidTag != null && _lastRfidTag.Data != null && _lastRfidTag.Data.Length > 0)
return CloneTag(_lastRfidTag);
}
return null;
}
private static RFIDTagData CloneTag(RFIDTagData tag)
{
return new RFIDTagData
{
Port = tag.Port,
Data = (byte[])tag.Data.Clone(),
Timestamp = tag.Timestamp,
Quality = tag.Quality,
PayloadKind = tag.PayloadKind
};
}
private static byte[] TrimTrailingZeros(byte[] data)
{
if (data == null || data.Length == 0)
return new byte[0];
int len = data.Length;
while (len > 0 && data[len - 1] == 0)
len--;
if (len == data.Length)
return data;
var trimmed = new byte[len];
Array.Copy(data, trimmed, len);
return trimmed;
}
private bool TryRunSfisWorkflow(RFIDTagData tag, SfisRunPlan plan)
{
try
{
var config = SnapshotSfisConfig();
var context = SfisRfidMapper.FromRfidTag(tag, config);
var result = GetOrCreateSfisWorkflow().ProcessUnit(context, plan.RunPass, plan.RunUpload);
PrintSfisResult(result);
return result.Success;
}
catch (ArgumentException ex)
{
SendTaskMessage("SFIS 数据无效: " + ex.Message, MessageLevel.Alarm);
return false;
}
catch (Exception ex)
{
SendTaskMessage("SFIS 流程异常: " + ex.Message, MessageLevel.Alarm);
return false;
}
}
private void PrintSfisResult(SfisWorkflowResult result)
{
if (result == null)
return;
SendTaskMessage(result.Success
? "SFIS 流程成功 ISN=" + result.Isn
: "SFIS 流程失败 ISN=" + result.Isn + " => " + result.ErrorMessage, MessageLevel.Info);
if (result.Steps == null)
return;
foreach (var step in result.Steps)
{
string msg = step.Response != null ? step.Response.Message : string.Empty;
int code = step.Response != null ? step.Response.ReturnCode : -1;
SendTaskMessage("SFIS " + step.StepName + ": P_RET=" + code + " " + msg, MessageLevel.Debug);
}
}
private void BgEipCommunicate_OnLog(string obj)
{
SendTaskMessage(obj, MessageLevel.Info);
}
///
/// 初始化后台脚本
///
public void InitBackgroundcript()
{
try
{
if (!Directory.Exists(FilePath.BackgroundScriptPath))
{
Directory.CreateDirectory(FilePath.BackgroundScriptPath);
}
try
{
string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath);
List ScriptFilesCollection = new List();
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
string fileExtension = Path.GetExtension(file);
if (fileExtension == ".cs")
{
ScriptFilesCollection.Add(file);
}
}
foreach (var item in ScriptFilesCollection)
{
try
{
string script = FileHelper.ReadFile(item);
SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info);
Task.Factory.StartNew(() =>
{
ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst =>
{
if (!rst.Item1)
{
foreach (var err in rst.Item2)
{
SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error);
}
}
});
});
}
catch (Exception ex)
{
LogHelper.WriteLogError($"开启脚本时出错:{item}", ex);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("读取本地脚本文件列表时出错", ex);
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("开启后台脚本时出错!", ex);
}
}
#endregion
#region 产品操作
///
/// 加载所有产品
///
public void LoadAllProducts()
{
Products = new ObservableCollection();
try
{
if (File.Exists(FilePath.ProductsPath + "//ProductList.cfg"))
{
Dictionary list = FileHelper.ReadJsonFile>(FilePath.ProductsPath + "//ProductList.cfg");
foreach (var item in list)
{
Products.Add(FileHelper.ReadJsonFile(FilePath.ProductsPath + "//" + item.Value + "//" + item.Value + ".cfg"));
//for (int i = 0; i < Products[Products.Count - 1].CameraProcedures.Count; i++)
//{
// for (int j = 0; j < Products[Products.Count - 1].CameraProcedures[i].ProcedureModels.Count; j++)
// {
// string prcPath = FilePath.ProductsPath + "//" + item.Value + "//" + Products[Products.Count - 1].CameraProcedures[i].Camera + "//" + Products[Products.Count - 1].CameraProcedures[i].ProcedureModels[j].Name + ".prc";
// Products[Products.Count - 1].CameraProcedures[i].ProcedureModels[j].Procedure = VmProcedure.Load(prcPath);
// }
//}
}
SendTaskMessage($"{Lang.所有产品加载完成}!", MessageLevel.Debug);
}
else
{
SendTaskMessage($"{Lang.无产品}!", MessageLevel.Alarm);
}
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
LogHelper.WriteLogError("加载所有产品时出错!", ex);
}
}
///
/// 加载产品
///
public void LoadProducts(ProductModel product)
{
var prd = Products.FirstOrDefault(x => x.ID == product.ID);
if (prd == null)
{
return;
}
try
{
//清除上一个产品的相机拍照数据
feederCurentBlobArea = new Dictionary>();
LastPointsForFeeder = new Dictionary>>();
PointCollection = new Dictionary>>();
for (int i = 0; i < prd.CameraProcedures.Count; i++)
{
for (int j = 0; j < prd.CameraProcedures[i].ProcedureModels.Count; j++)
{
string prcPath = FilePath.ProductsPath + "//" + prd.Name + "//" + prd.CameraProcedures[i].Camera + "//" + prd.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
prd.CameraProcedures[i].ProcedureModels[j].ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
}
}
//设置Feeder的光源亮度及Feeder的振动参数
prd.IsLoad = true;
foreach (var item in Products)
{
if (item.ID != prd.ID)
{
item.IsLoad = false;
}
}
CurrentProduct = prd;
Dictionary> keyValuePairs = new Dictionary>();
Dictionary> keyValuePairsT = new Dictionary>();
foreach (var item in prd.CameraProcedures)
{
foreach (var itemT in item.ProcedureModels)
{
IRobot robot = RobotService.GetRobot(itemT.RobotId);
if (robot != null && robot.Brand == RobotBrand.XYZ_Platform)
{
if (keyValuePairs.ContainsKey(itemT.Id))
{
keyValuePairs[itemT.Id].Add(itemT.TriggerCommand);
}
else
{
keyValuePairs.Add(itemT.Id, new List { itemT.TriggerCommand });
}
if (!keyValuePairsT.ContainsKey(itemT.Id))
{
keyValuePairsT.Add(itemT.Id, itemT.ProcedureOutputsOpcAdrs);
}
}
}
}
Guid[] Threadkeys = PlcTrigger.Keys.ToArray();
Thread[] ThreadValues = PlcTrigger.Values.ToArray();
for (int i = 0; i < PlcTrigger.Count; i++)
{
var procedure = prd.CameraProcedures.FirstOrDefault(p => p.ProcedureModels?.FirstOrDefault(f => f.Id == Threadkeys[i]) != null);
Guid guid = procedure.ProcedureModels.FirstOrDefault(f => f.Id == Threadkeys[i]).RobotId;
XYZ_Platform robot = RobotService.GetRobot(guid) as XYZ_Platform;
robot.IsTrigger = false;
ThreadValues[i].Abort();
}
PlcTrigger.Clear();
Guid[] keys = keyValuePairs.Keys.ToArray();
List[] values = keyValuePairs.Values.ToArray();
for (int i = 0; i < keyValuePairs?.Count; i++)
{
var procedure = prd.CameraProcedures.FirstOrDefault(p =>
p.ProcedureModels?.FirstOrDefault(f => f.Id == keys[i]) != null);
Guid guid = procedure.ProcedureModels.FirstOrDefault(f => f.Id == keys[i]).RobotId;
XYZ_Platform robot = RobotService.GetRobot(guid) as XYZ_Platform;
robot.IsTrigger = false;
if (keyValuePairsT.ContainsKey(keys[i]))
{
List ProcedureOutputOpcAdrs = new List();
var saas = keyValuePairsT[keys[i]];
for (int j = 0; j < keyValuePairsT[keys[i]]?.Count; j++)
{
ProcedureOutputOpcAdrs.Add(keyValuePairsT[keys[i]][j]);
}
robot.IsTrigger = true;
Thread thread = robot.CreateThreadToTrigger(values[i].ToArray(), ProcedureOutputOpcAdrs);
PlcTrigger.Add(keys[i], thread);
}
}
DatabaseHelper.UpdateProductDatabase(product);
SendTaskMessage(Lang.产品加载完成.Replace("{0}", CurrentProduct.Name), MessageLevel.Debug);
App.Current.Dispatcher.Invoke(() =>
{
_eventAggregator.GetEvent().Publish(CurrentProduct);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.产品加载完成.Replace("{0}", CurrentProduct.Name), Duration = 1 });
});
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
LogHelper.WriteLogError($"加载产品[{prd.Name}]时出错!", ex);
}
}
///
/// 保存产品
///
///
public void SaveProducts(ProductModel product)
{
try
{
product.DateTime = DateTime.Now;
var prod = Products.FirstOrDefault(item => item.ID == product.ID);
if (prod != null)
{
prod = product;
}
else
{
product.IsCreate = false;
Products.Add(product);
}
Dictionary list = new Dictionary();
foreach (var item in Products)
{
list.Add(item.ID, item.Name);
}
FileHelper.WriteJsonFile(list, FilePath.ProductsPath + "//ProductList.cfg");
FileHelper.WriteJsonFile(product, FilePath.ProductsPath + "//" + product.Name + "//" + product.Name + ".cfg");
foreach (var item in product.CameraProcedures)
{
foreach (var item1 in item.ProcedureModels)
{
string prcPath = FilePath.ProductsPath + "//" + product.Name + "//" + item.Camera + "//" + item1.Name + ".vpp";
if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
}
if (item1.ToolBlock != null)
{
CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
//item1.ToolBlock= CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
}
else
{
if (File.Exists(prcPath))
{
item1.ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
}
else
{
item1.ToolBlock = CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
}
}
}
}
DatabaseHelper.UpdateProductDatabase(product);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
LogHelper.WriteLogError("保存产品时出错!", ex);
}
}
///
/// 保存产品
///
public void SaveProducts()
{
Dictionary list = new Dictionary();
foreach (var item in Products)
{
list.Add(item.ID, item.Name);
}
FileHelper.WriteJsonFile(list, FilePath.ProductsPath + "//ProductList.cfg");
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
}
///
/// 保存产品模板
///
///
public void SaveProductTemplate(ProductModel product)
{
try
{
product.DateTime = DateTime.Now;
var prod = Products.FirstOrDefault(item => item.ID == product.ID);
if (prod != null)
{
prod = product;
}
else
{
product.IsCreate = false;
}
FileHelper.WriteJsonFile(product, FilePath.ProductTemplatePath + "//" + product.Name + "//" + product.Name + ".cfg");
foreach (var item in product.CameraProcedures)
{
foreach (var item1 in item.ProcedureModels)
{
string prcPath = FilePath.ProductTemplatePath + "//" + product.Name + "//" + item.Camera + "//" + item1.Name + ".vpp";
if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
}
if (item1.ToolBlock != null)
{
CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
//item1.ToolBlock= CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
}
else
{
if (File.Exists(prcPath))
{
item1.ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
}
else
{
item1.ToolBlock = CogSerializer.LoadObjectFromFile(FilePath.SimpleProcedurePath) as CogToolBlock;
}
}
}
}
DatabaseHelper.UpdateProductDatabase(product);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
LogHelper.WriteLogError("保存产品模板时出错!", ex);
}
}
///
/// 复制产品
///
///
///
public ProductModel CopyProduct(ProductModel product, string newName)
{
var p = product.Clone();
p.Name = newName;
p.ID = Guid.NewGuid();
p.DateTime = DateTime.Now;
for (int i = 0; i < p.CameraProcedures.Count; i++)
{
for (int j = 0; j < p.CameraProcedures[i].ProcedureModels.Count; j++)
{
string sorPath = FilePath.ProductsPath + "//" + ((ProductModel)product).Name + "//" + p.CameraProcedures[i].Camera + "//" + ((ProductModel)product).CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
string procname = p.CameraProcedures[i].ProcedureModels[j].Name.Split('-')[2];
procname = $"{p.Name}-{p.CameraProcedures[i].Camera}-{procname}";
p.CameraProcedures[i].ProcedureModels[j].Name = procname;
string prcPath = FilePath.ProductsPath + "//" + p.Name + "//" + p.CameraProcedures[i].Camera + "//" + p.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
}
if (File.Exists(sorPath))
{
File.Copy(sorPath, prcPath, true);
if (p.CameraProcedures[i].ProcedureModels[j].ToolBlock == null)
{
p.CameraProcedures[i].ProcedureModels[j].ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
}
}
}
}
Products.Add(p);
SaveProducts(p);
return p;
}
///
/// 重新命名产品
///
///
///
public void RenameProduct(ProductModel product, string newName)
{
string oldname = product.Name;
//更改产品名称
product.Name = newName;
//遍历所有的相机流程,更改相机流程的名称
for (int i = 0; i < product.CameraProcedures.Count; i++)
{
for (int j = 0; j < product.CameraProcedures[i].ProcedureModels.Count; j++)
{
//旧路径
string sorPath = FilePath.ProductsPath + "//" + oldname + "//" + product.CameraProcedures[0].Camera + "//" + product.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
string procname = product.CameraProcedures[i].ProcedureModels[j].Name.Split('-')[2];
procname = $"{product.Name}-{product.CameraProcedures[i].Camera}-{procname}";
product.CameraProcedures[i].ProcedureModels[j].Name = procname;
//新路径
string prcPath = FilePath.ProductsPath + "//" + product.Name + "//" + product.CameraProcedures[0].Camera + "//" + product.CameraProcedures[i].ProcedureModels[j].Name + ".vpp";
if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
}
if (File.Exists(sorPath))
{
File.Copy(sorPath, prcPath, true);
File.Delete(sorPath);
}
}
string prcPath1 = FilePath.ProductsPath + "//" + oldname + "//" + product.CameraProcedures[0].Camera;
if (Directory.Exists(prcPath1))
{
Directory.Delete(prcPath1);
}
}
//更改产品数据库
string src = FilePath.ProductsPath + "//" + oldname + "//" + oldname + ".db";
string dsc = FilePath.ProductsPath + "//" + product.Name + "//" + product.Name + ".db";
if (File.Exists(src))
{
File.Copy(src, dsc, true);
File.Delete(src);
}
//更改数据库中有关的产品名称
DatabaseHelper.RevampProductName(product, oldname);
SaveProducts(product);
//删除旧产品路径
string sorPath1 = FilePath.ProductsPath + "//" + oldname + "//" + oldname + ".cfg";
if (File.Exists(sorPath1))
{
File.Delete(sorPath1);
}
sorPath1 = FilePath.ProductsPath + "//" + oldname;
if (Directory.Exists(sorPath1))
{
Directory.Delete(sorPath1);
}
}
///
/// 移除产品
///
///
public void RemoveProduct(ProductModel product)
{
var prod = Products.FirstOrDefault(p => p.ID == product.ID);
if (prod != null)
{
Products.Remove(prod);
SaveProducts();
}
}
#endregion
#region 相机校准操作
///
/// 加载所有校准
///
public void LoadAllCalibration()
{
try
{
if (File.Exists(FilePath.CalibrationPath + "//CalibrationList.cfg"))
{
DeviceConfig.Calibrations = new ObservableCollection();
Dictionary list = FileHelper.ReadJsonFile>(FilePath.CalibrationPath + "//CalibrationList.cfg");
foreach (var item in list)
{
DeviceConfig.Calibrations.Add(FileHelper.ReadJsonFile(FilePath.CalibrationPath + "//" + item.Value + "//" + item.Value + ".cfg"));
}
SendTaskMessage(Lang.校准加载完成, MessageLevel.Debug);
}
else
{
SendTaskMessage(Lang.无校准, MessageLevel.Alarm);
}
}
catch (Exception ex)
{
DeviceConfig.Calibrations = new ObservableCollection();
LogHelper.WriteLogError("加载校准配置文件时出错!", ex);
}
}
///
/// 保存校准
///
///
public void SaveCalibration(CalibrationInfo calibration)
{
try
{
calibration.DateTime = DateTime.Now;
var calib = DeviceConfig.Calibrations.FirstOrDefault(item => item.Id == calibration.Id);
if (calib != null)
{
calib = calibration;
}
else
{
calibration.IsCreate = false;
DeviceConfig.Calibrations.Add(calibration);
}
Dictionary list = new Dictionary();
foreach (var item in DeviceConfig.Calibrations)
{
list.Add(item.Id, item.Name);
}
FileHelper.WriteJsonFile(list, FilePath.CalibrationPath + "//CalibrationList.cfg");
FileHelper.WriteJsonFile(calibration, FilePath.CalibrationPath + "//" + calibration.Name + "//" + calibration.Name + ".cfg");
if (calibration.ToolBlock != null)
{
string prcPath = FilePath.CalibrationPath + "//" + calibration.Name + "//" + calibration.Name + ".vpp";
if (!Directory.Exists(Path.GetDirectoryName(prcPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(prcPath));
}
CogSerializer.SaveObjectToFile(calibration.ToolBlock, prcPath);
}
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
LogHelper.WriteLogError("保存校准时出错!", ex);
}
}
///
/// 移除校准
///
///
public void RemoveCalibration(CalibrationInfo calibration)
{
var calib = DeviceConfig.Calibrations.FirstOrDefault(p => p.Id == calibration.Id);
if (calib != null)
{
DeviceConfig.Calibrations.Remove(calib);
Dictionary list = new Dictionary();
foreach (var item in DeviceConfig.Calibrations)
{
list.Add(item.Id, item.Name);
}
FileHelper.WriteJsonFile(list, FilePath.CalibrationPath + "//CalibrationList.cfg");
_eventAggregator.GetEvent().Publish(new MessageParameter() { Msg = Lang.保存完成, Duration = 1 });
}
}
#endregion
#region Feeder清料动作
///
/// 加载Feeder清料动作
///
public Dictionary> LoadFeedersClearTask()
{
Dictionary> FeedersClearWork = new Dictionary>();
try
{
if (File.Exists(FilePath.FeedersClearTaskPath))
{
FeedersClearWork = FileHelper.ReadJsonFile>>(FilePath.FeedersClearTaskPath);
}
return FeedersClearWork;
}
catch (Exception ex)
{
LogHelper.WriteLogError("加载Feeder清料动作配置文件时出错!", ex);
return FeedersClearWork;
}
}
///
/// 保存Feeder清料动作
///
public void SaveFeedersClearTask(Dictionary> FeedersClearWork)
{
FileHelper.WriteJsonFile(FeedersClearWork, FilePath.FeedersClearTaskPath);
}
///
/// 执行Feeder清料
///
///
///
///
public async Task ExecuteFeederClear(Guid FeederId, FeederClearWork feederClearWork, CancellationToken cancellationToken)
{
IVoiceCoilMotorFeeder Feeder = FeederService.GetFeeder(FeederId);
if (!Feeder.IsConnected)
{
return;
}
for (int i = 0; i < feederClearWork.ClearCount; i++)
{
//1.Feeder振动之前,打开挡板
await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
await Task.Delay(200);
//2.执行配置的Feeder振动任务
for (int j = 0; j < feederClearWork.VibrationCount; j++)
{
await ExecuteFeederWorks(Feeder, feederClearWork.FeederWorks, true);
//如果料仓停止了,则打开料仓运动
if (!await Feeder.GetOutputStatusAsync())
{
await Feeder.OutputAsync((int)feederClearWork.BeforeOutput + 1, 0);
}
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
await Feeder.StopOutputAsync();
return;
}
}
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
await Feeder.StopOutputAsync();
return;
}
//3.Feeder振动之后,关闭挡板
await Feeder.StopOutputAsync();
await Task.Delay(300);
}
//3.Feeder振动之后,关闭挡板
await Feeder.StopOutputAsync();
await Task.Delay(300);
}
#endregion
#region 机器人指令执行
public Dictionary RobotTCPCollection = new Dictionary();
///
/// 机器人TCP接收
///
///
///
///
private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
{
try
{
if (!RobotTCPCollection.ContainsKey(robotid))
RobotTCPCollection.Add(robotid, new CancellationTokenSource());
else
{
if (RobotTCPCollection[robotid].IsCancellationRequested)
{
RobotTCPCollection[robotid] = new CancellationTokenSource();
}
}
var robot = await RobotService.GetRobotAsync(robotid);
var r = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == robotid);
//从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
SendTaskMessage($"{r.RobotName}Received:{buffer}", MessageLevel.Info);
var _ = Task.Run(async () =>
{
try
{
await ExecuteRemoteCommand(buffer, async result =>
{
if (result.Item1)
{
try
{
if (result.Item2.Length > 1)
{
foreach (var item in result.Item2)
{
if (robot.ConnectType == TCPConnectType.Client)
{
if (robot.IsConnected)
{
await robot.SendAsync($"{item}");
}
}
else
{
var cient = (ITcpSessionClient)arg2;
if (cient.Online)
{
await robot.SendAsync(cient, $"{item}");
}
}
await Task.Delay(10);
}
}
else
{
if (robot.ConnectType == TCPConnectType.Client)
{
if (robot.IsConnected)
{
await robot.SendAsync($"{result.Item2[0]}");
}
}
else
{
var cient = (ITcpSessionClient)arg2;
if (cient.Online)
{
await robot.SendAsync(cient, $"{result.Item2[0]}");
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("TCP发送数据时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
}
}, RobotTCPCollection[robotid].Token);
}
catch (Exception ex)
{
LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
}
///
/// 机器人XY模组执行命令
///
///
///
///
private async void Management_TrggerChangeEvent(Guid arg1, object arg2, List arg3)
{
if (!RobotTCPCollection.ContainsKey(arg1))
RobotTCPCollection.Add(arg1, new CancellationTokenSource());
else
{
if (RobotTCPCollection[arg1].IsCancellationRequested)
{
RobotTCPCollection[arg1] = new CancellationTokenSource();
}
}
var robot = await RobotService.GetRobotAsync(arg1) as XYZ_Platform;
var r = DeviceConfig.Robots.FirstOrDefault(ro => ro.Id == arg1);
SendTaskMessage($"{r.RobotName}Received:{arg2}", MessageLevel.Info);
var _ = Task.Run(async () =>
{
try
{
await ExecuteRemoteCommand(arg2.ToString(), async result =>
{
if (result.Item1)
{
try
{
string[] adrs = new string[arg3.Count];
object[] values = new object[arg3.Count];
values[0] = false;
values[1] = false;
string[] results = result.Item2[0].Split(',');
for (int i = 0; i < arg3.Count; i++)
{
if (i == 0)
{
if (results[1] == "OK")
{
adrs[i] = arg3[i].Name;
values[i] = true;
adrs[i + 1] = arg3[i + 1].Name;
values[i + 1] = false;
}
else
{
adrs[i] = arg3[i].Name;
values[i] = false;
adrs[i + 1] = arg3[i + 1].Name;
values[i + 1] = true;
}
i += 1;
continue;
}
if (i < arg3.Count - 1)
{
adrs[i] = arg3[i].Name;
if (i < results.Length)
{
float res = 0f;
if (float.TryParse(results[i], out res))
{
values[i] = results[i];
}
else
{
values[i] = res;
}
}
else
{
values[i] = 0f;
}
}
}
adrs[adrs.Length - 1] = arg3[arg3.Count - 1].Name;
values[values.Length - 1] = true;
robot.Plc.OpcUaClient.WriteNodes(adrs, values);
await Task.Delay(10);
}
catch (Exception ex)
{
LogHelper.WriteLogError("回复plc发送数据时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
}
}, RobotTCPCollection[arg1].Token);
}
catch (Exception ex)
{
LogHelper.WriteLogError("处理XYZ机器人接收的命令时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
});
}
#region 处理命令
///
/// 执行命令
///
///
public async Task ExecuteRemoteCommand(string command, Action> callback, CancellationToken cancellationToken)
{
string[] commandItem = command.Split(',');
if (CurrentProduct == null)
{
if (commandItem[0] == "GetProductName")
{
callback.Invoke(new Tuple(true, new string[] { $"{commandItem[0]},null" }));
return;
}
}
ProcedureModel procedure = null;
foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
{
procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == commandItem[0]);
if (procedure != null) break;
}
if (procedure != null)
{
//相机拍照
await RunProcedure(procedure, commandItem, rst =>
{
if (rst.Item1)
{
if (rst.Item2.Length > 1)
{
List buffers = new List();
foreach (var item in rst.Item2)
{
buffers.Add($"{commandItem[0]},{item}");
}
callback.Invoke(new Tuple(rst.Item1, buffers.ToArray()));
}
else
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2[0]}" }));
}
}
else
{
callback.Invoke(rst);
}
}, cancellationToken);
return;
}
switch (commandItem[0])
{
case "LoadProduct":
await LoadProduct(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetProductName":
await GetCurrentProductName(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetProductID":
await GetCurrentProductID(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetSpeed":
await GetCurrentProductSpeed(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetAllRobotPoints":
await GetAllRobotPoints(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetRobotPointsCount":
await GetRobotPointsCount(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetRobotPoint":
await GetRobotPoint(int.Parse(commandItem[1]), rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetPalletsCount":
await GetPalletsCount(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetAllPallets":
await GetAllPallet(rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetPallet":
await GetPallet(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetPalletPoint":
await GetPalletPoint(commandItem[1], int.Parse(commandItem[2]), rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetToolCount":
await GetToolCount(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetTool":
await GetTool(commandItem[1], int.Parse(commandItem[2]), rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "GetProcedureParam":
await GetProcedureParam(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "CycleTime":
ExecuteCycleTime(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "Record":
AddProductionRecords(commandItem[1], rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
break;
case "Err":
SendTaskMessage(commandItem[1], MessageLevel.Error);
DatabaseHelper.AppendAlarm(commandItem[1]);
break;
case "Info":
SendTaskMessage(commandItem[1], MessageLevel.Info);
break;
case "GetGlobalParam":
if (commandItem.Length == 2)
{
GetGlobalParam(commandItem[1], -1, rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
}
else if (commandItem.Length == 3)
{
GetGlobalParam(commandItem[1], int.Parse(commandItem[2]), rst =>
{
callback.Invoke(new Tuple(rst.Item1, new string[] { $"{commandItem[0]},{rst.Item2}" }));
});
}
break;
}
}
///
/// 运行流程
///
/// 流程对象
/// 触发命令
/// 回调函数
/// 取消任务
///
public async Task RunProcedure(ProcedureModel procedure, string[] items, Action> callback, CancellationToken cancellationToken)
{
string path = FilePath.ProductsPath + "//" + CurrentProduct.Name + "//" + procedure.CameraName + "//" + procedure.Name + ".cs";
string script = "";
if (File.Exists(path))
{
try
{
script = FileHelper.ReadFile(path);
SendTaskMessage(Lang.执行视觉处理脚本, MessageLevel.Debug);
var rst1 = await ScriptHelper.ExecuteVisionScriptingAsync(script, _regionManager, _eventAggregator, _container, procedure, items, rst =>
{
callback.Invoke(rst);
});
if (!rst1.Item1)
{
SendTaskMessage(Lang.视觉处理脚本出错, MessageLevel.Error);
callback.Invoke(new Tuple(false, new string[] { "ScriptError" }));
foreach (var item in rst1.Item2)
{
SendTaskMessage(item, MessageLevel.Error);
}
}
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
LogHelper.WriteLogError("执行视觉处理脚本时出错!", ex);
callback.Invoke(new Tuple(false, new string[] { "ScriptError" }));
}
}
else
{
//正常执行模块,每次拍照,会返回所有的结果数据
IVoiceCoilMotorFeeder Feeder = null;
if (procedure.FeederId != Guid.Empty)
{
Feeder = this.FeederService.GetFeeder(procedure.FeederId);
await RunProcedureFeeder(Feeder, procedure, items, rst =>
{
callback.Invoke(rst);
}, cancellationToken);
}
else
{
RunProcedureOther(procedure, items, rst =>
{
callback.Invoke(rst);
}, cancellationToken);
}
}
}
///
/// Feeder当前Blob的面积,产品-流程-面积
///
public Dictionary> feederCurentBlobArea = new Dictionary>();
///
/// 最后一次feeder拍照出来的点位,流程-点数据
///
public Dictionary>> LastPointsForFeeder = new Dictionary>>();
///
/// 每次拍照得到的点位数据集合,每个流程中包含多个结果输出项,每个结果项中包含多个点位,流程-输出集合-点位队列
///
public Dictionary>> PointCollection = new Dictionary>>();
///
/// Feeder相机引导模式
///
/// feeder
/// 流程对象
/// 触发命令
/// 回调函数
///
public async Task RunProcedureFeeder(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, string[] items, Action> callback, CancellationToken cancellationToken)
{
//是否检测上次的点位,相同点位排除
bool IsCheckLastPoints = false;
bool IsSingleResultModel = false;
int InputVibration = 0;
int GetPosCount = 1;
Dictionary InputTerminal = null; //触发命令传入的输入终端
if (items.Length >= 2 && string.Equals(items[1], "GetPos"))
{
//Camera1,GetPos,PosCount,CheckLastPoints
if (items.Length >= 4 && string.Equals(items[3], "CheckLastPoints"))
{
IsCheckLastPoints = true;
GetPosCount = int.Parse(items[2]);
}
////Camera1,GetPos,CheckLastPoints
else if (items.Length >= 3 && string.Equals(items[2], "CheckLastPoints"))
{
IsCheckLastPoints = true;
GetPosCount = 1;
}
else if (items.Length >= 3 && int.TryParse(items[2], out GetPosCount))
{
}
else
{
GetPosCount = 1;
}
if (GetPosCount <= 0)
{
GetPosCount = 1;
}
//进入一次拍照后,,点位数据保存在软件里面,机器人每次跟软件获取一个或者两个点位
////获取点位数据
if (!PointCollection.ContainsKey(procedure.Id))
{
PointCollection.Add(procedure.Id, new Dictionary>());
}
IsSingleResultModel = true;
}
else if (items.Length >= 2 && string.Equals(items[1], "ClearPos"))
{
//进入一次拍照后,,点位数据保存在软件里面,机器人每次跟软件获取一个或者两个点位
////清除所有点位数据
if (!PointCollection.ContainsKey(procedure.Id))
{
PointCollection.Add(procedure.Id, new Dictionary>());
}
PointCollection[procedure.Id].Clear();
IsSingleResultModel = true;
callback.Invoke(new Tuple(true, new string[] { "ClearPos" }));
return;
}
else if (items.Length >= 2 && string.Equals(items[1], "CheckLastPoints"))
{
IsCheckLastPoints = true;
}
else if (items.Length >= 2 && string.Equals(items[1], "Vibration"))
{
//先振后拍
InputVibration = 1;
}
else if (items.Length >= 2 && string.Equals(items[1], "NoVibration"))
{
//先拍再决定是否要不要振
InputVibration = 2;
}
else if (items.Length >= 2 && string.Equals(items[1], "SetVisionToolInputs"))
{
InputTerminal = new Dictionary();
//触发命令传入的输入终端
for (int i = 2; i < items.Length; i += 2)
{
if (!string.IsNullOrEmpty(items[i]) && items.Length >= i + 2)
{
InputTerminal.Add(items[i].Trim(), items[i + 1].Trim());
}
}
if (InputTerminal.Count <= 0)
{
InputTerminal = null;
}
}
//如果还没有结果项目,则触发拍照,获取结果
if (IsSingleResultModel && PointCollection[procedure.Id].Count > 0)
{
//遍历所有的结果项
foreach (var item in PointCollection[procedure.Id])
{
//如果结果的数量大于等于可获取的点位数量,则直接返回点位数据
if (item.Value != null && item.Value.Count >= GetPosCount)
{
List poslist = new List();
for (int i = 0; i < GetPosCount; i++)
{
poslist.Add(item.Value.Dequeue());
}
callback.Invoke(new Tuple(true, new string[] { $"OK,{item.Key},{string.Join(",", poslist)}" }));
SendTaskMessage($"{item.Key}{Lang.剩余点位数量}:{item.Value.Count}", MessageLevel.Debug);
return;
}
}
}
if (IsSingleResultModel)
{
PointCollection[procedure.Id].Clear();
}
await ExecuteFeederForPhotoBefore(Feeder, procedure, InputVibration, cancellationToken);
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
await Feeder.CloseLightAsync();
return;
}
DateTime nowtime = DateTime.Now;
//多次拍照
for (int i = 0; i < procedure.FeederFailLimit; i++)
{
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
await Feeder.CloseLightAsync();
return;
}
SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
string photoresult = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
if (!string.IsNullOrEmpty(photoresult))
{
//多次拍照,如果拍照次数到达上限,直接返回结果
if (i == procedure.FeederFailLimit - 1)
{
callback.Invoke(new Tuple(true, new string[] { $"NG,{photoresult}" }));
return;
}
else
{
continue;
}
}
var BlobTotalArea = (double)outputCollection["BlobTotalArea"].Value;
//记录当前的blob面积
Dictionary tuple;
if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
{
//如流程当前已经存在此流程的记录
if (tuple.ContainsKey(procedure.Id))
{
tuple[procedure.Id] = BlobTotalArea;
}
else
{
tuple.Add(procedure.Id, BlobTotalArea);
}
}
else
{
feederCurentBlobArea.Add(CurrentProduct.ID, new Dictionary());
feederCurentBlobArea[CurrentProduct.ID].Add(procedure.Id, BlobTotalArea);
}
if (!outputCollection.Contains("Found"))
{
callback.Invoke(new Tuple(true, new string[] { "NG,NoOut[Found]" }));
return;
}
bool Found = (bool)(outputCollection["Found"].Value);
//拍照OK
if (Found)
{
SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
if (procedure.ProcedureOutputs == null)
{
SendTaskMessage(Lang.视觉流程未配置输出项, MessageLevel.Alarm);
callback.Invoke(new Tuple(true, new string[] { "NG,NotOutputs" }));
return;
}
var ResultCollection = GetVisionOutput(procedure, outputCollection, items);
if (!ResultCollection.Item1)
{
callback.Invoke(new Tuple(true, new string[] { ResultCollection.Item2 }));
return;
}
List SendResults = new List();
//将本次点位结果记录至最后一次
if (!LastPointsForFeeder.ContainsKey(Feeder.Id))
{
LastPointsForFeeder.Add(Feeder.Id, new List>());
}
int PosNum = 0;
bool ishavepoint = false;
List> pointBuffer = new List>();
foreach (var result in ResultCollection.Item3)
{
//是点位数据时
if (result.Value.Item1)
{
ishavepoint = true;
//值不为空时
if (result.Value.Item2 != null)
{
List points = new List();
foreach (var pos in (List>)(result.Value.Item2))
{
pointBuffer.Add(pos);
//判断是否有重复的点位,防止机器人重复取同一个物料,陷入死循环
if (IsCheckLastPoints)
{
if (LastPointsForFeeder.ContainsKey(Feeder.Id))
{
var repeated = LastPointsForFeeder[Feeder.Id].FirstOrDefault(p => Math.Abs(p[0] - pos[0]) < 1 && Math.Abs(p[1] - pos[1]) < 1);
if (repeated != null) continue;
}
}
if (IsSingleResultModel)
{
PosNum++;
//如果当前是软件点位队列存储模式,则,将所有数据存储在队列中
if (!PointCollection[procedure.Id].ContainsKey(result.Key))
{
PointCollection[procedure.Id].Add(result.Key, new Queue());
}
PointCollection[procedure.Id][result.Key].Enqueue($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
}
else
{
//根据当前点位数量决定是否继续输出点位。
PosNum++;
if (PosNum >= procedure.OutputPointCountMax)
{
points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
break;
}
else
{
points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
}
}
}
if (IsSingleResultModel)
{
//如果当前是软件点位队列存储模式,则,将所有数据存储在队列中
if (!PointCollection[procedure.Id].ContainsKey(result.Key))
{
PointCollection[procedure.Id].Add(result.Key, new Queue());
}
SendTaskMessage($"{result.Key}{Lang.可用的点位个数}:{PointCollection[procedure.Id][result.Key].Count}", MessageLevel.Debug);
}
else
{
if (points.Count == 0)
{
SendResults.Add($"0");
break;
}
else
{
SendResults.Add($"{points.Count},{string.Join(",", points)}");
}
}
}
else
{
SendResults.Add($"0");
}
}
//其他输出数据时
else
{
if (result.Value.Item2 != null)
{
SendResults.Add((string)result.Value.Item2);
}
else
{
SendResults.Add($"null");
}
}
}
//将本次点位结果记录至最后一次
LastPointsForFeeder[Feeder.Id] = pointBuffer;
if (ishavepoint && PosNum <= 0)
{
//存在点位输出项,但是点位数量为0
await ExecuteFeederForPhotoLater(Feeder, procedure, BlobTotalArea, cancellationToken);
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
await Feeder.CloseLightAsync();
return;
}
continue;
}
if (Feeder != null)
{
await Feeder.CloseLightAsync();
}
if (IsSingleResultModel)
{
//遍历所有的结果项
foreach (var item in PointCollection[procedure.Id])
{
//如果结果的数量大于等于可获取的点位数量,则直接返回点位数据
if (item.Value != null && item.Value.Count >= GetPosCount)
{
List poslist = new List();
for (int j = 0; j < GetPosCount; j++)
{
poslist.Add(item.Value.Dequeue());
}
callback.Invoke(new Tuple(true, new string[] { $"OK,{item.Key},{string.Join(",", poslist)}" }));
SendTaskMessage($"{item.Key}{Lang.剩余点位数量}:{item.Value.Count}", MessageLevel.Debug);
return;
}
}
}
else
{
callback.Invoke(new Tuple(true, new string[] { $"OK,{string.Join(";", SendResults)}" }));
}
return;
}
//拍照NG
else
{
SendTaskMessage(Lang.拍照NG, MessageLevel.Error);
await ExecuteFeederForPhotoLater(Feeder, procedure, BlobTotalArea, cancellationToken);
continue;
}
}
SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
callback.Invoke(new Tuple(true, new string[] { "NG,NoFind" }));
}
///
/// 相机拍照,其他模式
///
///
///
///
public void RunProcedureOther(ProcedureModel procedure, string[] items, Action> callback, CancellationToken cancellationToken)
{
DateTime nowtime = DateTime.Now;
Dictionary InputTerminal = null; //触发命令传入的输入终端
if (items.Length >= 2 && string.Equals(items[1], "SetVisionToolInputs"))
{
InputTerminal = new Dictionary();
//触发命令传入的输入终端
for (int i = 2; i < items.Length; i += 2)
{
if (!string.IsNullOrEmpty(items[i]) && items.Length >= i + 2)
{
InputTerminal.Add(items[i].Trim(), items[i + 1].Trim());
}
}
if (InputTerminal.Count <= 0)
{
InputTerminal = null;
}
}
for (int i = 0; i < procedure.FeederFailLimit; i++)
{
if (cancellationToken != null && cancellationToken.IsCancellationRequested)
{
return;
}
SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
string photoresult = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
if (!string.IsNullOrEmpty(photoresult))
{
//多次拍照,如果拍照次数到达上限,直接返回结果
if (i == procedure.FeederFailLimit - 1)
{
callback.Invoke(new Tuple(true, new string[] { $"NG,{photoresult}" }));
return;
}
else
{
continue;
}
}
if (!outputCollection.Contains("Found"))
{
callback.Invoke(new Tuple(true, new string[] { "NG,NoOut[Found]" }));
return;
}
bool Found = (bool)(outputCollection["Found"].Value);
//拍照OK
if (Found)
{
SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
if (procedure.ProcedureOutputs == null)
{
SendTaskMessage(Lang.视觉流程未配置输出项, MessageLevel.Alarm);
callback.Invoke(new Tuple(true, new string[] { "NG,NotOutputs" }));
return;
}
var ResultCollection = GetVisionOutput(procedure, outputCollection, items);
if (!ResultCollection.Item1)
{
callback.Invoke(new Tuple(true, new string[] { ResultCollection.Item2 }));
return;
}
List SendResults = new List();
int PosNum = 0;
bool ishavepoint = false;
foreach (var result in ResultCollection.Item3)
{
//是点位数据时
if (result.Value.Item1)
{
ishavepoint = true;
//值不为空时
if (result.Value.Item2 != null)
{
List points = new List();
foreach (var pos in (List>)(result.Value.Item2))
{
//根据当前点位数量决定是否继续输出点位。
PosNum++;
if (PosNum >= procedure.OutputPointCountMax)
{
points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
break;
}
else
{
points.Add($"{pos[0]:F3},{pos[1]:F3},{pos[2]:F3}");
}
}
if (points.Count == 0)
{
SendResults.Add($"0");
break;
}
else
{
SendResults.Add($"{points.Count},{string.Join(",", points)}");
}
}
else
{
SendResults.Add($"0");
}
}
//其他输出数据时
else
{
if (result.Value.Item2 != null)
{
SendResults.Add((string)result.Value.Item2);
}
else
{
SendResults.Add($"null");
}
}
}
if (ishavepoint && PosNum <= 0)
{
continue;
}
callback.Invoke(new Tuple(true, new string[] { $"OK,{string.Join(";", SendResults)}" }));
return;
}
//拍照NG
else
{
SendTaskMessage(Lang.拍照NG, MessageLevel.Error);
continue;
}
}
SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
callback.Invoke(new Tuple(true, new string[] { "NG,NoFind" }));
}
#region 相机拍照
///
/// 执行相机拍照
///
///
///
///
public string ExecutePhoto(ProcedureModel procedure, Dictionary InputTerminal, out CogToolBlockTerminalCollection outputCollection)
{
try
{
//采集图像
var camera = CameraService.GetCamera(procedure.CameraId);
bool succed = camera.SetExposureTime(procedure.ExposureTime);
if (!succed)
{
SendTaskMessage($"相机曝光设置失败!", MessageLevel.Error);
}
succed = camera.SetGain(procedure.Gain);
if (!succed)
{
SendTaskMessage($"相机增益设置失败!", MessageLevel.Error);
}
DateTime nowtime = DateTime.Now;
LogHelper.WriteLogInfo("开始采集图像");
var image = camera.Grab();
if (image == null)
{
SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
outputCollection = null;
return "CameraError";
}
procedure.ToolBlock.Inputs["InputImage"].Value = image;
LogHelper.WriteLogInfo($"采集图像完成;用时:{(DateTime.Now - nowtime).Milliseconds}ms");
if (InputTerminal != null)
{
LogHelper.WriteLogInfo($"为ToolBlock传入输入终端");
foreach (var item in InputTerminal)
{
if (procedure.ToolBlock.Inputs.Contains(item.Key))
{
LogHelper.WriteLogInfo($"传入[{item.Key}]={item.Value}");
procedure.ToolBlock.Inputs[item.Key].Value = item.Value;
}
else
{
LogHelper.WriteLogInfo($"创建并传入[{item.Key}]={item.Value}");
procedure.ToolBlock.Inputs.Add(new CogToolBlockTerminal(item.Key, item.Value));
}
}
}
//运行视觉工具
LogHelper.WriteLogInfo("开始运行视觉工具");
procedure.ToolBlock.Run();
if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
{
SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
outputCollection = procedure.ToolBlock.Outputs;
ICogRecord record = null;
foreach (CogToolBlockTerminal item in outputCollection)
{
if (item.Value is ICogRecord)
record = item.Value as ICogRecord;
}
_eventAggregator.GetEvent().Publish(new ShowRender()
{
CameraName = procedure.CameraName,
Id = procedure.CameraId,
Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
Record = record,
Result = (bool)(outputCollection["Found"].Value),
IsShow = true,
IsSaveImage = procedure.IsSaveImage,
SaveImageModel = procedure.SaveImageModel,
SaveImagePathModel = procedure.SaveImagePathModel,
SavePath = procedure.SavePath,
IsCompress = procedure.IsCompress,
});
DatabaseHelper.AddCameraRecords(CurrentProduct.Name, procedure.Name, outputCollection);
return string.Empty;
}
else
{
SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
outputCollection = null;
_eventAggregator.GetEvent().Publish(new ShowRender()
{
CameraName = procedure.CameraName,
Id = procedure.CameraId,
Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
Graphic = new CogGraphicCollection(),
Result = false,
IsShow = true,
IsSaveImage = procedure.IsSaveImage,
SaveImageModel = procedure.SaveImageModel,
SaveImagePathModel = procedure.SaveImagePathModel,
SavePath = procedure.SavePath
});
DatabaseHelper.AddCameraRecords(CurrentProduct.Name, procedure.Name, outputCollection);
return "ToolBlockError";
}
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
outputCollection = null;
return "Error";
}
}
///
/// 校准转换
///
///
///
///
///
///
public Vector TransformPoint(CalibrationInfo calib, double x, double y, double angle, string[] items, out string message, RobotBrand robotBrand = RobotBrand.Default)
{
//得到校准矩阵
Matrix matrix = Matrix.Build.DenseOfArray(calib.AffineTransformationMaterial);
if (calib.CameraMount == CameraMount.FixedDown || calib.CameraMount == CameraMount.MobileJ2 || calib.CameraMount == CameraMount.MobileJ4)
{
angle *= -1;
}
//将像素坐标转换成机器人坐标
var rpos = matrix * Vector.Build.Dense(new double[] { x, y, 1 });
if (calib.CameraMount == Enums.CameraMount.MobileJ4)
{
if (items.Length < 4)
{
SendTaskMessage(Lang.J4移动相机校准转换条件错误, MessageLevel.Alarm);
message = "NG,DataError";
return null;
}
//像素直接转换成mm时的点位
double Robot_X, Robot_Y;
Robot_X = rpos[0];
Robot_Y = rpos[1];
//机器人当前TOOL 0下的坐标
double curpos_x = 0, curpos_y = 0, curpos_u = 0;
curpos_x = double.Parse(items[1]);
curpos_y = double.Parse(items[2]);
curpos_u = double.Parse(items[3]);
//得到旋转矩阵
double angle1 = Math.PI * (curpos_u - calib.MarkPoint.U) / 180;
// 创建T矩阵
Matrix rotationMatrix = Matrix.Build.DenseOfArray(new double[,]
{
{ Math.Cos(angle1), -Math.Sin(angle1) },
{ Math.Sin(angle1), Math.Cos(angle1) }
});
Vector p3 = Vector.Build.Dense(new double[] { Robot_X - calib.CalibPoints[0].Robot.X, Robot_Y - calib.CalibPoints[0].Robot.Y });
Vector phere = Vector.Build.Dense(new double[] { curpos_x, curpos_y });
var cc = rotationMatrix * p3 + phere;
rpos = Vector.Build.Dense(new double[] { cc[0], cc[1] });
}
else if (calib.CameraMount == Enums.CameraMount.MobileDown_XYPlatform)
{
if (items.Length < 4)
{
SendTaskMessage(Lang.移动相机校准转换条件错误, MessageLevel.Alarm);
message = "NG,DataError";
return null;
}
//像素直接转换成mm时的点位
double Robot_X, Robot_Y;
Robot_X = rpos[0];
Robot_Y = rpos[1];
//模组当前TOOL 0下的坐标(相当于模组吸嘴坐标)
double curpos_x = 0, curpos_y = 0, curpos_u = 0;
curpos_x = double.Parse(items[1]);
curpos_y = double.Parse(items[2]);
curpos_u = double.Parse(items[3]);
//得到旋转矩阵
//double angle1 = Math.PI * (curpos_u - calib.MarkPoint.U) / 180;
double angle1 = 0;
// 创建T矩阵
Matrix rotationMatrix = Matrix.Build.DenseOfArray(new double[,]
{
{ Math.Cos(angle1), -Math.Sin(angle1) },
{ Math.Sin(angle1), Math.Cos(angle1) }
});
Vector p3 = Vector.Build.Dense(new double[] { Robot_X - calib.CalibPoints[0].Robot.X, Robot_Y - calib.CalibPoints[0].Robot.Y });
Vector phere = Vector.Build.Dense(new double[] { curpos_x, curpos_y });
var cc = rotationMatrix * p3 + phere;
rpos = Vector.Build.Dense(new double[] { cc[0], cc[1] });//Mark点在tool0下的的坐标
}
else
{
//当需要直接转换工具坐标时
if (items.Length == 4 && double.TryParse(items[1], out double curposX) && double.TryParse(items[2], out double curposY) && double.TryParse(items[3], out double curposU))
{
//根据机器人当前的点位计算工具坐标
ToolCoord tool = new ToolCoord();
if (robotBrand == RobotBrand.Schneider)
{
curposU *= -1;
}
tool.ComputeTool(curposX, curposY, curposU, rpos[0], rpos[1]);
rpos = Vector.Build.Dense(new double[] { tool.X, tool.Y });
}
}
message = string.Empty;
return Vector.Build.Dense(new double[] { rpos[0], rpos[1], angle });
}
///
/// 获取需要输出项
///
///
///
///
/// 是否成功,错误返回内容,<项的名称,<是否是点位数据,值>>
public Tuple>> GetVisionOutput(ProcedureModel procedure, CogToolBlockTerminalCollection outputCollection, string[] items)
{
RobotBrand robotBrand = RobotBrand.Default;
var robot = DeviceConfig.Robots.FirstOrDefault(r => r.Id == procedure.RobotId);
if (robot != null)
{
robotBrand = robot.RobotBrand;
}
List SendResults = new List();
//<输出项的名称,<是否点位,每项输出集合值>>
Dictionary> ResultCollection = new Dictionary>();
foreach (var output in procedure.ProcedureOutputs) //遍历配置的所有需要输出项
{
//根据输出类型进行区分输出
if (output.ValueType == typeof(string))
{
//需要点位转换时,进行点位提取
if (output.IsPointTran)
{
if (outputCollection[output.Name].Value == null || string.IsNullOrEmpty(outputCollection[output.Name].Value.ToString()))
{
//如果需要输出的项的值为空,即点位数据为空,则输出点位的个数为0
ResultCollection.Add(output.Name, new Tuple(true, null));
continue;
}
string[] strpoints = outputCollection[output.Name].Value.ToString().Split(";");
List> currentPointsForFeeder = new List>();
int index = 0;
//获取相机校准
var calib = DeviceConfig.Calibrations.FirstOrDefault(cal => cal.Id == procedure.CalibrationId);
if (calib == null)
{
SendTaskMessage(Lang.J4移动相机校准转换条件错误1, MessageLevel.Alarm);
return new Tuple>>(false, "NG,NotCalibrations", null);
}
List SendDtat = new List();
List points = new List();
//遍历所有的输出点位
foreach (var pos in strpoints)
{
//转换点位-像素转换成机器人绝对坐标
var rpos = TransformPoint(calib, double.Parse(pos.Split(',')[0]), double.Parse(pos.Split(',')[1]), double.Parse(pos.Split(',')[2]), items, out string message, robotBrand);
if (rpos == null)
{
return new Tuple>>(false, message, null);
}
currentPointsForFeeder.Add(rpos);
}
ResultCollection[output.Name] = new Tuple(true, currentPointsForFeeder);
}
//直接输出字符串
else
{
if (outputCollection[output.Name].Value == null || string.IsNullOrEmpty(outputCollection[output.Name].Value.ToString()))
{
ResultCollection.Add(output.Name, new Tuple(false, null));
continue;
}
ResultCollection[output.Name] = new Tuple(false, outputCollection[output.Name].Value.ToString());
}
}
else
{
if (outputCollection[output.Name].Value == null)
{
ResultCollection.Add(output.Name, new Tuple(false, null));
}
else
{
ResultCollection[output.Name] = new Tuple(false, outputCollection[output.Name].Value.ToString());
}
}
}
return new Tuple>>(true, string.Empty, ResultCollection);
}
///
/// Feeder拍照前,执行Feeder
///
///
///
///
public async Task ExecuteFeederForPhotoBefore(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, int CompulsoryVibration, CancellationToken cancellationToken)
{
if (Feeder.FeederBrand == FeederBrand.AFAG)
{
await Feeder.SetLightValueAsync((ushort)procedure.LightValue);
}
else
{
//Feeder光源亮度设置
if (procedure.LightValue > 3)
{
var light = await Feeder.GetLightBrightnessAsync();
if (procedure.LightValue != light)
{
await Feeder.SetLightValueAsync((ushort)procedure.LightValue);
}
//打开光源
await Feeder.OpenLightAsync();
}
}
if (CompulsoryVibration == 2)
{
return;
}
//先振后拍时
if (procedure.VibrationModel == VibrationModel.VibrationPhoto || CompulsoryVibration == 1)
{
if (procedure.FeederWorks != null && procedure.FeederWorks.FeederWorkList != null)
{
bool flog = false;
Dictionary tuple;
if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
{
//首先判断是否是当前流程
if (tuple.TryGetValue(procedure.Id, out double minArea))
{
//如果上次的Blob面积小于设定的最小值,则触发供料
if (minArea <= procedure.MinArea)
{
flog = true;
SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
await Task.Delay(procedure.WaitFeederStop);
SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
}
}
}
if (!flog)
{
//执行配置的Feeder振动任务
await ExecuteFeederWorks(Feeder, procedure.FeederWorks, cancellationToken, false);
}
await Task.Delay(procedure.WaitFeederStop);
}
}
else
{
if (procedure.LightValue > 3)
{
await Task.Delay(procedure.WaitPhoto);
}
Dictionary tuple;
if (feederCurentBlobArea.TryGetValue(CurrentProduct.ID, out tuple))
{
//首先判断是否是当前流程
if (tuple.TryGetValue(procedure.Id, out double minArea))
{
//如果上次的Blob面积小于设定的最小值,则触发供料
if (minArea <= procedure.MinArea)
{
SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
await Task.Delay(procedure.WaitFeederStop);
SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
//执行配置的Feeder振动任务
/*foreach (var feederwork in procedure.FeederWorks.FeederWorkList)
{
if (feederwork.Function == VibrationFunction.Delay)
{
await Task.Delay(feederwork.Duration);
}
else
{
await Feeder.StartAction((int)feederwork.Function, feederwork.Duration);
await Task.Delay(feederwork.Duration);
}
}*/
await Task.Delay(procedure.WaitFeederStop);
}
}
}
}
}
///
/// Feeder拍照后,执行Feeder
///
///
///
///
///
public async Task ExecuteFeederForPhotoLater(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, double curentBlobArea, CancellationToken cancellationToken)
{
//根据斑点面积决定是否料仓供料
if (curentBlobArea <= procedure.MinArea)
{
SendTaskMessage(Lang.执行料仓供料, MessageLevel.Info);
await ExecuteFeederStockWorks(Feeder, procedure.FeederStockWorks, cancellationToken);
await Task.Delay(procedure.WaitFeederStop);
SendTaskMessage(Lang.料仓供料结束, MessageLevel.Info);
}
else
{
if (procedure.FeederWorks != null && procedure.FeederWorks.FeederWorkList != null)
{
SendTaskMessage(Lang.执行Feeder振动, MessageLevel.Info);
//执行配置的Feeder振动任务
await ExecuteFeederWorks(Feeder, procedure.FeederWorks, cancellationToken);
await Task.Delay(procedure.WaitFeederStop);
SendTaskMessage(Lang.Feeder振动结束, MessageLevel.Info);
}
}
}
#endregion
///
/// 加载产品
///
///
///
///
private Task LoadProduct(string name, Action> callback)
{
return Task.Run(() =>
{
ProductModel product = null;
product = Products.FirstOrDefault(p => p.Name == name);
if (product == null)
{
if (int.TryParse(name, out int ProductNumber))
{
product = Products.FirstOrDefault(p => p.NumberCode == ProductNumber);
}
else
{
callback.Invoke(new Tuple(true, "NG,NoProduct"));
return;
}
}
LoadProducts(product);
callback.Invoke(new Tuple(true, "OK"));
});
}
///
/// 获取当前产品名称
///
///
///
private Task GetCurrentProductName(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null)
{
callback.Invoke(new Tuple(true, "null"));
return;
}
callback.Invoke(new Tuple(true, CurrentProduct.Name));
});
}
///
/// 获取当前产品ID
///
///
///
private Task GetCurrentProductID(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null)
{
callback.Invoke(new Tuple(true, "null"));
return;
}
callback.Invoke(new Tuple(true, CurrentProduct.ID.ToString()));
});
}
///
/// 获取速度
///
///
///
private Task GetCurrentProductSpeed(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null)
{
return;
}
int power = CurrentProduct.Power ? 1 : 0;
int IsUserUpCamera = CurrentProduct.IsUserUpCamera ? 1 : 0;
callback.Invoke(new Tuple(true, $"{CurrentProduct.Speed},{CurrentProduct.Accel},{CurrentProduct.Speeds},{CurrentProduct.Accels},{power},{IsUserUpCamera}"));
});
}
///
/// 获取所有的机器人点位
///
///
///
private Task GetAllRobotPoints(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
StringBuilder sb = new StringBuilder();
foreach (var item in CurrentProduct.RobotPoint.Points)
{
sb.Append($"{item.Number},{item.X.ToString("F3")},{item.Y.ToString("F3")},{item.Z.ToString("F3")},{item.U.ToString("F3")},{item.V.ToString("F3")},{item.W.ToString("F3")},{(int)item.Hand},{item.Local},{item.Tool},{item.RobotId.ToString()},");
}
callback.Invoke(new Tuple(true, $"{sb.ToString().TrimEnd(',')}"));
});
}
///
/// 获取机器人点位数量
///
///
///
private Task GetRobotPointsCount(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
if (CurrentProduct.RobotPoint.Points == null)
{
callback.Invoke(new Tuple(true, $"0"));
}
else
{
callback.Invoke(new Tuple(true, $"{CurrentProduct.RobotPoint.Points.Count}"));
}
});
}
///
/// 获取指定编号机器人点位
///
///
///
private Task GetRobotPoint(int number, Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
var pos = CurrentProduct.RobotPoint.Points.FirstOrDefault(p => p.Number == number);
if (pos == null)
{
callback.Invoke(new Tuple(true, $"null"));
}
else
{
callback.Invoke(new Tuple(true, $"{pos.Number},{pos.X.ToString("F3")},{pos.Y.ToString("F3")},{pos.Z.ToString("F3")},{pos.U.ToString("F3")},{pos.V.ToString("F3")},{pos.W.ToString("F3")},{(int)pos.Hand},{pos.Local},{pos.Tool},{pos.RobotId.ToString()}"));
}
});
}
///
/// 获取托盘数量
///
///
///
private Task GetPalletsCount(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
if (CurrentProduct.RobotPoint.Pallets == null)
{
callback.Invoke(new Tuple(true, $"0"));
}
else
{
callback.Invoke(new Tuple(true, $"{CurrentProduct.RobotPoint.Pallets.Count}"));
}
});
}
///
/// 获取所有的托盘
///
///
///
private Task GetAllPallet(Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
StringBuilder sb = new StringBuilder();
foreach (var item in CurrentProduct.RobotPoint.Pallets)
{
sb.Append($"{item.Name},{item.Row},{item.Column},{(int)item.Arrangement},{item.P0.X.ToString("F3")},{item.P0.Y.ToString("F3")},{item.P0.Z.ToString("F3")},{item.P0.U.ToString("F3")},{item.P0.V.ToString("F3")},{item.P0.W.ToString("F3")},{(int)item.P0.Hand},{item.P0.Local},{item.P0.Tool}," +
$"{item.P1.X.ToString("F3")},{item.P1.Y.ToString("F3")},{item.P1.Z.ToString("F3")},{item.P1.U.ToString("F3")},{item.P1.V.ToString("F3")},{item.P1.W.ToString("F3")},{(int)item.P1.Hand},{item.P1.Local},{item.P1.Tool}," +
$"{item.P2.X.ToString("F3")},{item.P2.Y.ToString("F3")},{item.P2.Z.ToString("F3")},{item.P2.U.ToString("F3")},{item.P2.V.ToString("F3")},{item.P2.W.ToString("F3")},{(int)item.P2.Hand},{item.P0.Local},{item.P2.Tool},");
}
callback.Invoke(new Tuple(true, $"{sb.ToString().TrimEnd(',')}"));
});
}
///
/// 获取指定名称的托盘
///
///
///
private Task GetPallet(string name, Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
var pallet = CurrentProduct.RobotPoint.Pallets.FirstOrDefault(p => p.Name == name);
if (pallet == null)
{
callback.Invoke(new Tuple(true, $"null"));
}
else
{
callback.Invoke(new Tuple(true, $"{pallet.Name},{pallet.Row},{pallet.Column},{(int)pallet.Arrangement},{pallet.P0.X.ToString("F3")},{pallet.P0.Y.ToString("F3")},{pallet.P0.Z.ToString("F3")},{pallet.P0.U.ToString("F3")},{pallet.P0.V.ToString("F3")},{pallet.P0.W.ToString("F3")},{(int)pallet.P0.Hand},{pallet.P0.Local},{pallet.P0.Tool}," +
$"{pallet.P1.X.ToString("F3")},{pallet.P1.Y.ToString("F3")},{pallet.P1.Z.ToString("F3")},{pallet.P1.U.ToString("F3")},{pallet.P1.V.ToString("F3")},{pallet.P1.W.ToString("F3")},{(int)pallet.P1.Hand},{pallet.P1.Local},{pallet.P1.Tool}," +
$"{pallet.P2.X.ToString("F3")},{pallet.P2.Y.ToString("F3")},{pallet.P2.Z.ToString("F3")},{pallet.P2.U.ToString("F3")},{pallet.P2.V.ToString("F3")},{pallet.P2.W.ToString("F3")},{(int)pallet.P2.Hand},{pallet.P0.Local},{pallet.P2.Tool}"));
}
});
}
///
/// 获取夹具末端执行器数量
///
///
///
private Task GetToolCount(string command, Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.CameraProcedures == null)
{
return;
}
ProcedureModel procedure = null;
foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
{
procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
if (procedure != null) break;
}
if (procedure == null || procedure.ToolInfo == null)
{
callback.Invoke(new Tuple(true, $"0"));
return;
}
callback.Invoke(new Tuple(true, $"{procedure.ToolInfo.Count}"));
});
}
///
/// 获取指定编号的夹具末端执行器参数
///
///
///
private Task GetTool(string command, int index, Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.CameraProcedures == null)
{
return;
}
ProcedureModel procedure = null;
foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
{
procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
if (procedure != null) break;
}
if (procedure == null || procedure.ToolInfo == null)
{
callback.Invoke(new Tuple(true, $"null"));
return;
}
var tool = procedure.ToolInfo[index];
callback.Invoke(new Tuple(true, $"{tool.Tool.Number},{tool.Tool.X.ToString("F3")},{tool.Tool.Y.ToString("F3")},{tool.OffsetX.ToString("F3")},{tool.OffsetY.ToString("F3")},{tool.OffsetZ.ToString("F3")},{tool.OffsetU.ToString("F3")}"));
});
}
///
/// 获取流程参数
///
///
///
private Task GetProcedureParam(string command, Action> callback)
{
return Task.Run(() =>
{
if (CurrentProduct == null || CurrentProduct.RobotPoint == null)
{
return;
}
ProcedureModel procedure = null;
foreach (var cameraProcedures in CurrentProduct.CameraProcedures)
{
procedure = cameraProcedures.ProcedureModels.FirstOrDefault(p => p.TriggerCommand == command);
if (procedure != null) break;
}
if (procedure == null)
{
callback.Invoke(new Tuple(true, $"null"));
return;
}
callback.Invoke(new Tuple