This commit is contained in:
liyaobang 2025-04-24 09:00:57 +08:00
commit 77b75050b2
6 changed files with 7601 additions and 7459 deletions

View File

@ -1,117 +1,169 @@
using System; 
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using Newtonsoft.Json;
using System.Threading.Tasks;
namespace DH.Commons.Helper namespace DH.Commons.Helper
{ {
public static class SchemeHelper public static class SchemeHelper
{ {
private const string SchemesKey = "Schemes"; private const string DefaultSchemeName = "默认方案";
private const string CurrentSchemeKey = "CurrentScheme"; private static readonly string ConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes.json");
private const char Separator = '|';
/// <summary>
/// 方案配置数据结构
/// </summary>
private class SchemeConfig
{
public List<string> Schemes { get; set; } = new List<string>();
public string CurrentScheme { get; set; } = DefaultSchemeName;
}
/// <summary> /// <summary>
/// 初始化配置(首次运行时调用) /// 初始化配置(首次运行时调用)
/// </summary> /// </summary>
public static void Initialize() public static void Initialize()
{ {
// 如果Schemes不存在创建空键 if (!File.Exists(ConfigFilePath))
if (!SystemConfigHelper.KeyExists(SchemesKey))
{ {
SystemConfigHelper.SetValue(SchemesKey, ""); var defaultConfig = new SchemeConfig
} {
Schemes = new List<string> { DefaultSchemeName },
// 如果CurrentScheme不存在创建空键 CurrentScheme = DefaultSchemeName
if (!SystemConfigHelper.KeyExists(CurrentSchemeKey)) };
{ SaveConfig(defaultConfig);
SystemConfigHelper.SetValue(CurrentSchemeKey, "");
} }
} }
/// <summary> /// <summary>
/// 获取所有方案(自动处理空值) /// 获取所有方案
/// </summary> /// </summary>
public static List<string> GetAllSchemes() public static List<string> GetAllSchemes()
{ {
var schemeString = SystemConfigHelper.GetValue(SchemesKey, ""); var config = LoadConfig();
return string.IsNullOrEmpty(schemeString) return config.Schemes ?? new List<string>();
? new List<string>()
: new List<string>(schemeString.Split(Separator));
} }
/// <summary> /// <summary>
/// 添加新方案(自动初始化处理) /// 添加新方案
/// </summary> /// </summary>
public static void AddScheme(string schemeName) public static void AddScheme(string schemeName)
{ {
if (string.IsNullOrWhiteSpace(schemeName)) if (string.IsNullOrWhiteSpace(schemeName))
throw new ArgumentException("方案名称无效"); throw new ArgumentException("方案名称无效");
var schemes = GetAllSchemes(); var config = LoadConfig();
if (schemes.Contains(schemeName)) if (config.Schemes.Contains(schemeName))
throw new InvalidOperationException($"方案 {schemeName} 已存在"); throw new InvalidOperationException($"方案 {schemeName} 已存在");
schemes.Add(schemeName); config.Schemes.Add(schemeName);
SaveSchemes(schemes); SaveConfig(config);
} }
/// <summary> /// <summary>
/// 设置当前方案(空值安全处理) /// 设置当前方案
/// </summary> /// </summary>
public static void SetCurrentScheme(string schemeName) public static void SetCurrentScheme(string schemeName)
{ {
var schemes = GetAllSchemes(); var config = LoadConfig();
if (!schemes.Contains(schemeName)) if (!config.Schemes.Contains(schemeName))
throw new KeyNotFoundException($"方案 {schemeName} 不存在"); throw new KeyNotFoundException($"方案 {schemeName} 不存在");
SystemConfigHelper.SetValue(CurrentSchemeKey, schemeName); config.CurrentScheme = schemeName;
SaveConfig(config);
} }
/// <summary> /// <summary>
/// 获取当前方案(默认值处理) /// 获取当前方案
/// </summary> /// </summary>
public static string GetCurrentScheme() public static string GetCurrentScheme()
{ {
var current = SystemConfigHelper.GetValue(CurrentSchemeKey, ""); var config = LoadConfig();
return !string.IsNullOrEmpty(current) ? current : "默认方案"; return !string.IsNullOrEmpty(config.CurrentScheme)
? config.CurrentScheme
: DefaultSchemeName;
} }
private static void SaveSchemes(List<string> schemes)
{
var schemeString = schemes.Count > 0
? string.Join(Separator.ToString(), schemes)
: "";
SystemConfigHelper.SetValue(SchemesKey, schemeString);
}
/// <summary> /// <summary>
/// 删除指定方案(自动同步当前方案状态) /// 删除指定方案
/// </summary> /// </summary>
/// <param name="schemeName">要删除的方案名称</param>
/// <exception cref="ArgumentException">当方案名称为空时抛出</exception>
/// <exception cref="KeyNotFoundException">当方案不存在时抛出</exception>
public static void DeleteScheme(string schemeName) public static void DeleteScheme(string schemeName)
{ {
if (string.IsNullOrWhiteSpace(schemeName)) if (string.IsNullOrWhiteSpace(schemeName))
throw new ArgumentException("方案名称无效"); throw new ArgumentException("方案名称无效");
var schemes = GetAllSchemes(); var config = LoadConfig();
if (!schemes.Contains(schemeName)) if (!config.Schemes.Contains(schemeName))
throw new KeyNotFoundException($"方案 {schemeName} 不存在"); throw new KeyNotFoundException($"方案 {schemeName} 不存在");
// 删除前检查是否是当前方案 // 如果是当前方案,需要先切换
bool isCurrent = GetCurrentScheme() == schemeName; if (config.CurrentScheme == schemeName)
{
var otherScheme = config.Schemes.FirstOrDefault(s => s != schemeName);
if (otherScheme != null)
{
config.CurrentScheme = otherScheme;
}
else
{
config.CurrentScheme = DefaultSchemeName;
if (!config.Schemes.Contains(DefaultSchemeName))
{
config.Schemes.Add(DefaultSchemeName);
}
}
}
// 执行删除操作 config.Schemes.Remove(schemeName);
schemes.Remove(schemeName); SaveConfig(config);
SaveSchemes(schemes); }
/// <summary>
/// 加载配置文件
/// </summary>
private static SchemeConfig LoadConfig()
{
if (!File.Exists(ConfigFilePath))
{
Initialize();
}
try
{
string json = File.ReadAllText(ConfigFilePath);
return JsonConvert.DeserializeObject<SchemeConfig>(json) ?? new SchemeConfig();
}
catch
{
// 如果读取失败,返回默认配置
return new SchemeConfig
{
Schemes = new List<string> { DefaultSchemeName },
CurrentScheme = DefaultSchemeName
};
}
}
/// <summary>
/// 保存配置文件
/// </summary>
private static void SaveConfig(SchemeConfig config)
{
try
{
string json = JsonConvert.SerializeObject(config, Formatting.Indented);
File.WriteAllText(ConfigFilePath, json);
}
catch (Exception ex)
{
// 处理保存失败的情况
throw new InvalidOperationException("保存方案配置失败", ex);
}
} }
} }
} }

