Vehicle.cs 59 KB

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