Vehicle.cs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  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.ControlLayer.Serial.BatteryTabos;
  23. using VehicleControlSystem.ControlLayer.Serial.DataModel;
  24. using VehicleControlSystem.Managers;
  25. namespace VehicleControlSystem.ControlLayer
  26. {
  27. /// <summary>
  28. /// Control Layer 의 자원을 여기서 사용하자.
  29. /// </summary>
  30. public class Vehicle : ControlObjectBase, IDisposable
  31. {
  32. /// <summary>
  33. /// OCS Report Code
  34. /// 목적지에 도착해서 Load, Unload 시 발생하는 Alarm
  35. /// </summary>
  36. public enum eFailCode
  37. {
  38. Load_PortHasNotCarrier = 1,
  39. Load_VehicleHasCarrier,
  40. Unload_PortHasCarrier,
  41. Unload_VehicleHasNotCarrier,
  42. LoadPIOInterlockTimeout,
  43. UnlaodPIOInterlockTimeout,
  44. }
  45. static Logger logger = Logger.GetLogger();
  46. static Logger loggerPIO = Logger.GetLogger( "PIO" );
  47. #region Properties
  48. /// <summary>
  49. /// Tag 위치
  50. /// </summary>
  51. private string currentTag = "0000";
  52. public string CurrentTag
  53. {
  54. get { return currentTag; }
  55. set
  56. {
  57. if ( SetField( ref this.currentTag , value ) )
  58. {
  59. var info = sql.VehicleInfoDAL.GetInfo();
  60. info.CurrentTag = value;
  61. sql.VehicleInfoDAL.Update( info );
  62. this.OnCurrentTagChanged?.Invoke( value );
  63. }
  64. }
  65. }
  66. /// <summary>
  67. /// Scale Value
  68. /// </summary>
  69. private double currentPosition;
  70. public double CurrentPosition
  71. {
  72. get { return currentPosition; }
  73. set
  74. {
  75. if ( SetField( ref this.currentPosition , value ) )
  76. {
  77. }
  78. }
  79. }
  80. private double currentSpeed;
  81. public double CurrentSpeed
  82. {
  83. get { return currentSpeed; }
  84. set { SetField( ref this.currentSpeed , value ); }
  85. }
  86. private double currentTorque;
  87. public double CurrentTorque
  88. {
  89. get { return currentTorque; }
  90. set { SetField( ref this.currentTorque , value ); }
  91. }
  92. private bool isContain;
  93. public bool IsContain
  94. {
  95. get { return isContain; }
  96. set { SetField( ref this.isContain , value ); }
  97. }
  98. eClampState _clampState;
  99. public eClampState ClampState
  100. {
  101. get { return this._clampState; }
  102. set { this.SetField( ref this._clampState , value ); }
  103. }
  104. private eSteeringState steeringState;
  105. public eSteeringState SteeringState
  106. {
  107. get { return steeringState; }
  108. set { SetField( ref this.steeringState , value ); }
  109. }
  110. private int _obstacleDrive;
  111. public int ObstacleDrive { get { return this._obstacleDrive; } set { SetField( ref this._obstacleDrive , value ); } }
  112. private int _obstacleCurve;
  113. public int ObstacleCurve { get { return this._obstacleCurve; } set { SetField( ref this._obstacleCurve , value ); } }
  114. private eObstacleState obstacleState = eObstacleState.Normal;
  115. public eObstacleState ObstacleStateProperty
  116. {
  117. get { return obstacleState; }
  118. set
  119. {
  120. if ( SetField( ref this.obstacleState , value ) )
  121. {
  122. if ( value == eObstacleState.Blocked )
  123. this.VehicleStateProperty = eVehicleState.Blocked;
  124. }
  125. }
  126. }
  127. private eVehicleState vehicleState = eVehicleState.None;
  128. public eVehicleState VehicleStateProperty
  129. {
  130. get { return vehicleState; }
  131. set
  132. {
  133. if ( SetField( ref this.vehicleState , value ) )
  134. {
  135. var info = sql.VehicleInfoDAL.GetInfo();
  136. info.VehicleState = value;
  137. sql.VehicleInfoDAL.Update( info );
  138. }
  139. }
  140. }
  141. private eMachineMode machineMode = eMachineMode.LocalMode;
  142. public eMachineMode MachineMode
  143. {
  144. get { return machineMode; }
  145. set
  146. {
  147. if ( SetField( ref this.machineMode , value ) )
  148. {
  149. var info = sql.VehicleInfoDAL.GetInfo();
  150. info.MachineMode = value;
  151. sql.VehicleInfoDAL.Update( info );
  152. }
  153. }
  154. }
  155. private int obstaclePattern;
  156. public int ObstaclePattern
  157. {
  158. get { return obstaclePattern; }
  159. set { SetField( ref this.obstaclePattern, value ); }
  160. }
  161. //이동
  162. public bool Busy
  163. {
  164. get
  165. {
  166. return this.CurrentSubCommand == null ? false : true;
  167. }
  168. set { }
  169. }
  170. public bool IsMoving { get; set; }
  171. double batteryVoltage;
  172. public double BatteryVoltage
  173. {
  174. get { return this.batteryVoltage; }
  175. set { this.SetField( ref this.batteryVoltage , value );}
  176. }
  177. double batteryCurrent;
  178. public double BatteryCurrent
  179. {
  180. get { return this.batteryCurrent; }
  181. set{this.SetField(ref this.batteryCurrent, value); }
  182. }
  183. double batteryState;
  184. public double BatteryState
  185. {
  186. get { return this.batteryState; }
  187. set { this.SetField( ref this.batteryState , value); }
  188. }
  189. double batteryChargeTime;
  190. public double BatteryChargeTime
  191. {
  192. get { return this.batteryChargeTime; }
  193. set { this.SetField( ref this.batteryChargeTime , value ); }
  194. }
  195. double batteryDisChargeTime;
  196. public double BatteryDisChargeTime
  197. {
  198. get { return this.batteryDisChargeTime; }
  199. set { this.SetField( ref this.batteryDisChargeTime , value ); }
  200. }
  201. double batteryStateOfCharge;
  202. public double BatteryStateOfCharge
  203. {
  204. get { return this.batteryStateOfCharge; }
  205. set { this.SetField( ref this.batteryStateOfCharge , value ); }
  206. }
  207. double batteryStateOfHealth;
  208. public double BatteryStateOfHealth
  209. {
  210. get { return this.batteryStateOfHealth; }
  211. set { this.SetField( ref this.batteryStateOfHealth , value ); }
  212. }
  213. double batteryCapacity;
  214. public double BatteryCapacity
  215. {
  216. get { return this.batteryCapacity; }
  217. set { this.SetField( ref this.batteryCapacity , value ); }
  218. }
  219. double batteryEnergy;
  220. public double BatteryEnergy
  221. {
  222. get { return this.batteryEnergy; }
  223. set { this.SetField( ref this.batteryEnergy , value ); }
  224. }
  225. double batteryTemperature;
  226. public double BatteryTemperature
  227. {
  228. get { return this.batteryTemperature; }
  229. set { this.SetField( ref this.batteryTemperature , value ); }
  230. }
  231. bool batteryIsConnect;
  232. public bool BatteryIsConnect
  233. {
  234. get
  235. {
  236. this.BatteryIsConnect = this.bMUManager.IsConnected;
  237. return this.bMUManager.IsConnected;
  238. }
  239. set { this.SetField( ref this.batteryIsConnect , value ); }
  240. }
  241. public bool IsError { get; set; }
  242. public SubCmd CurrentSubCommand { get; private set; }
  243. #endregion
  244. #region Event
  245. public event Action OnMoveReady;
  246. public event Action OnMoving;
  247. public event Action OnMoveFinish;
  248. public event Action OnChargingStart;
  249. public event Action OnCharging;
  250. public event Action OnChargingFull;
  251. public event Action<double> OnBatteryVelueChanged;
  252. public event Action<bool> OnPIOStart;
  253. public event Action<bool> OnConveyorStart;
  254. public event Action<bool> OnConveyorStop;
  255. public event Action<bool> OnCarrierDetected;
  256. public event Action OnLoadComplete;
  257. public event Action OnUnloadComplete;
  258. public event Action<string> OnCurrentTagChanged;
  259. public event Action OnManualMove;
  260. public event Action OnManualLoad;
  261. public event Action OnManualUnload;
  262. public event Action OnManualCharging;
  263. public event Action<eFailCode> OnFailReport;
  264. #endregion
  265. #region List.
  266. List<ICylinder> cylinders = new List<ICylinder>();
  267. List<string> obstacleBitList = new List<string>();
  268. #endregion
  269. EzIO iO = null;
  270. GSIMotion motion = null;
  271. SqliteManager sql = null;
  272. Clamp clamp = null;
  273. Steering steering = null;
  274. AutoManager autoManager = null;
  275. BMUManager bMUManager = null;
  276. ThreadCancel cancel = new ThreadCancel();
  277. TaskCancel taskCancel = new TaskCancel();
  278. TaskCancel taskMoveCancel = new TaskCancel();
  279. IEventAggregator eventAggregator;
  280. public Vehicle( IIO io, SqliteManager sqliteManager, IEventAggregator ea, AutoManager auto )
  281. {
  282. this.iO = io as EzIO;
  283. this.iO.OnChangedIO += IO_OnChangedIO;
  284. this.sql = sqliteManager;
  285. this.autoManager = auto;
  286. this.obstacleBitList.AddRange( new string[]
  287. {
  288. "OUT_OBSTRUCTION_PATTERN_00",
  289. "OUT_OBSTRUCTION_PATTERN_01",
  290. "OUT_OBSTRUCTION_PATTERN_02",
  291. "OUT_OBSTRUCTION_PATTERN_03",
  292. "OUT_OBSTRUCTION_PATTERN_04",
  293. } );
  294. this.eventAggregator = ea;
  295. /*Drive*/
  296. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Unsubscribe( ReceiveDriveControlEvent );
  297. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Subscribe( ReceiveDriveControlEvent );
  298. this.eventAggregator.GetEvent<ObstacleControlPubSubEvent>().Unsubscribe( ObstacleReceiveEvent );
  299. this.eventAggregator.GetEvent<ObstacleControlPubSubEvent>().Subscribe( ObstacleReceiveEvent );
  300. }
  301. private void ObstacleReceiveEvent( ObstacleControlEventArgs obj )
  302. {
  303. if ( this.autoManager.OperationModeProperty != eOperatationMode.ManualMode )
  304. return;
  305. if ( obj.EventDir == ObstacleControlEventArgs.eEventDir.ToBack )
  306. {
  307. switch ( obj.ControlKind )
  308. {
  309. case ObstacleControlEventArgs.eControlKind.NONE:
  310. break;
  311. case ObstacleControlEventArgs.eControlKind.DRIVE:
  312. //this.ChgObstacleDetectPattern( new Random().Next( 0 , 40 ) );
  313. break;
  314. case ObstacleControlEventArgs.eControlKind.CURVE:
  315. //this.ChgObstacleDetectPattern( new Random().Next( 0 , 40 ) );
  316. break;
  317. case ObstacleControlEventArgs.eControlKind.STATE:
  318. //var value = this.GetObstacleDetectPattern();
  319. break;
  320. case ObstacleControlEventArgs.eControlKind.INFO:
  321. {
  322. var msg = new ObstacleControlEventArgs
  323. {
  324. ControlKind = ObstacleControlEventArgs.eControlKind.INFO,
  325. Drive = this.ObstacleDrive,
  326. Curve = this.ObstacleCurve,
  327. ObstacleState = this.ObstacleStateProperty.ToString()
  328. };
  329. this.ObstacleControlEventPublish( msg );
  330. }
  331. break;
  332. case ObstacleControlEventArgs.eControlKind.SAVE:
  333. {
  334. this.ObstacleCurve = obj.Curve;
  335. this.ObstacleDrive = obj.Drive;
  336. var reply = new ObstacleControlEventArgs
  337. {
  338. ControlKind = ObstacleControlEventArgs.eControlKind.SAVE
  339. };
  340. reply.Result = Results.Ok( ObstacleControlEventArgs.eControlKind.SAVE );
  341. this.ObstacleControlEventPublish( reply );
  342. }
  343. break;
  344. }
  345. }
  346. }
  347. private void ObstacleControlEventPublish( ObstacleControlEventArgs args )
  348. {
  349. args.EventDir = ObstacleControlEventArgs.eEventDir.ToFront;
  350. this.eventAggregator.GetEvent<ObstacleControlPubSubEvent>().Publish( args );
  351. }
  352. private void ReceiveDriveControlEvent( DriveControlEventArgs _args )
  353. {
  354. if ( this.autoManager.OperationModeProperty != eOperatationMode.ManualMode )
  355. return;
  356. var msg = _args;
  357. if ( msg.EventDir == DriveControlEventArgs.eEventDir.ToBack )
  358. {
  359. switch ( msg.ControlKind )
  360. {
  361. case DriveControlEventArgs.eControlKind.MOVE:
  362. this.ReqMoveToPos( _args );
  363. break;
  364. case DriveControlEventArgs.eControlKind.STOP:
  365. break;
  366. case DriveControlEventArgs.eControlKind.Steering:
  367. if ( msg.MoveDir == DriveControlEventArgs.eMoveDir.LEFT )
  368. this.steering.ControlSteering( true );
  369. else
  370. this.steering.ControlSteering();
  371. break;
  372. case DriveControlEventArgs.eControlKind.SteeringState:
  373. {
  374. var reply = new DriveControlEventArgs();
  375. reply.ControlKind = DriveControlEventArgs.eControlKind.SteeringState;
  376. if ( this.steering.IsLeft() )
  377. reply.Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>( DriveControlEventArgs.eMoveDir.LEFT );
  378. else
  379. reply.Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>( DriveControlEventArgs.eMoveDir.RIGHT );
  380. this.DriveControlEventPublish( reply );
  381. }
  382. break;
  383. case DriveControlEventArgs.eControlKind.ReqCurrentPos:
  384. //this.ReqCurrentPos();
  385. break;
  386. case DriveControlEventArgs.eControlKind.ReqStopCurrentPos:
  387. //this.taskCancel.Cancel();
  388. //this.taskCancel.WaitAll();
  389. break;
  390. case DriveControlEventArgs.eControlKind.FaultReset:
  391. this.ReqFaultReset( _args );
  392. break;
  393. case DriveControlEventArgs.eControlKind.DriveON:
  394. this.ReqDriveOn( _args );
  395. break;
  396. case DriveControlEventArgs.eControlKind.DriveOFF:
  397. this.ReqDriveOff( _args );
  398. break;
  399. case DriveControlEventArgs.eControlKind.JOG:
  400. this.ReqJog( _args );
  401. break;
  402. case DriveControlEventArgs.eControlKind.VehicleState:
  403. ReqVehicleState( _args );
  404. break;
  405. case DriveControlEventArgs.eControlKind.NONE:
  406. break;
  407. case DriveControlEventArgs.eControlKind.Conveyor:
  408. this.ReqConveyor( _args );
  409. break;
  410. default:
  411. break;
  412. }
  413. }
  414. }
  415. private void ReqConveyor( DriveControlEventArgs args )
  416. {
  417. if ( args.CvDir == DriveControlEventArgs.eCvDir.CW ) //Load
  418. this.OnOffConveyor( true, false );
  419. else if ( args.CvDir == DriveControlEventArgs.eCvDir.CCW ) //Unload
  420. this.OnOffConveyor( true, true );
  421. else if ( args.CvDir == DriveControlEventArgs.eCvDir.STOP )
  422. this.OnOffConveyor( false, false );
  423. }
  424. private void DriveControlEventPublish( DriveControlEventArgs args )
  425. {
  426. args.EventDir = DriveControlEventArgs.eEventDir.ToFront;
  427. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish( args );
  428. }
  429. public void Init()
  430. {
  431. this.CreateClamp();
  432. this.CreateSteering();
  433. this.CreateDrive();
  434. this.CreateBMUManager();
  435. ThreadStart();
  436. //TimerUtils.Once(5000, () => { this.CurrentPosition = 1000; });
  437. var v = sql.VehicleInfoDAL.GetInfo();
  438. v.CurrentTag = "0000";
  439. v.VehicleState = eVehicleState.None;
  440. v.MachineMode = eMachineMode.LocalMode;
  441. sql.VehicleInfoDAL.Update( v );
  442. }
  443. public int InitializationVehicle()
  444. {
  445. int result = 0;
  446. if ( this.IsDetectedCenter() ) //자제가 있으면 Lock
  447. result = this.clamp.Lock_Sync();
  448. else
  449. result = this.clamp.Unlock_Sync();
  450. if ( this.motion.IsErrorOn )
  451. return 22;
  452. this.VehicleStateProperty = eVehicleState.Idle;
  453. return result;
  454. }
  455. public void Dispose()
  456. {
  457. this.cancel.Cancel();
  458. this.cancel.StopWaitAll();
  459. }
  460. #region Request Method
  461. private void ReqVehicleState( DriveControlEventArgs args )
  462. {
  463. VehicleInfo state = new VehicleInfo();
  464. state.CurrentPosition = this.CurrentPosition;
  465. state.CurrentSpeed = this.CurrentSpeed;
  466. state.CurrentTag = this.CurrentTag;
  467. state.CurrentTorque = this.CurrentTorque;
  468. state.Voltage = this.BatteryVoltage;
  469. state.Current = this.BatteryCurrent;
  470. state.BatteryState = this.BatteryState;
  471. state.ChargeTime = this.BatteryChargeTime;
  472. state.DisChargeTime = this.BatteryDisChargeTime;
  473. state.SOC = this.BatteryStateOfCharge;
  474. state.SOH = this.BatteryStateOfHealth;
  475. state.Capacity = this.BatteryCapacity;
  476. state.Energy = this.BatteryEnergy;
  477. state.Temperature = this.BatteryTemperature;
  478. state.BatteryIsConnect = this.BatteryIsConnect;
  479. var msg = new DriveControlEventArgs();
  480. msg.ControlKind = args.ControlKind;
  481. msg.Args = state;
  482. DriveControlEventPublish( msg );
  483. }
  484. private void ReqMoveToPos( DriveControlEventArgs args )
  485. {
  486. //var result = drive.Move( args.PositionTag );
  487. //this.MoveTo( "1111" );
  488. var reply = new DriveControlEventArgs();
  489. int targetTag = args.TargetRouteID;
  490. var route = sql.RouteDal.GetK( targetTag );
  491. if ( route == null )
  492. {
  493. reply.Result = Results.Fail( "Not Found Route" );
  494. this.DriveControlEventPublish( reply );
  495. return;
  496. }
  497. this.MoveTo( route.Name );
  498. reply.Result = Results.Ok( "Position Move" );
  499. this.DriveControlEventPublish( reply );
  500. }
  501. void ReqFaultReset( DriveControlEventArgs _args )
  502. {
  503. var drive = 0;
  504. //var result = drive.ResetAmpFault();
  505. var msg = new DriveControlEventArgs
  506. {
  507. ControlKind = DriveControlEventArgs.eControlKind.FaultReset
  508. };
  509. msg.Result = Results.Ok( "Drive On" );
  510. this.DriveControlEventPublish( msg );
  511. }
  512. void ReqJog( DriveControlEventArgs _args )
  513. {
  514. var drive = string.Empty;
  515. if ( _args.JogDir == DriveControlEventArgs.eJogMoveDir.Positive )
  516. drive = "POSITIVE";
  517. else
  518. drive = "NEGATIVE";
  519. }
  520. void ReqCurrentPos()
  521. {
  522. var task = Task.Factory.StartNew( () =>
  523. {
  524. while ( !this.taskCancel.Canceled )
  525. {
  526. LockUtils.Wait( 500 );
  527. var msg = new DriveControlEventArgs
  528. {
  529. EventDir = DriveControlEventArgs.eEventDir.ToFront,
  530. ControlKind = DriveControlEventArgs.eControlKind.ReqCurrentPos,
  531. CurrentPosition = new Random().Next( 0, 1000 ),
  532. };
  533. this.DriveControlEventPublish( msg );
  534. }
  535. } );
  536. this.taskCancel.Add( task );
  537. }
  538. void ReqDriveOn( DriveControlEventArgs _args )
  539. {
  540. var drive = "Drive Name";
  541. //drive.On();
  542. var msg = new DriveControlEventArgs
  543. {
  544. ControlKind = DriveControlEventArgs.eControlKind.DriveON
  545. };
  546. msg.Result = Results.Ok( "Drive On" );
  547. this.DriveControlEventPublish( msg );
  548. }
  549. void ReqDriveOff( DriveControlEventArgs _args )
  550. {
  551. var drive = "Drive Name";
  552. //drive.Off();
  553. var msg = new DriveControlEventArgs
  554. {
  555. ControlKind = DriveControlEventArgs.eControlKind.DriveOFF
  556. };
  557. msg.Result = Results.Ok( "Drive On" );
  558. this.DriveControlEventPublish( msg );
  559. }
  560. #endregion
  561. #region Thread
  562. void ThreadStart()
  563. {
  564. this.cancel.AddGo( new Action( this._ThSubCmdWorker ) );
  565. this.cancel.AddGo( new Action( this._ThObstacleChecker ) );
  566. }
  567. //장애물 감지 Thread
  568. //장애물 감지 패턴 변경도 여기 하자.
  569. private void _ThObstacleChecker()
  570. {
  571. while ( !this.cancel.Canceled )
  572. {
  573. try
  574. {
  575. if ( this.autoManager.OperationModeProperty == eOperatationMode.AutoMode )
  576. this.CheckObstacle();
  577. this.CheckIOState();
  578. }
  579. catch ( ThreadInterruptedException threadInterruptedException )
  580. {
  581. }
  582. catch ( Exception exception )
  583. {
  584. logger.E( exception );
  585. }
  586. finally
  587. {
  588. LockUtils.Wait( 5 );
  589. }
  590. }
  591. logger.D( "Vehicle - _ThObstacleChecker Dispose" );
  592. }
  593. private void CheckIOState()
  594. {
  595. //이미 알람이면 체크 안함.
  596. if ( this.VehicleStateProperty == eVehicleState.Abnormal ) return;
  597. if ( this.iO.IsConnectError ) return;
  598. if ( this.iO.IsOn( "IN_EMS_SW" ) ) this.OccurVehicleAlarm( 28 );
  599. if ( !this.iO.IsOn( "IN_CP_ON_SAFETY" ) ) this.OccurVehicleAlarm( 31 );
  600. if ( !this.iO.IsOn( "IN_CP_ON_24V" ) ) this.OccurVehicleAlarm( 30 );
  601. if ( !this.iO.IsOn( "IN_MC_ON" ) ) this.OccurVehicleAlarm( 29 );
  602. }
  603. /// <summary>
  604. /// Scheduler 가 주는 Sub Command 를 이용하여 동작하자.
  605. /// </summary>
  606. public void _ThSubCmdWorker()
  607. {
  608. while ( !this.cancel.Canceled )
  609. {
  610. try
  611. {
  612. if ( this.ObstacleStateProperty != eObstacleState.Normal ) //장애물 감지 상태 시 조그 동작만 가능하게.
  613. continue;
  614. if ( this.autoManager.AutoModeStateProperty != eAutoModeState.Run ) //
  615. continue;
  616. var subCmd = sql.SubCmdDAL.GetSubCmd();
  617. if ( subCmd == null ) continue;
  618. if ( !sql.CommandDAL.All.Any( x => x.CommandID.Equals( subCmd.CmdID ) ) )
  619. {
  620. if ( subCmd.CmdType == SubCmd.eCmdType.Auto ) //자동 명령중 Main Command 가 없으면 삭제.
  621. {
  622. sql.SubCmdDAL.Delete( subCmd );
  623. logger.I( $"SubCmd Deleted - ID={subCmd.ID}, CommandID={subCmd.CmdID}" );
  624. }
  625. }
  626. switch ( subCmd.Type )
  627. {
  628. case eSubCommandType.Move:
  629. this.CurrentSubCommand = subCmd;
  630. this.Move( subCmd );
  631. break;
  632. case eSubCommandType.Load:
  633. this.CurrentSubCommand = subCmd;
  634. this.LoadCarrier( subCmd );
  635. break;
  636. case eSubCommandType.Unload:
  637. this.CurrentSubCommand = subCmd;
  638. this.UnloadCarrier( subCmd );
  639. break;
  640. case eSubCommandType.Charge:
  641. this.CurrentSubCommand = subCmd;
  642. this.BatteryCharge( subCmd );
  643. break;
  644. default:
  645. break;
  646. }
  647. }
  648. catch ( ThreadInterruptedException threadInterruptedException )
  649. {
  650. }
  651. catch ( Exception exception )
  652. {
  653. logger.E( exception );
  654. }
  655. finally
  656. {
  657. LockUtils.Wait( 500 );
  658. }
  659. }
  660. logger.D( "Vehicle - _ThSubCmdWorker Dispose" );
  661. }
  662. #endregion
  663. #region Control Action Method
  664. public void EStop()
  665. {
  666. OnOffConveyor( false );
  667. //Clamp EStop
  668. this.clamp.ClampEStop();
  669. this.motion.EStop();
  670. this.OccurVehicleAlarm( 23 );
  671. }
  672. #region For Moving
  673. void Move( SubCmd sub )
  674. {
  675. if ( this.MoveTo( sub.TargetID ) )
  676. {
  677. }
  678. sql.SubCmdDAL.Delete( sub );
  679. }
  680. bool MoveTo( string pointID )
  681. {
  682. //this.BuzzerOnOff(true, eBuzzerKind.StartWarn);
  683. ////TimerUtils.Once(3000, BuzzerOnOff, false, eBuzzerKind.StartWarn );
  684. //Thread.Sleep(3000);
  685. //this.BuzzerOnOff(false);
  686. if ( this.VehicleStateProperty == eVehicleState.Idle )
  687. {
  688. this.OnMoveReady?.Invoke();
  689. var moveReadyBuzzerTime = sql.ConfigDal.GetValueToInt( ConstString.BuzzerStartReadyTime );
  690. Thread.Sleep( moveReadyBuzzerTime );
  691. this.VehicleStateProperty = eVehicleState.Move;
  692. }
  693. this.OnMoving?.Invoke();
  694. this.IsMoving = true;
  695. //이전에 있던 작업들 종료 및 삭제
  696. this.taskMoveCancel.Cancel();
  697. this.taskMoveCancel.WaitAll();
  698. this.taskMoveCancel.Add( CheckCrossPoint() );
  699. //this.BuzzerOnOff(true, eBuzzerKind.Moving);
  700. this.motion.MoveToPoint( pointID, 100 );
  701. bool result = Wait4MoveDone();
  702. //this.BuzzerOnOff(false);
  703. this.taskMoveCancel.Cancel();
  704. this.taskMoveCancel.WaitAll();
  705. if ( motion.IsStop )
  706. {
  707. this.IsMoving = false;
  708. this.OnMoveFinish?.Invoke();
  709. this.VehicleStateProperty = eVehicleState.Idle;
  710. }
  711. return result;
  712. }
  713. bool Wait4MoveDone()
  714. {
  715. int waitTime = 9000; //설정 할 수있게.
  716. long st = SwUtils.CurrentTimeMillis;
  717. //Todo: 이동시 확인 사항들.
  718. while ( true )
  719. {
  720. Thread.Sleep( 5 );
  721. if ( SwUtils.Gt( st, waitTime ) )
  722. {
  723. //Todo: 이동시간 초과 시 동작들.
  724. break;
  725. }
  726. //Todo: 이동중 명령이 삭제 되면 처리 할일들.
  727. //이동중 메인 명력이 없어진다면 정지 후
  728. if ( !sql.CommandDAL.HasK( this.CurrentSubCommand.CmdID ) )
  729. {
  730. logger.D( "[Wait Move Done] - 메인 명령 사라짐" );
  731. var cmd = sql.CommandDAL.GetCmd();
  732. if ( cmd == null )
  733. {
  734. logger.D( "[Wait Move Done] - Main Command not Exist Motion Stop" );
  735. motion.Stop();
  736. return true;
  737. }
  738. else
  739. {
  740. logger.D( "[Wait Move Done] - Main Command not Exist Motion command 없음" );
  741. return true;
  742. }
  743. }
  744. //20.04.04 Kang Drive 측으로 상태만 알려주면 알아서 처리함.
  745. //if ( this.ObstacleStateProperty != eObstacleState.Normal )
  746. //{
  747. // if ( this.ObstacleStateProperty == eObstacleState.Blocked )
  748. // this.VehicleStateProperty = eVehicleState.Blocked;
  749. // if ( this.ObstacleStateProperty == eObstacleState.Abnormal )
  750. // {
  751. // this.VehicleStateProperty = eVehicleState.Abnormal;
  752. // this.OccurVehicleAlarm( 24 );
  753. // return false;
  754. // }
  755. //}
  756. }
  757. return true;
  758. }
  759. Task CheckCrossPoint()
  760. {
  761. var task = Task.Run( () =>
  762. {
  763. long sTime = SwUtils.CurrentTimeMillis;
  764. while ( !this.taskMoveCancel.Canceled )
  765. {
  766. Thread.Sleep( 10 );
  767. //ToDo: approach Cross Point Check
  768. //ToDo: Obstacle Laser Sensor Pattern Change Method 구현 필요.
  769. }
  770. } );
  771. return task;
  772. }
  773. #endregion
  774. public bool LoadCarrier( SubCmd sub )
  775. {
  776. this.VehicleStateProperty = eVehicleState.Load;
  777. var route = sql.RouteDal.GetRoute( sub.TargetID );
  778. if ( !CorrectPosition( route, this.CurrentPosition ) )
  779. {
  780. this.OccurVehicleAlarm( 20 );
  781. return false; //Alarm
  782. }
  783. int result = this.clamp.Unlock_Sync();
  784. if ( result != 0 )
  785. {
  786. this.OccurVehicleAlarm( result );
  787. return false;
  788. }
  789. this.iO.OutputOn( "OUT_PIO_SENSOR_ONOFF" );
  790. result = this.PIOAndLoad( sub.TargetID );
  791. if ( result != 0 )
  792. {
  793. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  794. this.OccurVehicleAlarm( result );
  795. return false;
  796. }
  797. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  798. result = this.clamp.Lock_Sync();
  799. if ( result != 0 )
  800. {
  801. this.OccurVehicleAlarm( result );
  802. return false;
  803. }
  804. //Load, Unload 가 끝나면 메인 Command 를 완료 했다고 판단.
  805. sql.CommandDAL.UpdateState( sub.CmdID, eCommandState.Complete );
  806. sql.SubCmdDAL.Delete( sub );
  807. this.VehicleStateProperty = eVehicleState.Idle;
  808. return true;
  809. }
  810. public bool UnloadCarrier( SubCmd sub )
  811. {
  812. this.VehicleStateProperty = eVehicleState.Unload;
  813. var route = sql.RouteDal.GetRoute( sub.TargetID );
  814. if ( !CorrectPosition( route, this.CurrentPosition ) )
  815. {
  816. this.OccurVehicleAlarm( 21 );
  817. return false; //Alarm
  818. }
  819. int result = this.clamp.Unlock_Sync();
  820. if ( result != 0 )
  821. {
  822. this.OccurVehicleAlarm( result );
  823. return false;
  824. }
  825. this.iO.OutputOn( "OUT_PIO_SENSOR_ONOFF" );
  826. result = this.PIOAndUnload( sub.TargetID );
  827. if ( result != 0 )
  828. {
  829. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  830. this.OccurVehicleAlarm( result );
  831. return false;
  832. }
  833. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  834. sql.CommandDAL.UpdateState( sub.CmdID, eCommandState.Complete );
  835. sql.SubCmdDAL.Delete( sub );
  836. this.VehicleStateProperty = eVehicleState.Idle;
  837. return true;
  838. }
  839. private void BatteryCharge( SubCmd subCmd )
  840. {
  841. this.VehicleStateProperty = eVehicleState.Charge;
  842. this.iO.OutputOn( "OUT_PIO_SENSOR_ONOFF" );
  843. this.PIOBatteryCharge( subCmd );
  844. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  845. sql.CommandDAL.UpdateState( subCmd.CmdID, eCommandState.Complete );
  846. sql.SubCmdDAL.Delete( subCmd );
  847. this.VehicleStateProperty = eVehicleState.Idle;
  848. }
  849. /// <summary>
  850. /// Battery Charge
  851. /// 충전 시 PIO 를 해야 함.
  852. /// </summary>
  853. /// <param name="sub"></param>
  854. /// <returns></returns>
  855. public int PIOBatteryCharge( SubCmd sub )
  856. {
  857. var route = sql.RouteDal.GetRoute( sub.TargetID );
  858. if ( !CorrectPosition( route, this.CurrentPosition ) )
  859. {
  860. this.OccurVehicleAlarm( 21 );
  861. return 0; //Alarm
  862. }
  863. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  864. PIOClear();
  865. loggerPIO.I( $"Start Charge PIO - [{sub.TargetID}]" );
  866. if ( !this.iO.IsOn( "IN_PIO_READY" ) )
  867. {
  868. loggerPIO.E( "[Port] - 1 Ready not On" );
  869. this.iO.OutputOff( "OUT_PIO_SENSOR_ONOFF" );
  870. this.OccurVehicleAlarm( 25 );
  871. return 0;
  872. }
  873. this.iO.WriteOutputIO( "OUT_PIO_READY", true );
  874. loggerPIO.I( "[Vehicle] - 1 Ready On" );
  875. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_RECEIVE_RUN" ) )
  876. {
  877. PIOClear();
  878. loggerPIO.E( "[Port] - 2 Receive CV Run Timeout" );
  879. this.OccurVehicleAlarm( 26 );
  880. return 0;
  881. }
  882. this.iO.WriteOutputIO( "OUT_PIO_SENDING_RUN", true );
  883. loggerPIO.I( "[Vehicle] - 2 Send Run On" );
  884. var sTime = SwUtils.CurrentTimeMillis;
  885. while ( true )
  886. {
  887. Thread.Sleep( 5 );
  888. if ( !this.iO.IsOn( "IN_PIO_READY" ) || this.iO.IsOn( "IN_PIO_RECEIVE_RUN" ) )
  889. break;
  890. if ( !sql.CommandDAL.HasK( this.CurrentSubCommand.CmdID ) )
  891. {
  892. PIOClear();
  893. logger.D( "[Wait Charging] - 메인 명령 사라짐" );
  894. break;
  895. }
  896. }
  897. if ( !this.iO.WaitChangeInputIO( true, pioTimeout, "IN_PIO_RECEIVE_COMPLITE" ) )
  898. {
  899. PIOClear();
  900. loggerPIO.E( "[Port] - 3 Receive Complete Timeout" );
  901. this.OccurVehicleAlarm( 26 );
  902. return 0;
  903. }
  904. PIOClear();
  905. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", true );
  906. Thread.Sleep( 1000 );
  907. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE", false );
  908. return 0;
  909. }
  910. #endregion
  911. #region Check Method
  912. bool CheckObstacle()
  913. {
  914. //if ( this.iO.IsOn( "IN_OBSTRUCTION_DETECT_SAFETY" ) || this.iO.IsOn( "IN_OBSTRUCTION_DETECT_ERROR" ) )
  915. //{
  916. // this.ObstacleStateProperty = eObstacleState.Abnormal;
  917. // this.motion.SetObstacleState( this.ObstacleStateProperty );
  918. // return true;
  919. //}
  920. //if ( this.iO.IsOn( "IN_OBSTRUCTION_DETECT_STOP" ) )
  921. //{
  922. // this.ObstacleStateProperty = eObstacleState.Blocked;
  923. // this.motion.SetObstacleState( this.ObstacleStateProperty );
  924. // return true;
  925. //}
  926. //if ( this.iO.IsOn( "IN_OBSTRUCTION_DETECT_SLOW" ) )
  927. //{
  928. // this.ObstacleStateProperty = eObstacleState.Decelerate;
  929. // this.motion.SetObstacleState( this.ObstacleStateProperty );
  930. // return true;
  931. //}
  932. this.ObstacleStateProperty = eObstacleState.Normal;
  933. this.motion.SetObstacleState( this.ObstacleStateProperty );
  934. return false;
  935. }
  936. #endregion
  937. #region Mechanical Method
  938. #region Conveyor
  939. /// <summary>
  940. /// (Run = true, CW = true CCW = false)
  941. /// </summary>
  942. /// <param name="isOn"></param>
  943. /// <param name="isLoad">bit On 시 Unload 방향 진행.</param>
  944. /// <returns></returns>
  945. int OnOffConveyor( bool isOn, bool isLoad = false )
  946. {
  947. if ( IsInverterError() )
  948. return 16;
  949. if ( isLoad )
  950. this.iO.OutputOn( "OUT_CV_CWCCW" );
  951. else
  952. this.iO.OutputOff( "OUT_CV_CWCCW" );
  953. if ( isOn )
  954. this.iO.OutputOn( "OUT_CV_RUN" );
  955. else
  956. this.iO.OutputOff( "OUT_CV_RUN" );
  957. return 0;
  958. }
  959. void SetConveyorSpeed( bool IsHight )
  960. {
  961. if ( IsHight )
  962. this.iO.WriteOutputIO( "OUT_CV_DA", true );
  963. else
  964. this.iO.WriteOutputIO( "OUT_CV_DA", false );
  965. }
  966. bool IsCvRun() => this.iO.IsOn( "OUT_CV_RUN" );
  967. bool IsCvCWCCW() => this.iO.IsOn( "OUT_CV_CWCCW" );
  968. /// <summary>
  969. /// 입구 감지 로딩시 감속 사용
  970. /// </summary>
  971. /// <returns></returns>
  972. bool IsDetectedLoadStart() => this.iO.IsOn( "IN_CV_DETECT_00" );
  973. /// <summary>
  974. /// 실물 감지
  975. /// </summary>
  976. /// <returns></returns>
  977. public bool IsDetectedCenter() => this.iO.IsOn( "IN_CV_DETECT_01" );
  978. bool IsDetectedLoadStop() => this.iO.IsOn( "IN_CV_DETECT_02" );
  979. bool IsInverterError() => !this.iO.IsOn( "IN_CV_ERROR" ); //Normal Close로 생각 됨.
  980. bool IsLifterPositinCheck() => this.iO.IsOn( "IN_LIFTER_POSITION_DETECT" );
  981. bool IsLifterDuplication() => this.iO.IsOn( "IN_LIFTER_DUPLICATION_DETECT" );
  982. bool IsPIOInterLockOn() => this.iO.IsOn( "OUT_PIO_INTERLOCK" );
  983. public int ConveyorLoad()
  984. {
  985. if ( IsDetectedCenter() )
  986. return 9;
  987. logger.D( "[Manual Load] - Conveyor On" );
  988. OnOffConveyor( true, true );
  989. bool isStartDetected = false;
  990. long sTime = SwUtils.CurrentTimeMillis;
  991. while ( true )
  992. {
  993. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) ) //Wait 20Sec
  994. {
  995. OnOffConveyor( false, true );
  996. return 10;
  997. }
  998. if ( this.IsDetectedLoadStart() && !isStartDetected )
  999. isStartDetected = true;
  1000. if ( !this.IsDetectedLoadStart() && isStartDetected )
  1001. {
  1002. this.SetConveyorSpeed( false );
  1003. logger.D( "[Manual Load] - Conveyor Slow State" );
  1004. }
  1005. if ( IsDetectedLoadStop() )
  1006. break;
  1007. }
  1008. OnOffConveyor( false );
  1009. logger.D( "[Manual Load] - Conveyor Off" );
  1010. return 0;
  1011. }
  1012. public int ConveyorUnload()
  1013. {
  1014. if ( !IsDetectedCenter() )
  1015. return 11;
  1016. logger.D( "[Manual Unload] - Conveyor On" );
  1017. OnOffConveyor( true, false );
  1018. long sTime = SwUtils.CurrentTimeMillis;
  1019. while ( true )
  1020. {
  1021. if ( SwUtils.Gt( sTime, 20 * ConstUtils.ONE_SECOND ) ) //Wait 20Sec
  1022. {
  1023. OnOffConveyor( false, false );
  1024. return 12;
  1025. }
  1026. if ( !IsDetectedLoadStart() && !IsDetectedCenter() )
  1027. break;
  1028. }
  1029. Thread.Sleep( 2000 );
  1030. OnOffConveyor( false );
  1031. logger.D( "[Manual Unload] - Conveyor Off" );
  1032. return 0;
  1033. }
  1034. public int PIOAndLoad( string targetName )
  1035. {
  1036. #if SIMULATION
  1037. PIOClear();
  1038. loggerPIO.I( $"Start Load PIO - [{targetName}]" );
  1039. this.OnPIOStart?.Invoke( true );
  1040. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN", true );
  1041. loggerPIO.I( "[Vehicle] - 4 Receive Run On" );
  1042. Thread.Sleep( 1000 );//상대 IO 기다린다 생각.
  1043. loggerPIO.E( "[Port] - 4 Ready On" );
  1044. //Conveyor Start
  1045. loggerPIO.I( "[Vehicle] - Conveyor Run" );
  1046. this.OnConveyorStart?.Invoke( true );
  1047. Thread.Sleep( 10000 );//Conveyor 구동
  1048. this.OnCarrierDetected?.Invoke( true );
  1049. PIOClear();
  1050. Thread.Sleep( 1000 );
  1051. this.OnConveyorStop?.Invoke( true );
  1052. Thread.Sleep( 1000 );
  1053. this.OnLoadComplete?.Invoke();
  1054. #else
  1055. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  1056. if ( this.IsInverterError() )
  1057. return 16;
  1058. if ( this.IsLifterPositinCheck() )
  1059. return 14;
  1060. if ( !this.IsLifterDuplication() )
  1061. {
  1062. this.OnFailReport?.Invoke( eFailCode.Load_PortHasNotCarrier );
  1063. return 0;
  1064. }
  1065. if ( this.IsDetectedCenter() )
  1066. {
  1067. this.OnFailReport?.Invoke( eFailCode.Load_VehicleHasCarrier );
  1068. return 0;
  1069. }
  1070. PIOClear();
  1071. loggerPIO.I( $"Start Load PIO - [{targetName}]" );
  1072. this.OnPIOStart?.Invoke( true );
  1073. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN" , true );
  1074. loggerPIO.I( "[Vehicle] - 4 Receive Run On" );
  1075. if ( !this.iO.WaitChangeInputIO( true , pioTimeout , "IN_PIO_SENDABLE" ) )
  1076. {
  1077. PIOClear();
  1078. loggerPIO.E( "[Port] - 4 Ready Time Out" );
  1079. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  1080. return 0;
  1081. }
  1082. loggerPIO.E( "[Port] - 4 Ready On" );
  1083. this.SetConveyorSpeed( true );
  1084. this.OnOffConveyor( true , true );
  1085. this.iO.WriteOutputIO( "OUT_PIO_RECEIVE_RUN" , true );
  1086. loggerPIO.I( "[Vehicle] - Conveyor Run" );
  1087. this.OnConveyorStart?.Invoke( true );
  1088. if ( !this.iO.WaitChangeInputIO( true , pioTimeout , "IN_PIO_SEND_RUN" ) )
  1089. {
  1090. this.OnOffConveyor( false , true );
  1091. PIOClear();
  1092. loggerPIO.E( "[Port] - 5 Sending Run Time Out" );
  1093. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  1094. return 0;
  1095. }
  1096. bool isStartDetected = false;
  1097. var sTime = SwUtils.CurrentTimeMillis;
  1098. while ( true )
  1099. {
  1100. if ( SwUtils.Gt( sTime , 20 * ConstUtils.ONE_SECOND ) )
  1101. {
  1102. PIOClear();
  1103. this.OnOffConveyor( false , true );
  1104. loggerPIO.E( "[Vehicle] Conveyor Wait Time Out" );
  1105. this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
  1106. if ( this.IsDetectedLoadStart() ) // 감지가 시작 되었으면 이동중 Error 로 판단 설비를 정지 상태로
  1107. return 10; //Conveyor Moving Timeout
  1108. else
  1109. return 0;
  1110. }
  1111. if ( this.IsDetectedLoadStart() && !isStartDetected )
  1112. isStartDetected = true;
  1113. if ( !this.IsDetectedLoadStart() && isStartDetected )
  1114. this.SetConveyorSpeed( false );
  1115. if ( this.IsDetectedLoadStop() ) break;
  1116. if ( this.IsPIOInterLockOn() )
  1117. {
  1118. PIOClear();
  1119. this.OnOffConveyor( false ); //Stop
  1120. loggerPIO.E( "[Port] PIO InterLock On " );
  1121. return 19; //
  1122. }
  1123. }
  1124. if ( this.IsDetectedCenter() )
  1125. this.OnCarrierDetected?.Invoke( true );
  1126. this.OnOffConveyor( false ); //Stop
  1127. PIOClear();
  1128. this.OnConveyorStop?.Invoke( true );
  1129. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE" , true );
  1130. this.iO.WriteOutputIO( "OUT_PIO_RECIVE_COMPLITE" , false , 1000 );
  1131. this.OnLoadComplete?.Invoke();
  1132. #endif
  1133. return 0;
  1134. }
  1135. public int PIOAndUnload( string targetName )
  1136. {
  1137. #if SIMULATION
  1138. PIOClear();
  1139. loggerPIO.I( $"Start Unload PIO - [{targetName}]" );
  1140. this.OnPIOStart?.Invoke( false );
  1141. Thread.Sleep( 1000 );
  1142. this.iO.WriteOutputIO( "OUT_PIO_READY", true );
  1143. loggerPIO.I( "[Vehicle] - 1 Ready On" );
  1144. Thread.Sleep( 1000 );
  1145. this.OnConveyorStart?.Invoke( false );
  1146. Thread.Sleep( 10000 );
  1147. this.OnOffConveyor( false ); //Stop
  1148. this.OnConveyorStop?.Invoke( false );
  1149. PIOClear();
  1150. Thread.Sleep( 1000 );
  1151. this.OnUnloadComplete?.Invoke();
  1152. #else
  1153. var pioTimeout = sql.ConfigDal.GetValueToInt( ConstString.PIOTimeOut );
  1154. if ( this.IsInverterError() )
  1155. return 16;
  1156. if ( this.IsLifterDuplication() )
  1157. {
  1158. this.OnFailReport?.Invoke( eFailCode.Unload_PortHasCarrier );
  1159. return 0;
  1160. }
  1161. if ( !this.IsDetectedCenter() )
  1162. {
  1163. this.OnFailReport?.Invoke( eFailCode.Unload_VehicleHasNotCarrier );
  1164. return 0;
  1165. }
  1166. if ( this.IsLifterPositinCheck() )
  1167. return 13;
  1168. PIOClear();
  1169. loggerPIO.I( $"Start Unload PIO - [{targetName}]" );
  1170. this.OnPIOStart?.Invoke( false );
  1171. if ( !this.iO.IsOn( "IN_PIO_READY" ) )
  1172. {
  1173. loggerPIO.E( "[Port] - 1 Ready not On" );
  1174. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  1175. return 0;
  1176. }
  1177. this.iO.WriteOutputIO( "OUT_PIO_READY" , true );
  1178. loggerPIO.I( "[Vehicle] - 1 Ready On" );
  1179. if ( !this.iO.WaitChangeInputIO( true , pioTimeout , "IN_PIO_RECEIVE_RUN" ) )
  1180. {
  1181. PIOClear();
  1182. loggerPIO.E( "[Port] - 2 Receive CV Run Timeout" );
  1183. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  1184. return 0;
  1185. }
  1186. this.iO.WriteOutputIO( "OUT_PIO_SENDING_RUN" , true );
  1187. loggerPIO.I( "[Vehicle] - 2 Send Run On" );
  1188. this.SetConveyorSpeed( true );
  1189. this.OnOffConveyor( true );
  1190. this.OnConveyorStart?.Invoke( false );
  1191. var sTime = SwUtils.CurrentTimeMillis;
  1192. while ( true )
  1193. {
  1194. if ( SwUtils.Gt( sTime , 20 * ConstUtils.ONE_SECOND ) )
  1195. {
  1196. PIOClear();
  1197. this.OnOffConveyor( false , true );
  1198. loggerPIO.E( "[Port] Conveyor Wait Time Out" );
  1199. this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
  1200. if ( IsDetectedLoadStart() || IsDetectedCenter() ) //중간에 걸려 있다고 생각해서 알람 처리.
  1201. return 12; //Conveyor Moving Timeout
  1202. else
  1203. return 0;
  1204. }
  1205. if ( this.iO.IsOn( "IN_PIO_RECEIVE_COMPLITE" ) )
  1206. break;
  1207. }
  1208. if ( !IsDetectedCenter() )
  1209. this.OnCarrierDetected?.Invoke( false );
  1210. this.OnOffConveyor( false ); //Stop
  1211. this.OnConveyorStop?.Invoke( false );
  1212. PIOClear();
  1213. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE" , true );
  1214. Thread.Sleep( 1000 );
  1215. this.iO.WriteOutputIO( "OUT_PIO_SEND_COMPLITE" , false );
  1216. this.OnUnloadComplete?.Invoke();
  1217. #endif
  1218. return 0;
  1219. }
  1220. void PIOClear()
  1221. {
  1222. 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" };
  1223. pio.FwEach( x => { this.iO.OutputOff( x ); } );
  1224. }
  1225. #endregion
  1226. #endregion
  1227. #region Hardware Create Method
  1228. void CreateSteering()
  1229. {
  1230. this.steering = new Steering( this.iO, this.sql, this.eventAggregator );
  1231. this.steering.OnSteeringError += Steering_OnSteeringError;
  1232. this.steering.PropertyChanged += Steering_PropertyChanged;
  1233. }
  1234. void CreateClamp()
  1235. {
  1236. this.clamp = new Clamp( this.sql, this.eventAggregator );
  1237. this.clamp.Init();
  1238. this.clamp.PropertyChanged += Clamp_PropertyChanged;
  1239. }
  1240. void CreateDrive()
  1241. {
  1242. this.motion = new GSIMotion( this.sql );
  1243. this.motion.PropertyChanged += Motion_PropertyChanged;
  1244. }
  1245. void CreateBMUManager()
  1246. {
  1247. this.bMUManager = new BMUManager();
  1248. this.bMUManager.BMUConfig = new Serial.BatteryTabos.Config() { ID = "0" };
  1249. this.bMUManager.OnConnect += BMUManager_OnConnect;
  1250. this.bMUManager.OnDisconnect += BMUManager_OnDisconnect;
  1251. this.bMUManager.OnChangedReceivedData += BMUManager_OnChangedReceivedData;
  1252. this.bMUManager.OnFirstColtd += BMUManager_OnFirstColtd;
  1253. this.bMUManager.Connect(BMUManager.eCANSelect.Advantech);
  1254. }
  1255. private void BMUManager_OnDisconnect( string obj, bool state )
  1256. {
  1257. this.BatteryIsConnect = state;
  1258. this.OccurVehicleAlarm( 32 );
  1259. }
  1260. private void BMUManager_OnConnect( string obj, bool state )
  1261. {
  1262. this.BatteryIsConnect = state;
  1263. }
  1264. private void BMUManager_OnFirstColtd( List<ReceivedData> obj )
  1265. {
  1266. }
  1267. private void BMUManager_OnChangedReceivedData( Serial.DataModel.ReceivedData obj )
  1268. {
  1269. var kind = CastTo<eDataKind>.From<Enum>( obj.DataKind );
  1270. switch ( kind )
  1271. {
  1272. case eDataKind.Voltage:
  1273. this.BatteryVoltage = (double)obj.Value * obj.Scale;
  1274. break;
  1275. case eDataKind.Current:
  1276. this.BatteryCurrent = (double)obj.Value * obj.Scale;
  1277. break;
  1278. case eDataKind.BatteryState:
  1279. if ( obj.Value == null )
  1280. return;
  1281. this.BatteryState = ( double )obj.Value;
  1282. break;
  1283. case eDataKind.ChargeCompleteTime:
  1284. if ( obj.Value == null || obj.Value <= 0 )
  1285. return;
  1286. this.BatteryChargeTime = (double)obj.Value / obj.Scale;
  1287. break;
  1288. case eDataKind.DisChargeCompleteTime:
  1289. if ( obj.Value == null || obj.Value <= 0 )
  1290. return;
  1291. this.BatteryDisChargeTime = ( double )obj.Value / obj.Scale;
  1292. break;
  1293. case eDataKind.SOC:
  1294. this.BatteryStateOfCharge = ( double )obj.Value * obj.Scale;
  1295. break;
  1296. case eDataKind.SOH:
  1297. this.BatteryStateOfHealth = ( double )obj.Value * obj.Scale;
  1298. break;
  1299. case eDataKind.ResidualCapacity:
  1300. this.BatteryCapacity = ( double )obj.Value * obj.Scale;
  1301. break;
  1302. case eDataKind.ResidualEnergy:
  1303. this.BatteryEnergy = ( double )obj.Value * obj.Scale;
  1304. break;
  1305. case eDataKind.Temperature:
  1306. this.BatteryTemperature = ( double )obj.Value * obj.Scale;
  1307. break;
  1308. default:
  1309. break;
  1310. }
  1311. }
  1312. #endregion
  1313. #region Help Method
  1314. /// <summary>
  1315. /// 현재 좌표 값이 등록된 Route 에 맞는 위치인지 확인한다.
  1316. /// 판단 기준은 Route 에 Tolerance 범위를 사용.
  1317. /// </summary>
  1318. /// <param name="route"></param>
  1319. /// <param name="currentPosition"></param>
  1320. /// <returns></returns>
  1321. bool CorrectPosition( Route route, double currentPosition )
  1322. {
  1323. var rScale = route.ScaleValue;
  1324. var rTolerance = route.ScaleTolerance;
  1325. var result = currentPosition - rScale;
  1326. if ( rTolerance < Math.Abs( result ) )
  1327. return false;
  1328. return true;
  1329. }
  1330. /// <summary>
  1331. /// if no is zero, Laser Off
  1332. /// bit Off, On, On, On,On Area1
  1333. /// </summary>
  1334. /// <param name="no"> 0 == Off Laser</param>
  1335. /// <returns></returns>
  1336. public bool ChgObstacleDetectPattern( int no )
  1337. {
  1338. var bitArray = BitUtils.ChgBitArray( no );
  1339. int bitIndex = 0;
  1340. this.obstacleBitList.ForEach( b =>
  1341. {
  1342. if ( bitArray[bitIndex] )
  1343. this.iO.OutputOff( b );
  1344. else
  1345. this.iO.OutputOn( b );
  1346. bitIndex++;
  1347. } );
  1348. ObstaclePattern = no;
  1349. return true;
  1350. }
  1351. public int GetObstacleDetectPattern()
  1352. {
  1353. int bitIndex = 0;
  1354. BitArray bitArray = new BitArray( this.obstacleBitList.Count );
  1355. this.obstacleBitList.ForEach( b =>
  1356. {
  1357. if ( this.iO.IsOn( b, false ) )
  1358. bitArray.Set( bitIndex, false );
  1359. else
  1360. bitArray.Set( bitIndex, true );
  1361. bitIndex++;
  1362. } );
  1363. return BitUtils.ChgInt32( bitArray );
  1364. }
  1365. void OccurVehicleAlarm( int alarmID )
  1366. {
  1367. this.MachineMode = eMachineMode.LocalMode;
  1368. this.VehicleStateProperty = eVehicleState.Abnormal;
  1369. this.autoManager.ProcessAlarm( alarmID );
  1370. }
  1371. public void SetObstaclePattern( ObstacleControlEventArgs.eControlKind state, int value )
  1372. {
  1373. if ( state == ObstacleControlEventArgs.eControlKind.DRIVE )
  1374. {
  1375. this.ObstacleDrive = value;
  1376. ChgObstacleDetectPattern( this.ObstacleDrive );
  1377. }
  1378. else if ( state == ObstacleControlEventArgs.eControlKind.CURVE )
  1379. {
  1380. this.ObstacleCurve = value;
  1381. ChgObstacleDetectPattern( this.ObstacleCurve );
  1382. }
  1383. else
  1384. return;
  1385. }
  1386. #endregion
  1387. #region Event Subscribe
  1388. private void Motion_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e )
  1389. {
  1390. var property = sender.GetType().GetProperty( e.PropertyName );
  1391. var newValue = property.GetValue( sender, null );
  1392. if ( e.PropertyName.Equals( "CurrentPos" ) )
  1393. {
  1394. var v = CastTo<double>.From<object>( newValue );
  1395. this.CurrentPosition = v;
  1396. }
  1397. if ( e.PropertyName.Equals( "CurrentTag" ) )
  1398. {
  1399. var v = CastTo<string>.From<object>( newValue );
  1400. this.CurrentTag = v;
  1401. }
  1402. if ( e.PropertyName.Equals( "CurrentSpeed" ) )
  1403. {
  1404. var v = CastTo<double>.From<object>( newValue );
  1405. this.CurrentSpeed = v;
  1406. }
  1407. if ( e.PropertyName.Equals( "CurrentTorque" ) )
  1408. {
  1409. var v = CastTo<double>.From<object>( newValue );
  1410. this.CurrentTorque = v;
  1411. }
  1412. }
  1413. private void Steering_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e )
  1414. {
  1415. var property = sender.GetType().GetProperty( e.PropertyName );
  1416. var newValue = property.GetValue( sender, null );
  1417. //Todo: 나중에 Test 하자
  1418. //var ownPropperty = this.GetType().GetProperty(e.PropertyName);
  1419. if ( e.PropertyName.Equals( "SteeringState" ) )
  1420. {
  1421. var v = CastTo<eSteeringState>.From<object>( newValue );
  1422. this.SteeringState = v;
  1423. }
  1424. }
  1425. private void Clamp_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e )
  1426. {
  1427. var property = sender.GetType().GetProperty( e.PropertyName );
  1428. var newValue = property.GetValue( sender, null );
  1429. if ( e.PropertyName.Equals( "ClampState" ) )
  1430. {
  1431. var v = CastTo<eClampState>.From<object>( newValue );
  1432. this.ClampState = v;
  1433. }
  1434. }
  1435. private void IO_OnChangedIO( BitBlock bit )
  1436. {
  1437. if ( bit.Tag.Equals( "IN_CV_DETECT_01" ) )
  1438. {
  1439. this.IsContain = bit.IsBitOn;
  1440. }
  1441. }
  1442. private void Steering_OnSteeringError( object sender, int e )
  1443. {
  1444. if ( e != 0 )
  1445. {
  1446. logger.E( $"[Steering] - Control Error {e}" );
  1447. this.OccurVehicleAlarm( e ) ;
  1448. }
  1449. else
  1450. {
  1451. var msg = new DriveControlEventArgs()
  1452. {
  1453. EventDir = DriveControlEventArgs.eEventDir.ToFront,
  1454. ControlKind = DriveControlEventArgs.eControlKind.Steering,
  1455. Result = FluentResults.Results.Ok<DriveControlEventArgs.eMoveDir>( DriveControlEventArgs.eMoveDir.LEFT ),
  1456. };
  1457. this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish( msg );
  1458. }
  1459. }
  1460. #endregion
  1461. }
  1462. }