using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.Net.NetworkInformation; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml.Linq; using DH.Commons.Base; using DH.Commons.Enums; using DH.Commons.Helper; using DH.Commons.Models; using HslCommunication; using HslCommunication.Enthernet; using HslCommunication.Profinet.XINJE; using OpenCvSharp; using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel; namespace DH.Devices.PLC { public class XinJEPLCTcpNet : PLCBase, ILogger { private static XinJEPLCTcpNet _instance; public static XinJEPLCTcpNet Instance { get { if (_instance == null) _instance = new XinJEPLCTcpNet(); return _instance; } } public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper(); public event Action OnLog; private XinJETcpNet TcpNet = new XinJETcpNet(); private TaskFactory _taskFac = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning); public override bool PLCConnect() { try { LoggerHelper.LogPath = "D://PROJECTS//Logs//"; LoggerHelper.LogPrefix = "PLC"; TcpNet.IpAddress = IP; TcpNet.Port = Port; TcpNet.ConnectTimeOut = 5000; TcpNet.ReceiveTimeOut = 10000; TcpNet.SleepTime = 0; TcpNet.AddressStartWithZero = true; TcpNet.IsStringReverse = false; TcpNet.Station = 1; switch (PLCType) { case EnumPLCType.信捷XD网口: TcpNet.Series = XinJESeries.XD; TcpNet.DataFormat = HslCommunication.Core.DataFormat.CDAB; break; case EnumPLCType.信捷XC网口: TcpNet.Series = XinJESeries.XC; TcpNet.DataFormat = HslCommunication.Core.DataFormat.CDAB; break; } OperateResult ret = TcpNet.ConnectServer(); if (ret.IsSuccess) { Connected = true; //初始化流程 InitProcess(); LogAsync(DateTime.Now, LogLevel.Information, $"{IP}:{Port}PLC连接成功"); return true; } else { Connected = false; LogAsync(DateTime.Now, LogLevel.Error, $"PLC初始化失败"); return false; //throw new Exception($"{IP}:{Port}PLC连接失败!"); } } catch (Exception ex) { Connected = false; LogAsync(DateTime.Now, LogLevel.Error, $"{IP}:{Port}PLC连接失败!失败原因:{ex.ToString()}"); return false; //throw new Exception($"{IP}:{Port}PLC连接失败!失败原因:{ex.ToString()}"); } } public override Int16 ReadInt16(string address) { try { if (Connected) { // 读取Int变量 var result = TcpNet.ReadInt16(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取int16失败,地址{address}"); throw new Exception($"PLC操作读取int16失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取int16失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取int16失败,地址{address},失败原因:{ex.ToString()}"); } } public override Int32 ReadInt32(string address) { try { if (Connected) { // 读取Int变量 var result = TcpNet.ReadInt32(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取int32失败,地址{address}"); throw new Exception($"PLC操作读取int32失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取int32失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取int32失败,地址{address},失败原因:{ex.ToString()}"); } } public override UInt16 ReadUInt16(string address) { try { if (Connected) { // 读取Int变量 var result = TcpNet.ReadUInt16(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取uint16失败,地址{address}"); throw new Exception($"PLC操作读取uint16失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取uint16失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取uint16失败,地址{address},失败原因:{ex.ToString()}"); } } public override UInt32 ReadUInt32(string address) { try { if (Connected) { // 读取Int变量 var result = TcpNet.ReadUInt32(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作uint32失败,地址{address}"); throw new Exception($"PLC操作uint32失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取uint32失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取uint32失败,地址{address},失败原因:{ex.ToString()}"); } } public override float ReadFloat(string address) { try { if (Connected) { // 读取Float变量 var result = TcpNet.ReadFloat(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取float失败,地址{address}"); throw new Exception($"PLC操作读取float失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取float失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取float失败,地址{address},失败原因:{ex.ToString()}"); } } public override bool ReadBool(string address) { try { if (Connected) { // 读取Bool变量 var result = TcpNet.ReadBool(address); if (result.IsSuccess) { return result.Content; } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取bool失败,地址{address}"); throw new Exception($"PLC操作读取bool失败,地址{address}"); } } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作读取bool失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作读取bool失败,地址{address},失败原因:{ex.ToString()}"); } } /// /// 写单独地址 uint32 值 /// /// 地址 /// 要写入的 int 值 /// 是否等待回复 public override bool WriteUInt32(string address, UInt32 writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作写入uint32失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作写入uint32失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } return false; } /// /// 写单独地址 uint16 值 /// /// 地址 /// 要写入的 int 值 /// 是否等待回复 public override bool WriteUInt16(string address, UInt16 writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作写入uint16失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作写入uint16失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } return false; } /// /// 写单独地址 int32 值 /// /// 地址 /// 要写入的 int 值 /// 是否等待回复 public override bool WriteInt32(string address, Int32 writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作写入int32失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作写入int32失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); } else { throw new Exception($"PLC未连接,地址{address}"); } return false; } /// /// 写单独地址 int16 值 /// /// 地址 /// 要写入的 int 值 /// 是否等待回复 public override bool WriteInt16(string address, Int16 writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { throw new Exception($"PLC操作写入int16失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); } else { throw new Exception($"PLC未连接,地址{address}"); } return false; } /// /// 写单独地址 float 值 /// /// 地址 /// 要写入的 float 值 /// 是否等待回复 public override bool WriteFloat(string address, float writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作写入float失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作写入float失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } return false; } /// /// 写单独地址 bool 值 /// /// 地址 /// 要写入的 bool 值 /// 是否等待回复 public override bool WriteBool(string address, bool writeValue, bool waitForReply = true) { if (Connected) { if (string.IsNullOrEmpty(address)) { return false; } int repeatTime = 3; do { try { var result = TcpNet.Write(address, writeValue); if (result.IsSuccess) { return true; } } catch (Exception ex) { repeatTime--; if (repeatTime <= 0) { LogAsync(DateTime.Now, LogLevel.Error, $"PLC操作写入bool失败,地址{address},失败原因:{ex.ToString()}"); throw new Exception($"PLC操作写入bool失败,地址{address},失败原因:{ex.ToString()}"); } } } while (repeatTime > 0); Thread.Sleep(30); } else { LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}"); } return false; } public override bool PLCDisConnect() { if (Connected) { var res = TcpNet.ConnectClose(); if (res.IsSuccess) { LogAsync(DateTime.Now, LogLevel.Information, $"{IP}:{Port}停止"); Connected = false; return true; } return false; } return false; } private void MonitorPieces() { ThreadStart ts = new ThreadStart(MonitorPiecesImpl); Thread th = new Thread(ts); th.Priority = ThreadPriority.AboveNormal; th.IsBackground = false; th.Start(); } public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning); private Dictionary piecesCountDic = new Dictionary(); private uint piecesCount = 0; /// /// int,int 轴号 捕获位置 /// public event Action OnNewPieces; private System.Threading.Timer timer; private System.Threading.TimerCallback timerCallback; public void NewPieces(int axisIndex, uint pieceNumber) { _taskFactory.StartNew(() => { Thread.CurrentThread.Priority = ThreadPriority.Highest; OnNewPieces?.Invoke(axisIndex, pieceNumber); }); } public async Task HeartbeatAsync1() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "心跳地址"); #if false Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; if (pLCItem == null) return; while (Connected) { try { LogAsync(DateTime.Now, LogLevel.Information, $"心跳\t"); WriteBool(pLCItem.Address, true); await Task.Delay(2000); // 非阻塞,等待1秒 } catch (Exception ex) { } } #else timerCallback = (object? state) => { timer.Change(2000, 2000); try { //WriteBool(pLCItem.Address, true); WriteBool("M31", true); } catch (Exception ex) { LogAsync(DateTime.Now, LogLevel.Error, $"心跳:{ex.Message}"); } }; timer = new System.Threading.Timer( timerCallback, null, 0, 2000); timer.Change(2000, 2000); #endif } /// /// 入料监听 /// /// private void MonitorPiecesImpl() { PLCItem pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "产品计数"); if (pLCItem == null) return; string Count = pLCItem.Address; DateTime startTime = DateTime.Now; DateTime endTime = startTime; TimeSpan timeSpan = endTime - startTime; Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; //while (CurrentState != DeviceState.DSClose && CurrentState != DeviceState.DSExcept && CurrentState != DeviceState.DSUninit) while (Connected) { Stopwatch sw = new Stopwatch(); uint tmpPieceNumber = 0; sw.Start(); // var ret = TcpNet.ReadUInt16("D1016"); var ret = TcpNet.ReadUInt32(Count); sw.Stop(); if (ret.IsSuccess) { tmpPieceNumber = ret.Content; } if (ret.IsSuccess && ret.Content > piecesCount) { sw.Start(); // Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} 板卡{station}产品入列触发{tmpPieceNumber}"); //LogAsync(DateTime.Now, LogLevel.Information, $"转盘{0}产品入列 {piecesCountDic[0]} size:{sum}"); if (tmpPieceNumber != piecesCount + 1) { LogAsync(DateTime.Now, LogLevel.Information, $"入列触发丢失\t{tmpPieceNumber}"); // Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t板卡{station}产品入列触发丢失,{piecesCountDic[station]}\t{tmpPieceNumber}"); } piecesCount = tmpPieceNumber; //NewPieces(ai, piecesCountDic[station]); NewPieces(1, piecesCount); sw.Stop(); startTime = DateTime.Now; //if (idalarm) //{ // idalarm = false; // AlarmVibration(false); //} } Thread.Sleep(2); } } public void InitProcess() { //启用心跳 OpenHeartbeat(true); // LogAsync(DateTime.Now, LogLevel.Information, $"启用心跳"); //状态复位 StatusReset(); //LogAsync(DateTime.Now, LogLevel.Information, $"状态复位"); //关闭定位 VisionPos(false); // LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位"); //写入流程加载点位配置 InitProcessAction(); //LogAsync(DateTime.Now, LogLevel.Information, $"写入流程加载点位配置"); //计数清零 CountToZero(); // LogAsync(DateTime.Now, LogLevel.Information, $"计数清零"); //停止转盘 TurnStart(false); //LogAsync(DateTime.Now, LogLevel.Information, $"停止转盘"); //转盘使能 TurnEnable(true); LogAsync(DateTime.Now, LogLevel.Information, $"启用心跳-状态复位-关闭定位-写入流程加载点位配置-计数清零-停止转盘-转盘使能"); //开启入料监听 MonitorPieces(); } public void StartProcess() { //状态复位 StatusReset(); // LogAsync(DateTime.Now, LogLevel.Information, $"状态复位"); //关闭定位 VisionPos(false); // LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位"); //写入流程启动点位配置 StartProcessAction(); PLCItem? pLCItem = ConfigModel.GlobalList? .FirstOrDefault()? .StartProcessList? .Where(it => it.Name == "挡料电机回原点速度").FirstOrDefault(); if (pLCItem == null) { throw new Exception($"未找到挡料电机回原点速度地址,请检查该地址是否存在于点位表!"); } PLCItem? pLCItem1 = ConfigModel.GlobalList? .FirstOrDefault()? .StartProcessList? .Where(it => it.Name == "挡料电机位置").FirstOrDefault(); if (pLCItem1 == null) { throw new Exception($"未找到挡料电机位置地址,请检查该地址是否存在于点位表!"); } FeedingMotor(true, Convert.ToInt32(pLCItem.Value), Convert.ToInt32(pLCItem1.Value)); PLCItem? pLCItemmontor = ConfigModel.GlobalList? .FirstOrDefault()? .StartProcessList? .Where(it => it.Name == "相机步进速度").FirstOrDefault(); if (pLCItemmontor == null) { throw new Exception($"未找到相机步进速度地址,请检查该地址是否存在于点位表!"); } PLCItem? pLCItemmontor1 = ConfigModel.GlobalList? .FirstOrDefault()? .StartProcessList? .Where(it => it.Name == "相机步进位置").FirstOrDefault(); if (pLCItemmontor1 == null) { throw new Exception($"未找到相机步进位置地址,请检查该地址是否存在于点位表!"); } Motor(true, Convert.ToInt32(pLCItemmontor.Value), Convert.ToInt32(pLCItemmontor1.Value)); // if (_PLCConfig?.Enable == true) //挡料电机操作 // _PLC.FeedingMotor(_PLCConfig.CunToZeroSpeed, _PLCConfig.CunPos, _PLCConfig.CunSpeed, _PLCConfig.CunDirection); //流程开启操作配置 // ProcessInitialAction(); // if (_PLC?Enabled == true) // LogAsync(DateTime.Now, LogLevel.Information, $"写入流程加载点位配置"); bool? enableBelt = ConfigModel.GlobalList?.FirstOrDefault()?.EnableBelt; if (enableBelt == true) { Belt(true); } Thread.Sleep(1000); bool? enableVibrator = ConfigModel.GlobalList?.FirstOrDefault()?.EnableVibrator; if (enableVibrator == true) { Vibrator(true); } Thread.Sleep(1000); //转盘使能 TurnEnable(true); //转盘启动 TurnStart(true); Thread.Sleep(1000); //计数清零 CountToZero(); LogAsync(DateTime.Now, LogLevel.Information, $"状态复位-关闭定位-写入流程加载点位配置-计数清零"); Thread.Sleep(200); } public void StopProcess() { StatusReset(); VisionPos(false); CountToZero(); bool? enableVibrator = ConfigModel.GlobalList?.FirstOrDefault()?.EnableVibrator; if (enableVibrator == true) { Vibrator(true); } Thread.Sleep(1000); bool? enableBelt = ConfigModel.GlobalList?.FirstOrDefault()?.EnableBelt; if (enableBelt == true) { Belt(false); } Thread.Sleep(1000); StopProcessAction(); TurnStart(false); LogAsync(DateTime.Now, LogLevel.Action, $"流程停止"); Task.Run(async () => { await ExecuteClearDelayAsync(); }); } public async Task ExecuteClearDelayAsync() { int? clearTime = ConfigModel.GlobalList?.FirstOrDefault()?.ClearTime; if (clearTime != null) { LogAsync(DateTime.Now, LogLevel.Action, $"转盘清料开始"); TurnClear(true); await Task.Delay(clearTime.Value * 1000); LogAsync(DateTime.Now, LogLevel.Action, $"转盘清料完成"); TurnClear(false); } } public void CloseProcess() { StatusReset(); VisionPos(false); CountToZero(); TurnStart(false); TurnEnable(false); StopProcessAction(); TurnClear(false); OpenHeartbeat(false); PLCDisConnect(); // LogAsync(DateTime.Now, LogLevel.Information, $"PLC断开连接"); } public void InitProcessAction() => ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.InitProcessList?.ToList() ?? new List()); public void StartProcessAction() => ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.StartProcessList?.ToList() ?? new List()); public void StopProcessAction() => ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.StopProcessList?.ToList() ?? new List()); public void StartResetAction() => ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.StartResetList?.ToList() ?? new List()); public void StopResetAction() => ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.StopResetList?.ToList() ?? new List()); // 处理方法:无需再检查 null private void ProcessAction(List items) { if (items.Count == 0) return; foreach (var item in items.OrderBy(x => x.StartIndex)) { switch (item.Type) { case EnumPLCDataType.单字整型: WriteUInt16(item.Address, ushort.Parse(item.Value)); break; case EnumPLCDataType.双字整型: WriteUInt32(item.Address, uint.Parse(item.Value)); break; case EnumPLCDataType.浮点型: WriteFloat(item.Address, float.Parse(item.Value)); break; case EnumPLCDataType.布尔型: WriteBool(item.Address, item.Value.Equals("true", StringComparison.OrdinalIgnoreCase)); break; } } } /// /// 状态复位 /// public void StatusReset() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "状态复位"); if (pLCItem == null) return; WriteBool(pLCItem.Address, false); } /// /// 开启关闭视觉定位 /// public void VisionPos(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "启用定位"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); } /// /// 转盘方向 /// /// public void TurnDirection(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "转盘方向"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); } /// /// 转盘速度 /// /// public void TurnSpeed(int speed) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "转盘速度"); if (pLCItem == null) return; WriteUInt16(pLCItem.Address, (ushort)speed); } /// /// 转盘启停 /// public void TurnStart(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "转盘启动"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); piecesCount = 0; } /// /// 转盘使能 /// /// public void TurnEnable(bool b) { PLCItem? DiskOpenItem = PLCItemList.FirstOrDefault(u => u.Name == "转盘使能"); if (DiskOpenItem == null) return; WriteBool(DiskOpenItem.Address, b); Thread.Sleep(30); } /// /// 计数清零 /// public void CountToZero() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "计数清零"); if (pLCItem == null) return; WriteBool(pLCItem.Address, true); Thread.Sleep(30); } public void RedLight(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "指示灯红"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void GreenLight(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "指示灯绿"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void YellowLight(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "指示灯黄"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void Buzzer(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "蜂鸣器"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void Belt(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "皮带"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void Vibrator(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "振动盘"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } public void Motor(bool direction, int speed, int pos) { int timeout = 60000; int elapsedTime = 0; int checkInterval = 100; MotorToZero(false); Thread.Sleep(300); MotorClockwise(false); Thread.Sleep(300); MotorCounterclockwise(false); Thread.Sleep(300); MotorSpeed(speed); // 速度 Thread.Sleep(300); // 发送回原点指令 MotorToZero(true); Thread.Sleep(1000); // 给设备一些时间响应 // 等待回到原点 while (true) { if (elapsedTime >= timeout) { LogAsync(DateTime.Now, LogLevel.Error, $"超时"); break; } if (ReadMotorRealPos() == 0) { break; } Thread.Sleep(checkInterval); elapsedTime += checkInterval; } MotorToZero(false); Thread.Sleep(200); MotorClockwise(false); Thread.Sleep(200); MotorCounterclockwise(false); // 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置 // MotorSpeed(speed); Thread.Sleep(300); MotorPos(pos); // 目标位置 Thread.Sleep(300); if (direction) { MotorClockwise(true); // 顺时针转动 } else { MotorCounterclockwise(true); // 逆时针转动 } int timeout1 = 60000; int elapsedTime1 = 0; int checkInterval1 = 100; while (true) { if (elapsedTime1 >= timeout1) { break; } if (ReadMotorRealPos() == pos) { break; } Thread.Sleep(checkInterval1); elapsedTime1 += checkInterval1; } Thread.Sleep(1500); } /// /// 挡料电机操作 /// true: 顺时针 /// False: 逆时针 /// /// public void FeedingMotor(bool direction, int speed, int pos) { int timeout = 10000; int elapsedTime = 0; int checkInterval = 100; BarrierToZero(false); Thread.Sleep(300); // 检查是否不在原点,如果不在,则回原点 BarrierClockwise(false); Thread.Sleep(300); BarrierCounterclockwise(false); Thread.Sleep(300); BarrierToZeroSpeed(speed); // 速度 Thread.Sleep(300); // 发送回原点指令 BarrierToZero(true); Thread.Sleep(300); // 给设备一些时间响应 // 等待回到原点 while (true) { if (elapsedTime >= timeout) { break; } if (ReadBarrierRealPos() == 0) { break; } Thread.Sleep(checkInterval); elapsedTime += checkInterval; } BarrierToZero(false); Thread.Sleep(300); // 检查是否不在原点,如果不在,则回原点 BarrierClockwise(false); Thread.Sleep(300); BarrierCounterclockwise(false); Thread.Sleep(300); // 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置 BarrierSpeed(speed); Thread.Sleep(300); if (direction) { BarrierClockwise(true); // 顺时针转动 } else { BarrierCounterclockwise(true); // 逆时针转动 } Thread.Sleep(300); BarrierPos(pos); // 目标位置 Thread.Sleep(300); int timeout1 = 10000; int elapsedTime1 = 0; int checkInterval1 = 100; while (true) { if (elapsedTime1 >= timeout1) { break; } if (ReadBarrierRealPos() == pos) { break; } Thread.Sleep(checkInterval1); elapsedTime1 += checkInterval1; } Thread.Sleep(300); } /// /// 转盘清料 /// /// public void TurnClear(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "转盘清料"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); } /// /// 开启心跳 /// /// public void OpenHeartbeat(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "启用心跳"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); Thread.Sleep(30); if (b) { //开启心跳 //Task.Run(async () => await HeartbeatAsync1()); _taskFac.StartNew(async () => await HeartbeatAsync1()); } } int currentRegister = 0; public void Blowing(uint productNumber, UInt16 value) { int Register = (int)((productNumber - 1) % 30); currentRegister = 411 + Register; WriteUInt16($"D{currentRegister}", value); } /// /// 读取定位脉冲 /// /// public int ReadVisionPos() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "定位完成脉冲值"); if (pLCItem == null) return 0; int value = ReadInt32(pLCItem.Address); Thread.Sleep(100); return Math.Abs(value); } /// /// 挡杆回原点 /// public void BarrierToZero(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机回原点"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); } /// /// 变焦相机回原点 /// public void ZoomcameraToZero(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "步进电机回原点"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); } /// /// 读取挡料电机实时位置 /// /// public int ReadBarrierRealPos() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机实时位置"); if (pLCItem == null) { throw new Exception("未找到挡料电机实时位置点位"); } return ReadInt16(pLCItem.Address); } /// /// 读取 挡杆回原点状态 /// /// /// public bool ReadBarrierToZero() { //PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机回原点"); //if (pLCItem == null) //{ // throw new Exception("未找到挡料电机回原点点位"); //} //挡料电机传感器感应点 return ReadBool("X11"); } /// /// 挡杆回原点速度 /// public void BarrierToZeroSpeed(int speed) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机回原点速度"); if (pLCItem == null) return; WriteInt32(pLCItem.Address, speed); } /// /// 挡杆位置 /// public void BarrierPos(int value) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机位置"); if (pLCItem == null) return; WriteInt16(pLCItem.Address, (short)value); } /// /// 挡杆速度 /// public void BarrierSpeed(int value) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机速度"); if (pLCItem == null) return; WriteUInt32(pLCItem.Address, (uint)value); } /// /// 挡杆顺时针 /// public void BarrierClockwise(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机顺时针"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); Thread.Sleep(30); } /// /// 挡杆逆时针 /// public void BarrierCounterclockwise(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机逆时针"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); Thread.Sleep(30); } /// /// 相机步进电机回原点 /// /// public void MotorToZero(bool b) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进原点"); if (pLCItem == null) return; WriteBool(pLCItem.Address, b); } /// /// 读取相机步进电机回原点状态 /// /// /// public bool ReadMotorToZero() { //PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进原点"); //if (pLCItem == null) //{ // throw new Exception("未找到挡料电机回原点点位"); //} //return ReadBool(pLCItem.Address); return ReadBool("X10"); } /// /// 相机步进电机位置 /// /// public void MotorPos(int value) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进位置"); if (pLCItem == null) return; WriteInt32(pLCItem.Address, (ushort)value); } public int ReadMotorRealPos() { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进实时位置"); if (pLCItem == null) { throw new Exception("未找到相机步进实时位置"); } return ReadInt32(pLCItem.Address); } /// /// 相机步进电机速度 /// /// public void MotorSpeed(int speed) { PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进速度"); if (pLCItem == null) return; WriteInt32(pLCItem.Address, speed); } /// /// 相机步进顺时针 /// public void MotorClockwise(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进顺时针"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); Thread.Sleep(30); } /// /// 相机步进逆时针 /// public void MotorCounterclockwise(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进逆时针"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); Thread.Sleep(30); } /// /// 相机步进点动 /// public void MotorTest(bool b) { PLCItem? DiskRunItem = PLCItemList.FirstOrDefault(u => u.Name == "点动相机步进"); if (DiskRunItem == null) return; WriteBool(DiskRunItem.Address, b); Thread.Sleep(30); } public void LogAsync(LogMsg msg) { msg.MsgSource = "PLC"; msg.ThreadId = Thread.CurrentThread.ManagedThreadId; //OnLog?.BeginInvoke(msg, null, null); OnLog?.Invoke(msg); //if (InitialConfig.IsEnableLog) { LoggerHelper.LogAsync(msg); } } public void LogAsync(DateTime dt, LogLevel logLevel, string msg) { LogAsync(new LogMsg(dt, logLevel, msg)); } } }