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.
 
 

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