Vehicle.cs 57 KB

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