终端一体化运控平台
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

908 linhas
39 KiB

  1. using static BPA.Helper.EventBus;
  2. using System.Collections.Concurrent;
  3. using BPASmartClient.CustomResource;
  4. using BPASmartClient.MorkSVer3.Enum;
  5. //using BPA.Helper;
  6. namespace BPASmartClient.MorkSVer3
  7. {
  8. public class Control_MorkSVer3 : BaseDevice
  9. {
  10. public override DeviceClientType DeviceType => DeviceClientType.MORKS;
  11. private GVL_MorkSVer3 mORKS = new GVL_MorkSVer3();
  12. private Alarm alarm = new Alarm();
  13. public override void DoMain()
  14. {
  15. MonitorViewModel.DeviceId = DeviceId;
  16. ServerInit();
  17. DataParse();
  18. Json<MorksPar>.Read();
  19. Json<OrderStatistics>.Read();
  20. if (Json<MorksPar>.Data.parSets == null)
  21. Json<MorksPar>.Data.parSets = new ObservableCollection<ParSet>();
  22. if (Json<MorksPar>.Data.parSets.Count < 6)
  23. {
  24. Json<MorksPar>.Data.parSets.Clear();
  25. for (int i = 0; i < 6; i++)
  26. {
  27. Json<MorksPar>.Data.parSets.Add(new ParSet()
  28. {
  29. CheckBoxContext = $"煮面口{i + 1}屏蔽",
  30. Minute = 1,
  31. Second = 0,
  32. IsShield = false,
  33. TextBlockContext = $"煮面口{i + 1}时间设定"
  34. });
  35. }
  36. }
  37. ActionManage.GetInstance.Register(new Action<object[]>((o) =>
  38. {
  39. if (o.Length > 0)
  40. {
  41. Random rd = new Random();
  42. TaskManage.GetInstance.StartLong(new Action(() =>
  43. {
  44. int NoodleLoc = (int)o[0] == 0 ? rd.Next(1, 4) : (int)o[0];
  45. int BowlLoc = (int)o[1] == 0 ? rd.Next(10, 12) : (int)o[1];
  46. string guid = Guid.NewGuid().ToString();
  47. var locInfo = new OrderLocInfo() { Loc = (ushort)NoodleLoc, SuborderId = guid };
  48. mORKS.MakeNoodleTask.Enqueue(locInfo);
  49. mORKS.RBTakeNoodleTask.Enqueue(locInfo);
  50. MessageLog.GetInstance.Show($"添加模拟订单【{guid}】:面条位置【{NoodleLoc}】");
  51. mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = (ushort)BowlLoc, SuborderId = guid });
  52. MessageLog.GetInstance.Show($"添加模拟订单【{guid}】:碗位置【{BowlLoc}】");
  53. Thread.Sleep(60000);
  54. }), "ForOrder");
  55. }
  56. }), "EnableForOrder");
  57. ActionManage.GetInstance.Register(new Action<object>((o) =>
  58. {
  59. if (o != null && o is WritePar writePar)
  60. WriteData(writePar.Address, writePar.Value);
  61. }), "WriteVW");
  62. ActionManage.GetInstance.Register(new Action<object>((o) =>
  63. {
  64. if (o != null && o is WritePar writePar)
  65. WriteData(writePar.Address, writePar.Value);
  66. }), "WriteBools");
  67. ActionManage.GetInstance.Register(new Action(() => { DeviceInit(); }), "InitDevice");
  68. }
  69. public override void ResetProgram()
  70. {
  71. mORKS = null;
  72. mORKS = new GVL_MorkSVer3();
  73. }
  74. public override void Stop()
  75. {
  76. }
  77. private void ServerInit()
  78. {
  79. //物料信息
  80. EventBus.GetInstance.Subscribe<MaterialDeliveryEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack)
  81. {
  82. if (@event == null)
  83. return;
  84. if (@event is MaterialDeliveryEvent material)
  85. {
  86. orderMaterialDelivery = material.orderMaterialDelivery;
  87. }
  88. });
  89. //配方数据信息
  90. EventBus.GetInstance.Subscribe<RecipeBomEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack)
  91. {
  92. if (@event == null)
  93. return;
  94. if (@event is RecipeBomEvent recipe)
  95. {
  96. recipeBoms = recipe.recipeBoms;
  97. }
  98. });
  99. OrderNotifyInit();
  100. }
  101. #region 接口通知任务处理
  102. ConcurrentQueue<OrderStatusModel> osm = new ConcurrentQueue<OrderStatusModel>();
  103. private void OrderNotifyInit()
  104. {
  105. TaskManage.GetInstance.StartLong(() =>
  106. {
  107. while (osm.Count > 0)
  108. {
  109. TempOrderChange(osm.ElementAt(0).SubOrderId, osm.ElementAt(0).Status, () =>
  110. {
  111. osm.TryDequeue(out OrderStatusModel tempOSM);
  112. DeviceProcessLogShow($"订单:【{tempOSM.SubOrderId}】, 状态:【{tempOSM.Status}】, API状态修改成功。");
  113. });
  114. }
  115. Thread.Sleep(100);
  116. }, $"订单状态更新接口{DeviceId}", true);
  117. }
  118. private void TempOrderChange(string subid, ORDER_STATUS oRDER_STATUS, Action complete)
  119. {
  120. var res = mORKS.doOrderEvents.FirstOrDefault(p => p.MorkOrder.SuborderId == subid);
  121. string goodName = string.Empty;
  122. string SortNum = string.Empty;
  123. if (res != null)
  124. {
  125. goodName = res.MorkOrder.GoodsName;
  126. SortNum = res.MorkOrder.SortNum.ToString();
  127. }
  128. if (!string.IsNullOrEmpty(goodName) && !string.IsNullOrEmpty(SortNum))
  129. {
  130. EventBus.GetInstance.Publish(new OrderStatusChangedEvent() { SortNum = SortNum, GoodName = goodName, Status = oRDER_STATUS, SubOrderId = subid, deviceClientType = DeviceType }, e => { complete?.Invoke(); });
  131. var index = DataServer.GetInstance.morkS.MakeOrder.FindIndex(p => p.SortNum == SortNum);
  132. //如果订单信息已经存在,则修改状态,否则新增。
  133. if (index >= 0 && index < DataServer.GetInstance.morkS.MakeOrder.Count)
  134. {
  135. if (oRDER_STATUS == ORDER_STATUS.COMPLETED_COOK)
  136. {
  137. DataServer.GetInstance.morkS.MakeOrder.RemoveAt(index);
  138. DataServer.GetInstance.morkS.MakeOrderOver.Add(new OrderMakeModel()
  139. {
  140. Status = oRDER_STATUS,
  141. GoodName = goodName,
  142. SortNum = SortNum,
  143. StopTime = DateTime.Now.ToString("HH:mm:ss")
  144. });
  145. }
  146. else if (oRDER_STATUS == ORDER_STATUS.COMPLETED_TAKE)
  147. {
  148. var temp = DataServer.GetInstance.morkS.MakeOrderOver.FirstOrDefault(p => p.SortNum == SortNum);
  149. if (temp != null) DataServer.GetInstance.morkS.MakeOrderOver.Remove(temp);
  150. }
  151. else DataServer.GetInstance.morkS.MakeOrder.ElementAt(index).Status = oRDER_STATUS;
  152. }
  153. else
  154. {
  155. DataServer.GetInstance.morkS.MakeOrder.Add(new OrderMakeModel()
  156. {
  157. Status = oRDER_STATUS,
  158. GoodName = goodName,
  159. SortNum = SortNum,
  160. StartTime = DateTime.Now.ToString("HH:mm:ss")
  161. });
  162. }
  163. }
  164. }
  165. #endregion
  166. private void OrderChange(string subid, ORDER_STATUS oRDER_STATUS)
  167. {
  168. osm.Enqueue(new OrderStatusModel() { SubOrderId = subid, Status = oRDER_STATUS });
  169. return;
  170. }
  171. private void GetStatus(string key, Action<object> action)
  172. {
  173. if (peripheralStatus.ContainsKey(key))
  174. {
  175. if (peripheralStatus[key] != null)
  176. {
  177. action?.Invoke(peripheralStatus[key]);
  178. }
  179. }
  180. }
  181. public override void ReadData()
  182. {
  183. //DataServer.GetInstance.morkS.Alarm.Clear();
  184. //alarms.ForEach(item =>
  185. //{
  186. // DataServer.GetInstance.morkS.Alarm.Add(new AlarmModel()
  187. // {
  188. // AlarmTime = $"{item.Date} {item.Time}",
  189. // AlarmMs = item.Info
  190. // });
  191. //});
  192. GetStatus("M0.1", new Action<object>((obj) =>
  193. {
  194. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 7)
  195. {
  196. Initing = !bools[0];
  197. mORKS.InitComplete = bools[0];
  198. mORKS.MoveScrewRodInitCom = bools[1];
  199. mORKS.SacrificialVesselInitCom = bools[2];
  200. mORKS.CylinderInitCom = bools[3];
  201. mORKS.NoodleCookerInitCom = bools[4];
  202. mORKS.RobotInitCom = bools[5];
  203. mORKS.NMachInitComp = bools[6];
  204. alarm.DeviceNoInit = !mORKS.InitComplete;
  205. alarm.MoveScrewRodNoInit = !mORKS.MoveScrewRodInitCom;
  206. alarm.SacrificialVesselNoInit = !mORKS.SacrificialVesselInitCom;
  207. alarm.CylinderNoInit = !mORKS.CylinderInitCom;
  208. alarm.NoodleCookerNoInit = !mORKS.NoodleCookerInitCom;
  209. alarm.RobotNoInit = !mORKS.RobotInitCom;
  210. alarm.NMachNoInit = !mORKS.NMachInitComp;
  211. }
  212. }));
  213. GetStatus("M10.0", new Action<object>((obj) =>
  214. {
  215. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 2)
  216. {
  217. mORKS.AllowInvertedFace = bools[0];
  218. mORKS.DiningComplete = bools[1];
  219. }
  220. }));
  221. GetStatus("M10.4", new Action<object>((obj) =>
  222. {
  223. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 1)
  224. {
  225. mORKS.DropBowlMechanismStatus = bools[0];
  226. }
  227. }));
  228. GetStatus("M12.2", new Action<object>((obj) =>
  229. {
  230. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 1)
  231. {
  232. mORKS.FixedFlag = bools[0];
  233. }
  234. }));
  235. GetStatus("M13.0", new Action<object>((obj) =>
  236. {
  237. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 3)
  238. {
  239. mORKS.CylLeftPos = bools[0];
  240. mORKS.CylRightPos = bools[1];
  241. mORKS.CylRotate = bools[2];
  242. alarm.NoodleBoxError = mORKS.CylRightPos == mORKS.CylLeftPos;
  243. }
  244. }));
  245. GetStatus("M16.7", new Action<object>((obj) =>
  246. {
  247. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 1)
  248. {
  249. mORKS.RobotTakeNoodleCom = bools[0];
  250. }
  251. }));
  252. GetStatus("M17.4", new Action<object>((obj) =>
  253. {
  254. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 1)
  255. {
  256. mORKS.RobotStatus = bools[0];
  257. }
  258. }));
  259. GetStatus("M18.0", new Action<object>((obj) =>
  260. {
  261. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 5)
  262. {
  263. mORKS.SmallBowlYesOrNoCheck = bools[0];
  264. mORKS.LargeBowYesOrNoCheck = bools[1];
  265. //mORKS.TurntableLowPosition = bools[2];
  266. //mORKS.TurntableHighPosition = bools[3];
  267. alarm.Supply2_LossBowl = !mORKS.SmallBowlYesOrNoCheck;
  268. alarm.Supply1_LossBowl = !mORKS.LargeBowYesOrNoCheck;
  269. }
  270. }));
  271. GetStatus("M20.0", new Action<object>((obj) =>
  272. {
  273. if (obj is bool[] bools && bools.Length > 0 && bools.Length <= 1)
  274. {
  275. mORKS.NMachMakeComp = bools[0];
  276. }
  277. }));
  278. GetStatus("VW17", new Action<object>((obj) =>
  279. {
  280. if (obj is ushort[] ushorts && ushorts.Length > 0 && ushorts.Length <= 1)
  281. {
  282. var tt = ushorts.ToBytes().ToUShorts();
  283. for (byte i = 0; i < 6; i++)
  284. {
  285. if (RTrig.GetInstance($"CookNoodleCom{i + 1}").Start(tt[0].GetBitValue((byte)(i + 1))))
  286. {
  287. if (!string.IsNullOrEmpty(mORKS.CookNodelId[i]))
  288. mORKS.CookNoodleCom[i] = true;
  289. }
  290. }
  291. mORKS.Heating = ushorts[0].GetBitValue(15);
  292. mORKS.TemperatureReaches = ushorts[0].GetBitValue(16);
  293. alarm.MachineLowTemperature = !mORKS.TemperatureReaches;
  294. }
  295. }));
  296. //GetStatus("VW770", new Action<object>((obj) =>
  297. //{
  298. // if (obj is ushort[] ushorts && ushorts.Length > 0 && ushorts.Length <= 1)
  299. // {
  300. // mORKS.CurrentFeedbackLoc = ushorts[0];
  301. // }
  302. //}));
  303. mORKS.TakeBowlTaskCount = mORKS.TakeBowlTask.Count;
  304. mORKS.RBTakeNoodleTaskCount = mORKS.RBTakeNoodleTask.Count;
  305. for (int i = 0; i < Json<MorksPar>.Data.parSets.Count; i++)
  306. {
  307. mORKS.nsm.ElementAt(i).IsShield = Json<MorksPar>.Data.parSets.ElementAt(i).IsShield;
  308. mORKS.nsm.ElementAt(i).NoodleCookerStatus = mORKS.NoodleCookerStatus[i];
  309. }
  310. }
  311. /// <summary>数据解析</summary>
  312. private void DataParse()
  313. {
  314. EventBus.GetInstance.Subscribe<DoOrderEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBackHandle)
  315. {
  316. if (@event == null)
  317. return;
  318. if (@event is DoOrderEvent order)
  319. {
  320. mORKS.doOrderEvents.Add(order);
  321. //mORKS.doe.TryAdd(order.MorkOrder.SuborderId, order);
  322. if (order.MorkOrder.GoodBatchings == null)
  323. return;
  324. if (mORKS.HistorySuborderId.Contains(order.MorkOrder.SuborderId))
  325. return;
  326. OrderCount++;
  327. if (DateTime.Now.Subtract(Json<OrderStatistics>.Data.StatisticsTime).Days != 0)
  328. Json<OrderStatistics>.Data.Count = 0;
  329. Json<OrderStatistics>.Data.StatisticsTime = DateTime.Now;
  330. Json<OrderStatistics>.Data.Count++;
  331. Json<OrderStatistics>.Save();
  332. OrderChange(order.MorkOrder.SuborderId, ORDER_STATUS.WAIT);
  333. DeviceProcessLogShow($"接收到{OrderCount}次订单,订单ID:{order.MorkOrder.SuborderId}");
  334. mORKS.HistorySuborderId.Add(order.MorkOrder.SuborderId);
  335. foreach (var item in order.MorkOrder.GoodBatchings)
  336. {
  337. var res = orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId);
  338. if (res != null)
  339. {
  340. if (ushort.TryParse(res.BatchingLoc, out ushort loc))
  341. {
  342. if (loc >= 1 && loc <= 3)
  343. {
  344. var result1 = mORKS.RBTakeNoodleTask.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null;
  345. var result2 = mORKS.MakeNoodleTask.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null;
  346. if (result1 && result2)
  347. {
  348. var info = new OrderLocInfo()
  349. {
  350. GoodName = order.MorkOrder.GoodsName,
  351. Loc = ushort.Parse(res.BatchingLoc),
  352. SuborderId = order.MorkOrder.SuborderId,
  353. SortNum = order.MorkOrder.SortNum,
  354. BatchingId = res.BatchingId
  355. };
  356. mORKS.RBTakeNoodleTask.Enqueue(info);
  357. mORKS.MakeNoodleTask.Enqueue(info);
  358. }
  359. }
  360. else if (loc >= 10 && loc <= 11)
  361. {
  362. int index = 0;
  363. if (recipeBoms != null)
  364. {
  365. index = Array.FindIndex(recipeBoms.RecipeIds?.ToArray(), p => p.RecipeId == order.MorkOrder.RecipeId);
  366. index++;
  367. }
  368. if (mORKS.TakeBowlTask.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null)
  369. mORKS.TakeBowlTask.Enqueue(new OrderLocInfo()
  370. {
  371. BatchingId = res.BatchingId,
  372. GoodName = order.MorkOrder.GoodsName,
  373. Loc = ushort.Parse(res.BatchingLoc),
  374. SuborderId = order.MorkOrder.SuborderId,
  375. SortNum = order.MorkOrder.SortNum,
  376. RecipeNumber = (index >= 1 && index <= 10) ? (ushort)index : (ushort)0
  377. });
  378. }
  379. }
  380. }
  381. }
  382. }
  383. });
  384. }
  385. public override void MainTask()
  386. {
  387. mORKS.AllowRun = mORKS.InitComplete;
  388. if (Json<KeepDataBase>.Data.IsVerify)
  389. IsHealth = mORKS.InitComplete;
  390. else
  391. IsHealth = true;
  392. TakeBowlTask();
  393. TakeNoodleTask();
  394. OutNoodleTask();
  395. SingleDetect();
  396. //TurntableControl();
  397. MakeNoodle();
  398. TurnBoxes();
  399. }
  400. private void BowlControl(OrderLocInfo orderLocInfo)
  401. {
  402. if (orderLocInfo.Loc >= 10 && orderLocInfo.Loc <= 11)
  403. {
  404. //mORKS.TakeBowlId = orderLocInfo.SuborderId;
  405. mORKS.TakeBowName = orderLocInfo.GoodName;
  406. mORKS.TakeBowSortNum = orderLocInfo.SortNum;
  407. TakeBowlControl(orderLocInfo.Loc);
  408. //OrderChange(mORKS.TakeBowlId, ORDER_STATUS.COOKING);
  409. OrderChange(orderLocInfo.SuborderId, ORDER_STATUS.COOKING);
  410. //DeviceProcessLogShow($"订单【{mORKS.TakeBowlId}】执行取碗控制,位置:[{orderLocInfo.Loc}]");
  411. //2023-8-5修改修改取碗打印日志。
  412. //DeviceProcessLogShow($"订单【{orderLocInfo.SuborderId}】执行取碗控制,位置:[{orderLocInfo.Loc}]");
  413. DeviceProcessLogShow($"执行取碗控制,位置:[{orderLocInfo.Loc}]");
  414. mORKS.TakeBowlInterlock = true;
  415. }
  416. }
  417. /// <summary>取碗控制</summary>
  418. private void TakeBowlTask()
  419. {
  420. if (mORKS.AllowRun && mORKS.TakeBowlTask.Count > 0 && !mORKS.DropBowlMechanismStatus && !mORKS.TakeBowlInterlock)
  421. {
  422. ushort BowLoc = 0;
  423. var res = orderMaterialDelivery?.BatchingInfo?.Where(p => p.BatchingId == mORKS.TakeBowlTask.ElementAt(0).BatchingId).ToList();
  424. if (res == null || res?.Count == 0)
  425. {
  426. if (mORKS.TakeBowlTask.TryDequeue(out OrderLocInfo orderLocInfo))
  427. BowlControl(orderLocInfo);
  428. }
  429. else
  430. {
  431. foreach (var item in res)
  432. {
  433. if (ushort.TryParse(item.BatchingLoc, out ushort loc))
  434. {
  435. if (loc == 10 && mORKS.SmallBowlYesOrNoCheck)
  436. {
  437. BowLoc = loc;
  438. break;
  439. }
  440. else if (loc == 11 && mORKS.LargeBowYesOrNoCheck)
  441. {
  442. BowLoc = loc;
  443. break;
  444. }
  445. }
  446. }
  447. if (BowLoc >= 10 && BowLoc <= 11)
  448. {
  449. if (mORKS.TakeBowlTask.TryDequeue(out OrderLocInfo orderLocInfo))
  450. {
  451. orderLocInfo.Loc = BowLoc;
  452. BowlControl(orderLocInfo);
  453. }
  454. }
  455. }
  456. }
  457. }
  458. private void MakeNoodle()
  459. {
  460. //TODO:可能会需要取消制作完成条件,刚开机可能没有制作完成。
  461. if (mORKS.AllowRun && !mORKS.MakeNoodleInterlock && mORKS.MakeNoodleTask.Count > 0 && mORKS.NMachMakeComp && mORKS.NoodleBoxes[0] == null)
  462. {
  463. if (mORKS.MakeNoodleTask.TryDequeue(out OrderLocInfo order))
  464. {
  465. //TODO:具体物料大小份怎么定待商议。
  466. var loc = order.Loc;
  467. SetNMachMake(loc - 1);
  468. mORKS.CurrentMakeNoodleID = order.SuborderId;
  469. mORKS.CurrentMakeBatchingID = order.BatchingId;
  470. DeviceProcessLogShow($"订单【{order.SuborderId}】开始制面【{order.Loc}】。");
  471. mORKS.MakeNoodleInterlock = true;
  472. }
  473. }
  474. }
  475. private void TurnBoxes()
  476. {
  477. if (mORKS.AllowRun && !mORKS.TakeNoodleInterlock && !mORKS.MakeNoodleInterlock && mORKS.NMachMakeComp && mORKS.NoodleBoxes[0] != null && mORKS.NoodleBoxes[1] == null)
  478. {
  479. SwapNoodleBox();
  480. }
  481. }
  482. /// <summary>转台控制</summary>
  483. //private void TurntableControl()
  484. //{
  485. // if (Global.EnableLocalSimOrder)
  486. // {
  487. // //不做轮询,直接取面,模拟订单使用
  488. // if (mORKS.SiloInPlace && !mORKS.Feeding && mORKS.InitComplete && !mORKS.AllowTakeNoodle && mORKS.RBTakeNoodleTask.Count > 0)
  489. // {
  490. // if (mORKS.TurntableLowPosition)
  491. // {
  492. // TurntableStart(mORKS.RBTakeNoodleTask.ElementAt(0).Loc);
  493. // mORKS.TurntableLocLists.Clear();
  494. // mORKS.AllowTakeNoodle = true;
  495. // DeviceProcessLogShow($"控制机器人去转台【{mORKS.RBTakeNoodleTask.ElementAt(0).Loc}】号位置取面");
  496. // }
  497. // }
  498. // }
  499. // else
  500. // {
  501. // //正常轮询
  502. // if (Delay.GetInstance("到位检测延时").Start(mORKS.SiloInPlace, 2))
  503. // {
  504. // if (mORKS.SiloInPlace && !mORKS.Feeding && mORKS.InitComplete && !mORKS.AllowTakeNoodle && mORKS.RBTakeNoodleTask.Count > 0)
  505. // {
  506. // var result = orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == mORKS.RBTakeNoodleTask.ElementAt(0).BatchingId).ToList();
  507. // if (result != null)
  508. // {
  509. // var res = result.FirstOrDefault(P => P.BatchingLoc == mORKS.CurrentFeedbackLoc.ToString());
  510. // if (mORKS.TurntableLowPosition && res != null)
  511. // {
  512. // TurntableStart(mORKS.CurrentFeedbackLoc);
  513. // mORKS.TurntableLocLists.Clear();
  514. // mORKS.AllowTakeNoodle = true;
  515. // DeviceProcessLogShow($"控制机器人去转台【{mORKS.CurrentFeedbackLoc}】号位置取面");
  516. // }
  517. // else
  518. // {
  519. // if (!mORKS.TurntableInterlock)
  520. // {
  521. // foreach (var item in result)
  522. // {
  523. // if (ushort.TryParse(item.BatchingLoc, out ushort loc))
  524. // {
  525. // if (mORKS.CurrentFeedbackLoc != loc && !mORKS.TurntableLocLists.Contains(loc))
  526. // {
  527. // if (!mORKS.TurntableLowPosition)
  528. // {
  529. // DeviceProcessLogShow($"执行了转台启动互锁信号复位");
  530. // }
  531. // TurntableStart(loc);
  532. // DeviceProcessLogShow($"没有物料检测的启动转台控制,转台位置:[{loc}]");
  533. // break;
  534. // }
  535. // else if (mORKS.CurrentFeedbackLoc == loc && !mORKS.TurntableLocLists.Contains(loc))
  536. // mORKS.TurntableLocLists.Add(loc);
  537. // }
  538. // }
  539. // }
  540. // }
  541. // }
  542. // else
  543. // DeviceProcessLogShow("未找到可用的物料信息");
  544. // }
  545. // }
  546. // }
  547. // //补料中检测
  548. // if (RTrig.GetInstance("mORKS.Feeding").Start(mORKS.Feeding))
  549. // {
  550. // mORKS.AllowTakeNoodle = false;
  551. // mORKS.TakeNoodleInterlock = false;
  552. // }
  553. // //转台到位检测
  554. // if (RTrig.GetInstance("TurntableInPlace").Start(mORKS.SiloInPlace && mORKS.CurrentLoc == mORKS.CurrentFeedbackLoc))
  555. // {
  556. // mORKS.TurntableInterlock = false;
  557. // DeviceProcessLogShow("转台到位检测");
  558. // }
  559. // //补料完成检测
  560. // if (RTrig.GetInstance("FeedComplete").Start(mORKS.FeedComplete))
  561. // {
  562. // if (!mORKS.AllowTakeNoodle && mORKS.TurntableLocLists.Count > 0)
  563. // {
  564. // mORKS.TurntableLocLists.Clear();
  565. // mORKS.TurntableInterlock = false;
  566. // DeviceProcessLogShow("补料完成检测");
  567. // }
  568. // }
  569. //}
  570. /// <summary>取面任务</summary>
  571. private void TakeNoodleTask()
  572. {
  573. if (mORKS.AllowRun && mORKS.RobotStatus && !mORKS.RobotTaskInterlock && mORKS.AllowTakeNoodle && !mORKS.TakeNoodleInterlock && mORKS.RBTakeNoodleTask.Count > 0)
  574. {
  575. //查找煮面炉空闲位置
  576. int loc = mORKS.nsm.ToList().FindIndex(p => p.NoodleCookerStatus == false && p.IsShield == false);
  577. if (loc >= 0 && loc <= 5)
  578. {
  579. if (mORKS.RBTakeNoodleTask.TryDequeue(out OrderLocInfo orderLocInfo))
  580. {
  581. //写入煮面时间
  582. List<ushort> values = new List<ushort>();
  583. var setTime = Json<MorksPar>.Data.parSets.ElementAt(loc);
  584. values.Add(setTime.Minute);
  585. values.Add(setTime.Second);
  586. WriteData($"VW{324 + (loc * 4)}", values.ToArray());
  587. DeviceProcessLogShow($"煮面炉[{loc + 1}]:写入煮面时间{setTime.Minute}分{setTime.Second}秒。");
  588. mORKS.CookNodelId[loc] = orderLocInfo.SuborderId;
  589. mORKS.NoodleCookerStatus[loc] = true;
  590. SetFallNoodleLoc((ushort)(loc + 1));
  591. //机器人开始取面
  592. OrderChange(orderLocInfo.SuborderId, ORDER_STATUS.COOKING);
  593. DeviceProcessLogShow($"订单【{orderLocInfo.SuborderId}】,请求机器人倒面至【{loc + 1}】号煮面栏");
  594. mORKS.TakeNoodleInterlock = true;
  595. }
  596. }
  597. }
  598. }
  599. /// <summary>出餐控制</summary>
  600. private void OutNoodleTask()
  601. {
  602. if (mORKS.AllowInvertedFace && mORKS.RobotTaskInterlock && !mORKS.RobotOutDinnigLock && !mORKS.TakeNoodleInterlock && mORKS.RobotStatus)
  603. {
  604. for (int loc = 0; loc < mORKS.CookNodelId.Length; loc++)
  605. {
  606. if (mORKS.CookNoodleCom[loc] && !mORKS.RobotOutDinnigLock)
  607. {
  608. SetTakeNoodleLoc((ushort)(loc + 1));
  609. mORKS.NoodleCookerStatus[loc] = false;
  610. WriteData($"VW260", (ushort)0);//设置出汤时间
  611. OrderChange(mORKS.CookNodelId[loc], ORDER_STATUS.COMPLETED_COOK);
  612. DeviceProcessLogShow($"订单【{mORKS.CookNodelId[loc]}】制作完成");
  613. mORKS.CookCompleteFlatBit = true;
  614. mORKS.OutMealId = mORKS.CookNodelId[loc];
  615. mORKS.OutMealName = mORKS.IngredientsCompleteName;
  616. mORKS.OutMealSortNum = mORKS.IngredientsCompleteSortNum;
  617. mORKS.IngredientsCompleteId = string.Empty;
  618. mORKS.CookNodelId[loc] = string.Empty;
  619. DeviceProcessLogShow($"{loc + 1} 号位置出餐控制,订单ID:{mORKS.OutMealId}");
  620. mORKS.CookNoodleCom[loc] = false;
  621. mORKS.RobotOutDinnigLock = true;
  622. }
  623. }
  624. }
  625. }
  626. /// <summary>信号检测</summary>
  627. private void SingleDetect()
  628. {
  629. //允许倒面信号检测
  630. if (RTrig.GetInstance("AllowFallNoodle").Start(mORKS.AllowInvertedFace))
  631. {
  632. //mORKS.IngredientsCompleteId = mORKS.TakeBowlId;
  633. mORKS.IngredientsCompleteName = mORKS.TakeBowName;
  634. mORKS.IngredientsCompleteSortNum = mORKS.TakeBowSortNum;
  635. mORKS.TakeBowSortNum = 0;
  636. mORKS.TakeBowlId = string.Empty;
  637. mORKS.TakeBowName = string.Empty;
  638. //DeviceProcessLogShow($"碗到位,允许到面,{mORKS.IngredientsCompleteId}");
  639. DeviceProcessLogShow($"碗到位,允许倒面。");
  640. mORKS.TakeBowlInterlock = false;
  641. mORKS.RobotOutDinnigLock = false;
  642. }
  643. //取餐完成逻辑处理
  644. if (RTrig.GetInstance("CompleteChange1").Start(mORKS.DiningComplete) && mORKS.CookCompleteFlatBit == true)
  645. {
  646. OrderChange(mORKS.OutMealId, ORDER_STATUS.COMPLETED_TAKE);
  647. DeviceProcessLogShow($"订单【{mORKS.OutMealId}】取餐完成");
  648. WriteData("M10.1", false);
  649. var orderEvent = mORKS.doOrderEvents.FirstOrDefault(order => order.MorkOrder.SuborderId == mORKS.OutMealId);
  650. mORKS.OutMealSortNum = orderEvent?.MorkOrder.SortNum ?? 0;
  651. DeviceProcessLogShow($"出餐订单序号【{mORKS.OutMealSortNum}】");
  652. VoiceAPI.Speak(mORKS.OutMealSortNum.ToString());
  653. //DeviceProcessLogShow($"叫号系统通知主题【MORKS/VoiceCall/{DeviceId}】");
  654. //Plugin.GetInstance.GetPlugin<MQTTMgr>().Publish($"MORKS/VoiceCall/{DeviceId}", mORKS.OutMealSortNum.ToString());
  655. mORKS.CookCompleteFlatBit = false;
  656. mORKS.OutMealId = string.Empty;
  657. mORKS.OutMealName = string.Empty;
  658. mORKS.OutMealSortNum = 0;
  659. }
  660. //机器人取面完成信号检测
  661. if (RTrig.GetInstance("TakeNoodleComplete").Start(mORKS.RobotTakeNoodleCom))
  662. {
  663. mORKS.TakeNoodleInterlock = false;
  664. mORKS.AllowTakeNoodle = false;
  665. mORKS.TurntableInterlock = false;
  666. DeviceProcessLogShow("检测到机器人取面完成信号");
  667. }
  668. //制面机制面完成信号检测
  669. if (RTrig.GetInstance("MakeNoodleCompleted").Start(mORKS.NMachMakeComp))
  670. {
  671. DeviceProcessLogShow($"检测到制面机制面完成信号,配方【{mORKS.CurrentMakeNoodleID}】");
  672. mORKS.MakeNoodleInterlock = false;
  673. mORKS.NoodleBoxes[0] = new()
  674. {
  675. SubOrderID = mORKS.CurrentMakeNoodleID,
  676. BathingID = mORKS.CurrentMakeBatchingID,
  677. IsOccupy = true
  678. };
  679. mORKS.CurrentMakeNoodleID = string.Empty;
  680. }
  681. int OutMealRequstCount = mORKS.CookNoodleCom.Where(p => p == true).ToList().Count;
  682. //int mlCount = mORKS.NoodleCookerStatus.Where(p => p == true).ToList().Count - Json<MorksPar>.Data.parSets.Where(x => x.IsShield == true).ToList().Count;
  683. int mlCount = mORKS.nsm.Where(p => p.NoodleCookerStatus == true && p.IsShield == false).ToList().Count;
  684. int index = Array.FindIndex(mORKS.CookNodelId, p => p == mORKS.IngredientsCompleteId);
  685. bool isok = index >= 0 && index < mORKS.CookNoodleCom.Length && mORKS.CookNoodleCom[index];
  686. //mORKS.PriorityJudgment = Delay.GetInstance("取餐优先级判断").Start(mORKS.TurntableLocLists.Count > 0 && !mORKS.TurntableLowPosition, 4);
  687. //mORKS.RobotTaskInterlock = OutMealRequstCount > 0 && mORKS.AllowInvertedFace && (mlCount >= 2 || mORKS.RBTakeNoodleTask.Count == 0 || mORKS.PriorityJudgment);
  688. //mORKS.RobotTaskInterlock = isok && mORKS.AllowInvertedFace && (mlCount >= 2 || mORKS.RBTakeNoodleTask.Count == 0 || mORKS.PriorityJudgment);
  689. //2023-8-5注释修改,并联出餐请求,出餐优先。
  690. //mORKS.RobotTaskInterlock = mORKS.AllowInvertedFace && (mlCount >= 6 || mORKS.RBTakeNoodleTask.Count == 0 || mORKS.PriorityJudgment);
  691. mORKS.RobotTaskInterlock = mORKS.AllowInvertedFace && (OutMealRequstCount >= 1 || mORKS.RBTakeNoodleTask.Count == 0 || mORKS.PriorityJudgment);
  692. }
  693. /// <summary>语音提醒取餐</summary>
  694. /// <param name="meal"></param>
  695. private void WaitMeaLSpeak(string meal)
  696. {
  697. //VoiceAPI.m_SystemPlayWav(@"Vioce\电子提示音.wav");
  698. //Thread.Sleep(1000);
  699. //if (meal != null) mORKS.speech.Speak(meal);
  700. //VoiceAPI.m_SystemPlayWav(@"Vioce\取餐通知.wav");
  701. }
  702. #region PLC 控制函数
  703. private void WriteData(string address, object value)
  704. {
  705. EventBus.GetInstance.Publish(new WriteModel() { DeviceId = DeviceId, Address = address, Value = value });
  706. }
  707. /// <summary>设备初始化</summary>
  708. public async void DeviceInit()
  709. {
  710. WriteData("M0.0", true);
  711. await Task.Delay(1000);
  712. WriteData("M0.0", false);
  713. }
  714. /// <summary>取碗控制</summary>
  715. /// <param name="loc"></param>
  716. private void TakeBowlControl(ushort loc)
  717. {
  718. if (loc == 10)//一次性碗
  719. {
  720. WriteData("M9.1", true);
  721. }
  722. else if (loc == 11)//大碗
  723. {
  724. WriteData("M9.0", true);
  725. }
  726. }
  727. /// <summary>启动转台</summary>
  728. /// <param name="loc"></param>
  729. //private void TurntableStart(ushort loc)
  730. //{
  731. // if (loc >= 1 && loc <= 5)
  732. // {
  733. // mORKS.CurrentLoc = loc;
  734. // mORKS.TurntableInterlock = true;
  735. // mORKS.TurntableLocLists.Add(loc);
  736. // WriteData($"M13.{loc - 1}", true);
  737. // }
  738. //}
  739. /// <summary>设置倒面位置</summary>
  740. /// <param name="loc"></param>
  741. private void SetFallNoodleLoc(ushort loc)
  742. {
  743. if (loc >= 1 && loc <= 6)
  744. WriteData($"M14.{loc - 1}", true);
  745. }
  746. /// <summary>设置出餐位置</summary>
  747. /// <param name="loc"></param>
  748. private void SetTakeNoodleLoc(ushort loc)
  749. {
  750. if (loc >= 1 && loc <= 6)
  751. WriteData($"M15.{loc - 1}", true);
  752. }
  753. /// <summary>
  754. /// 制面机制面
  755. /// </summary>
  756. private async void SetNMachMake(int noodleSize, int number = 1)
  757. {
  758. if (number <= 0)
  759. {
  760. throw new ArgumentException("份数不应小于1。");
  761. }
  762. WriteData($"M20.{(5 + noodleSize)}", true);
  763. WriteData("VD800", number);
  764. Task.Delay(1000).Wait();
  765. WriteData("M20.2", new bool[] { true, true });
  766. await Task.Delay(1000);
  767. WriteData($"M20.{(5 + noodleSize)}", false);
  768. WriteData("M20.2", false);
  769. }
  770. /// <summary>
  771. /// 交换制面框
  772. /// </summary>
  773. private void SwapNoodleBox()
  774. {
  775. bool oper = false;
  776. if (mORKS.CylLeftPos)
  777. {
  778. oper = false;
  779. }
  780. else if (mORKS.CylRightPos)
  781. {
  782. oper = true;
  783. }
  784. WriteData("M13.2", oper);
  785. //todo:应该校验到位信号。
  786. //交换
  787. Swap(mORKS.NoodleBoxes, 0, 1);
  788. }
  789. public override void SimOrder()
  790. {
  791. EventBus.GetInstance.Subscribe<MorksSimorderModel>(0, delegate (IEvent @event, EventCallBackHandle callBackHandle)
  792. {
  793. if (@event != null && @event is MorksSimorderModel msm)
  794. {
  795. string guid = Guid.NewGuid().ToString();
  796. if (msm.NoodleLoc >= 1 && msm.NoodleLoc <= 3)
  797. {
  798. var locInfo = new OrderLocInfo() { Loc = (ushort)msm.NoodleLoc, SuborderId = guid };
  799. mORKS.MakeNoodleTask.Enqueue(locInfo);
  800. mORKS.RBTakeNoodleTask.Enqueue(locInfo);
  801. MessageLog.GetInstance.Show($"添加模拟订单【{guid}】:面条位置【{(ushort)msm.NoodleLoc}】");
  802. }
  803. if (msm.Bowloc >= 10 && msm.Bowloc <= 11)
  804. {
  805. mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = (ushort)msm.Bowloc, SuborderId = guid });
  806. MessageLog.GetInstance.Show($"添加模拟订单【{guid}】:碗位置【{(ushort)msm.Bowloc}】");
  807. }
  808. }
  809. });
  810. }
  811. #endregion PLC 控制函数
  812. static void Swap<T>(T[] list, int index1, int index2)
  813. {
  814. T temp = list[index1];
  815. list[index1] = list[index2];
  816. list[index2] = temp;
  817. }
  818. }
  819. }