chengsc
2 天以前 4c7f2d26fd6041d32f4e291559bc443671493246
Admin.NET/WCS.Application/PLC/PLCTaskAction.cs
@@ -2,13 +2,19 @@
using DocumentFormat.OpenXml.Bibliography;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Drawing.Charts;
using Elastic.Clients.Elasticsearch.Snapshot;
using Furion.Logging;
using Microsoft.AspNetCore.SignalR;
using NewLife.Serialization;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using OnceMi.AspNetCore.OSS;
using Qiniu.Storage;
using System;
using System.Drawing.Drawing2D;
using System.Net.NetworkInformation;
using WCS.Application.Entity;
using WCS.Application.Util;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinExpressIntracityUpdateStoreRequest.Types;
//using WCS.Application.Util;
@@ -35,6 +41,7 @@
    private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
    private static readonly SysCacheService sysCacheService = App.GetRequiredService<SysCacheService>();
    private static readonly SysConfigService _sysConfigService = App.GetService<SysConfigService>();
    private static readonly WcsTaskService _taskService = App.GetService<WcsTaskService>();
    private static List<WcsPlc> listPlc = new List<WcsPlc>();
    private static List<WcsDevice> listPlcDevice = new List<WcsDevice>();
@@ -45,6 +52,7 @@
    private static CancellationTokenSource cts = new CancellationTokenSource();//取消线程标识
    private static List<ModbusUtil> listModbusUtil = new List<ModbusUtil>();
    public static List<ModbusUtil> modbusUtilConn
    {
@@ -80,11 +88,12 @@
        boDrumReversal = _sysConfigService.GetConfigValue<bool>("sys_DrumReversal").Result;
        boOutLock = _sysConfigService.GetConfigValue<bool>("sys_BoOutLock").Result;
        boEnterLock = _sysConfigService.GetConfigValue<bool>("sys_BoEnterLock").Result;
    }
    /// <summary>
    /// 初始化PLC连接
    /// </summary>
    public static void Init()
    public static void Init()
    {
        cts.Cancel();
        listPlc = _db.Queryable<WcsPlc>()
@@ -137,6 +146,7 @@
            StartRead();
            ConnectionStatus();
            StartWatchAlarm();
            AssignTasks();
            //StartWatchPosition();
        }
    }