View File

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using DH.Commons.Base; using DH.Commons.Base;
using DH.Commons.Enums; using DH.Commons.Enums;
using DH.Commons.Helper;
using DH.Commons.Models; using DH.Commons.Models;
using HslCommunication; using HslCommunication;
using HslCommunication.Enthernet; using HslCommunication.Enthernet;
@ -37,6 +38,8 @@ namespace DH.Devices.PLC
public event Action<LogMsg> OnLog; public event Action<LogMsg> OnLog;
private XinJETcpNet TcpNet = new XinJETcpNet(); private XinJETcpNet TcpNet = new XinJETcpNet();
private TaskFactory _taskFac = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
public override bool PLCConnect() public override bool PLCConnect()
{ {
try try
@ -82,7 +85,7 @@ namespace DH.Devices.PLC
} }
catch(Exception ex) catch (Exception ex)
{ {
Connected = false; Connected = false;
LogAsync(DateTime.Now, LogLevel.Error, $"{IP}:{Port}PLC连接失败!失败原因:{ex.ToString()}"); LogAsync(DateTime.Now, LogLevel.Error, $"{IP}:{Port}PLC连接失败!失败原因:{ex.ToString()}");
@ -182,7 +185,7 @@ namespace DH.Devices.PLC
LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}");
throw new Exception($"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -258,7 +261,8 @@ namespace DH.Devices.PLC
public override bool ReadBool(string address) public override bool ReadBool(string address)
{ {
try try
{ if (Connected) {
if (Connected)
{ {
// 读取Bool变量 // 读取Bool变量
var result = TcpNet.ReadBool(address); var result = TcpNet.ReadBool(address);
@ -343,7 +347,7 @@ namespace DH.Devices.PLC
public override bool WriteUInt16(string address, UInt16 writeValue, bool waitForReply = true) public override bool WriteUInt16(string address, UInt16 writeValue, bool waitForReply = true)
{ {
if (Connected) if (Connected)
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
@ -472,13 +476,13 @@ namespace DH.Devices.PLC
{ {
throw new Exception($"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}");
} }
return false; return false;
} }
/// <summary> /// <summary>
/// 写单独地址 float 值 /// 写单独地址 float 值
/// </summary> /// </summary>
@ -534,7 +538,7 @@ namespace DH.Devices.PLC
/// <param name="waitForReply">是否等待回复</param> /// <param name="waitForReply">是否等待回复</param>
public override bool WriteBool(string address, bool writeValue, bool waitForReply = true) public override bool WriteBool(string address, bool writeValue, bool waitForReply = true)
{ {
if(Connected) if (Connected)
{ {
if (string.IsNullOrEmpty(address)) if (string.IsNullOrEmpty(address))
{ {
@ -570,17 +574,17 @@ namespace DH.Devices.PLC
LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}"); LogAsync(DateTime.Now, LogLevel.Error, $"PLC未连接,地址{address}");
throw new Exception($"PLC未连接,地址{address}"); throw new Exception($"PLC未连接,地址{address}");
} }
return false; return false;
} }
public override bool PLCDisConnect() public override bool PLCDisConnect()
{ {
if (Connected) if (Connected)
{ {
var res = TcpNet.ConnectClose(); var res = TcpNet.ConnectClose();
if (res.IsSuccess) if (res.IsSuccess)
{ {
@ -598,7 +602,7 @@ namespace DH.Devices.PLC
private void MonitorPieces() private void MonitorPieces()
{ {
ThreadStart ts = new ThreadStart(MonitorPiecesImpl); ThreadStart ts = new ThreadStart(MonitorPiecesImpl);
Thread th = new Thread(ts); Thread th = new Thread(ts);
th.Priority = ThreadPriority.AboveNormal; th.Priority = ThreadPriority.AboveNormal;
@ -617,7 +621,9 @@ namespace DH.Devices.PLC
/// int,int 轴号 捕获位置 /// int,int 轴号 捕获位置
/// </summary> /// </summary>
public event Action<int, uint> OnNewPieces; public event Action<int, uint> OnNewPieces;
private System.Threading.Timer timer;
private System.Threading.TimerCallback timerCallback;
public void NewPieces(int axisIndex, uint pieceNumber) public void NewPieces(int axisIndex, uint pieceNumber)
{ {
@ -631,14 +637,47 @@ namespace DH.Devices.PLC
public async Task HeartbeatAsync1() public async Task HeartbeatAsync1()
{ {
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "心跳地址"); PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "心跳地址");
#if false
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
if (pLCItem == null)
return;
while (Connected) while (Connected)
{ {
try
if (pLCItem == null) {
return; LogAsync(DateTime.Now, LogLevel.Information, $"心跳\t");
WriteBool(pLCItem.Address, true);
await Task.Delay(900); // 非阻塞等待1秒 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
} }
/// <summary> /// <summary>
/// 入料监听 /// 入料监听
@ -647,7 +686,7 @@ namespace DH.Devices.PLC
private void MonitorPiecesImpl() private void MonitorPiecesImpl()
{ {
PLCItem pLCItem= PLCItemList.FirstOrDefault(u => u.Name == "产品计数"); PLCItem pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "产品计数");
if (pLCItem == null) if (pLCItem == null)
return; return;
string Count = pLCItem.Address; string Count = pLCItem.Address;
@ -661,8 +700,8 @@ namespace DH.Devices.PLC
Stopwatch sw = new Stopwatch(); Stopwatch sw = new Stopwatch();
uint tmpPieceNumber = 0; uint tmpPieceNumber = 0;
sw.Start(); sw.Start();
// var ret = TcpNet.ReadUInt16("D1016"); // var ret = TcpNet.ReadUInt16("D1016");
var ret = TcpNet.ReadUInt32(Count); var ret = TcpNet.ReadUInt32(Count);
sw.Stop(); sw.Stop();
@ -678,13 +717,13 @@ namespace DH.Devices.PLC
//LogAsync(DateTime.Now, LogLevel.Information, $"转盘{0}产品入列 {piecesCountDic[0]} size:{sum}"); //LogAsync(DateTime.Now, LogLevel.Information, $"转盘{0}产品入列 {piecesCountDic[0]} size:{sum}");
if (tmpPieceNumber != piecesCount + 1) if (tmpPieceNumber != piecesCount + 1)
{ {
LogAsync(DateTime.Now, LogLevel.Information, $"入列触发丢失\t{tmpPieceNumber}"); LogAsync(DateTime.Now, LogLevel.Information, $"入列触发丢失\t{tmpPieceNumber}");
// Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t板卡{station}产品入列触发丢失,{piecesCountDic[station]}\t{tmpPieceNumber}"); // Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t板卡{station}产品入列触发丢失,{piecesCountDic[station]}\t{tmpPieceNumber}");
} }
piecesCount = tmpPieceNumber; piecesCount = tmpPieceNumber;
//NewPieces(ai, piecesCountDic[station]); //NewPieces(ai, piecesCountDic[station]);
NewPieces(1, piecesCount); NewPieces(1, piecesCount);
sw.Stop(); sw.Stop();
startTime = DateTime.Now; startTime = DateTime.Now;
//if (idalarm) //if (idalarm)
@ -695,7 +734,7 @@ namespace DH.Devices.PLC
} }
Thread.Sleep(1); Thread.Sleep(2);
} }
} }
@ -703,19 +742,19 @@ namespace DH.Devices.PLC
{ {
//启用心跳 //启用心跳
OpenHeartbeat(true); OpenHeartbeat(true);
// LogAsync(DateTime.Now, LogLevel.Information, $"启用心跳"); // LogAsync(DateTime.Now, LogLevel.Information, $"启用心跳");
//状态复位 //状态复位
StatusReset(); StatusReset();
//LogAsync(DateTime.Now, LogLevel.Information, $"状态复位"); //LogAsync(DateTime.Now, LogLevel.Information, $"状态复位");
//关闭定位 //关闭定位
VisionPos(false); VisionPos(false);
// LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位"); // LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位");
//写入流程加载点位配置 //写入流程加载点位配置
InitProcessAction(); InitProcessAction();
//LogAsync(DateTime.Now, LogLevel.Information, $"写入流程加载点位配置"); //LogAsync(DateTime.Now, LogLevel.Information, $"写入流程加载点位配置");
//计数清零 //计数清零
CountToZero(); CountToZero();
// LogAsync(DateTime.Now, LogLevel.Information, $"计数清零"); // LogAsync(DateTime.Now, LogLevel.Information, $"计数清零");
//停止转盘 //停止转盘
TurnStart(false); TurnStart(false);
//LogAsync(DateTime.Now, LogLevel.Information, $"停止转盘"); //LogAsync(DateTime.Now, LogLevel.Information, $"停止转盘");
@ -725,16 +764,18 @@ namespace DH.Devices.PLC
//开启入料监听 //开启入料监听
MonitorPieces(); MonitorPieces();
} }
public void StartProcess() public void StartProcess()
{ {
//状态复位 //状态复位
StatusReset(); StatusReset();
// LogAsync(DateTime.Now, LogLevel.Information, $"状态复位"); // LogAsync(DateTime.Now, LogLevel.Information, $"状态复位");
//关闭定位 //关闭定位
VisionPos(false); VisionPos(false);
// LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位"); // LogAsync(DateTime.Now, LogLevel.Information, $"关闭定位");
//写入流程启动点位配置 //写入流程启动点位配置
StartProcessAction(); StartProcessAction();
PLCItem? pLCItem = ConfigModel.GlobalList? PLCItem? pLCItem = ConfigModel.GlobalList?
@ -743,7 +784,7 @@ namespace DH.Devices.PLC
.Where(it => it.Name == "挡料电机回原点速度").FirstOrDefault(); .Where(it => it.Name == "挡料电机回原点速度").FirstOrDefault();
if (pLCItem == null) if (pLCItem == null)
{ {
throw new Exception( $"未找到挡料电机回原点速度地址,请检查该地址是否存在于点位表!"); throw new Exception($"未找到挡料电机回原点速度地址,请检查该地址是否存在于点位表!");
} }
PLCItem? pLCItem1 = ConfigModel.GlobalList? PLCItem? pLCItem1 = ConfigModel.GlobalList?
.FirstOrDefault()? .FirstOrDefault()?
@ -792,17 +833,26 @@ namespace DH.Devices.PLC
//转盘启动 //转盘启动
TurnStart(true); TurnStart(true);
} }
public void StopProcess()
{
StatusReset();
VisionPos(false);
CountToZero();
StopProcessAction();
TurnStart(false);
// LogAsync(DateTime.Now, LogLevel.Information, $"PLC断开连接");
}
public void CloseProcess() public void CloseProcess()
{ {
StatusReset(); StatusReset();
VisionPos(false); VisionPos(false);
CountToZero(); CountToZero();
TurnStart(false); TurnStart(false);
TurnEnable(false); TurnEnable(false);
StopProcessAction();
OpenHeartbeat(false); OpenHeartbeat(false);
PLCDisConnect(); PLCDisConnect();
// LogAsync(DateTime.Now, LogLevel.Information, $"PLC断开连接"); // LogAsync(DateTime.Now, LogLevel.Information, $"PLC断开连接");
} }
public void InitProcessAction() => public void InitProcessAction() =>
ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.InitProcessList?.ToList() ?? new List<PLCItem>()); ProcessAction(ConfigModel.GlobalList?.FirstOrDefault()?.InitProcessList?.ToList() ?? new List<PLCItem>());
@ -875,7 +925,7 @@ namespace DH.Devices.PLC
if (pLCItem == null) if (pLCItem == null)
return; return;
WriteBool(pLCItem.Address, b); WriteBool(pLCItem.Address, b);
} }
/// <summary> /// <summary>
@ -888,7 +938,7 @@ namespace DH.Devices.PLC
if (pLCItem == null) if (pLCItem == null)
return; return;
WriteUInt16(pLCItem.Address, (ushort)speed); WriteUInt16(pLCItem.Address, (ushort)speed);
} }
/// <summary> /// <summary>
@ -968,12 +1018,16 @@ namespace DH.Devices.PLC
{ {
int timeout = 5000; int timeout = 60000;
int elapsedTime = 0; int elapsedTime = 0;
int checkInterval = 100; int checkInterval = 100;
MotorToZero(false); MotorToZero(false);
// 检查是否不在原点,如果不在,则回原点 Thread.Sleep(300);
MotorClockwise(false);
Thread.Sleep(300);
MotorCounterclockwise(false);
Thread.Sleep(300);
MotorSpeed(speed); // 速度 MotorSpeed(speed); // 速度
Thread.Sleep(300); Thread.Sleep(300);
@ -984,22 +1038,34 @@ namespace DH.Devices.PLC
// 等待回到原点 // 等待回到原点
while (!ReadMotorToZero()) while (true)
{ {
if (elapsedTime >= timeout) if (elapsedTime >= timeout)
{ {
LogAsync(DateTime.Now, LogLevel.Error, $"超时");
break; break;
} }
if (ReadMotorRealPos() == 0)
{
break;
}
Thread.Sleep(checkInterval); Thread.Sleep(checkInterval);
elapsedTime += checkInterval; elapsedTime += checkInterval;
} }
// }
MotorToZero(false);
Thread.Sleep(200);
MotorClockwise(false);
Thread.Sleep(200);
MotorCounterclockwise(false);
// 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置 // 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置
MotorSpeed(speed); // MotorSpeed(speed);
Thread.Sleep(300);
MotorPos(pos); // 目标位置
Thread.Sleep(300);
if (direction) if (direction)
{ {
MotorClockwise(true); // 顺时针转动 MotorClockwise(true); // 顺时针转动
@ -1010,11 +1076,27 @@ namespace DH.Devices.PLC
MotorCounterclockwise(true); // 逆时针转动 MotorCounterclockwise(true); // 逆时针转动
} }
Thread.Sleep(30);
MotorPos(pos); // 目标位置
Thread.Sleep(2000);
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);
} }
@ -1024,61 +1106,84 @@ namespace DH.Devices.PLC
/// False: 逆时针 /// False: 逆时针
/// </summary> /// </summary>
/// <param name="u"></param> /// <param name="u"></param>
public void FeedingMotor( bool direction,int speed,int pos) public void FeedingMotor(bool direction, int speed, int pos)
{ {
int timeout = 5000; int timeout = 10000;
int elapsedTime = 0; int elapsedTime = 0;
int checkInterval = 100; int checkInterval = 100;
BarrierToZero(false); BarrierToZero(false);
Thread.Sleep(300);
// 检查是否不在原点,如果不在,则回原点 // 检查是否不在原点,如果不在,则回原点
BarrierClockwise(false);
Thread.Sleep(300);
BarrierCounterclockwise(false);
Thread.Sleep(300);
BarrierToZeroSpeed(speed); // 速度 BarrierToZeroSpeed(speed); // 速度
Thread.Sleep(300); Thread.Sleep(300);
// 发送回原点指令 // 发送回原点指令
BarrierToZero(true); BarrierToZero(true);
Thread.Sleep(1000); // 给设备一些时间响应 Thread.Sleep(300); // 给设备一些时间响应
// 等待回到原点 // 等待回到原点
while (!ReadBarrierToZero()) while (true)
{
if (elapsedTime >= timeout)
{ {
if (elapsedTime >= timeout) break;
{
break;
}
Thread.Sleep(checkInterval);
elapsedTime += checkInterval;
} }
if (ReadBarrierRealPos() == 0)
{
break;
}
Thread.Sleep(checkInterval);
elapsedTime += checkInterval;
}
// 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置 // 无论是刚回到原点还是已经在原点,执行目标位置、速度和方向设置
BarrierSpeed(speed); BarrierSpeed(speed);
Thread.Sleep(300);
if (direction) if (direction)
{ {
BarrierClockwise(true); // 顺时针转动 BarrierClockwise(true); // 顺时针转动
} }
else else
{ {
BarrierCounterclockwise(true); // 逆时针转动 BarrierCounterclockwise(true); // 逆时针转动
} }
Thread.Sleep(30); Thread.Sleep(300);
BarrierPos(pos); // 目标位置 BarrierPos(pos); // 目标位置
Thread.Sleep(2000); 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);
} }
/// <summary> /// <summary>
/// 转盘清料 /// 转盘清料
/// </summary> /// </summary>
@ -1106,7 +1211,8 @@ namespace DH.Devices.PLC
if (b) if (b)
{ {
//开启心跳 //开启心跳
Task.Run(async () => await HeartbeatAsync1()); //Task.Run(async () => await HeartbeatAsync1());
_taskFac.StartNew(async () => await HeartbeatAsync1());
} }
} }
@ -1116,7 +1222,7 @@ namespace DH.Devices.PLC
int Register = (int)((productNumber - 1) % 30); int Register = (int)((productNumber - 1) % 30);
currentRegister = 411 + Register; currentRegister = 411 + Register;
WriteUInt16($"D{currentRegister}", value); WriteUInt16($"D{currentRegister}", value);
} }
/// <summary> /// <summary>
@ -1155,6 +1261,20 @@ namespace DH.Devices.PLC
WriteBool(pLCItem.Address, b); WriteBool(pLCItem.Address, b);
} }
/// <summary>
/// 读取挡料电机实时位置
/// </summary>
/// <returns></returns>
public int ReadBarrierRealPos()
{
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机实时位置");
if (pLCItem == null)
{
throw new Exception("未找到挡料电机实时位置点位");
}
return ReadInt16(pLCItem.Address);
}
/// <summary> /// <summary>
/// 读取 挡杆回原点状态 /// 读取 挡杆回原点状态
/// </summary> /// </summary>
@ -1169,7 +1289,7 @@ namespace DH.Devices.PLC
// throw new Exception("未找到挡料电机回原点点位"); // throw new Exception("未找到挡料电机回原点点位");
//} //}
//挡料电机传感器感应点 //挡料电机传感器感应点
return ReadBool("X11"); return ReadBool("X11");
} }
/// <summary> /// <summary>
@ -1180,7 +1300,7 @@ namespace DH.Devices.PLC
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机回原点速度"); PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机回原点速度");
if (pLCItem == null) if (pLCItem == null)
return; return;
WriteUInt32(pLCItem.Address, (uint)speed); WriteInt32(pLCItem.Address, speed);
} }
@ -1192,7 +1312,7 @@ namespace DH.Devices.PLC
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机位置"); PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "挡料电机位置");
if (pLCItem == null) if (pLCItem == null)
return; return;
WriteUInt16(pLCItem.Address, (ushort)value); WriteInt16(pLCItem.Address, (short)value);
} }
@ -1253,12 +1373,13 @@ namespace DH.Devices.PLC
/// <exception cref="Exception"></exception> /// <exception cref="Exception"></exception>
public bool ReadMotorToZero() public bool ReadMotorToZero()
{ {
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进原点"); //PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进原点");
if (pLCItem == null) //if (pLCItem == null)
{ //{
throw new Exception("未找到挡料电机回原点点位"); // throw new Exception("未找到挡料电机回原点点位");
} //}
return ReadBool(pLCItem.Address); //return ReadBool(pLCItem.Address);
return ReadBool("X10");
} }
@ -1271,7 +1392,7 @@ namespace DH.Devices.PLC
PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进位置"); PLCItem? pLCItem = PLCItemList.FirstOrDefault(u => u.Name == "相机步进位置");
if (pLCItem == null) if (pLCItem == null)
return; return;
WriteUInt16(pLCItem.Address, (ushort)value); WriteInt32(pLCItem.Address, (ushort)value);
} }
@ -1285,7 +1406,7 @@ namespace DH.Devices.PLC
{ {
throw new Exception("未找到相机步进实时位置"); throw new Exception("未找到相机步进实时位置");
} }
return ReadInt16(pLCItem.Address); return ReadInt32(pLCItem.Address);
} }

