机械臂cs.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. using Newtonsoft.Json;
  2. using PlcSiemens.Core.Extension;
  3. using ServiceCenter.Extensions;
  4. using ServiceCenter.Logs;
  5. using ServiceCenter.SqlSugars;
  6. using SqlSugar;
  7. using System.ComponentModel;
  8. using WCS.Core;
  9. using WCS.Entity;
  10. using WCS.Entity.Protocol.Protocol.Robot;
  11. using WCS.Entity.Protocol.Robot;
  12. using WCS.Entity.Protocol.Station;
  13. using WCS.WorkEngineering.Extensions;
  14. using WCS.WorkEngineering.Model.WMS;
  15. using WCS.WorkEngineering.Worlds.环形库.环形库;
  16. using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
  17. using TaskStatus = WCS.Entity.TaskStatus;
  18. namespace WCS.WorkEngineering.Systems
  19. {
  20. /// <summary>
  21. /// 机械臂
  22. /// </summary>
  23. [BelongTo(typeof(RingWorld1))]
  24. [Description("机械臂")]
  25. public class 机械臂 : DeviceSystem<Device<IRobot520, IRobot521, IRobot522>>
  26. {
  27. protected override bool ParallelDo => true;
  28. /// <summary>
  29. /// 取货点设备集合
  30. /// </summary>
  31. private Dictionary<string, List<Device>> PickUpDevices = new();
  32. /// <summary>
  33. /// 放货设备
  34. /// </summary>
  35. private Dictionary<string, List<Device<IStation520, IStation521, IStation523, IRobot530>>> PutDevices = new();
  36. public 机械臂()
  37. {
  38. //获取所有的机械臂 集合
  39. var devices = Device.All.Where(v => v.HasFlag(DeviceFlags.Robot));
  40. //开始分配
  41. foreach (var robot in devices)
  42. {
  43. //取货设备
  44. PickUpDevices.Add(robot.Code, robot.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => v).ToList());
  45. PutDevices.Add(robot.Code, robot.Targets.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device<IStation520, IStation521, IStation523, IRobot530>(v, World)).ToList());
  46. }
  47. }
  48. public override void Do(Device<IRobot520, IRobot521, IRobot522> obj)
  49. {
  50. #region 处理完成任务
  51. //判断DB520 完成任务确认清除信号 是否为1
  52. if (obj.Data.OkAck == 1 && obj.Data2 is { TaskFinishId1: 0, TaskFinishId2: 0 }) obj.Data.OkAck = 0;
  53. if (obj.Data2.TaskFinishId1 > 0 || obj.Data2.TaskFinishId2 > 0)
  54. {
  55. //处理完成的任务信息
  56. var tasks = new List<WCS_TaskInfo>();
  57. //开始处理
  58. SqlSugarHelper.Do(db =>
  59. {
  60. World.Log($"机械臂任务处理:开始--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Low);
  61. var isDP = obj.Entity.GetIsDirectPalletizing(db.Default);
  62. //根据DB521任务号获取对应任务
  63. var taskInfoList = db.Default.Queryable<WCS_TaskInfo>().Where(v => v.ID == obj.Data2.TaskFinishId1 || v.ID == obj.Data2.TaskFinishId2).ToList();
  64. foreach (var task in taskInfoList.Where(task => task.Status == Entity.TaskStatus.StackerExecution))
  65. {
  66. //根据任务类型做不同的处理
  67. switch (task.Type)
  68. {
  69. case TaskType.SetPlate: //工字轮入库
  70. if (isDP)
  71. {
  72. //完成任务
  73. task.Status = Entity.TaskStatus.ConveyorExecution;
  74. task.EndTime = DateTime.Now;
  75. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
  76. task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "直接码垛任务完成码垛");
  77. }
  78. else
  79. {
  80. //完成任务
  81. task.Status = Entity.TaskStatus.Finish;
  82. task.EndTime = DateTime.Now;
  83. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
  84. task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "入库任务结束");
  85. }
  86. break;
  87. case TaskType.OutDepot:
  88. //var pall = db.Default.Queryable<WCS_TaskInfo>().Where(x => x.AddrTo == task.AddrTo && x.Type == TaskType.Delivery && x.Status < TaskStatus.Finish).First() ?? throw new Exception($"未找到对应的托盘搬运任务,无法进行绑盘");
  89. task.Status = Entity.TaskStatus.StackerCompleted;
  90. task.EditTime = DateTime.Now;
  91. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EditTime }).ExecuteCommand();
  92. task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "出库任务结束");
  93. break;
  94. case TaskType.TransferDepot:
  95. task.Status = Entity.TaskStatus.Finish;
  96. task.EndTime = DateTime.Now;
  97. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.EndTime }).ExecuteCommand();
  98. task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "移库任务结束");
  99. break;
  100. }
  101. tasks.Add(task);
  102. }
  103. });
  104. if (!tasks.Any()) throw new KnownException("数据库提交事务错误", LogLevelEnum.High);
  105. // 写入信号
  106. obj.Data.OkAck = 1;
  107. World.Log($"机械臂任务处理:结束--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Mid);
  108. }
  109. #endregion 处理完成任务
  110. //robot是否可以下发任务
  111. if (obj.Data2.VoucherNo != obj.Data.VoucherNo)
  112. {
  113. World.Log($"凭证号不一致,DB520:{obj.Data.VoucherNo},DB521:{obj.Data2.VoucherNo}", LogLevelEnum.Mid);
  114. return;
  115. }
  116. if (obj.Data2.RobotMode != RobotMode.Automatic)
  117. {
  118. World.Log($"robot处于{obj.Data2.RobotMode.GetDescription()}模式", LogLevelEnum.Mid);
  119. return;
  120. }
  121. if (obj.Data2.RunStatus != RobotRunStatus.Idle)
  122. {
  123. World.Log($"robot处于{obj.Data2.RunStatus.GetDescription()}状态", LogLevelEnum.Mid);
  124. return;
  125. }
  126. //判断是否有任务是机器人执行中
  127. //再检查是否有等待执行的货物
  128. var inMaxQuantity = 0; //出入库的周期检查比为1:3
  129. var taskss = new List<WCS_TaskInfo>();
  130. var isDP = false; //当前机械臂是否直接码垛
  131. SqlSugarHelper.Do(db =>
  132. {
  133. isDP = obj.Entity.GetIsDirectPalletizing(db.Default);
  134. var code = $"RobotMaxConsecutiveStorageCount{obj.Entity.Code.Last()}";
  135. inMaxQuantity = db.Default.Queryable<fjSysConfig>().First(x => x.Code == code).SContent.ToInt();
  136. //获取当前堆垛机的所有未完成任务 ,就算查到了未提交的事务也无所谓,无非下一个周期再执行一次
  137. taskss = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(v => v.Status < Entity.TaskStatus.Finish && v.Device == obj.Entity.Code).ToList();
  138. //任务集合是否有处于堆垛机执行状态的任务
  139. if (taskss.Any(v => v.Status == Entity.TaskStatus.StackerExecution)) throw new KnownException($"有任务处于堆垛机执行状态", LogLevelEnum.High);
  140. });
  141. if (isDP) //直接码垛
  142. {
  143. //获取当前机械臂所有的取货站台
  144. var pickUpDevices = obj.Entity.Sources.Where(x => x.HasFlag(DeviceFlags.输送机)).Where(x => x.DeviceGroup.Any()).Select(
  145. x =>
  146. {
  147. var group = x.DeviceGroup.Select(s => new Device<IStation523, IStation524>(s, World)).ToList();
  148. return new Tuple<Device<IStation523, IStation524>, List<Device<IStation523, IStation524>>>(new Device<IStation523, IStation524>(x, World), group);
  149. }).ToList();
  150. if (!pickUpDevices.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无取货路径点", LogLevelEnum.High);
  151. //获取取货设备的设备组中都是停止运行的
  152. var arrIn = pickUpDevices.Where(x => x.Item2.All(a => !a.Data.Status.HasFlag(StationStatus.Run)))
  153. .Where(x =>
  154. {
  155. var inStock = x.Item2.Any(a => a.Data2.TaskNumber > 0 && a.Data.Status.HasFlag(StationStatus.PH_Status));
  156. var minDevice = x.Item2.OrderBy(o => o.Entity.Code.ToShort()).First();
  157. return minDevice.Data2.TaskNumber > 0 && minDevice.Data.Status.HasFlag(StationStatus.PH_Status) && inStock;
  158. }).ToList();
  159. //.OrderBy(x => x.Item1.Data2.TaskNumber)
  160. if (!arrIn.Any())
  161. {
  162. World.Log($"[{obj.Entity.Code}]等待入库任务输送到位");
  163. obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //在无货物的情况下,只检查一次,下次直接查询是否有出库任务,避免无效检查周期的产生
  164. return;
  165. }
  166. //先按可取货位数量排序,直接码垛优先取小的
  167. var devGroup = arrIn.OrderBy(x => x.Item2.Count(i => i.Data2.TaskNumber > 0 && i.Data.Status.HasFlag(StationStatus.PH_Status)))
  168. .First().Item2
  169. .Where(x => x.Data2.TaskNumber > 0 && x.Data.Status.HasFlag(StationStatus.PH_Status));
  170. var taskList = new List<Tuple<WCS_TaskInfo, Device<IStation523, IStation524>>>();
  171. SqlSugarHelper.Do(db =>
  172. {
  173. foreach (var dev in devGroup)
  174. {
  175. var task = db.Default.Queryable<WCS_TaskInfo>().First(v => v.Type == TaskType.SetPlate && v.Status == Entity.TaskStatus.FinishOfShunt && dev.Data2.TaskNumber == v.ID);
  176. if (task == null) continue;
  177. if (db.Default.Queryable<WCS_TaskInfo>().Where(x => x.WmsTask == task.WmsTask && x.AddrTo == task.AddrTo && x.Status < TaskStatus.Finish).Count() > 1)
  178. {
  179. throw new KnownException($"当前码垛编号与任务{task.ID}码垛编号重复,请联系工程师确认是否有误", LogLevelEnum.High);
  180. }
  181. task.Status = Entity.TaskStatus.StackerExecution;
  182. task.LastInteractionPoint = dev.Entity.Code;
  183. task.SrmStation = dev.Entity.Code;
  184. task.Device = obj.Entity.Code;
  185. task.EditWho = "WCS";
  186. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.AddrTo, x.Line, x.Col, x.Layer, x.Depth, x.LastInteractionPoint, x.SrmStation, x.Device, x.EditWho }).ExecuteCommand();
  187. task.AddWCS_TASK_DTL(db.Default, dev.Entity.Code, task.AddrTo, "任务下发机械臂执行");
  188. taskList.Add(new(task, dev));
  189. }
  190. });
  191. if (!taskList.Any()) return;
  192. switch (taskList.Count)
  193. {
  194. case 1:
  195. var task = taskList.FirstOrDefault().Item1;
  196. var dev = taskList.FirstOrDefault().Item2;
  197. //下发任务
  198. obj.Data.TaskNumber1 = task.ID;
  199. obj.Data.SLine1 = dev.Entity.Code.ToShort();
  200. obj.Data.SCol1 = 0;
  201. obj.Data.SLayer1 = 0;
  202. obj.Data.SDepth1 = 0;
  203. obj.Data.ELine1 = task.AddrTo.ToShort();
  204. obj.Data.ECol1 = task.WmsTask.ToShort();
  205. obj.Data.ELayer1 = 0;
  206. obj.Data.EDepth1 = 0;
  207. obj.Data.TaskNumber2 = 0;
  208. obj.Data.SLine2 = 0;
  209. obj.Data.SCol2 = 0;
  210. obj.Data.SLayer2 = 0;
  211. obj.Data.SDepth2 = 0;
  212. obj.Data.ELine2 = 0;
  213. obj.Data.ECol2 = 0;
  214. obj.Data.ELayer2 = 0;
  215. obj.Data.EDepth2 = 0;
  216. obj.Data.TaskSum = taskList.Count.ToShort();
  217. obj.Data.GoodsType = task.GoodsType switch
  218. {
  219. 18 => 1,
  220. 34 => 2,
  221. 50 => 3,
  222. _ => 0
  223. };
  224. obj.Data.TaskType = 6;
  225. obj.Data.VoucherNo++;
  226. break;
  227. case 2:
  228. taskList = taskList.OrderByDescending(x => x.Item2.Entity.Code.ToInt()).ToList();
  229. var maxWmsTask = taskList.Max(x => x.Item1.WmsTask).ToShort();
  230. var minWmsTask = taskList.Min(x => x.Item1.WmsTask).ToShort();
  231. //一工位取深度较大的任务
  232. var taskInfo = taskList[1];
  233. task = taskInfo.Item1;
  234. dev = taskInfo.Item2;
  235. obj.Data.TaskNumber1 = task.ID;
  236. obj.Data.SLine1 = dev.Entity.Code.ToShort();
  237. obj.Data.SCol1 = 0;
  238. obj.Data.SLayer1 = 0;
  239. obj.Data.SDepth1 = 0;
  240. obj.Data.ELine1 = task.AddrTo.ToShort();
  241. obj.Data.ECol1 = task.WarehouseCode.Contains("N") ? minWmsTask : maxWmsTask;
  242. obj.Data.ELayer1 = 0;
  243. obj.Data.EDepth1 = 0;
  244. //二工位取深度较少的值
  245. taskInfo = taskList[0];
  246. task = taskInfo.Item1;
  247. dev = taskInfo.Item2;
  248. obj.Data.TaskNumber2 = task.ID;
  249. obj.Data.SLine2 = dev.Entity.Code.ToShort();
  250. obj.Data.SCol2 = 0;
  251. obj.Data.SLayer2 = 0;
  252. obj.Data.SDepth2 = 0;
  253. obj.Data.ELine2 = task.AddrTo.ToShort();
  254. obj.Data.ECol2 = task.WarehouseCode.Contains("N") ? maxWmsTask : minWmsTask;
  255. obj.Data.ELayer2 = 0;
  256. obj.Data.EDepth2 = 0;
  257. obj.Data.TaskSum = taskList.Count.ToShort();
  258. obj.Data.GoodsType = task.GoodsType switch
  259. {
  260. 18 => 1,
  261. 34 => 2,
  262. 50 => 3,
  263. _ => 0
  264. };
  265. obj.Data.TaskType = 6;
  266. obj.Data.VoucherNo++;
  267. break;
  268. default:
  269. throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid);
  270. }
  271. }
  272. else
  273. {
  274. //获取入库次数
  275. var inQuantity = obj.Entity.GetFlag<int>("InQuantity");
  276. //入库任务优先 或 上一个周期是出库任务并且出库任务无优先
  277. if (inQuantity < inMaxQuantity) //入库任务
  278. {
  279. //判断本次优先执行楼层,并设置下次执行时优先楼层
  280. var floor = obj.Entity.GetFlag<int>("FloorIn");
  281. floor = floor % 2 + 1;
  282. obj.Entity.SetFlag("FloorIn", floor);
  283. obj.Entity.SetFlag("InQuantity", inQuantity + 1);
  284. //获取当前机械臂所有的取货站台
  285. var pickUpDevices = obj.Entity.Sources.Where(x => x.HasFlag(DeviceFlags.输送机)).Where(x => x.DeviceGroup.Any()).Select(
  286. x =>
  287. {
  288. var group = x.DeviceGroup.Select(s => new Device<IStation523, IStation524>(s, World)).ToList();
  289. return new Tuple<Device<IStation523, IStation524>, List<Device<IStation523, IStation524>>>(new Device<IStation523, IStation524>(x, World), group);
  290. }).ToList();
  291. if (!pickUpDevices.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无取货路径点", LogLevelEnum.High);
  292. //获取取货设备的设备组中都是停止运行的
  293. var arrIn = pickUpDevices.Where(x => x.Item2.All(a => !a.Data.Status.HasFlag(StationStatus.Run)))
  294. .Where(x =>
  295. {
  296. var inStock = x.Item2.Any(a => a.Data2.TaskNumber > 0 && a.Data.Status.HasFlag(StationStatus.PH_Status));
  297. var minDevice = x.Item2.OrderBy(o => o.Entity.Code.ToShort()).First();
  298. return minDevice.Data2.TaskNumber > 0 && minDevice.Data.Status.HasFlag(StationStatus.PH_Status) && minDevice.Data2.CmdType.HasFlag(StationCmd.Res7) && inStock;
  299. }).ToList();
  300. //.OrderBy(x => x.Item1.Data2.TaskNumber)
  301. if (!arrIn.Any())
  302. {
  303. World.Log($"[{obj.Entity.Code}]等待入库任务输送到位");
  304. obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //在无货物的情况下,只检查一次,下次直接查询是否有出库任务,避免无效检查周期的产生
  305. return;
  306. }
  307. //先按可取货位数量排序,再按任务号排序
  308. var devGroup = arrIn.OrderByDescending(x => x.Item2.Count(i => i.Data2.TaskNumber > 0 && i.Data.Status.HasFlag(StationStatus.PH_Status)))
  309. .ThenByDescending(x =>
  310. {
  311. int number;
  312. List<Device<IStation523, IStation524>> devices = new List<Device<IStation523, IStation524>>();
  313. var deviceCodes = GetDeviceCodeList(x.Item1.Entity.Code);
  314. devices = Device.All.Where(x => deviceCodes.Contains(x.Code)).Select(x => new Device<IStation523, IStation524>(x, World)).ToList();
  315. number = devices.Count(x => x.Data2.TaskNumber > 0 && x.Data.Status.HasFlag(StationStatus.PH_Status) && !x.Data.Status.HasFlag(StationStatus.Run));
  316. return number;
  317. }).First().Item2
  318. .Where(x => x.Data2.TaskNumber > 0 && x.Data.Status.HasFlag(StationStatus.PH_Status));
  319. //可用取货位数量为1,且出库任务有优先
  320. if (devGroup.Count() == 1 && (obj.Entity.GetFlag<bool>($"isOut-{obj.Entity.Code}") || taskss.Any(v => v.Device == obj.Entity.Code && v.Status == TaskStatus.WaitingToExecute && v.Type == TaskType.OutDepot)))
  321. {
  322. obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //跳过入库任务执行出库任务,下次直接查询是否有出库任务,避免无效检查周期的产生
  323. return;
  324. }
  325. if (!devGroup.Any())
  326. {
  327. obj.Entity.SetFlag("InQuantity", inMaxQuantity + 100); //在无有效取货位的情况下,只检查一次,下次直接查询是否有出库任务,避免无效检查周期的产生
  328. throw new KnownException($"无有效入库取货位", LogLevelEnum.High);
  329. }
  330. //如果入库任务只有一个
  331. //等待下发的任务信息
  332. var taskList = new List<Tuple<WCS_TaskInfo, Device<IStation523, IStation524>>>();
  333. SqlSugarHelper.Do(db =>
  334. {
  335. foreach (var dev in devGroup)
  336. {
  337. var task = db.Default.Queryable<WCS_TaskInfo>().First(v => v.Type == TaskType.SetPlate && v.Status == Entity.TaskStatus.FinishOfShunt && dev.Data2.TaskNumber == v.ID);
  338. if (task == null) continue;
  339. task.Status = Entity.TaskStatus.StackerExecution;
  340. task.LastInteractionPoint = dev.Entity.Code;
  341. task.SrmStation = dev.Entity.Code;
  342. task.Device = obj.Entity.Code;
  343. task.EditWho = "WCS";
  344. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.AddrTo, x.Line, x.Col, x.Layer, x.Depth, x.LastInteractionPoint, x.SrmStation, x.Device, x.EditWho }).ExecuteCommand();
  345. task.AddWCS_TASK_DTL(db.Default, dev.Entity.Code, task.AddrTo, "任务下发机械臂执行");
  346. taskList.Add(new(task, dev));
  347. }
  348. });
  349. if (!taskList.Any()) return;
  350. switch (taskList.Count)
  351. {
  352. case 1:
  353. var task = taskList.FirstOrDefault().Item1;
  354. var dev = taskList.FirstOrDefault().Item2;
  355. //下发任务
  356. obj.Data.TaskNumber1 = task.ID;
  357. obj.Data.SLine1 = dev.Entity.Code.ToShort();
  358. obj.Data.SCol1 = 0;
  359. obj.Data.SLayer1 = 0;
  360. obj.Data.SDepth1 = 0;
  361. obj.Data.ELine1 = task.Line.ToShort();
  362. obj.Data.ECol1 = task.Col.ToShort();
  363. obj.Data.ELayer1 = task.Layer.ToShort();
  364. obj.Data.EDepth1 = task.Depth.ToShort();
  365. obj.Data.TaskNumber2 = 0;
  366. obj.Data.SLine2 = 0;
  367. obj.Data.SCol2 = 0;
  368. obj.Data.SLayer2 = 0;
  369. obj.Data.SDepth2 = 0;
  370. obj.Data.ELine2 = 0;
  371. obj.Data.ECol2 = 0;
  372. obj.Data.ELayer2 = 0;
  373. obj.Data.EDepth2 = 0;
  374. obj.Data.TaskSum = taskList.Count.ToShort();
  375. obj.Data.GoodsType = task.GoodsType switch
  376. {
  377. 18 => 1,
  378. 34 => 2,
  379. 50 => 3,
  380. _ => 0
  381. };
  382. obj.Data.TaskType = 3;
  383. obj.Data.VoucherNo++;
  384. break;
  385. case 2:
  386. taskList = taskList = taskList.OrderBy(x => x.Item1.Depth).ToList();
  387. //一工位取深度较大的任务
  388. var taskInfo = taskList[1];
  389. task = taskInfo.Item1;
  390. dev = taskInfo.Item2;
  391. obj.Data.TaskNumber1 = task.ID;
  392. obj.Data.SLine1 = dev.Entity.Code.ToShort();
  393. obj.Data.SCol1 = 0;
  394. obj.Data.SLayer1 = 0;
  395. obj.Data.SDepth1 = 0;
  396. obj.Data.ELine1 = task.Line.ToShort();
  397. obj.Data.ECol1 = task.Col.ToShort();
  398. obj.Data.ELayer1 = task.Layer.ToShort();
  399. obj.Data.EDepth1 = task.Depth.ToShort();
  400. //二工位取深度较少的值
  401. taskInfo = taskList[0];
  402. task = taskInfo.Item1;
  403. dev = taskInfo.Item2;
  404. obj.Data.TaskNumber2 = task.ID;
  405. obj.Data.SLine2 = dev.Entity.Code.ToShort();
  406. obj.Data.SCol2 = 0;
  407. obj.Data.SLayer2 = 0;
  408. obj.Data.SDepth2 = 0;
  409. obj.Data.ELine2 = task.Line.ToShort();
  410. obj.Data.ECol2 = task.Col.ToShort();
  411. obj.Data.ELayer2 = task.Layer.ToShort();
  412. obj.Data.EDepth2 = task.Depth.ToShort();
  413. obj.Data.TaskSum = taskList.Count.ToShort();
  414. obj.Data.GoodsType = task.GoodsType switch
  415. {
  416. 18 => 1,
  417. 34 => 2,
  418. 50 => 3,
  419. _ => 0
  420. };
  421. obj.Data.TaskType = 3;
  422. obj.Data.VoucherNo++;
  423. break;
  424. default:
  425. throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid);
  426. }
  427. World.Log($"机械臂任务处理:下发入库任务{obj.Data.TaskNumber1}--{obj.Data.TaskNumber2}--{obj.Data.VoucherNo}", LogLevelEnum.Mid);
  428. }
  429. else //出库任务
  430. {
  431. //判断本次优先执行楼层,并设置下次执行时优先楼层
  432. var floor = obj.Entity.GetFlag<int>("FloorOut");
  433. floor = floor % 2 + 1;
  434. obj.Entity.SetFlag("FloorOut", floor);
  435. obj.Entity.SetFlag("InQuantity", 0);
  436. //获取当前堆垛机所有的取货站台
  437. var arrOut = PutDevices.First(v => v.Key == obj.Entity.Code).Value;
  438. if (!arrOut.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无放货路径点", LogLevelEnum.High);
  439. //获取可以放货的设备集合
  440. arrOut = arrOut.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status) && v.Data.TaskNumber == 0 && v.Data.GoodsEnd == 0).ToList();//有光电
  441. if (!arrOut.Any())
  442. {
  443. World.Log($"[{obj.Entity.Code}]等待出库任务输送到位");
  444. return;
  445. }
  446. var taskInfoList = new List<WCS_TaskInfo>();
  447. var nextAdd = "";
  448. SqlSugarHelper.Do(db =>
  449. {
  450. //所有出库点设备号,即
  451. var allOutCode = arrOut.Select(v => new
  452. {
  453. v.Entity.Code,
  454. v.Data4.Type
  455. }).ToList();
  456. //两个工位同时码垛,并不会一个执行一次,只有一个托盘任务全部执行完毕,才会继续执行下一个,先生成任务的码垛工位会优先执行
  457. var taskInfos = db.Default.Queryable<WCS_TaskInfo>().NoLock().Where(v =>
  458. (v.Status == TaskStatus.WaitingToExecute || v.Status == TaskStatus.ConveyorExecution) &&
  459. v.Type == TaskType.OutDepot && v.Device == obj.Entity.Code)
  460. .ToList().Where(v => allOutCode.Any(x => v.SrmStation == x.Code && v.PalletType == x.Type))
  461. .ToList();
  462. var deliveryTask = db.Default.Queryable<WCS_TaskInfo>().Where(x => x.Status > 0 && x.Type == TaskType.Delivery).ToList().Select(x => x.AddrTo);
  463. taskInfos = taskInfos.Where(x => deliveryTask.Contains(x.SrmStation)).ToList();
  464. if (!taskInfos.Any())
  465. {
  466. World.Log("等待空托盘到位");
  467. return;
  468. }
  469. if (!taskInfos.Any()) throw new KnownException($"未找到站台{JsonConvert.SerializeObject(allOutCode)}可用的出库任务", LogLevelEnum.Mid);
  470. var srmStation = taskInfos.GroupBy(x => x.SrmStation).Where(x => x.Any(s => s.Status == TaskStatus.WaitingToExecute)).Select(x => new
  471. {
  472. x.Key,
  473. x.OrderByDescending(t => t.AddTime).First().AddTime
  474. }).OrderBy(x => x.AddTime).First().Key;
  475. taskInfos = taskInfos.Where(x => x.SrmStation == srmStation).ToList(); //找到一个可以放货的待执行站台
  476. //如果全部是待执行状态,需要验证待执行的任务的数量是否与任务总数相等
  477. if (taskInfos.All(x => x.Status == TaskStatus.WaitingToExecute))
  478. {
  479. var task = taskInfos.First();
  480. if (task.FullQty != taskInfos.Count) throw new KnownException($"等待站台{srmStation}所有码垛出库任务完成初始化", LogLevelEnum.Mid);
  481. }
  482. taskInfos = taskInfos.Where(x => x.Status == TaskStatus.WaitingToExecute).OrderBy(x => x.ProdLine).ToList();
  483. if (taskInfos.FirstOrDefault().WarehouseCode.Contains("S")) //如果是南侧,翻转排序
  484. {
  485. taskInfos = taskInfos.OrderByDescending(x => x.ProdLine).ToList();
  486. }
  487. var surplusTaskNumber = taskInfos.Count; //剩余任务数量
  488. taskInfos = taskInfos.Take(2).ToList();
  489. var warehouseCode = taskInfos.FirstOrDefault().WarehouseCode;
  490. var exTaskNumber = taskInfos.Count;//执行任务数量
  491. surplusTaskNumber -= exTaskNumber;
  492. if (exTaskNumber == 2) //有两个任务
  493. {
  494. var minDepth = taskInfos!.MinBy(x => x.Depth);
  495. var maxDepth = taskInfos.MaxBy(x => x.Depth);
  496. //产品类型不同时,只能取一个
  497. if (minDepth.GoodsType != maxDepth.GoodsType)
  498. {
  499. //南边取位号较大的,北边取位号较小的
  500. taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList();
  501. }
  502. //深度之和等于6(机械臂当前无法同时执行两个三深度的取货任务)
  503. else if (taskInfos.Sum(x => x.Depth) == 6)
  504. {
  505. taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList();
  506. }
  507. else if (taskInfos[0].SrmStation != taskInfos[1].SrmStation)
  508. {
  509. taskInfos = warehouseCode.Contains("S") ? taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList() : taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList();
  510. }
  511. else if (warehouseCode.Contains("S"))
  512. {
  513. //从大到小 一抓偶数
  514. var max = taskInfos.MaxBy(x => x.ProdLine).ProdLine;
  515. if ((max & 1) == 1) //抓一不是偶数
  516. {
  517. taskInfos = taskInfos.OrderByDescending(x => x.ProdLine).Take(1).ToList();
  518. }
  519. }
  520. else if (warehouseCode.Contains("N"))
  521. {
  522. //从小到达 一抓奇数
  523. var mix = taskInfos.MinBy(x => x.ProdLine).ProdLine;
  524. if ((mix & 1) == 0) //抓一不是奇数
  525. {
  526. taskInfos = taskInfos.OrderBy(x => x.ProdLine).Take(1).ToList();
  527. }
  528. }
  529. }
  530. #region 计算剩余可执行任务数
  531. //如果有两个任务,且只有一个任务可以执行,剩余任务数+1
  532. if (exTaskNumber == 2 && taskInfoList.Count == 1) surplusTaskNumber += 1;
  533. if (surplusTaskNumber >= 1) obj.Entity.SetFlag($"isOut-{obj.Entity.Code}", true); //剩余任务数大于或等于1,下次满足条件时可以优先执行出库任务
  534. else obj.Entity.SetFlag($"isOut-{obj.Entity.Code}", false); //剩余任务数等于或小于0,下次满足条件时不可以优先执行出库任务
  535. #endregion 计算剩余可执行任务数
  536. foreach (var task in taskInfos)
  537. {
  538. task.Status = Entity.TaskStatus.StackerExecution;
  539. task.LastInteractionPoint = task.Device;
  540. task.StartTime = DateTime.Now;
  541. task.EditWho = "WCS";
  542. nextAdd = task.SrmStation;
  543. db.Default.UpdateableRowLock(task).UpdateColumns(x => new { x.Status, x.LastInteractionPoint, x.StartTime, x.EditWho }).ExecuteCommand();
  544. task.AddWCS_TASK_DTL(db.Default, task.Device, task.SrmStation, "任务下发机械臂执行");
  545. taskInfoList.Add(task);
  546. }
  547. });
  548. if (!taskInfoList.Any()) return;
  549. switch (taskInfoList.Count)
  550. {
  551. case 1:
  552. var task = taskInfoList.FirstOrDefault();
  553. //下发任务
  554. obj.Data.TaskNumber1 = task.ID;
  555. obj.Data.SLine1 = task.Line.ToShort();
  556. obj.Data.SCol1 = task.Col.ToShort();
  557. obj.Data.SLayer1 = task.Layer.ToShort();
  558. obj.Data.SDepth1 = task.Depth.ToShort();
  559. obj.Data.ELine1 = nextAdd.ToShort();
  560. obj.Data.ECol1 = task.ProdLine;
  561. obj.Data.ELayer1 = 0;
  562. obj.Data.EDepth1 = 0;
  563. obj.Data.TaskNumber2 = 0;
  564. obj.Data.SLine2 = 0;
  565. obj.Data.SCol2 = 0;
  566. obj.Data.SLayer2 = 0;
  567. obj.Data.SDepth2 = 0;
  568. obj.Data.ELine2 = 0;
  569. obj.Data.ECol2 = 0;
  570. obj.Data.ELayer2 = 0;
  571. obj.Data.EDepth2 = 0;
  572. obj.Data.TaskSum = taskInfoList.Count.ToShort();
  573. obj.Data.GoodsType = task.GoodsType switch
  574. {
  575. 18 => 1,
  576. 34 => 2,
  577. 50 => 3,
  578. _ => 0
  579. };
  580. obj.Data.TaskType = 4;
  581. obj.Data.VoucherNo++;
  582. break;
  583. case 2:
  584. taskInfoList = taskInfoList.OrderBy(x => x.Depth).ToList();
  585. //一工位取深度较大的任务
  586. var taskInfo = taskInfoList[1];
  587. obj.Data.TaskNumber1 = taskInfo.ID;
  588. obj.Data.SLine1 = taskInfo.Line.ToShort();
  589. obj.Data.SCol1 = taskInfo.Col.ToShort();
  590. obj.Data.SLayer1 = taskInfo.Layer.ToShort();
  591. obj.Data.SDepth1 = taskInfo.Depth.ToShort();
  592. obj.Data.ELine1 = nextAdd.ToShort();
  593. obj.Data.ECol1 = taskInfo.WarehouseCode.Contains("S") ? taskInfoList.Max(x => x.ProdLine) : taskInfoList.Min(x => x.ProdLine);
  594. obj.Data.ELayer1 = 0;
  595. obj.Data.EDepth1 = 0;
  596. //二工位取深度较少的值
  597. taskInfo = taskInfoList[0];
  598. obj.Data.TaskNumber2 = taskInfo.ID;
  599. obj.Data.SLine2 = taskInfo.Line.ToShort();
  600. obj.Data.SCol2 = taskInfo.Col.ToShort();
  601. obj.Data.SLayer2 = taskInfo.Layer.ToShort();
  602. obj.Data.SDepth2 = taskInfo.Depth.ToShort();
  603. obj.Data.ELine2 = nextAdd.ToShort();
  604. obj.Data.ECol2 = taskInfo.WarehouseCode.Contains("S") ? taskInfoList.Min(x => x.ProdLine) : taskInfoList.Max(x => x.ProdLine);
  605. obj.Data.ELayer2 = 0;
  606. obj.Data.EDepth2 = 0;
  607. obj.Data.TaskSum = taskInfoList.Count.ToShort();
  608. obj.Data.GoodsType = taskInfo.GoodsType switch
  609. {
  610. 18 => 1,
  611. 34 => 2,
  612. 50 => 3,
  613. _ => 0
  614. };
  615. obj.Data.TaskType = 4;
  616. obj.Data.VoucherNo++;
  617. break;
  618. default:
  619. throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid);
  620. }
  621. World.Log($"机械臂任务处理:下发出库任务{obj.Data.TaskNumber1}--{obj.Data.TaskNumber2}--{obj.Data.VoucherNo}", LogLevelEnum.Mid);
  622. }
  623. }
  624. }
  625. public override bool Select(Device dev)
  626. {
  627. return dev.Code is "Robot1" or "Robot2" or "Robot3" or "Robot4" or "Robot5" or "Robot6";
  628. }
  629. public List<string> GetDeviceCodeList(string code)
  630. {
  631. return code switch
  632. {
  633. "424" => new List<string>()
  634. {
  635. "424",
  636. "425",
  637. "422",
  638. "426",
  639. "427"
  640. },
  641. "433" => new List<string>()
  642. {
  643. "433",
  644. "434",
  645. "431",
  646. "435",
  647. "436"
  648. },
  649. "442" => new List<string>()
  650. {
  651. "442",
  652. "443",
  653. "440",
  654. "444",
  655. "445"
  656. },
  657. "642" => new List<string>()
  658. {
  659. "642",
  660. "643",
  661. "640",
  662. "644",
  663. "645"
  664. },
  665. "633" => new List<string>()
  666. {
  667. "633",
  668. "634",
  669. "631",
  670. "635",
  671. "636"
  672. },
  673. "624" => new List<string>()
  674. {
  675. "624",
  676. "625",
  677. "622",
  678. "226",
  679. "627"
  680. },
  681. "824" => new List<string>()
  682. {
  683. "824",
  684. "825",
  685. "822",
  686. "826",
  687. "827"
  688. },
  689. "833" => new List<string>()
  690. {
  691. "833",
  692. "834",
  693. "831",
  694. "835",
  695. "836"
  696. },
  697. "842" => new List<string>()
  698. {
  699. "842",
  700. "843",
  701. "840",
  702. "844",
  703. "845"
  704. },
  705. "1042" => new List<string>()
  706. {
  707. "1042",
  708. "1043"
  709. //"1040",
  710. //"1044",
  711. //"1045"
  712. },
  713. "1033" => new List<string>()
  714. {
  715. "1033",
  716. "1034"
  717. //"1031",
  718. //"1035",
  719. //"1036"
  720. },
  721. "1024" => new List<string>()
  722. {
  723. "1024",
  724. "1025",
  725. "1022",
  726. "1026",
  727. "1027"
  728. },
  729. "1224" => new List<string>()
  730. {
  731. "1224",
  732. "1225",
  733. "1222",
  734. "1226",
  735. "1227"
  736. },
  737. "1233" => new List<string>()
  738. {
  739. "1233",
  740. "1234",
  741. "1231",
  742. "1235",
  743. "1236"
  744. },
  745. "1242" => new List<string>()
  746. {
  747. "1242",
  748. "1243",
  749. "1240",
  750. "1244",
  751. "1245"
  752. },
  753. "1442" => new List<string>()
  754. {
  755. "1442",
  756. "1443",
  757. "1440",
  758. "1444",
  759. "1445"
  760. },
  761. "1433" => new List<string>()
  762. {
  763. "1433",
  764. "1434",
  765. "1431",
  766. "1435",
  767. "1436"
  768. },
  769. "1424" => new List<string>()
  770. {
  771. "1424",
  772. "1425",
  773. "1422",
  774. "1426",
  775. "1427"
  776. },
  777. _ => new List<string>()
  778. };
  779. }
  780. }
  781. }