123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215 |
- using DBHelper;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using WCS.Core;
- using WCS.Entity;
- using WCS.Entity.Protocol;
- using WCS.Entity.Protocol.RGV;
- using WCS.Service.Helpers;
- using WCS.Service.Log;
- namespace WCS.Service.Extensions
- {
- /// <summary>
- /// 输送机设备组
- /// </summary>
- public class StationDeviceGroup : DeviceGroup<IStation520, IStation521, IStation523>
- {
- /// <summary>
- /// 当前设备可用的RGV
- /// </summary>
- private static List<RGVDevice> AllRGVList;
- static StationDeviceGroup()
- {
- AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
- }
- public StationDeviceGroup(WCS_DEVICE entity) : base(entity)
- {
- }
- /// <summary>
- /// 执行输送机设备组任务 单例锁
- /// </summary>
- /// <param name="act"></param>
- public void EX(Action<StationDeviceGroup> act)
- {
- var key = $"WCS:Lock:{Entity.CODE}";
- try
- {
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"[{Entity.CODE}]--触发并发管控");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- act(this);
- }
- catch (DoException ex)
- {
- ex.DoExceptionEX(Entity);
- }
- catch (WarnException ex)
- {
- ex.WarnExceptionEX(Entity);
- }
- catch (Exception ex)
- {
- ex.ExceptionEx(Entity);
- }
- finally
- {
- ProtocolProxy.YG150Redis.Del(key);
- }
- }
- /// <summary>
- /// 当前设备可用的RGV
- /// </summary>
- public List<RGVDevice> RgvList
- {
- get
- {
- return AllRGVList.Where(v => v.LocationList.Any(p => p.Entity == Entity) && v.Data2.WorkMode != 0).ToList();
- }
- }
- /// <summary>
- /// 当前设备环穿组
- /// </summary>
- private List<StationLocation> LoncationList
- {
- get
- {
- var dev = StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE);
- return StationLocation.ALLlocations.Where(v => v.PLC == dev.PLC).ToList();
- }
- }
- /// <summary>
- /// 设备组自身的位置
- /// </summary>
- public float Position
- {
- get
- {
- return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Location;
- }
- }
- /// <summary>
- /// 设备组所在环穿的总长度
- /// </summary>
- public float Length
- {
- get
- {
- return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Length;
- }
- }
- /// <summary>
- /// 设备组是否满足任务执行条件
- /// </summary>
- /// <param name="type">给当前设备组下发任务时需要的请求</param>
- /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
- /// <exception cref="Exception"></exception>
- public void WhetherToExecute(IstationRequest type = IstationRequest.无)
- {
- foreach (var item in Items)
- {
- if (item.Data.VoucherNo != item.Data2.VoucherNo) throw new WarnException($"等待{item.Entity.CODE}执行任务{item.Data.Tasknum},凭证号不一致");
- if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) throw new DoException($"{item.Entity.CODE}运行中");
- if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException($"[{item.Entity.CODE}]无光电");
- }
- }
- /// <summary>
- /// 获取设备组中需要取货的设备
- /// </summary>
- /// <returns></returns>
- public List<Device<IStation520, IStation521, IStation523>> RGVGetTaskedDevice()
- {
- var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
- .Where(v => v.Entity.CODE.ToShort() != v.Data2.Goodsend && v.Data2.Goodsend != 0)
- .ToList();
- return a.Count == 0 ? null : a;
- }
- /// <summary>
- /// 是否可以取货
- /// </summary>
- /// <returns></returns>
- public bool IsPickUp(RGVDevice rgvDevice)
- {
- if (Entity.CODE is "G2" or "G3") return true;
- var emptyQty = ProtocolProxy.YGWMS150Redis.Get("TuBuRgvTaskCount").ToInt();
- int dCount = 0;
- if (emptyQty > 3)
- {
- dCount = emptyQty;
- }
- else
- {
- dCount = Device.Where(v => v.CODE is "G1" or "G1340" or "G1337").Select(v => v.Create<StationDeviceGroup>()).Count(v =>
- {
- var count = v.Items.Count(v => !v.Data3.Status.HasFlag(StationStatus.运行状态位) && !v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum < 10000
- && v.Data3.Status.HasFlag(StationStatus.自动));
- return count == 2 ? true : false;
- });
- }
- var rCount = rgvDevice.RGVList.Count(v => v.Data.DestPosition_1 == 1);
- return rCount < dCount;
- }
- /// <summary>
- /// 入库位置获取需要生产任务的设备及条码信息
- /// </summary>
- /// <returns></returns>
- public List<FinishTaskList<string>> GetBcrValid()
- {
- var list = new List<FinishTaskList<string>>();
- //获取需要执行的设备信息
- foreach (var dev in Items)
- {
- if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态))
- {
- InfoLog.INFO_INFO($"{dev.Entity.CODE}--没有光电");
- continue;
- }
- if (dev.Data2.Request != IstationRequest.扫码入库)
- {
- InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--有光电没有扫码入库请求--1", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- continue;
- };
- if (dev.Data2.Tasknum > 10000)
- {
- InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--有光电有请求,但已有任务号", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- continue;
- }
- var bcr = dev.Entity.BCR();
- var barcode = bcr.Content.Trim('\r');
- if (barcode == "")
- {
- InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--扫码失败,内容为空", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- continue;
- };
- list.Add(new FinishTaskList<string>(barcode, dev.Entity.Create<StationDevice>()));
-
- }
- return list;
- }
- /// <summary>
- /// 获取下一个地址的有效设备
- /// </summary>
- /// <returns></returns>
- public List<FinishTaskList<string>> GetAddressValid()
- {
- var list = new List<FinishTaskList<string>>();
- //获取需要执行的设备信息
- foreach (var dev in Items)
- {
- if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态))
- {
- InfoLog.INFO_INFO($"{dev.Entity.CODE}--没有光电");
- continue;
- }
- if (dev.Data2.Request != IstationRequest.请求分配目标地址)
- {
- InfoLog.INFO_INFO($"{dev.Entity.CODE}--有光电没有分配目标地址请求--2");
- continue;
- };
- if (dev.Data2.Tasknum < 10000)
- {
- InfoLog.INFO_WarnDb($"{dev.Entity.CODE}--有光电有请求没有任务号", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- continue;
- }
- list.Add(new FinishTaskList<string>(dev.Entity.CODE, dev.Entity.Create<StationDevice>()));
- }
- return list;
- }
- /// <summary>
- /// 最近的RGV
- /// </summary>
- /// <returns></returns>
- public RGVDevice RecentRGV()
- {
- return RgvList.OrderBy(v => v.Distance(this)).FirstOrDefault();
- }
- /// <summary>
- /// 计算目标RGV与站台自身的距离
- /// </summary>
- /// <param name="rgv"></param>
- /// <returns></returns>
- public float Distance(RGVDevice rgv)
- {
- return DevEX.Distance(Position, rgv.Position, Length);
- }
- /// <summary>
- /// 计算两个站台之间的距离
- /// </summary>
- /// <param name="rgv"></param>
- /// <returns></returns>
- public float Distance(StationDeviceGroup dev)
- {
- return DevEX.Distance(Position, dev.Position, Length);
- }
- /// <summary>
- /// 当前RGV
- /// </summary>
- /// <returns></returns>
- public RGVDevice CurrentRGV()
- {
- //RGV与站台距离误差为 正负50
- var max = Position + 500;
- var min = Position - 500;
- return RgvList?.FirstOrDefault(v => v.Data2.Position < max && v.Data2.Position > min);
- }
- /// <summary>
- /// 是否需要RGV
- /// </summary>
- /// <returns>true:需要RGV false:不需要RGV</returns>
- public bool NeedRgv()
- {
- var rgvs = Device.Where(v => v.IsRGV()).Select(v => v.Device<IRGV521>());
- var code = Entity.CODE.Replace("G", "").ToShort();
- if (rgvs.Any(v => v.Data.DestPosition_1 == code && v.Data.SystemStatus != RGVRunStatus.空闲))
- throw new WarnException("已有RGV执行中");
- foreach (var item in Items)
- {
- if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) return false;
- if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) return false;
- }
- return true;
- }
- /// <summary>
- /// BCR 站点是否被禁止
- /// </summary>
- /// <returns></returns>
- public bool BcrStationIsForbid()
- {
- var res = true;
- var config = ProtocolProxy.YGWMS150Redis.Get("ForbidTubuEnter").Split(",");
- if (config.Contains(Entity.CODE))
- {
- InfoLog.INFO_WarnDb("当前入库口已被禁用,请联系机修人员了解具体情况", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常);
- res = false;
- };
- return res;
- }
- }
- /// <summary>
- /// 输送机设备
- /// </summary>
- public class StationDevice : Device<IStation520, IStation521, IStation523>
- {
- public StationDevice(WCS_DEVICE entity) : base(entity)
- {
- }
- /// <summary>
- /// 设备组是否满足任务执行条件
- /// </summary>
- /// <param name="type">给当前设备组下发任务时需要的请求</param>
- /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
- /// <exception cref="Exception"></exception>
- public void WhetherToExecute(IstationRequest type = IstationRequest.无)
- {
- //正在运行
- if (Data3.Status.HasFlag(StationStatus.运行状态位)) throw new DoException("运行中");
- //上一次的任务还未执行
- if (Data.VoucherNo != Data2.VoucherNo)
- throw new WarnException($"等待任务[{Data2.Tasknum}]执行");
- //没有光电
- if (!Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException("无光电"); ;
- //没有任务号
- switch (type)
- {
- case IstationRequest.无:
- if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
- throw new WarnException($"设备无任务");
- break;
- case IstationRequest.扫码入库:
- if (Data2.Tasknum > 10000 && Data.Tasknum > 10000)
- throw new WarnException($"设备已有任务任务");
- break;
- case IstationRequest.堆垛机放货完成请求目标地址:
- if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
- throw new WarnException($"设备无任务信息");
- break;
- case IstationRequest.请求分配目标地址:
- if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
- throw new WarnException($"设备无任务信息");
- break;
- }
- //没有请求
- if (type != IstationRequest.无 && Data2.Request != type)
- throw new WarnException($"有光电无{type}请求");
- }
- /// <summary>
- /// 执行输送机任务 单例锁
- /// </summary>
- /// <param name="act"></param>
- public void EX(Action<StationDevice> act)
- {
- var key = $"WCS:Lock:{Entity.CODE}";
- try
- {
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"[{Entity.CODE}]--触发并发管控");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- act(this);
- }
- catch (DoException ex)
- {
- ex.DoExceptionEX(Entity);
- }
- catch (WarnException ex)
- {
- ex.WarnExceptionEX(Entity);
- }
- catch (Exception ex)
- {
- ex.ExceptionEx(Entity);
- }
- finally
- {
- ProtocolProxy.YG150Redis.Del(key);
- }
- }
- }
- /// <summary>
- /// RGV设备
- /// </summary>
- public class RGVDevice : Device<IRGV520, IRGV521, IRGV523>
- {
- static RGVDevice()
- {
- AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
- }
- public RGVDevice(WCS_DEVICE entity) : base(entity)
- {
- }
- /// <summary>
- /// 所有环穿RGV
- /// </summary>
- private static List<RGVDevice> AllRGVList { get; set; }
- /// <summary>
- /// 与当前RGV处于同一环穿的RGV
- /// </summary>
- public List<RGVDevice> RGVList
- {
- get
- {
- //利用WorkMode来排除的环穿维护设备
- return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.PLC.IP == d.DB.PLC.IP)))
- .Where(v => v.Data2.WorkMode != 0)
- .Where(v => v.Entity.CODE != Entity.CODE).ToList();
- }
- }
- /// <summary>
- /// RGV当前位置
- /// </summary>
- public float Position
- {
- get
- {
- return Data2.Position;
- }
- }
- /// <summary>
- /// 与当前RGV处于同一环穿的站台
- /// </summary>
- public List<StationDeviceGroup> LocationList
- {
- get
- {
- return StationLocation.ALLlocations.Where(v => Entity.PROTOCOLS.Any(p => p.DB.PLC.CODE == v.PLC))
- .Select(v => Device.Find(v.Station).Create<StationDeviceGroup>()).ToList();
- }
- }
- /// <summary>
- /// 总长度
- /// </summary>
- public float Length
- {
- get
- {
- return LocationList.FirstOrDefault().Length;
- }
- }
- /// <summary>
- /// 执行RGV任务 单例锁
- /// </summary>
- /// <param name="act"></param>
- public void EX(Action<RGVDevice> act)
- {
- var key = $"WCS:Lock:{Entity.CODE}";
- try
- {
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"[{Entity.CODE}]--触发并发管控");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- act(this);
- }
- catch (DoException ex)
- {
- ex.DoExceptionEX(Entity);
- }
- catch (WarnException ex)
- {
- ex.WarnExceptionEX(Entity);
- }
- catch (Exception ex)
- {
- ex.ExceptionEx(Entity);
- }
- finally
- {
- ProtocolProxy.YG150Redis.Del(key);
- }
- }
- /// <summary>
- /// 获取前一个取货点
- /// </summary>
- /// <returns></returns>
- public StationDeviceGroup BeforeStation()
- {
- var a = LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组) || v.Entity.Is(DF.BOPPRGV取货设备组));
- return LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组) || v.Entity.Is(DF.BOPPRGV取货设备组) && v.Entity.CODE != this.CurrentStation().Entity.CODE).OrderBy(v => Distance(v)).FirstOrDefault();
- }
- /// <summary>
- /// 前一个RGV
- /// </summary>
- /// <returns></returns>
- public RGVDevice Before()
- {
- //按照位置排序
- var arr = RGVList.OrderBy(v => v.Position);
- var rgv = arr.FirstOrDefault(v => v.Position > Position);
- if (rgv == null)
- rgv = arr.LastOrDefault(v => v.Position < Position);
- return rgv;
- }
- /// <summary>
- /// 后一个RGV
- /// </summary>
- /// <returns></returns>
- public RGVDevice After()
- {
- //到当前RGV最近的一个RGV
- return RGVList.OrderBy(v => v.Distance(this)).FirstOrDefault();
- }
- /// <summary>
- /// 获取当前所在的取货站台
- /// </summary>
- /// <returns></returns>
- public StationDeviceGroup CurrentStation()
- {
- return LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组) || v.Entity.Is(DF.涂布RGV放货设备组) || v.Entity.Is(DF.BOPPRGV取货设备组) || v.Entity.Is(DF.BOPPRGV放货设备组)).Where(v =>
- {
- //RGV与站台距离误差为 正负50500
- var max = v.Position + 100;
- var min = v.Position - 100;
- return Data2.Position < max && Data2.Position > min;
- }).FirstOrDefault();
- }
- /// <summary>
- /// 计算当前RGV与指定RGV之间的距离
- /// </summary>
- /// <param name="rgv"></param>
- /// <returns></returns>
- public float Distance(RGVDevice rgv)
- {
- //return Math.Abs((Position - rgv.Position + Length) % Length);
- return DevEX.Distance(Position, rgv.Position, Length);
- }
- /// <summary>
- /// 计算当前RGV与指定站台之间的距离
- /// </summary>
- /// <param name="after"></param>
- /// <returns></returns>
- public float Distance(StationDeviceGroup after)
- {
- if (after == null) throw new WarnException($"不是一个有效的StationDeviceGroup,{Entity.CODE}");
- return DevEX.Distance(Position, after.Position, Length);
- }
- /// <summary>
- /// 是否需要执行放货任务
- /// </summary>
- /// <returns></returns>
- public bool IsPut()
- {
- if (Data2.TaskType_1 != RGVTaskType.取货) return false;
- if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.RGV到站)) return false;
- if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.任务完成)) return false;
- if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) return false;
- return true;
- }
- /// <summary>
- /// 写入移动任务
- /// </summary>
- /// <param name="addr">目标地址</param>
- public void Move(StationDeviceGroup addr)
- {
- if (Data.TaskType_1 == RGVTaskType.取货) throw new WarnException($"当前有{Data.TaskType_1}任务,无法执行移动任务");
- if (Data2.WorkMode != RGVMode.自动) throw new WarnException($"RGV状态{Data2.WorkMode},无法执行移动任务");
- if (Data2.SystemStatus != RGVRunStatus.空闲) throw new WarnException($"rgv状态为{Data2.SystemStatus},无法执行移动任务");
- if (Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) throw new WarnException("RGV有光电,无法执行移动任务");
- if (Data2.TaskID_1 == addr.Entity.CODE.GetShortCode() && Data.TaskType_1 == RGVTaskType.移动)
- {
- InfoLog.INFO_RGVINFO($"{Entity.CODE}]--已有目标地址相同的移动任务");
- return;
- }
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV移动任务-开始:{Data.TaskID_1},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- Data.TaskID_1 = addr.Entity.CODE.GetShortCode();
- Data.TaskID_2 = 0;
- Data.TaskType_1 = RGVTaskType.移动;
- Data.DestPosition_1 = addr.Entity.CODE.GetShortCode();
- Data.Trigger_1++;
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV移动任务-结束:{Data.TaskID_1},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- }
- /// <summary>
- /// 写入取货任务
- /// </summary>
- /// <param name="addr">目标地址</param>
- public void Pick(StationDeviceGroup addr, int task1, int task2)
- {
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV取货任务-开始:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- Data.TaskType_1 = RGVTaskType.取货;
- Data.DestPosition_1 = addr.Entity.CODE.GetShortCode();
- Data.TaskID_1 = task1;
- Data.TaskID_2 = task2;
- Data.Trigger_1++;
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV取货任务-结束:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- }
- ///// <summary>
- ///// 写入取货任务
- ///// </summary>
- ///// <param name="addr">目标地址</param>
- //public void Pick(StationDeviceGroup addr, int task1 = 0, int task2 = 0)
- //{
- // InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV取货任务-开始:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- // Data.TaskType_1 = RGVTaskType.取货;
- // Data.DestPosition_1 = addr.Entity.CODE.GetShortCode();
- // if (task1 != 0) Data.TaskID_1 = task1;
- // if (task2 != 0) Data.TaskID_2 = task2;
- // Data.Trigger_1++;
- // InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV取货任务-结束:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- //}
- /// <summary>
- /// 写入放货任务
- /// </summary>
- /// <param name="addr">目标地址</param>
- public void Put(StationDeviceGroup addr, int task1 = 0, int task2 = 0)
- {
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV放货任务-开始:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- Data.TaskType_1 = RGVTaskType.放货;
- Data.DestPosition_1 = addr.Entity.CODE.GetShortCode();
- if (task1 != 0) Data.TaskID_1 = task1;
- if (task2 != 0) Data.TaskID_2 = task2;
- Data.Trigger_1++;
- InfoLog.INFO_RGVINFO($"[{Entity.CODE}]--写入RGV放货任务-结束:{Data.TaskID_1},{Data.TaskID_2},{Data.TaskType_1},{Data.DestPosition_1},{Data.Trigger_1}");
- }
- /// <summary>
- /// 筛选出所有与当前RGV距离小于指定长度的RGV
- /// </summary>
- /// <param name="distance">指定长度</param>
- /// <returns></returns>
- public RGVDevice[] RgvAfter(float distance)
- {
- return RGVList.Where(v => Distance(v) < distance).ToArray();
- }
- /// <summary>
- /// 当前RGV是否有拦住指定RGV
- /// </summary>
- /// <param name="rgv">RGV</param>
- /// <returns></returns>
- public bool StopedByMe(RGVDevice rgv)
- {
- //目标站台
- var target = rgv.Data2.DestPosition_1;
- //获取目标站台的设备组信息
- var station = Device.Find($"G{target}").Create<StationDeviceGroup>();
- if (station.Distance(rgv) < 5000) return false;
- //当前RGV与目标站台的距离小于传入RGV到达目标站台的距离
- return (this.Distance(station) < rgv.Distance(station)) || station.CurrentRGV()?.Entity.CODE == this.Entity.CODE;
- }
- /// <summary>
- /// 当前站台rgv是否挡住放货任务需要移动
- /// </summary>
- /// <param name="rgv">RGV</param>
- /// <returns></returns>
- public bool NeedToMove(RGVDevice rgv)
- {
- return (rgv.Position > 1777767 && rgv.Position < 2714350);
- }
- /// <summary>
- /// 获取当前RGV的下一个站台,即距离最近的一个站台
- /// </summary>
- /// <returns></returns>
- public StationDeviceGroup NextStation()
- {
- //先取当前RGV与所有站台的距离
- var dev = LocationList.OrderBy(v => v.Distance(this)).FirstOrDefault();
- return dev;
- }
- }
- /// <summary>
- /// 堆垛机设备
- /// </summary>
- public class SRMDevice : Device<ISRM520, ISRM521, ISRM537>
- {
- public SRMDevice(WCS_DEVICE entity) : base(entity)
- {
- }
- /// <summary>
- /// 获取放货点
- /// </summary>
- public List<StationDevice> GetDeliveryPoint()
- {
- return Entity.ROUTES.Select(v => v.NEXT) //巷道
- .SelectMany(v => v.ROUTES.Select(d => d.NEXT)) //放货点
- .Where(v => v.IsConv()) //必须是输送线
- .Select(v => v.Create<StationDevice>()).ToList();
- }
- /// <summary>
- /// 获取取货点
- /// </summary>
- public List<StationDevice> GetPickPoint()
- {
- return Device.Where(v => v.Is(DF.SRM二级品取货) || v.Is(DF.SRM涂布取货) || v.Is(DF.SRMBOPP取货))
- .Where(v => v.ROUTES.Any(p => p.NEXT.ROUTES.Any(d => d.NEXT.CODE == Entity.CODE)))
- .Select(v => v.Create<StationDevice>())
- .ToList();
- }
- /// <summary>
- /// 处理完成任务
- /// </summary>
- public void FinishedTaskHandle()
- {
- WCS_TASK task = new WCS_TASK();
- DB.Do(db =>
- {
- var taskIds = new List<int>() { Data2.FinishedTask_1, Data2.FinishedTask_2 }.ToArray();
- for (int i = 0; i < taskIds.Length; i++)
- {
- //判断当前工位是否有完成任务
- if (taskIds[i] == 0) continue;
- task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);
- if (task.STATUS != TaskStatus.堆垛机执行 && task.STATUS != TaskStatus.堆垛机完成)
- {
- InfoLog.INFO_WarnDb($"任务{task.ID},状态位{task.STATUS}", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- continue;
- };
- if (task.STATUS == TaskStatus.堆垛机完成)
- {
- if (i == 0)
- {
- Data.FinishedACK_1 = 1;
- Data.TaskID_1 = 0;
- }
- else
- {
- Data.FinishedACK_2 = 1;
- Data.TaskID_2 = 0;
- }
- throw new DoException("二次处理堆垛机完成任务");
- }
- switch (task.TYPE)
- {
- case TaskType.入库:
- task.ENDTIME = DateTime.Now;
- task.STATUS = TaskStatus.已完成;
- task.UPDATETIME = DateTime.Now;
- break;
- case TaskType.出库:
- task.STATUS = TaskStatus.堆垛机完成;
- task.UPDATETIME = DateTime.Now;
- break;
- case TaskType.移库:
- {
- if (task.STATUS == TaskStatus.堆垛机执行)
- {
- task.STATUS = TaskStatus.已完成;
- task.UPDATETIME = DateTime.Now;
- }
- break;
- }
- case TaskType.倒库:
- if (task.DEVICEDL == Entity.CODE)
- {
- task.STATUS = TaskStatus.已完成;
- task.UPDATETIME = DateTime.Now;
- }
- else
- {
- task.STATUS = TaskStatus.堆垛机完成;
- task.UPDATETIME = DateTime.Now;
- }
- break;
- default:
- throw new Exception($"[{Entity.CODE}]任务类型错误,{task.ID}");
- }
- if (task.TYPE == TaskType.出库)
- {
- task.CreateStatusLog(db, $"任务堆垛机完成", this.GetType());
- }
- else
- {
- task.CreateStatusLog(db, $"任务完成", this.GetType());
- }
-
- }
- db.Default.SaveChanges();
- });
- DB.Do(db =>
- {
- var taskIds = new List<int>() { Data2.FinishedTask_1, Data2.FinishedTask_2 }.ToArray();
- for (int i = 0; i < taskIds.Length; i++)
- {
- //判断当前工位是否有完成任务
- if (taskIds[i] == 0) continue;
- //获取当前工位的目标地址
- task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);
- if (i == 0)
- {
- Data.FinishedACK_1 = 1;
- Data.TaskID_1 = 0;
- }
- else
- {
- Data.FinishedACK_2 = 1;
- Data.TaskID_2 = 0;
- }
- }
- });
- }
- /// <summary>
- /// 执行堆垛机任务 单例锁
- /// </summary>
- /// <param name="act"></param>
- public void EX(Action<SRMDevice> act)
- {
- var key = $"WCS:Lock:{Entity.CODE}";
- try
- {
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"[{Entity.CODE}]--触发并发管控");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- act(this);
- }
- catch (DoException ex)
- {
- ex.DoExceptionEX(Entity);
- }
- catch (WarnException ex)
- {
- ex.WarnExceptionEX(Entity);
- }
- catch (Exception ex)
- {
- ex.ExceptionEx(Entity);
- }
- finally
- {
- ProtocolProxy.YG150Redis.Del(key);
- }
- }
- /// <summary>
- /// 执行出库任务 出库单例锁
- /// </summary>
- /// <param name="act"></param>
- public void EXOutStock(Action<SRMDevice> act)
- {
- var key = "WCS:Lock:";
- try
- {
- if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4")
- {
- key += "SRM3-SRM4-Out";
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"触发出库并发管控--[{Entity.CODE}]");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- }
- if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6")
- {
- key += "SRM5-SRM6-Out";
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"触发出库并发管控--[{Entity.CODE}]");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- }
- if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8")
- {
- key += "SRM7-SRM8-Out";
- if (ProtocolProxy.YG150Redis.Get(key) != null) throw new WarnException($"触发出库并发管控--[{Entity.CODE}]");
- ProtocolProxy.YG150Redis.Set(key, Entity.CODE);
- }
- act(this);
- }
- finally
- {
- if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4") ProtocolProxy.YG150Redis.Del($"{key}SRM3-SRM4-Out");
- if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6") ProtocolProxy.YG150Redis.Del($"{key}SRM5-SRM6-Out");
- if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8") ProtocolProxy.YG150Redis.Del($"{key}SRM7-SRM8-Out");
- }
- }
- /// <summary>
- /// 一工位写任务
- /// </summary>
- /// <param name="task"></param>
- /// <param name="goodsnum">货物数量</param>
- public void WriteTask1(Task task, short goodsnum)
- {
- InfoLog.INFO_SRMINFO($"出库--写入堆垛机[{Entity.CODE}]1工位-开始:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]--[{Data.RES1_1}]");
- Data.TaskID_1 = task.ID;
- Data.SLine_1 = task.Line;
- Data.SCol_1 = task.Col;
- Data.SLayer_1 = task.Layer;
- if (task.TYPE == TaskType.移库)
- {
- Data.ELine_1 = task.EndLine;
- Data.ECol_1 = task.EndCol;
- Data.ELayer_1 = task.EndLayer;
- }
- else
- {
- Data.ELine_1 = task.SRMSTATION.ToShort();
- Data.ECol_1 = 0;
- Data.ELayer_1 = 0;
- }
- Data.RES1_1 = goodsnum;
- Data.VoucherNo_1++;
- InfoLog.INFO_SRMINFO($"出库--写入堆垛机[{Entity.CODE}]1工位-结束:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]--[{Data.RES1_1}]");
- }
- /// <summary>
- /// 二工位写任务
- /// </summary>
- /// <param name="task"></param>
- /// <param name="goodsnum">货物数量</param>
- public void WriteTask2(Task task, short goodsnum)
- {
- InfoLog.INFO_SRMINFO($"出库--写入堆垛机[{Entity.CODE}]2工位-开始:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]--[{Data.RES1_2}]");
- Data.TaskID_2 = task.ID;
- Data.SLine_2 = task.Line;
- Data.SCol_2 = task.Col;
- Data.SLayer_2 = task.Layer;
- if (task.TYPE == TaskType.移库)
- {
- Data.ELine_2 = task.EndLine;
- Data.ECol_2 = task.EndCol;
- Data.ELayer_2 = task.EndLayer;
- }
- else
- {
- Data.ELine_2 = task.SRMSTATION.ToShort();
- Data.ECol_2 = 0;
- Data.ELayer_2 = 0;
- }
- Data.RES1_2 = goodsnum;
- Data.VoucherNo_2++;
- InfoLog.INFO_SRMINFO($"出库--写入堆垛机[{Entity.CODE}]2工位-结束:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]--[{Data.RES1_2}]");
- }
- /// <summary>
- /// 获取任务对应的货叉
- /// </summary>
- /// <param name="task">任务信息</param>
- /// <param name="index">任务在下发任务集合中的索引</param>
- /// <returns></returns>
- public SrmFork GetFork(Task task, int index)
- {
- return index switch
- {
- > 1 => throw new WarnException("一次最多下发两个任务"),
- //如果索引是1,直接返回货叉2
- 1 => SrmFork.货叉2,
- _ => task.Col switch
- {
- 102 => Entity.CODE switch
- {
- "SRM1" => SrmFork.货叉1,
- _ => SrmFork.货叉2,
- },
- 112 => SrmFork.货叉2,
- _ => SrmFork.货叉1,
- }
- };
- }
- /// <summary>
- /// 检查同组堆垛机是否有出库任务正在执行
- /// </summary>
- public void CheckOutTask()
- {
- //检查同组堆垛机是否有正在执行出库任务的
- DB.Do(db =>
- {
- try
- {
- var srm = Device.Find("SRM4").Create<SRMDevice>();
- var task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM4" && v.TYPE == TaskType.出库);
- switch (Entity.CODE)
- {
- case "SRM3":
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM4正在执行出库任务");
- break;
- case "SRM4":
- srm = Device.Find("SRM3").Create<SRMDevice>();
- task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM3" && v.TYPE == TaskType.出库);
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM3正在执行出库任务");
- break;
- case "SRM5":
- srm = Device.Find("SRM6").Create<SRMDevice>();
- task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM6" && v.TYPE == TaskType.出库);
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM6正在执行出库任务");
- break;
- case "SRM6":
- srm = Device.Find("SRM5").Create<SRMDevice>();
- task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM5" && v.TYPE == TaskType.出库);
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM5正在执行出库任务");
- break;
- case "SRM7":
- srm = Device.Find("SRM8").Create<SRMDevice>();
- task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM8" && v.TYPE == TaskType.出库);
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM8正在执行出库任务");
- break;
- case "SRM8":
- srm = Device.Find("SRM7").Create<SRMDevice>();
- task = db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM7" && v.TYPE == TaskType.出库);
- if (srm.Data3.SCAlarm != 0 || srm.Data2.SRMMode != WCS.Entity.Protocol.SRM.SCMode.远程 || task)
- throw new DoException("SRM7正在执行出库任务");
- break;
- }
- }
- catch (Exception e)
- {
- InfoLog.INFO_WarnDb(e.Message, Entity.CODE, WCS_EXCEPTIONTYPE.设备异常);
- }
- });
- }
- }
- /// <summary>
- /// 异常处理
- /// </summary>
- public static class DevEX
- {
- /// <summary>
- /// 计算两点距离
- /// </summary>
- /// <param name="start">起始点</param>
- /// <param name="end">结束点</param>
- /// <param name="total">总长</param>
- /// <returns></returns>
- public static float Distance(float start, float end, float total)
- {
- float distance = 0;
- if (start > end) distance = (total - start) + end;
- else distance = end - start;
- return distance;
- }
- public static void DoExceptionEX(this DoException ex, WCS_DEVICE Entity)
- {
- InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");
- }
- /// <summary>
- /// 警报执行记录
- /// </summary>
- /// <param name="ex">警报信息</param>
- /// <param name="Entity">发生设备</param>
- /// <param name="reportMonitor">是否上报监控</param>
- /// <exception cref="Exception"></exception>
- public static void WarnExceptionEX(this WarnException ex, WCS_DEVICE Entity, bool reportMonitor = true)
- {
- InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");
- if (ex.Message.Contains("The database operation was expected")) return;
- if (!reportMonitor)
- {
- LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
- }
- //排除部分频繁触发的异常上报
- if (ex.Message.Contains("触发并发管控")) return;
- if (reportMonitor)
- {
- throw new Exception($"[{Entity.CODE}]--{ex.Message}");
- }
- }
- public static void ExceptionEx(this Exception ex, WCS_DEVICE Entity)
- {
- InfoLog.INFO_ERROR($"[{Entity.CODE}]--{ex.Message}--{ex.StackTrace}");
- //排除部分频繁触发的异常上报
- if (ex.Message.Contains("Collection was modified; enumeration operation may not execute.")) return;
- Ltc.Log(ex.GetBaseException().Message);
- }
- }
- /// <summary>
- /// 堆垛机货叉/工位
- /// </summary>
- public enum SrmFork
- {
- 货叉1 = 0,
- 货叉2 = 1,
- }
- /// <summary>
- /// 站台位置信息
- /// </summary>
- public class StationLocation
- {
- /// <summary>
- /// 所有环穿站台的信息
- /// </summary>
- public static List<StationLocation> ALLlocations { get; set; } = new List<StationLocation>();
- static StationLocation()
- {
- ALLlocations.AddRange(new List<StationLocation>() {
- new StationLocation("G1",486326,"RGV3",1567770),
- new StationLocation("G2",693631,"RGV3",1567770),
- new StationLocation("G3",789931,"RGV3",1567770),
- new StationLocation("G4",961595,"RGV3",1567770),
- new StationLocation("G5",1013350,"RGV3",1567770),
- new StationLocation("G6",1069938,"RGV3",1567770),
- new StationLocation("G7",1126338,"RGV3",1567770),
- new StationLocation("G8",1178355,"RGV3",1567770),
- new StationLocation("G9",1256875,"RGV3",1567770),
- new StationLocation("G10",1313239,"RGV3",1567770),
- new StationLocation("G11",1369970,"RGV3",1567770),
- new StationLocation("G12",636770,"RGV1",3719290),
- new StationLocation("G13",749520,"RGV1",3719290),
- new StationLocation("G14",879930,"RGV1",3719290),
- new StationLocation("G15",936310,"RGV1",3719290),
- new StationLocation("G16",988000,"RGV1",3719290),
- //new StationLocation("G17",1607000,"RGV1",3719290),
- //new StationLocation("G18",1667000,"RGV1",3719290),
- new StationLocation("G19",1777767,"RGV1",3719290),
- //new StationLocation("G20",2548012,"RGV1",3719290),
- //new StationLocation("G21",2606033,"RGV1",3719290),
- //new StationLocation("G22",2660833,"RGV1",3719290),
- new StationLocation("G23",2714350,"RGV1",3719290),
- });
- }
- public StationLocation(string station, int location, string plc, int length)
- {
- Station = station;
- Location = location;
- PLC = plc;
- Length = length;
- }
- /// <summary>
- /// 输送机设备组编号
- /// </summary>
- public string Station { get; set; }
- /// <summary>
- /// 输送机在环轨中的位置
- /// </summary>
- public int Location { get; set; }
- /// <summary>
- /// 所属RGV组 PLC名称
- /// </summary>
- public string PLC { get; set; }
- /// <summary>
- /// 所属环穿轨道的长度
- /// </summary>
- public int Length { get; set; }
- }
- /// <summary>
- /// 巷道信息
- /// </summary>
- public class TunnelInfo
- {
- public WCS_DEVICE Tunnel;
- public WCS_DEVICE taskIN;
- public Device<ISRM520, ISRM521, ISRM537> SRM;
- }
- }
|