using DBHelper; using System; using System.Collections.Generic; using System.Linq; using WCS.Core; using WCS.Entity; using WCS.Entity.Protocol.RGV; using WCS.Service.Extensions; using WCS.Service.Handlers; using WCS.Service.Log; namespace WCS.Service.Works.RGV { [WorkTitle(typeof(RGVHandler), "直穿RGV")] public class 直穿RGV : DeviceWork { private readonly string ConvGroup_1030 = "G1030"; private readonly string RGV8 = "RGV8"; protected override void Do(RGVDevice rgv) { rgv.EX(rgv => { //RGV是自动且空闲的 if (rgv.Data2.WorkMode != RGVMode.自动) throw new DoException($"{rgv.Data2.WorkMode}"); if (rgv.Data2.SystemStatus != RGVRunStatus.空闲) throw new DoException($"{rgv.Data2.SystemStatus}"); if (rgv.Data.Trigger_1 != rgv.Data2.Trigger_1) throw new WarnException("凭证好不一致"); if (rgv.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new DoException("RGV有光电,无法执行任务"); //RGV状态为 RGV到站&&任务完成 时程序认为RGV当前不在取货点 if (rgv.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.RGV到站) && rgv.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.任务完成)) { //下达一个目标为1030的移动任务 rgv.Data.TaskID_1 = 1030; rgv.Data.DestPosition_1 = 1030; rgv.Data.TaskType_1 = RGVTaskType.移动; rgv.Data.Trigger_1++; } var obj = Device.Find(ConvGroup_1030).Create(); obj.WhetherToExecute(); //筛选出有任务号和起始及目标地址的设备 var dev = obj.RGVGetTaskedDevice() ?? throw new WarnException("无可用任务"); DB.Do(db => { var taskids = dev.Select(v => v.Data2.Tasknum); var tasks = db.Default.Set().Where(p => taskids.Contains(p.ID)); if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new WarnException("任务组ID不一致"); if (!tasks.GroupBy(p => p.TaskGroupKey).Any()) throw new WarnException("无任务组ID"); var gw1 = obj.Items.ToArray()[0]; var gw2 = obj.Items.ToArray()[1]; if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0) { if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new WarnException($"{obj.Entity.CODE}目标地址不一致"); } rgv.Data.TaskID_1 = gw1.Data2.Tasknum; rgv.Data.TaskID_2 = gw2.Data2.Tasknum; if (gw1.Data2.Tasknum != 0) { rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort(); rgv.Data.DestPosition_1 = gw1.Data2.Goodsend; } else { rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort(); rgv.Data.DestPosition_1 = gw2.Data2.Goodsend; } rgv.Data.Trigger_1++; foreach (var task in tasks) { var msg = $"下达从{rgv.Data.StartPosition_1}移动至{rgv.Data.DestPosition_1}的RGV PLC指令。"; msg += $"[{task.ID}][{rgv.Data.StartPosition_1}][{rgv.Data.DestPosition_1}[{rgv.Data.Trigger_1}]"; task.CreateStatusLog(db, msg, this.GetType()); } }); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.CODE == RGV8; } } [WorkTitle(typeof(RGVHandler), "涂布环穿")] public class 涂布环穿 : DeviceWork { protected override void Do(RGVDevice obj) { //11号站台是取货点,但不是待命点,如需取货,从九号站台调车 //2号站台是一个待命点,但是为了保证入库取货效率,所有后面会跟一个车 //如果3号站台的小车拦住了后一个小车的放货任务,检测一次最近的空车距离值,如果大于或等于618500并且小于被拦住小车的位置值再进行调车,用于避免无效空跑 obj.EX(rgvDevice => { if (rgvDevice.Data2.Trigger_1 != rgvDevice.Data.Trigger_1) throw new WarnException($"等待执行任务{rgvDevice.Data2.TaskID_1}--{rgvDevice.Data2.TaskID_2}"); if (rgvDevice.Data2.WorkMode != RGVMode.自动) throw new DoException(rgvDevice.Data2.WorkMode.ToString()); if (rgvDevice.Data2.SystemStatus != RGVRunStatus.空闲) throw new DoException(rgvDevice.Data2.SystemStatus.ToString()); //RGV当前是否刚刚完成取货任务,等待放货 if (rgvDevice.IsPut()) { if (!rgvDevice.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new WarnException("RGV无光电,无法放货,请检查实际情况"); //取小车上的任务 DB.Do(db => { var taskids = new List() { rgvDevice.Data2.TaskID_1, rgvDevice.Data2.TaskID_2 }; var tasks = db.Default.Set().Where(p => taskids.Contains(p.ID)); if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new WarnException("任务组ID不一致"); if (!tasks.GroupBy(p => p.TaskGroupKey).Any()) throw new WarnException("无任务组ID"); var destStation = Device.Find(tasks.FirstOrDefault()!.ADDRNEXT).Create(); rgvDevice.Put(destStation, rgvDevice.Data2.TaskID_1, rgvDevice.Data2.TaskID_2); }); return; } //当前有rgv的取货站台 var pickStation = rgvDevice.CurrentStation(); //RGV是否在任何一个站台 if (pickStation != null) { //是否是取货站台 if (pickStation.Entity.Is(DF.涂布RGV取货设备组)) { // 筛选出有任务号和起始及目标地址的设备 var devise = pickStation.RGVGetTaskedDevice(); //是否需要取货 if (devise is { Count: > 0 } && pickStation.IsPickUp(rgvDevice)) { //开始下达取货任务 DB.Do(db => { if (rgvDevice.Data.TaskID_1 != pickStation.Entity.CODE.Replace("G","").ToShort()) throw new WarnException($"目标站台{rgvDevice.Data.TaskID_1}与当前站台{pickStation.Entity.CODE.Replace("G", "").ToShort()}不一致"); if (rgvDevice.Data2.TaskType_1 != RGVTaskType.移动) throw new WarnException($"RGV正在执行{rgvDevice.Data2.TaskType_1}"); if (rgvDevice.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new WarnException("RGV有光电,无法取货,请检查实际情况"); if (!rgvDevice.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.RGV到站)) throw new WarnException("RGV无到站状态,请检查RGV实际状态"); var taskids = devise.Select(v => v.Data2.Tasknum); var tasks = db.Default.Set().Where(p => taskids.Contains(p.ID)); if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new WarnException("任务组ID不一致"); if (!tasks.GroupBy(p => p.TaskGroupKey).Any()) throw new WarnException("无任务组ID"); var gw1 = pickStation.Items.ToArray()[0]; var gw2 = pickStation.Items.ToArray()[1]; if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0) { if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new WarnException($"{rgvDevice.Entity.CODE}目标地址不一致"); } InfoLog.INFO_RGVINFO($"[{rgvDevice.Entity.CODE}]--写入RGV取货任务-开始:{rgvDevice.Data.TaskID_1},{rgvDevice.Data.TaskID_2},{rgvDevice.Data.TaskType_1},{rgvDevice.Data.DestPosition_1},{rgvDevice.Data.Trigger_1}"); rgvDevice.Data.TaskID_1 = gw1.Data2.Tasknum; rgvDevice.Data.TaskID_2 = gw2.Data2.Tasknum; rgvDevice.Data.TaskType_1 = RGVTaskType.取货; rgvDevice.Data.DestPosition_1 = pickStation.Entity.CODE.Replace("G", "").ToShort(); InfoLog.INFO_RGVINFO($"[{rgvDevice.Entity.CODE}]--写入RGV取货任务-结束:{rgvDevice.Data.TaskID_1},{rgvDevice.Data.TaskID_2},{rgvDevice.Data.TaskType_1},{rgvDevice.Data.DestPosition_1},{rgvDevice.Data.Trigger_1}"); rgvDevice.Data.Trigger_1++; foreach (var task in tasks) { var msg = $"下达从{rgvDevice.Data.StartPosition_1}移动至{rgvDevice.Data.DestPosition_1}的RGV PLC指令。"; msg += $"[{task.ID}][{rgvDevice.Data.StartPosition_1}][{rgvDevice.Data.DestPosition_1}[{rgvDevice.Data.Trigger_1}]"; task.CreateStatusLog(db, msg, this.GetType()); } }); return; } if (rgvDevice.RGVList.Count + 1 != 6)//有小车进入维修站时启用该逻辑,避免在正常使用时影响效率,RGVList把自身排除在外了所以需要+1 { //var stationList = rgvDevice.LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组)).Where(v => v.RGVGetTaskedDevice().Any()) // .Where(v => // { // if (v.CurrentRGV() == null) return true; // return false; // }); //if (stationList != null) //{ // var station11 = stationList.MinBy(rgvDevice.Distance); // //该站台到当前小车的范围中没有车 // if (rgvDevice.RGVList.Any(v => station11!.Position <= v.Position && rgvDevice.Position > v.Position)) // { // rgvDevice.Move(station11); // return; // } //} } if (pickStation.Entity.CODE == "G9") { //九站台的小车需要额外检测一下11站台是否需要取货 var station11 = Device.Find("G11").Create(); var station11Dev = station11.RGVGetTaskedDevice(); if (station11Dev != null && station11Dev.Count > 0) { rgvDevice.Move(station11); return; } } //找到自己的后一个小车 var afterRgv = rgvDevice.After(); //自己是否阻挡了该小车 if (afterRgv.Data2.WorkMode == RGVMode.自动 && afterRgv.Data2.SystemStatus != RGVRunStatus.空闲 && rgvDevice.StopedByMe(afterRgv)) { switch (pickStation.Entity.CODE) { case "G2": { if (rgvDevice.RGVList.Count + 1 != 6) break; //此站台因需要进行排队,因此是否需要赶车取决于是否拦住了两个小车的任务 var afterRgv1 = afterRgv.After(); //如果是空闲或者没有拦住他,就不执行赶车 if (afterRgv1.Data2.WorkMode == RGVMode.自动 && (afterRgv1.Data2.SystemStatus == RGVRunStatus.空闲 || !afterRgv.StopedByMe(afterRgv1))) return; break; } case "G3": { if (rgvDevice.RGVList.Count + 1 != 6) break; //为了减少空跑,需要被阻拦的小车后面的小车任务类型为移动并且位置值要大于618500小于被阻拦小车的位置值 var afterRgv1 = afterRgv.After(); if (afterRgv1.Data2.WorkMode == RGVMode.自动 && afterRgv.Data2.TaskType_1 != RGVTaskType.移动 && !(afterRgv1.Position < afterRgv.Position && afterRgv1.Position > 618500)) return; break; } } //找到当前所在站台的下一个取货点 var beforeStation = Device.Where(v => v.Is(DF.涂布RGV取货设备组) && v.CODE != pickStation.Entity.CODE) .Select(v => v.Create()).MinBy(v => pickStation.Distance(v)); //写入移动任务 rgvDevice.Move(beforeStation); return; } if (pickStation.Entity.CODE == "G11") { rgvDevice.Move(Device.Find("G2").Create()); return; } } //是否在一个放货站台 if (pickStation.Entity.Is(DF.涂布RGV放货设备组)) { pickStation = rgvDevice.BeforeStation(); rgvDevice.Move(pickStation); return; } } //此时RGV即没有等待执行的放货任务,也不在任何一个取货点,因此需要调往最近的一个取货点 //找到距离这个RGV最近的一个取货点 //必须所有RGV都是空闲状态时才可以进行初始化 if (rgvDevice.RGVList.Any(v => v.Data2.SystemStatus != RGVRunStatus.空闲)) return; pickStation = rgvDevice.BeforeStation(); rgvDevice.Move(pickStation); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.Is(DF.涂布RGV); } } [WorkTitle(typeof(RGVHandler), "BOPP环穿")] public class BOPP环穿 : DeviceWork { protected override void Do(RGVDevice obj) { obj.EX(obj => { if (obj.Data2.Trigger_1 != obj.Data.Trigger_1) throw new WarnException($"等待执行任务{obj.Data2.TaskID_1}--{obj.Data2.TaskID_2}"); if (obj.Data2.WorkMode != RGVMode.自动) throw new DoException(obj.Data2.WorkMode.ToString()); if (obj.Data2.SystemStatus != RGVRunStatus.空闲) throw new DoException(obj.Data2.SystemStatus.ToString()); //RGV当前是否刚刚完成取货任务,等待放货 if (obj.IsPut()) { if (!obj.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new WarnException("RGV无光电,无法放货,请检查实际情况"); //取小车上的任务 DB.Do(db => { List taskids = new List() { obj.Data2.TaskID_1, obj.Data2.TaskID_2 }; var tasks = db.Default.Set().Where(p => taskids.Contains(p.ID)); if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new WarnException("任务组ID不一致"); if (!tasks.GroupBy(p => p.TaskGroupKey).Any()) throw new WarnException("无任务组ID"); var destStation = Device.Find(tasks.FirstOrDefault().ADDRNEXT).Create(); obj.Put(destStation, obj.Data2.TaskID_1, obj.Data2.TaskID_2); }); return; } var pickStation = obj.CurrentStation(); //RGV是否在任何一个站台 if (pickStation != null) { //是否是取货站台 if (pickStation.Entity.Is(DF.BOPPRGV取货设备组)) { // 筛选出有任务号和起始及目标地址的设备 var devs = pickStation.RGVGetTaskedDevice(); //是否需要取货 if (devs != null && devs.Count() > 0) { //开始下达取货任务 DB.Do(db => { if (obj.Data2.TaskType_1 != RGVTaskType.移动) throw new WarnException($"RGV正在执行{obj.Data2.TaskType_1}"); if (obj.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new WarnException("RGV有光电,无法取货,请检查实际情况"); if (!obj.Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.RGV到站)) throw new WarnException("RGV无到站状态,请检查RGV实际状态"); var taskids = devs.Select(v => v.Data2.Tasknum); var tasks = db.Default.Set().Where(p => taskids.Contains(p.ID)); if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new WarnException("任务组ID不一致"); if (!tasks.GroupBy(p => p.TaskGroupKey).Any()) throw new WarnException("无任务组ID"); var gw1 = pickStation.Items.ToArray()[0]; var gw2 = pickStation.Items.ToArray()[1]; if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0) { if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new WarnException($"{obj.Entity.CODE}目标地址不一致"); } obj.Pick(pickStation, gw1.Data2.Tasknum, gw2.Data2.Tasknum); foreach (var task in tasks) { var msg = $"下达从{obj.Data.StartPosition_1}移动至{obj.Data.DestPosition_1}的RGV PLC指令。"; msg += $"[{task.ID}][{obj.Data.StartPosition_1}][{obj.Data.DestPosition_1}[{obj.Data.Trigger_1}]"; task.CreateStatusLog(db, msg, this.GetType()); } }); return; } ////找到自己的后一个小车 //var afterRgv = obj.After(); ////自己是否阻挡了该小车 //if (afterRgv.Data2.WorkMode == RGVMode.自动 && afterRgv.Data2.SystemStatus != RGVRunStatus.空闲 && obj.StopedByMe(afterRgv)) //{ // //找到当前所在站台的下一个取货点 // var beforeStation = Device.Where(v => v.Is(DF.BOPPRGV取货设备组) && v.CODE != pickStation.Entity.CODE) // .Select(v => v.Create()) // .OrderBy(v => pickStation.Distance(v)) // .FirstOrDefault(); // //写入移动任务 // obj.Move(beforeStation); // return; //} //else //{ // //取前一个取货点 // pickStation = obj.BeforeStation(); // //前一个取货点的小车 // var rgv = pickStation.CurrentRGV(); // //前一个取货点没有车 且没有非空闲目的地为前一个取货点的小车 // if (rgv == null && !obj.RGVList.Any(v => v.Data2.SystemStatus != RGVRunStatus.空闲 && v.Data2.DestPosition_1 == pickStation.Entity.CODE.Replace("G", "").ToShort())) // { // obj.Move(pickStation); // return; // } //} //计算当前RGV拦住小车的数量 var max = obj.RGVList.Count(v => v.Data2.WorkMode == RGVMode.自动 && v.Data2.SystemStatus != RGVRunStatus.空闲 && obj.StopedByMe(v)); if (pickStation.Entity.CODE == "G19" && max > 2) { obj.Move(Device.Find("G23").Create()); } //else if (pickStation.Entity.CODE == "G23" && max > 3) //{ // obj.Move(Device.Find("G19").Create()); //} } //是否在一个放货站台 if (pickStation.Entity.Is(DF.BOPPRGV放货设备组)) { pickStation = obj.BeforeStation(); obj.Move(Device.Find("G23").Create()); } return; } //此时RGV即没有等待执行的放货任务,也不在任何一个取货点,因此需要调往最近的一个取货点 //找到距离这个RGV最近的一个取货点 //必须所有RGV都是空闲状态时才可以进行初始化 if (obj.RGVList.Any(v => v.Data2.SystemStatus != RGVRunStatus.空闲 || v.Data2.WorkMode != RGVMode.自动)) return; pickStation = obj.BeforeStation(); obj.Move(Device.Find("G23").Create()); }); } protected override bool SelectDevice(WCS_DEVICE dev) { return dev.Is(DF.BOPPRGV); } } }