Vehicle.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  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. //state.CurrentPosition = this.CurrentPosition;
  293. //state.CurrentSpeed = this.CurrentSpeed;
  294. //state.CurrentTag = this.CurrentTag;
  295. //state.CurrentTorque = this.CurrentTorque;
  296. var msg = new DriveControlEventArgs();
  297. msg.ControlKind = args.ControlKind;
  298. //msg.Args = state;
  299. DriveControlEventPublish(msg);
  300. }
  301. private void ReqMoveToPos( DriveControlEventArgs args )
  302. {
  303. //var result = drive.Move( args.PositionTag );
  304. //this.MoveTo( "1111" );
  305. var reply = new DriveControlEventArgs();
  306. int targetTag = args.TargetRouteID;
  307. var route = sql.RouteDal.GetK(targetTag);
  308. if ( route == null)
  309. {
  310. reply.Result = Results.Fail("Not Found Route");
  311. this.DriveControlEventPublish(reply);
  312. return;
  313. }
  314. this.MoveTo(route.Name);
  315. reply.Result = Results.Ok( "Position Move" );
  316. this.DriveControlEventPublish(reply);
  317. }
  318. void ReqFaultReset(DriveControlEventArgs _args)
  319. {
  320. //TODO:[20/03/18 ys-hwang] Drive Assign
  321. var drive = 0;
  322. //var result = drive.ResetAmpFault();
  323. var msg = new DriveControlEventArgs
  324. {
  325. ControlKind = DriveControlEventArgs.eControlKind.FaultReset
  326. };
  327. msg.Result = Results.Ok("Drive On");
  328. this.DriveControlEventPublish(msg);
  329. }
  330. void ReqJog(DriveControlEventArgs _args)
  331. {
  332. //TODO:[20/03/18 ys-hwang] Drive Jog Request
  333. var drive = string.Empty;
  334. if (_args.JogDir == DriveControlEventArgs.eJogMoveDir.Positive)
  335. drive = "POSITIVE";
  336. else
  337. drive = "NEGATIVE";
  338. }
  339. void ReqCurrentPos()
  340. {
  341. //TODO:[20/03/18 ys-hwang] Drive Current Position Publish
  342. var task = Task.Factory.StartNew(() =>
  343. {
  344. while (!this.taskCancel.Canceled)
  345. {
  346. LockUtils.Wait(500);
  347. var msg = new DriveControlEventArgs
  348. {
  349. EventDir = DriveControlEventArgs.eEventDir.ToFront ,
  350. ControlKind = DriveControlEventArgs.eControlKind.ReqCurrentPos ,
  351. CurrentPosition = new Random().Next(0, 1000),
  352. };
  353. this.DriveControlEventPublish( msg );
  354. }
  355. });
  356. this.taskCancel.Add(task);
  357. }
  358. void ReqDriveOn(DriveControlEventArgs _args)
  359. {
  360. var drive = "Drive Name";
  361. //drive.On();
  362. var msg = new DriveControlEventArgs
  363. {
  364. ControlKind = DriveControlEventArgs.eControlKind.DriveON
  365. };
  366. msg.Result = Results.Ok("Drive On");
  367. this.DriveControlEventPublish(msg);
  368. }
  369. void ReqDriveOff(DriveControlEventArgs _args)
  370. {
  371. var drive = "Drive Name";
  372. //drive.Off();
  373. var msg = new DriveControlEventArgs
  374. {
  375. ControlKind = DriveControlEventArgs.eControlKind.DriveOFF
  376. };
  377. msg.Result = Results.Ok("Drive On");
  378. this.DriveControlEventPublish(msg);
  379. }
  380. #endregion
  381. #region Thread
  382. void ThreadStart()
  383. {
  384. this.cancel.AddGo(new Action(this._ThSubCmdWorker));
  385. this.cancel.AddGo(new Action(this._ThObstacleChecker));
  386. }
  387. //장애물 감지 Thread
  388. //장애물 감지 패턴 변경도 여기 하자.
  389. private void _ThObstacleChecker()
  390. {
  391. while (!this.cancel.Canceled)
  392. {
  393. try
  394. {
  395. if (this.autoManager.OperationModeProperty == eOperatationMode.AutoMode)
  396. this.CheckObstacle();
  397. }
  398. catch (ThreadInterruptedException threadInterruptedException)
  399. {
  400. }
  401. catch (Exception exception)
  402. {
  403. logger.E(exception);
  404. }
  405. finally
  406. {
  407. LockUtils.Wait(5);
  408. }
  409. }
  410. logger.D("Vehicle - _ThObstacleChecker Dispose");
  411. }
  412. /// <summary>
  413. /// Scheduler 가 주는 Sub Command 를 이용하여 동작하자.
  414. /// </summary>
  415. public void _ThSubCmdWorker()
  416. {
  417. while (!this.cancel.Canceled)
  418. {
  419. try
  420. {
  421. if (this.ObstacleStateProperty != eObstacleState.Normal) //장애물 감지 상태 시 조그 동작만 가능하게.
  422. continue;
  423. if (this.autoManager.AutoModeStateProperty != eAutoModeState.Run) //
  424. continue;
  425. var subCmd = sql.SubCmdDAL.GetSubCmd();
  426. if (subCmd == null) continue;
  427. if (!sql.CommandDAL.All.Any(x => x.CommandID.Equals(subCmd.CmdID)))
  428. {
  429. if (subCmd.CmdType == SubCmd.eCmdType.Auto) //자동 명령중 Main Command 가 없으면 삭제.
  430. {
  431. sql.SubCmdDAL.Delete(subCmd);
  432. logger.I($"SubCmd Deleted - ID={subCmd.ID}, CommandID={subCmd.CmdID}");
  433. }
  434. }
  435. switch (subCmd.Type)
  436. {
  437. case SubCmd.eType.Move:
  438. this.CurrentSubCommand = subCmd;
  439. this.Move(subCmd);
  440. break;
  441. case SubCmd.eType.Load:
  442. this.CurrentSubCommand = subCmd;
  443. this.LoadCarrier(subCmd);
  444. break;
  445. case SubCmd.eType.Unload:
  446. this.CurrentSubCommand = subCmd;
  447. this.UnloadCarrier(subCmd);
  448. break;
  449. case SubCmd.eType.Charge:
  450. this.CurrentSubCommand = subCmd;
  451. this.BatteryCharge(subCmd);
  452. break;
  453. default:
  454. break;
  455. }
  456. }
  457. catch (ThreadInterruptedException threadInterruptedException)
  458. {
  459. }
  460. catch (Exception exception)
  461. {
  462. logger.E(exception);
  463. }
  464. finally
  465. {
  466. LockUtils.Wait(500);
  467. }
  468. }
  469. logger.D("Vehicle - _ThSubCmdWorker Dispose");
  470. }
  471. #endregion
  472. #region Control Action Method
  473. public void EStop()
  474. {
  475. //Clamp EStop
  476. this.clamp.ClampEStop();
  477. this.motion.EStop();
  478. this.autoManager.ProcessAlarm(23);
  479. }
  480. void Move(SubCmd sub)
  481. {
  482. if (this.MoveTo(sub.TargetID))
  483. {
  484. sql.SubCmdDAL.Delete(sub);
  485. }
  486. else
  487. {
  488. if (this.ObstacleStateProperty == eObstacleState.Blocked)
  489. {
  490. }
  491. }
  492. }
  493. bool MoveTo(string pointID)
  494. {
  495. //this.BuzzerOnOff(true, eBuzzerKind.StartWarn);
  496. ////TimerUtils.Once(3000, BuzzerOnOff, false, eBuzzerKind.StartWarn );
  497. //Thread.Sleep(3000);
  498. //this.BuzzerOnOff(false);
  499. this.OnMoveReady?.Invoke();
  500. var moveReadyBuzzerTime = sql.ConfigDal.GetValueToInt(ConstString.BuzzerStartReadyTime);
  501. Thread.Sleep(moveReadyBuzzerTime);
  502. this.OnMoving?.Invoke();
  503. this.IsMoving = true;
  504. //this.BuzzerOnOff(true, eBuzzerKind.Moving);
  505. this.motion.MoveToPoint(pointID, 100);
  506. bool result = Wait4MoveDone();
  507. this.IsMoving = false;
  508. //this.BuzzerOnOff(false);
  509. this.OnMoveFinish?.Invoke();
  510. return result;
  511. }
  512. bool Wait4MoveDone()
  513. {
  514. int waitTime = 6000; //설정 할 수있게.
  515. long st = SwUtils.CurrentTimeMillis;
  516. //Todo: 이동시 확인 사항들.
  517. while (true)
  518. {
  519. Thread.Sleep(5);
  520. if (SwUtils.Gt(st, waitTime))
  521. {
  522. //Todo: 이동시간 초과 시 동작들.
  523. break;
  524. }
  525. if (this.ObstacleStateProperty == eObstacleState.Blocked)
  526. return false;
  527. //Todo: 이동중 명령이 삭제 되면 처리 할일들.
  528. //if (!sql.SubCmdDAL.HasK(this.CurrentSubCommand.ID))
  529. //{
  530. //}
  531. }
  532. return true;
  533. }
  534. public bool LoadCarrier(SubCmd sub)
  535. {
  536. var route = sql.RouteDal.GetRoute(sub.TargetID);
  537. if (!CorrectPosition(route, this.CurrentPosition))
  538. {
  539. this.autoManager.ProcessAlarm(20);
  540. return false; //Alarm
  541. }
  542. int result = this.clamp.Unlock_Sync();
  543. if (result != 0)
  544. {
  545. this.autoManager.ProcessAlarm(result);
  546. return false;
  547. }
  548. result = this.PIOAndLoad(sub.TargetID);
  549. if (result != 0)
  550. {
  551. this.autoManager.ProcessAlarm(result);
  552. return false;
  553. }
  554. result = this.clamp.Lock_Sync();
  555. if (result != 0)
  556. {
  557. this.autoManager.ProcessAlarm(result);
  558. return false;
  559. }
  560. //Load, Unload 가 끝나면 메인 Command 를 완료 했다고 판다.
  561. sql.CommandDAL.UpdateState(sub.CmdID, eCommandState.Complete);
  562. sql.SubCmdDAL.Delete(sub);
  563. return true;
  564. }
  565. public bool UnloadCarrier(SubCmd sub)
  566. {
  567. var route = sql.RouteDal.GetRoute(sub.TargetID);
  568. if (!CorrectPosition(route, this.CurrentPosition))
  569. {
  570. this.autoManager.ProcessAlarm(21);
  571. return false; //Alarm
  572. }
  573. int result = this.clamp.Unlock_Sync();
  574. if (result != 0)
  575. {
  576. this.autoManager.ProcessAlarm(result);
  577. return false;
  578. }
  579. result = this.PIOAndUnload(sub.TargetID);
  580. if (result != 0)
  581. {
  582. this.autoManager.ProcessAlarm(result);
  583. return false;
  584. }
  585. sql.CommandDAL.UpdateState(sub.CmdID, eCommandState.Complete);
  586. sql.SubCmdDAL.Delete(sub);
  587. return true;
  588. }
  589. /// <summary>
  590. /// Battery Charge
  591. /// 충전 시 PIO 를 해야 함.
  592. /// </summary>
  593. /// <param name="sub"></param>
  594. /// <returns></returns>
  595. public bool BatteryCharge(SubCmd sub)
  596. {
  597. var route = sql.RouteDal.GetRoute(sub.TargetID);
  598. if (!CorrectPosition(route, this.CurrentPosition))
  599. {
  600. this.autoManager.ProcessAlarm(21);
  601. return false; //Alarm
  602. }
  603. var pioTimeout = sql.ConfigDal.GetValueToInt(ConstString.PIOTimeOut);
  604. PIOClear();
  605. loggerPIO.I($"Start Unload PIO - [{sub.TargetID}]");
  606. this.OnPIOStart?.Invoke(false);
  607. if (!this.iO.IsOn("IN_PIO_READY"))
  608. {
  609. loggerPIO.E("[Port] - 1 Ready not On");
  610. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  611. //return 0;
  612. }
  613. this.iO.WriteOutputIO("OUT_PIO_READY", true);
  614. loggerPIO.I("[Vehicle] - 1 Ready On");
  615. if (!this.iO.WaitChangeInputIO(true, pioTimeout, "IN_PIO_RECEIVE_RUN"))
  616. {
  617. PIOClear();
  618. loggerPIO.E("[Port] - 2 Receive CV Run Timeout");
  619. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  620. //return 0;
  621. }
  622. this.iO.WriteOutputIO("OUT_PIO_SENDING_RUN", true);
  623. loggerPIO.I("[Vehicle] - 2 Send Run On");
  624. this.SetConveyorSpeed(true);
  625. this.OnOffConveyor(true);
  626. this.OnConveyorStart?.Invoke(false);
  627. var sTime = SwUtils.CurrentTimeMillis;
  628. while (true)
  629. {
  630. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND))
  631. {
  632. PIOClear();
  633. this.OnOffConveyor(false, true);
  634. loggerPIO.E("[Port] Conveyor Wait Time Out");
  635. this.OnFailReport?.Invoke(eFailCode.UnlaodPIOInterlockTimeout);
  636. //if (IsDetectedLoadStart() || IsDetectedCenter()) //중간에 걸려 있다고 생각해서 알람 처리.
  637. // return 12; //Conveyor Moving Timeout
  638. //else
  639. // return 0;
  640. }
  641. if (this.iO.IsOn("IN_PIO_RECEIVE_COMPLITE"))
  642. break;
  643. }
  644. if (!IsDetectedCenter())
  645. this.OnCarrierDetected?.Invoke(false);
  646. this.OnOffConveyor(false); //Stop
  647. this.OnConveyorStop?.Invoke(false);
  648. PIOClear();
  649. this.iO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", true);
  650. this.iO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", false, 1000);
  651. this.OnUnloadComplete?.Invoke();
  652. return true;
  653. }
  654. #endregion
  655. #region Check Method
  656. bool CheckObstacle()
  657. {
  658. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_SAFETY") || this.iO.IsOn("IN_OBSTRUCTION_DETECT_ERROR"))
  659. {
  660. this.motion.Stop();
  661. this.ObstacleStateProperty = eObstacleState.Abnormal;
  662. return true;
  663. }
  664. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_STOP"))
  665. {
  666. this.motion.Stop();
  667. this.ObstacleStateProperty = eObstacleState.Blocked;
  668. return true;
  669. }
  670. if (this.iO.IsOn("IN_OBSTRUCTION_DETECT_SLOW"))
  671. {
  672. this.motion.SlowStop();
  673. this.ObstacleStateProperty = eObstacleState.Decelerate;
  674. return true;
  675. }
  676. this.ObstacleStateProperty = eObstacleState.Normal;
  677. return false;
  678. }
  679. #endregion
  680. #region Mechanical Method
  681. #region Conveyor
  682. int OnOffConveyor(bool isOn, bool isCW = false)
  683. {
  684. if (IsInverterError())
  685. return 16;
  686. if (isCW)
  687. this.iO.OutputOn("OUT_CV_CWCCW");
  688. else
  689. this.iO.OutputOff("OUT_CV_CWCCW");
  690. if (isOn)
  691. this.iO.OutputOn("OUT_CV_RUN");
  692. else
  693. this.iO.OutputOff("OUT_CV_RUN");
  694. return 0;
  695. }
  696. void SetConveyorSpeed(bool IsHight)
  697. {
  698. if (IsHight)
  699. this.iO.WriteOutputIO("OUT_CV_DA", true);
  700. else
  701. this.iO.WriteOutputIO("OUT_CV_DA", false);
  702. }
  703. /// <summary>
  704. /// 입구 감지 로딩시 감속 사용
  705. /// </summary>
  706. /// <returns></returns>
  707. bool IsDetectedLoadStart() => this.iO.IsOn("IN_CV_DETECT_00");
  708. /// <summary>
  709. /// 실물 감지
  710. /// </summary>
  711. /// <returns></returns>
  712. public bool IsDetectedCenter() => this.iO.IsOn("IN_CV_DETECT_01");
  713. bool IsDetectedLoadStop() => this.iO.IsOn("IN_CV_DETECT_02");
  714. bool IsInverterError() => this.iO.IsOn("IN_CV_ERROR");
  715. bool IsLifterPositinCheck() => this.iO.IsOn("IN_LIFTER_POSITION_DETECT");
  716. bool IsLifterDuplication() => this.iO.IsOn("IN_LIFTER_DUPLICATION_DETECT");
  717. bool IsPIOInterLockOn() => this.iO.IsOn("OUT_PIO_INTERLOCK");
  718. int Load_Carrier()
  719. {
  720. if (IsDetectedCenter())
  721. return 9;
  722. OnOffConveyor(true, true);
  723. long sTime = SwUtils.CurrentTimeMillis;
  724. while (true)
  725. {
  726. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND)) //Wait 20Sec
  727. {
  728. OnOffConveyor(false, true);
  729. return 10;
  730. }
  731. if (IsDetectedLoadStart())
  732. break;
  733. }
  734. return 0;
  735. }
  736. int UnloadCarrier()
  737. {
  738. if (!IsDetectedLoadStart())
  739. return 11;
  740. OnOffConveyor(true, true);
  741. long sTime = SwUtils.CurrentTimeMillis;
  742. while (true)
  743. {
  744. if (SwUtils.Gt(sTime, 20 * ConstUtils.ONE_SECOND)) //Wait 20Sec
  745. {
  746. OnOffConveyor(false, true);
  747. return 12;
  748. }
  749. if (!IsDetectedLoadStart())
  750. break;
  751. }
  752. return 0;
  753. }
  754. public int PIOAndLoad(string targetName)
  755. {
  756. #if SIMULATION
  757. PIOClear();
  758. loggerPIO.I($"Start Load PIO - [{targetName}]");
  759. this.OnPIOStart?.Invoke(true);
  760. this.iO.WriteOutputIO("OUT_PIO_RECEIVE_RUN", true);
  761. loggerPIO.I("[Vehicle] - 4 Receive Run On");
  762. Thread.Sleep(1000);//상대 IO 기다린다 생각.
  763. loggerPIO.E("[Port] - 4 Ready On");
  764. //Conveyor Start
  765. loggerPIO.I("[Vehicle] - Conveyor Run");
  766. this.OnConveyorStart?.Invoke(true);
  767. Thread.Sleep(10000);//Conveyor 구동
  768. this.OnCarrierDetected?.Invoke(true);
  769. PIOClear();
  770. Thread.Sleep(1000);
  771. this.OnConveyorStop?.Invoke(true);
  772. #else
  773. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  774. if ( this.IsInverterError() )
  775. return 16;
  776. if ( this.IsLifterPositinCheck() )
  777. return 14;
  778. if ( !this.IsLifterDuplication() )
  779. {
  780. this.OnFailReport?.Invoke( eFailCode.Load_PortHasNotCarrier );
  781. return 0;
  782. }
  783. if ( this.IsDetectedCenter() )
  784. {
  785. this.OnFailReport?.Invoke( eFailCode.Load_VehicleHasCarrier );
  786. return 0;
  787. }
  788. PIOClear();
  789. loggerPIO.I( $"Start Load PIO - [{targetName}]" );
  790. this.OnPIOStart?.Invoke( true );
  791. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN", true );
  792. loggerPIO.I( "[Vehicle] - 4 Receive Run On" );
  793. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_SENDABLE" ) )
  794. {
  795. PIOClear();
  796. loggerPIO.E( "[Port] - 4 Ready Time Out" );
  797. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  798. return 0;
  799. }
  800. loggerPIO.E( "[Port] - 4 Ready On" );
  801. this.SetConveyorSpeed( true );
  802. this.OnOffConveyor( true, true );
  803. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN", true );
  804. loggerPIO.I( "[Vehicle] - Conveyor Run" );
  805. this.OnConveyorStart?.Invoke( true );
  806. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_SEND_RUN" ) )
  807. {
  808. this.OnOffConveyor( false, true );
  809. PIOClear();
  810. loggerPIO.E( "[Port] - 5 Sending Run Time Out" );
  811. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  812. return 0;
  813. }
  814. bool isStartDetected = false;
  815. var sTime = SwUtils.CurrentTimeMillis;
  816. while ( true )
  817. {
  818. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) )
  819. {
  820. PIOClear();
  821. this.OnOffConveyor( false, true );
  822. loggerPIO.E( "[Vehicle] Conveyor Wait Time Out" );
  823. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  824. if ( this.IsDetectedLoadStart() ) // 감지가 시작 되었으면 이동중 Error 로 판단 설비를 정지 상태로
  825. return 10; //Conveyor Moving Timeout
  826. else
  827. return 0;
  828. }
  829. if ( this.IsDetectedLoadStart() && !isStartDetected )
  830. isStartDetected = true;
  831. if ( !this.IsDetectedLoadStart() && isStartDetected )
  832. this.SetConveyorSpeed( false );
  833. if ( this.IsDetectedLoadStop() ) break;
  834. if ( this.IsPIOInterLockOn() )
  835. {
  836. PIOClear();
  837. this.OnOffConveyor( false ); //Stop
  838. loggerPIO.E( "[Port] PIO InterLock On " );
  839. return 19; //
  840. }
  841. }
  842. if ( this.IsDetectedCenter() )
  843. this.OnCarrierDetected?.Invoke( true );
  844. this.OnOffConveyor( false ); //Stop
  845. PIOClear();
  846. this.OnConveyorStop?.Invoke( true );
  847. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE", true );
  848. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE", false, 1000 );
  849. this.OnLoadComplete?.Invoke();
  850. #endif
  851. return 0;
  852. }
  853. public int PIOAndUnload(string targetName)
  854. {
  855. #if SIMULATION
  856. PIOClear();
  857. loggerPIO.I($"Start Unload PIO - [{targetName}]");
  858. this.OnPIOStart?.Invoke(false);
  859. Thread.Sleep(1000);
  860. this.iO.WriteOutputIO("OUT_PIO_READY", true);
  861. loggerPIO.I("[Vehicle] - 1 Ready On");
  862. Thread.Sleep(1000);
  863. this.OnConveyorStart?.Invoke(false);
  864. Thread.Sleep(10000);
  865. this.OnOffConveyor(false); //Stop
  866. this.OnConveyorStop?.Invoke(false);
  867. PIOClear();
  868. this.OnUnloadComplete?.Invoke();
  869. #else
  870. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  871. if ( this.IsInverterError() )
  872. return 16;
  873. if ( this.IsLifterDuplication() )
  874. {
  875. this.OnFailReport?.Invoke( eFailCode.Unload_PortHasCarrier );
  876. return 0;
  877. }
  878. if ( !this.IsDetectedCenter() )
  879. {
  880. this.OnFailReport?.Invoke( eFailCode.Unload_VehicleHasNotCarrier );
  881. return 0;
  882. }
  883. if ( this.IsLifterPositinCheck() )
  884. return 13;
  885. PIOClear();
  886. loggerPIO.I( $"Start Unload PIO - [{targetName}]" );
  887. this.OnPIOStart?.Invoke( false );
  888. if ( !this.iO.IsOn( "IN_PIO_READY" ) )
  889. {
  890. loggerPIO.E( "[Port] - 1 Ready not On" );
  891. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  892. return 0;
  893. }
  894. this.iO.WriteOutputIO( "OUT_PIO_READY", true );
  895. loggerPIO.I( "[Vehicle] - 1 Ready On" );
  896. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_RECEIVE_RUN" ) )
  897. {
  898. PIOClear();
  899. loggerPIO.E( "[Port] - 2 Receive CV Run Timeout" );
  900. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  901. return 0;
  902. }
  903. this.iO.WriteOutputIO( "OUT_PIO_SENDING_RUN", true );
  904. loggerPIO.I( "[Vehicle] - 2 Send Run On" );
  905. this.SetConveyorSpeed( true );
  906. this.OnOffConveyor( true );
  907. this.OnConveyorStart?.Invoke( false );
  908. var sTime = SwUtils.CurrentTimeMillis;
  909. while ( true )
  910. {
  911. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) )
  912. {
  913. PIOClear();
  914. this.OnOffConveyor( false, true );
  915. loggerPIO.E( "[Port] Conveyor Wait Time Out" );
  916. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  917. if ( IsDetectedLoadStart() || IsDetectedCenter() ) //중간에 걸려 있다고 생각해서 알람 처리.
  918. return 12; //Conveyor Moving Timeout
  919. else
  920. return 0;
  921. }
  922. if ( this.iO.IsOn( "IN_PIO_RECEIVE_COMPLITE" ) )
  923. break;
  924. }
  925. if ( !IsDetectedCenter() )
  926. this.OnCarrierDetected?.Invoke( false );
  927. this.OnOffConveyor( false ); //Stop
  928. this.OnConveyorStop?.Invoke( false );
  929. PIOClear();
  930. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", true );
  931. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", false, 1000 );
  932. this.OnUnloadComplete?.Invoke();
  933. #endif
  934. return 0;
  935. }
  936. void PIOClear()
  937. {
  938. 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" };
  939. pio.FwEach(x => { this.iO.OutputOff(x); });
  940. }
  941. #endregion
  942. #endregion
  943. #region Hardware Create Method
  944. void CreateSteering()
  945. {
  946. this.steering = new Steering(this.iO, this.sql, this.eventAggregator);
  947. this.steering.OnSteeringError += Steering_OnSteeringError;
  948. this.steering.PropertyChanged += Steering_PropertyChanged;
  949. }
  950. void CreateClamp()
  951. {
  952. this.clamp = new Clamp(this.sql, this.eventAggregator);
  953. this.clamp.Init();
  954. }
  955. void CreateDrive()
  956. {
  957. this.motion = new GSIMotion(this.sql);
  958. this.motion.PropertyChanged += Motion_PropertyChanged;
  959. }
  960. #endregion
  961. #region Help Method
  962. /// <summary>
  963. /// 현재 좌표 값이 등록된 Route 에 맞는 위치인지 확인한다.
  964. /// 판단 기준은 Route 에 Tolerance 범위를 사용.
  965. /// </summary>
  966. /// <param name="route"></param>
  967. /// <param name="currentPosition"></param>
  968. /// <returns></returns>
  969. bool CorrectPosition(Route route, double currentPosition)
  970. {
  971. var rScale = route.ScaleValue;
  972. var rTolerance = route.ScaleTolerance;
  973. var result = currentPosition - rScale;
  974. if (rTolerance < Math.Abs(result))
  975. return false;
  976. return true;
  977. }
  978. /// <summary>
  979. /// if no is zero, Laser Off
  980. /// bit Off, On, On, On,On Area1
  981. /// </summary>
  982. /// <param name="no"> 0 == Off Laser</param>
  983. /// <returns></returns>
  984. bool ChgObstacleDetectPattern(int no)
  985. {
  986. var bitArray = BitUtils.ChgBitArray(no);
  987. int bitIndex = 0;
  988. this.obstacleBitList.ForEach(b =>
  989. {
  990. if (bitArray[bitIndex])
  991. this.iO.OutputOff(b);
  992. else
  993. this.iO.OutputOn(b);
  994. bitIndex++;
  995. });
  996. return true;
  997. }
  998. int GetObstacleDetectPattern()
  999. {
  1000. int bitIndex = 0;
  1001. BitArray bitArray = new BitArray(this.obstacleBitList.Count);
  1002. this.obstacleBitList.ForEach(b =>
  1003. {
  1004. if (this.iO.IsOn(b))
  1005. bitArray.Set(bitIndex, false);
  1006. else
  1007. bitArray.Set(bitIndex, true);
  1008. bitIndex++;
  1009. });
  1010. return BitUtils.ChgInt32(bitArray);
  1011. }
  1012. #endregion
  1013. #region Event Subscribe
  1014. private void Motion_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
  1015. {
  1016. var property = sender.GetType().GetProperty(e.PropertyName);
  1017. var newValue = property.GetValue(sender, null);
  1018. if (e.PropertyName.Equals("CurrentPos"))
  1019. {
  1020. var v = CastTo<double>.From<object>(newValue);
  1021. this.CurrentPosition = v;
  1022. }
  1023. if (e.PropertyName.Equals("CurrentTag"))
  1024. {
  1025. var v = CastTo<string>.From<object>(newValue);
  1026. this.CurrentTag = v;
  1027. }
  1028. if (e.PropertyName.Equals("CurrentSpeed"))
  1029. {
  1030. var v = CastTo<double>.From<object>(newValue);
  1031. this.CurrentSpeed = v;
  1032. }
  1033. if (e.PropertyName.Equals("CurrentTorque"))
  1034. {
  1035. var v = CastTo<double>.From<object>(newValue);
  1036. this.CurrentTorque = v;
  1037. }
  1038. }
  1039. private void Steering_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
  1040. {
  1041. var property = sender.GetType().GetProperty(e.PropertyName);
  1042. var newValue = property.GetValue(sender, null);
  1043. //Todo: 나중에 Test 하자
  1044. //var ownPropperty = this.GetType().GetProperty(e.PropertyName);
  1045. if (e.PropertyName.Equals("SteeringState"))
  1046. {
  1047. var v = CastTo<eSteeringState>.From<object>(newValue);
  1048. this.SteeringState = v;
  1049. }
  1050. }
  1051. private void IO_OnChangedIO(BitBlock bit)
  1052. {
  1053. if (bit.Tag.Equals("IN_CV_DETECT_01"))
  1054. {
  1055. this.IsContain = bit.IsBitOn;
  1056. }
  1057. }
  1058. private void Steering_OnSteeringError(object sender, int e)
  1059. {
  1060. if (e != 0)
  1061. {
  1062. logger.E($"[Steering] - Control Error {e}");
  1063. this.autoManager.ProcessAlarm(e);
  1064. }
  1065. else
  1066. {
  1067. var msg = new DriveControlEventArgs()
  1068. {
  1069. EventDir = DriveControlEventArgs.eEventDir.ToFront,
  1070. ControlKind = DriveControlEventArgs.eControlKind.Steering,
  1071. Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>(DriveControlEventArgs.eMoveDir.LEFT),
  1072. };
  1073. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish(msg);
  1074. }
  1075. }
  1076. #endregion
  1077. }
  1078. }