View File

@ -10,6 +10,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<ApplicationIcon>assets\favicon.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
@ -22,6 +23,7 @@
<ItemGroup> <ItemGroup>
<Content Include="assets\favicon.ico" />
<Content Include="db\config.json"> <Content Include="db\config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@ -53,6 +53,7 @@
iptName.PlaceholderText = "请输入用户名"; iptName.PlaceholderText = "请输入用户名";
iptName.Size = new Size(227, 37); iptName.Size = new Size(227, 37);
iptName.TabIndex = 1; iptName.TabIndex = 1;
iptName.Text = "user";
// //
// iptPwd // iptPwd
// //
@ -62,6 +63,7 @@
iptPwd.PlaceholderText = "请输入密码"; iptPwd.PlaceholderText = "请输入密码";
iptPwd.Size = new Size(227, 37); iptPwd.Size = new Size(227, 37);
iptPwd.TabIndex = 2; iptPwd.TabIndex = 2;
iptPwd.Text = "123";
iptPwd.UseSystemPasswordChar = true; iptPwd.UseSystemPasswordChar = true;
// //
// button_cancel // button_cancel
@ -101,7 +103,6 @@
Name = "LoginWindow"; Name = "LoginWindow";
StartPosition = FormStartPosition.CenterScreen; StartPosition = FormStartPosition.CenterScreen;
Text = "登录界面"; Text = "登录界面";
ResumeLayout(false); ResumeLayout(false);
} }

