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.
 
 

633 lines
23 KiB

  1. //#define test
  2. using BPA.Message;
  3. using HBLConsole.Communication;
  4. using HBLConsole.Factory;
  5. using HBLConsole.Interface;
  6. using HBLConsole.Model;
  7. using HBLConsole.Service;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using BPA.Message.Enum;
  15. using HBLConsole.GVL;
  16. using BPA.Models;
  17. using BPA.Message.IOT;
  18. namespace HBLConsole.MORKS
  19. {
  20. public class Control_MORKS : IControl
  21. {
  22. GVL_MORKS mORKS = new GVL_MORKS();
  23. public void Init()
  24. {
  25. ActionOperate.GetInstance.Register(new Action(() => { WriteRecipeBoms(); }), "recipeBom");
  26. ActionOperate.GetInstance.Register(new Action(() => { DeviceInit(); }), "InitCommand");
  27. }
  28. public void ConnectOk()
  29. {
  30. //WriteRecipeBoms();
  31. ReadData();
  32. Main();
  33. //ResetProgram();
  34. MessageLog.GetInstance.Show("MORKS 设备初始化完成");
  35. }
  36. /// <summary>
  37. /// 复位程序
  38. /// </summary>
  39. private void ResetProgram()
  40. {
  41. ThreadOperate.GetInstance.StartLong(new Action(() =>
  42. {
  43. if (RTrig.GetInstance("ResetProgram").Start(mORKS.DeviceIniting))
  44. {
  45. ThreadOperate.GetInstance.StopTask("MainTask", new Action(() =>
  46. {
  47. mORKS.AllowRun = false;
  48. TakeBowlId = string.Empty;
  49. IngredientsCompleteId = string.Empty;
  50. CookNodelId = new string[6] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, };
  51. mORKS.RobotTaskInterlock = false;
  52. OutMealId = string.Empty;
  53. mORKS.TakeBowlInterlock = false;
  54. mORKS.TakeNoodleInterlock = false;
  55. mORKS.OutNoodleing = false;
  56. Main();
  57. }));
  58. }
  59. Thread.Sleep(10);
  60. }), "ResetProgram");
  61. }
  62. /// <summary>
  63. /// 数据读取
  64. /// </summary>
  65. public void ReadData()
  66. {
  67. ThreadOperate.GetInstance.StartLong(new Action(() =>
  68. {
  69. ModbusTcpHelper.GetInstance.Readbool(323, 3, new Action<bool[]>((bools) =>
  70. {
  71. mORKS.RobotTakeNoodle = bools[0];
  72. mORKS.RobotOutMeal = bools[1];
  73. mORKS.MoveTurntable = bools[2];
  74. }));
  75. ModbusTcpHelper.GetInstance.Readbool(1120, 16, new Action<bool[]>((bools) =>
  76. {
  77. mORKS.InitComplete = bools[0];
  78. mORKS.TakeBowlIdle = bools[1];
  79. mORKS.TemperatureReached = bools[2];
  80. mORKS.AllowFallNoodle = bools[3];
  81. mORKS.RbTakeNoodleComplete = bools[4];
  82. mORKS.RbFallNoodleComplete = bools[5];
  83. mORKS.RbOutMealComplete = bools[6];
  84. mORKS.RobotIdle = bools[7];
  85. mORKS.TakeMealDetect = bools[8];
  86. mORKS.MissingBowl = bools[9];
  87. mORKS.DeviceIniting = bools[10];
  88. mORKS.TurntableLowerLimit = bools[11];
  89. mORKS.MissingBowlSignal2 = bools[12];
  90. mORKS.TurntableUpLimit = bools[13];
  91. mORKS.TurntableMoveInPlace = bools[15];
  92. }));
  93. ModbusTcpHelper.GetInstance.Readbool(1136, 6, new Action<bool[]>((bools) =>
  94. {
  95. for (int i = 0; i < 6; i++)
  96. {
  97. mORKS.NoodleCookerStatus[i] = bools[i];
  98. }
  99. }));
  100. ModbusTcpHelper.GetInstance.Readbool(1144, 6, new Action<bool[]>((bools) =>
  101. {
  102. for (int i = 0; i < 6; i++)
  103. {
  104. mORKS.CookNoodlesComplete[i] = bools[i];
  105. }
  106. }));
  107. var ResLoc = ModbusTcpHelper.GetInstance.Read(286, ReadType.HoldingRegisters);
  108. if (ResLoc != null)
  109. {
  110. if (ResLoc is ushort loc)
  111. {
  112. mORKS.TurntableFeedbackloc = loc;
  113. }
  114. }
  115. Thread.Sleep(500);
  116. }), "ReadPLCData");
  117. }
  118. public void SimOrder<T>(T simOrder)
  119. {
  120. if (simOrder != null)
  121. {
  122. if (simOrder is List<ushort> locs)
  123. {
  124. string subId = Guid.NewGuid().ToString();
  125. foreach (var item in locs)
  126. {
  127. if (item >= 1 && item <= 5)
  128. {
  129. mORKS.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = item, SuborderId = subId });
  130. MessageLog.GetInstance.Show($"添加订单:面条位置【{item}】");
  131. }
  132. if (item >= 10 && item <= 11)
  133. {
  134. mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = item, SuborderId = subId });
  135. MessageLog.GetInstance.Show($"添加订单:碗位置【{item}】");
  136. }
  137. }
  138. }
  139. }
  140. }
  141. /// <summary>
  142. /// IOT 广播消息命令
  143. /// </summary>
  144. public void IotBroadcast<T>(T broadcast)
  145. {
  146. if (broadcast != null && broadcast is IOTCommandModel iOTCommand)
  147. {
  148. MessageLog.GetInstance.Show($"IOT 广播消息命令 {iOTCommand.deviceName} 设备命令 {iOTCommand.CommandName} 控制变量{iOTCommand.CommandValue.Keys.First()}{iOTCommand.CommandValue[iOTCommand.CommandValue.Keys.First()]}");
  149. switch (iOTCommand.CommandName)
  150. {
  151. case 0://控制类
  152. if (iOTCommand.CommandValue != null)
  153. {
  154. if (iOTCommand.CommandValue.ContainsKey("order"))
  155. {
  156. List<ushort> vs = new List<ushort>();
  157. vs.Add((ushort)(new Random().Next(1, 5)));
  158. vs.Add(ushort.Parse(iOTCommand.CommandValue["order"]));
  159. SimOrder(vs);
  160. }
  161. else if (iOTCommand.CommandValue.ContainsKey("init"))
  162. {
  163. DeviceInit();
  164. }
  165. else if (iOTCommand.CommandValue.ContainsKey("stop"))
  166. {
  167. }
  168. else if (iOTCommand.CommandValue.ContainsKey("start"))
  169. {
  170. }
  171. }
  172. break;
  173. case 1://设置属性
  174. break;
  175. case 2://通知消息
  176. break;
  177. default:
  178. break;
  179. }
  180. }
  181. }
  182. /// <summary>
  183. /// 数据解析
  184. /// </summary>
  185. public void DataParse<T>(T order)
  186. {
  187. if (order is MorkOrderPush morkOrderPush)
  188. {
  189. BatchingInfo batching_M = null;//面条
  190. BatchingInfo batching_W = null;//碗
  191. foreach (var item in morkOrderPush.GoodBatchings)
  192. {
  193. var res = Json<BatchingInfoPar>.Data.orderMaterialDelivery.BatchingInfo.FirstOrDefault(p => p.BatchingId == item.BatchingId);
  194. if (res != null)
  195. {
  196. if (ushort.TryParse(res.BatchingLoc, out ushort loc))
  197. {
  198. if (loc >= 1 && loc <= 5) { batching_M = res; }
  199. else if (loc >= 10 && loc <= 11) { batching_W = res; }
  200. }
  201. }
  202. }
  203. if (batching_M != null && batching_W != null)
  204. {
  205. batching_W.BatchingLoc = "10";
  206. mORKS.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = ushort.Parse(batching_M.BatchingLoc), SuborderId = morkOrderPush.SuborderId, BatchingId = batching_M.BatchingId });
  207. int index = Array.FindIndex(Json<BatchingInfoPar>.Data.recipeBoms.RecipeIds.ToArray(), p => p.RecipeId == morkOrderPush.RecipeId);
  208. index++;
  209. mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = ushort.Parse(batching_W.BatchingLoc), SuborderId = morkOrderPush.SuborderId, RecipeNumber = (index >= 1 && index <= 10) ? (ushort)index : (ushort)0 });
  210. }
  211. }
  212. }
  213. #region 临时变量
  214. /// <summary>
  215. /// 取碗订单ID
  216. /// </summary>
  217. string TakeBowlId = string.Empty;
  218. /// <summary>
  219. /// 配料完成订单ID
  220. /// </summary>
  221. string IngredientsCompleteId = string.Empty;
  222. /// <summary>
  223. /// 煮面口对应的订单ID
  224. /// </summary>
  225. string[] CookNodelId = new string[6] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, };
  226. /// <summary>
  227. /// 出餐订单ID
  228. /// </summary>
  229. string OutMealId = string.Empty;
  230. /// <summary>
  231. /// 转台位置轮询
  232. /// </summary>
  233. List<ushort> TurntableLoc = new List<ushort>();
  234. #endregion
  235. public void Main()
  236. {
  237. ThreadOperate.GetInstance.StartLong(new Action(() =>
  238. {
  239. mORKS.AllowRun = mORKS.InitComplete && !mORKS.TemperatureReached;
  240. //mORKS.AllowRun = mORKS.InitComplete && mORKS.TemperatureReached;
  241. //GeneralConfig.Healthy = true;
  242. GeneralConfig.Healthy = mORKS.AllowRun;
  243. TakeBowlTask();
  244. TakeNoodleTask();
  245. OutNoodleTask();
  246. SingleDetect();
  247. TurntableControl();
  248. Thread.Sleep(100);
  249. }), "MainTask");
  250. }
  251. /// <summary>
  252. /// 取碗控制
  253. /// </summary>
  254. private void TakeBowlTask()
  255. {
  256. if (mORKS.AllowRun && mORKS.TakeBowlTask.Count > 0 && !mORKS.TakeBowlIdle && !mORKS.TakeBowlInterlock)
  257. {
  258. if (mORKS.TakeBowlTask.TryDequeue(out OrderLocInfo orderLocInfo))
  259. {
  260. TakeBowlId = orderLocInfo.SuborderId;
  261. TakeBowlControl(orderLocInfo.Loc);
  262. SetRecipeNumber(orderLocInfo.RecipeNumber);
  263. SimpleFactory.GetInstance.OrderChanged(TakeBowlId, ORDER_STATUS.COOKING);
  264. MessageLog.GetInstance.Show($"订单【{TakeBowlId}】执行取碗控制,位置:[{orderLocInfo.Loc}]");
  265. }
  266. mORKS.TakeBowlInterlock = true;
  267. }
  268. }
  269. /// <summary>
  270. /// 转台控制
  271. /// </summary>
  272. private void TurntableControl()
  273. {
  274. if (mORKS.TurntableMoveInPlace && mORKS.InitComplete && !mORKS.AllowTakeNoodle && mORKS.RBTakeNoodleTask.Count > 0)
  275. {
  276. if (mORKS.TurntableLowerLimit)
  277. {
  278. SetTurntableLoc(mORKS.RBTakeNoodleTask.ElementAt(0).Loc);
  279. MoveTurntable();
  280. mORKS.AllowTakeNoodle = true;
  281. TurntableLoc.Clear();
  282. MessageLog.GetInstance.Show("转台位置OK");
  283. mORKS.IsNoodles = true;
  284. }
  285. else
  286. {
  287. if (!mORKS.TurntableInterlock)
  288. {
  289. var result = Json<BatchingInfoPar>.Data.orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == mORKS.RBTakeNoodleTask.ElementAt(0).BatchingId).ToList();
  290. if (result != null)
  291. {
  292. foreach (var item in result)
  293. {
  294. if (ushort.TryParse(item.BatchingLoc, out ushort loc))
  295. {
  296. if (mORKS.TurntableFeedbackloc != loc)
  297. {
  298. if (!TurntableLoc.Contains(loc))
  299. {
  300. SetTurntableLoc(loc);
  301. MoveTurntable();
  302. mORKS.TurntableInterlock = true;
  303. TurntableLoc.Add(loc);
  304. return;
  305. }
  306. }
  307. }
  308. }
  309. mORKS.IsNoodles = false;
  310. MessageLog.GetInstance.Show("转台位置缺少物料");
  311. }
  312. }
  313. }
  314. }
  315. }
  316. /// <summary>
  317. /// 取面任务
  318. /// </summary>
  319. private void TakeNoodleTask()
  320. {
  321. //取面控制
  322. if (mORKS.AllowRun && mORKS.RobotIdle && !mORKS.RobotTaskInterlock && mORKS.AllowTakeNoodle && mORKS.TurntableMoveInPlace && !mORKS.TakeNoodleInterlock && !mORKS.OutNoodleing && mORKS.RBTakeNoodleTask.Count > 0)
  323. {
  324. int loc = Array.FindIndex(mORKS.NoodleCookerStatus, p => p == false);//查找煮面炉空闲位置
  325. if (loc >= 0 && loc <= 5)
  326. {
  327. if (mORKS.RBTakeNoodleTask.TryDequeue(out OrderLocInfo orderLocInfo))
  328. {
  329. //设置转台位置
  330. SetTurntableLoc(orderLocInfo.Loc);
  331. //设置倒面位置
  332. CookNodelId[loc] = orderLocInfo.SuborderId;
  333. SetFallNoodleLoc((ushort)(loc + 1));
  334. //机器人开始取面
  335. RobotTakeNoodle();
  336. SimpleFactory.GetInstance.OrderChanged(orderLocInfo.SuborderId, ORDER_STATUS.COOKING);
  337. MessageLog.GetInstance.Show($"订单【{orderLocInfo.SuborderId}】,转台:[{orderLocInfo}],煮面栏:[{loc + 1}]");
  338. mORKS.TakeNoodleInterlock = true;
  339. }
  340. }
  341. }
  342. }
  343. /// <summary>
  344. /// 出餐控制
  345. /// </summary>
  346. private void OutNoodleTask()
  347. {
  348. if (mORKS.AllowFallNoodle && mORKS.RobotTaskInterlock && !mORKS.TakeNoodleInterlock && mORKS.RobotIdle && !mORKS.TakeMealDetect)
  349. {
  350. int loc = Array.FindIndex(CookNodelId, p => p == IngredientsCompleteId && p.Length > 0);
  351. if (loc >= 0 && loc <= 5)
  352. {
  353. if (mORKS.CookNoodlesComplete[loc])
  354. {
  355. SetTakeNoodleLoc((ushort)(loc + 1));
  356. RobotOutMeal();
  357. CookNoodleStatusReset((ushort)(loc + 1));
  358. ResetAllowFallNoodle();
  359. OutMealId = IngredientsCompleteId;
  360. IngredientsCompleteId = string.Empty;
  361. CookNodelId[loc] = string.Empty;
  362. MessageLog.GetInstance.Show($"{loc + 1}号位置出餐控制");
  363. mORKS.OutNoodleing = true;
  364. }
  365. }
  366. }
  367. }
  368. /// <summary>
  369. /// 信号检测
  370. /// </summary>
  371. private void SingleDetect()
  372. {
  373. //允许倒面信号检测
  374. if (RTrig.GetInstance("AllowFallNoodle").Start(mORKS.AllowFallNoodle))
  375. {
  376. IngredientsCompleteId = TakeBowlId;
  377. TakeBowlId = string.Empty;
  378. MessageLog.GetInstance.Show($"允许到面,{IngredientsCompleteId}");
  379. mORKS.TakeBowlInterlock = false;
  380. }
  381. //出餐完成信号检测
  382. if (RTrig.GetInstance("CompleteChange").Start(mORKS.RbOutMealComplete))
  383. {
  384. SimpleFactory.GetInstance.OrderChanged(OutMealId, ORDER_STATUS.COMPLETED_COOK);
  385. MessageLog.GetInstance.Show($"订单【{OutMealId}】制作完成");
  386. mORKS.OutNoodleing = false;
  387. }
  388. //取餐完成逻辑处理
  389. if (DelayRTrig.GetInstance("CompleteChange1").Start(mORKS.RbOutMealComplete && !mORKS.TakeMealDetect, 2))
  390. {
  391. SimpleFactory.GetInstance.OrderChanged(OutMealId, ORDER_STATUS.COMPLETED_TAKE);
  392. MessageLog.GetInstance.Show($"订单【{OutMealId}】取餐完成");
  393. var RemoveItem = Json<MorkOrderPushPar>.Data.morkOrderPushes.FirstOrDefault(p => p.OrderPush.SuborderId == OutMealId);
  394. if (RemoveItem != null)
  395. {
  396. Json<MorkOrderPushPar>.Data.morkOrderPushes.Remove(RemoveItem);
  397. }
  398. ResetCookComplete();
  399. OutMealId = string.Empty;
  400. }
  401. //机器人取面完成信号检测
  402. if (RTrig.GetInstance("TakeNoodleComplete").Start(mORKS.RbTakeNoodleComplete))
  403. {
  404. mORKS.TakeNoodleInterlock = false;
  405. mORKS.AllowTakeNoodle = false;
  406. MessageLog.GetInstance.Show("取面完成");
  407. TakeNoodleCompleteReset();
  408. }
  409. //转台到位检测
  410. if (RTrig.GetInstance("TurntableInPlace").Start(mORKS.TurntableMoveInPlace))
  411. {
  412. mORKS.TurntableInterlock = false;
  413. }
  414. int OutMealRequstCount = mORKS.CookNoodlesComplete.Where(p => p == true).ToList().Count;
  415. int mlCount = mORKS.NoodleCookerStatus.Where(p => p == true).ToList().Count;
  416. mORKS.RobotTaskInterlock = OutMealRequstCount > 0 && mORKS.AllowFallNoodle && (mlCount >= 2 || mORKS.RBTakeNoodleTask.Count == 0);
  417. }
  418. #region PLC 控制函数
  419. /// <summary>
  420. /// 写入配方数据到 PLC
  421. /// </summary>
  422. private void WriteRecipeBoms()
  423. {
  424. List<ushort> recipeBoms = new List<ushort>();
  425. foreach (var item in Json<BatchingInfoPar>.Data.recipeBoms.RecipeIds)
  426. {
  427. foreach (var rec in item.Recipes)
  428. {
  429. recipeBoms.Add((ushort)rec);
  430. }
  431. }
  432. if (recipeBoms.Count > 0)
  433. {
  434. if (ModbusTcpHelper.GetInstance.Write(1100, WriteType.HoldingRegisters, recipeBoms.ToArray()))
  435. {
  436. MessageLog.GetInstance.Show("成功写入配方数据");
  437. }
  438. }
  439. }
  440. /// <summary>
  441. /// 转台移动
  442. /// </summary>
  443. private void MoveTurntable()
  444. {
  445. ModbusTcpHelper.GetInstance.Write(325, WriteType.Coils, true);
  446. }
  447. /// <summary>
  448. /// 取面完成复位
  449. /// </summary>
  450. private void TakeNoodleCompleteReset()
  451. {
  452. ModbusTcpHelper.GetInstance.Write(1124, WriteType.Coils, false);
  453. }
  454. /// <summary>
  455. /// 指定煮面口状态复位
  456. /// </summary>
  457. /// <param name="num"></param>
  458. private void CookNoodleStatusReset(int num)
  459. {
  460. if (num >= 1 && num <= 6)
  461. {
  462. ushort addRess = (ushort)(1136 + num - 1);
  463. ModbusTcpHelper.GetInstance.Write(addRess, WriteType.Coils, false);
  464. MessageLog.GetInstance.Show($"{num}号煮面口占用复位");
  465. }
  466. }
  467. /// <summary>
  468. /// 写配方编号
  469. /// </summary>
  470. /// <param name="num"></param>
  471. private void SetRecipeNumber(ushort num)
  472. {
  473. ModbusTcpHelper.GetInstance.Write(100, WriteType.HoldingRegisters, num);
  474. }
  475. /// <summary>
  476. /// 设置转台位置
  477. /// </summary>
  478. /// <param name="loc"></param>
  479. private void SetTurntableLoc(ushort loc)
  480. {
  481. ModbusTcpHelper.GetInstance.Write(101, WriteType.HoldingRegisters, loc);
  482. }
  483. /// <summary>
  484. /// 设置倒面位置
  485. /// </summary>
  486. /// <param name="loc"></param>
  487. private void SetFallNoodleLoc(ushort loc)
  488. {
  489. ModbusTcpHelper.GetInstance.Write(102, WriteType.HoldingRegisters, loc);
  490. }
  491. /// <summary>
  492. /// 设置取面位置
  493. /// </summary>
  494. /// <param name="loc"></param>
  495. private void SetTakeNoodleLoc(ushort loc)
  496. {
  497. ModbusTcpHelper.GetInstance.Write(103, WriteType.HoldingRegisters, loc);
  498. }
  499. /// <summary>
  500. /// 取碗控制
  501. /// </summary>
  502. /// <param name="loc"></param>
  503. private void TakeBowlControl(ushort loc)
  504. {
  505. if (loc == 10)
  506. {
  507. ModbusTcpHelper.GetInstance.Write(321, WriteType.Coils, true);
  508. }
  509. else if (loc == 11)
  510. {
  511. ModbusTcpHelper.GetInstance.Write(322, WriteType.Coils, true);
  512. }
  513. }
  514. /// <summary>
  515. /// 机器人取面
  516. /// </summary>
  517. private void RobotTakeNoodle()
  518. {
  519. ModbusTcpHelper.GetInstance.Write(323, WriteType.Coils, true);
  520. }
  521. /// <summary>
  522. /// 机器人取餐
  523. /// </summary>
  524. private void RobotOutMeal()
  525. {
  526. ModbusTcpHelper.GetInstance.Write(324, WriteType.Coils, true);
  527. var result = ModbusTcpHelper.GetInstance.Read(324, ReadType.Coils);
  528. if (result is bool res)
  529. while (!res)
  530. {
  531. ModbusTcpHelper.GetInstance.Write(324, WriteType.Coils, true);
  532. }
  533. }
  534. /// <summary>
  535. /// 制作完成信号复位
  536. /// </summary>
  537. private void ResetCookComplete()
  538. {
  539. ModbusTcpHelper.GetInstance.Write(1126, WriteType.Coils, false);
  540. }
  541. /// <summary>
  542. /// 复位允许取面信号
  543. /// </summary>
  544. private void ResetAllowFallNoodle()
  545. {
  546. ModbusTcpHelper.GetInstance.Write(1123, WriteType.Coils, false);
  547. }
  548. /// <summary>
  549. /// 设备初始化
  550. /// </summary>
  551. public async void DeviceInit()
  552. {
  553. ModbusTcpHelper.GetInstance.Write(320, WriteType.Coils, true);
  554. await Task.Delay(1000);
  555. ModbusTcpHelper.GetInstance.Write(320, WriteType.Coils, false);
  556. }
  557. #endregion
  558. }
  559. }