using ServiceCenter.Extensions; using ServiceCenter.Logs; using ServiceCenter.SqlSugars; using SqlSugar; using System.ComponentModel; using WCS.Core; using WCS.Entity; using WCS.WorkEngineering.Extensions; using WCS.WorkEngineering.Protocol.Robot; using WCS.WorkEngineering.Protocol.Station; using WCS.WorkEngineering.WebApi.Controllers; using WCS.WorkEngineering.Worlds; using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags; namespace WCS.WorkEngineering.Systems { /// /// 机械臂 /// [BelongTo(typeof(RingWorld))] [Description("机械臂")] public class 机械臂 : DeviceSystem> { protected override bool ParallelDo => true; protected override bool SaveLogsToFile => true; /// /// 取货点设备集合 /// private Dictionary> PickUpDevices = new(); /// /// 放货设备 /// private Dictionary>> PutDevices = new(); public 机械臂() { //获取所有的机械臂 集合 var devices = Device.All.Where(v => v.HasFlag(DeviceFlags.Robot)); //开始分配 foreach (var roobot in devices) { //取货设备 PickUpDevices.Add(roobot.Code, roobot.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => v).ToList()); PutDevices.Add(roobot.Code, roobot.Targets.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device(v, World)).ToList()); } } public override void Do(Device obj) { #region 处理完成任务 //判断DB520 完成任务确认清除信号 是否为1 if (obj.Data.OkAck == 1 && obj.Data2.TaskFinishId1 == 0 || obj.Data2.TaskFinishId2 == 0) obj.Data.OkAck = 0; if (obj.Data2.TaskFinishId1 > 0 || obj.Data2.TaskFinishId2 > 0) { //处理完成的任务信息 WCS_TaskInfo taskInfo = null; //开始处理 SqlSugarHelper.Do(db => { World.Log($"机械臂任务处理:开始--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Low); //根据DB521任务号获取对应任务 var taskInfoList = db.Default.Queryable().Where(v => v.ID == obj.Data2.TaskFinishId1 || v.ID == obj.Data2.TaskFinishId2).ToList(); foreach (var task in taskInfoList) { if (task.Status != Entity.TaskStatus.StackerExecution) continue; //根据任务类型做不同的处理 switch (task.Type) { case TaskType.SetPlate: //工字轮入库 //完成任务 task.Status = Entity.TaskStatus.Finish; task.EedTime = DateTime.Now; db.Default.Updateable(task).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "入库任务结束"); break; case TaskType.OutDepot: task.Status = Entity.TaskStatus.Finish; task.EedTime = DateTime.Now; db.Default.Updateable(task).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "出库任务结束"); break; case TaskType.TransferDepot: task.Status = Entity.TaskStatus.Finish; task.EedTime = DateTime.Now; db.Default.Updateable(task).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "移库任务结束"); break; } if (task.Status >= Entity.TaskStatus.Finish) task.CompleteOrCancelTasks(db.Default); taskInfo = task; } }); if (taskInfo == null) throw new KnownException("数据库提交事务错误", LogLevelEnum.High); // 写入信号 obj.Data.OkAck = 1; //通知WMS任务完成 if (taskInfo.Status == Entity.TaskStatus.Finish) WmsApi.CompleteTask(taskInfo.ID); if (taskInfo.Type == TaskType.OutDepot && taskInfo.Status == Entity.TaskStatus.ConveyorExecution) WmsApi.SrmPickOutCompleted(taskInfo.ID); World.Log($"机械臂任务处理:结束--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Mid); } #endregion 处理完成任务 //robot是否可以下发任务 if (obj.Data2.VoucherNo != obj.Data.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo},DB521:{obj.Data2.VoucherNo}", LogLevelEnum.Mid); if (obj.Data2.RobotMode != RobotMode.Automatic) throw new KnownException($"robot处于{obj.Data2.RobotMode.GetDescription()}模式", LogLevelEnum.Low); if (obj.Data2.RunStatus != RobotRunStatus.Idle) throw new KnownException($"robot处于{obj.Data2.RunStatus.GetDescription()}状态", LogLevelEnum.High); //上一个周期是不是出库任务 第一次获取返回结果会是false var lastIsOut = obj.Entity.GetFlag("LastIsOut"); obj.Entity.SetFlag("LastIsOut", !lastIsOut); //入库任务优先 或 上一个周期是出库任务并且出库任务无优先 if (lastIsOut) //入库任务 { //判断本次优先执行楼层,并设置下次执行时优先楼层 var floor = obj.Entity.GetFlag("FloorIn"); floor = floor % 2 + 1; obj.Entity.SetFlag("FloorIn", floor); //获取当前机械臂所有的取货站台 var pickUpDevices = obj.Entity.Sources.Where(x => x.HasFlag(DeviceFlags.输送机)).Where(x => x.DeviceGroup.Any()).Select( x => { var group = x.DeviceGroup.Select(s => new Device(s, World)).ToList(); return new Tuple, List>>(new Device(x, World), group); }).ToList(); if (!pickUpDevices.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无取货路径点", LogLevelEnum.High); //获取取货设备的设备组中都是停止运行的 var arrIn = pickUpDevices.Where(x => x.Item2.All(a => !a.Data.Status.HasFlag(StationStatus.Run))) .Where(x => x.Item2.OrderBy(o => o.Entity.Code.ToShort()) //前两个设备中有取货任务的 .Take(2) .Any(a => a.Data2.TaskNumber > 0 && a.Data.Status.HasFlag(StationStatus.PH_Status))) .ToList(); if (!arrIn.Any()) throw new KnownException($"[{obj.Entity.Code}]等待入库任务输送到位", LogLevelEnum.Mid); //等待下发的任务信息 var taskList = new List>>(); SqlSugarHelper.Do(db => { //跟据设备组中第一个设备任务号最小的一个先执行 var devGroup = arrIn.MinBy(x => x.Item2.OrderBy(o => o.Data2.TaskNumber)); foreach (var dev in devGroup.Item2.OrderBy(x => x.Entity.Code.ToShort()).Take(2) ) { var task = db.Default.Queryable().First(v => v.Type == TaskType.SetPlate && v.Status == Entity.TaskStatus.FinishOfShunt && dev.Data2.TaskNumber == v.ID); if (task == null) continue; var res = WmsApi.RingApplyStockInLoc(task.ID, task.Device, dev.Entity.Code, task.Height); task.Status = Entity.TaskStatus.StackerExecution; task.AddrTo = res.ResData.CellNo; task.Line = res.ResData.Row; task.Col = res.ResData.Colomn; task.Layer = res.ResData.Layer; task.Depth = res.ResData.Row; task.LastInteractionPoint = dev.Entity.Code; task.SrmStation = dev.Entity.Code; task.EditWho = "WCS"; db.Default.Updateable(task).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, dev.Entity.Code, task.AddrTo, "任务下发机械臂执行"); taskList.Add(new(task, dev)); } }); if (!taskList.Any()) return; switch (taskList.Count) { case 1: var task = taskList.FirstOrDefault().Item1; var dev = taskList.FirstOrDefault().Item2; //下发任务 obj.Data.TaskNumber1 = task.ID; obj.Data.SLine1 = dev.Entity.Code.ToShort(); obj.Data.SCol1 = 0; obj.Data.SLayer1 = 0; obj.Data.SDepth1 = 0; obj.Data.ELine1 = task.Line.ToShort(); obj.Data.ECol1 = task.Col.ToShort(); obj.Data.ELayer1 = task.Layer.ToShort(); obj.Data.EDepth1 = task.Depth.ToShort(); obj.Data.TaskNumber2 = 0; obj.Data.SLine2 = 0; obj.Data.SCol2 = 0; obj.Data.SLayer2 = 0; obj.Data.SDepth2 = 0; obj.Data.ELine2 = 0; obj.Data.ECol2 = 0; obj.Data.ELayer2 = 0; obj.Data.EDepth2 = 0; obj.Data.TaskSum = taskList.Count.ToShort(); obj.Data.GoodsType = 1; obj.Data.TaskType = 3; obj.Data.VoucherNo++; break; case 2: //一工位取深度较大的任务 var taskInfo = taskList.MaxBy(x => x.Item1.Depth); task = taskInfo.Item1; dev = taskInfo.Item2; obj.Data.TaskNumber1 = task.ID; obj.Data.SLine1 = dev.Entity.Code.ToShort(); obj.Data.SCol1 = 0; obj.Data.SLayer1 = 0; obj.Data.SDepth1 = 0; obj.Data.ELine1 = task.Line.ToShort(); obj.Data.ECol1 = task.Col.ToShort(); obj.Data.ELayer1 = task.Layer.ToShort(); obj.Data.EDepth1 = task.Depth.ToShort(); //二工位取深度较少的值 taskInfo = taskList.MinBy(x => x.Item1.Depth); task = taskInfo.Item1; dev = taskInfo.Item2; obj.Data.TaskNumber2 = task.ID; obj.Data.SLine2 = dev.Entity.Code.ToShort(); obj.Data.SCol2 = 0; obj.Data.SLayer2 = 0; obj.Data.SDepth2 = 0; obj.Data.ELine2 = task.Line.ToShort(); obj.Data.ECol2 = task.Col.ToShort(); obj.Data.ELayer2 = task.Layer.ToShort(); obj.Data.EDepth2 = task.Depth.ToShort(); obj.Data.TaskSum = taskList.Count.ToShort(); obj.Data.GoodsType = 1; obj.Data.TaskType = 3; obj.Data.VoucherNo++; break; default: throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid); } } else if (!lastIsOut) //出库任务 { //判断本次优先执行楼层,并设置下次执行时优先楼层 var floor = obj.Entity.GetFlag("FloorOut"); floor = floor % 2 + 1; obj.Entity.SetFlag("FloorOut", floor); //获取当前堆垛机所有的取货站台 var arrOut = PutDevices.First(v => v.Key == obj.Entity.Code).Value; if (!arrOut.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无放货路径点", LogLevelEnum.High); //获取可以放货的设备集合 arrOut = arrOut.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status)).ToList();//无光电 if (!arrOut.Any()) throw new KnownException($"[{obj.Entity.Code}]等待出库任务输送到位", LogLevelEnum.Mid); WCS_TaskInfo taskInfo = null; SqlSugarHelper.Do(db => { var allOutCode = arrOut.Select(v => v.Entity.Code).ToList(); var task = db.Default.Queryable().Where(v => v.Type == TaskType.OutDepot && v.Status == Entity.TaskStatus.WaitingToExecute) .Where(v => allOutCode.Contains(v.SrmStation)) .OrderByDescending(v => v.Priority) .OrderBy(v => v.AddTime) .First() ?? throw new KnownException($"{obj.Entity.Code}未找到出库任务", LogLevelEnum.High); task.Status = Entity.TaskStatus.StackerExecution; task.LastInteractionPoint = task.Device; task.EditWho = "WCS"; db.Default.Updateable(task).ExecuteCommand(); task.AddWCS_TASK_DTL(db.Default, task.Device, task.SrmStation, "任务下发机械臂执行"); taskInfo = task; }); if (taskInfo == null) throw new KnownException("数据更新错误", LogLevelEnum.High); var addrFrom = taskInfo.AddrFrom.Split("-"); obj.Data.TaskNumber1 = taskInfo.ID; obj.Data.SLine1 = addrFrom[0].ToShort(); obj.Data.SCol1 = addrFrom[1].ToShort(); obj.Data.SLayer1 = addrFrom[2].ToShort(); obj.Data.SDepth1 = addrFrom[3].ToShort(); obj.Data.ELine1 = taskInfo.SrmStation.ToShort(); obj.Data.ECol1 = taskInfo.ProdLine; obj.Data.TaskSum = 1; obj.Data.GoodsType = 1; obj.Data.TaskType = 4; obj.Data.VoucherNo++; } } public override bool Select(Device dev) { return dev.HasFlag(DeviceFlags.Robot); } } }