File diff suppressed because it is too large Load Diff

View File

@ -632,49 +632,7 @@ namespace DHSoftware
segmented1.Items.Remove(itemToHide); segmented1.Items.Remove(itemToHide);
} }
public void LoadScheme()
{
try
{
//方案配置初始化
SchemeHelper.Initialize();
//读取方案列表
List<string> list = SchemeHelper.GetAllSchemes();
string CurrentScheme = "默认方案";
//如果是空,新增默认数据
if (list == null || list.Count <= 0)
{
list = new() { CurrentScheme };
//显示到方案列表
sltProjects.Items.Clear();
sltProjects.Items.Add(CurrentScheme);
//保存到方案配置
SchemeHelper.AddScheme(CurrentScheme);
SchemeHelper.SetCurrentScheme(CurrentScheme);
//新构建配置文件
ConfigHelper.InitializeScheme(CurrentScheme);
sltProjects.SelectedIndex = 0;
}
else
{
foreach (string s in list)
{
sltProjects.Items.Add(s);
}
CurrentScheme = SchemeHelper.GetCurrentScheme();
sltProjects.SelectedValue = CurrentScheme;
}
SystemModel.CurrentScheme = CurrentScheme;
//加载当前方案配置
ConfigHelper.LoadConfig();
}
catch (Exception ex)
{
AntdUI.Message.error(this, ex.Message, autoClose: 3);
}
}
public void ConnectCamera() public void ConnectCamera()
{ {
@ -973,7 +931,36 @@ namespace DHSoftware
lblUPH.Text = UPM.ToString(); lblUPH.Text = UPM.ToString();
})); }));
} }
public void LoadScheme()
{
try
{
// 初始化方案配置(会自动创建默认方案)
SchemeHelper.Initialize();
// 读取方案列表
var schemes = SchemeHelper.GetAllSchemes();
sltProjects.Items.Clear();
// 绑定方案到下拉列表
foreach (var scheme in schemes)
{
sltProjects.Items.Add(scheme);
}
// 设置当前选中的方案
string currentScheme = SchemeHelper.GetCurrentScheme();
sltProjects.SelectedValue = currentScheme;
SystemModel.CurrentScheme = currentScheme;
// 加载当前方案配置
ConfigHelper.LoadConfig();
}
catch (Exception ex)
{
AntdUI.Message.error(this, ex.Message, autoClose: 3);
}
}
private void BtnDeleteProject_Click(object? sender, EventArgs e) private void BtnDeleteProject_Click(object? sender, EventArgs e)
{ {
try try
@ -983,29 +970,21 @@ namespace DHSoftware
var result = AntdUI.Modal.open(this, "删除警告!", "确认要删除该方案吗?", TType.Warn); var result = AntdUI.Modal.open(this, "删除警告!", "确认要删除该方案吗?", TType.Warn);
if (result == DialogResult.OK) if (result == DialogResult.OK)
{ {
string schemeToDelete = sltProjects.Text;
int selectedIndex = sltProjects.SelectedIndex; int selectedIndex = sltProjects.SelectedIndex;
// 删除当前选中项 // 删除方案SchemeHelper会自动处理当前方案的切换
SchemeHelper.DeleteScheme(sltProjects.Text); SchemeHelper.DeleteScheme(schemeToDelete);
ConfigHelper.DeleteSchemeConfig(sltProjects.Text); ConfigHelper.DeleteSchemeConfig(schemeToDelete);
AntdUI.Message.success(this, $"删除方案{sltProjects.Text}成功!", autoClose: 3);
sltProjects.Items.RemoveAt(selectedIndex);
// 自动选择下一个(如果存在)
if (sltProjects.Items.Count > 0)
{
// 如果删除的不是最后一项,则选中原位置的新项,否则选中最后一项
sltProjects.SelectedIndex = selectedIndex < sltProjects.Items.Count
? selectedIndex
: sltProjects.Items.Count - 1;
SystemModel.CurrentScheme = sltProjects.Text; // 刷新UI
SchemeHelper.SetCurrentScheme(SystemModel.CurrentScheme); LoadScheme();
//加载当前方案配置
ConfigHelper.LoadConfig(); AntdUI.Message.success(this, $"删除方案{schemeToDelete}成功!", autoClose: 3);
}
else // 如果没有方案了,提示用户
if (sltProjects.Items.Count == 0)
{ {
sltProjects.SelectedIndex = -1; // 清空选择
AntdUI.Modal.open(this, "空方案警告!", "当前方案全部删除,需重启程序!", TType.Warn); AntdUI.Modal.open(this, "空方案警告!", "当前方案全部删除,需重启程序!", TType.Warn);
} }
} }
@ -1021,18 +1000,23 @@ namespace DHSoftware
try try
{ {
if (sltProjects.Items.Count == 0 || sltProjects.SelectedIndex == -1) return; if (sltProjects.Items.Count == 0 || sltProjects.SelectedIndex == -1) return;
if (SystemModel.CurrentScheme == sltProjects.Text)
string selectedScheme = sltProjects.Text;
if (SystemModel.CurrentScheme == selectedScheme)
{ {
AntdUI.Message.warn(this, "当前已是该方案,无需重复载入!", autoClose: 3); AntdUI.Message.warn(this, "当前已是该方案,无需重复载入!", autoClose: 3);
return; return;
} }
//修改当前软件当前方案
SystemModel.CurrentScheme = sltProjects.Text; // 设置当前方案
//修改配置当前方案 SchemeHelper.SetCurrentScheme(selectedScheme);
SchemeHelper.SetCurrentScheme(SystemModel.CurrentScheme); SystemModel.CurrentScheme = selectedScheme;
//将配置文件替换为当前方案
// 加载配置
ConfigHelper.LoadConfig(); ConfigHelper.LoadConfig();
AntdUI.Message.success(this, $"载入方案{SystemModel.CurrentScheme}成功!", autoClose: 3);
AntdUI.Message.success(this, $"载入方案{selectedScheme}成功!", autoClose: 3);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1049,31 +1033,27 @@ namespace DHSoftware
{ {
BtnHeight = 0, BtnHeight = 0,
}); });
if (form.submit) if (form.submit)
{ {
string SchemeName = form.SchemeName; string schemeName = form.SchemeName;
//保存到方案配置
SchemeHelper.AddScheme(SchemeName); // 保存到方案配置
SchemeHelper.AddScheme(schemeName);
// 根据选择初始化配置
if (form.NullScheme) if (form.NullScheme)
{ {
//新构建配置文件 ConfigHelper.InitializeScheme(schemeName);
ConfigHelper.InitializeScheme(SchemeName);
} }
else else
{ {
//派生当前方案 ConfigHelper.DeriveScheme(schemeName);
ConfigHelper.DeriveScheme(SchemeName);
} }
//刷新方案列表
sltProjects.Items.Clear(); // 刷新UI
List<string> list = SchemeHelper.GetAllSchemes(); LoadScheme();
foreach (string s in list) AntdUI.Message.success(this, $"新增方案{schemeName}成功!", autoClose: 3);
{
sltProjects.Items.Add(s);
}
string CurrentScheme = SchemeHelper.GetCurrentScheme();
sltProjects.SelectedValue = CurrentScheme;
AntdUI.Message.success(this, $"新增方案{SchemeName}成功!", autoClose: 3);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -1087,11 +1067,84 @@ namespace DHSoftware
public Dictionary<string, SimboObjectDetection> Dectection { get; } = new Dictionary<string, SimboObjectDetection>(); public Dictionary<string, SimboObjectDetection> Dectection { get; } = new Dictionary<string, SimboObjectDetection>();
public XinJEPLCTcpNet PLC { get; } = XinJEPLCTcpNet.Instance; public XinJEPLCTcpNet PLC { get; } = XinJEPLCTcpNet.Instance;
private SLDMotion sLDMotion = new SLDMotion(); private SLDMotion sLDMotion = new SLDMotion();
// 线程控制标志
private volatile bool _isRunning = false;
private Thread _monitorThread;
private void MainWindow_Load(object sender, EventArgs e) private void MainWindow_Load(object sender, EventArgs e)
{ {
//开启按钮监听
// 启动所有监控线程
StartAllMonitors();
} }
private void StartAllMonitors()
{
if (PLC.Connected)
{
if (_monitorThread == null || !_monitorThread.IsAlive)
{
_isRunning = true;
_monitorThread = new Thread(MonitorPlcButtons);
_monitorThread.IsBackground = true; // 后台线程
_monitorThread.Start();
}
}
}
private void MonitorPlcButtons(object? obj)
{
while (_isRunning)
{
try
{
// 读取 PLC 输入点状态
bool startPressed = PLC.ReadBool("X3");
bool resetPressed = PLC.ReadBool("X4");
bool stopPressed = PLC.ReadBool("X5");
bool eStopPressed = PLC.ReadBool("X6");
// 处理按钮状态变化
if (startPressed)
{
PLC.TurnSpeed(0);
PLC.TurnStart(false);
HandleStartButton();
}
if (resetPressed)
{
//ResetProcess();
}
if (stopPressed)
{
HandleStopButton();
}
if (eStopPressed)
{
//EmergencyStop(null, null, null);
}
Thread.Sleep(50); // 降低 CPU 占用,根据实际调整轮询间隔
}
catch (Exception ex)
{
_isRunning = false;
// 记录错误并停止线程
// throw new ProcessException($"按钮监听线程:{ex.Message}");
}
}
}
// 停止监听线程
private void StopMonitoring()
{
_isRunning = false;
if (_monitorThread != null && _monitorThread.IsAlive)
{
_monitorThread.Join(1000); // 等待线程退出
}
}
private bool _isClosing = false; // 状态标志 private bool _isClosing = false; // 状态标志
private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
@ -1122,6 +1175,7 @@ namespace DHSoftware
{ {
PLC.CloseProcess(); PLC.CloseProcess();
} }
StopMonitoring();
_visionEngine.Stop();//释放模型 _visionEngine.Stop();//释放模型
CloseWindow.Instance.Close();// 关闭提示窗口 CloseWindow.Instance.Close();// 关闭提示窗口
//Application.Exit(); //Application.Exit();
@ -1221,11 +1275,14 @@ namespace DHSoftware
private void StartProcess() private async void StartProcess()
{ {
try try
{ {
if (CurrentMachine)
{
return;
}
BatchNO = textBoxBatchNO.Text; BatchNO = textBoxBatchNO.Text;
textBoxBatchNO.ReadOnly = true; textBoxBatchNO.ReadOnly = true;
@ -1314,20 +1371,41 @@ namespace DHSoftware
//mOfflineImageTimer.Start(); //mOfflineImageTimer.Start();
#endregion #endregion
//流程执行时PLC
PLC.StartProcess();
LogAsync(DateTime.Now, LogLevel.Action, "流程启动11111111111完成");
///这里会执行完成后会造成后台线程断断续续会造成界面UI卡顿
//var settings = ConfigModel.DetectionList.Where(u => u.IsEnabled && u.IsAddStation).ToList();
//if (settings != null)
//{
// settings = settings.Where(s => s.IsEnabled).ToList();
// ProductBaseCount = settings.Count;
var settings = _visionEngine.DetectionConfigs.Where(u => u.IsEnabled && u.IsAddStation).ToList(); // for (int i = 0; i < ProductBaseCount * ProductListMulti; i++)
if (settings != null) // {
// ConcurrentDictionary<uint, ProductData> products = new ConcurrentDictionary<uint, ProductData>();
// _productLists.Add(products);
// }
//}
await Task.Run(() =>
{ {
settings = settings.Where(s => s.IsEnabled).ToList(); var settings = ConfigModel.DetectionList.Where(u => u.IsEnabled && u.IsAddStation).ToList();
ProductBaseCount = settings.Count; if (settings != null)
for (int i = 0; i < ProductBaseCount * ProductListMulti; i++)
{ {
ConcurrentDictionary<uint, ProductData> products = new ConcurrentDictionary<uint, ProductData>(); ProductBaseCount = settings.Count;
_productLists.Add(products); _productLists.Clear(); // 清空旧数据
}
}
// 预分配列表容量(减少动态扩容开销)
_productLists.Capacity = ProductBaseCount * ProductListMulti;
for (int i = 0; i < ProductBaseCount * ProductListMulti; i++)
{
_productLists.Add(new ConcurrentDictionary<uint, ProductData>());
}
}
});
// _MGSCameraList = DeviceCollection // _MGSCameraList = DeviceCollection
//.OfType<MGSCameraDriver>() // 直接筛选出 MGSCameraDriver 类型的元素 //.OfType<MGSCameraDriver>() // 直接筛选出 MGSCameraDriver 类型的元素
//.Where(camera => camera.IConfig != null && camera.IConfig.IsEnabled) // 进一步筛选 IConfig 不为 null 且 IsEnabled 为 true //.Where(camera => camera.IConfig != null && camera.IConfig.IsEnabled) // 进一步筛选 IConfig 不为 null 且 IsEnabled 为 true
@ -1337,9 +1415,10 @@ namespace DHSoftware
//流程执行时PLC
PLC.StartProcess();
InitialOEEStatistic(); InitialOEEStatistic();
CurrentMachine = true;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1771,14 +1850,19 @@ namespace DHSoftware
private void HandleStopButton() private void HandleStopButton()
{ {
if (!CurrentMachine)
{
return;
}
textBoxBatchNO.ReadOnly = false; textBoxBatchNO.ReadOnly = false;
btnCreateBatchNO.Enabled = true; btnCreateBatchNO.Enabled = true;
// Cameras.Clear(); // Cameras.Clear();
// Dectection.Clear(); // Dectection.Clear();
// Add the code for the "停止" button click here // Add the code for the "停止" button click here
PLC.TurnStart(false); PLC.StopProcess();
CurrentMachine = true; CurrentMachine = false;
//sLDMotion.Stop(); //sLDMotion.Stop();
} }