DeviceExtension.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using WCS.Core;
  5. using WCS.Entity;
  6. using WCS.Entity.Protocol;
  7. using WCS.Entity.Protocol.RGV;
  8. using WCS.Service.Helpers;
  9. namespace WCS.Service.Extensions
  10. {
  11. /// <summary>
  12. /// 输送机设备组
  13. /// </summary>
  14. public class StationDeviceGroup : DeviceGroup<IStation520, IStation521, IStation523>
  15. {
  16. public StationDeviceGroup(WCS_DEVICE entity) : base(entity)
  17. {
  18. }
  19. private List<RGVDevice> RGVs;
  20. /// <summary>
  21. /// 设备组自身的位置
  22. /// </summary>
  23. public float Position
  24. {
  25. get
  26. {
  27. return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Location;
  28. }
  29. }
  30. /// <summary>
  31. /// 设备组所在环穿的总长度
  32. /// </summary>
  33. public float Length
  34. {
  35. get
  36. {
  37. return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Length;
  38. }
  39. }
  40. /// <summary>
  41. /// 设备组是否满足任务执行条件
  42. /// </summary>
  43. /// <param name="type">给当前设备组下发任务时需要的请求</param>
  44. /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
  45. /// <exception cref="Exception"></exception>
  46. public bool WhetherToExecute(IstationRequest type = IstationRequest.无)
  47. {
  48. //当前组有一个运行的设备就停止执行
  49. if (Items.Any(v => v.Data3.Status.HasFlag(StationStatus.运行状态位))) return true;
  50. //设备组中没有设备有光带信息
  51. if (!Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态))) return true;
  52. ////有光电无任务
  53. //if (Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum < 10000))
  54. // throw new Exception(LogHelper.SpliceLogMessage("有光电无任务", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
  55. ////有光电有任务无请求
  56. //if (Items.Any(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum < 10000 && (type != IstationRequest.无 && v.Data2.Request != type)))
  57. // throw new Exception(LogHelper.SpliceLogMessage($"有光电有任务无 {type} 请求", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
  58. return false;
  59. }
  60. /// <summary>
  61. /// 获取设备组中需要取货的设备
  62. /// </summary>
  63. /// <param name="obj"></param>
  64. /// <returns></returns>
  65. public List<Device<IStation520, IStation521, IStation523>> RGVGetTaskedDevice()
  66. {
  67. var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
  68. .Where(v => v.Entity.CODE.ToShort() != v.Data2.Goodsend && v.Data2.Goodsend != 0)
  69. .ToList();
  70. return a.Count == 0 ? null : a;
  71. }
  72. /// <summary>
  73. /// 获取设备组中需要分配目标地址的设备
  74. /// </summary>
  75. /// <param name="obj"></param>
  76. /// <returns></returns>
  77. public List<Device<IStation520, IStation521, IStation523>> TaskedDeviceGetNextAddress()
  78. {
  79. var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
  80. .Where(v => v.Data2.Goodsend != 0)
  81. .ToList();
  82. return a.Count == 0 ? null : a;
  83. }
  84. /// <summary>
  85. ///
  86. /// </summary>
  87. /// <returns></returns>
  88. public RGVDevice NextRGV()
  89. {
  90. return new RGVDevice(new WCS_DEVICE());
  91. }
  92. /// <summary>
  93. /// 计算目标RGV与站台自身的距离
  94. /// </summary>
  95. /// <param name="rgv"></param>
  96. /// <returns></returns>
  97. public float Distance(RGVDevice rgv)
  98. {
  99. return Math.Abs((Position - rgv.Position + Length) % Length);
  100. }
  101. /// <summary>
  102. /// 当前RGV
  103. /// </summary>
  104. /// <returns></returns>
  105. public RGVDevice CurrentRGV()
  106. {
  107. return new RGVDevice(new WCS_DEVICE());
  108. }
  109. /// <summary>
  110. /// 是否需要RGV
  111. /// </summary>
  112. /// <returns>true:需要RGV false:不需要RGV</returns>
  113. public bool NeedRgv()
  114. {
  115. var rgvs = Device.Where(v => v.IsRGV()).Select(v => v.Device<IRGV521>());
  116. var code = Entity.CODE.Replace("G", "").ToShort();
  117. if (rgvs.Any(v => v.Data.DestPosition_1 == code && v.Data.SystemStatus != RGVRunStatus.空闲))
  118. throw new Exception(LogHelper.SpliceLogMessage("已有RGV执行中", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  119. foreach (var item in Items)
  120. {
  121. if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) return false;
  122. if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) return false;
  123. }
  124. return true;
  125. }
  126. }
  127. /// <summary>
  128. /// 输送机设备
  129. /// </summary>
  130. public class StationDevice : Device<IStation520, IStation521, IStation523>
  131. {
  132. public StationDevice(WCS_DEVICE entity) : base(entity)
  133. {
  134. }
  135. /// <summary>
  136. /// 设备组是否满足任务执行条件
  137. /// </summary>
  138. /// <param name="type">给当前设备组下发任务时需要的请求</param>
  139. /// <returns>true:不满足执行条件需要进行停止执行 false:表示满足条件不需要停止执行 </returns>
  140. /// <exception cref="Exception"></exception>
  141. public bool WhetherToExecute(IstationRequest type = IstationRequest.无)
  142. {
  143. //正在运行
  144. if (Data3.Status.HasFlag(StationStatus.运行状态位)) return true;
  145. //上一次的任务还未执行
  146. if (Data.VoucherNo != Data2.VoucherNo)
  147. throw new Exception(LogHelper.SpliceLogMessage($"等待任务[{Data2.Tasknum}]执行", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  148. //没有光电
  149. if (!Data2.Status.HasFlag(IstationStatus.光电状态)) return true;
  150. //没有任务号
  151. switch (type)
  152. {
  153. case IstationRequest.无:
  154. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  155. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  156. break;
  157. case IstationRequest.扫码入库:
  158. if (Data2.Tasknum > 10000 && Data.Tasknum > 10000)
  159. throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  160. break;
  161. case IstationRequest.堆垛机放货完成请求目标地址:
  162. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  163. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  164. break;
  165. case IstationRequest.请求分配目标地址:
  166. if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
  167. throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
  168. break;
  169. }
  170. //没有请求
  171. if (type != IstationRequest.无 && Data2.Request != type)
  172. throw new Exception(LogHelper.SpliceLogMessage($"有光电无{type}请求", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
  173. return false;
  174. }
  175. }
  176. /// <summary>
  177. /// RGV设备
  178. /// </summary>
  179. public class RGVDevice : Device<IRGV520, IRGV521, IRGV523>
  180. {
  181. static RGVDevice()
  182. {
  183. AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
  184. }
  185. public RGVDevice(WCS_DEVICE entity) : base(entity)
  186. {
  187. }
  188. /// 所有环穿RGV
  189. /// </summary>
  190. private static List<RGVDevice> AllRGVList { get; set; }
  191. /// <summary>
  192. /// 与当前RGV处于同一环穿的RGV
  193. /// </summary>
  194. public List<RGVDevice> RGVList
  195. {
  196. get
  197. {
  198. return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.ID == d.DB.ID)))
  199. .Where(v => v.Entity.CODE != Entity.CODE).ToList();
  200. }
  201. }
  202. /// <summary>
  203. /// RGV当前位置
  204. /// </summary>
  205. public float Position
  206. {
  207. get
  208. {
  209. return Data2.Position;
  210. }
  211. }
  212. /// <summary>
  213. /// 与当前RGV处于同一环穿的RGV
  214. /// </summary>
  215. public List<StationLocation> LocationList
  216. {
  217. get
  218. {
  219. return StationLocation.ALLlocations.Where(v => Entity.PROTOCOLS.Any(p => p.DB.PLC.CODE == v.PLC)).ToList();
  220. }
  221. }
  222. /// <summary>
  223. /// 总长度
  224. /// </summary>
  225. public float Length
  226. {
  227. get
  228. {
  229. return LocationList.FirstOrDefault().Length;
  230. }
  231. }
  232. /// <summary>
  233. /// 前一个RGV
  234. /// </summary>
  235. /// <returns></returns>
  236. public RGVDevice Before()
  237. {
  238. //按照位置排序
  239. var arr = RGVList.OrderBy(v => v.Position);
  240. var rgv = arr.FirstOrDefault(v => v.Position > Position);
  241. if (rgv == null)
  242. rgv = arr.LastOrDefault(v => v.Position < Position);
  243. return rgv;
  244. }
  245. /// <summary>
  246. /// 后一个RGV
  247. /// </summary>
  248. /// <returns></returns>
  249. public RGVDevice After()
  250. {
  251. var arr = RGVList.OrderBy(v => v.Position);
  252. var rgv = arr.FirstOrDefault(v => v.Position < Position);
  253. if (rgv == null)
  254. rgv = arr.LastOrDefault(v => v.Position > Position);
  255. return rgv;
  256. }
  257. /// <summary>
  258. /// 计算当前RGV与指定RGV之间的距离
  259. /// </summary>
  260. /// <param name="after"></param>
  261. /// <returns></returns>
  262. public float Distance(RGVDevice after)
  263. {
  264. return Math.Abs((Position - after.Position + Length) % Length);
  265. }
  266. /// <summary>
  267. /// 是否可用
  268. /// </summary>
  269. /// <returns></returns>
  270. public bool Valid()
  271. {
  272. return true;
  273. }
  274. /// <summary>
  275. /// 写入移动任务
  276. /// </summary>
  277. /// <param name="addr">目标地址</param>
  278. public void Move(StationDeviceGroup addr)
  279. {
  280. }
  281. /// <summary>
  282. /// 写入取货任务
  283. /// </summary>
  284. /// <param name="addr">目标地址</param>
  285. public void Pick(StationDeviceGroup addr)
  286. {
  287. }
  288. /// <summary>
  289. /// 写入放货任务
  290. /// </summary>
  291. /// <param name="addr">目标地址</param>
  292. public void Put(StationDeviceGroup addr)
  293. {
  294. }
  295. /// <summary>
  296. /// 筛选出所有与当前RGV距离小于指定长度的RGV
  297. /// </summary>
  298. /// <param name="distance">指定长度</param>
  299. /// <returns></returns>
  300. public RGVDevice[] RgvAfter(float distance)
  301. {
  302. return RGVList.Where(v => Distance(v) < distance).ToArray();
  303. }
  304. /// <summary>
  305. /// 当前RGV是否有拦住传入RGV
  306. /// </summary>
  307. /// <param name="rgv">RGV</param>
  308. /// <returns></returns>
  309. public bool StopedByMe(RGVDevice rgv)
  310. {
  311. //目标站台
  312. var target = rgv.Data2.DestPosition_1;
  313. //获取目标站台的设备组信息
  314. var station = Device.Find($"G{target}").Create<StationDeviceGroup>();
  315. //当前RGV与目标站台的距离小于传入RGV到达目标站台的距离
  316. return station.Distance(this) < station.Distance(rgv);
  317. }
  318. /// <summary>
  319. /// 获取当前RGV的下一个站台,即距离最近的一个站台
  320. /// </summary>
  321. /// <returns></returns>
  322. public StationDeviceGroup NextStation()
  323. {
  324. //先取当前RGV与所有站台的距离
  325. var dev = LocationList.OrderBy(v =>
  326. {
  327. var dev = Device.Find(v.Station).Create<StationDeviceGroup>();
  328. return dev.Distance(this);
  329. }).FirstOrDefault();
  330. return Device.Find(dev.Station).Create<StationDeviceGroup>(); ;
  331. }
  332. }
  333. /// <summary>
  334. /// 堆垛机设备
  335. /// </summary>
  336. public class SRMDevice : Device<ISRM520, ISRM521, ISRM537>
  337. {
  338. public SRMDevice(WCS_DEVICE entity) : base(entity)
  339. {
  340. }
  341. /// <summary>
  342. /// 获取放货点
  343. /// </summary>
  344. public List<StationDevice> GetDeliveryPoint()
  345. {
  346. return Entity.ROUTES.Select(v => v.NEXT) //巷道
  347. .SelectMany(v => v.ROUTES.Select(d => d.NEXT)) //放货点
  348. .Where(v => v.IsConv()) //必须是输送线
  349. .Select(v => v.Create<StationDevice>()).ToList();
  350. }
  351. /// <summary>
  352. /// 获取取货点
  353. /// </summary>
  354. public List<StationDevice> GetPickPoint()
  355. {
  356. return Device.Where(v => v.Is(DF.SRM取货))
  357. .Where(v => v.ROUTES.Any(p => p.NEXT.ROUTES.Any(d => d.NEXT == Entity)))
  358. .Select(v => v.Create<StationDevice>())
  359. .ToList();
  360. }
  361. }
  362. /// <summary>
  363. /// 站台位置信息
  364. /// </summary>
  365. public class StationLocation
  366. {
  367. /// <summary>
  368. /// 所有环穿站台的信息
  369. /// </summary>
  370. public static List<StationLocation> ALLlocations { get; set; }
  371. static StationLocation()
  372. {
  373. ALLlocations.AddRange(new List<StationLocation>() {
  374. new StationLocation("G1187",0,"RGV1",0),
  375. new StationLocation("G1196",0,"RGV1",0),
  376. new StationLocation("G1205",0,"RGV1",0),
  377. new StationLocation("G1214",0,"RGV1",0),
  378. new StationLocation("G1222",0,"RGV1",0),
  379. new StationLocation("G1164",0,"RGV1",0),
  380. new StationLocation("G1285",0,"RGV3",0),
  381. new StationLocation("G1401",0,"RGV3",0),
  382. new StationLocation("G1294",0,"RGV3",0),
  383. new StationLocation("G1410",0,"RGV3",0),
  384. new StationLocation("G1303",0,"RGV3",0),
  385. new StationLocation("G1417",0,"RGV3",0),
  386. new StationLocation("G1412",0,"RGV3",0),
  387. new StationLocation("G1426",0,"RGV3",0),
  388. new StationLocation("G1332",0,"RGV3",0),
  389. new StationLocation("G1391",0,"RGV3",0),
  390. new StationLocation("G1399",0,"RGV3",0),
  391. });
  392. }
  393. public StationLocation(string station, int location, string plc, int length)
  394. {
  395. Station = station;
  396. Location = location;
  397. PLC = plc;
  398. Length = length;
  399. }
  400. /// <summary>
  401. /// 输送机设备组编号
  402. /// </summary>
  403. public string Station { get; set; }
  404. /// <summary>
  405. /// 输送机在环轨中的位置
  406. /// </summary>
  407. public int Location { get; set; }
  408. /// <summary>
  409. /// 所属PLC名称
  410. /// </summary>
  411. public string PLC { get; set; }
  412. /// <summary>
  413. /// 所属环穿轨道的长度
  414. /// </summary>
  415. public int Length { get; set; }
  416. }
  417. /// <summary>
  418. /// 巷道信息
  419. /// </summary>
  420. public class TunnelInfo
  421. {
  422. public WCS_DEVICE Tunnel;
  423. public WCS_DEVICE taskIN;
  424. public Device<ISRM520, ISRM521, ISRM537> SRM;
  425. }
  426. }