机械臂cs.cs 34 KB

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