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.
 
 

580 lines
24 KiB

  1. using System;
  2. using HBLConsole.Interface;
  3. using HBLConsole.Service;
  4. using HBLConsole.Communication;
  5. using BPA.Message;
  6. using HBLConsole.Model;
  7. using System.Linq;
  8. using System.Threading;
  9. using HBLConsole.Factory;
  10. using BPA.Message.Enum;
  11. using BPA.Message.IOT;
  12. using System.Collections.Generic;
  13. using System.Diagnostics;
  14. namespace HBLConsole.MORKD
  15. {
  16. public class Control_MORKD : IControl
  17. {
  18. GVL_MORKD mORKD = new GVL_MORKD();
  19. Alarm_MORKD alarm = new Alarm_MORKD();
  20. public void ConnectOk()
  21. {
  22. Main();
  23. ReadData();
  24. ResetProgram();
  25. }
  26. public void DataParse<T>(T order)
  27. {
  28. if (order is MorkOrderPush morkOrderPush)
  29. {
  30. foreach (var item in morkOrderPush.GoodBatchings)
  31. {
  32. var res = Json<BatchingInfoPar>.Data.orderMaterialDelivery.BatchingInfo.FirstOrDefault(p => p.BatchingId == item.BatchingId);
  33. if (res != null)
  34. {
  35. if (ushort.TryParse(res.BatchingLoc, out ushort loc))
  36. {
  37. if (loc >= 1 && loc <= 5)
  38. {
  39. mORKD.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = loc, SuborderId = morkOrderPush.SuborderId, BatchingId = res.BatchingId });
  40. }
  41. else if (loc >= 6 && loc <= 10)
  42. {
  43. mORKD.TakeSoupTask.Enqueue(new OrderLocInfo() { Loc = (ushort)(loc - 5), SuborderId = morkOrderPush.SuborderId });
  44. }
  45. else if (loc >= 11 && loc <= 12)
  46. {
  47. mORKD.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = (ushort)(loc - 10), SuborderId = morkOrderPush.SuborderId });
  48. }
  49. }
  50. }
  51. }
  52. }
  53. }
  54. public void Init()
  55. {
  56. ActionManage.GetInstance.Register(new Action(() =>
  57. {
  58. mORKD.InitControl();
  59. }), "InitCommand");
  60. }
  61. /// <summary>
  62. /// 复位程序
  63. /// </summary>
  64. private void ResetProgram()
  65. {
  66. ThreadManage.GetInstance.StartLong(new Action(() =>
  67. {
  68. if (RTrig.GetInstance("ResetProgram").Start(DeviceData.Initing))
  69. {
  70. ThreadManage.GetInstance.StopTask("MainTask", new Action(() =>
  71. {
  72. ThreadManage.GetInstance.StopTask("ReadPLCData", new Action(() =>
  73. {
  74. mORKD = null;
  75. mORKD = new GVL_MORKD();
  76. ActionManage.GetInstance.Send("ResetProgram");
  77. ReadData();
  78. Main();
  79. }));
  80. }));
  81. }
  82. Thread.Sleep(10);
  83. }), "ResetProgram");
  84. }
  85. public void Main()
  86. {
  87. ThreadManage.GetInstance.StartLong(new Action(() =>
  88. {
  89. mORKD.AllowRun = mORKD.InitComplete && !mORKD.TemperatureReached;
  90. TakeBowlTask();
  91. TakeNoodleTask();
  92. OutNoodleTask();
  93. SingleDetect();
  94. TurntableControl();
  95. OutSoupTask();
  96. TakeSoupTask();
  97. Thread.Sleep(10);
  98. }), "MainTask");
  99. }
  100. public void ReadData()
  101. {
  102. ThreadManage.GetInstance.StartLong(new Action(() =>
  103. {
  104. ModbusTcpHelper.GetInstance.Readbool(1120, 30, new Action<bool[]>((bools) =>
  105. {
  106. mORKD.InitComplete = bools[0];
  107. mORKD.TurntableInPlace = bools[1];
  108. mORKD.RBTakeNoodleComplete = bools[2];
  109. for (int i = 0; i < 2; i++)
  110. {
  111. mORKD.AxisIdle[i] = bools[3 + i];
  112. mORKD.AxisAllowInvertedNoodle[i] = bools[5 + i];
  113. mORKD.AxisAllowInvertedSoup[i] = bools[7 + i];
  114. mORKD.SoupHeatComplete[i] = bools[9 + i];
  115. mORKD.BreakMechanismIdle[i] = bools[25 + i];
  116. }
  117. for (int i = 0; i < 6; i++)
  118. {
  119. mORKD.CookNoodleBasketIdle[i] = bools[11 + i];
  120. mORKD.CookNoodleComplete[i] = bools[17 + i];
  121. }
  122. mORKD.TakeNoodleRobotIdle = bools[23];
  123. mORKD.TakeSoupRobotIdle = bools[24];
  124. mORKD.TakeSoupComplete = bools[27];
  125. mORKD.PutNoodleTakeMealComplete = bools[28];
  126. DeviceData.Initing = bools[29];
  127. }));
  128. ModbusTcpHelper.GetInstance.Readbool(1280, 11, new Action<bool[]>((bools) =>
  129. {
  130. mORKD.TurntableLowerLimit = bools[0];
  131. mORKD.TurntableUpLimit = bools[1];
  132. for (int i = 0; i < 5; i++)
  133. {
  134. mORKD.SoupMaterialShortage[i] = bools[2 + i];
  135. }
  136. for (int i = 0; i < 3; i++)
  137. {
  138. mORKD.OutMealDetect[i] = bools[7 + i];
  139. }
  140. mORKD.TemperatureReached = bools[10];
  141. }));
  142. var ResLoc = ModbusTcpHelper.GetInstance.Read(720, ReadType.HoldingRegisters);
  143. if (ResLoc != null)
  144. {
  145. if (ResLoc is ushort loc)
  146. {
  147. mORKD.TurntableFeedbackloc = loc;
  148. }
  149. }
  150. /** 读取Alarm 报警信息 2022.4.2
  151. */
  152. ModbusTcpHelper.GetInstance.Readbool(1570, 20, new Action<bool[]>((bools) =>
  153. {
  154. // 0 -- 1570
  155. //10 -- 1580
  156. int bit1570 = 1570;
  157. alarm.MachineLeftLowTemperature = bools[bit1570];
  158. alarm.MachineRightLowTemperature = bools[bit1570 + 1];
  159. alarm.Supply1_LossBowl = bools[bit1570 + 2];
  160. alarm.Supply2_LossBowl = bools[bit1570 + 3];
  161. alarm.Supply1_ErrorOutBowl = bools[bit1570 + 4];
  162. alarm.Supply2_ErrorOutBowl = bools[bit1570 + 5];
  163. alarm.PushBowlCylinderError = bools[bit1570 + 6];
  164. alarm.NoodleMacCommunicateError = bools[bit1570 + 7];
  165. //
  166. int bit1580 = 1580;
  167. alarm.DosingMacCommunicateError = bools[bit1580];
  168. alarm.RobotMacCommunicateError = bools[bit1580 + 1];
  169. alarm.RobotInitError = bools[bit1580 + 3];
  170. alarm.RobotUrgentStop = bools[bit1580 + 4];
  171. alarm.RobotNotInRemoteMode = bools[bit1580 + 5];
  172. alarm.RobotNotInReady = bools[bit1580 + 6];
  173. alarm.RobotSelfInException = bools[bit1580 + 7];
  174. }));
  175. Thread.Sleep(100);
  176. }), "ReadPLCData");
  177. }
  178. public void SimOrder<T>(T simOrder)
  179. {
  180. if (simOrder != null)
  181. {
  182. if (simOrder is List<ushort> locs)
  183. {
  184. string subId = Guid.NewGuid().ToString();
  185. foreach (var item in locs)
  186. {
  187. if (item >= 1 && item <= 5)
  188. {
  189. //临时变量batchId
  190. int tBatchId = item;
  191. mORKD.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = item, BatchingId = tBatchId, SuborderId = subId });
  192. MessageLog.GetInstance.Show($"添加订单:面条位置【{item}】");
  193. //先注释,暂时不从服务器获取 2022.3.29
  194. //BPA.Models.BatchingInfo res = Json<BatchingInfoPar>.Data.orderMaterialDelivery.BatchingInfo.FirstOrDefault(p => p.BatchingLoc == item.ToString());
  195. //if (res != null)
  196. //{
  197. // mORKD.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = item, BatchingId = res.BatchingId, SuborderId = subId });
  198. // MessageLog.GetInstance.Show($"添加订单:面条位置【{item}】");
  199. //}
  200. }
  201. if (item >= 6 && item <= 10)
  202. {
  203. mORKD.TakeSoupTask.Enqueue(new OrderLocInfo() { Loc = (ushort)(item - 5), SuborderId = subId });
  204. MessageLog.GetInstance.Show($"添加订单:浇头位置【{item}】");
  205. }
  206. if (item >= 11 && item <= 12)
  207. {
  208. mORKD.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = (ushort)(item - 10), SuborderId = subId });
  209. MessageLog.GetInstance.Show($"添加订单:碗位置【{item - 10}】");
  210. }
  211. }
  212. }
  213. }
  214. }
  215. /// <summary>
  216. /// IOT 广播消息命令
  217. /// </summary>
  218. public void IotBroadcast<T>(T broadcast)
  219. {
  220. if (broadcast != null && broadcast is IOTCommandModel iOTCommand)
  221. {
  222. switch (iOTCommand.CommandName)
  223. {
  224. case 0://控制类
  225. if (iOTCommand.CommandValue != null)
  226. {
  227. if (iOTCommand.CommandValue.ContainsKey("SimOrder"))
  228. {
  229. SimOrder(new SimOrderData { NoodleLoc = 1, BowlLoc = 10 });
  230. }
  231. }
  232. break;
  233. case 1://设置属性
  234. break;
  235. case 2://通知消息
  236. break;
  237. default:
  238. break;
  239. }
  240. }
  241. }
  242. /// <summary>
  243. /// 取碗控制
  244. /// </summary>
  245. private void TakeBowlTask()
  246. {
  247. mORKD.AxisIdleIndex = mORKD.AxisIdle.GetIndex(true);
  248. mORKD.AxisIdleLockIndex = mORKD.AxisIdleLock.GetIndex(false);
  249. if (mORKD.AxisIdleLockIndex == mORKD.AxisIdleIndex)
  250. {
  251. if (mORKD.AxisIdleIndex >= 0 && mORKD.AxisIdleIndex <= 1)
  252. {
  253. if (mORKD.AllowRun && mORKD.TakeBowlTask.Count > 0)
  254. {
  255. if (mORKD.TakeBowlTask.TryDequeue(out OrderLocInfo orderLocInfo))
  256. {
  257. mORKD.AxisAllowInvertedNoodleID[mORKD.AxisIdleIndex] = orderLocInfo.SuborderId;
  258. mORKD.DropBowlStart((ushort)(mORKD.AxisIdleIndex + 1), orderLocInfo.Loc);
  259. mORKD.AxisIdleLock[mORKD.AxisIdleLockIndex] = true;
  260. MessageLog.GetInstance.Show($"执行取碗控制,碗位置:[{orderLocInfo.Loc}],轴位置:[{mORKD.AxisIdleIndex + 1}]");
  261. MessageLog.GetInstance.Show($"{mORKD.AxisIdleIndex + 1}号轴订单ID:[{orderLocInfo.SuborderId}]");
  262. }
  263. }
  264. }
  265. }
  266. }
  267. /// <summary>
  268. /// 转台控制
  269. /// </summary>
  270. private void TurntableControl()
  271. {
  272. if (mORKD.TurntableInPlace && mORKD.InitComplete && !mORKD.AllowTakeNoodle && mORKD.RBTakeNoodleTask.Count > 0)
  273. {
  274. var result = Json<BatchingInfoPar>.Data.orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == mORKD.RBTakeNoodleTask.ElementAt(0).BatchingId).ToList();
  275. if (mORKD.TurntableLowerLimit)
  276. {
  277. if (mORKD.TurntableFeedbackloc == mORKD.RBTakeNoodleTask.ElementAt(0).Loc || (result?.Count > 0 && result?.Count == mORKD.TurntableLocLists.Count))
  278. {
  279. mORKD.TurntableLocLists.Clear();
  280. mORKD.AllowTakeNoodle = true;
  281. MessageLog.GetInstance.Show("转台位置OK,执行机器人取面");
  282. }
  283. else
  284. {
  285. if (!mORKD.TurntableInterlock)
  286. {
  287. mORKD.TurntableStart(mORKD.RBTakeNoodleTask.ElementAt(0).Loc);
  288. MessageLog.GetInstance.Show($"有物料检测,反馈位置不同的转台启动控制,转台位置:[{mORKD.RBTakeNoodleTask.ElementAt(0).Loc}]");
  289. }
  290. }
  291. }
  292. else
  293. {
  294. if (!mORKD.TurntableInterlock)
  295. {
  296. if (result != null)
  297. {
  298. foreach (var item in result)
  299. {
  300. if (ushort.TryParse(item.BatchingLoc, out ushort loc))
  301. {
  302. if (mORKD.TurntableFeedbackloc != loc && !mORKD.TurntableLocLists.Contains(loc))
  303. {
  304. mORKD.TurntableStart(loc);
  305. MessageLog.GetInstance.Show($"没有物料检测的启动转台控制,转台位置:[{loc}]");
  306. break;
  307. }
  308. else if (mORKD.TurntableFeedbackloc == loc && !mORKD.TurntableLocLists.Contains(loc)) mORKD.TurntableLocLists.Add(loc);
  309. }
  310. }
  311. }
  312. //result?.ForEach(item =>
  313. //{
  314. // if (ushort.TryParse(item.BatchingLoc, out ushort loc))
  315. // {
  316. // if (mORKD.TurntableFeedbackloc != loc && !mORKD.TurntableLocLists.Contains(loc))
  317. // {
  318. // mORKD.TurntableStart(loc);
  319. // MessageLog.GetInstance.Show($"没有物料检测的启动转台控制,转台位置:[{loc}]");
  320. // return;
  321. // }
  322. // else if (mORKD.TurntableFeedbackloc == loc) mORKD.TurntableLocLists.Add(loc);
  323. // }
  324. //});
  325. }
  326. }
  327. }
  328. //转台到位检测
  329. if (RTrig.GetInstance("TurntableInPlace").Start(mORKD.TurntableInPlace))
  330. {
  331. mORKD.TurntableInterlock = false;
  332. }
  333. }
  334. bool isNotTakeNoodle = false; //true-无法取面,false-可以取面
  335. /// <summary>
  336. /// 取面任务
  337. /// </summary>
  338. private void TakeNoodleTask()
  339. {
  340. //取面控制
  341. if (mORKD.AllowRun && mORKD.TakeNoodleRobotIdle && !mORKD.RobotTaskInterlock && mORKD.AllowTakeNoodle)
  342. {
  343. if (mORKD.TurntableInPlace && !mORKD.OutNoodleing && mORKD.RBTakeNoodleTask.Count > 0)
  344. {
  345. int loc = mORKD.CookNoodleBasketIdle.GetIndex(false);//查找煮面炉空闲位置
  346. int IdleLoc = mORKD.CookNodeState.GetIndex(false);//获取煮面炉空闲状态互锁位置
  347. if (loc >= 0 && loc <= 5)
  348. {
  349. if (isNotTakeNoodle)
  350. {
  351. return;
  352. }
  353. if (mORKD.RBTakeNoodleTask.TryDequeue(out OrderLocInfo orderLocInfo))
  354. {
  355. mORKD.RBTakeNoodleStart((ushort)(loc + 1), orderLocInfo.Loc);
  356. mORKD.CookNodeState[loc] = true;
  357. mORKD.CookNodelId[loc] = orderLocInfo.SuborderId;
  358. SimpleFactory.GetInstance.OrderChanged(orderLocInfo.SuborderId, ORDER_STATUS.COOKING);
  359. //MessageLog.GetInstance.Show($"订单【{orderLocInfo.SuborderId}】,煮面栏:[{loc + 1}]");
  360. mORKD.TakeNoodleInterlock = true;
  361. MessageLog.GetInstance.Show($"{loc + 1}号煮面篮订单ID:[{orderLocInfo.SuborderId}]");
  362. Trace.WriteLine($"%%%开始下面。。。" + $"{loc + 1}号煮面篮订单ID:[{orderLocInfo.SuborderId}]");
  363. isNotTakeNoodle = true;
  364. }
  365. }
  366. }
  367. }
  368. //机器人取面完成信号检测
  369. if (RTrig.GetInstance("TakeNoodleComplete").Start(mORKD.RBTakeNoodleComplete))
  370. {
  371. mORKD.TakeNoodleInterlock = false;
  372. mORKD.AllowTakeNoodle = false;
  373. MessageLog.GetInstance.Show("转台取面完成");
  374. mORKD.TakeNoodleCompleteReset();
  375. isNotTakeNoodle = false;
  376. }
  377. }
  378. /// <summary>
  379. /// 出面控制
  380. /// </summary>
  381. private void OutNoodleTask()
  382. {
  383. for (ushort i = 0; i < 6; i++)
  384. {
  385. if (RTrig.GetInstance($"CookNoodleCompleteTask{i}").Start(mORKD.CookNoodleComplete[i] && mORKD.CookNodeState[i]))
  386. {
  387. mORKD.CookNoodleCompleteTask.Enqueue(i);
  388. MessageLog.GetInstance.Show($"{i + 1}号煮面口请求出面");
  389. }
  390. }
  391. if (mORKD.RobotTaskInterlock && !mORKD.TakeNoodleInterlock && mORKD.TakeNoodleRobotIdle)
  392. {
  393. if (mORKD.CookNoodleCompleteTask.Count > 0)
  394. {
  395. RevertOutNoodleQueue(); //交换出面台位顺序 2022.3.30
  396. string id = mORKD.CookNodelId[mORKD.CookNoodleCompleteTask.ElementAt(0)];
  397. int index = mORKD.AxisAllowInvertedNoodleID.GetIndex(id);
  398. if (index >= 0 && index <= 1)
  399. {
  400. if (mORKD.AxisAllowInvertedNoodle[index])
  401. {
  402. if (mORKD.CookNoodleCompleteTask.TryDequeue(out ushort loc))
  403. {
  404. mORKD.OutNoodleing = true;
  405. mORKD.RBOutNoodleStart((ushort)(loc + 1), (ushort)(index + 1));
  406. mORKD.CookNodeState[loc] = false;
  407. mORKD.AxisIdleLock[index] = false;
  408. mORKD.AxisAllowInvertedSoupID[index] = mORKD.AxisAllowInvertedNoodleID[index];
  409. mORKD.AxisAllowInvertedNoodleID[index] = string.Empty;
  410. MessageLog.GetInstance.Show($"从{loc + 1}号位置取面");
  411. MessageLog.GetInstance.Show($"倒入{index + 1}号碗位置");
  412. MessageLog.GetInstance.Show($"{index + 1}号轴允许倒浇头ID:[{ mORKD.AxisAllowInvertedSoupID[index]}]");
  413. //Trace.WriteLine($"###出面控制。。。");
  414. }
  415. }
  416. }
  417. }
  418. }
  419. int mlCount = mORKD.CookNoodleBasketIdle.Where(p => p == true).ToList().Count;
  420. mORKD.RobotTaskInterlock = mORKD.CookNoodleCompleteTask.Count > 0 && (mlCount >= 2 || mORKD.RBTakeNoodleTask.Count == 0);
  421. }
  422. public int tCount = 0;
  423. /// <summary>
  424. /// 交换出面台位优先级
  425. /// </summary>
  426. void RevertOutNoodleQueue()
  427. {
  428. string id = mORKD.CookNodelId[mORKD.CookNoodleCompleteTask.ElementAt(0)];
  429. int index = mORKD.AxisAllowInvertedNoodleID.GetIndex(id);
  430. if (index == -1)
  431. {
  432. tCount++;
  433. if (tCount == 100)
  434. {
  435. //交换取面位置
  436. mORKD.CookNoodleCompleteTask.TryDequeue(out ushort result2);
  437. mORKD.CookNoodleCompleteTask.Enqueue(result2);
  438. tCount = 0;
  439. }
  440. }
  441. else
  442. {
  443. tCount = 0;
  444. }
  445. }
  446. /// <summary>
  447. /// 取浇头控制
  448. /// </summary>
  449. private void TakeSoupTask()
  450. {
  451. int index = mORKD.BreakMechanismIdle.GetIndex(true);
  452. if (index >= 0 && index <= 1)
  453. {
  454. if (mORKD.TakeSoupTask.Count > 0 && !mORKD.AllowTakeSoup && mORKD.TakeSoupRobotIdle && mORKD.AllowRun)
  455. {
  456. if (mORKD.TakeSoupTask.TryDequeue(out OrderLocInfo orderLocInfo))
  457. {
  458. mORKD.SoupHeatLocID[index] = orderLocInfo.SuborderId;
  459. mORKD.RBTakeSoupStart(orderLocInfo.Loc, (ushort)(index + 1));
  460. SimpleFactory.GetInstance.OrderChanged(orderLocInfo.SuborderId, ORDER_STATUS.COOKING);
  461. MessageLog.GetInstance.Show($"{index + 1}号浇头加热位ID:[{ mORKD.SoupHeatLocID[index]}]");
  462. }
  463. }
  464. }
  465. if (RTrig.GetInstance("TakeSoupComplete").Start(mORKD.TakeSoupComplete))
  466. {
  467. mORKD.AllowTakeSoup = false;
  468. MessageLog.GetInstance.Show("取浇头完成");
  469. mORKD.TakeSoupCompleteReset();
  470. }
  471. }
  472. /// <summary>
  473. /// 浇头加热完成出浇头控制
  474. /// </summary>
  475. private void OutSoupTask()
  476. {
  477. if (!mORKD.AllowTakeSoup && !mORKD.AllowPutSoup && mORKD.TakeSoupRobotIdle)
  478. {
  479. mORKD.PutNoodleLoc = mORKD.OutMealDetect.GetIndex(false);
  480. if (mORKD.PutNoodleLoc >= 0 && mORKD.PutNoodleLoc <= 2)
  481. {
  482. for (int i = 0; i < 2; i++)
  483. {
  484. if (mORKD.SoupHeatComplete[i] && mORKD.SoupHeatLocID[i].Length > 0)
  485. {
  486. for (int m = 0; m < 2; m++)
  487. {
  488. if (mORKD.AxisAllowInvertedSoup[m] && mORKD.AxisAllowInvertedSoupID[m].Length > 0)
  489. {
  490. if (mORKD.SoupHeatLocID[i] == mORKD.AxisAllowInvertedSoupID[m])
  491. {
  492. mORKD.HeatCompleteTakeSoupStart((ushort)(i + 1), (ushort)(m + 1), (ushort)(mORKD.PutNoodleLoc + 1));
  493. mORKD.OutMealId[mORKD.PutNoodleLoc] = mORKD.AxisAllowInvertedSoupID[m];
  494. mORKD.AxisAllowInvertedSoupID[m] = string.Empty;
  495. mORKD.SoupHeatLocID[i] = string.Empty;
  496. MessageLog.GetInstance.Show($"取浇头机器人往{m + 1}号轴到浇头");
  497. MessageLog.GetInstance.Show($"{mORKD.PutNoodleLoc + 1}号出餐口订单ID:[{ mORKD.OutMealId[mORKD.PutNoodleLoc]}]");
  498. }
  499. }
  500. }
  501. }
  502. }
  503. }
  504. }
  505. if (RTrig.GetInstance("PutNoodleTakeMealComplete").Start(mORKD.PutNoodleTakeMealComplete))
  506. {
  507. mORKD.AllowPutSoup = false;
  508. SimpleFactory.GetInstance.OrderChanged(mORKD.OutMealId[mORKD.PutNoodleLoc], ORDER_STATUS.COMPLETED_COOK);
  509. mORKD.PutNoodleTakeMealCompleteReset();
  510. }
  511. }
  512. /// <summary>
  513. /// 信号检测
  514. /// </summary>
  515. private void SingleDetect()
  516. {
  517. //取餐完成
  518. //var RemoveItem = Json<MorkOrderPushPar>.Data.morkOrderPushes.FirstOrDefault(p => p.OrderPush.SuborderId == "取餐口订单ID");
  519. //if (RemoveItem != null)
  520. // Json<MorkOrderPushPar>.Data.morkOrderPushes.Remove(RemoveItem);
  521. }
  522. }
  523. }