@@ -202,15 +212,6 @@
                                        var (result, value) = modPlcUtil.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos);
                                        if (result.IsSucceed)
                                        {
                                            //如果是穿梭车,这里发送心跳
                                            if (modPlc.Type == PLCTypeEnum.ShuttleCar)
                                            {
                                                var modHeart = listPlcPosition.Where(s => s.DeviceId == modDevice.Id && s.Text == "心跳").FirstOrDefault();
                                                if (modHeart != null)
                                                {
                                                    modPlcUtil.SetPlcDBValue(modHeart.PosType, modHeart.PlcPos, "1");
                                                }
                                            }
                                            //无流程跳出
                                            if (Convert.ToInt32(value) == 0)
                                                continue;
@@ -258,11 +259,22 @@
                                        var (result, value) = modbusUtil.GetDBValue(modDevice.PosType, modDevice.PlcPos);
                                        if (result.IsSucceed)
                                        {
                                            //如果是穿梭车,这里发送心跳
                                            if (modPlc.Type == PLCTypeEnum.ShuttleCar)
                                            {
                                                var modHeart = listPlcPosition.Where(s => s.DeviceId == modDevice.Id && s.Text == "心跳").FirstOrDefault();
                                                if (modHeart != null)
                                                {
                                                    modbusUtil.SetDBValue(modHeart.PosType, modHeart.PlcPos, "1");
                                                }
                                            }
                                            //无流程跳出
                                            if (value == 0)
                                                continue;
                                            var dto = modDevice.Adapt<WcsDeviceDto>();
                                            dto.Value = value;
                                            dto.PlcIdIP = modPlc.IP;
                                            dto.Type = _modplc.Type;
                                            dto.modbusUtil = modbusUtil;
                                            dto.listStation = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
@@ -320,7 +332,7 @@
                        Thread.Sleep(1000);
                        Thread.Sleep(2000);
                    }
                    catch (OperationCanceledException)
                    {
@@ -334,6 +346,280 @@
            }, cts.Token);
        }
    }
    /// <summary>
    /// 四向车任务分配
    /// </summary>
    private static void AssignTasks()
    {
        Task.Run(() =>
        {
            while (true)
            {
                //Console.WriteLine("开启四向车任务自分配");
                //取消线程 关闭PLC连接
                if (cts.Token.IsCancellationRequested)
                {
                    foreach (var modModBusUtil in listModbusUtil)
                    {
                        if (modModBusUtil != null && modModBusUtil.Connected)
                            modModBusUtil.Close();
                    }
                    break;
                }
                try
                {
                    // 获取密集库未执行任务 根据创建时间排序
                    var waitTask = _db.Queryable<WcsTask>().Where(s => s.IsDelete == false && s.Status == TaskStatusEnum.Wait && s.Type == PLCTypeEnum.ShuttleCar).OrderBy(s => new {s.Levels, s.CreateTime}).First();
                    if (waitTask == null)
                    {
                        continue;
                    }
                    var starLocate = "";
                    var endLocate = "";
                    var taskceng = 0;
                    //01010101: 01排 01列 01层 01深度-此项目不做判断
                    if (waitTask.TaskType == TaskTypeEnum.In )
                    {
                        //入库任务起始巷道就是四向车取货工位
                        if (string.IsNullOrWhiteSpace(waitTask.StartRoadway) || string.IsNullOrWhiteSpace(waitTask.EndLocate))
                        {
                            continue;
                        }
                        taskceng = int.Parse(waitTask.StartRoadway.Substring(4, 2));
                        starLocate = waitTask.StartRoadway;
                        endLocate = waitTask.EndLocate;
                    }
                    else if (waitTask.TaskType == TaskTypeEnum.Out)
                    {
                        //出库任务目标巷道就是四向车放货工位
                        taskceng = int.Parse(waitTask.StartLocate.Substring(4, 2));
                        starLocate = waitTask.StartLocate;
                        endLocate = waitTask.EndRoadway;
                        #region 添加输送线与任务验证
                        var text = "";
                        var devStation = "";
                        var ip = "";
                        var carcon = new carConverModel();
                        if (carcon.conveyorBei.Keys.Contains(endLocate))
                        {
                            text = "输送线北";
                            ip = "10.26.254.10";
                            devStation = carcon.conveyorBei[endLocate];
                        }
                        else if (carcon.conveyorNan.Keys.Contains(endLocate))
                        {
                            text = "输送线南";
                            ip = "10.26.254.11";
                            devStation = carcon.conveyorNan[endLocate];
                        }
                        if (text != "")
                        {
                            //var modPlc = PLCTaskAction.plcs.FirstOrDefault(s => s.Text == text);
                            //var modConn = new PLCUtil(modPlc);
                            var modConn = PLCTaskAction.listPlcConn.First(m => m.PlcIP == ip);
                            var modDevice = PLCTaskAction.plcDevices.First(s => s.StationNum == devStation);
                            var (plcResult, palletVal) = modConn.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos);
                            if (!plcResult.IsSucceed || Convert.ToInt32(palletVal) != 720)
                            {
                                continue;//放货工位没有读取成功或不是空闲
                            }
                            var gongwei = carcon.conveyorRuKu[endLocate];
                            //判断任务
                            var convarTask = _db.Queryable<WcsTask>().First(m => m.IsDelete == false && m.StartLocate == gongwei
                            && m.Type == PLCTypeEnum.ConveyorLine && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing));
                            if (convarTask != null)
                            {
                                continue;//放货工位有任务
                            }
                        }
                        #endregion
                    }
                    else if (waitTask.TaskType == TaskTypeEnum.Move)
                    {
                        taskceng = int.Parse(waitTask.StartLocate.Substring(4, 2));
                        starLocate = waitTask.StartLocate;
                        endLocate = waitTask.EndLocate;
                    }
                    else
                    {
                        continue;
                    }
                    #region 获取当前任务所在层所有空闲小车
                    // 获取有任务的小车编号
                    var taskCarList = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && m.Status == TaskStatusEnum.Wait).Select(m => m.CarNo).Distinct().ToList();
                    // 获取当前任务所在层所有空闲小车(根据小车任务表是否有任务和小车状态共同判断小车是否空闲)
                    var kXCarList = new List<CarInfo>();
                    var carErr = false;//小车是否有失联的
                    foreach (var modbusUtil in listModbusUtil)
                    {
                        //如果小车有未执行的任务,跳出
                        if (taskCarList.Contains(modbusUtil.PlcIP))
                        {
                            continue;
                        }
                        //获取小车的WcsDevice信息
                        var listDevice = listPlcDevice.Where(s => s.PlcId == modbusUtil.PlcId && s.DeviceType == DeviceTypeEnum.Business).ToList();
                        //循环读设备
                        foreach (var modDevice in listDevice)
                        {
                            var (result, value) = modbusUtil.GetDBValue(modDevice.PosType, modDevice.PlcPos);
                            if (result.IsSucceed)
                            {
                                //获取工位WCSPLCPosition信息
                                var plcPosition = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
                                if (value == 3)
                                {
                                    var modCarDl = plcPosition.FirstOrDefault(s => s.Text == "电池电量");
                                    var (resultDl, valueDl) = modbusUtil.GetDBValue(modCarDl.PosType, modCarDl.PlcPos);
                                    if (resultDl.IsSucceed && valueDl> (int)FourWayCarDLEnum.Dl)
                                    {
                                        //写入结束充电命令
                                        var modCdEnd = plcPosition.FirstOrDefault(s => s.Text == "充电命令");
                                        var resultDl22 = modbusUtil.SetDBValue(modCdEnd.PosType, modCdEnd.PlcPos.ToString(), "3") ;
                                        carErr = true;
                                        break; //暂缓分配,防止同层小车关机或失联导致阻挡路径
                                    }
                                }
                                var modCarPall = plcPosition.FirstOrDefault(s => s.Text == "托盘检测");
                                var (resultPall, valuePall) = modbusUtil.GetDBValue(modCarPall.PosType, modCarPall.PlcPos);
                                if (resultPall.IsSucceed && valuePall  == 1)  //1有托盘 2无托盘
                                {
                                    break; //暂缓分配
                                }
                                //小车空闲加入集合
                                if (value == 1)
                                {
                                    var modStationX = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(X)");
                                    var (resultx, valuex) = modbusUtil.GetDBValue(modStationX.PosType, modStationX.PlcPos);
                                    var modStationY = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(Y)");
                                    var (resulty, valuey) = modbusUtil.GetDBValue(modStationY.PosType, modStationY.PlcPos);
                                    var modStationZ = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(Z)");
                                    var (resultz, valuez) = modbusUtil.GetDBValue(modStationZ.PosType, modStationZ.PlcPos);
                                    //小车当前层
                                    var carZ = (int)valuez;
                                    //任务层与小车层相同
                                    if (taskceng == carZ)
                                    {
                                        if (!kXCarList.Any(m => m.CarPlcIp == modbusUtil.PlcIP))
                                        {
                                            var carVal = ((int)valuex).ToString().PadLeft(2, '0') + ((int)valuey).ToString().PadLeft(2, '0') + ((int)valuez).ToString().PadLeft(2, '0');
                                            //小车到取货储位路径
                                            var d = FourWayCarUtil.GetCarPath(carVal, starLocate);
                                            kXCarList.Add(new CarInfo()
                                            {
                                                CarPlcIp = modbusUtil.PlcIP,
                                                X = (int)valuex,
                                                Y = (int)valuey,
                                                Z = (int)valuez,
                                                Level = d.Count,
                                            });
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Console.WriteLine($"读取四向车{modbusUtil.PlcIP}状态失败");
                                carErr = true;
                                break;//有一个小车读取失败跳出方法,暂缓分配,防止同层小车关机或失联导致阻挡路径
                            }
                        }
                        //有小车失联,不分配任务
                        if (carErr)
                        {
                            kXCarList.Clear();//清楚空车记录
                            break;
                        }
                    }
                    #endregion
                    // 获取适合执行当前任务的小车 生成路径(需考虑小车阻阻挡)
                    var assignCar = kXCarList.OrderBy(m => m.Level).FirstOrDefault();
                    if (assignCar == null)
                    {
                        continue;//没有空闲小车
                    }
                    if (assignCar.Level != 1)
                    {
                        //判断小车位置是否与任务的起始储位相同,不相同:获取小车到取货储位路径
                        var carLocate = assignCar.X.ToString().PadLeft(2, '0')+assignCar.Y.ToString().PadLeft(2, '0')+ assignCar.Z.ToString().PadLeft(2, '0');
                        //获取小车去取货储位任务路径
                        var data1 = FourWayCarUtil.GetCarPath(carLocate, starLocate);
                        var datas1 = FourWayCarUtil.GetCarPathUp(data1, 0);
                        if (datas1 == null)
                        {
                            continue;
                        }
                        else
                        {
                            var bl = FourWayCarUtil.AddCarTask(datas1, kXCarList, assignCar, waitTask,0);
                            //分配错误,删除分配信息
                            if (!bl)
                            {
                                var carTask = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && m.TaskNo == waitTask.TaskNo).ToList();
                                _db.Deleteable(carTask).ExecuteCommand();
                            }
                        }
                    }
                    var typeStr = "1";
                    var typeStr2 = 1;
                    if (waitTask.Levels  == 888 )
                    {
                        typeStr = "0";//小车任务是充电任务
                        typeStr2 = 0;
                    }
                    //获取小车去放货储位任务路径
                    var data2 = FourWayCarUtil.GetCarPath(starLocate, endLocate, typeStr);
                    var datas2 = FourWayCarUtil.GetCarPathUp(data2, typeStr2);
                    if (datas2 == null)
                    {
                        continue;
                    }
                    else
                    {
                        var bl = FourWayCarUtil.AddCarTask(datas2,kXCarList,assignCar,waitTask,1);
                        //分配错误,删除分配信息
                        if (!bl)
                        {
                            waitTask.Status = TaskStatusEnum.Wait;
                            _db.Updateable(waitTask).ExecuteCommand();
                            var carTask = _db.Queryable<WcsCarTasks>().Where(m=>m.IsDelete == false && m.TaskNo == waitTask.TaskNo).ToList();
                            _db.Deleteable(carTask).ExecuteCommand();
                        }
                    }
                    Thread.Sleep(3000);
                }
                catch (Exception ex)
                {
                    Log.Error("任务分配发生异常", ex);
                }
            }
        },cts.Token);
    }
    /// <summary>
    /// 连接状态线程
@@ -692,6 +978,10 @@
            }
        });
    }
    /// <summary>
    /// 修改位置信息
    /// </summary>
    /// <param name="modInfo"></param>
    private static void UpdatePosition(PlcPositionInfo modInfo)
    {
        var modTemp = listPositionInfo.FirstOrDefault(s => s.StationNum == modInfo.StationNum && modInfo.Type == s.Type);