| | |
| | | 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; |
| | |
| | | |
| | | private static List<ModbusUtil> listModbusUtil = new List<ModbusUtil>(); |
| | | |
| | | |
| | | public static List<ModbusUtil> modbusUtilConn |
| | | { |
| | | get { return listModbusUtil; } |
| | |
| | | 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>() |
| | |
| | | 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; |
| | |
| | | |
| | | |
| | | |
| | | Thread.Sleep(1000); |
| | | Thread.Sleep(2000); |
| | | } |
| | | catch (OperationCanceledException) |
| | | { |
| | |
| | | { |
| | | while (true) |
| | | { |
| | | Console.WriteLine("开启四向车任务自分配"); |
| | | //Console.WriteLine("开启四向车任务自分配"); |
| | | //取消线程 关闭PLC连接 |
| | | if (cts.Token.IsCancellationRequested) |
| | | { |
| | |
| | | } |
| | | try |
| | | { |
| | | |
| | | |
| | | // 获取密集库未执行任务 根据创建时间排序 |
| | | var waitTask = _db.Queryable<WcsTask>().Where(s => s.IsDelete == false && s.Status == TaskStatusEnum.Wait && s.Type == PLCTypeEnum.ShuttleCar).OrderBy(s => s.CreateTime).First(); |
| | | 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深度-此项目不做判断 |
| | | var taskpai = int.Parse(waitTask.StartLocate.Substring(0, 2)); |
| | | var tasklie = int.Parse(waitTask.StartLocate.Substring(2, 2)); |
| | | var taskceng = int.Parse(waitTask.StartLocate.Substring(4, 2)); |
| | | |
| | | 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 获取当前任务所在层所有空闲小车 |
| | | |
| | |
| | | { |
| | | //获取工位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); |
| | | //var modCarju = plcPosition.FirstOrDefault(s => s.Text == "举升位置"); |
| | | //var (resultju, valueju) = modbusUtil.GetDBValue(modCarju.PosType, modCarju.PlcPos); |
| | | //if (resultPall.IsSucceed && valuePall == 1 && resultPall.IsSucceed && valuePall != 1) //1顶货 2子通道 3主通道 |
| | | //{ |
| | | // break; //暂缓分配 |
| | | //} |
| | | if (resultPall.IsSucceed && valuePall == 1) //1有托盘 2无托盘 |
| | | { |
| | | break; //暂缓分配 |
| | | } |
| | | //小车空闲加入集合 |
| | | if (value == 1) |
| | | { |
| | |
| | | { |
| | | 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, waitTask.StartLocate); |
| | | var d = FourWayCarUtil.GetCarPath(carVal, starLocate); |
| | | kXCarList.Add(new CarInfo() |
| | | { |
| | | CarPlcIp = modbusUtil.PlcIP, |
| | |
| | | |
| | | #endregion |
| | | |
| | | #region 获取适合执行当前任务的小车 生成路径(需考虑小车阻阻挡) |
| | | |
| | | // 获取适合执行当前任务的小车 生成路径(需考虑小车阻阻挡) |
| | | var assignCar = kXCarList.OrderBy(m => m.Level).FirstOrDefault(); |
| | | if (assignCar == null) |
| | | { |
| | | continue;//没有空闲小车 |
| | | } |
| | | var data = new List<CarModel>(); |
| | | if (assignCar.Level != 0) |
| | | |
| | | 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, waitTask.StartLocate); |
| | | var datas = FourWayCarUtil.GetCarPathUp(data1, 0); |
| | | data.AddRange(datas); |
| | | 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(waitTask.StartLocate, waitTask.EndLocate, "1"); |
| | | var datas2 = FourWayCarUtil.GetCarPathUp(data2, 1); |
| | | data.AddRange(datas2); |
| | | if (data == null) { continue; } |
| | | |
| | | var preId1 = "";//前置任务Id |
| | | var executionPath1 = "";//交互路径 |
| | | var executionPath2 = "";//交互路径 |
| | | var path = "";//所有路径 |
| | | var isOk = "1"; //是否完整路径 1完整 2 两条路径 |
| | | for (int i = 0; i < data.Count; i++) |
| | | { |
| | | //路径节点 |
| | | var pathXYZ = data[i].X.ToString().PadLeft(2, '0') + data[i].Y.ToString().PadLeft(2, '0') + data[i].Z.ToString().PadLeft(2, '0')+ data[i].NodeCom.ToString(); |
| | | path += pathXYZ + ";"; |
| | | |
| | | //获取等待或正在执行的任务中包含当前节点的小车任务 |
| | | var taskList = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing) && m.Path.Contains(pathXYZ)).Select(m => m.Id).Distinct().ToList(); |
| | | |
| | | foreach (var item in taskList) |
| | | { |
| | | //判断如果是完整路径 记录交互路径 |
| | | if (isOk == "1") |
| | | { |
| | | //if (i == 0) |
| | | //{ |
| | | // return;//第一个节点有和其他任务路径冲突,无法避免 |
| | | //} |
| | | var pathXYZQian = data[i - 1].X.ToString().PadLeft(2, '0') + data[i - 1].Y.ToString().PadLeft(2, '0') + data[i - 1].Z.ToString().PadLeft(2, '0') + data[i].NodeCom.ToString(); |
| | | if (!executionPath1.Contains(pathXYZQian)) |
| | | { |
| | | executionPath1 += pathXYZQian + ";"; |
| | | } |
| | | executionPath2 += pathXYZQian + ";"; |
| | | } |
| | | //判断添加前置任务Id |
| | | if (!preId1.Contains(item + "")) |
| | | { |
| | | preId1 += item + ";"; |
| | | } |
| | | |
| | | isOk = "2"; |
| | | } |
| | | |
| | | if (data[i].IsSendPlc) |
| | | { |
| | | if (isOk == "1") |
| | | { |
| | | executionPath1 += pathXYZ + ";"; |
| | | } |
| | | else |
| | | { |
| | | executionPath2 += pathXYZ + ";"; |
| | | } |
| | | |
| | | } |
| | | |
| | | var data2 = FourWayCarUtil.GetCarPath(starLocate, endLocate, typeStr); |
| | | var datas2 = FourWayCarUtil.GetCarPathUp(data2, typeStr2); |
| | | |
| | | if (datas2 == null) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 判断是否有空闲小车阻挡路径 3 |
| | | var preId3 = "";//前置任务Id |
| | | foreach (var item in kXCarList) |
| | | else |
| | | { |
| | | if (item == assignCar) |
| | | var bl = FourWayCarUtil.AddCarTask(datas2,kXCarList,assignCar,waitTask,1); |
| | | //分配错误,删除分配信息 |
| | | if (!bl) |
| | | { |
| | | continue;//排除当前分配任务的小车 |
| | | } |
| | | //小车位置 |
| | | var carXYZ = item.X.ToString().PadLeft(2, '0') + item.Y.ToString().PadLeft(2, '0') + item.Z.ToString().PadLeft(2, '0') ; |
| | | //分配的任务路径中 当前小车是否阻挡 |
| | | if (path.Contains(carXYZ)) |
| | | { |
| | | //获取等待或正在执行的任务中包含当前节点的小车任务,不会有太多任务,同层有几个小车最多有几个任务 |
| | | var taskList3 = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing)).ToList(); |
| | | |
| | | var str3 = "";//所有已分配或执行的任务全路径之和 |
| | | |
| | | foreach (var item2 in taskList3) |
| | | { |
| | | str3 += item2.Path; |
| | | } |
| | | var endLocate3 = ""; |
| | | var executionPath3 = ""; |
| | | var path3 = ""; |
| | | var datas3 = new List<CarModel>(); |
| | | //查找目标位置 |
| | | while (endLocate3 == "" || datas3.Count == 0 || datas3 == null) |
| | | { |
| | | endLocate3 = FourWayCarUtil.GetCarEndLocation(carXYZ, str3); |
| | | var data3 = FourWayCarUtil.GetCarPath(carXYZ, endLocate3, "0"); |
| | | datas3 = FourWayCarUtil.GetCarPathUp(data3, 0); |
| | | } |
| | | foreach (var itemPath in datas3) |
| | | { |
| | | var pathXYZ = itemPath.X.ToString().PadLeft(2, '0') + itemPath.Y.ToString().PadLeft(2, '0') + itemPath.Z.ToString().PadLeft(2, '0') + itemPath.NodeCom.ToString(); |
| | | |
| | | path3 += pathXYZ + ";"; |
| | | if (itemPath.IsSendPlc) |
| | | { |
| | | executionPath3 += pathXYZ + ";"; |
| | | } |
| | | } |
| | | WcsTask modTask = new WcsTask() |
| | | { |
| | | TaskNo = _taskService.GetTaskCode(), |
| | | TaskType = TaskTypeEnum.Move, |
| | | Type = PLCTypeEnum.ShuttleCar, |
| | | StartLocate = carXYZ, |
| | | EndLocate = endLocate3, |
| | | PalletNo = "", |
| | | Status = TaskStatusEnum.Wait, |
| | | Levels = 2, |
| | | Origin = "WCS" |
| | | }; |
| | | _db.Insertable(modTask).ExecuteCommand(); |
| | | HubUtil.PublicTask(modTask.Adapt<WcsTaskOutput>()); |
| | | //移动小车 |
| | | var carTaskYC = new WcsCarTasks() |
| | | { |
| | | TaskNo = modTask.TaskNo, |
| | | PreId = "", |
| | | ExecutionPath = executionPath3, |
| | | Path = path3, |
| | | CarNo = item.CarPlcIp, |
| | | Status = TaskStatusEnum.Wait |
| | | }; |
| | | var idLong = _db.Insertable(carTaskYC).ExecuteReturnBigIdentity(); |
| | | preId3 += idLong + ";"; |
| | | 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(); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 判断现有任务中最终节点是否在当前分配路径中,如有 添加移走小车任务并加入前置任务 4 |
| | | |
| | | //获取等待或正在执行的任务中包含当前节点的小车任务,不会有太多任务,同层有几个小车最多有几个任务 |
| | | var taskList4 = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && (m.Status == TaskStatusEnum.Wait || m.Status == TaskStatusEnum.Doing)).ToList(); |
| | | var preId4 = "";//前置任务Id |
| | | var str4 = "";//所有已分配或执行的任务全路径之和 |
| | | |
| | | foreach (var item in taskList4) |
| | | { |
| | | str4 += item.Path; |
| | | } |
| | | //判断现有任务中最终节点是否在当前分配路径中,如有 添加移走小车任务并加入前置任务 |
| | | foreach (var item in taskList4) |
| | | { |
| | | var lastPathList = item.ExecutionPath.Split(';'); |
| | | // a;b;c; 最后一个位是“”,所以lastPathList.Length - 2 |
| | | var lastPath = lastPathList[lastPathList.Length - 2]; |
| | | |
| | | //如果此此分配路径包含醉舞中最终节点路径,添加移走小车 |
| | | if (path.Contains(lastPath)) |
| | | { |
| | | var endLocate = ""; |
| | | var executionPath4 = ""; |
| | | var path4 = ""; |
| | | var datas4 = new List<CarModel>(); |
| | | //查找目标位置 |
| | | while (endLocate == "" || datas4.Count == 0 || datas4 == null) |
| | | { |
| | | endLocate = FourWayCarUtil.GetCarEndLocation(lastPath, str4); |
| | | var data4 = FourWayCarUtil.GetCarPath(lastPath, endLocate); |
| | | datas4 = FourWayCarUtil.GetCarPathUp(data4, 0); |
| | | } |
| | | foreach (var itemPath in datas4) |
| | | { |
| | | var pathXYZ = itemPath.X.ToString().PadLeft(2, '0') + itemPath.Y.ToString().PadLeft(2, '0') + itemPath.Z.ToString().PadLeft(2, '0') + itemPath.NodeCom.ToString(); |
| | | |
| | | path4 += pathXYZ + ";"; |
| | | if (itemPath.IsSendPlc) |
| | | { |
| | | executionPath4 += pathXYZ + ";"; |
| | | } |
| | | } |
| | | WcsTask modTask = new WcsTask() |
| | | { |
| | | TaskNo = _taskService.GetTaskCode(), |
| | | TaskType = TaskTypeEnum.Move, |
| | | Type = PLCTypeEnum.ShuttleCar, |
| | | StartLocate = lastPath, |
| | | EndLocate = endLocate, |
| | | PalletNo = "", |
| | | Status = TaskStatusEnum.Wait, |
| | | Levels = 2, |
| | | Origin = "WCS" |
| | | }; |
| | | _db.Insertable(modTask).ExecuteCommand(); |
| | | HubUtil.PublicTask(modTask.Adapt<WcsTaskOutput>()); |
| | | //移动小车 |
| | | var carTaskYC = new WcsCarTasks() |
| | | { |
| | | TaskNo = modTask.TaskNo, |
| | | PreId = "", |
| | | ExecutionPath = executionPath4, |
| | | Path = path4, |
| | | CarNo = item.CarNo, |
| | | Status = TaskStatusEnum.Wait |
| | | }; |
| | | var idLong = _db.Insertable(carTaskYC).ExecuteReturnBigIdentity(); |
| | | preId4 += idLong + ";"; |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 插入任务数据 改变任务状态 |
| | | |
| | | // 插入四向车任务表 |
| | | var carTask1 = new WcsCarTasks() |
| | | { |
| | | TaskNo = waitTask.TaskNo, |
| | | PreId = preId1+ preId3+preId4, |
| | | ExecutionPath = executionPath1, |
| | | Path = path, |
| | | CarNo = assignCar.CarPlcIp, |
| | | Status = TaskStatusEnum.Wait |
| | | }; |
| | | _db.Insertable(carTask1).ExecuteCommand(); |
| | | if (!string.IsNullOrWhiteSpace(executionPath1) && isOk == "2") |
| | | { |
| | | // 插入四向车任务表 |
| | | var carTask2 = new WcsCarTasks() |
| | | { |
| | | TaskNo = waitTask.TaskNo, |
| | | PreId = preId1, |
| | | ExecutionPath = executionPath2, |
| | | Path = path, |
| | | CarNo = assignCar.CarPlcIp, |
| | | Status = TaskStatusEnum.Wait |
| | | }; |
| | | _db.Insertable(carTask2).ExecuteCommand(); |
| | | } |
| | | // 改变总任务表状态 |
| | | waitTask.Status = TaskStatusEnum.Doing; |
| | | waitTask.UpdateTime = DateTime.Now; |
| | | _db.Updateable(waitTask).ExecuteCommand(); |
| | | HubUtil.PublicTask(waitTask.Adapt<WcsTaskOutput>()); |
| | | |
| | | #endregion |
| | | |
| | | |
| | | Thread.Sleep(3000); |
| | | } |