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.
 
 

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