BoatModule.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using Aitex.Core.Common;
  5. using Aitex.Core.RT.DataCenter;
  6. using Aitex.Core.RT.Device;
  7. using Aitex.Core.RT.Device.Unit;
  8. using Aitex.Core.RT.Event;
  9. using Aitex.Core.RT.Fsm;
  10. using Aitex.Core.RT.OperationCenter;
  11. using Aitex.Core.RT.Routine;
  12. using Aitex.Core.RT.SCCore;
  13. using Aitex.Core.Utilities;
  14. using Aitex.Sorter.Common;
  15. using MECF.Framework.Common.Alarms;
  16. using MECF.Framework.Common.Equipment;
  17. using MECF.Framework.Common.Schedulers;
  18. using MECF.Framework.Common.SubstrateTrackings;
  19. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts;
  20. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
  21. using FurnaceRT.Equipments.Systems;
  22. using static Aitex.Core.RT.Device.Unit.IoAutoShutter;
  23. using Aitex.Core.Util;
  24. using MECF.Framework.Common.Device.Bases;
  25. using Aitex.Core.RT.Log;
  26. using FurnaceRT.Devices;
  27. namespace FurnaceRT.Equipments.Boats
  28. {
  29. public partial class BoatModule : ModuleFsmDevice, IModuleDevice
  30. {
  31. public enum STATE
  32. {
  33. Init,
  34. Idle,
  35. Error,
  36. Homing,
  37. InTransfer,
  38. ZAxisMoving,
  39. ZAxisManualMoving,
  40. RAxisMoving,
  41. RAxisMovingTest,
  42. ZAxisMovingTest,
  43. ShutterCycleTest,
  44. MovingTest,
  45. BoatMoving,
  46. }
  47. public enum MSG
  48. {
  49. Home,
  50. Reset,
  51. Init,
  52. Error,
  53. Abort,
  54. InTransfer,
  55. TransferComplete,
  56. ZAxisManualMove,
  57. ZAxisMove,
  58. RAxisMove,
  59. RAxisMoveTest,
  60. ZAxisMoveTest,
  61. ShutterCycleTest,
  62. MoveTest,
  63. ZAxisManualMoveRetry,
  64. ZAxisMoveRetry,
  65. RAxisMoveRetry,
  66. BoatMove,
  67. BoatMoveRetry,
  68. }
  69. public bool IsReady
  70. {
  71. get { return FsmState == (int)STATE.Idle; }
  72. }
  73. public bool IsError
  74. {
  75. get
  76. {
  77. return FsmState == (int)STATE.Error;
  78. }
  79. }
  80. public bool IsInit
  81. {
  82. get { return FsmState == (int)STATE.Init; }
  83. }
  84. public event Action<string> OnEnterError;
  85. private bool _jobDone;
  86. private bool _isInit;
  87. private Stopwatch _timerNotifyJobDone = new Stopwatch();
  88. private BoatHome _home;
  89. private BoatZAxisMove _zAxisMove;
  90. private BoatZAxisManualMove _zAxisManualMove;
  91. private BoatRAxisMove _rAxisMove;
  92. private BoatRAxisMoveCycleTest _rAxisMoveCycleTest;
  93. private BoatZAxisMoveCycleTest _zAxisMoveCycleTest;
  94. private BoatMoveCycleTest _moveCycleTest;
  95. private BoatShutterCycleTest _shutterCycleTest;
  96. private BoatMove _boatMove;
  97. public bool IsExcuteRoutineFailed { get; set; }
  98. public bool IsBoatElevatorAtHomePosition => ZAxisDevice == null ? false : ZAxisDevice.CheckServoAtPosition("HomePosition") && ZAxisDevice.IsReady;
  99. public bool IsBoatRotationAtHomePosition => RAxisDevice == null ? false : RAxisDevice.IsHomeDone && RAxisDevice.IsReady;
  100. public BoatModule(ModuleName module) : base()
  101. {
  102. Name = module.ToString();
  103. Module = module.ToString();
  104. IsOnline = true;
  105. }
  106. public override bool Initialize()
  107. {
  108. InitRoutine();
  109. InitDevice();
  110. InitFsm();
  111. InitOp();
  112. InitData();
  113. InitAlarmEvent();
  114. Singleton<EventManager>.Instance.OnAlarmEvent += Instance_OnAlarmEvent;
  115. return base.Initialize();
  116. }
  117. private void Instance_OnAlarmEvent(EventItem item)
  118. {
  119. if (item != null && item.Level == EventLevel.Alarm && (item.Source == Name || item.Source == Module))
  120. {
  121. DEVICE.GetDevice<SignalTowerBase>("System.SignalTower")?.Reset();
  122. LOG.Write($"{item.Source} {item.EventEnum} {item.Description}\n");
  123. PostMsg(MSG.Error);
  124. }
  125. }
  126. private void InitRoutine()
  127. {
  128. _home = new BoatHome(this);
  129. _zAxisMove = new BoatZAxisMove(this);
  130. _zAxisManualMove = new BoatZAxisManualMove(this);
  131. _rAxisMove = new BoatRAxisMove(this);
  132. _rAxisMoveCycleTest = new BoatRAxisMoveCycleTest(this);
  133. _zAxisMoveCycleTest = new BoatZAxisMoveCycleTest(this);
  134. _shutterCycleTest = new BoatShutterCycleTest(this);
  135. _moveCycleTest = new BoatMoveCycleTest(this);
  136. _boatMove = new BoatMove(this);
  137. }
  138. private void InitData()
  139. {
  140. DATA.Subscribe($"{Module}.Status", () => IsExcuteRoutineFailed ? STATE.Error.ToString() : StringFsmStatus);
  141. DATA.Subscribe($"{Module}.IsError", () => IsError);
  142. DATA.Subscribe($"{Module}.IsOnline", () => IsOnline);
  143. DATA.Subscribe($"{Module}.BoatTestCycledCount", () => _moveCycleTest.LoopCounter);
  144. DATA.Subscribe($"{Module}.ShutterCycledCount", () => _shutterCycleTest.LoopCounter);
  145. }
  146. private void InitOp()
  147. {
  148. OP.Subscribe($"{Module}.Home", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Home));
  149. OP.Subscribe($"{Module}.Abort", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Abort));
  150. OP.Subscribe($"{Module}.Reset", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Reset));
  151. OP.Subscribe($"{Module}.ZAxisMove", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ZAxisMove, args));
  152. OP.Subscribe($"{Module}.ZAxisManualMove", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ZAxisManualMove, args));
  153. OP.Subscribe($"{Module}.RAxisMove", (string cmd, object[] args) => CheckToPostMessage((int)MSG.RAxisMove, args));
  154. OP.Subscribe($"{Module}.RAxisMovingTest", (string cmd, object[] args) => CheckToPostMessage((int)MSG.RAxisMoveTest, args));
  155. OP.Subscribe($"{Module}.ZAxisMovingTest", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ZAxisMoveTest, args));
  156. OP.Subscribe($"{Module}.ShutterCycleTest", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ShutterCycleTest, args));
  157. OP.Subscribe($"{Module}.MovingTest", (string cmd, object[] args) => CheckToPostMessage((int)MSG.MoveTest, args));
  158. OP.Subscribe($"{Name}.SetBoatZAxisSpeed", SetBoatZAxisSpeed);
  159. OP.Subscribe($"{Name}.SetBoatRAxisSpeed", SetBoatRAxisSpeed);
  160. OP.Subscribe($"{Name}.SetBoatRAxisAngle", SetBoatRAxisAngle);
  161. OP.Subscribe($"{Name}.BoatZAxisStop", SetBoatZAxisStop);
  162. OP.Subscribe($"{Name}.BoatRAxisStop", SetBoatRAxisStop);
  163. OP.Subscribe($"{Module}.AlarmAction", (string cmd, object[] args) =>
  164. {
  165. Enum.TryParse(args[0].ToString(), out AlarmAction alarmAction);
  166. string eventName = null;
  167. if (args.Length > 1)
  168. eventName = args[1].ToString();
  169. if (eventName != null)
  170. {
  171. EV.ClearAlarmEvent(eventName);
  172. var item = _triggeredAlarmList.FirstOrDefault(x => x.EventEnum == eventName);
  173. if (item != null)
  174. {
  175. item.Reset();
  176. _triggeredAlarmList.Remove(item);
  177. }
  178. if (item != null)
  179. {
  180. switch (alarmAction)
  181. {
  182. case AlarmAction.Retry:
  183. {
  184. CheckToPostMessage((int)item.RetryMessage, item.RetryMessageParas);
  185. }
  186. break;
  187. case AlarmAction.Abort:
  188. {
  189. CheckToPostMessage((int)MSG.Abort);
  190. }
  191. break;
  192. case AlarmAction.Clear:
  193. {
  194. int alarmCount = 0;
  195. var alarms = EV.GetAlarmEvent();
  196. foreach (var alarm in alarms)
  197. {
  198. if (alarm.Level == EventLevel.Alarm && alarm.Source == Name)
  199. alarmCount++;
  200. }
  201. if (alarmCount == 0)
  202. CheckToPostMessage((int)MSG.Reset);
  203. }
  204. break;
  205. case AlarmAction.Continue:
  206. {
  207. int alarmCount = 0;
  208. var alarms = EV.GetAlarmEvent();
  209. foreach (var alarm in alarms)
  210. {
  211. if (alarm.Level == EventLevel.Alarm && alarm.Source == Name)
  212. alarmCount++;
  213. }
  214. if (alarmCount == 0)
  215. CheckToPostMessage((int)MSG.Reset);
  216. }
  217. break;
  218. }
  219. }
  220. }
  221. return true;
  222. });
  223. }
  224. private void InitFsm()
  225. {
  226. EnumLoop<STATE>.ForEach((item) =>
  227. {
  228. MapState((int)item, item.ToString());
  229. });
  230. EnumLoop<MSG>.ForEach((item) =>
  231. {
  232. MapMessage((int)item, item.ToString());
  233. });
  234. EnableFsm(100, STATE.Idle);
  235. //Init
  236. Transition(STATE.Init, MSG.Home, FsmStartHome, STATE.Homing);
  237. Transition(STATE.Error, MSG.Home, FsmStartHome, STATE.Homing);
  238. Transition(STATE.Idle, MSG.Home, FsmStartHome, STATE.Homing);
  239. Transition(STATE.Homing, FSM_MSG.TIMER, FsmMonitorHomeTask, STATE.Idle);
  240. Transition(STATE.Homing, MSG.Error, null, STATE.Init);
  241. Transition(STATE.Homing, MSG.Abort, FsmAbortTask, STATE.Init);
  242. EnterExitTransition<STATE, FSM_MSG>(STATE.Idle, FsmEnterIdle, FSM_MSG.NONE, FsmExitIdle);
  243. Transition(STATE.Idle, MSG.Abort, null, STATE.Idle);
  244. Transition(STATE.Idle, MSG.Reset, null, STATE.Idle);
  245. Transition(STATE.Init, MSG.Reset, null, STATE.Init);
  246. Transition(STATE.Error, MSG.Abort, null, STATE.Error);
  247. //Error
  248. AnyStateTransition(MSG.Error, FsmOnError, STATE.Error);
  249. Transition(STATE.Error, MSG.Reset, FsmReset, STATE.Idle);
  250. EnterExitTransition<STATE, FSM_MSG>(STATE.Error, FsmEnterError, FSM_MSG.NONE, FsmExitError);
  251. //ZAxisMove,open shutter
  252. Transition(STATE.Error, MSG.ZAxisMoveRetry, FsmStartZAxisMove, STATE.ZAxisMoving);
  253. Transition(STATE.Idle, MSG.ZAxisMove, FsmStartZAxisMove, STATE.ZAxisMoving);
  254. Transition(STATE.ZAxisMoving, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  255. Transition(STATE.ZAxisMoving, MSG.Abort, FsmAbortTask, STATE.Idle);
  256. //ZAxisManualMove,not open shutter
  257. Transition(STATE.Error, MSG.ZAxisManualMoveRetry, FsmStartZAxisManualMove, STATE.ZAxisManualMoving);
  258. Transition(STATE.Idle, MSG.ZAxisManualMove, FsmStartZAxisManualMove, STATE.ZAxisManualMoving);
  259. Transition(STATE.ZAxisManualMoving, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  260. Transition(STATE.ZAxisManualMoving, MSG.Abort, FsmAbortTask, STATE.Idle);
  261. //RAxisMove
  262. Transition(STATE.Error, MSG.RAxisMoveRetry, FsmStartRAxisMove, STATE.RAxisMoving);
  263. Transition(STATE.Idle, MSG.RAxisMove, FsmStartRAxisMove, STATE.RAxisMoving);
  264. Transition(STATE.RAxisMoving, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  265. Transition(STATE.RAxisMoving, MSG.Abort, FsmAbortTask, STATE.Idle);
  266. //RAxisMoveCycleTest
  267. Transition(STATE.Idle, MSG.RAxisMoveTest, FsmStartRAxisMoveTest, STATE.RAxisMovingTest);
  268. Transition(STATE.RAxisMovingTest, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  269. Transition(STATE.RAxisMovingTest, MSG.Abort, FsmAbortTask, STATE.Idle);
  270. //ZAxisMoveCycleTest
  271. Transition(STATE.Idle, MSG.ZAxisMoveTest, FsmStartZAxisMoveTest, STATE.ZAxisMovingTest);
  272. Transition(STATE.ZAxisMovingTest, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  273. Transition(STATE.ZAxisMovingTest, MSG.Abort, FsmAbortTask, STATE.Idle);
  274. //ShutterCycleTest
  275. Transition(STATE.Idle, MSG.ShutterCycleTest, FsmStartShutterCycleTest, STATE.ShutterCycleTest);
  276. Transition(STATE.ShutterCycleTest, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  277. Transition(STATE.ShutterCycleTest, MSG.Abort, FsmAbortTask, STATE.Idle);
  278. //MoveCycleTest
  279. Transition(STATE.Idle, MSG.MoveTest, FsmStartMoveTest, STATE.MovingTest);
  280. Transition(STATE.MovingTest, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  281. Transition(STATE.MovingTest, MSG.Abort, FsmAbortTask, STATE.Idle);
  282. //BoatMove
  283. Transition(STATE.Error, MSG.BoatMoveRetry, FsmStartBoatMove, STATE.BoatMoving);
  284. Transition(STATE.Idle, MSG.BoatMove, FsmStartBoatMove, STATE.BoatMoving);
  285. Transition(STATE.BoatMoving, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
  286. Transition(STATE.BoatMoving, MSG.Abort, FsmAbortTask, STATE.Idle);
  287. Transition(STATE.Idle, MSG.InTransfer, null, STATE.InTransfer);
  288. Transition(STATE.InTransfer, MSG.InTransfer, null, STATE.InTransfer);
  289. Transition(STATE.InTransfer, MSG.TransferComplete, null, STATE.Idle);
  290. Transition(STATE.InTransfer, MSG.Abort, null, STATE.Idle);
  291. }
  292. public bool Home(out string reason)
  293. {
  294. if (!CheckToPostMessage((int)MSG.Home))
  295. {
  296. reason = $"Can not home in {StringFsmStatus} status";
  297. return false;
  298. }
  299. reason = string.Empty;
  300. return true;
  301. }
  302. public void NoteJobStart()
  303. {
  304. _jobDone = false;
  305. }
  306. public void NoteJobComplete()
  307. {
  308. _timerNotifyJobDone.Restart();
  309. _jobDone = true;
  310. }
  311. public override void Monitor()
  312. {
  313. base.Monitor();
  314. }
  315. public override void Reset()
  316. {
  317. if (IsError)
  318. {
  319. CheckToPostMessage((int)MSG.Reset);
  320. }
  321. }
  322. private bool FsmReset(object[] param)
  323. {
  324. return true;
  325. }
  326. private bool FsmOnError(object[] param)
  327. {
  328. if (FsmState == (int)STATE.Error)
  329. {
  330. return false;
  331. }
  332. AbortRoutine();
  333. if (FsmState == (int)STATE.Init)
  334. return false;
  335. return true;
  336. }
  337. private bool FsmExitIdle(object[] param)
  338. {
  339. return true;
  340. }
  341. private bool FsmEnterIdle(object[] param)
  342. {
  343. return true;
  344. }
  345. private bool FsmExitError(object[] param)
  346. {
  347. return true;
  348. }
  349. private bool FsmEnterError(object[] param)
  350. {
  351. if (OnEnterError != null)
  352. OnEnterError(Module);
  353. return true;
  354. }
  355. private bool FsmAbortTask(object[] param)
  356. {
  357. AbortRoutine();
  358. return true;
  359. }
  360. private bool FsmToInit(object[] param)
  361. {
  362. return true;
  363. }
  364. private bool FsmToIdle(object[] param)
  365. {
  366. return true;
  367. }
  368. private bool FsmStartHome(object[] param)
  369. {
  370. Result ret = StartRoutine(_home);
  371. if (ret == Result.FAIL || ret == Result.DONE)
  372. return false;
  373. _isInit = false;
  374. return ret == Result.RUN;
  375. }
  376. private bool FsmStartZAxisMove(object[] param)
  377. {
  378. _zAxisMove.Init(param[0].ToString(), param[1].ToString());
  379. Result ret = StartRoutine(_zAxisMove);
  380. if (ret == Result.FAIL || ret == Result.DONE)
  381. return false;
  382. return ret == Result.RUN;
  383. }
  384. private bool FsmStartZAxisManualMove(object[] param)
  385. {
  386. _zAxisManualMove.Init(param[0].ToString(), param.Length > 1 ? param[1].ToString() : "0");
  387. Result ret = StartRoutine(_zAxisManualMove);
  388. if (ret == Result.FAIL || ret == Result.DONE)
  389. return false;
  390. return ret == Result.RUN;
  391. }
  392. private bool FsmStartRAxisMove(object[] param)
  393. {
  394. _rAxisMove.Init(param[0].ToString(), param.Length > 1 ? param[1].ToString() : "0", param.Length > 2 ? param[2].ToString() : "0");
  395. Result ret = StartRoutine(_rAxisMove);
  396. if (ret == Result.FAIL || ret == Result.DONE)
  397. return false;
  398. return ret == Result.RUN;
  399. }
  400. private bool FsmStartMoveTest(object[] param)
  401. {
  402. _moveCycleTest.Init(param[0].ToString(), param[1].ToString(), param[2].ToString());
  403. Result ret = StartRoutine(_moveCycleTest);
  404. if (ret == Result.FAIL || ret == Result.DONE)
  405. return false;
  406. return ret == Result.RUN;
  407. }
  408. private bool FsmStartRAxisMoveTest(object[] param)
  409. {
  410. _rAxisMoveCycleTest.Init(param[0].ToString());
  411. Result ret = StartRoutine(_rAxisMoveCycleTest);
  412. if (ret == Result.FAIL || ret == Result.DONE)
  413. return false;
  414. return ret == Result.RUN;
  415. }
  416. private bool FsmStartZAxisMoveTest(object[] param)
  417. {
  418. _zAxisMoveCycleTest.Init(param[0].ToString(), param[1].ToString());
  419. Result ret = StartRoutine(_zAxisMoveCycleTest);
  420. if (ret == Result.FAIL || ret == Result.DONE)
  421. return false;
  422. return ret == Result.RUN;
  423. }
  424. private bool FsmStartShutterCycleTest(object[] param)
  425. {
  426. _shutterCycleTest.Init();
  427. Result ret = StartRoutine(_shutterCycleTest);
  428. if (ret == Result.FAIL || ret == Result.DONE)
  429. return false;
  430. return ret == Result.RUN;
  431. }
  432. private bool FsmStartBoatMove(object[] param)
  433. {
  434. _boatMove.Init(param[0].ToString(), param[1].ToString(), param[2].ToString());
  435. Result ret = StartRoutine(_boatMove);
  436. if (ret == Result.FAIL || ret == Result.DONE)
  437. return false;
  438. return ret == Result.RUN;
  439. }
  440. private bool FsmMonitorHomeTask(object[] param)
  441. {
  442. Result ret = MonitorRoutine();
  443. if (ret == Result.FAIL)
  444. {
  445. PostMsg(MSG.Error);
  446. return false;
  447. }
  448. if (ret == Result.DONE)
  449. {
  450. _isInit = true;
  451. return true;
  452. }
  453. return false;
  454. }
  455. private bool FsmMonitorTask(object[] param)
  456. {
  457. Result ret = MonitorRoutine();
  458. if (ret == Result.FAIL)
  459. {
  460. PostMsg(MSG.Error);
  461. return false;
  462. }
  463. return ret == Result.DONE;
  464. }
  465. public bool CheckPrepareMove(out string reason, bool isNeedCheckShutter = true)
  466. {
  467. reason = string.Empty;
  468. //if (!SensorPS13LStatus.Value)
  469. //{
  470. // reason = "PS13 not true, tube not ATM";
  471. // return false;
  472. //}
  473. if (!SensorVAC1.Value)
  474. {
  475. reason = "VAC1 not true";
  476. return false;
  477. }
  478. if (!SensorVAC2.Value)
  479. {
  480. reason = "VAC2 not true";
  481. return false;
  482. }
  483. if (!SensorVAC3.Value)
  484. {
  485. reason = "VAC3 not true";
  486. return false;
  487. }
  488. if (!SensorBoatUnloadInterlock.Value)
  489. {
  490. reason = "boat unload interlock is not OK, please check VAC1,VAV2,VAC3,PS13 status";
  491. return false;
  492. }
  493. if (isNeedCheckShutter && ShutterDevice.OpenCloseStatus != DeviceStatus.Open)
  494. {
  495. reason = "shutter not open";
  496. return false;
  497. }
  498. return true;
  499. }
  500. public void NoteTransferStart()
  501. {
  502. CheckToPostMessage((int)MSG.InTransfer);
  503. }
  504. public void NoteTransferStop()
  505. {
  506. if (FsmState == (int)STATE.InTransfer)
  507. CheckToPostMessage((int)MSG.TransferComplete);
  508. }
  509. public void ZAxisMove(string position, string speed)
  510. {
  511. CheckToPostMessage((int)MSG.ZAxisMove, position, speed);
  512. }
  513. public void BoatMove(string command, string targetPosition, float speed)
  514. {
  515. CheckToPostMessage((int)MSG.BoatMove, command, targetPosition, speed);
  516. }
  517. }
  518. }