终端一体化运控平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

928 lines
38 KiB

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