using Cognex.VisionPro.ToolBlock;
using MathNet.Numerics.LinearAlgebra;
using NPOI.SS.Formula.Functions;
using OpenCvSharp;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using Team.FFFeederService.Interfaces;
using TeamAAS_VP.Core.PLCs;
using TeamAAS_VP.Core.ScrewDriver;
using TeamAAS_VP.Enums;
using TeamAAS_VP.Events;
using TeamAAS_VP.Interfaces;
using TeamAAS_VP.Models;
using TeamAAS_VP.Resources.Languages;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace TeamAAS_VP.Core
{
public class Management : BindableBase
{
#region 字段
IRegionManager _regionManager;
IEventAggregator _eventAggregator;
IContainerProvider _container;
IConfigService _configService;
IRobotService _robotService;
ICameraService _cameraService;
IFeederService _feederService;
IPlcService _plcService;
ILightManagerService _lightManagerService;
IProductService _productService;
ICalibrationService _calibrationService;
IRemoteCommandService _remoteCommandService;
ISystemDatabaseService _systemDatabaseService;
IMesService _mesService;
Timer yieldtimer;
private DateTime StartTime = DateTime.Now;
// Pressure collection
///
/// 压力采集信号控制CTS
///
private CancellationTokenSource[] _pressureCts = new CancellationTokenSource[10];
///
/// 压力采集超时CTS
///
private CancellationTokenSource[] _pressureTimeoutCts = new CancellationTokenSource[10];
///
/// 压力采集CTS
///
private CancellationTokenSource[] _pressureLinkedCts = new CancellationTokenSource[10];
///
/// 压力数据集合
///
private List<(DateTime Timestamp, float Value)>[] _pressureSamples = new List<(DateTime, float)>[10];
///
/// 采样间隔毫秒
///
private int _pressureSampleIntervalMs = 50; //采样间隔毫秒
///
/// 超时自动停止秒数
///
private int _pressureMaxDurationSeconds = 30; //超时自动停止秒数
DateTime[] StartCtqTime = new DateTime[3];//开始采集Ctq数据的时间
#endregion
#region 属性
private ObservableCollection _Renders;
///
/// 显示界面
///
public ObservableCollection Renders
{
get { return _Renders; }
set { SetProperty(ref _Renders, value); }
}
public BgCommunicate BgCommunicate { get; private set; }
public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
private ObservableCollection _Status = new ObservableCollection();
///
/// 状态栏集合
///
public ObservableCollection Status
{
get { return _Status; }
set { SetProperty(ref _Status, 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); }
}
private XYD_ScrewDriver _ScrewDriver;
public XYD_ScrewDriver ScrewDriver
{
get { return _ScrewDriver; }
set { SetProperty(ref _ScrewDriver, value); }
}
public Dictionary BackupObject { get; set; } = new Dictionary();
private double _CTtime;
///
/// ct
///
public double CTtime
{
get { return _CTtime; }
set { SetProperty(ref _CTtime, value); }
}
private ObservableCollection _dfc = new ObservableCollection();
///
/// CTQ数据集合
///
public ObservableCollection DFC
{
get { return _dfc; }
set { SetProperty(ref _dfc, value); }
}
#endregion
#region 命令
#endregion
#region 事件
#endregion
public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService,
IMesService mesService)
{
_regionManager = regionManager;
_eventAggregator = ea;
_container = container;
_configService = configService;
_robotService = robotService;
_cameraService = cameraService;
_feederService = feederService;
_plcService = plcService;
_calibrationService = calibrationService;
yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
Renders = new ObservableCollection();
_configService = configService;
_productService = productService;
_remoteCommandService = remoteCommandService;
_systemDatabaseService = systemDatabaseService;
_lightManagerService = lightManagerService;
_mesService = mesService;
InitPressure();
}
#region 初始化硬件模块
///
/// 初始化Feeder
///
///
public async Task<(bool IsSucceed, string Msg)> InitFeeders()
{
var feeders = _configService.GetAllFeeders();
StringBuilder sb = new StringBuilder();
foreach (var item in feeders)
{
_feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand);
var feeder = _feederService.GetFeeder(item.Id);
Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
try
{
feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged;
await feeder.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 (true, "");
}
else
{
return (false, sb.ToString());
}
}
///
/// 初始化机器人
///
///
public async Task<(bool IsSucceed, string Msg)> InitRobots()
{
var robots = _configService.GetAllRobots();
StringBuilder sb = new StringBuilder();
foreach (var item in robots)
{
_robotService.CreateRobot(item.Id, item);
try
{
Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
var robot = _robotService.GetRobot(item.Id);
robot.ReceivedEvent += Management_ReceivedEvent;
robot.SendEvent += Management_SendEvent;
robot.ConnectedEvent += Management_ConnectedEvent;
robot.DisconnectedEvent += Management_DisconnectedEvent;
await robot.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 (true, "");
}
else
{
return (false, sb.ToString());
}
}
///
/// 初始化PLC
///
///
public async Task<(bool IsSucceed, string Msg)> InitPlc()
{
var plcs = _configService.GetAllPlcs();
StringBuilder sb = new StringBuilder();
foreach (var item in plcs)
{
try
{
_plcService.CreatePlc(item.Id, item);
var plc = _plcService.GetPlc(item.Id);
Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
await plc.ConnectAsync(); //连接PLC
//SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug);
}
catch (Exception ex)
{
sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
}
}
try
{
await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
RegisterPlcMonitorAddress();
}
catch (Exception ex)
{
LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错", ex);
}
if (sb.Length == 0)
{
return (true, "");
}
else
{
return (false, sb.ToString());
}
}
///
/// 初始化相机
///
///
public async Task<(bool IsSucceed, string Msg)> InitCameras()
{
var cameras = _configService.GetAllCameras();
StringBuilder sb = new StringBuilder();
foreach (var item in cameras)
{
try
{
// Renders.Add(new ShowRender() { Id = item.Id, CameraName = item.CameraName });
_cameraService.CreateCamera(item.Id, item);
var camera = _cameraService.GetCamera(item.Id);
Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
try
{
if (await camera.OpenDeviceAsync())
{
SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
}
else
{
SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
}
}
catch (Exception ex)
{
SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm);
sb.AppendLine($"{item.CameraName}:{ex.Message}!");
}
}
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 (true, "");
}
else
{
return (false, sb.ToString());
}
}
///
/// 初始化光源控制器
///
///
public async Task<(bool IsSucceed, string Msg)> InitLightControllers()
{
var lightcontrollers = _configService.GetAllLightControllers();
StringBuilder sb = new StringBuilder();
foreach (var item in lightcontrollers)
{
try
{
var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item);
//var lightcontroller = _cameraService.GetLightController(item.Id);
//await lightcontroller.ConnectAsync(); //连接光源控制器
//SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug);
}
catch (Exception ex)
{
//sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]");
//SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm);
}
}
if (lightcontrollers.Count > 0)
{
var result = await _lightManagerService.ConnectAllAsync();
if (result)
{
return (true, "");
}
else
{
return (false, "Light Controller Connect Failed!");
}
}
return (true, "");
//if (sb.Length == 0)
//{
// return (true, "");
//}
//else
//{
// return (false, sb.ToString());
//}
}
///
/// 初始化后台TCP服务器通讯
///
public void InitBgTcp()
{
var config = _configService.GetBgTcp();
try
{
BgCommunicate = new BgCommunicate(config);
BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
BgCommunicate.SendEvent += BgCommunicate_SendEvent;
BgCommunicate.StartListening();
SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug);
}
catch (Exception ex)
{
SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error);
LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex);
}
}
///
/// 初始化后台ModbusTCP从站
///
public void InitModbusTcp()
{
try
{
var config = _configService.GetBgModbusTcp();
BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config);
if (config.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);
}
}
///
/// 初始化后台脚本
///
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);
}
}
///
/// 初始化电批
///
///
public async Task InitScrewDriver()
{
try
{
var screwDriverConfig = _configService.GetScrewDriverConfig();
ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port);
Status.Add(new StatusInfo(ScrewDriver.Id, "电批未连接", new SolidColorBrush(Colors.Red)));
ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent;
ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout;
screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout;
var isConnected = await ScrewDriver.ConnectAsync();
if (isConnected)
{
SendTaskMessage($"电批已连接", MessageLevel.Debug);
}
else
{
SendTaskMessage($"电批连接失败", MessageLevel.Error);
}
}
catch (Exception ex)
{
SendTaskMessage($"电批连接失败:{ex.Message}", MessageLevel.Alarm);
LogHelper.WriteLogError("连接电批时出错!", ex);
}
}
#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);
//从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info);
var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg =>
{
try
{
if (robot.ConnectType == TCPConnectType.Client)
{
if (robot.IsConnected)
{
await robot.SendAsync($"{msg}");
}
}
else
{
var cient = (ITcpSessionClient)arg2;
if (cient.Online)
{
await robot.SendAsync(cient, $"{msg}");
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("TCP发送数据时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
}
#endregion
#region 机器人&Feeder&相机连接状态事件
///
/// 机器人发送事件
///
///
///
///
///
private void Management_SendEvent(Guid robotid, object arg2, string arg3)
{
var r = _robotService.GetRobot(robotid);
SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
}
///
/// 机器人断开连接时
///
///
///
///
///
private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3)
{
if (RobotTCPCollection.ContainsKey(robotid))
{
RobotTCPCollection[robotid].Cancel();
}
var r = _configService.GetRobot(robotid);
if (r.ConnectType == TCPConnectType.Server)
{
ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
var robot = _robotService.GetRobot(robotid);
if (robot.TcpService.Count < 1)
{
var sta = Status.FirstOrDefault(s => s.ID == robotid);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{r.RobotName}{Lang.未连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
}
}
else
{
SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error);
var sta = Status.FirstOrDefault(s => s.ID == robotid);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{r.RobotName}{Lang.断开连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
}
}
///
/// 机器人连接成功时
///
///
///
///
///
private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3)
{
var r = _configService.GetRobot(robotid);
if (r.ConnectType == TCPConnectType.Server)
{
ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
var robot = _robotService.GetRobot(robotid);
if (robot.TcpService.Count > 0)
{
var sta = Status.FirstOrDefault(s => s.ID == robotid);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{r.RobotName}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
}
}
else
{
SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug);
var sta = Status.FirstOrDefault(s => s.ID == robotid);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{r.RobotName}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
}
}
///
/// Feeder连接状态改变时
///
///
///
private void Management_FeederConnectionStatusChanged(object sender, bool state)
{
IFeeder feeder = sender as IFeeder;
var sta = Status.FirstOrDefault(s => s.ID == feeder.Id);
if (state)
{
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{feeder.Name}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug);
}
else
{
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{feeder.Name}{Lang.未连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error);
}
}
///
/// 相机连接或者断开时
///
///
///
private void Management_CameraConnectChangedEvent(Guid id, bool state)
{
var sta = Status.FirstOrDefault(s => s.ID == id);
var camera = _configService.GetCamera(id);
if (sta != null && camera != null)
{
if (state)
{
App.Current.Dispatcher.Invoke(new Action(() =>
{
sta.Message = $"{camera.CameraName}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
}
else
{
App.Current.Dispatcher.Invoke(new Action(() =>
{
sta.Message = $"{camera.CameraName}{Lang.断开连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
}
}
}
///
/// PLC连接状态改变事件
///
///
///
private async void Management_PlcConnectChangedEvent(object sender, bool isconnected)
{
IPlc plc = sender as IPlc;
var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
if (plc.IsConnected)
{
SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug);
if (sta == null) return;
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{plc.Name}{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
try
{
await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
await WritePositionToPlcAsync();
}
catch (Exception ex)
{
LogHelper.WriteLogError("PLC连接成功时,写入系统参数和点位信息时出错!", ex);
}
}
else
{
SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error);
if (sta == null) return;
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"{plc.Name}{Lang.未连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
}
}
///
/// 电批连接状态改变时
///
///
///
private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state)
{
try
{
XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver;
if (state)
{
SendTaskMessage($"电批{Lang.已连接}!", MessageLevel.Debug);
var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"电批{Lang.已连接}";
sta.Background = new SolidColorBrush(Colors.Green);
}));
}
else
{
SendTaskMessage($"电批{Lang.未连接}!", MessageLevel.Error);
var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
App.Current.Dispatcher.Invoke(new
Action(() =>
{
sta.Message = $"电批{Lang.未连接}";
sta.Background = new SolidColorBrush(Colors.Red);
}));
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("电批连接状态改变时出错了", ex);
}
}
#endregion
#region 后台服务器通讯事件
private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg)
{
SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
}
public Dictionary BgCommunicateollection = new Dictionary();
private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg)
{
try
{
if (!BgCommunicateollection.ContainsKey(client.Id))
{
BgCommunicateollection.Add(client.Id, new CancellationTokenSource());
}
SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response =>
{
try
{
if (!client.Online)
{
return;
}
await BgCommunicate.SendAsync(client, $"{response}");
}
catch (Exception ex)
{
LogHelper.WriteLogError("后台TCP发送数据时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", ex);
SendTaskMessage(ex.Message, MessageLevel.Alarm);
}
}
private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e)
{
SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm);
if (BgCommunicateollection.ContainsKey(client.Id))
{
BgCommunicateollection[client.Id].Cancel();
}
}
private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e)
{
SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug);
}
#endregion
#region PLC
///
/// 将系统参数写入PLC
///
///
///
public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration)
{
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
Dictionary nodeValues = new Dictionary();
nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode);
nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum);
nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum);
nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum);
nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum);
nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum);
nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum);
nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum);
nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum);
nodeValues.Add(addressConfig.Out_ScrewTeachNum.Address, (Int16)systemConfiguration.ScrewTeachNum);
var res = await plc.WriteNodesAsync(nodeValues);
}
///
/// 注册需要监控的PLC地址
///
public void RegisterPlcMonitorAddress()
{
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
//PLC地址数组
List monitorNodeIds = new List()
{
addressConfig.In_DowmCameraExe.Address,
addressConfig.In_UpCameraPickExe.Address,
addressConfig.In_UpCameraPutExe.Address,
addressConfig.In_UPCameracheckExe.Address,
addressConfig.In_FixedCameraPickExe.Address,
addressConfig.In_FixedCameraPutExe.Address,
addressConfig.In_FixedCameracheckExe.Address,
addressConfig.In_RequestPosition.Address,
addressConfig.In_ScrewTeachExe.Address,
addressConfig.In_QrCodePhotoRequest.Address,
addressConfig.In_PickINC.Address,
};
for (int i = 0; i < 10; i++)
{
monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
}
for (int i = 0; i < 7; i++)
{
monitorNodeIds.Add(string.Format(addressConfig.In_WorkStart.Address, i));
monitorNodeIds.Add(string.Format(addressConfig.In_WorkDone.Address, i));
}
//订阅PLC地址变化
plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger);
}
///
/// 写入点位信息给PLC
///
///
public async Task WritePositionToPlcAsync()
{
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
var current = _productService.GetCurrentProduct();
if (current == null) return;
if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
{
foreach (var item in current.PickCameraPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
}
}
if (current.PickPoints != null && current.PickPoints.Count > 0)
{
foreach (var item in current.PickPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
}
}
if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
{
foreach (var item in current.SecPosCameraPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc);
}
}
if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0)
{
foreach (var item in current.ScrewCameraPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc);
}
}
if (current.ScrewPoints != null && current.ScrewPoints.Count > 0)
{
foreach (var item in current.ScrewPoints)
{
await item.WriteToPlcAddressEx(addressConfig.Out_Screw, plc);
}
await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)current.ScrewPoints.Count);
}
if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0)
{
foreach (var item in current.CheckCameraPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc);
}
}
if (current.RemovePoints != null && current.RemovePoints.Count > 0)
{
foreach (var item in current.RemovePoints)
{
await item.WriteToPlcAddress(addressConfig.Out_RemovePos, plc);
}
}
if (current.PressurePlacePoints != null && current.PressurePlacePoints.Count > 0)
{
foreach (var item in current.PressurePlacePoints)
{
await item.WriteToPlcAddress(addressConfig.Out_PressurePlace, plc);
}
}
if (current.IndependentCamerPoints != null && current.IndependentCamerPoints.Count > 0)
{
foreach (var item in current.IndependentCamerPoints)
{
await item.WriteToPlcAddress(addressConfig.Out_IndependentCamer, plc);
}
}
if (current.QrCodePoints != null && current.QrCodePoints.Count > 0)
{
foreach (var item in current.QrCodePoints)
{
await item.WriteToPlcAddress(addressConfig.Out_QrCodeCamera, plc);
}
}
}
public async Task WriteParameterToPlcAsync()
{
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
try
{
if (!File.Exists(FilePath.PressureParamterConfigPath))
{
List models = new List();
models.Add(new PressureModel());
models.Add(new PressureModel());
models.Add(new PressureModel());
FileHelper.WriteJsonFile(models, FilePath.PressureParamterConfigPath);
}
var PressureParam = FileHelper.ReadJsonFile>(FilePath.PressureParamterConfigPath);
await plc.WriteNodeAsync(addressConfig.PUT_Down_Time.Address, PressureParam[0].PressureTime);
await plc.WriteNodeAsync(addressConfig.PUT_WetOut_Num.Address, PressureParam[0].PressureNum);
await plc.WriteNodeAsync(addressConfig.PUT_WetOut_Num_max.Address, PressureParam[0].PressureNumMax);
await plc.WriteNodeAsync(addressConfig.Down_Time.Address, PressureParam[1].PressureTime);
await plc.WriteNodeAsync(addressConfig.Down_WetOut_Num.Address, PressureParam[1].PressureNum);
await plc.WriteNodeAsync(addressConfig.Down_WetOut_Num_max.Address, PressureParam[1].PressureNumMax);
}
catch (Exception)
{
}
}
///
/// 固定向上相机拍照结果
///
OpenCvSharp.Point3f[] DowmCameraResults = new OpenCvSharp.Point3f[10];
///
/// 移动向下相机拍照结果
///
OpenCvSharp.Point3f[] UpCameraPutResults = new OpenCvSharp.Point3f[10];
///
/// 取料移动相机拍照结果
///
OpenCvSharp.Point3f UpCameraPickResult = new OpenCvSharp.Point3f();
///
/// 最终组装位置
///
OpenCvSharp.Point3f PlaceActualCoord = new OpenCvSharp.Point3f();
///
/// 零件SN
///
string PartSN = "";
///
/// 产品SN
///
string[] ProductMainSN = new string[10];//产品主sn
///
/// 工单信息
///
string[] wo = new string[10];
///
/// 复检结果
///
string gapString = "";
///
/// 二次定位相机的工具坐标
///
ToolCoord DownTool = new ToolCoord();
double _FixedUpCameraAngle = 0;
double _MoveCameraAngle = 0;
bool _LastDowmCameraExe = false;
bool _LastScrewTeachExe = false;
bool _LastUpCameraPickExe = false;
bool _LastUpCameraPutExe = false;
bool _LastUPCameracheckExe = false;
bool _LastFixedCameraPickExe = false;
bool _LastFixedCameraPutExe = false;
bool _LastFixedCameracheckExe = false;
Int16[] _LastWorkStart = new Int16[7];
Int16 _LastQrCodePhotoRequest = 0;
Int16[] _LastWorkDone = new Int16[7];
Int16 _LastRequestPosition = 0;
Int16 _LastPickINC = 0;
Int16[] _LastMesCheck = new Int16[10];
DateTime[] _LastMesCheckTime = new DateTime[10];
double[] currentPressure = new double[10];//当前压力
///
/// PLC命令触发时
///
///
private async void PlcCommandTrigger((string key, string nodeId, object value) tuple)
{
try
{
if (tuple.key != "AutoSensor")
{
return;
}
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
// 获取当前产品
var currentProduct = _productService.GetCurrentProduct();
if (currentProduct == null)
{
return;
}
//获取产品编码
_productService.CurrentProductCode = plc.ReadNode(string.Format(addressConfig.In_Code.Address, 0));
//如果产品编码为空,则以当前的时间戳作为编码
if (string.IsNullOrEmpty(_productService.CurrentProductCode))
{
_productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
}
bool isDryMode = plc.ReadNode(addressConfig.In_DryMode.Address);
// 触发下相机拍照--下相机拍屏幕,预定位
if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastDowmCameraExe != state)
{
_LastDowmCameraExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发下相机拍照...", MessageLevel.Debug);
//相机的编号
Int16 cameraIndex = plc.ReadNode(addressConfig.In_DowmCameraNum.Address);
SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
// 获取机器人当前坐标
var robot = _robotService.GetAllRobots().FirstOrDefault();
if (robot == null)
{
SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
var currentPosition = robot.GetRobotPos();
//如果下相机拍照的次数是1,则判断用时拍照的相机是几个
int downCameraNum = _configService.GetSystemConfiguration().DowmCameraNum;
if (downCameraNum == 1)
{
//如果下相机2的流程id为空,则表示只有一个下相机
if (currentProduct.FixedUpCamera2ProcedureId == Guid.Empty)
{
//获取固定向上相机1的流程
var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
if (process == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, null);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
if (visionResult.IsSucceed)
{
//float toolX = (float)(visionResult.X - currentPosition.X);
//float toolY = (float)(visionResult.Y - currentPosition.Y);
DowmCameraResults[0] = new OpenCvSharp.Point3f((float)visionResult.X, (float)visionResult.Y, (float)visionResult.U);
//DownTool = new PointF(toolX, toolY);
//以LCD的的上边中心创建工具坐标
DownTool.ComputeTool(currentPosition.X, currentPosition.Y, currentPosition.U, DowmCameraResults[0].X, DowmCameraResults[0].Y);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
else
{
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
}
else
{
//获取固定向上相机1的流程
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
if (process1 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
//获取固定向上相机2的流程
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera2ProcedureId);
if (process2 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera2ProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, null, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, null, _cts.Token, 2, null);
var visionResults = await Task.WhenAll(task1, task2);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed)
{
float toolX = (float)(visionResults[0].X + visionResults[1].X) / 2;
float toolY = (float)(visionResults[0].Y + visionResults[1].Y) / 2;
_FixedUpCameraAngle = Common.CalculateAngleBetweenPointsDegrees(new PointF((float)visionResults[0].X, (float)visionResults[0].Y), new PointF((float)visionResults[1].X, (float)visionResults[1].Y));
SendTaskMessage($"屏幕中心点位:{toolX:F3},{toolY:F4},{_FixedUpCameraAngle:F4}", MessageLevel.Info);
SendTaskMessage($"当前机器人点位:{currentPosition.X:F3},{currentPosition.Y:F4},{currentPosition.U:F4}", MessageLevel.Info);
DowmCameraResults[0] = new OpenCvSharp.Point3f(toolX, toolY, (float)_FixedUpCameraAngle);
//DownTool = new PointF(toolX, toolY);
//以LCD的的上边中心创建工具坐标
DownTool.ComputeTool(currentPosition.X, currentPosition.Y, currentPosition.U, DowmCameraResults[0].X, DowmCameraResults[0].Y);
SendTaskMessage($"屏幕Tool:{DownTool.X:F3},{DownTool.Y:F4}", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
}
}
else if (downCameraNum == 2)
{
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
//如果下相机2的流程id为空,则表示只有一个下相机
if (currentProduct.FixedUpCamera2ProcedureId == Guid.Empty)
{
//获取固定向上相机1的流程
//var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
//if (process == null)
//{
// SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
// await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
// return;
//}
//// 执行视觉任务
//var _cts = new CancellationTokenSource();
//var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token);
//if (visionResult.IsSucceed)
//{
// float toolX = (float)(visionResult.X - currentPosition.X);
// float toolY = (float)(visionResult.Y - currentPosition.Y);
// DowmCameraResults[cameraIndex] = new PointF(toolX, toolX);
// if (cameraIndex == downCameraNum)
// {
// //求取多个DowmCameraResults的中心点
// DownTool = new PointF(toolX, toolX);
// }
// await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
// return;
//}
//else
//{
// await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
// return;
//}
//暂时没有应用场景,不支持
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
else
{
//获取固定向上相机1的流程
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
if (process1 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
//获取固定向上相机2的流程
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera2ProcedureId);
if (process2 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera2ProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 2, null);
var visionResults = await Task.WhenAll(task1, task2);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed)
{
float toolX = (float)(visionResults[0].X + visionResults[1].X) / 2;
float toolY = (float)(visionResults[0].Y + visionResults[1].Y) / 2;
_FixedUpCameraAngle = Common.CalculateAngleBetweenPointsDegrees(new PointF((float)visionResults[0].X, (float)visionResults[0].Y), new PointF((float)visionResults[1].X, (float)visionResults[1].Y));
DowmCameraResults[cameraIndex] = new OpenCvSharp.Point3f(toolX, toolY, (float)_FixedUpCameraAngle);
//DownTool = new PointF(toolX, toolY);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
}
}
else
{
//暂时没有应用场景,不支持
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
}
else
{
SendTaskMessage($"触发下相机拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)0);
}
}
}
// 触发下相机拍照披头
if (addressConfig.In_ScrewTeachExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastScrewTeachExe != state)
{
_LastScrewTeachExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发下相机拍照...", MessageLevel.Debug);
//相机的编号
Int16 cameraIndex = plc.ReadNode(addressConfig.In_DowmCameraNum.Address);
SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
// 获取流程
//var process = _productService.GetCurrentProductProcedureModelById(currentProduct.FixedUpCamera1ProcedureId);
//if (process == null)
//{
// SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.FixedUpCamera1ProcedureId}", MessageLevel.Alarm);
// await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
// return;
//}
//// 获取机器人当前坐标
//var robot = _robotService.GetAllRobots().FirstOrDefault();
//if (robot == null)
//{
// SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
// await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
// return;
//}
//var currentPosition = robot.GetRobotPos();
//// 执行视觉任务
//var _cts = new CancellationTokenSource();
//var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token);
//if (visionResult.IsSucceed)
//{
// //披头偏差
// float offsetX = (float)(visionResult.X - currentPosition.X);
// float offsetY = (float)(visionResult.Y - currentPosition.Y);
// DowmCameraResults[cameraIndex] = new PointF(offsetX, offsetY);
// await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)1);
// return;
//}
//else
//{
// await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)2);
// return;
//}
}
else
{
SendTaskMessage($"触发下相机拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_ScrewTeachOk.Address, (Int16)0);
}
}
}
// 触发上相机取料拍照
else if (addressConfig.In_UpCameraPickExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastUpCameraPickExe != state)
{
_LastUpCameraPickExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发上相机取料拍照...", MessageLevel.Debug);
//相机的编号
Int16 cameraIndex = plc.ReadNode(addressConfig.In_UpCameraPickNum.Address);
SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
// 获取机器人当前坐标
var robot = _robotService.GetAllRobots().FirstOrDefault();
if (robot == null)
{
SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
var currentPosition = robot.GetRobotPos();
//如果上相机2的流程id为空,则表示只有一个下相机
if (currentProduct.MoveDownCamer2PickPhotoProcedureId == Guid.Empty)
{
//获取移动向下相机1的流程
var process = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamer1PickPhotoProcedureId);
if (process == null)
{
SendTaskMessage($"移动向下相机1视觉流程,流程ID:{currentProduct.MoveDownCamer1PickPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, null);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
return;
}
if (visionResult.IsSucceed)
{
currentProduct.PickPoints[0].X_Position = (float)visionResult.X;
currentProduct.PickPoints[0].Y_Position = (float)visionResult.Y;
//currentProduct.PickPoints[0].U_Position += (float)visionResult.U;
await currentProduct.ScrewPoints[0].WriteToPlcAddress(addressConfig.Out_Pick, plc);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
}
else
{
//获取固定向上相机1的流程
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamer1PickPhotoProcedureId);
if (process1 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.MoveDownCamer1PickPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
//获取固定向上相机2的流程
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamer2PickPhotoProcedureId);
if (process2 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.MoveDownCamer2PickPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 2, null);
var visionResults = await Task.WhenAll(task1, task2);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed)
{
float tool1X = (float)(visionResults[0].X - visionResults[0].X);
float tool1Y = (float)(visionResults[0].Y - visionResults[0].Y);
float tool2X = (float)(visionResults[1].X - visionResults[1].X);
float tool2Y = (float)(visionResults[1].Y - visionResults[1].Y);
float toolX = (tool1X + tool2X) / 2;
float toolY = (tool1Y + tool2Y) / 2;
//计算两个点的线角度
currentProduct.PickPoints[0].X_Position = (float)toolX;
currentProduct.PickPoints[0].Y_Position = (float)toolY;
//currentProduct.PickPoints[0].U_Position += (float)visionResult.U;
await currentProduct.ScrewPoints[0].WriteToPlcAddress(addressConfig.Out_Pick, plc);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)2);
return;
}
}
}
else
{
SendTaskMessage($"触发上相机取料拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPickStatus.Address, (Int16)0);
}
}
}
// 上相机锁附/组装拍照
else if (addressConfig.In_UpCameraPutExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastUpCameraPutExe != state)
{
_LastUpCameraPutExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发上相机锁附/组装拍照...", MessageLevel.Debug);
//相机的编号
Int16 cameraIndex = plc.ReadNode(addressConfig.In_UpCameraPutNum.Address);
SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
// 获取机器人当前坐标
var robot = _robotService.GetAllRobots().FirstOrDefault();
if (robot == null)
{
SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
var currentPosition = robot.GetRobotPos();
//如果上相机2的流程id为空,则表示只有一个上相机
if (currentProduct.MoveDownCamera2LockPhotoProcedureId == Guid.Empty)
{
//获取移动向下相机1的流程
var process = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamera1LockPhotoProcedureId);
if (process == null)
{
SendTaskMessage($"移动向下相机1视觉流程,流程ID:{currentProduct.MoveDownCamera1LockPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, cameraIndex, null);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
return;
}
if (visionResult.IsSucceed)
{
UpCameraPutResults[cameraIndex] = new OpenCvSharp.Point3f((float)visionResult.X, (float)visionResult.Y, (float)visionResult.U);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
}
else
{
//获取移动向下相机1的流程
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamera1LockPhotoProcedureId);
if (process1 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.MoveDownCamera1LockPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
//获取移动向下相机2的流程
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.MoveDownCamera2LockPhotoProcedureId);
if (process2 == null)
{
SendTaskMessage($"固定向上相机1视觉流程,流程ID:{currentProduct.MoveDownCamera2LockPhotoProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, new double[] { currentPosition.X, currentPosition.Y, currentPosition.U }, _cts.Token, 2, null);
var visionResults = await Task.WhenAll(task1, task2);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed)
{
float centerX = (float)(visionResults[0].X + visionResults[1].X) / 2;
float centerY = (float)(visionResults[0].Y + visionResults[1].Y) / 2;
_MoveCameraAngle = Common.CalculateAngleBetweenPointsDegrees(new PointF((float)visionResults[0].X, (float)visionResults[0].Y), new PointF((float)visionResults[1].X, (float)visionResults[1].Y));
UpCameraPutResults[cameraIndex] = new OpenCvSharp.Point3f(centerX, centerY, (float)_MoveCameraAngle);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)1);
return;
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)2);
return;
}
}
}
else
{
SendTaskMessage($"触发上相机锁附/组装拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UpCameraPutStatus.Address, (Int16)0);
}
}
}
// 上相机检测拍照
else if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastUPCameracheckExe != state)
{
_LastUPCameracheckExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发上相机检测拍照...", MessageLevel.Debug);
//相机的编号
Int16 cameraIndex = plc.ReadNode(addressConfig.In_UPCameracheckNum.Address);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
return;
}
//视觉流程ID
Guid procedureId = Guid.Empty;
//获取锁付拍照的点位
var pos = currentProduct.CheckCameraPoints.FirstOrDefault(p => p.Number == cameraIndex);
if (pos != null)
{
procedureId = pos.VisionProcessID;
}
// 获取流程
var process = _productService.GetCurrentProductProcedureModelById(procedureId);
if (process == null)
{
SendTaskMessage(string.Format("未找到点位:{0}的视觉流程:{1}", cameraIndex, procedureId), MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
return;
}
// 执行视觉任务
var _cts = new CancellationTokenSource();
var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(process, null, null, _cts.Token, cameraIndex, null);
if (visionResult.IsSucceed)
{
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
SendTaskMessage($"点位{cameraIndex}检测OK", MessageLevel.Debug);
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
SendTaskMessage($"点位{cameraIndex}检测NG", MessageLevel.Error);
}
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
}
else
{
SendTaskMessage($"触发上相机检测拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0);
}
}
}
// 固定相机取料拍照--屏幕拍照,取上边沿中心(防呆作用)
else if (addressConfig.In_FixedCameraPickExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastFixedCameraPickExe != state)
{
_LastFixedCameraPickExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发固定相机取料拍照...", MessageLevel.Debug);
//相机的编号
//Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameraPickNum.Address);
if (currentProduct.IndependentCamer1AuxProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer2AuxProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer3AuxProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer4AuxProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
//获取四个独立相机的流程id
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer1AuxProcedureId);
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer2AuxProcedureId);
var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3AuxProcedureId);
var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4AuxProcedureId);
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, null, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, null, _cts.Token, 2, null);
var task3 = _remoteCommandService.ExecutePhotoGetSinglePoint(process3, null, null, _cts.Token, 3, null);
var task4 = _remoteCommandService.ExecutePhotoGetSinglePoint(process4, null, null, _cts.Token, 4, null);
var visionResults = await Task.WhenAll(task1, task2, task3, task4);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
{
Vector p1 = Vector.Build.Dense(new double[] { visionResults[0].X, visionResults[0].Y });
Vector p2 = Vector.Build.Dense(new double[] { visionResults[1].X, visionResults[1].Y });
Vector p3 = Vector.Build.Dense(new double[] { visionResults[2].X, visionResults[2].Y });
Vector p4 = Vector.Build.Dense(new double[] { visionResults[3].X, visionResults[3].Y });
//var center = RectangleCenterCalculator.CalculateByDirectMethod(new List> { p1, p2, p3, p4 });
var center = RectangleCenterCalculator.CalculateOptimalCenter(new List> { p1, p2, p3, p4 });//0215修改,不考虑点顺序
//UpCameraPutResults[1].X = (float)center.Center[0];
//UpCameraPutResults[1].Y = (float)center.Center[1];
//UpCameraPutResults[1].Z = (float)center.MajorAxisAngle;
UpCameraPutResults[1].X = ((float)center.TopLeft[0] + (float)center.TopRight[0]) / 2;
UpCameraPutResults[1].Y = ((float)center.TopLeft[1] + (float)center.TopRight[1]) / 2;
UpCameraPutResults[1].Z = (float)center.MajorAxisAngle;
SendTaskMessage($"LCD拍照结果:X={UpCameraPutResults[1].X},Y={UpCameraPutResults[1].Y},Angle={UpCameraPutResults[1].Z}", MessageLevel.Info);
var dist1 = RectangleCenterCalculator.Distance(center.TopLeft, center.TopRight);//长1
var dist2 = RectangleCenterCalculator.Distance(center.TopRight, center.BottomRight);//宽1
var dist3 = RectangleCenterCalculator.Distance(center.BottomLeft, center.BottomRight);//长2
var dist4 = RectangleCenterCalculator.Distance(center.TopLeft, center.BottomLeft);//宽2
LogHelper.WriteLogInfo($"dist1={dist1};dist2={dist2};dist3={dist3};dist4={dist4};");
if (currentProduct.GlobalParamListCollection.Count >= 4)
{
var param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 2);
if (param != null)//长
{
var length = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
if (!(((length + limtDown) <= dist1) && (dist1 <= (length + LimtUp)) && (((length + limtDown) <= dist3) && (dist3 <= (length + LimtUp)))))
{
SendTaskMessage($"屏幕长度超范围:长1={dist1},长2={dist3},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"屏幕长度防呆:长1={dist1},长2={dist3},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Info);
}
param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 3);
if (param != null)//宽
{
var length = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
if (!(((length + limtDown) <= dist2) && (dist2 <= (length + LimtUp)) && (((length + limtDown) <= dist4) && (dist4 <= (length + LimtUp)))))
{
SendTaskMessage($"屏幕宽度超范围:宽1={dist2},宽2={dist4},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"屏幕宽度防呆:宽1={dist2},宽2={dist4},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Info);
}
if (currentProduct.GlobalParamListCollection.Count >= 7)
{
param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 4);
if (param != null)//X防呆
{
var Limt_val = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
var dist = UpCameraPutResults[1].X - UpCameraPutResults[0].X;
if (!(((Limt_val + limtDown) <= dist) && (dist <= (Limt_val + LimtUp))))
{
SendTaskMessage($"贴合X防呆超限:X实际差值={dist},X允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"贴合X防呆:X实际差值={dist},X允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
}
param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 5);
if (param != null)//Y防呆
{
var Limt_val = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
var dist = UpCameraPutResults[1].Y - UpCameraPutResults[0].Y;
if (!(((Limt_val + limtDown) <= dist) && (dist <= (Limt_val + LimtUp))))
{
SendTaskMessage($"贴合Y防呆超限:Y实际差值={dist},Y允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"贴合Y防呆:Y实际差值={dist},Y允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
}
param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 6);
if (param != null)//U防呆
{
var Limt_val = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
var dist = UpCameraPutResults[1].Z - UpCameraPutResults[0].Z;
if (!(((Limt_val + limtDown) <= dist) && (dist <= (Limt_val + LimtUp))))
{
SendTaskMessage($"贴合U防呆超限:U实际差值={dist},X允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"贴合U防呆:U实际差值={dist},X允许差值={Limt_val},下限={limtDown},上限={LimtUp}", MessageLevel.Info);
}
}
}
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
return;
}
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
}
else
{
SendTaskMessage($"触发固定相机取料拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
}
}
}
// 固定相机锁附/组装拍照--外壳拍照
else if (addressConfig.In_FixedCameraPutExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastFixedCameraPutExe != state)
{
_LastFixedCameraPutExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发固定相机锁附/组装拍照...", MessageLevel.Debug);
//相机的编号
//Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameraPutNum.Address);
if (currentProduct.IndependentCamer1ProductProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer2ProductProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer3ProductProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer4ProductProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
//获取四个独立相机的流程id
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer1ProductProcedureId);
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer2ProductProcedureId);
var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3ProductProcedureId);
var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4ProductProcedureId);
// 执行视觉任务
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetSinglePoint(process1, null, null, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetSinglePoint(process2, null, null, _cts.Token, 2, null);
var task3 = _remoteCommandService.ExecutePhotoGetSinglePoint(process3, null, null, _cts.Token, 3, null);
var task4 = _remoteCommandService.ExecutePhotoGetSinglePoint(process4, null, null, _cts.Token, 4, null);
var visionResults = await Task.WhenAll(task1, task2, task3, task4);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
{
Vector p1 = Vector.Build.Dense(new double[] { visionResults[0].X, visionResults[0].Y });
Vector p2 = Vector.Build.Dense(new double[] { visionResults[1].X, visionResults[1].Y });
Vector p3 = Vector.Build.Dense(new double[] { visionResults[2].X, visionResults[2].Y });
Vector p4 = Vector.Build.Dense(new double[] { visionResults[3].X, visionResults[3].Y });
//var center = RectangleCenterCalculator.CalculateByDirectMethod(new List> { p1, p2, p3, p4 });
var center = RectangleCenterCalculator.CalculateOptimalCenter(new List> { p1, p2, p3, p4 });//0215修改,不考虑点顺序
//UpCameraPutResults[0].X = (float)center.Center[0];
//UpCameraPutResults[0].Y = (float)center.Center[1];
UpCameraPutResults[0].X = ((float)center.TopLeft[0] + (float)center.TopRight[0]) / 2;
UpCameraPutResults[0].Y = ((float)center.TopLeft[1] + (float)center.TopRight[1]) / 2;
UpCameraPutResults[0].Z = (float)center.MajorAxisAngle;
SendTaskMessage($"产品拍照结果:X={UpCameraPutResults[0].X},Y={UpCameraPutResults[0].Y},Angle={UpCameraPutResults[0].Z}", MessageLevel.Info);
var dist1 = RectangleCenterCalculator.Distance(center.TopLeft, center.TopRight);//长1
var dist2 = RectangleCenterCalculator.Distance(center.TopRight, center.BottomRight);//宽1
var dist3 = RectangleCenterCalculator.Distance(center.BottomLeft, center.BottomRight);//长2
var dist4 = RectangleCenterCalculator.Distance(center.TopLeft, center.BottomLeft);//宽2
LogHelper.WriteLogInfo($"dist1={dist1};dist2={dist2};dist3={dist3};dist4={dist4};");
if (currentProduct.GlobalParamListCollection.Count >= 4)
{
var param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 0);
if (param != null)//长
{
var length = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
if (!(((length + limtDown) <= dist1) && (dist1 <= (length + LimtUp)) && (((length + limtDown) <= dist3) && (dist3 <= (length + LimtUp)))))
{
SendTaskMessage($"外壳长度超范围:长1={dist1},长2={dist3},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"外壳长度防呆:长1={dist1},长2={dist3},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Info);
}
param = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Number == 1);
if (param != null)//宽
{
var length = Double.Parse(param.Param1);
var limtDown = Double.Parse(param.Param2);
var LimtUp = Double.Parse(param.Param3);
if (!(((length + limtDown) <= dist2) && (dist2 <= (length + LimtUp)) && (((length + limtDown) <= dist4) && (dist4 <= (length + LimtUp)))))
{
SendTaskMessage($"外壳宽度超范围:宽1={dist2},宽2={dist4},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
SendTaskMessage($"外壳宽度防呆:宽1={dist2},宽2={dist4},para1={length},para2={limtDown},para3={LimtUp}", MessageLevel.Info);
}
}
}
else
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)2);
return;
}
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)1);
}
else
{
SendTaskMessage($"触发固定相机锁附/组装拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPutStatus.Address, (Int16)0);
}
}
}
// 固定相机检测拍照
else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId))
{
if (tuple.value is bool state)
{
if (_LastFixedCameracheckExe != state)
{
_LastFixedCameracheckExe = state;
}
else
{
return;
}
if (state)
{
SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
//相机的编号
//Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameracheckNum.Address);
if (currentProduct.IndependentCamer1CheckProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer2CheckProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer3CheckProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
return;
}
if (currentProduct.IndependentCamer4CheckProcedureId == Guid.Empty)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
return;
}
//获取四个独立相机的流程id
var process1 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer1CheckProcedureId);
var process2 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer2CheckProcedureId);
var process3 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer3CheckProcedureId);
var process4 = _productService.GetCurrentProductProcedureModelById(currentProduct.IndependentCamer4CheckProcedureId);
// 执行视觉任务(复检结果gap)
var _cts = new CancellationTokenSource();
var task1 = _remoteCommandService.ExecutePhotoGetDistance(process1, null, null, _cts.Token, 1, null);
var task2 = _remoteCommandService.ExecutePhotoGetDistance(process2, null, null, _cts.Token, 2, null);
var task3 = _remoteCommandService.ExecutePhotoGetDistance(process3, null, null, _cts.Token, 3, null);
var task4 = _remoteCommandService.ExecutePhotoGetDistance(process4, null, null, _cts.Token, 4, null);
var visionResults = await Task.WhenAll(task1, task2, task3, task4);
if (isDryMode)
{
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
return;
}
if (visionResults[0].IsSucceed && visionResults[1].IsSucceed && visionResults[2].IsSucceed && visionResults[3].IsSucceed)
{
SendTaskMessage($"固定相机检测OK", MessageLevel.Debug);
SendTaskMessage($"流程1结果:{visionResults[0].distance}", MessageLevel.Debug);
SendTaskMessage($"流程2结果:{visionResults[1].distance}", MessageLevel.Debug);
SendTaskMessage($"流程3结果:{visionResults[2].distance}", MessageLevel.Debug);
SendTaskMessage($"流程4结果:{visionResults[3].distance}", MessageLevel.Debug);
gapString = $"{visionResults[0].distance.Split(',')[1]},{visionResults[1].distance.Split(',')[1]},{visionResults[2].distance.Split(',')[1]},{visionResults[3].distance.Split(',')[1]}";
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)1);
return;
}
else
{
string res1="", res2 = "", res3 = "", res4 = "";
if(visionResults[0].IsSucceed)
{
res1 = visionResults[0].distance.Split(',')[1];
}
if (visionResults[1].IsSucceed)
{
res2 = visionResults[1].distance.Split(',')[1];
}
if (visionResults[2].IsSucceed)
{
res3 = visionResults[2].distance.Split(',')[1];
}
if (visionResults[3].IsSucceed)
{
res4 = visionResults[3].distance.Split(',')[1];
}
SendTaskMessage($"固定相机检测NG", MessageLevel.Error);
gapString = $"{res1},{res2},{res3},{res4}";
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
return;
}
}
else
{
SendTaskMessage($"触发固定相机检测拍照信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)0);
}
}
}
// 多相机坐标合并
else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastRequestPosition != state)
{
_LastRequestPosition = state;
}
else
{
return;
}
if (state == 1)
{
SendTaskMessage($"收到多相机坐标合并请求,开始合并...", MessageLevel.Debug);
if (isDryMode)//空跑模式
{
var point1 = currentProduct.ScrewPoints[0].Clone();
SendTaskMessage($"空跑模式点:1,{point1.X_Position:F3},{point1.Y_Position:F4},{point1.U_Position:F4}", MessageLevel.Info);
await point1.WriteToPlcAddress(addressConfig.Out_Screw, plc);
await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)1);
await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
return;
}
// 获取机器人当前坐标
var robot = _robotService.GetAllRobots().FirstOrDefault();
if (robot == null)
{
SendTaskMessage($"未找到机器人,无法执行上相机锁附/组装拍照视觉任务", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
var currentPosition = robot.GetRobotPos();
//已经通过下相机拍屏幕两角获取--DownTool
//以LCD的中线创建工具坐标
//ToolCoord toolCoord = new ToolCoord();
//toolCoord.ComputeTool(currentPosition.X, currentPosition.Y, currentPosition.U, UpCameraPutResults[1].X, UpCameraPutResults[1].Y);
//添加新的补偿算法--20260213
double offset_X = 0, offset_Y = 0, offset_U = 0;
var current = _productService.GetCurrentProduct();
if (current.ScrewPoints == null || current.ScrewPoints.Count <= 0)
{
SendTaskMessage($"未找到任务贴合补偿参数", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_DownCameraStatus.Address, (Int16)2);
return;
}
offset_X = current.ScrewPoints[0].X_Offset;
offset_Y = current.ScrewPoints[0].Y_Offset;
offset_U = current.ScrewPoints[0].U_Offset;
SendTaskMessage($"放料补偿:X={offset_X},Y={offset_Y},U={offset_U}", MessageLevel.Info);
//利用补偿偏差算出,补偿后的壳体中心,p_new
ToolCoord toolCoord2 = new ToolCoord();
toolCoord2.SetTool(offset_X, offset_Y);
var p_new_Vector = Vector.Build.Dense(new double[] { UpCameraPutResults[0].X, UpCameraPutResults[0].Y });
var p_new = toolCoord2.GetToolnCoord(p_new_Vector, UpCameraPutResults[0].Z);
SendTaskMessage($"放料原点:1,{UpCameraPutResults[0].X:F3},{UpCameraPutResults[0].Y:F4},{UpCameraPutResults[0].Z:F4}", MessageLevel.Info);
SendTaskMessage($"放料补偿点:2,{p_new[0]:F3},{p_new[1]:F4},{UpCameraPutResults[0].Z:F4}", MessageLevel.Info);
//计算放料角度--带入下相机的角度
double angle = currentPosition.U - DowmCameraResults[0].Z + UpCameraPutResults[0].Z + offset_U;
//将产品的中心点坐标转换为Tool0下的坐标
var point = currentProduct.ScrewPoints[0].Clone();
//var pn = Vector.Build.Dense(new double[] { UpCameraPutResults[0].X, UpCameraPutResults[0].Y });
var pn = p_new;
//var p0 = toolCoord.GetTool0Coord(pn, angle);
var p0 = DownTool.GetTool0Coord(pn, angle);//下相机拍照tool,动态Tool
point.X_Position = (float)p0[0];
point.Y_Position = (float)p0[1];
point.U_Position = (float)angle;
PlaceActualCoord = new OpenCvSharp.Point3f(point.X_Position, point.Y_Position, point.U_Position);
//SendTaskMessage($"点:1,{point.X_Position:F3},{point.Y_Position:F4},{point.U_Position:F4}", MessageLevel.Info);
SendTaskMessage($"目标点:3,{point.X_Position:F3},{point.Y_Position:F4},{point.U_Position:F4}", MessageLevel.Info);
await point.WriteToPlcAddressEx2(addressConfig.Out_Screw, plc);//补偿参数提前代入计算,直接发最终点位
await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)1);
await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
//原计算方法--20260213
////计算放料角度
//double angle = currentPosition.U - UpCameraPutResults[1].Z + UpCameraPutResults[0].Z;
////将产品的中心点坐标转换为Tool0下的坐标
//var point = currentProduct.ScrewPoints[0].Clone();
//var pn = Vector.Build.Dense(new double[] { UpCameraPutResults[0].X, UpCameraPutResults[0].Y });
//var p0 = toolCoord.GetTool0Coord(pn, angle);
//point.X_Position = (float)p0[0];
//point.Y_Position = (float)p0[1];
//point.U_Position = (float)angle;
//PlaceActualCoord = new OpenCvSharp.Point3f(point.X_Position, point.Y_Position, point.U_Position);
//SendTaskMessage($"点:1,{point.X_Position:F3},{point.Y_Position:F4},{point.U_Position:F4}", MessageLevel.Info);
//await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
//await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)1);
//await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
}
else
{
SendTaskMessage($"多相机坐标合并请求已结束或被取消,state={state}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0);
}
}
}
// 螺丝供料器螺丝递减
else if (addressConfig.In_PickINC.Address.Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastPickINC != state)
{
_LastPickINC = state;
}
else
{
return;
}
if (state != 0)
{
SendTaskMessage($"螺丝供料器...", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.In_PickINC.Address, (Int16)0);
}
}
}
// PLC请求二维码拍照
else if (addressConfig.In_QrCodePhotoRequest.Address.Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastQrCodePhotoRequest != state)
{
_LastQrCodePhotoRequest = state;
}
else
{
return;
}
if (state == 1)
{
//相机的编号
//Int16 cameraIndex = plc.ReadNode(addressConfig.In_QrCodeCamera_ScanNum.Address);
//SendTaskMessage(string.Format("扫码编号", cameraIndex), MessageLevel.Info);
Guid qrCodeProcedureId = currentProduct.QrCodeProcedureId;
//视觉流程ID
var qrCodeProcess = _productService.GetCurrentProductProcedureModelById(qrCodeProcedureId);
if (qrCodeProcess == null)
{
SendTaskMessage($"未找到二维码视觉流程,流程ID: {qrCodeProcedureId}", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
return;
}
SendTaskMessage($"开始执行二维码扫码视觉流程", MessageLevel.Debug);
var _cts = new CancellationTokenSource();
await _remoteCommandService.SetLightBeforePhoto(qrCodeProcess);
var qrCodeResult = _remoteCommandService.ExecutePhoto(1, qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
if (qrCodeResult && outputCollection.Contains("QR"))
{
PartSN = outputCollection["QR"].Value as string;
if (!string.IsNullOrEmpty(PartSN))
{
await plc.WriteNodeAsync(addressConfig.Out_PartCode.Address, PartSN);
SendTaskMessage($"二维码扫码成功:{PartSN}", MessageLevel.Info);
await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
}
else
{
PartSN = "";
SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
return;
}
}
else
{
PartSN = "";
SendTaskMessage("二维码扫码失败", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
return;
}
}
else
{
SendTaskMessage("二维码拍照点位发送信号已关闭", MessageLevel.Alarm);
await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)0);
}
}
}
else
{
// 过站检查
for (int i = 0; i < 10; i++)
{
if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastMesCheck[i] != state)
{
_LastMesCheck[i] = state;
}
else
{
return;
}
var code = plc.ReadNode(string.Format(addressConfig.In_Code.Address, i));
string comp = PartSN;
SendTaskMessage($"产品sn:{code},辅料码:{comp}", MessageLevel.Info);
//询问mes
if (state == 1)
{
// 这里缺少从MES获取产品配方的内容,需要补充
_LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(i, code, 2)).Now;
//获取当前工位的配置
var stationConfig = _configService.GetDeviceInfo(i);
if (stationConfig.EnableDoubleMes)
{
SendTaskMessage($"收到{i}:{stationConfig.DeviceName}过站检查请求(当站是否生产)(当前需要双MES验证)...", MessageLevel.Debug);
LogHelper.WriteLogMes($"【mes开始QUERY】");
SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
(bool isSuccess, string response) = await _mesService.StationGetExAsync(i, code, "", 2);//询问mes
if (isSuccess)
{
LogHelper.WriteLogMes($"询问mes成功");
SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
string ProductMainSN_Temp = "";
if (response != "MES功能未启用!")
{
string[] item = response.Split('\n');
//获取过度件sn
string snItem = item.FirstOrDefault(f => f.Contains("sn="));
if (snItem != null)
{
ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
}
}
(bool isSuccess2, string response2) = await _mesService.StationGetAsync(i, ProductMainSN_Temp, "", 2);//询问mes
if (isSuccess2)
{
LogHelper.WriteLogMes($"第二次询问mes成功");
SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
if (response2 != "MES功能未启用!")
{
string[] item = response2.Split('\n');
//获取产品主sn和wo用于后续上传数据使用
string snItem = item.FirstOrDefault(f => f.Contains("sn="));
if (snItem != null)
{
ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
if (i == 0)
{
_productService.CurrentProductCode = ProductMainSN[i];
}
SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
}
string woItem = item.FirstOrDefault(f => f.Contains("wo="));
if (woItem != null)
{
wo[i] = woItem.Replace("wo=", "").Trim();
SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
}
}
//产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
}
else
{
LogHelper.WriteLogMes($"第二次询问mes失败");
SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
//产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
}
}
else
{
LogHelper.WriteLogMes($"询问mes失败");
SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
//产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
}
LogHelper.WriteLogMes($"【mes结束QUERY】");
SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
}
else
{
SendTaskMessage($"收到{i}:{stationConfig.DeviceName}过站检查请求(当站是否生产)(当前不需要双MES验证)...", MessageLevel.Debug);
LogHelper.WriteLogMes($"【mes开始QUERY】");
SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
(bool isSuccess, string response) = await _mesService.StationGetAsync(i, code, "", 2);//询问mes
if (isSuccess)
{
if (response != "MES功能未启用!")
{
string[] item = response.Split('\n');
//获取产品主sn和wo用于后续上传数据使用
string snItem = item.FirstOrDefault(f => f.Contains("sn="));
if (snItem != null)
{
ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
if (i == 0)
{
_productService.CurrentProductCode = ProductMainSN[i];
}
SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
}
string woItem = item.FirstOrDefault(f => f.Contains("wo="));
if (woItem != null)
{
wo[i] = woItem.Replace("wo=", "").Trim();
SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
}
}
else
{
ProductMainSN[i] = DateTime.Now.ToString();
if (i == 0)
{
_productService.CurrentProductCode = ProductMainSN[i];
}
}
LogHelper.WriteLogMes($"询问mes成功");
SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
//产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
}
else
{
LogHelper.WriteLogMes($"询问mes失败");
SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
//产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
}
LogHelper.WriteLogMes($"【mes结束QUERY】");
SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
}
}
// 上传本站数据
else if (state == 2)
{
DFC.Clear();
//获取当前工位的配置
var stationConfig = _configService.GetDeviceInfo(i);
SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
//从服务器中获取当前时间
var serverTimeResult = await _mesService.GetServerTimeAsync(i, code, 2);
double ct = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
if (i == 0)
{
CTtime = ct;
}
//从PLC获取零件编号
PartSN = plc.ReadNode(addressConfig.In_PartCode.Address);
comp = PartSN;
//读取产品结果
Int16 resultIndex = plc.ReadNode(string.Format(addressConfig.In_Result.Address, i));
resultIndex = 1;
//读取压力值
float pressure = plc.ReadNode(string.Format(addressConfig.In_PressureValue.Address, i));
AssemblyRecord assemblyRecord = new AssemblyRecord();
assemblyRecord.ProductSN = code;
assemblyRecord.RecipeName = currentProduct.Name;
assemblyRecord.PartSN = PartSN;
assemblyRecord.AssemblyDurationSeconds = ct;
assemblyRecord.AssemblyPressure = pressure;
assemblyRecord.DeviceId = i;
assemblyRecord.DeviceName = stationConfig.DeviceName;
assemblyRecord.OperatorName = _systemDatabaseService.GetCurrentUser().UserName;
assemblyRecord.Success = resultIndex == 1 ? true : false;
assemblyRecord.DownCameraCoord1 = "";
assemblyRecord.DownCameraCoord2 = "";
assemblyRecord.DownCameraCoord3 = "";
assemblyRecord.DownCameraCoord4 = "";
assemblyRecord.PickMoveCameraCoord = "";
assemblyRecord.PlaceMoveCameraCoord1 = "";
assemblyRecord.PlaceMoveCameraCoord2 = "";
assemblyRecord.PlaceMoveCameraCoord3 = "";
assemblyRecord.PlaceMoveCameraCoord4 = "";
assemblyRecord.PlaceActualCoord = "";
//目前只记录当前站
if (i == 0)
{
await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
{
ProductName = currentProduct.Name,
ProductCode = code,
DeviceId = i,
DeviceName = "",
Category = resultIndex == 1 ? "OK" : "NG",
Quantity = 1,
Remark = $"TotalSeconds:{ct.ToString("F2")}",
UserName = _systemDatabaseService.GetCurrentUser().UserName,
});
assemblyRecord.PlaceMoveCameraCoord1 = $"{UpCameraPutResults[0].X:F3},{UpCameraPutResults[0].Y:F3},{UpCameraPutResults[0].Z:F3}";
assemblyRecord.PlaceMoveCameraCoord2 = $"{UpCameraPutResults[1].X:F3},{UpCameraPutResults[1].Y:F3},{UpCameraPutResults[1].Z:F3}";
assemblyRecord.PlaceActualCoord = $"{PlaceActualCoord.X:F3},{PlaceActualCoord.Y:F3},{PlaceActualCoord.Z:F3}";
App.Current.Dispatcher.Invoke(() =>
{
_eventAggregator.GetEvent().Publish(assemblyRecord);
});
}
await _systemDatabaseService.RecordAssemblyAsync(assemblyRecord);
var pressureParam = FileHelper.ReadJsonFile>(FilePath.PressureParamterConfigPath);
var p1 = pressureParam[0];//组装压力
var p2 = pressureParam[1];//保压压力
LogHelper.WriteLogMes($"【mes开始ADD】");
SendTaskMessage($"mes开始ADD", MessageLevel.Info);
Dictionary data = new Dictionary();
string gap = ""; string press = ""; string presstime = ""; string assypress = "";
if (i == 0)
{
gap = gapString;
try
{
assypress = currentPressure[0].ToString("F2");
if (currentPressure[0] >= p1.PressureDownLimit && currentPressure[0] <= p1.PressureUpLimit)
{
resultIndex = 1;
}
else
{
resultIndex = 2;
}
}
catch (Exception ex)
{
assypress = "0";
resultIndex = 2;
}
data.Add("gap", gap);
data.Add("assy_pressure", assypress);
SendTaskMessage($"gap:{gap},组装压力:{assypress}", MessageLevel.Info);
#region 数据
bool assyPresRes;
if (currentPressure[0] >= p1.PressureDownLimit && currentPressure[0] <= p1.PressureUpLimit)
{
assyPresRes = true;
}
else assyPresRes = false;
DFC.Clear();
int itemIndex = 0;
var gaps = gap.Split(',');
foreach (var item in gaps)
{
itemIndex++;
DFC.Add(new DataFormCtq
{
PPID = ProductMainSN[i],
PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
CTQ_NAME = $"Gap{itemIndex}",
CTQ_VALUE = item,
CTQ_LSL = "",
CTQ_USL = "",
PROCESS_END_TIME = serverTimeResult.Now.ToString(),
SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
REVISION = stationConfig.DataInfo.REVISION,
WO = wo[i],
MFG_LOT = stationConfig.DataInfo.MFG_LOT,
MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
PROCESS_OUTCOME = "PASS",
PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
CTQ_UNIT_OF_MEASURE = "mm",
ERROR_MESSAGE = ""
});
}
DFC.Add(new DataFormCtq
{
PPID = ProductMainSN[i],
PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
CTQ_NAME = "Assy_Pressure",
CTQ_VALUE = assypress,
CTQ_LSL = p1.PressureDownLimit.ToString("F3"),
CTQ_USL = p1.PressureUpLimit.ToString("F3"),
PROCESS_END_TIME = serverTimeResult.Now.ToString(),
SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
REVISION = stationConfig.DataInfo.REVISION,
WO = wo[i],
MFG_LOT = stationConfig.DataInfo.MFG_LOT,
MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
PROCESS_OUTCOME = assyPresRes ? "PASS" : "FAIL",
PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
CTQ_UNIT_OF_MEASURE = "kg",
ERROR_MESSAGE = assyPresRes ? "" : "Assy_Pressure OOS"
});
#endregion
}
else if (i == 1)
{
try
{
press = currentPressure[1].ToString("F2");
if (currentPressure[1] >= p2.PressureDownLimit && currentPressure[1] <= p2.PressureUpLimit)
{
resultIndex = 1;
}
else
{
resultIndex = 2;
}
}
catch (Exception ex)
{
press = "0";
resultIndex = 2;
}
presstime = p2.PressureTime.ToString();
data.Add("pressure", press);
data.Add("pressure_time", presstime);
SendTaskMessage($"保压压力:{press},保压时间:{presstime}", MessageLevel.Info);
#region 数据
bool presRes;
if (currentPressure[1] >= p2.PressureDownLimit && currentPressure[1] <= p2.PressureUpLimit)
{
presRes = true;
}
else presRes = false;
DFC.Clear();
DFC.Add(new DataFormCtq
{
PPID = ProductMainSN[i],
PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
CTQ_NAME = "Pressure",
CTQ_VALUE = press,
CTQ_LSL = p2.PressureDownLimit.ToString("F3"),
CTQ_USL = p2.PressureUpLimit.ToString("F3"),
PROCESS_END_TIME = serverTimeResult.Now.ToString(),
SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
REVISION = stationConfig.DataInfo.REVISION,
WO = wo[i],
MFG_LOT = stationConfig.DataInfo.MFG_LOT,
MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
PROCESS_OUTCOME = presRes ? "PASS" : "FAIL",
PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
CTQ_UNIT_OF_MEASURE = "kg",
ERROR_MESSAGE = presRes ? "" : "Assy_Pressure OOS"
});
DFC.Add(new DataFormCtq
{
PPID = ProductMainSN[i],
PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
CTQ_NAME = "Pressure_time",
CTQ_VALUE = Math.Round(double.Parse(presstime), 3).ToString(),
CTQ_LSL = p2.PressureTime.ToString("F3"),
CTQ_USL = p2.PressureTime.ToString("F3"),
PROCESS_END_TIME = serverTimeResult.Now.ToString(),
SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
REVISION = stationConfig.DataInfo.REVISION,
WO = stationConfig.DataInfo.WO,
MFG_LOT = stationConfig.DataInfo.MFG_LOT,
MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
PROCESS_OUTCOME = "PASS",
PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
CTQ_UNIT_OF_MEASURE = "s",
ERROR_MESSAGE = ""
});
#endregion
}
//gap-复检gap参数, press-保压站实际压力值, presstime-保压站保压时间, assypress-组装站实际压力值
(bool isSuccess, string response) = await _mesService.SubmitGetAsync(i, code, comp, resultIndex == 1 ? true : false, data, _LastMesCheckTime[i], serverTimeResult.Now);
if (isSuccess)
{
LogHelper.WriteLogMes($"上传mes成功");
SendTaskMessage($"上传mes成功", MessageLevel.Debug);
}
else
{
LogHelper.WriteLogMes($"上传mes失败");
SendTaskMessage($"上传mes失败", MessageLevel.Error);
}
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
//是否保存当前的产品记录至CSV?
if (stationConfig.SaveCsv)
{
//判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
{
bool recordResult = RecordStationResult(i, DFC, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
if (recordResult)
{
SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
}
else
{
SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
}
}
else
{
SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
}
}
else
{
SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
}
LogHelper.WriteLogMes($"【mes结束ADD】");
SendTaskMessage($"mes结束ADD", MessageLevel.Info);
return;
}
else
{
SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
return;
}
}
}
}
//开始/停止 组装/锁附
for (int i = 0; i < 7; i++)
{
//开始组装
if (string.Format(addressConfig.In_WorkStart.Address, i).Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastWorkStart[i] != state)
{
_LastWorkStart[i] = state;
}
else
{
return;
}
var code = plc.ReadNode(string.Format(addressConfig.In_Code.Address, i));
if (state == 1)
{
//SendTaskMessage($"收到开始组装信号[{i}]...", MessageLevel.Debug);
SendTaskMessage($"收到开始保压信号[{i}]...", MessageLevel.Debug);
// 开始采集压力值
StartPressureCollection(currentProduct.Name, code, i);
StartCtqTime[i] = DateTime.Now;
}
else
{
SendTaskMessage($"关闭开始保压信号[{i}]...", MessageLevel.Debug);
}
}
}
//停止组装
else if (string.Format(addressConfig.In_WorkDone.Address, i).Contains(tuple.nodeId))
{
if (tuple.value is Int16 state)
{
if (_LastWorkDone[i] != state)
{
_LastWorkDone[i] = state;
}
else
{
return;
}
if (state == 1)
{
SendTaskMessage($"收到停止压力信号[{i}]...", MessageLevel.Debug);
//读取压力值
//float pressure = plc.ReadNode(addressConfig.In_PressureValue.Address);
//读取压力值
float pressure = plc.ReadNode(string.Format(addressConfig.In_PressureValue.Address, i));
currentPressure[i] = pressure;
SendTaskMessage($"[{i}]压力:{pressure}", MessageLevel.Info);
//await Task.Delay(60);
await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
var code = plc.ReadNode(string.Format(addressConfig.In_Code.Address, i));
// 停止采集压力并保存
await StopAndSavePressureCollectionAsync(currentProduct.Name, code, i);
}
else
{
SendTaskMessage($"停止压力信号[{i}]已关闭", MessageLevel.Alarm);
}
}
}
}
}
}
catch (Exception ex)
{
SendTaskMessage(ex.Message, MessageLevel.Error);
LogHelper.WriteLogError("PLC命令执行时出错!", ex);
}
}
#endregion
#region 方法
private void SendTaskMessage(string msg, MessageLevel level)
{
App.Current.Dispatcher.Invoke(() =>
{
_eventAggregator.GetEvent().Publish(new Models.MessageStruct() { Message = msg, level = level });
});
}
#region Pressure collection helpers
public void InitPressure()
{
for (int i = 0; i < _pressureSamples.Length; i++)
{
_pressureSamples[i] = new List<(DateTime, float)>();
}
for (int i = 0; i < _pressureCts.Length; i++)
{
_pressureCts[i] = new CancellationTokenSource();
}
for (int i = 0; i < _pressureTimeoutCts.Length; i++)
{
_pressureTimeoutCts[i] = new CancellationTokenSource();
}
for (int i = 0; i < _pressureLinkedCts.Length; i++)
{
_pressureLinkedCts[i] = new CancellationTokenSource();
}
}
///
/// 开始采集压力值
///
/// 配方名称
/// 产品编号
/// 编号
private void StartPressureCollection(string productName, string productCode, int Index)
{
try
{
// cancel existing if any
//_pressureCts[Index]?.Cancel();
//_pressureTimeoutCts[Index]?.Cancel();
//_pressureLinkedCts[Index]?.Dispose();
_pressureSamples[Index]?.Clear();
_pressureCts[Index] = new CancellationTokenSource();
_pressureTimeoutCts[Index] = new CancellationTokenSource();
// timeout after configured seconds
_pressureTimeoutCts[Index].CancelAfter(TimeSpan.FromSeconds(_pressureMaxDurationSeconds));
// link tokens so either stop or timeout cancels
_pressureLinkedCts[Index] = CancellationTokenSource.CreateLinkedTokenSource(_pressureCts[Index].Token, _pressureTimeoutCts[Index].Token);
var token = _pressureLinkedCts[Index].Token;
var addressConfig = _configService.GetPlcAddresses();
var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
if (plc == null || !plc.IsConnected) return;
Task.Run(async () =>
{
SendTaskMessage($"Pressure collection started for position {Index}", MessageLevel.Debug);
while (!token.IsCancellationRequested)
{
try
{
float pressure = plc.ReadNode(string.Format(addressConfig.In_PressureValue.Address, Index));
lock (_pressureSamples[Index])
{
_pressureSamples[Index].Add((DateTime.Now, pressure));
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("采集压力值时出错", ex);
}
await Task.Delay(_pressureSampleIntervalMs);
}
// if cancelled due to timeout
if (_pressureTimeoutCts[Index].IsCancellationRequested && !_pressureCts[Index].IsCancellationRequested)
{
SendTaskMessage("Pressure collection timed out, saving collected data.", MessageLevel.Alarm);
await StopAndSavePressureCollectionAsync(productName, productCode, Index);
}
}, token);
}
catch (Exception ex)
{
LogHelper.WriteLogError("StartPressureCollection error", ex);
SendTaskMessage($"压力采集时出错:{ex.Message}", MessageLevel.Error);
}
}
///
/// 停止采集并保存压力数据
///
///
///
///
///
private async Task StopAndSavePressureCollectionAsync(string productName, string productCode, int Index)
{
try
{
// cancel sampling
//_pressureCts[Index]?.Cancel();
// allow worker to observe cancel
await Task.Delay(50);
List<(DateTime Timestamp, float Value)> snapshot;
lock (_pressureSamples[Index])
{
snapshot = new List<(DateTime, float)>(_pressureSamples[Index]);
}
if (snapshot.Count == 0)
{
SendTaskMessage("No pressure samples collected.", MessageLevel.Info);
return;
}
// save to file under configured path
try
{
//获取系统参数
var systemConfig = _configService.GetSystemConfiguration();
if (systemConfig.PressureSensorConfig == null || systemConfig.PressureSensorConfig.Count <= 0)
{
SendTaskMessage("当前没有配置任何压力传感器!", MessageLevel.Alarm);
return;
}
//获取当前压力传感器配置
var pressureSensorConfig = systemConfig.PressureSensorConfig.FirstOrDefault(p => p.SensorId == Index);
if (pressureSensorConfig == null)
{
SendTaskMessage($"当前压力传感器配置不存在!- {Index}", MessageLevel.Alarm);
return;
}
//PressureFinishNotification : Prism.Events.PubSubEvent<(bool IsSuccess, int Index, (DateTime Timestamp, float Value)[] values,string SavePath )>
string basePath = pressureSensorConfig?.PressureCurvePath ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
string dirPath = Path.Combine(basePath, datePath, productName ?? "UnknownProduct", productCode ?? DateTime.Now.ToString("yyyyMMddHHmmssfff"));
if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
string csvfileName = $"pressure-{productCode}-{Index}-{DateTime.Now.ToString("HHmmss")}.csv";
string csvPath = Path.Combine(dirPath, csvfileName);
string pngfileName = $"pressure-{productCode}-{Index}-{DateTime.Now.ToString("HHmmss")}.png";
string pngPath = Path.Combine(dirPath, pngfileName);
if (!pressureSensorConfig.IsSavePressureCurve)
{
csvPath = string.Empty;
pngPath = string.Empty;
}
App.Current.Dispatcher.Invoke(() =>
{
_eventAggregator.GetEvent().Publish((true, Index, snapshot.ToArray(), pngPath));
});
//判断是否保存锁付曲线
if (pressureSensorConfig.IsSavePressureCurve)
{
if (!string.IsNullOrEmpty(csvPath))
{
var sb = new StringBuilder();
sb.AppendLine("Timestamp,Value");
foreach (var s in snapshot)
{
sb.AppendLine($"{s.Timestamp:O},{s.Value}");
}
File.WriteAllText(csvPath, sb.ToString());
SendTaskMessage($"Pressure samples saved to {csvPath}", MessageLevel.Debug);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("保存压力采样文件时出错", ex);
SendTaskMessage("保存压力采样文件时出错: " + ex.Message, MessageLevel.Error);
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("StopAndSavePressureCollectionAsync error", ex);
}
finally
{
try
{
_pressureLinkedCts[Index]?.Cancel();
_pressureLinkedCts[Index]?.Dispose();
_pressureTimeoutCts[Index]?.Dispose();
_pressureCts[Index]?.Dispose();
_pressureSamples[Index]?.Clear();
}
catch { }
}
}
#endregion
private async void DoYieldTime(object state)
{
try
{
//获取当前产品
var currentproduct = _productService.GetCurrentProduct();
if (currentproduct == null) return;
TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name);
TotalQuantityToday = await _systemDatabaseService.GetTodayProductionAsync(currentproduct.Name);
CurrentUPH = await _systemDatabaseService.GetLastHourProductionAsync(currentproduct.Name);
}
catch (Exception)
{
}
}
#region vm启动检测
///
/// 杀死所有VM有关进程
///
public void KillVMProcess()
{
KillProcess("VisionMasterServerApp");
KillProcess("VisionMaster");
KillProcess("VmModuleProxy.exe");
KillProcess("vServerApp.exe");
}
///
/// 杀死指定进程名的进程
///
///
public void KillProcess(string strKillName)
{
foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
{
if (p.ProcessName.Contains(strKillName))
{
try
{
p.Kill();
p.WaitForExit();
}
catch (Exception ex)
{
LogHelper.WriteLogError($"杀死进程:{strKillName}时失败!", ex);
}
}
}
}
#endregion
///
/// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
///
///
///
///
///
///
///
///
///
private bool RecordStationResult(int stationIndex, IEnumerable dfcs, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true)
{
try
{
//获取当前工位的配置
var stationConfig = _configService.GetDeviceInfo(stationIndex);
if (stationConfig == null) return false;
//如果保存路径为空,则不保存
if (string.IsNullOrEmpty(savePath)) return false;
string fullPath = savePath;
//如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
if (File.Exists(savePath) || Path.HasExtension(savePath))
{
fullPath = savePath;
//如果路径不存在,则创建
// 创建目录
string directory = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
}
else
{
//结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
string datePath = timestamp.ToString("yyyy-MM") + "\\";
string dirPath = Path.Combine(savePath, datePath);
if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
fullPath = Path.Combine(dirPath, fileName);
}
StringBuilder sb = new StringBuilder();
if (!File.Exists(fullPath))
{
sb.Append("PPID,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," +
"MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE");
sb.AppendLine();
}
if (dfcs == null || dfcs.Count() == 0)
{
return false;
}
foreach (var dfc in dfcs)
{
sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE},{dfc.CTQ_LSL},{dfc.CTQ_USL},{dfc.PROCESS_END_TIME},{dfc.SUPPLIER_NAME},{dfc.COMMODITY_TYPE},{dfc.REVISION},{dfc.WO},{dfc.MFG_LOT},{dfc.MFG_ASSY_LINE},{dfc.PROCESS_OUTCOME},{dfc.PROCESS_MACHINE_ID},{dfc.CTQ_UNIT_OF_MEASURE},{dfc.ERROR_MESSAGE}");
sb.AppendLine();
}
// 使用 StreamWriter 以追加模式打开文件
StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
sw.Write(sb.ToString());
sw.Close();
sw.Dispose();
return true;
}
catch (Exception ex)
{
if (!isFirstEnter)
{
return false;
}
LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
//我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
//生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
string datePath = timestamp.ToString("yyyy-MM") + "\\";
string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
RecordStationResult(stationIndex, dfcs, productMainSN, ct, timestamp, tempFileName, false);
return false;
}
}
#endregion
}
}