using Common; using Common.Models; using CommunityToolkit.Mvvm.Messaging; using MegaRobo.C00225155.ControlDevices; using MegaRobo.C00225155.ControlDevices.WeightDevice; using MegaRobo.C00225155.Entities; using MegaRobo.C00225155.Entities.Entity_DB; using MegaRobo.Contract; using MegaRobo.Contract.Abstractions; using MegaRobo.ControlDevices; using MegaRobo.Entities; using MegaRobo.Logger; using MegaRobo.PipetteTool.HamiltonConsole.PipetteDevices.HamiltonDevices; using Microsoft.VisualBasic; using NetTaste; using Newtonsoft.Json.Linq; using Nito.AsyncEx; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.Diagnostics; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Policy; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Xml.Serialization; namespace MegaRobo.C00225155.AppServer.ExecuteWorks { /// /// 这里主要写配置工站上位机和PLC通讯的函数 /// public partial class StationService_MaterialDosing : StationServiceBase { // /// // /// 下工装---等待信号的锁 // /// // private static readonly AsyncLock _lockWaitSignal_Dnload = new AsyncLock(); // /// // /// 上工装---等待信号的锁 // /// // private static readonly AsyncLock _lockWaitSignal_Upload = new AsyncLock(); // /// // /// 四轴机械手---等待信号的锁 // /// // private static readonly AsyncLock _lockWaitSignal_FourAxis = new AsyncLock(); // /// // /// 粉末原液瓶---等待信号的锁 // /// // private static readonly AsyncLock _lockWaitSignal_Powder = new AsyncLock(); // /// // /// 六轴机械手下反应瓶工装线程的信号锁,防止多线程同时操作 // /// // private static readonly AsyncLock _lockBoxDn_SixAxis = new AsyncLock(); // /// // /// 六轴机械手上反应瓶缓存工装线程的信号锁,防止多线程同时操作 // /// // private static readonly AsyncLock _lockBoxUp_SixAxis = new AsyncLock(); // /// // /// 冷却平台 是否有瓶子 更新属性的锁 // /// // private static readonly SemaphoreSlim _lockColdStateTrace = new SemaphoreSlim(1, 1); // /// // /// 磁力搅拌 是否有瓶子 更新属性的锁 // /// // private static readonly SemaphoreSlim _lockMagneticStirStateTrace = new SemaphoreSlim(1, 1); #region PLC点位写/读 /// /// 下料 /// /// /// public async Task ReadScannedValueAsync_Dnload(ushort address) { await Task.Delay(0); this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { return this.ModbusClient.Command.ReadValue(address); } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站读取PLC信号异常", Content = $"ReadScannedValueAsync_Dnload读取 {address} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"ReadScannedValueAsync_Dnload读取 {address} 时发生错误: {ex.Message}"); } return 0; } /// /// 上料 /// /// /// public async Task ReadScannedValueAsync_Upload(ushort address) { await Task.Delay(0); this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { return this.ModbusClient.Command.ReadValue(address); } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站读取PLC信号异常", Content = $"ReadScannedValueAsync_Upload读取 {address} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"ReadScannedValueAsync_Upload读取 {address} 时发生错误: {ex.Message}"); } return 0; } public async Task ReadScannedValueAsync_FourAxis(ushort address) { await Task.Delay(0); this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { return this.ModbusClient.Command.ReadValue(address); } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站读取PLC信号异常", Content = $"ReadSixAxis读取 {address} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"ReadScannedValueAsync_SixAxis读取 {address} 时发生错误: {ex.Message}"); } return 0; } public async Task ReadScannedValueAsync_XZ(ushort address) { await Task.Delay(0); this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { return this.ModbusClient.Command.ReadValue(address); } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站读取PLC信号异常", Content = $"ReadPowder读取 {address} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"ReadScannedValueAsync_Powder读取 {address} 时发生错误: {ex.Message}"); } return 0; } public async Task WriteCommandAsync_Dnload(ushort address, ushort value) { this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { this.ModbusClient.Command.WriteValue(address, value); //await Task.Delay(30); while (await ReadScannedValueAsync_Dnload(address) != value) { this.ModbusClient.Command.WriteValue(address, value); await Task.Delay(30); } } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站写入PLC信号异常", Content = $"WriteDnload写入 {address}值{value} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WriteCommandAsync_Dnload写入 {address}值{value} 时发生错误: {ex.Message}"); return; } } public async Task WriteCommandAsync_Upload(ushort address, ushort value) { this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { this.ModbusClient.Command.WriteValue(address, value); //await Task.Delay(30); while (await ReadScannedValueAsync_Upload(address) != value) { this.ModbusClient.Command.WriteValue(address, value); await Task.Delay(30); } } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站写入PLC信号异常", Content = $"WriteUpload写入 {address}值{value} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WriteCommandAsync_Upload写入 {address}值{value} 时发生错误: {ex.Message}"); return; } } public async Task WriteCommandAsync_FourAxis(ushort address, ushort value) { this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { this.ModbusClient.Command.WriteValue(address, value); //await Task.Delay(30); while (await ReadScannedValueAsync_FourAxis(address) != value) { this.ModbusClient.Command.WriteValue(address, value); await Task.Delay(30); } } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站写入PLC信号异常", Content = $"WriteFourAxis写入 {address}值{value} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WriteCommandAsync_FourAxis写入 {address}值{value} 时发生错误: {ex.Message}"); return; } } public async Task WriteCommandAsync_XZ(ushort address, ushort value) { this.StationProp.ManualResetEvent.WaitOne(); //暂停标志 try { this.ModbusClient.Command.WriteValue(address, value); //await Task.Delay(30); while (await ReadScannedValueAsync_XZ(address) != value) { this.ModbusClient.Command.WriteValue(address, value); await Task.Delay(30); } } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站写入PLC信号异常", Content = $"WritePowder写入 {address}值{value} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WriteCommandAsync_Powder写入 {address}值{value} 时发生错误: {ex.Message}"); return; } } public async Task WaitForActionFinishAsync_Dnload(ushort point, ushort waitValue, CancellationToken token) { //using (await _lockWaitSignal_Dnload.LockAsync(token)) { try { ushort result = 0; do { token.ThrowIfCancellationRequested(); this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志 result = await ReadScannedValueAsync_Dnload(point); await Task.Delay(100, token); } while (result != waitValue && !token.IsCancellationRequested); } catch (OperationCanceledException) { return; } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站等待PLC信号异常", Content = $"WaitForDnload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WaitForActionFinishAsync_Dnload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}"); return; } } } public async Task WaitForActionFinishAsync_Upload(ushort point, ushort waitValue, CancellationToken token) { //using (await _lockWaitSignal_Upload.LockAsync(token)) { try { ushort result = 0; do { token.ThrowIfCancellationRequested(); this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志 result = await ReadScannedValueAsync_Upload(point); await Task.Delay(100, token); } while (result != waitValue && !token.IsCancellationRequested); } catch (OperationCanceledException) { return; } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站等待PLC信号异常", Content = $"WaitForUpload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WaitForActionFinishAsync_Upload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}"); return; } } } public async Task WaitForActionFinishAsync_FourAxis(ushort point, ushort waitValue, CancellationToken cancellationToken) { //using (await _lockWaitSignal_FourAxis.LockAsync(cancellationToken)) { try { ushort result = 0; do { cancellationToken.ThrowIfCancellationRequested(); this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志 result = await ReadScannedValueAsync_FourAxis(point); await Task.Delay(100, cancellationToken); } while (result != waitValue && !cancellationToken.IsCancellationRequested); } catch (OperationCanceledException) { return; } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站等待PLC信号异常", Content = $"WaitForFourAxis等待 {point}是否为{waitValue} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WaitForActionFinishAsync_FourAxis等待 {point}是否为{waitValue} 时发生错误: {ex.Message}"); return; } } } public async Task WaitForActionFinishAsync_XZ(ushort point, ushort waitValue, CancellationToken cancellationToken) { //using (await _lockWaitSignal_Powder.LockAsync(cancellationToken)) { try { ushort result = 0; do { cancellationToken.ThrowIfCancellationRequested(); this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志 result = await ReadScannedValueAsync_XZ(point); await Task.Delay(100, cancellationToken); } while (result != waitValue && !cancellationToken.IsCancellationRequested); } catch (OperationCanceledException) { return; } catch (Exception ex) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"投料站等待PLC信号异常", Content = $"WaitForPowder等待 {point}是否为{waitValue} 时发生错误: {ex.Message}", OkButtonContent = "继续", CancelButtonContent = "取消", }); this.Logger.LogError($"WaitForActionFinishAsync_Powder等待 {point}是否为{waitValue} 时发生错误: {ex.Message}"); return; } } } #endregion #region 传送平台 /// /// 传送平台到过渡舱外准备上载具 /// /// /// /// private async Task TransferUploadBox(CancellationToken token) { if (token.IsCancellationRequested) return; //传送平台到过渡舱外 await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 1); await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 22, token); //清除信号 await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 0); //await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 0, token); await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 5, token); //等待PLC 准备就绪 等待空闲中 } /// /// 传送平台到手套箱内部 /// /// /// private async Task TransferToDeviceInner(CancellationToken token) { if (token.IsCancellationRequested) return; //传送平台到手套箱内部 await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 3); await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 22, token); //清除信号 await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 0); await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 5, token); //等待PLC 准备就绪 等待空闲中 } #endregion #region 四轴机械手 /// /// 四轴机械手取托盘 /// /// 目标区域编号 /// 托盘类型 /// 目标托盘位置号 /// /// private async Task FourAxisTakeBox(ushort aimarea, BoxTypeEnum boxType, ushort pos, CancellationToken token) { ///// 目标区域 ///// 1:手套箱传送平台; 2:Tip托盘存放平台;12:托盘存放平台; ///// //public readonly static ushort W_Robot_AimArea = 2202; ///// ///// 目标托盘位置号 ///// //public readonly static ushort W_Robot_AimAreaBoxPosid = 2203; ///// ///// 托盘类型:1:40mL瓶; 2:12mL瓶; 3:5mL瓶; 4:TIP头; ///// //public readonly static ushort W_Robot_BoxType = 2204; if (token.IsCancellationRequested || TestMode) return; ushort fixtureType = 0; switch (boxType) { case BoxTypeEnum._40mL原液工装: fixtureType = 1; break; case BoxTypeEnum._12mL样品工装: fixtureType = 2; break; case BoxTypeEnum._5mL样品工装: fixtureType = 3; break; case BoxTypeEnum._50uLTip头工装: fixtureType = 4; break; case BoxTypeEnum._300uLTip头工装: fixtureType = 4; break; case BoxTypeEnum._1000uLTip头工装: fixtureType = 4; break; } await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, pos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, fixtureType); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 11); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手放托盘 /// /// 目标区域编号 /// 托盘类型 /// 目标托盘位置号 /// /// private async Task FourAxisPutBox(ushort aimarea, BoxTypeEnum boxType, ushort pos, CancellationToken token) { ///// 目标区域 ///// 1:手套箱传送平台; 2:Tip托盘存放平台;12:托盘存放平台; ///// //public readonly static ushort W_Robot_AimArea = 2202; ///// ///// 目标托盘位置号 ///// //public readonly static ushort W_Robot_AimAreaBoxPosid = 2203; ///// ///// 托盘类型:1:40mL瓶; 2:12mL瓶; 3:5mL瓶; 4:TIP头; ///// //public readonly static ushort W_Robot_BoxType = 2204; if (token.IsCancellationRequested || TestMode) return; ushort fixtureType = 0; switch (boxType) { case BoxTypeEnum._40mL原液工装: fixtureType = 1; break; case BoxTypeEnum._12mL样品工装: fixtureType = 2; break; case BoxTypeEnum._5mL样品工装: fixtureType = 3; break; case BoxTypeEnum._50uLTip头工装: fixtureType = 4; break; case BoxTypeEnum._300uLTip头工装: fixtureType = 4; break; case BoxTypeEnum._1000uLTip头工装: fixtureType = 4; break; } await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, pos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, fixtureType); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 12); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手取粉末加样头 /// /// 目标区域编号 /// 目标托盘号 /// 目标位置号 /// 粉末类型 /// /// plc点位,起始或终点是传递仓到缓存位的话,开始取最终放需要写1 /// private async Task FourAxisTakePowderHeader(int aimarea, int aimarea_box, int bottlepos, PowderBottleTypeEnum powderbottletype, CancellationToken token, ushort point = 0) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, powderbottletype == PowderBottleTypeEnum._16mL ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, point); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 1); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手放粉末加样头 /// /// /// /// /// /// /// plc点位,起始或终点是传递仓到缓存位的话,开始取最终放需要写1 /// private async Task FourAxisPutPowderHeader(int aimarea, int aimarea_box, int bottlepos, PowderBottleTypeEnum powderbottletype, CancellationToken token, ushort point = 0) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, powderbottletype == PowderBottleTypeEnum._16mL ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, point); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 2); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴运行到扫码位置 /// /// bottle : 1:40 2:12 3:5 /// /// private async Task FourAxisGoToScannPos_liquid(CancellationToken token, int liquidBottle, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)liquidBottle); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 23); //goto scan pos await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveScanPos, 1, token); string sn = await scannerService.ReadAsnyc(TimeSpan.FromSeconds(5)); if (sourceLiquidBottle != null) { sourceLiquidBottle.SNCode = sn; } if (sampleBottle != null) { sampleBottle.SNCode = sn; } await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_ScanResult, 1); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveScanPos, 0, token); //清除信号 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_ScanResult, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴运行到粉末瓶扫码位置 /// /// 是否是粉末瓶子 /// /// private async Task FourAxisGoToScannPos_powder(CancellationToken token, SourcePowderBottleModel powderbottle) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 3); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveSideScanPos, 1, token); //触发扫码 string snCode = await scannerService_Powder.ReadAsnyc(TimeSpan.FromSeconds(5)); powderbottle.SNCode = snCode; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_SideScanResult, 1); //回复扫码完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveSideScanPos, 0, token); //清除信号 await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_SideScanResult, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } private async Task FourAxisPutPowderHeaderToPreWeight(CancellationToken token) { if (token.IsCancellationRequested || TestMode) return 16; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 4); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 2); //等待PLC回复到预称重位 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArrivePreWeightPos, 1, token); //这边需要称重并返回PLC完成 double powderWeight = TestMode ? 16 : (await preWeight.ReadWeightValue()); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_PreWeightFinish, 1); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); return powderWeight; } /// /// 四轴机械手拿液体瓶子 /// /// 目标区域编号 /// 目标托盘位置号 /// 目标孔编号 /// 瓶类型 /// /// private async Task FourAxisTakeLiquidBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SourceLiquidBottleModel sourceLiquidBottle) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 1); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sourceLiquidBottle.LiquidBottleLidState == SourceBottleLidStateEnum.Close ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 21); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手放液体瓶子 /// /// 目标区域编号 /// 目标托盘位置号 /// 目标孔编号 /// 瓶类型 /// /// private async Task FourAxisPutLiquidBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SourceLiquidBottleModel sourceLiquidBottle) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 1); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sourceLiquidBottle.LiquidBottleLidState == SourceBottleLidStateEnum.Close ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 22); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手取样品瓶子 /// /// 目标区域编号 /// 目标托盘位置号 /// 目标孔编号 /// 瓶类型 /// /// private async Task FourAxisTakeSampleBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SampleBottleModel sampleBottle) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, sampleBottle.SampleBottleType == SampleBottleTypeEnum._5mL ? (ushort)3 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sampleBottle.SampleBottleLidState == SampleBottleLidStateEnum.Close ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 21); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } /// /// 四轴机械手放样品瓶子 /// /// 目标区域编号 /// 目标托盘位置号 /// 目标孔编号 /// 瓶类型 /// /// private async Task FourAxisPutSampleBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SampleBottleModel sampleBottle) { if (token.IsCancellationRequested || TestMode) return; await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, sampleBottle.SampleBottleType == SampleBottleTypeEnum._5mL ? (ushort)3 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sampleBottle.SampleBottleLidState == SampleBottleLidStateEnum.Close ? (ushort)1 : (ushort)2); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 22); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token); //信号清零 await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0); await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0); await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token); } #endregion #region XZ模组 /// /// 假盖子开关盖 /// /// /// /// /// /// private async Task OpenCloseBottleFakeCap(CancellationToken token,bool isOpen, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null) { if (token.IsCancellationRequested || TestMode) return; int bottletype = 0; if (sourceLiquidBottle != null) { bottletype = 1; } if (sampleBottle != null) { if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL) { bottletype = 2; } else { bottletype = 3; } } ushort taskNo = isOpen ? (ushort)1 : (ushort)2; await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)2); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, taskNo); //等待PLC回复执行完成 await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); if (sourceLiquidBottle != null) { sourceLiquidBottle.LiquidBottleLidState = isOpen ? SourceBottleLidStateEnum.Open : SourceBottleLidStateEnum.Close; } if (sampleBottle != null) { sampleBottle.SampleBottleLidState = isOpen ? SampleBottleLidStateEnum.Open : SampleBottleLidStateEnum.Close; } await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// XZ模组开盖 /// /// /// /// /// private async Task OpenBottleLid(CancellationToken token, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null) { if (token.IsCancellationRequested || TestMode) return; int bottletype = 0; if (sourceLiquidBottle != null) { bottletype = 1; } if (sampleBottle != null) { if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL) { bottletype = 2; } else { bottletype = 3; } } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)1); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 1); //等待PLC回复执行完成 await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); if (sourceLiquidBottle != null) { sourceLiquidBottle.LiquidBottleLidState = SourceBottleLidStateEnum.Open; } if (sampleBottle != null) { sampleBottle.SampleBottleLidState = SampleBottleLidStateEnum.Open; } await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// XZ模组关盖 /// /// /// /// /// private async Task CloseBottleLid(CancellationToken token, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null) { if (token.IsCancellationRequested || TestMode) return; int bottletype = 0; if (sourceLiquidBottle != null) { bottletype = 1; } if (sampleBottle != null) { if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL) { bottletype = 2; } else { bottletype = 3; } } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)1); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 2); //等待PLC回复执行完成 await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); if (sourceLiquidBottle != null) { sourceLiquidBottle.LiquidBottleLidState = SourceBottleLidStateEnum.Close; } if (sampleBottle != null) { sampleBottle.SampleBottleLidState = SampleBottleLidStateEnum.Close; } await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// XZ摇匀 /// /// /// /// private async Task ShakeSampleBottle(CancellationToken token, SampleBottleModel sampleBottle) { if (token.IsCancellationRequested || TestMode) return; int bottletype = 0; if (sampleBottle != null) { if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL) { bottletype = 2; } else { bottletype = 3; } } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)10); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 3); //等待PLC回复执行完成 await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } //public async Task TestSuckVolume(CancellationToken token, double targetVolume,bool isFirst) //{ // SourceLiquidBottleModel sourceLiquidBottleModel = new SourceLiquidBottleModel() // { // LiquidBottleLidState = SourceBottleLidStateEnum.Close // }; // if (isFirst) // { // await FourAxisTakeLiquidBottle(_cts.Token, (int)BoxAreaEnum._托盘存放平台, 1, 1, sourceLiquidBottleModel); // await FourAxisPutLiquidBottle(_cts.Token, (int)BoxAreaEnum._开关盖区域, 0, 0, sourceLiquidBottleModel); // await OpenBottleLid(_cts.Token, sourceLiquidBottleModel, null); // } // else // { // await CloseBottleLid(_cts.Token, sourceLiquidBottleModel, null); // await FourAxisTakeLiquidBottle(_cts.Token, (int)BoxAreaEnum._开关盖区域, 0, 0, sourceLiquidBottleModel); // await FourAxisPutLiquidBottle(_cts.Token, (int)BoxAreaEnum._托盘存放平台, 1, 1, sourceLiquidBottleModel); // } // List<(int tipVolume, List countlists)> selectedTips = new List<(int tipVolume, List countlists)>(); // (int tipVolume, List countlists) selectedTip = (50,new List() { 30}); // selectedTips.Add(selectedTip); // for (int i = 0; i < selectedTips.Count; i++) // { // TipTypeEnum tipType = TipTypeEnum._1000UL; // DeviceNames deviceName = DeviceNames.Pipette_Dose_1ml_1; // if (selectedTips[i].tipVolume == 1000) // { // tipType = TipTypeEnum._1000UL; deviceName = DeviceNames.Pipette_Dose_1ml_1; // } // else if (selectedTips[i].tipVolume == 300) // { // tipType = TipTypeEnum._300UL; deviceName = DeviceNames.Pipette_Dose_1ml_2; // } // else if (selectedTips[i].tipVolume == 50) // { // tipType = TipTypeEnum._50UL; deviceName = DeviceNames.Pipette_Dose_1ml_3; // } // this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Ongoing) { Tag = "使用中" }); // while (true) // { // List targetTipBoxes = workService.ProjectPro.TipHeadArea.Where(tipBox => (tipBox.TipType == tipType) && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)).ToList(); // //告诉PLC到取Tip头位置 // if (targetTipBoxes == null) // { // WeakReferenceMessenger.Default.Send(new ConfirmMessage() // { // Header = $"取Tip失败", // Content = $"没有tip了!!!", // OkButtonContent = "继续", // CancelButtonContent = "取消", // }); // continue; // } // if (isFirst) // { // await PipetteTakeTip(token, targetTipBoxes.FirstOrDefault(), deviceName); // //取Tip // var restip = await GunPickUpTip_M1(deviceName, pipetteService_1ml, tipType); // if (restip) // { // break; // } // } // else // { // await PipetteDiscardTip(token, deviceName); // await GunDiscardTip_M1(deviceName, pipetteService_1ml); // return; // } // } // for (int j = 0; j < selectedTips[i].countlists.Count; j++)//用这种枪头要吸液排液多少次 // { // //告诉PLC到吸液位置 // await PipetteAbsorb(token, deviceName); // } // //告诉PLC到丢弃Tip头位置 // //await PipetteDiscardTip(token, deviceName); // //await GunDiscardTip_M1(deviceName, pipetteService_1ml); // //this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Done)); // } //} private async Task XZ_TakeTip_Absorb_Dispense_DiscardTip(CancellationToken token, string sourceliquidname, double targetVolume, SourceLiquidBottleModel sourceLiquidBottleModel, SampleBottleModel sampleBottleModel) { if (TestMode) return; List<(int tipVolume, List countlists)> selectedTips = new List<(int tipVolume, List countlists)>(); selectedTips = SelectTipsEx(targetVolume); for (int i = 0; i < selectedTips.Count; i++) { TipTypeEnum tipType = TipTypeEnum._1000UL; DeviceNames deviceName = DeviceNames.Pipette_Dose_1ml_1; if (selectedTips[i].tipVolume == 1000) { tipType = TipTypeEnum._1000UL; deviceName = DeviceNames.Pipette_Dose_1ml_1; } else if (selectedTips[i].tipVolume == 300) { tipType = TipTypeEnum._300UL; deviceName = DeviceNames.Pipette_Dose_1ml_2; } else if (selectedTips[i].tipVolume == 50) { tipType = TipTypeEnum._50UL; deviceName = DeviceNames.Pipette_Dose_1ml_3; } this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Ongoing) { Tag = "使用中" }); while (true) { List targetTipBoxes = workService.ProjectPro.TipHeadArea.Where(tipBox => (tipBox.TipType == tipType) && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)).ToList(); //告诉PLC到取Tip头位置 if (targetTipBoxes == null) { WeakReferenceMessenger.Default.Send(new ConfirmMessage() { Header = $"取Tip失败", Content = $"没有tip了!!!", OkButtonContent = "继续", CancelButtonContent = "取消", }); continue; } await PipetteTakeTip(token, targetTipBoxes.FirstOrDefault(), deviceName); //取Tip var restip = await GunPickUpTip_M1(deviceName, pipetteService_1ml, tipType); if (restip) { break; } } for (int j = 0; j < selectedTips[i].countlists.Count; j++)//用这种枪头要吸液排液多少次 { //告诉PLC到吸液位置 await PipetteAbsorb(token, deviceName); int bottletype = workService.ProjectPro.SampleBottleType == SampleBottleTypeEnum._12mL ? 1 : 2; await GunAbsorb_M1(deviceName, pipetteService_1ml, sourceliquidname, (int)tipType, selectedTips[i].countlists[j] * 10,sourceLiquidBottleModel); //告诉PLC到排液位置 await PipetteDispense(token, deviceName); await GunDispensing_M1(deviceName, pipetteService_1ml, sourceliquidname, (int)tipType, (uint)(selectedTips[i].countlists[j] * 10), sampleBottleModel); } //告诉PLC到丢弃Tip头位置 await PipetteDiscardTip(token,deviceName); await GunDiscardTip_M1(deviceName, pipetteService_1ml); this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Done)); } } public async Task UpdateTipBox(TipBoxModel tipBoxModel) { var tipInStation = await dataAccessService.LoadEntityAsync(t => t.BoxId_inDosingStation == tipBoxModel.BoxId_inDosingStation); if (tipInStation == null) { var tipaddres = await dataAccessService.AddEntityAsync(tipBoxModel); } else { await dataAccessService.UpdateEntityAsync(tipBoxModel); } } public List<(int tipVolume, List absorbVolumnList)> SelectTipsEx(double targetVolumn) { List<(int tipVolume, List absorbVolumnList)> selectedTips = new List<(int tipVolume, List absorbVolumnList)>(); bool has50Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._50UL && t.TipItems.Any(ti => ti.IsAvailable)); bool has300Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._300UL && t.TipItems.Any(ti => ti.IsAvailable)); bool has1000Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._1000UL && t.TipItems.Any(ti => ti.IsAvailable)); if (!has50Tip && !has300Tip && !has1000Tip) return selectedTips; TipTypeEnum tipType = TipTypeEnum._1000UL; if (targetVolumn <= 50) { tipType = has50Tip ? TipTypeEnum._50UL : (has300Tip ? TipTypeEnum._300UL : TipTypeEnum._1000UL); //优先50 30 1000 } else if (targetVolumn <= 300) { tipType = has300Tip ? TipTypeEnum._300UL : (has1000Tip ? TipTypeEnum._1000UL : TipTypeEnum._50UL); //优先30 1000 50 } else { tipType = has1000Tip ? TipTypeEnum._1000UL : (has300Tip ? TipTypeEnum._300UL : TipTypeEnum._50UL); //优先1000 50 30 } (int tipVolume, List absorbVolumnList) volumeInfo; volumeInfo.tipVolume = tipType == TipTypeEnum._50UL ? 50 : (tipType == TipTypeEnum._300UL ? 300 : 1000); volumeInfo.absorbVolumnList = new List(); while (targetVolumn > 0) { if (targetVolumn > volumeInfo.tipVolume) { volumeInfo.absorbVolumnList.Add(volumeInfo.tipVolume); targetVolumn -= volumeInfo.tipVolume; } else { volumeInfo.absorbVolumnList.Add(targetVolumn); targetVolumn = 0; } } selectedTips.Add(volumeInfo); return selectedTips; } /// /// 选择Tip头的函数 /// /// /// public List<(double tipVolume, List absorbVolumnList)> SelectTips(double targetVolumn) { List<(double tipVolume, List absorbVolumnList)> selectedTips = new List<(double tipVolume, List absorbVolumnList)>(); // 1. 查找「存在且有可用Tip头」的工装(判断是否有对应类型的Tip) TipBoxModel _1000ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox => tipBox.TipType == TipTypeEnum._1000UL && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)); TipBoxModel _300ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox => tipBox.TipType == TipTypeEnum._300UL && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)); TipBoxModel _50ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox => tipBox.TipType == TipTypeEnum._50UL && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)); // 2. 整理「可用的Tip容量」(按「从大到小」排序,确保优先用大容量) var availableTipVolumes = new List(); if (_1000ulTip != null) availableTipVolumes.Add(1000); // 有1000UL Tip则加入 if (_300ulTip != null) availableTipVolumes.Add(300); // 有300UL Tip则加入 if (_50ulTip != null) availableTipVolumes.Add(50); // 有10UL Tip则加入 // 无可用Tip时,直接返回空列表(可根据业务需求抛异常) if (!availableTipVolumes.Any()) { //跟BS要Tip头 return selectedTips; } // 3. 初始化剩余体积(保留3位小数,避免精度问题) double remainingVolume = Math.Round(targetVolumn, 3, MidpointRounding.ToPositiveInfinity); while (remainingVolume > 0) { double currentVolumn = 0; double tipvolumn = 1000; if (remainingVolume > 1000) { currentVolumn = 1000; remainingVolume -= 1000; tipvolumn = 1000; } else if (remainingVolume > 300) { tipvolumn = 1000; currentVolumn = remainingVolume; remainingVolume = 0; } else if (remainingVolume > 50) { tipvolumn = 300; currentVolumn = remainingVolume; remainingVolume = 0; } else { tipvolumn = 50; currentVolumn = remainingVolume; remainingVolume = 0; } var st = selectedTips.FirstOrDefault(s => s.tipVolume == tipvolumn); if (st.tipVolume > 0) { st.absorbVolumnList.Add(currentVolumn); } else { List absorbVolumes = new List(); absorbVolumes.Add(currentVolumn); selectedTips.Add((tipvolumn, absorbVolumes)); } } // 4. 优先用「最大可用Tip」处理剩余体积 //foreach (var tipVolume in availableTipVolumes) //{ // if (remainingVolume <= 0) break; // 体积处理完则退出循环 // List absorbVolumes = new List(); // // 步骤1:用当前Tip处理「尽可能多的满容量体积」 // if (remainingVolume >= tipVolume) // { // int fullTipCount = (int)(remainingVolume / tipVolume); // 需要的满容量Tip数量 // absorbVolumes.AddRange(Enumerable.Repeat(tipVolume, fullTipCount)); // 记录满容量吸液 // remainingVolume -= tipVolume * fullTipCount; // 扣除已处理的体积 // remainingVolume = Math.Round(remainingVolume, 3, MidpointRounding.ToPositiveInfinity); // 重新校准精度 // } // // 步骤2:处理「剩余的少量体积」(不足一个满容量Tip) // if (remainingVolume > 0) // { // absorbVolumes.Add(remainingVolume); // 用当前Tip处理剩余体积 // remainingVolume = 0; // 体积处理完成 // } // // 将当前Tip的选择结果加入列表 // selectedTips.Add((tipVolume, absorbVolumes)); //} return selectedTips; } /// /// 移液枪取Tip头 /// /// /// /// private async Task PipetteTakeTip(CancellationToken token, TipBoxModel tipBox, DeviceNames deviceName) { if (token.IsCancellationRequested || TestMode) return; ushort pipteId = 1; if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4) { pipteId = (ushort)((int)deviceName - 6); } TipHeadItem tipHead = tipBox.TipItems.FirstOrDefault(f => f.IsAvailable); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId); //移液枪编号 1-4 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)(3 - tipBox.BoxId_inDosingStation + 1));//(ushort)tipBox.BoxId_inDosingStation); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param3, (ushort)tipHead.UseIndex);// await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 11); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param3, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); tipHead.IsAvailable = false; await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// 移液枪吸液 /// /// /// /// private async Task PipetteAbsorb(CancellationToken token, DeviceNames deviceName) { if (token.IsCancellationRequested || TestMode) return; ushort pipteId = 1; if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4) { pipteId = (ushort)((int)deviceName - 6); } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId); //移液枪编号 1-4 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 12); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// 移液枪分液 /// /// /// /// private async Task PipetteDispense(CancellationToken token, DeviceNames deviceName) { if (token.IsCancellationRequested || TestMode) return; ushort pipteId = 1; if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4) { pipteId = (ushort)((int)deviceName - 6); } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId); //移液枪编号 1-4 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 13); //等待PLC回复执行完成 await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } /// /// 移液枪丢弃Tip头 /// /// /// /// private async Task PipetteDiscardTip(CancellationToken token, DeviceNames deviceName) { if (token.IsCancellationRequested || TestMode) return; ushort pipteId = 1; if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4) { pipteId = (ushort)((int)deviceName - 6); } await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId); //移液枪编号 1-4 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 14); //等待PLC回复执行完成 await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token); //信号清零 await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0); await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0); await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token); } #endregion private async Task RefreshReactBottleState(int boxId, int posId, SampleBottleStateEnum state) { await Task.Delay(0); } } }