RGVSystems.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. using ServiceCenter.Extensions;
  2. using ServiceCenter.Logs;
  3. using ServiceCenter.SqlSugars;
  4. using System.ComponentModel;
  5. using WCS.Core;
  6. using WCS.Entity;
  7. using WCS.Entity.Protocol.BCR;
  8. using WCS.Entity.Protocol.RGV;
  9. using WCS.Entity.Protocol.Robot;
  10. using WCS.Entity.Protocol.Station;
  11. using WCS.Entity.Protocol.Truss;
  12. using WCS.WorkEngineering.Extensions;
  13. using WCS.WorkEngineering.Worlds;
  14. using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
  15. using TaskStatus = WCS.Entity.TaskStatus;
  16. namespace WCS.WorkEngineering.Systems
  17. {
  18. /// <summary>
  19. /// RGV交互系统
  20. /// </summary>
  21. [BelongTo(typeof(RgvWorld))]
  22. [Description("RGV交互系统")]
  23. public class RGVSystems : DeviceSystem<Device<IRGV520, IRGV521, IBCR81>>
  24. {
  25. protected override bool ParallelDo => true;
  26. protected override bool SaveLogsToFile => true;
  27. /// <summary>
  28. /// 取货点设备集合
  29. /// </summary>
  30. private readonly Dictionary<string, List<Device<IStation520, IStation521, IStation523>>> _pickUpDevices = new();
  31. public RGVSystems()
  32. {
  33. //获取所有的巷道集合
  34. var rgvList = Device.All.Where(v => v.HasFlag(DeviceFlags.RGV));
  35. foreach (var rgv in rgvList)
  36. {
  37. _pickUpDevices.Add(rgv.Code, rgv.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device<IStation520, IStation521, IStation523>(v, this.World)).ToList());
  38. }
  39. }
  40. public override void Do(Device<IRGV520, IRGV521, IBCR81> obj)
  41. {
  42. try
  43. {
  44. if (obj.Data.VoucherNo != obj.Data2.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo}-DB521:{obj.Data2.VoucherNo}", LogLevelEnum.High);
  45. if (obj.Data2.WorkMode != RGVWorkMode.Automatic) return;
  46. if (obj.Data.RES1 == 1) return; //wcs任务完成确认信号未清除
  47. if (obj.Data2.Status.HasFlag(RGVStatus.Taskfinishi))
  48. {
  49. switch (obj.Data2.CmdType)
  50. {
  51. case RGVCmdType.PickGoods: //单独取货任务完成,默认只有空托盘才会下发单独取货任务
  52. //开始申请读码信息
  53. var bcrCode = obj.Data3.GetBCRCode();
  54. var taskNumber = 0;
  55. SqlSugarHelper.Do(_db =>
  56. {
  57. var db = _db.Default;
  58. var dev = Device.All.First(x => x.Code == obj.Data2.DestPosition.ToString());
  59. if (dev.HasFlag(DeviceFlags.桁架码垛位))
  60. {
  61. //开始绑定任务,并下发新的任务信息到小车
  62. var palletizingInfo = db.Queryable<WCS_Palletizing>().Single(x => x.Id == obj.Data2.TaskNumber);
  63. if (palletizingInfo == null) return;
  64. palletizingInfo.PalleCode = bcrCode;
  65. db.Updateable(palletizingInfo).ExecuteCommand();
  66. taskNumber = palletizingInfo.Id;
  67. }
  68. else if (dev.HasFlag(DeviceFlags.环形库码垛工位))
  69. {
  70. //开始处理对应的搬运任务信息
  71. var task = db.Queryable<WCS_TaskInfo>().First(x => x.Type == TaskType.Delivery && x.ID == obj.Data2.TaskNumber && x.AddrTo == obj.Data2.DestPosition.ToString());
  72. if (task == null) throw new KnownException($"未找到对应的任务{obj.Data2.TaskNumber}", LogLevelEnum.Mid);
  73. task.BarCode = bcrCode;
  74. db.Updateable(task).ExecuteCommand();
  75. task.AddWCS_TASK_DTL(db, obj.Entity.Code, obj.Data2.DestPosition.ToString(), $"环形库码垛位{obj.Data2.DestPosition}搬运任务绑定条码信息{bcrCode}");
  76. taskNumber = task.ID;
  77. }
  78. });
  79. if (taskNumber == 0) return;
  80. //清空起始点信息
  81. var staDev = new Device<IStation520>(Device.All.FirstOrDefault(x => x.Code == obj.Data2.DestPosition.ToString())!, World);
  82. staDev.Data.TaskNumber = 0;
  83. staDev.Data.GoodsStart = 0;
  84. staDev.Data.GoodsEnd = 0;
  85. obj.Data2.TaskNumber = taskNumber;
  86. obj.Data.RES1 = 1;
  87. break;
  88. case RGVCmdType.PutGoods:
  89. try
  90. {
  91. WCS_TaskInfo finishiTask = null;
  92. var startPosition = Device.All.Where(x => x.Code == obj.Data2.StartPosition.ToString())
  93. .Select(x => new Device<IStation520, IStation521, IStation523>(x, World))
  94. .FirstOrDefault();
  95. var destPosition = Device.All.FirstOrDefault(x => x.Code == obj.Data2.DestPosition.ToString());
  96. var isPalletizing = destPosition!.HasFlag(DeviceFlags.桁架码垛位, DeviceFlags.环形库码垛工位);
  97. short countQty = 0;
  98. short shortCode = 0;
  99. SqlSugarHelper.Do(_db =>
  100. {
  101. var db = _db.Default;
  102. if (isPalletizing)
  103. {
  104. if (destPosition.HasFlag(DeviceFlags.桁架码垛位))
  105. {
  106. var palletizingInfo = db.Queryable<WCS_Palletizing>()
  107. .First(x => x.Id == obj.Data.TaskNumber);
  108. countQty = palletizingInfo.CountQty.ToShort();
  109. shortCode = palletizingInfo.ShortCode;
  110. }
  111. else if (destPosition.HasFlag(DeviceFlags.环形库码垛工位))
  112. {
  113. var deliveryTask = db.Queryable<WCS_TaskInfo>()
  114. .First(x => x.ID == obj.Data.TaskNumber);
  115. countQty = deliveryTask.FullQty;
  116. shortCode = deliveryTask.PalletType;
  117. deliveryTask.Status = TaskStatus.RgvCompleted;
  118. deliveryTask.EditTime = DateTime.Now;
  119. deliveryTask.LastInteractionPoint = obj.Entity.Code;
  120. db.Updateable(deliveryTask).ExecuteCommand();
  121. deliveryTask.AddWCS_TASK_DTL(db, deliveryTask.AddrTo, $"RGV任务执行结束");
  122. }
  123. }
  124. });
  125. if (startPosition.Data.TaskNumber == obj.Data.TaskNumber) //初始化起始点信息
  126. {
  127. startPosition.Data.TaskNumber = 0;
  128. startPosition.Data.GoodsEnd = 0;
  129. }
  130. //目标地址是码垛工位
  131. if (isPalletizing)
  132. {
  133. if (destPosition.HasFlag(DeviceFlags.桁架码垛位))
  134. {
  135. var dest = new Device<ITruss530>(destPosition!, World);
  136. dest.Data.MaxQuantity = countQty;
  137. dest.Data.Quantity = 0;
  138. dest.Data.Type = shortCode;
  139. dest.Data.VoucherNo++;
  140. }
  141. else if (destPosition.HasFlag(DeviceFlags.环形库码垛工位))
  142. {
  143. var dest = new Device<IRobot530>(destPosition!, World);
  144. dest.Data.MaxQuantity = countQty;
  145. dest.Data.Type = shortCode;
  146. dest.Data.VoucherNo++;
  147. }
  148. }
  149. }
  150. catch (Exception e)
  151. {
  152. throw new KnownException($"处理小车放货完成是出现错误:{e.Message}-{e.StackTrace}", LogLevelEnum.High);
  153. }
  154. obj.Data.RES1 = 1;
  155. break;
  156. case RGVCmdType.Move:
  157. obj.Data.RES1 = 1;
  158. break;
  159. case RGVCmdType.ChangePutGoods:
  160. break;
  161. case RGVCmdType.ChangePickGoods:
  162. break;
  163. case RGVCmdType.PickPutGoods:
  164. var statDev = Device.All.FirstOrDefault(x => x.Code == obj.Data.StartPosition.ToString());
  165. if (statDev.HasFlag(DeviceFlags.二次码垛RGV取货口))
  166. {
  167. var dev = new Device<IStation520, IStation521, ITruss530>(statDev, World);
  168. WCS_Palletizing pall = new WCS_Palletizing();
  169. //获取码垛信息
  170. SqlSugarHelper.Do(_db =>
  171. {
  172. var db = _db.Default;
  173. pall = db.Queryable<WCS_Palletizing>().Includes(x => x.Layers, x => x.Rows, x => x.Locs)
  174. .First(x => x.Id == obj.Data2.TaskNumber) ?? throw new KnownException($"未找到对应任务{obj.Data2.TaskNumber}", LogLevelEnum.High);
  175. });
  176. var pallLoc = pall.Layers.SelectMany(x => x.Rows).SelectMany(x => x.Locs).Select(x => new { XYNo = x.XYNo.ToShort(), x.Finish }).ToList();
  177. foreach (var loc in pallLoc)
  178. {
  179. dev.Data3.GetType().GetProperty($"IsGoods{loc.XYNo - 1}").SetValue(obj.Data3, loc.Finish);
  180. }
  181. dev.Data3.MaxQuantity = pall.CountQty.ToShort();
  182. dev.Data3.Quantity = pallLoc.Count(x => x.Finish).ToShort();
  183. dev.Data3.Type = pall.ShortCode;
  184. dev.Data3.VoucherNo++;
  185. }
  186. else
  187. {
  188. var destDev = new Device<IStation520, IStation521>(Device.All.FirstOrDefault(x => x.Code == obj.Data.DestPosition.ToString())!, World);
  189. destDev.Data.TaskNumber = 0;
  190. destDev.Data.GoodsStart = 0;
  191. destDev.Data.GoodsEnd = 0;
  192. }
  193. obj.Data.RES1 = 1;
  194. break;
  195. default:
  196. throw new ArgumentOutOfRangeException();
  197. }
  198. return;
  199. }
  200. if (obj.Data2.SystemStatus != RGVSystemStatus.空闲) return;
  201. if (obj.Data2.Status.HasFlag(RGVStatus.RES1)) //离开非安全区域
  202. {
  203. obj.Data.TaskNumber = obj.Data.TaskNumber;
  204. obj.Data.CmdType = RGVCmdType.Move;
  205. obj.Data.DestPosition = obj.Entity.Code switch
  206. {
  207. "RGV1" => 1668,
  208. "RGV2" => 1683,
  209. "RGV3" => 1698,
  210. "RGV4" => 1713,
  211. "RGV5" => 1728,
  212. "RGV6" => 1743,
  213. _ => throw new ArgumentOutOfRangeException()
  214. };
  215. obj.Data.VoucherNo++;
  216. return;
  217. }
  218. if (obj.Data2.CmdType == RGVCmdType.PickGoods && !obj.Data2.Status.HasFlag(RGVStatus.Taskfinishi))
  219. {
  220. if (obj.Data2.Status.HasFlag(RGVStatus.PH_Status))
  221. {
  222. obj.Data.TaskNumber = obj.Data.TaskNumber;
  223. obj.Data.CmdType = RGVCmdType.PutGoods;
  224. obj.Data.StartPosition = obj.Data2.StartPosition;
  225. obj.Data.DestPosition = obj.Data2.DestPosition;
  226. obj.Data.VoucherNo++;
  227. return;
  228. }
  229. }
  230. var pickUpDevices = _pickUpDevices.FirstOrDefault(x => x.Key == obj.Entity.Code).Value;
  231. //有货且需要搬运货物的站台
  232. var devs = pickUpDevices.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status) && v.Data.TaskNumber != 0)
  233. .Where(v => v.Entity.Code.ToShort() != v.Data.GoodsEnd && v.Data.GoodsEnd != 0)
  234. .ToList();
  235. //筛选出目标站台无货的站台
  236. var putDev = obj.Entity.Targets.Where(x => x.HasFlag(DeviceFlags.输送机))
  237. .Select(x => new Device<IStation520, IStation521, IStation523>(x, World))
  238. .Where(x => !x.Data3.Status.HasFlag(StationStatus.PH_Status))
  239. .Select(x => x.Entity.Code.ToShort());
  240. var devList = devs.OrderBy(x => x.Entity.Code).Where(x => putDev.Contains(x.Data.GoodsEnd));
  241. foreach (var dev in devList)
  242. {
  243. //区分任务是拆盘机到码垛工位,还是码垛工位到拆盘机
  244. if (dev.Entity.HasFlag(DeviceFlags.拆盘机))
  245. {
  246. obj.Data.TaskNumber = dev.Data.TaskNumber;
  247. obj.Data.CmdType = RGVCmdType.PickGoods;
  248. obj.Data.StartPosition = dev.Entity.Code.ToShort();
  249. obj.Data.DestPosition = dev.Data.GoodsEnd;
  250. obj.Data.VoucherNo++;
  251. return;
  252. }
  253. if (dev.Entity.HasFlag(DeviceFlags.二次码垛RGV取货口))
  254. {
  255. obj.Data.TaskNumber = dev.Data.TaskNumber;
  256. obj.Data.CmdType = RGVCmdType.PickPutGoods;
  257. obj.Data.StartPosition = dev.Entity.Code.ToShort();
  258. obj.Data.DestPosition = dev.Data.GoodsEnd;
  259. obj.Data.VoucherNo++;
  260. return;
  261. }
  262. //非拆盘机起始任务
  263. //站台中的任务号
  264. WCS_TaskInfo task = null;
  265. SqlSugarHelper.Do(_db =>
  266. {
  267. var db = _db.Default;
  268. var taskInfo = db.Queryable<WCS_TaskInfo>().First(p => p.ID == dev.Data.TaskNumber && p.Status == TaskStatus.ConveyorExecution);
  269. if (taskInfo == null) return;
  270. taskInfo.Status = TaskStatus.RgvExecution;
  271. taskInfo.AddrNext = obj.Entity.Code;
  272. taskInfo.EditWho = "WCS";
  273. taskInfo.EditTime = DateTime.Now; ;
  274. db.Updateable(taskInfo).ExecuteCommand();
  275. taskInfo.AddWCS_TASK_DTL(db, dev.Entity.Code, obj.Entity.Code, $"任务分配至{obj.Entity.Code}");
  276. task = taskInfo;
  277. });
  278. if (task == null) continue;
  279. obj.Data.TaskNumber = task.ID;
  280. obj.Data.CmdType = RGVCmdType.PickPutGoods;
  281. obj.Data.StartPosition = dev.Entity.Code.ToShort();
  282. obj.Data.DestPosition = dev.Data.GoodsEnd;
  283. obj.Data.VoucherNo++;
  284. return;
  285. }
  286. }
  287. catch (Exception ex)
  288. {
  289. if (ex.Message == "Destination array was not long enough. Check the destination index, length, and the array's lower bounds")
  290. {
  291. World.Log($"未知异常:{ex.StackTrace}");
  292. }
  293. else if (ex.Message == "Number was less than the array's lower bound in the first dimension")
  294. {
  295. World.Log($"未知异常:{ex.StackTrace}");
  296. }
  297. else throw new KnownException(ex.Message, LogLevelEnum.Mid);
  298. }
  299. }
  300. public override bool Select(Device dev)
  301. {
  302. return dev.Code is "RGV1" or "RGV2" or "RGV3" or "RGV4" or "RGV5" or "RGV6";
  303. //return dev.HasFlag(Extensions.DeviceFlags.RGV);
  304. }
  305. }
  306. }