终端一体化运控平台
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

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