using Admin.NET.Core.Service; using COSXML.Network; using DocumentFormat.OpenXml.Bibliography; using DocumentFormat.OpenXml.Drawing; using DocumentFormat.OpenXml.Spreadsheet; using Furion.Logging; using IoTClient; using NewLife.Reflection; using WCS.Application.Entity; using WCS.Application.Util; namespace WCS.Application; public static class PLCService { private static readonly object OLock = new object(); public static bool AGVStatus = false; private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId); private static readonly WcsTaskService _taskService = App.GetService(); private static readonly SysCacheService sysCacheService = App.GetRequiredService(); private static readonly SysConfigService _sysConfigService = App.GetRequiredService(); private static Dictionary dicTaskNo = new Dictionary(); public static void OnChangeEvent(object sender, EventArgs e) { try { var mod = sender as WcsDeviceDto; //Console.WriteLine($"{mod.Text}值为" + mod.Value); switch (mod.Type) { case PLCTypeEnum.ConveyorLine: ConveyorLine(mod); // 托盘输送线 break; case PLCTypeEnum.AGV: AGV(mod); // AGV调度 break; case PLCTypeEnum.ShuttleCar: //穿梭车 ShuttleCar(mod); break; case PLCTypeEnum.RobotPalletizer: RobotPalletizer(mod);//码垛机器人 break; case PLCTypeEnum.PalletMachine: PalletMachine(mod); break; default: break; } } catch (Exception ex) { Log.Error(ex.Message, ex); } } /// /// 拆托机 /// /// private static void PalletMachine(WcsDeviceDto modDevice) { if (modDevice.Value) { //检测到缺托信号执行这里,如果没有取托任务的话就添加一个(储位-拆托机) if (!_db.Queryable() .Where(s => s.Type == PLCTypeEnum.AGV && s.Status <= TaskStatusEnum.Doing && s.EndLocate == AGVStaionEnum.D1.ToString()).Any()) { WcsTask modTask = new WcsTask() { TaskNo = _taskService.GetTaskCode(), TaskType = TaskTypeEnum.Move, Type = PLCTypeEnum.AGV, StartLocate = AGVStorageUtil.GetPalletOutStorage(), EndLocate = AGVStaionEnum.D1.ToString(), PalletNo = "", Status = TaskStatusEnum.Wait, Levels = 3, Origin = "WCS" }; if (modTask.StartLocate.IsNullOrEmpty()) return; _db.Insertable(modTask).ExecuteCommand(); HubUtil.PublicTask(modTask.Adapt()); } } } /// /// 码垛机器人业务处理 /// private static void RobotPalletizer(WcsDeviceDto modDevice) { var plcConn = modDevice.modbusUtil; string station = "B" + modDevice.StationNum; string value = Convert.ToString(modDevice.Value); if (value == "1") { if (modDevice.Level == DeviceLevelEnum.DB) { //生产工位缺托盘信号,生成任务叫小车去拉空托盘 if (!_db.Queryable().Where(s => s.Type == PLCTypeEnum.AGV && s.Status <= TaskStatusEnum.Doing && s.StartLocate == AGVStaionEnum.D1.ToString() && s.EndLocate == station.ToString()).Any()) { WcsTask modTask = new WcsTask() { TaskNo = _taskService.GetTaskCode(), TaskType = TaskTypeEnum.Move, Type = PLCTypeEnum.AGV, StartLocate = AGVStaionEnum.D1.ToString(), EndLocate = station, PalletNo = "", Status = TaskStatusEnum.Wait, Levels = 4, Origin = "WCS" }; _db.Insertable(modTask).ExecuteCommand(); HubUtil.PublicTask(modTask.Adapt()); } } else if (modDevice.Level == DeviceLevelEnum.Station) { //如果读到信号通知AGV小车拉货(满跺) var endLocate = "C" + modDevice.StationNum; if (!_db.Queryable().Where(s => s.Type == PLCTypeEnum.AGV && s.Status <= TaskStatusEnum.Doing && s.StartLocate == station.ToString()).Any()) { WcsTask modTask = new WcsTask() { TaskNo = _taskService.GetTaskCode(), TaskType = TaskTypeEnum.Move, Type = PLCTypeEnum.AGV, StartLocate = station.ToString(), EndLocate = endLocate, PalletNo = "", Status = TaskStatusEnum.Wait, Levels = 2, Origin = "WCS" }; _db.Insertable(modTask).ExecuteCommand(); HubUtil.PublicTask(modTask.Adapt()); } } } } /// /// 穿梭车业务处理 /// /// private static void ShuttleCar(WcsDeviceDto modDevice) { var plcConn = modDevice.modbusUtil; // 四向车状态 0:未空闲,1:空闲,2:异常 3:充电中 switch (modDevice.Value.ToString()) { case "0": sysCacheService.HashAddOrUpdate("AlarmInfo_Car", plcConn.PlcIP, -1); break; case "1": { sysCacheService.HashAddOrUpdate("AlarmInfo_Car", plcConn.PlcIP, -1); var modPosTaskStatus = modDevice.listStation.FirstOrDefault(s => s.Text == "任务状态"); var (resultTaskStatus, valueTaskStatus) = plcConn.GetDBValue(modPosTaskStatus.PosType, modPosTaskStatus.PlcPos); //判断读取任务状态是否成功 并且任务状态是1 0:无任务,1:任务完成,2:任务取消,3:任务暂停,4:任务异常 5:任务执行中 WcsCarTasks carTaskNext = null;//null 新任务 not null 当前小车&&当前任务 下一节任务 if (resultTaskStatus.IsSucceed && valueTaskStatus == 1) { var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "任务号"); var (resultTask, valueTask) = plcConn.GetDBValue(modPosTask.PosType, modPosTask.PlcPos); //读取任务号 int valueTaskStr = Convert.ToInt32(valueTask); //获取任务信息 根据 任务号、小车编号 var carTask = _db.Queryable().First(m=>m.IsDelete == false && m.Status == TaskStatusEnum.Doing && m.CarTaskNo == valueTaskStr && m.CarNo == modDevice.PlcIdIP); if (carTask == null) { var modRests = modDevice.listStation.FirstOrDefault(s => s.Text == "复位"); plcConn.SetDBValue(modRests.PosType, modRests.PlcPos, "1");//没有找到任务 复位 return; } var modFinshTask = _db.Queryable().First(s => s.Status == TaskStatusEnum.Doing && s.Type == PLCTypeEnum.ShuttleCar && s.TaskNo == carTask.TaskNo); if (modFinshTask == null) { break;//没有查询到总任务 } if (carTask != null && carTask.Status != TaskStatusEnum.Complete) { carTask.Status = TaskStatusEnum.Complete; carTask.UpdateTime = DateTime.Now; _db.Updateable(carTask).ExecuteCommand(); //添加任务明细 var taskMonitor = new WcsTaskMonitor() { TaskNo = carTask.TaskNo, PlcName = modDevice.Text, InteractiveMsg = $"穿梭车反馈任务完成" }; _db.Insertable(taskMonitor).ExecuteCommand(); //下发任务日志 HubUtil.PublicTaskMonitor(taskMonitor.Adapt()); } //获取路径2的任务 下发 carTaskNext = _db.Queryable().Where(m => m.IsDelete == false && m.TaskNo == carTask.TaskNo && m.CarNo == modDevice.PlcIdIP && m.Status <= TaskStatusEnum.Doing).OrderBy(m => m.CreateTime).First(); //总任务下没有其他未执行小车的任务 变更总任务信息 if (carTaskNext == null && modFinshTask != null && modFinshTask.Status != TaskStatusEnum.Complete) { modFinshTask.Status = TaskStatusEnum.Complete; modFinshTask.FinishDate = DateTime.Now; _db.Updateable(modFinshTask).ExecuteCommand(); //反馈WMS系统 任务完成 //HttpService httpService = new HttpService(); //var requestMode = new TaskRequestWMS() //{ // TaskNo = modFinshTask.TaskNo, // PalletNo = modFinshTask.PalletNo, // TaskType = ((int)modFinshTask.TaskType).ToString(), // TaskStatus = ((int)TaskStatusEnum.Complete).ToString() //}; //var modResponseTask = httpService.RequestTask(requestMode).Result; //modFinshTask.IsSuccess = TaskSuccessEnum.Success; //_db.Updateable(modFinshTask).ExecuteCommand(); HubUtil.PublicTask(modFinshTask.Adapt()); } } var modStationX = modDevice.listStation.FirstOrDefault(s => s.Text == "四向车位置(X)"); var (resultx, valuex) = plcConn.GetDBValue(modStationX.PosType, modStationX.PlcPos); var modStationY = modDevice.listStation.FirstOrDefault(s => s.Text == "四向车位置(Y)"); var (resulty, valuey) = plcConn.GetDBValue(modStationY.PosType, modStationY.PlcPos); var modStationZ = modDevice.listStation.FirstOrDefault(s => s.Text == "四向车位置(Z)"); var (resultz, valuez) = plcConn.GetDBValue(modStationZ.PosType, modStationZ.PlcPos); WcsTask modTask; //要下发路径2任务 if (carTaskNext != null) { modTask = _db.Queryable().First(s => s.IsDelete == false && s.TaskNo == carTaskNext.TaskNo && s.Status <= TaskStatusEnum.Doing && s.Type == PLCTypeEnum.ShuttleCar && s.CarIp == modDevice.PlcIdIP); carTaskNext = _db.Queryable().Where(m => m.IsDelete == false && m.TaskNo == modTask.TaskNo && m.CarNo == modDevice.PlcIdIP && m.Status == TaskStatusEnum.Wait).OrderBy(m => m.CreateTime).First(); } else { // 获取任务信息 modTask = _db.Queryable().Where(s => s.Status <= TaskStatusEnum.Doing && s.Type == PLCTypeEnum.ShuttleCar && s.CarIp == modDevice.PlcIdIP).OrderBy(m => m.Levels).OrderBy(m => m.CreateTime).First(); if (modTask == null) { return; } carTaskNext = _db.Queryable().Where(m => m.IsDelete == false && m.TaskNo == modTask.TaskNo && m.CarNo == modDevice.PlcIdIP && m.Status == TaskStatusEnum.Wait).OrderBy(m => m.CreateTime).First(); } //return; if (modTask == null || carTaskNext == null) { //判断小车是否有空闲时间记录 没有:添加 有:判断当前时间与记录时间是否满足5分钟 满足:添加让小车去充电任务 return; } if (carTaskNext.Status == TaskStatusEnum.Doing) { Thread.Sleep(3000); return; } //判断当前任务是否还有前置任务未完成 var preStrs = carTaskNext.PreId.Split(';'); foreach (var preStr in preStrs) { if (string.IsNullOrWhiteSpace(preStr)) { continue; } var preId = long.Parse(preStr); var CarTaskPre = _db.Queryable().First(m => m.Id == preId); if (CarTaskPre.Status <= TaskStatusEnum.Doing) { return;//前置任务未完成 } } //先复位 var modRest = modDevice.listStation.FirstOrDefault(s => s.Text == "复位"); plcConn.SetDBValue(modRest.PosType, modRest.PlcPos, "1"); List listResult = new List(); //获取小车任务号 var carTaskNo = FourWayCarUtil.GetTaskNo(); var modWriteTask = modDevice.listStation.FirstOrDefault(s => s.Text == "写入任务号"); listResult.Add(plcConn.SetDBValue(modWriteTask.PosType, modWriteTask.PlcPos, carTaskNo.ToString())); var modNodeX = modDevice.listStation.FirstOrDefault(s => s.Text == "节点坐标X"); var modNodeY = modDevice.listStation.FirstOrDefault(s => s.Text == "节点坐标Y"); var modNodeZ = modDevice.listStation.FirstOrDefault(s => s.Text == "节点坐标Z"); var modNodeStatus = modDevice.listStation.FirstOrDefault(s => s.Text == "节点举升状态"); int posX = Convert.ToInt32(modNodeX.PlcPos); int posY = Convert.ToInt32(modNodeY.PlcPos); int posZ = Convert.ToInt32(modNodeZ.PlcPos); int posStatus = Convert.ToInt32(modNodeStatus.PlcPos); //交互路径 var execuPath = carTaskNext.ExecutionPath.Split(';'); if (Convert.ToInt32(valuex) != Convert.ToInt32(execuPath[0].Substring(0, 2)) || Convert.ToInt32(valuey) != Convert.ToInt32(execuPath[0].Substring(2, 2)) || Convert.ToInt32(valuez) != Convert.ToInt32(execuPath[0].Substring(4, 2))) { return; //小车位置与路径起始位置不同 ////写入小车当前位置 //listResult.Add(plcConn.SetDBValue(modNodeX.PosType, posX++.ToString(), Convert.ToString(valuex))); //listResult.Add(plcConn.SetDBValue(modNodeY.PosType, posY++.ToString(), Convert.ToString(valuey))); //listResult.Add(plcConn.SetDBValue(modNodeZ.PosType, posZ++.ToString(), Convert.ToString(valuez))); //listResult.Add(plcConn.SetDBValue(modNodeStatus.PosType, posStatus++.ToString(), "3")); } foreach (var ePath in execuPath) { if (string.IsNullOrWhiteSpace(ePath)) { continue; } var epathx = ePath.Substring(0, 2); var epathy = ePath.Substring(2, 2); var epathz = ePath.Substring(4, 2); var epathn = ePath.Substring(6, 1); //写入交互位置 listResult.Add(plcConn.SetDBValue(modNodeX.PosType, posX++.ToString(), epathx)); listResult.Add(plcConn.SetDBValue(modNodeY.PosType, posY++.ToString(), epathy)); listResult.Add(plcConn.SetDBValue(modNodeZ.PosType, posZ++.ToString(), epathz)); listResult.Add(plcConn.SetDBValue(modNodeStatus.PosType, posStatus++.ToString(), epathn)); } //这里是把后面的坐标全写0(为了防止上次任务坐标没被覆盖) while (posX <= 43097) { listResult.Add(plcConn.SetDBValue(modNodeX.PosType, posX++.ToString(), "0")); listResult.Add(plcConn.SetDBValue(modNodeY.PosType, posY++.ToString(), "0")); listResult.Add(plcConn.SetDBValue(modNodeZ.PosType, posZ++.ToString(), "0")); listResult.Add(plcConn.SetDBValue(modNodeStatus.PosType, posStatus++.ToString(), "0")); } if (listResult.All(s => s.IsSucceed)) { var modStart = modDevice.listStation.FirstOrDefault(s => s.Text == "启动命令"); var result = plcConn.SetDBValue(modStart.PosType, modStart.PlcPos, "1"); if (result.IsSucceed) { carTaskNext.Status = TaskStatusEnum.Doing; carTaskNext.CarTaskNo = carTaskNo; _db.Updateable(carTaskNext).ExecuteCommand(); //清除小车空闲时间 var taskMonitor = new WcsTaskMonitor() { TaskNo = carTaskNext.TaskNo, PlcName = modDevice.Text, InteractiveMsg = $"向穿梭车下发任务{carTaskNext.TaskNo}" }; _db.Insertable(taskMonitor).ExecuteCommand(); //下发任务日志 HubUtil.PublicTaskMonitor(taskMonitor.Adapt()); } } } break; case "2": { //小车状态异常 var modPosTaskStatus = modDevice.listStation.FirstOrDefault(s => s.Text == "任务状态"); var (resultTaskStatus, valueTaskStatus) = plcConn.GetDBValue(modPosTaskStatus.PosType, modPosTaskStatus.PlcPos); if (resultTaskStatus.IsSucceed && valueTaskStatus == 1) { var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "任务号"); var (resultTask, valueTask) = plcConn.GetDBValue(modPosTask.PosType, modPosTask.PlcPos); string valueTaskStr = Convert.ToString(valueTask); string strNo = ""; var boNo = dicTaskNo.TryGetValue(modDevice.Id.ToString(), out strNo); if (valueTaskStr != "0" && strNo != valueTaskStr) { var modFinshTask = _db.Queryable().First(s => s.Status == TaskStatusEnum.Doing && s.Type == PLCTypeEnum.ShuttleCar && s.Id.ToString().EndsWith(valueTaskStr)); if (modFinshTask != null && modFinshTask.Status != TaskStatusEnum.Complete) { HttpService httpService = new HttpService(); var requestMode = new TaskRequestWMS() { TaskNo = modFinshTask.TaskNo, PalletNo = modFinshTask.PalletNo, TaskType = ((int)modFinshTask.TaskType).ToString(), TaskStatus = ((int)TaskStatusEnum.Complete).ToString() }; var modResponseTask = httpService.RequestTask(requestMode).Result; modFinshTask.IsSuccess = TaskSuccessEnum.Success; _db.Updateable(modFinshTask).ExecuteCommand(); //下发任务日志 //HubUtil.PublicTask(modFinshTask.Adapt()); //HubUtil.PublicTaskMonitor(taskMonitor.Adapt()); if (dicTaskNo.ContainsKey(modDevice.Id.ToString())) dicTaskNo.Remove(modDevice.Id.ToString()); dicTaskNo.Add(modDevice.Id.ToString(), valueTaskStr); } } } Console.WriteLine($"穿梭车{modDevice.PlcIdIP}异常"); var modPosError = modDevice.listStation.FirstOrDefault(s => s.Text == "错误码"); var (result, valueError) = plcConn.GetDBValue(modPosError.PosType, modPosError.PlcPos); if (result.IsSucceed) { sysCacheService.HashAddOrUpdate("AlarmInfo_Car", plcConn.PlcIP, Convert.ToInt32(valueError)); } } break; default: break; } } /// /// 输送线业务处理 /// /// private static void ConveyorLine(WcsDeviceDto modDevice) { var plcConn = modDevice.PLCUtil; var ledText = ""; switch (modDevice.Value.ToString()) { case "320": { // 申请密集库组 string strMsg = ""; string taskModel = ""; // 获取工位托盘码信息 var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); var (res, palletVal) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (!res.IsSucceed) { break; } var modPosEndLocat = modDevice.listStation.FirstOrDefault(s => s.Text == "目的工位"); //判断入库锁定是否打开 if (PLCTaskAction.boEnterLock) { var (res350, palletVal350) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (res350.IsSucceed && palletVal350 != "350") { ledText += $"申请入库失败\n\n"; ledText += $"托盘号:{palletVal}\n"; ledText += $"入库任务已锁定,请解锁后重试!\n"; LedDisplay(modDevice.LedIP, ledText); } // 写入输送线退回指令 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modPosEndLocat.PlcPos, modDevice.StationNum); if (ret.IsSucceed) { plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "350"); } break; } if (palletVal == null) { var (res350, palletVal350) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (res350.IsSucceed && palletVal350 != "350") { ledText += $"申请入库失败\n\n"; ledText += $"托盘号:{palletVal}\n"; ledText += $"扫描托盘号失败!\n"; LedDisplay(modDevice.LedIP, ledText); } // 写入输送线退回指令 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modPosEndLocat.PlcPos, modDevice.StationNum); if (ret.IsSucceed) { plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "350"); } break; } var http = new HttpService(); string TaskNo = "", EndLocate = ""; strMsg = http.RequestRoadWay(palletVal, modDevice.StationNum, taskModel, "1", ref EndLocate, ref TaskNo); if (!strMsg.Contains("-1")) { // 根据任务号获取起始工位地址,根据起始工位地址获取LEDIP 推送到LED屏幕。 var taskInfo = _db.Queryable().First(w => w.TaskNo == TaskNo); modDevice.LedIP = _db.Queryable() .Where(w => w.StationNum == taskInfo.StartLocate) .Select(s => s.LedIP).First(); // 写入330 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "330"); if (ret.IsSucceed) { // 插入任务明细 var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = TaskNo, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令330:{modDevice.StationNum}工位申请巷道", PalletNo = palletVal, Status = TaskStatusEnum.Complete, StartLocat = modDevice.StationNum, EndLocat = EndLocate, }; // 插入交互日志 _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // 通知任务界面任务已存在更新 请更新界面 HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); // led显示内容 try { ledText += $"任务类型:{taskInfo.TaskType.GetDescription()}\n\n"; ledText += $"任务号:{taskInfo.TaskNo}\n"; ledText += $"托盘号:{taskInfo.PalletNo}\n\n"; ledText += $"起始位:{taskInfo.StartRoadway + " " + taskInfo.StartLocate}\n"; ledText += $"目标位:{taskInfo.EndRoadway + " " + taskInfo.EndLocate}"; LedDisplay(modDevice.LedIP, ledText); } catch (Exception ex) { Log.Error(ex.Message); } } } else { var (res350, palletVal350) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (res350.IsSucceed && palletVal350 != "350") { ledText += $"申请入库失败\n\n"; ledText += $"托盘号:{palletVal}\n"; ledText += $"{strMsg}\n"; LedDisplay(modDevice.LedIP, ledText); } // 写入输送线退回指令 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modPosEndLocat.PlcPos, modDevice.StationNum); if (ret.IsSucceed) { plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "350"); } } } break; case "330": { // 获取工位托盘码信息 var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); var (res, palletVal) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (!res.IsSucceed) { break; } string pallet = palletVal.ToString(); // 获取任务信息 var modTask = _db.Queryable().First(s => s.IsDelete == false && s.PalletNo == pallet && s.Type == PLCTypeEnum.ConveyorLine && (s.Status == TaskStatusEnum.Wait || s.Status == TaskStatusEnum.Doing) && s.TaskType == TaskTypeEnum.In); if (modTask == null) { // 此托盘没有对应的转移任务 led显示 break; } //判断入库锁定是否打开 if (PLCTaskAction.boEnterLock) { break;//入库锁定打开则不执行入库任务 } // 获取四项车取货工位 string endLocatVlue = PLCCommon.RoadwayToStationNum(modTask.EndRoadway, modDevice.StationNum); // 给PLC写入任务数据 var listResult = new List(); // 任务号、任务类型、托盘号 var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "任务号"); listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTask.TaskId.ToString())); var modPosTaskType = modDevice.listStation.FirstOrDefault(s => s.Text == "任务类型"); var taskTypeStr = (int)modTask.TaskType; listResult.Add(plcConn.SetPlcDBValue(modPosTaskType.PosType, modDevice.DbNumber, modPosTaskType.PlcPos, taskTypeStr.ToString())); var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "托盘码"); listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTask.PalletNo)); // 起始工位、目的工位 var modPosStrLocat = modDevice.listStation.FirstOrDefault(s => s.Text == "起始工位"); listResult.Add(plcConn.SetPlcDBValue(modPosStrLocat.PosType, modDevice.DbNumber, modPosStrLocat.PlcPos, modDevice.StationNum)); var modPosEndLocat = modDevice.listStation.FirstOrDefault(s => s.Text == "目的工位"); listResult.Add(plcConn.SetPlcDBValue(modPosEndLocat.PosType, modDevice.DbNumber, modPosEndLocat.PlcPos, endLocatVlue)); if (listResult.All(s => s.IsSucceed)) { // 将任务状态变更为正在执行 _db.Updateable() .SetColumns(s => s.Status == TaskStatusEnum.Doing) .Where(s => s.Id == modTask.Id) .ExecuteCommand(); // 写入流程字 330 340 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "340"); // 根据任务号获取起始工位地址,根据起始工位地址获取LEDIP 推送到LED屏幕。 modDevice.LedIP = _db.Queryable().Where(w => w.StationNum == modTask.StartLocate).Select(s => s.LedIP).First(); if (ret.IsSucceed) { // 插入任务明细 var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令340:{modDevice.StationNum}储位====》{endLocatVlue}工位", PalletNo = palletVal, Status = TaskStatusEnum.Complete, StartLocat = modDevice.StationNum, EndLocat = endLocatVlue, }; // 插入交互日志 _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // 通知任务界面任务已存在更新 请更新界面 HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); } } } break; case "620": { // 申请储位 更新入库任务(储位地址) 630 var strMsg = ""; var taskModel = ""; //// 根据工位号获取巷道号 //var roadway = PLCCommon.GetRoadwayByStation(modDevice.StationNum); //if (roadway == "") //{ // break; //} // 获取工位托盘码信息 var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); var (res, palletVal) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); if (!res.IsSucceed) { break; } var http = new HttpService(); string TaskNo = ""; // 向WMS申请储位信息 strMsg = http.RequestLocate(palletVal, modDevice.StationNum, taskModel, "roadway", ref TaskNo); if (!strMsg.Contains("-1")) { // 根据任务号获取起始工位地址,根据起始工位地址获取LEDIP 推送到LED屏幕。 var taskInfo = _db.Queryable().First(w => w.TaskNo == TaskNo); modDevice.LedIP = _db.Queryable().Where(w => w.StationNum == taskInfo.StartLocate).Select(s => s.LedIP).First(); // 写入流程字 630 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "630"); if (ret.IsSucceed) { // 插入任务明细 var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = TaskNo, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令340:{modDevice.StationNum}工位申请储位", PalletNo = palletVal, Status = TaskStatusEnum.Complete, StartLocat = modDevice.StationNum, EndLocat = strMsg, }; // 插入交互日志 _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // 通知任务界面任务已存在更新 请更新界面 HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); var ledDevice = PLCTaskAction.plcDevices.First(m => m.StationNum == modDevice.StationNum && m.IsDelete == false && m.DeviceType == DeviceTypeEnum.Business); ledText += $"任务类型:{taskInfo.TaskType.GetDescription()}\n\n"; ledText += $"任务号:{taskInfo.TaskNo}\n"; ledText += $"托盘号:{taskInfo.PalletNo}\n\n"; ledText += $"起始位:{taskInfo.StartRoadway + " " + taskInfo.StartLocate}\n"; ledText += $"目标位:{taskInfo.EndRoadway + " " + taskInfo.EndLocate}"; LedDisplay(modDevice.LedIP, ledText); } } else { // 申请储位失败!LED显示 Log.Error(string.Format($"申请储位失败:{strMsg},读写plc错误")); // led显示内容 var ledDevice = PLCTaskAction.plcDevices.First(m => m.StationNum == modDevice.StationNum && m.IsDelete == false && m.DeviceType == DeviceTypeEnum.Business); ledText += $"申请入库失败\n\n"; ledText += $"{strMsg}\n"; LedDisplay(modDevice.LedIP, ledText); } } break; case "630": { #region plc光电扫描不到托盘后 自动清信息 //// 获取工位托盘码信息 //var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); //var (res, palletVal) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosPallet.PlcPos); //// 获取工位任务号信息 //var modPosTaskNo = modDevice.listStation.FirstOrDefault(m => m.Text == "任务号"); //var (taskRes, taskNoVal) = plcConn.GetPlcDBValue(PLCDataTypeEnum.String, modDevice.DbNumber, modPosTaskNo.PlcPos); //if (!res.IsSucceed || !taskRes.IsSucceed) //{ // break; //} //string pallet = palletVal.ToString(); //string taskNo = taskNoVal.ToString(); //// 获取任务信息 //var modTask = _db.Queryable().First(s => s.IsDelete == false && s.PalletNo == pallet && s.Status == TaskStatusEnum.Doing && s.TaskType == TaskTypeEnum.In && s.TaskNo == taskNo); //if (modTask == null) //{ // // 此托盘没有对应的转移任务 led显示 // break; //} //var sInfo = PLCCommon.GetStokePlc(modTask.EndRoadway, louCeng); //if (string.IsNullOrWhiteSpace(sInfo.Ip)) //{ // //需加上LED显示 // Log.Error(string.Format($"根据巷道获取跺机IP失败,请联系管理员")); // break; //} //// 跺机连接 //var plcStackeConn = PLCTaskAction.listPlcConn.First(m => m.PlcIP == sInfo.Ip); //if (plcStackeConn.Connected) //{ // // 目标排列层 // var endLocate = modTask.EndLocate; // if (string.IsNullOrWhiteSpace(modTask.EndLocate)) // { // Log.Error(string.Format($"目标位置为空,请人工处理,读写plc错误")); // break; // } // // 转换目标工位排列层 03010301 // var paiVal = PLCCommon.GetDjAdress(modTask.EndRoadway.Substring(1, 2), endLocate.Substring(0, 2), endLocate.Substring(6, 2)); // string pai = paiVal.ToString(); // string lie = int.Parse(endLocate.Substring(2, 2)).ToString(); // string ceng = int.Parse(endLocate.Substring(4, 2)).ToString(); // var djmodel = _db.Queryable().First(m => m.IP == sInfo.Ip); // var djMod = PLCTaskAction.plcDevices.First(m => m.PlcId == djmodel.Id // && m.DeviceType == DeviceTypeEnum.Business && m.IsDelete == false); // var djInfos = PLCTaskAction.plcPositions.Where(m => m.IsDelete == false && m.DeviceId == djMod.Id).ToList(); // var djInfo = djInfos.First(m => m.Text == "PLC流程字"); // // 获取跺机当前状态 // var (djRes, djVal) = plcStackeConn.GetPlcDBValue(djMod.PosType, djMod.DbNumber, djMod.PlcPos); // if (!djRes.IsSucceed || djVal.ToString() != "820") // { // // 跺机非空闲等待 // break; // } // // 给PLC写入任务数据 // var listResult = new List(); // // 任务号、任务类型、托盘号 // var modPosTask = djInfos.FirstOrDefault(s => s.Text == "任务号"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosTask.PosType, djMod.DbNumber, modPosTask.PlcPos, modTask.TaskNo)); // var modPosTaskType = djInfos.FirstOrDefault(s => s.Text == "任务类型"); // var taskTypeStr = (int)modTask.TaskType; // listResult.Add(plcStackeConn.SetPlcDBValue(modPosTaskType.PosType, djMod.DbNumber, modPosTaskType.PlcPos, taskTypeStr.ToString())); // var modPosPalletNo = djInfos.FirstOrDefault(s => s.Text == "托盘码"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosPalletNo.PosType, djMod.DbNumber, modPosPalletNo.PlcPos, modTask.PalletNo)); // //起始工位 // var modPosStrStationNum = djInfos.FirstOrDefault(s => s.Text == "起始工位"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosStrStationNum.PosType, djMod.DbNumber, modPosStrStationNum.PlcPos, modDevice.StationNum)); // //取货排、列、层 // var modPosStrPai = djInfos.FirstOrDefault(s => s.Text == "取货排"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosStrPai.PosType, djMod.DbNumber, modPosStrPai.PlcPos, sInfo.Pai)); // var modPosStrLie = djInfos.FirstOrDefault(s => s.Text == "取货列"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosStrLie.PosType, djMod.DbNumber, modPosStrLie.PlcPos, sInfo.Lie)); // var modPosStrCeng = djInfos.FirstOrDefault(s => s.Text == "取货层"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosStrCeng.PosType, djMod.DbNumber, modPosStrCeng.PlcPos, sInfo.Ceng)); // //放货排、列、层 // var modPosEndPai = djInfos.FirstOrDefault(s => s.Text == "放货排"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosEndPai.PosType, djMod.DbNumber, modPosEndPai.PlcPos, pai)); // var modPosEndLie = djInfos.FirstOrDefault(s => s.Text == "放货列"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosEndLie.PosType, djMod.DbNumber, modPosEndLie.PlcPos, lie)); // var modPosEndCeng = djInfos.FirstOrDefault(s => s.Text == "放货层"); // listResult.Add(plcStackeConn.SetPlcDBValue(modPosEndCeng.PosType, djMod.DbNumber, modPosEndCeng.PlcPos, ceng)); // if (listResult.All(s => s.IsSucceed)) // { // // 写入跺机 830 // var retc2 = plcStackeConn.SetPlcDBValue(djMod.PosType, djMod.DbNumber, djMod.WcsPos, "830"); // // 插入任务明细 任务明细实体类 // var modInsertTaskMonitor = new WcsTaskMonitor() // { // TaskNo = modTask.TaskNo, // PlcId = modDevice.Id, // PlcName = modDevice.Text, // PalletNo = modTask.PalletNo, // Status = TaskStatusEnum.Complete, // StartLocat = modDevice.StationNum, // EndLocat = modTask.EndLocate // 目标储位地址 // }; // if (!retc2.IsSucceed) // { // modInsertTaskMonitor.InteractiveMsg = $"输送线取货工位:{modDevice.StationNum},写入垛机取货任务830失败等待再次写入"; // // 插入交互日志 // _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // //下发任务日志 // HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); // break; // } // modInsertTaskMonitor.InteractiveMsg = $"跺机写入指令830:{modDevice.StationNum}工位====》" + modTask.EndLocate + "储位地址!"; // // 插入交互日志 // _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // if (PLCTaskAction.boRefresh) // { // //下发任务日志 // HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); // } // } //} #endregion } break; #region 出库交互 case "420": { #region 托盘到达拣选工位/出库口 // 出库口 // led显示托盘信息 // 写入430 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "430"); if (ret.IsSucceed) { var modPosTask = modDevice.listStation.FirstOrDefault(m => m.Text == "任务号"); var (res, taskVal) = plcConn.GetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos); var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); var (res2, palletVal) = plcConn.GetPlcDBValue(modPosPallet.PosType, modDevice.DbNumber, modPosPallet.PlcPos); var modPosStarStationNum = modDevice.listStation.FirstOrDefault(m => m.Text == "起始工位"); var (res3, starVal) = plcConn.GetPlcDBValue(modPosStarStationNum.PosType, modDevice.DbNumber, modPosStarStationNum.PlcPos); // 插入任务明细 var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = taskVal, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令430:托盘到达{modDevice.StationNum}工位", PalletNo = palletVal, Status = TaskStatusEnum.Complete, StartLocat = starVal, EndLocat = modDevice.StationNum, }; // 插入交互日志 _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // 通知任务界面任务已存在更新 请更新界面 HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); // 根据任务号获取起始工位地址,根据起始工位地址获取LEDIP 推送到LED屏幕。 var taskInfo = _db.Queryable().First(w => w.TaskNo == modInsertTaskMonitor.TaskNo); modDevice.LedIP = _db.Queryable().Where(w => w.StationNum == taskInfo.EndLocate).Select(s => s.LedIP).First(); // led显示内容 // 根据目标工位号获取对应的LEDIP地址 var ledDevice = PLCTaskAction.plcDevices.First(m => m.StationNum == modDevice.StationNum && m.IsDelete == false && m.DeviceType == DeviceTypeEnum.Business && m.PlcId == modDevice.PlcId); ledText += $"出库完成\n\n"; ledText += $"任务号:{taskInfo.TaskNo}\n"; ledText += $"托盘号:{taskInfo.PalletNo}\n\n"; ledText += $"起始位:{taskInfo.StartRoadway + " " + taskInfo.StartLocate}\n"; ledText += $"目标位:{taskInfo.EndRoadway + " " + taskInfo.EndLocate}"; LedDisplay(ledDevice.LedIP, ledText); } // 反馈WMS出库完成 //TaskReques taskReques = new TaskReques(); //taskReques.taskNo = TaskNo; //taskReques.TaskType = "1"; //taskReques.TaskStatus = "2"; //bool bl = wcsMySql.RequestTasks(taskReques); #endregion } break; case "440": { #region 拣选完成,托盘离开工位 // 写入450 var ret = plcConn.SetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.WcsPos, "450"); if (ret.IsSucceed) { var modPosTask = modDevice.listStation.FirstOrDefault(m => m.Text == "任务号"); var (res, taskVal) = plcConn.GetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos); var modPosPallet = modDevice.listStation.FirstOrDefault(m => m.Text == "托盘码"); var (res2, palletVal) = plcConn.GetPlcDBValue(modPosPallet.PosType, modDevice.DbNumber, modPosPallet.PlcPos); var modPosStarStationNum = modDevice.listStation.FirstOrDefault(m => m.Text == "起始工位"); var (res3, starVal) = plcConn.GetPlcDBValue(modPosStarStationNum.PosType, modDevice.DbNumber, modPosStarStationNum.PlcPos); string tasknoVal = taskVal.ToString(); var modTask = _db.Queryable().First(m => m.Status == TaskStatusEnum.Doing && m.TaskNo == tasknoVal && m.IsDelete == false); if (modTask == null) { Log.Error(string.Format("输送线440:未找到对应的任务。")); break; } // 改变任务状态 modTask.Status = TaskStatusEnum.Complete; modTask.FinishDate = DateTime.Now; modTask.Levels = 999; _db.Updateable(modTask).ExecuteCommand(); HubUtil.PublicTask(modTask.Adapt()); // 插入任务明细 var modInsertTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.Id, PlcName = modDevice.Text, InteractiveMsg = $"写入指令450:{modDevice.StationNum}出库完成", PalletNo = palletVal, Status = TaskStatusEnum.Complete, StartLocat = starVal.ToString(), EndLocat = modDevice.StationNum, }; if (modTask.Origin == "WMS") { // 反馈WMS var requestMode = new TaskRequestWMS() { TaskNo = modTask.TaskNo + modTask.EndLocate, PalletNo = modTask.PalletNo, TaskType = ((int)TaskTypeEnum.Out).ToString(), TaskStatus = ((int)TaskStatusEnum.Complete).ToString() }; HttpService httpService = new HttpService(); var modResponseTask = httpService.RequestTask(requestMode).Result; if (modResponseTask.StatusCode == 0) { modInsertTaskMonitor.InteractiveMsg += ",返回给WMS任务完成"; } else { Log.Error(string.Format("任务反馈失败:StatusCode:{0};Msg:{1}", modResponseTask.StatusCode, modResponseTask.Msg)); } } // 插入交互日志 _db.Insertable(modInsertTaskMonitor).ExecuteCommand(); // 通知任务界面任务已存在更新 请更新界面 HubUtil.PublicTaskMonitor(modInsertTaskMonitor.Adapt()); // led显示内容 var ledDevice = PLCTaskAction.plcDevices.First(m => m.StationNum == modDevice.StationNum && m.IsDelete == false && m.DeviceType == DeviceTypeEnum.Business && m.PlcId == modDevice.PlcId); ledText += $"出库完成\n\n"; ledText += $"任务号:{modTask.TaskNo}\n"; ledText += $"托盘号:{modTask.PalletNo}\n\n"; ledText += $"起始位:{modTask.StartRoadway + " " + modTask.StartLocate}\n"; ledText += $"目标位:{modTask.EndRoadway + " " + modTask.EndLocate}"; LedDisplay(ledDevice.LedIP, ledText); } #endregion } break; #endregion default: break; } } /// /// AGV业务处理 /// /// private static void AGV(WcsDeviceDto modDevice) { //这里找出来AGV待执行的任务、按照优先级下发一个任务给AGV var listTask = _db.Queryable().Where(s => (s.Status == TaskStatusEnum.Wait || s.Status == TaskStatusEnum.Doing) && s.Type == PLCTypeEnum.AGV).OrderBy(s => s.Levels).ToList(); if (listTask.Count == 0) { return; } foreach (var modTask in listTask) { if (_db.Queryable().Any(s => s.EndLocate == modTask.EndLocate && s.IsDelete == false && s.Status == TaskStatusEnum.Doing && s.Type == PLCTypeEnum.AGV )) { continue; // 有目的位置一致且正在执行的任务 } //下发AGV任务 AgvTaskInput input = new AgvTaskInput() { ReqCode = modTask.Id.ToString(), TaskCode = modTask.TaskNo, CtnrCode = modTask.PalletNo, PositionCodePath = new List() { new PositionCodePathItem(){ PositionCode = modTask.StartLocate }, new PositionCodePathItem(){ PositionCode = modTask.EndLocate } } }; input.TaskTyp = "1" + modTask.StartLocate.Substring(0, 1) + modTask.EndLocate.Substring(0, 1); var response = new HttpService().GenAgvSchedulingTask(input).Result; if (response.code == "0") { AGVStatus = true; modTask.Status = TaskStatusEnum.Doing; _db.Updateable(modTask).ExecuteCommand(); var modTaskMonitor = new WcsTaskMonitor() { TaskNo = modTask.TaskNo, PlcId = modDevice.modPlc.Id, PlcName = modDevice.modPlc.IP, InteractiveMsg = "向AGV小车下发任务" }; _db.Insertable(modTaskMonitor).ExecuteCommand(); //下发任务日志 HubUtil.PublicTask(modTask.Adapt()); HubUtil.PublicTaskMonitor(modTaskMonitor.Adapt()); } Console.WriteLine(response.ToJson()); return; } Thread.Sleep(3000); } /// /// Led屏展示信息 /// /// 地址 /// 上方区域 /// 中间区域 /// 底部区域 private static void LedDisplay(string ip, string top, string content, string foot) { try { LedDll Led = new LedDll(); Led.LEDstr(ip, top, content, foot); } catch (Exception ex) { Log.Error(ex.Message); } } /// /// LED信息展示 /// /// /// private static void LedDisplay(string ip, string text) { try { LedDll Led = new LedDll(); Led.ConsoleLeds(ip, text); // 设置实例 //Led.ConsoleLeds("10.18.51.238", $"任务类型:{TaskTypeEnum.Move.GetDescription()}\n\n任务号:TK2024102100001\n托盘号:LN000145\n\n起始位:033\n目标位:R01-02010102"); } catch (Exception ex) { Log.Error(ex.Message); } } private static void Test(WcsDeviceDto modDevice) { //卷帘门2申请打开 //var result = modDevice.PLCUtil.SetPlcDBValue(PLCDataTypeEnum.Short, "DB1000", "1152", "10"); //卷帘门2申请关闭 //var result = modDevice.PLCUtil.SetPlcDBValue(PLCDataTypeEnum.Short, "DB1000", "1152", "30"); //卷帘门3申请打开 //var result = modDevice.PLCUtil.SetPlcDBValue(PLCDataTypeEnum.Short, "DB1000", "1154", "10"); //卷帘门3申请关闭 //var result = modDevice.PLCUtil.SetPlcDBValue(PLCDataTypeEnum.Short, "DB1000", "1154", "30"); //C口AGV放托盘完成申请入库 var result = modDevice.PLCUtil.SetPlcDBValue(PLCDataTypeEnum.Short, "DB1000", "1156", "100"); ////写死测试读string //var (res, val) = modDevice.PLCUtil.GetPlcDBValue(PLCDataTypeEnum.String, "DB100", "64"); //Console.WriteLine("DB100.64----" + val); ////测试批量读取 //Dictionary listaddress = new Dictionary(); //foreach (var modStation in modDevice.listStation) //{ // listaddress.Add(modStation.PlcPos, modStation.PosType); //} //var result = modDevice.PLCUtil.GetPlcBatchDBValue(listaddress); //if (result.Value.Count > 0) //{ // foreach (var value in result.Value) // { // Console.WriteLine("地址" + value.Key + "----值" + value, value); // } //} //if (!result.IsSucceed) //{ // foreach (var err in result.ErrList) // { // Console.WriteLine(err); // } // if (result.Value.Count > 0)//有错误的也有成功的 // { // } //} //if (modDevice.Value == 820) //{ // //测试写入830 // //var result = mod.PLCUtil.SetPlcDBValue(mod.PosType.Value, mod.DbNumber, mod.PlcPos, "830"); // ////写入是否成功 // //if (result.IsSucceed) // //{ // //} //} //else if (modDevice.Value == 840) //{ //} //else if (modDevice.Value == 860) //{ //} } }