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.
 
 

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