Vehicle.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using FluentResults;
  8. using GSG.NET.Concurrent;
  9. using GSG.NET.Extensions;
  10. using GSG.NET.LINQ;
  11. using GSG.NET.Logging;
  12. using GSG.NET.Quartz;
  13. using GSG.NET.Utils;
  14. using OHV.Common.Events;
  15. using OHV.Common.Model;
  16. using OHV.Common.Shareds;
  17. using OHV.SqliteDAL;
  18. using Prism.Events;
  19. using VehicleControlSystem.ControlLayer.Actuator.Cylinder;
  20. using VehicleControlSystem.ControlLayer.IO;
  21. using VehicleControlSystem.ControlLayer.Motion;
  22. using VehicleControlSystem.Managers;
  23. namespace VehicleControlSystem.ControlLayer
  24. {
  25. /// <summary>
  26. /// Control Layer 의 자원을 여기서 사용하자.
  27. /// </summary>
  28. public class Vehicle : ControlObjectBase, IDisposable
  29. {
  30. /// <summary>
  31. /// OCS Report Code
  32. /// 목적지에 도착해서 Load, Unload 시 발생하는 Alarm
  33. /// </summary>
  34. public enum eFailCode
  35. {
  36. Load_PortHasNotCarrier = 1,
  37. Load_VehicleHasCarrier,
  38. Unload_PortHasCarrier,
  39. Unload_VehicleHasNotCarrier,
  40. LoadPIOInterlockTimeout,
  41. UnlaodPIOInterlockTimeout,
  42. }
  43. static Logger logger = Logger.GetLogger();
  44. static Logger loggerPIO = Logger.GetLogger("PIO");
  45. #region Properties
  46. /// <summary>
  47. /// Tag 위치
  48. /// </summary>
  49. private string currentTag;
  50. public string CurrentTag
  51. {
  52. get { return currentTag; }
  53. set
  54. {
  55. if ( SetField(ref this.currentTag, value))
  56. this.OnCurrentTagChanged?.Invoke(value);
  57. }
  58. }
  59. /// <summary>
  60. /// Scale Value
  61. /// </summary>
  62. private double currentPosition;
  63. public double CurrentPosition
  64. {
  65. get { return currentPosition; }
  66. set
  67. {
  68. if (SetField(ref this.currentPosition, value))
  69. {
  70. }
  71. }
  72. }
  73. private double currentSpeed;
  74. public double CurrentSpeed
  75. {
  76. get { return currentSpeed; }
  77. set { SetField(ref this.currentSpeed, value); }
  78. }
  79. private double currentTorque;
  80. public double CurrentTorque
  81. {
  82. get { return currentTorque; }
  83. set { SetField(ref this.currentTorque, value); }
  84. }
  85. private bool isContain;
  86. public bool IsContain
  87. {
  88. get { return isContain; }
  89. set { SetField(ref this.isContain, value); }
  90. }
  91. private eSteeringState steeringState;
  92. public eSteeringState SteeringState
  93. {
  94. get { return steeringState; }
  95. set { SetField(ref this.steeringState, value); }
  96. }
  97. //이동
  98. public bool Busy
  99. {
  100. get
  101. {
  102. return this.CurrentSubCommand == null ? false : true;
  103. }
  104. set { }
  105. }
  106. public bool IsMoving { get; set; }
  107. public double BatteryVolt { get; set; }
  108. public bool IsError { get; set; }
  109. public SubCmd CurrentSubCommand { get; private set; }
  110. #endregion
  111. #region Event
  112. public event Action OnMoveReady;
  113. public event Action OnMoving;
  114. public event Action OnMoveFinish;
  115. public event Action OnChargingStart;
  116. public event Action OnCharging;
  117. public event Action OnChargingFull;
  118. public event Action<double> OnBatteryVelueChanged;
  119. public event Action<bool> OnPIOStart;
  120. public event Action<bool> OnConveyorStart;
  121. public event Action<bool> OnConveyorStop;
  122. public event Action<bool> OnCarrierDetected;
  123. public event Action OnLoadComplete;
  124. public event Action OnUnloadComplete;
  125. public event Action<string> OnCurrentTagChanged;
  126. public event Action OnManualMove;
  127. public event Action OnManualLoad;
  128. public event Action OnManualUnload;
  129. public event Action OnManualCharging;
  130. public event Action<eFailCode> OnFailReport;
  131. #endregion
  132. EzIO iO = null;
  133. GSIMotion motion = null;
  134. SqliteManager sql = null;
  135. Clamp clamp = null;
  136. Steering steering = null;
  137. AutoManager autoManager = null;
  138. #region List.
  139. List<ICylinder> cylinders = new List<ICylinder>();
  140. List<string> obstacleBitList = new List<string>();
  141. #endregion
  142. ThreadCancel cancel = new ThreadCancel();
  143. TaskCancel taskCancel = new TaskCancel();
  144. private eObstacleState obstacleState = eObstacleState.Normal;
  145. public eObstacleState ObstacleStateProperty
  146. {
  147. get { return obstacleState; }
  148. set { SetField(ref this.obstacleState, value); }
  149. }
  150. private eVehicleState vehicleState;
  151. public eVehicleState VehicleStateProperty
  152. {
  153. get { return vehicleState; }
  154. set { SetField(ref this.vehicleState, value); }
  155. }
  156. IEventAggregator eventAggregator;
  157. public Vehicle(IIO io, SqliteManager sqliteManager, IEventAggregator ea, AutoManager auto)
  158. {
  159. this.iO = io as EzIO;
  160. this.iO.OnChangedIO += IO_OnChangedIO;
  161. this.sql = sqliteManager;
  162. this.autoManager = auto;
  163. this.obstacleBitList.AddRange(new string[]
  164. {
  165. "OUT_OBSTRUCTION_PATTERN_00",
  166. "OUT_OBSTRUCTION_PATTERN_01",
  167. "OUT_OBSTRUCTION_PATTERN_02",
  168. "OUT_OBSTRUCTION_PATTERN_03",
  169. "OUT_OBSTRUCTION_PATTERN_04",
  170. });
  171. this.eventAggregator = ea;
  172. /*Drive*/
  173. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Unsubscribe( ReceiveDriveControlEvent );
  174. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Subscribe( ReceiveDriveControlEvent );
  175. /*IO*/
  176. this.eventAggregator.GetEvent<IOControlPubSubEvent>().Unsubscribe( ReceiveIOControlEvent );
  177. this.eventAggregator.GetEvent<IOControlPubSubEvent>().Subscribe( ReceiveIOControlEvent );
  178. }
  179. private void ReceiveIOControlEvent( IOControlEventArgs _args )
  180. {
  181. if ( this.autoManager.OperationModeProperty != eOperatationMode.ManualMode )
  182. return;
  183. var msg = _args;
  184. if(msg.EventDir == IOControlEventArgs.eEventDir.ToBack)
  185. {
  186. switch ( msg.ControlKind )
  187. {
  188. case IOControlEventArgs.eControlKind.USE:
  189. break;
  190. case IOControlEventArgs.eControlKind.ON:
  191. break;
  192. case IOControlEventArgs.eControlKind.OFF:
  193. break;
  194. case IOControlEventArgs.eControlKind.STATE:
  195. break;
  196. }
  197. }
  198. }
  199. private void ReceiveDriveControlEvent(DriveControlEventArgs _args)
  200. {
  201. if (this.autoManager.OperationModeProperty != eOperatationMode.ManualMode)
  202. return;
  203. var msg = _args;
  204. if (msg.EventDir == DriveControlEventArgs.eEventDir.ToBack)
  205. {
  206. switch (msg.ControlKind)
  207. {
  208. case DriveControlEventArgs.eControlKind.MOVE:
  209. this.ReqMoveToPos(_args);
  210. break;
  211. case DriveControlEventArgs.eControlKind.STOP:
  212. break;
  213. case DriveControlEventArgs.eControlKind.Steering:
  214. if (msg.MoveDir == DriveControlEventArgs.eMoveDir.LEFT)
  215. this.steering.ControlSteering(true);
  216. else
  217. this.steering.ControlSteering();
  218. break;
  219. case DriveControlEventArgs.eControlKind.SteeringState:
  220. {
  221. DriveControlEventArgs reply = new DriveControlEventArgs();
  222. reply.ControlKind = DriveControlEventArgs.eControlKind.SteeringState;
  223. if (this.steering.IsLeft())
  224. reply.Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>(DriveControlEventArgs.eMoveDir.LEFT);
  225. else
  226. reply.Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>(DriveControlEventArgs.eMoveDir.RIGHT);
  227. this.DriveControlEventPublish(reply);
  228. }
  229. break;
  230. case DriveControlEventArgs.eControlKind.ReqCurrentPos:
  231. //this.ReqCurrentPos();
  232. break;
  233. case DriveControlEventArgs.eControlKind.ReqStopCurrentPos:
  234. //this.taskCancel.Cancel();
  235. //this.taskCancel.WaitAll();
  236. break;
  237. case DriveControlEventArgs.eControlKind.FaultReset:
  238. this.ReqFaultReset(_args);
  239. break;
  240. case DriveControlEventArgs.eControlKind.DriveON:
  241. this.ReqDriveOn(_args);
  242. break;
  243. case DriveControlEventArgs.eControlKind.DriveOFF:
  244. this.ReqDriveOff(_args);
  245. break;
  246. case DriveControlEventArgs.eControlKind.JOG:
  247. this.ReqJog(_args);
  248. break;
  249. case DriveControlEventArgs.eControlKind.VehicleState:
  250. ReqVehicleState(_args);
  251. break;
  252. default:
  253. break;
  254. }
  255. }
  256. }
  257. //private void DriveControlEventPublish( DriveControlEventArgs args ) { }
  258. private void DriveControlEventPublish(DriveControlEventArgs args)
  259. {
  260. args.EventDir = DriveControlEventArgs.eEventDir.ToFront;
  261. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish(args);
  262. }
  263. public void Init()
  264. {
  265. this.CreateClamp();
  266. this.CreateSteering();
  267. CreateDrive();
  268. ThreadStart();
  269. //TimerUtils.Once(5000, () => { this.CurrentPosition = 1000; });
  270. }
  271. public int InitializationVehicle()
  272. {
  273. int result = 0;
  274. if (this.IsDetectedCenter()) //자제가 있으면 Lock
  275. result = this.clamp.Lock_Sync();
  276. else
  277. result = this.clamp.Unlock_Sync();
  278. if (this.motion.IsErrorOn)
  279. return 22;
  280. return result;
  281. }
  282. public void Dispose()
  283. {
  284. this.cancel.Cancel();
  285. this.cancel.StopWaitAll();
  286. }
  287. #region Request Method
  288. private void ReqVehicleState(DriveControlEventArgs args)
  289. {
  290. //TODO:[20/03/20 ys-hwang] VehicleState Class Not Assign
  291. VehicleState state = new VehicleState
  292. {
  293. CurrentPosition = this.CurrentPosition ,
  294. CurrentSpeed = this.CurrentSpeed ,
  295. CurrentTag = this.CurrentTag ,
  296. CurrentTorque = this.CurrentTorque
  297. };
  298. var msg = new DriveControlEventArgs();
  299. msg.ControlKind = args.ControlKind;
  300. msg.Args = state;
  301. DriveControlEventPublish(msg);
  302. }
  303. private void ReqMoveToPos( DriveControlEventArgs args )
  304. {
  305. //var result = drive.Move( args.PositionTag );
  306. //this.MoveTo( "1111" );
  307. var reply = new DriveControlEventArgs();
  308. int targetTag = args.TargetRouteID;
  309. var route = sql.RouteDal.GetK(targetTag);
  310. if ( route == null)
  311. {
  312. reply.Result = Results.Fail("Not Found Route");
  313. this.DriveControlEventPublish(reply);
  314. return;
  315. }
  316. this.MoveTo(route.Name);
  317. reply.Result = Results.Ok( "Position Move" );
  318. this.DriveControlEventPublish(reply);
  319. }
  320. void ReqFaultReset(DriveControlEventArgs _args)
  321. {
  322. //TODO:[20/03/18 ys-hwang] Drive Assign
  323. var drive = 0;
  324. //var result = drive.ResetAmpFault();
  325. var msg = new DriveControlEventArgs
  326. {
  327. ControlKind = DriveControlEventArgs.eControlKind.FaultReset
  328. };
  329. msg.Result = Results.Ok("Drive On");
  330. this.DriveControlEventPublish(msg);
  331. }
  332. void ReqJog(DriveControlEventArgs _args)
  333. {
  334. //TODO:[20/03/18 ys-hwang] Drive Jog Request
  335. var drive = string.Empty;
  336. if (_args.JogDir == DriveControlEventArgs.eJogMoveDir.Positive)
  337. drive = "POSITIVE";
  338. else
  339. drive = "NEGATIVE";
  340. }
  341. void ReqCurrentPos()
  342. {
  343. //TODO:[20/03/18 ys-hwang] Drive Current Position Publish
  344. var task = Task.Factory.StartNew(() =>
  345. {
  346. while (!this.taskCancel.Canceled)
  347. {
  348. LockUtils.Wait(500);
  349. var msg = new DriveControlEventArgs
  350. {
  351. EventDir = DriveControlEventArgs.eEventDir.ToFront ,
  352. ControlKind = DriveControlEventArgs.eControlKind.ReqCurrentPos ,
  353. CurrentPosition = new Random().Next(0, 1000),
  354. };
  355. this.DriveControlEventPublish( msg );
  356. }
  357. });
  358. this.taskCancel.Add(task);
  359. }
  360. void ReqDriveOn(DriveControlEventArgs _args)
  361. {
  362. var drive = "Drive Name";
  363. //drive.On();
  364. var msg = new DriveControlEventArgs
  365. {
  366. ControlKind = DriveControlEventArgs.eControlKind.DriveON
  367. };
  368. msg.Result = Results.Ok("Drive On");
  369. this.DriveControlEventPublish(msg);
  370. }
  371. void ReqDriveOff(DriveControlEventArgs _args)
  372. {
  373. var drive = "Drive Name";
  374. //drive.Off();
  375. var msg = new DriveControlEventArgs
  376. {
  377. ControlKind = DriveControlEventArgs.eControlKind.DriveOFF
  378. };
  379. msg.Result = Results.Ok("Drive On");
  380. this.DriveControlEventPublish(msg);
  381. }
  382. #endregion
  383. #region Thread
  384. void ThreadStart()
  385. {
  386. this.cancel.AddGo(new Action(this._ThSubCmdWorker));
  387. this.cancel.AddGo(new Action(this._ThObstacleChecker));
  388. }
  389. //장애물 감지 Thread
  390. //장애물 감지 패턴 변경도 여기 하자.
  391. private void _ThObstacleChecker()
  392. {
  393. while (!this.cancel.Canceled)
  394. {
  395. try
  396. {
  397. if (this.autoManager.OperationModeProperty == eOperatationMode.AutoMode)
  398. this.CheckObstacle();
  399. }
  400. catch (ThreadInterruptedException threadInterruptedException)
  401. {
  402. }
  403. catch (Exception exception)
  404. {
  405. logger.E(exception);
  406. }
  407. finally
  408. {
  409. LockUtils.Wait(5);
  410. }
  411. }
  412. logger.D("Vehicle - _ThObstacleChecker Dispose");
  413. }
  414. /// <summary>
  415. /// Scheduler 가 주는 Sub Command 를 이용하여 동작하자.
  416. /// </summary>
  417. public void _ThSubCmdWorker()
  418. {
  419. while (!this.cancel.Canceled)
  420. {
  421. try
  422. {
  423. if (this.ObstacleStateProperty != eObstacleState.Normal) //장애물 감지 상태 시 조그 동작만 가능하게.
  424. continue;
  425. if (this.autoManager.AutoModeStateProperty != eAutoModeState.Run) //
  426. continue;
  427. var subCmd = sql.SubCmdDAL.GetSubCmd();
  428. if (subCmd == null) continue;
  429. if (!sql.CommandDAL.All.Any(x => x.CommandID.Equals(subCmd.CmdID)))
  430. {
  431. if (subCmd.CmdType == SubCmd.eCmdType.Auto) //자동 명령중 Main Command 가 없으면 삭제.
  432. {
  433. sql.SubCmdDAL.Delete(subCmd);
  434. logger.I($"SubCmd Deleted - ID={subCmd.ID}, CommandID={subCmd.CmdID}");
  435. }
  436. }
  437. switch (subCmd.Type)
  438. {
  439. case SubCmd.eType.Move:
  440. this.CurrentSubCommand = subCmd;
  441. this.Move(subCmd);
  442. break;
  443. case SubCmd.eType.Load:
  444. this.CurrentSubCommand = subCmd;
  445. this.LoadCarrier(subCmd);
  446. break;
  447. case SubCmd.eType.Unload:
  448. this.CurrentSubCommand = subCmd;
  449. this.UnloadCarrier(subCmd);
  450. break;
  451. case SubCmd.eType.Charge:
  452. this.CurrentSubCommand = subCmd;
  453. this.BatteryCharge(subCmd);
  454. break;
  455. default:
  456. break;
  457. }
  458. }
  459. catch (ThreadInterruptedException threadInterruptedException)
  460. {
  461. }
  462. catch (Exception exception)
  463. {
  464. logger.E(exception);
  465. }
  466. finally
  467. {
  468. LockUtils.Wait(500);
  469. }
  470. }
  471. logger.D("Vehicle - _ThSubCmdWorker Dispose");
  472. }
  473. #endregion
  474. #region Control Action Method
  475. public void EStop()
  476. {
  477. //Clamp EStop
  478. this.clamp.ClampEStop();
  479. this.motion.EStop();
  480. this.autoManager.ProcessAlarm(23);
  481. }
  482. void Move(SubCmd sub)
  483. {
  484. if (this.MoveTo(sub.TargetID))
  485. {
  486. sql.SubCmdDAL.Delete(sub);
  487. }
  488. else
  489. {
  490. if (this.ObstacleStateProperty == eObstacleState.Blocked)
  491. {
  492. }
  493. }
  494. }
  495. bool MoveTo(string pointID)
  496. {
  497. //this.BuzzerOnOff(true, eBuzzerKind.StartWarn);
  498. ////TimerUtils.Once(3000, BuzzerOnOff, false, eBuzzerKind.StartWarn );
  499. //Thread.Sleep(3000);
  500. //this.BuzzerOnOff(false);
  501. this.OnMoveReady?.Invoke();
  502. var moveReadyBuzzerTime = sql.ConfigDal.GetValueToInt(ConstString.BuzzerStartReadyTime);
  503. Thread.Sleep(moveReadyBuzzerTime);
  504. this.OnMoving?.Invoke();
  505. this.IsMoving = true;
  506. //this.BuzzerOnOff(true, eBuzzerKind.Moving);
  507. this.motion.MoveToPoint(pointID, 100);
  508. bool result = Wait4MoveDone();
  509. this.IsMoving = false;
  510. //this.BuzzerOnOff(false);
  511. this.OnMoveFinish?.Invoke();
  512. return result;
  513. }
  514. bool Wait4MoveDone()
  515. {
  516. int waitTime = 6000; //설정 할 수있게.
  517. long st = SwUtils.CurrentTimeMillis;
  518. //Todo: 이동시 확인 사항들.
  519. while (true)
  520. {
  521. Thread.Sleep(5);
  522. if (SwUtils.Gt(st, waitTime))
  523. {
  524. //Todo: 이동시간 초과 시 동작들.
  525. break;
  526. }
  527. if (this.ObstacleStateProperty == eObstacleState.Blocked)
  528. return false;
  529. //Todo: 이동중 명령이 삭제 되면 처리 할일들.
  530. //if (!sql.SubCmdDAL.HasK(this.CurrentSubCommand.ID))
  531. //{
  532. //}
  533. }
  534. return true;
  535. }
  536. public bool LoadCarrier(SubCmd sub)
  537. {
  538. var route = sql.RouteDal.GetRoute(sub.TargetID);
  539. if (!CorrectPosition(route, this.CurrentPosition))
  540. {
  541. this.autoManager.ProcessAlarm(20);
  542. return false; //Alarm
  543. }
  544. int result = this.clamp.Unlock_Sync();
  545. if (result != 0)
  546. {
  547. this.autoManager.ProcessAlarm(result);
  548. return false;
  549. }
  550. result = this.PIOAndLoad(sub.TargetID);
  551. if (result != 0)
  552. {
  553. this.autoManager.ProcessAlarm(result);
  554. return false;
  555. }
  556. result = this.clamp.Lock_Sync();
  557. if (result != 0)
  558. {
  559. this.autoManager.ProcessAlarm(result);
  560. return false;
  561. }
  562. //Load, Unload 가 끝나면 메인 Command 를 완료 했다고 판다.
  563. sql.CommandDAL.UpdateState(sub.CmdID, eCommandState.Complete);
  564. sql.SubCmdDAL.Delete(sub);
  565. return true;
  566. }
  567. public bool UnloadCarrier(SubCmd sub)
  568. {
  569. var route = sql.RouteDal.GetRoute(sub.TargetID);
  570. if (!CorrectPosition(route, this.CurrentPosition))
  571. {
  572. this.autoManager.ProcessAlarm(21);
  573. return false; //Alarm
  574. }
  575. int result = this.clamp.Unlock_Sync();
  576. if (result != 0)
  577. {
  578. this.autoManager.ProcessAlarm(result);
  579. return false;
  580. }
  581. result = this.PIOAndUnload(sub.TargetID);
  582. if (result != 0)
  583. {
  584. this.autoManager.ProcessAlarm(result);
  585. return false;
  586. }
  587. sql.CommandDAL.UpdateState(sub.CmdID, eCommandState.Complete);
  588. sql.SubCmdDAL.Delete(sub);
  589. return true;
  590. }
  591. /// <summary>
  592. /// Battery Charge
  593. /// 충전 시 PIO 를 해야 함.
  594. /// </summary>
  595. /// <param name="sub"></param>
  596. /// <returns></returns>
  597. public bool BatteryCharge(SubCmd sub)
  598. {
  599. var route = sql.RouteDal.GetRoute(sub.TargetID);
  600. if (!CorrectPosition(route, this.CurrentPosition))
  601. {
  602. this.autoManager.ProcessAlarm(21);
  603. return false; //Alarm
  604. }
  605. var pioTimeout = sql.ConfigDal.GetValueToInt(ConstString.PIOTimeOut);
  606. PIOClear();
  607. loggerPIO.I($"Start Unload PIO - [{sub.TargetID}]");
  608. this.OnPIOStart?.Invoke(false);
  609. if (!this.iO.IsOn("IN_PIO_READY"))
  610. {
  611. loggerPIO.E("[Port] - 1 Ready not On");
  612. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  613. //return 0;
  614. }
  615. this.iO.WriteOutputIO("OUT_PIO_READY", true);
  616. loggerPIO.I("[Vehicle] - 1 Ready On");
  617. if (!this.iO.WaitChangeInputIO(true, pioTimeout, "IN_PIO_RECEIVE_RUN"))
  618. {
  619. PIOClear();
  620. loggerPIO.E("[Port] - 2 Receive CV Run Timeout");
  621. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  622. //return 0;
  623. }
  624. this.iO.WriteOutputIO("OUT_PIO_SENDING_RUN", true);
  625. loggerPIO.I("[Vehicle] - 2 Send Run On");
  626. this.SetConveyorSpeed(true);
  627. this.OnOffConveyor(true);
  628. this.OnConveyorStart?.Invoke(false);
  629. var sTime = SwUtils.CurrentTimeMillis;
  630. while (true)
  631. {
  632. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND))
  633. {
  634. PIOClear();
  635. this.OnOffConveyor(false, true);
  636. loggerPIO.E("[Port] Conveyor Wait Time Out");
  637. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  638. //if (IsDetectedLoadStart() || IsDetectedCenter()) //중간에 걸려 있다고 생각해서 알람 처리.
  639. // return 12; //Conveyor Moving Timeout
  640. //else
  641. // return 0;
  642. }
  643. if (this.iO.IsOn("IN_PIO_RECEIVE_COMPLITE"))
  644. break;
  645. }
  646. if (!IsDetectedCenter())
  647. this.OnCarrierDetected?.Invoke(false);
  648. this.OnOffConveyor(false); //Stop
  649. this.OnConveyorStop?.Invoke(false);
  650. PIOClear();
  651. this.iO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", true);
  652. this.iO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", false, 1000);
  653. this.OnUnloadComplete?.Invoke();
  654. return true;
  655. }
  656. #endregion
  657. #region Check Method
  658. bool CheckObstacle()
  659. {
  660. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_SAFETY") || this.iO.IsOn("IN_OBSTRUCTION_DETECT_ERROR"))
  661. {
  662. this.motion.Stop();
  663. this.ObstacleStateProperty = eObstacleState.Abnormal;
  664. return true;
  665. }
  666. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_STOP"))
  667. {
  668. this.motion.Stop();
  669. this.ObstacleStateProperty = eObstacleState.Blocked;
  670. return true;
  671. }
  672. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_SLOW"))
  673. {
  674. this.motion.SlowStop();
  675. this.ObstacleStateProperty = eObstacleState.Decelerate;
  676. return true;
  677. }
  678. this.ObstacleStateProperty = eObstacleState.Normal;
  679. return false;
  680. }
  681. #endregion
  682. #region Mechanical Method
  683. #region Conveyor
  684. int OnOffConveyor(bool isOn, bool isCW = false)
  685. {
  686. if (IsInverterError())
  687. return 16;
  688. if (isCW)
  689. this.iO.OutputOn("OUT_CV_CWCCW");
  690. else
  691. this.iO.OutputOff("OUT_CV_CWCCW");
  692. if (isOn)
  693. this.iO.OutputOn("OUT_CV_RUN");
  694. else
  695. this.iO.OutputOff("OUT_CV_RUN");
  696. return 0;
  697. }
  698. void SetConveyorSpeed(bool IsHight)
  699. {
  700. if (IsHight)
  701. this.iO.WriteOutputIO("OUT_CV_DA", true);
  702. else
  703. this.iO.WriteOutputIO("OUT_CV_DA", false);
  704. }
  705. /// <summary>
  706. /// 입구 감지 로딩시 감속 사용
  707. /// </summary>
  708. /// <returns></returns>
  709. bool IsDetectedLoadStart() => this.iO.IsOn("IN_CV_DETECT_00");
  710. /// <summary>
  711. /// 실물 감지
  712. /// </summary>
  713. /// <returns></returns>
  714. public bool IsDetectedCenter() => this.iO.IsOn("IN_CV_DETECT_01");
  715. bool IsDetectedLoadStop() => this.iO.IsOn("IN_CV_DETECT_02");
  716. bool IsInverterError() => this.iO.IsOn("IN_CV_ERROR");
  717. bool IsLifterPositinCheck() => this.iO.IsOn("IN_LIFTER_POSITION_DETECT");
  718. bool IsLifterDuplication() => this.iO.IsOn("IN_LIFTER_DUPLICATION_DETECT");
  719. bool IsPIOInterLockOn() => this.iO.IsOn("OUT_PIO_INTERLOCK");
  720. int Load_Carrier()
  721. {
  722. if (IsDetectedCenter())
  723. return 9;
  724. OnOffConveyor(true, true);
  725. long sTime = SwUtils.CurrentTimeMillis;
  726. while (true)
  727. {
  728. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND)) //Wait 20Sec
  729. {
  730. OnOffConveyor(false, true);
  731. return 10;
  732. }
  733. if (IsDetectedLoadStart())
  734. break;
  735. }
  736. return 0;
  737. }
  738. int UnloadCarrier()
  739. {
  740. if (!IsDetectedLoadStart())
  741. return 11;
  742. OnOffConveyor(true, true);
  743. long sTime = SwUtils.CurrentTimeMillis;
  744. while (true)
  745. {
  746. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND)) //Wait 20Sec
  747. {
  748. OnOffConveyor(false, true);
  749. return 12;
  750. }
  751. if (!IsDetectedLoadStart())
  752. break;
  753. }
  754. return 0;
  755. }
  756. public int PIOAndLoad(string targetName)
  757. {
  758. #if SIMULATION
  759. PIOClear();
  760. loggerPIO.I($"Start Load PIO - [{targetName}]");
  761. this.OnPIOStart?.Invoke(true);
  762. this.iO.WriteOutputIO("OUT_PIO_RECEIVE_RUN", true);
  763. loggerPIO.I("[Vehicle] - 4 Receive Run On");
  764. Thread.Sleep(1000);//상대 IO 기다린다 생각.
  765. loggerPIO.E("[Port] - 4 Ready On");
  766. //Conveyor Start
  767. loggerPIO.I("[Vehicle] - Conveyor Run");
  768. this.OnConveyorStart?.Invoke(true);
  769. Thread.Sleep(10000);//Conveyor 구동
  770. this.OnCarrierDetected?.Invoke(true);
  771. PIOClear();
  772. Thread.Sleep(1000);
  773. this.OnConveyorStop?.Invoke(true);
  774. #else
  775. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  776. if ( this.IsInverterError() )
  777. return 16;
  778. if ( this.IsLifterPositinCheck() )
  779. return 14;
  780. if ( !this.IsLifterDuplication() )
  781. {
  782. this.OnFailReport?.Invoke( eFailCode.Load_PortHasNotCarrier );
  783. return 0;
  784. }
  785. if ( this.IsDetectedCenter() )
  786. {
  787. this.OnFailReport?.Invoke( eFailCode.Load_VehicleHasCarrier );
  788. return 0;
  789. }
  790. PIOClear();
  791. loggerPIO.I( $"Start Load PIO - [{targetName}]" );
  792. this.OnPIOStart?.Invoke( true );
  793. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN", true );
  794. loggerPIO.I( "[Vehicle] - 4 Receive Run On" );
  795. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_SENDABLE" ) )
  796. {
  797. PIOClear();
  798. loggerPIO.E( "[Port] - 4 Ready Time Out" );
  799. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  800. return 0;
  801. }
  802. loggerPIO.E( "[Port] - 4 Ready On" );
  803. this.SetConveyorSpeed( true );
  804. this.OnOffConveyor( true, true );
  805. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN", true );
  806. loggerPIO.I( "[Vehicle] - Conveyor Run" );
  807. this.OnConveyorStart?.Invoke( true );
  808. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_SEND_RUN" ) )
  809. {
  810. this.OnOffConveyor( false, true );
  811. PIOClear();
  812. loggerPIO.E( "[Port] - 5 Sending Run Time Out" );
  813. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  814. return 0;
  815. }
  816. bool isStartDetected = false;
  817. var sTime = SwUtils.CurrentTimeMillis;
  818. while ( true )
  819. {
  820. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) )
  821. {
  822. PIOClear();
  823. this.OnOffConveyor( false, true );
  824. loggerPIO.E( "[Vehicle] Conveyor Wait Time Out" );
  825. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  826. if ( this.IsDetectedLoadStart() ) // 감지가 시작 되었으면 이동중 Error 로 판단 설비를 정지 상태로
  827. return 10; //Conveyor Moving Timeout
  828. else
  829. return 0;
  830. }
  831. if ( this.IsDetectedLoadStart() && !isStartDetected )
  832. isStartDetected = true;
  833. if ( !this.IsDetectedLoadStart() && isStartDetected )
  834. this.SetConveyorSpeed( false );
  835. if ( this.IsDetectedLoadStop() ) break;
  836. if ( this.IsPIOInterLockOn() )
  837. {
  838. PIOClear();
  839. this.OnOffConveyor( false ); //Stop
  840. loggerPIO.E( "[Port] PIO InterLock On " );
  841. return 19; //
  842. }
  843. }
  844. if ( this.IsDetectedCenter() )
  845. this.OnCarrierDetected?.Invoke( true );
  846. this.OnOffConveyor( false ); //Stop
  847. PIOClear();
  848. this.OnConveyorStop?.Invoke( true );
  849. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE", true );
  850. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE", false, 1000 );
  851. this.OnLoadComplete?.Invoke();
  852. #endif
  853. return 0;
  854. }
  855. public int PIOAndUnload(string targetName)
  856. {
  857. #if SIMULATION
  858. PIOClear();
  859. loggerPIO.I($"Start Unload PIO - [{targetName}]");
  860. this.OnPIOStart?.Invoke(false);
  861. Thread.Sleep(1000);
  862. this.iO.WriteOutputIO("OUT_PIO_READY", true);
  863. loggerPIO.I("[Vehicle] - 1 Ready On");
  864. Thread.Sleep(1000);
  865. this.OnConveyorStart?.Invoke(false);
  866. Thread.Sleep(10000);
  867. this.OnOffConveyor(false); //Stop
  868. this.OnConveyorStop?.Invoke(false);
  869. PIOClear();
  870. this.OnUnloadComplete?.Invoke();
  871. #else
  872. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  873. if ( this.IsInverterError() )
  874. return 16;
  875. if ( this.IsLifterDuplication() )
  876. {
  877. this.OnFailReport?.Invoke( eFailCode.Unload_PortHasCarrier );
  878. return 0;
  879. }
  880. if ( !this.IsDetectedCenter() )
  881. {
  882. this.OnFailReport?.Invoke( eFailCode.Unload_VehicleHasNotCarrier );
  883. return 0;
  884. }
  885. if ( this.IsLifterPositinCheck() )
  886. return 13;
  887. PIOClear();
  888. loggerPIO.I( $"Start Unload PIO - [{targetName}]" );
  889. this.OnPIOStart?.Invoke( false );
  890. if ( !this.iO.IsOn( "IN_PIO_READY" ) )
  891. {
  892. loggerPIO.E( "[Port] - 1 Ready not On" );
  893. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  894. return 0;
  895. }
  896. this.iO.WriteOutputIO( "OUT_PIO_READY", true );
  897. loggerPIO.I( "[Vehicle] - 1 Ready On" );
  898. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_RECEIVE_RUN" ) )
  899. {
  900. PIOClear();
  901. loggerPIO.E( "[Port] - 2 Receive CV Run Timeout" );
  902. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  903. return 0;
  904. }
  905. this.iO.WriteOutputIO( "OUT_PIO_SENDING_RUN", true );
  906. loggerPIO.I( "[Vehicle] - 2 Send Run On" );
  907. this.SetConveyorSpeed( true );
  908. this.OnOffConveyor( true );
  909. this.OnConveyorStart?.Invoke( false );
  910. var sTime = SwUtils.CurrentTimeMillis;
  911. while ( true )
  912. {
  913. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) )
  914. {
  915. PIOClear();
  916. this.OnOffConveyor( false, true );
  917. loggerPIO.E( "[Port] Conveyor Wait Time Out" );
  918. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  919. if ( IsDetectedLoadStart() || IsDetectedCenter() ) //중간에 걸려 있다고 생각해서 알람 처리.
  920. return 12; //Conveyor Moving Timeout
  921. else
  922. return 0;
  923. }
  924. if ( this.iO.IsOn( "IN_PIO_RECEIVE_COMPLITE" ) )
  925. break;
  926. }
  927. if ( !IsDetectedCenter() )
  928. this.OnCarrierDetected?.Invoke( false );
  929. this.OnOffConveyor( false ); //Stop
  930. this.OnConveyorStop?.Invoke( false );
  931. PIOClear();
  932. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", true );
  933. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", false, 1000 );
  934. this.OnUnloadComplete?.Invoke();
  935. #endif
  936. return 0;
  937. }
  938. void PIOClear()
  939. {
  940. string[] pio = { "OUT_PIO_READY", "OUT_PIO_SENDING_RUN", "OUT_PIO_SEND_COMPLITE", "OUT_PIO_RECEIVABLE", "OUT_PIO_RECEIVE_RUN", "OUT_PIO_RECIVE_COMPLITE", "OUT_PIO_INTERLOCK" };
  941. pio.FwEach(x => { this.iO.OutputOff(x); });
  942. }
  943. #endregion
  944. #endregion
  945. #region Hardware Create Method
  946. void CreateSteering()
  947. {
  948. this.steering = new Steering(this.iO, this.sql, this.eventAggregator);
  949. this.steering.OnSteeringError += Steering_OnSteeringError;
  950. this.steering.PropertyChanged += Steering_PropertyChanged;
  951. }
  952. void CreateClamp()
  953. {
  954. this.clamp = new Clamp(this.sql, this.eventAggregator);
  955. this.clamp.Init();
  956. }
  957. void CreateDrive()
  958. {
  959. this.motion = new GSIMotion(this.sql);
  960. this.motion.PropertyChanged += Motion_PropertyChanged;
  961. }
  962. #endregion
  963. #region Help Method
  964. /// <summary>
  965. /// 현재 좌표 값이 등록된 Route 에 맞는 위치인지 확인한다.
  966. /// 판단 기준은 Route 에 Tolerance 범위를 사용.
  967. /// </summary>
  968. /// <param name="route"></param>
  969. /// <param name="currentPosition"></param>
  970. /// <returns></returns>
  971. bool CorrectPosition(Route route, double currentPosition)
  972. {
  973. var rScale = route.ScaleValue;
  974. var rTolerance = route.ScaleTolerance;
  975. var result = currentPosition - rScale;
  976. if (rTolerance < Math.Abs(result))
  977. return false;
  978. return true;
  979. }
  980. /// <summary>
  981. /// if no is zero, Laser Off
  982. /// bit Off, On, On, On,On Area1
  983. /// </summary>
  984. /// <param name="no"> 0 == Off Laser</param>
  985. /// <returns></returns>
  986. bool ChgObstacleDetectPattern(int no)
  987. {
  988. var bitArray = BitUtils.ChgBitArray(no);
  989. int bitIndex = 0;
  990. this.obstacleBitList.ForEach(b =>
  991. {
  992. if (bitArray[bitIndex])
  993. this.iO.OutputOff(b);
  994. else
  995. this.iO.OutputOn(b);
  996. bitIndex++;
  997. });
  998. return true;
  999. }
  1000. int GetObstacleDetectPattern()
  1001. {
  1002. int bitIndex = 0;
  1003. BitArray bitArray = new BitArray(this.obstacleBitList.Count);
  1004. this.obstacleBitList.ForEach(b =>
  1005. {
  1006. if (this.iO.IsOn(b))
  1007. bitArray.Set(bitIndex, false);
  1008. else
  1009. bitArray.Set(bitIndex, true);
  1010. bitIndex++;
  1011. });
  1012. return BitUtils.ChgInt32(bitArray);
  1013. }
  1014. #endregion
  1015. #region Event Subscribe
  1016. private void Motion_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
  1017. {
  1018. var property = sender.GetType().GetProperty(e.PropertyName);
  1019. var newValue = property.GetValue(sender, null);
  1020. if (e.PropertyName.Equals("CurrentPos"))
  1021. {
  1022. var v = CastTo<double>.From<object>(newValue);
  1023. this.CurrentPosition = v;
  1024. }
  1025. if (e.PropertyName.Equals("CurrentTag"))
  1026. {
  1027. var v = CastTo<string>.From<object>(newValue);
  1028. this.CurrentTag = v;
  1029. }
  1030. if (e.PropertyName.Equals("CurrentSpeed"))
  1031. {
  1032. var v = CastTo<double>.From<object>(newValue);
  1033. this.CurrentSpeed = v;
  1034. }
  1035. if (e.PropertyName.Equals("CurrentTorque"))
  1036. {
  1037. var v = CastTo<double>.From<object>(newValue);
  1038. this.CurrentTorque = v;
  1039. }
  1040. }
  1041. private void Steering_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
  1042. {
  1043. var property = sender.GetType().GetProperty(e.PropertyName);
  1044. var newValue = property.GetValue(sender, null);
  1045. //Todo: 나중에 Test 하자
  1046. //var ownPropperty = this.GetType().GetProperty(e.PropertyName);
  1047. if (e.PropertyName.Equals("SteeringState"))
  1048. {
  1049. var v = CastTo<eSteeringState>.From<object>(newValue);
  1050. this.SteeringState = v;
  1051. }
  1052. }
  1053. private void IO_OnChangedIO(BitBlock bit)
  1054. {
  1055. if (bit.Tag.Equals("IN_CV_DETECT_01"))
  1056. {
  1057. this.IsContain = bit.IsBitOn;
  1058. }
  1059. }
  1060. private void Steering_OnSteeringError(object sender, int e)
  1061. {
  1062. if (e != 0)
  1063. {
  1064. logger.E($"[Steering] - Control Error {e}");
  1065. this.autoManager.ProcessAlarm(e);
  1066. }
  1067. else
  1068. {
  1069. var msg = new DriveControlEventArgs()
  1070. {
  1071. EventDir = DriveControlEventArgs.eEventDir.ToFront,
  1072. ControlKind = DriveControlEventArgs.eControlKind.Steering,
  1073. Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>(DriveControlEventArgs.eMoveDir.LEFT),
  1074. };
  1075. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish(msg);
  1076. }
  1077. }
  1078. #endregion
  1079. }
  1080. }