BoatModule.cs 22 KB

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