JetAxisBase.cs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Device;
  3. using Aitex.Core.RT.Event;
  4. using Aitex.Core.RT.Log;
  5. using Aitex.Core.RT.OperationCenter;
  6. using Aitex.Core.RT.Routine;
  7. using Aitex.Core.RT.SCCore;
  8. using Aitex.Core.Util;
  9. using MECF.Framework.Common.Beckhoff.AxisProvider;
  10. using MECF.Framework.Common.Beckhoff.IOAxis;
  11. using MECF.Framework.Common.Beckhoff.Station;
  12. using MECF.Framework.Common.CommonData.PUF;
  13. using MECF.Framework.Common.TwinCat;
  14. using MECF.Framework.Common.Utilities;
  15. using CyberX8_Core;
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Reflection;
  20. using System.Text;
  21. using System.Threading;
  22. using System.Threading.Tasks;
  23. using System.Timers;
  24. using CommunityToolkit.HighPerformance.Buffers;
  25. using System.Windows.Documents;
  26. namespace CyberX8_RT.Devices.AXIS
  27. {
  28. public abstract class JetAxisBase : BaseDevice, IDevice
  29. {
  30. #region 常量
  31. private const string STATUS_WORD = "StatusWord";
  32. private const string DIGITAL_INPUTS="DigitalInputs";
  33. private const string CONTROL_WORD = "ControlWord";
  34. private const string MODE_OF_OPERATION = "ModeOfOperation";
  35. protected const string PROFILE_VELOCITY = "ProfileVelocity";
  36. protected const string PROFILE_ACCEL = "ProfileAccel";
  37. protected const string PROFILE_DECEL = "ProfileDecel";
  38. private const string TARGET_POSITION = "TargetPosition";
  39. private const string MOTOR_POSITION = "MotorPosition";
  40. private const string ACTUAL_VELOCITY = "ActualVelocity";
  41. private const string ACTUAL_TORQUE = "ActualTorque";
  42. private const string POSITION_ERROR = "PositionError";
  43. private const string MOTION_DATA = "MotionData";
  44. private const string CURRENT_STATION = "CurrentStation";
  45. protected const string CURRENT_STATION_LIST = "CurrentStationList";
  46. private const string IS_SWITCH_ON = "IsSwitchOn";
  47. private const string HOME_OFFSET = "HomeOffset";
  48. private const string HOMING_METHOD = "HomingMethod";
  49. protected const string HOMING_VELOCITY = "HomingVelocity";
  50. protected const string HOMING_VELOCITY_SLOW = "HomingVelocitySlow";
  51. protected const string HOMING_ACCEL = "HomingAccel";
  52. private const string NEGATIVE_TORQUE_LIMIT="NegativeTorqueLimit";
  53. private const string POSITIVE_TORQUE_LIMIT = "PositiveTorqueLimit";
  54. private const string MANUF_STATUS="ManufStatus";
  55. private const string SOFTWARE_LIMIT_MINUS= "SoftwareLimitMinus";
  56. private const string SOFTWARE_LIMIT_PLUS = "SoftwareLimitPlus";
  57. #endregion
  58. #region 内部变量
  59. /// <summary>
  60. /// 比例因子
  61. /// </summary>
  62. private double _scaleFactor = 0;
  63. /// <summary>
  64. /// jog限制
  65. /// </summary>
  66. private double _jogLimit = 0;
  67. /// <summary>
  68. /// 当前位置数值(用于判定是否正在运动)
  69. /// </summary>
  70. private int _currentLocation = 0;
  71. /// <summary>
  72. /// 是否运动
  73. /// </summary>
  74. private bool _isRun = false;
  75. /// <summary>
  76. /// 当前位置
  77. /// </summary>
  78. private string _currentStation = "";
  79. /// <summary>
  80. /// 当前位置集合(多个位置共用一个数值)
  81. /// </summary>
  82. private List<string> _currentStationList = new List<string>();
  83. /// <summary>
  84. /// 当前位置锁
  85. /// </summary>
  86. private object _locationLocker = new object();
  87. /// <summary>
  88. /// 工位位置对象
  89. /// </summary>
  90. private BeckhoffStationAxis _stationAxis;
  91. /// <summary>
  92. /// 运动时间
  93. /// </summary>
  94. private DateTime _runTime = DateTime.Now;
  95. /// <summary>
  96. /// 尺寸
  97. /// </summary>
  98. private int _waferSize = 0;
  99. /// <summary>
  100. /// inter lock
  101. /// </summary>
  102. private IAxisInterLock _interLock;
  103. /// <summary>
  104. /// 是否存在Rev Sensor Limit
  105. /// </summary>
  106. private bool _isRevSensorLimit = false;
  107. /// <summary>
  108. /// 是否存在Forward Limit
  109. /// </summary>
  110. private bool _isForwardSensorLimit = false;
  111. /// <summary>
  112. /// Home Switched是否触发
  113. /// </summary>
  114. private bool _isHomeSwitchedTrigger = false;
  115. /// <summary>
  116. /// 变量是否初始化字典
  117. /// </summary>
  118. private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
  119. #endregion
  120. #region protected 字段
  121. /// <summary>
  122. /// 轴参数对象
  123. /// </summary>
  124. protected BeckhoffAxis _beckhoffAxis = null;
  125. /// <summary>
  126. /// 状态
  127. /// </summary>
  128. protected RState _status;
  129. /// <summary>
  130. /// 当前操作
  131. /// </summary>
  132. protected MotionOperation _currentOperation = MotionOperation.None;
  133. /// <summary>
  134. /// 模式
  135. /// </summary>
  136. protected byte _modeOfOperation;
  137. /// <summary>
  138. /// 状态字
  139. /// </summary>
  140. protected ushort _statusWord;
  141. /// <summary>
  142. /// 控制字
  143. /// </summary>
  144. protected ushort _controlWord;
  145. /// <summary>
  146. /// 运动数据对象
  147. /// </summary>
  148. protected CommandMotionData _commandMotionData = new CommandMotionData();
  149. /// <summary>
  150. /// Home状态
  151. /// </summary>
  152. protected bool _isHomed;
  153. /// <summary>
  154. /// SwitchOn状态
  155. /// </summary>
  156. protected bool _isSwitchOn;
  157. /// <summary>
  158. /// 是否错误
  159. /// </summary>
  160. protected bool _isError;
  161. /// <summary>
  162. /// 是否到达目标位置
  163. /// </summary>
  164. protected bool _inTargetPosition = false;
  165. /// <summary>
  166. /// 初始化的速度
  167. /// </summary>
  168. protected int _initialVelocity = 0;
  169. /// <summary>
  170. /// 初始化的加速度
  171. /// </summary>
  172. protected int _initialAcceleration = 0;
  173. /// <summary>
  174. /// 初始化的减速度
  175. /// </summary>
  176. protected int _initialDeceleration = 0;
  177. /// <summary>
  178. /// 运动速度
  179. /// </summary>
  180. protected int _profileVelocity = 0;
  181. /// <summary>
  182. /// 运动加速度
  183. /// </summary>
  184. protected int _profileAcceleration = 0;
  185. /// <summary>
  186. /// 运动减速度
  187. /// </summary>
  188. protected int _profileDeceleration = 0;
  189. /// <summary>
  190. /// 负向Torque限制
  191. /// </summary>
  192. protected int _profileNegativeTorqueLimit = 0;
  193. /// <summary>
  194. /// 正向Torque限制
  195. /// </summary>
  196. protected int _profilePositiveTorqueLimit = 0;
  197. /// <summary>
  198. /// Homing 速度
  199. /// </summary>
  200. protected int _profileHomingVelocity = 0;
  201. /// <summary>
  202. /// Homing 速度Slow
  203. /// </summary>
  204. protected int _profileHomingVelocitySlow = 0;
  205. /// <summary>
  206. /// Homing加速度
  207. /// </summary>
  208. protected int _profileHomingAccel = 0;
  209. /// <summary>
  210. /// coe连接状态
  211. /// </summary>
  212. protected bool _coeConnected=false;
  213. /// <summary>
  214. /// 目标位置
  215. /// </summary>
  216. protected double _targetPosition = 0.0;
  217. /// <summary>
  218. /// home超时时长
  219. /// </summary>
  220. protected int _homeTimeout = 5000;
  221. /// <summary>
  222. /// coe输出变量集合
  223. /// </summary>
  224. protected List<string> _coeOutputs = new List<string>();
  225. /// <summary>
  226. /// 速度比例
  227. /// </summary>
  228. protected int _speedRatio = 1;
  229. /// <summary>
  230. /// 加速度的比例
  231. /// </summary>
  232. protected int _accelerationRatio = 1;
  233. /// <summary>
  234. /// torque比例
  235. /// </summary>
  236. protected int _torqueRatio = 1000;
  237. #endregion
  238. #region 属性
  239. /// <summary>
  240. /// 状态
  241. /// </summary>
  242. public RState Status { get { return _status; } }
  243. /// <summary>
  244. /// Home状态
  245. /// </summary>
  246. public bool IsHomed { get { return _isHomed; } set { _isHomed = value; } }
  247. /// <summary>
  248. /// SwitchOn状态
  249. /// </summary>
  250. public bool IsSwitchOn { get { return _isSwitchOn; } }
  251. /// <summary>
  252. /// 模式
  253. /// </summary>
  254. public byte ModeOfOperation { get { return _modeOfOperation; } }
  255. /// <summary>
  256. /// 控制字
  257. /// </summary>
  258. public ushort ControlWord { get { return _controlWord; } }
  259. /// <summary>
  260. /// 是否运动中
  261. /// </summary>
  262. public bool IsRun { get { return _isRun; } }
  263. /// <summary>
  264. /// 当前位置
  265. /// </summary>
  266. public string CurrentStation { get { return _currentStation; } }
  267. /// <summary>
  268. /// 是否到达目标位置
  269. /// </summary>
  270. public bool InTargetPosition { get { return _inTargetPosition; } }
  271. /// <summary>
  272. /// 运动数据对象
  273. /// </summary>
  274. public CommandMotionData MotionData { get { return _commandMotionData; } }
  275. /// <summary>
  276. /// 负向Torque限制数值
  277. /// </summary>
  278. public int NegativeTorqueLimit { get { return _profileNegativeTorqueLimit; } }
  279. /// <summary>
  280. /// 正向Torque限制数值
  281. /// </summary>
  282. public int PositiveTorqueLimit { get { return _profilePositiveTorqueLimit; } }
  283. /// <summary>
  284. /// 是否错误
  285. /// </summary>
  286. public bool IsError { get { return _isError; } }
  287. /// <summary>
  288. /// 目标位置
  289. /// </summary>
  290. public double TargetPosition { get { return _targetPosition; } }
  291. /// <summary>
  292. /// 加速度
  293. /// </summary>
  294. public double ProfileAcceleration { get { return _profileAcceleration; } }
  295. /// <summary>
  296. /// 减速度
  297. /// </summary>
  298. public double ProfileDeceleration { get { return _profileDeceleration; } }
  299. /// <summary>
  300. /// inter lock接口对象
  301. /// </summary>
  302. public IAxisInterLock InterLock { set { _interLock= value; } }
  303. /// <summary>
  304. /// 是否存在Sensor Limit
  305. /// </summary>
  306. public bool IsRevSensorLimit { set { _isRevSensorLimit = value; } }
  307. /// <summary>
  308. /// 是否存在正向Sensor Limit
  309. /// </summary>
  310. public bool IsForwardSensorLimit { set { _isForwardSensorLimit = value; } }
  311. /// <summary>
  312. /// Home Switch是否触发
  313. /// </summary>
  314. public bool IsHomeSwitchedTriggered { get { return _isHomeSwitchedTrigger; } set { _isHomeSwitchedTrigger = value; } }
  315. /// <summary>
  316. /// 所有io变量是否初始化
  317. /// </summary>
  318. public bool IOInitialized { get { return AllIoVariableInitialized(); } }
  319. /// <summary>
  320. /// COE连接成功
  321. /// </summary>
  322. public bool CoeConnected { get { return _coeConnected; } }
  323. #endregion
  324. /// <summary>
  325. /// 构造函数
  326. /// </summary>
  327. /// <param name="moduleName"></param>
  328. /// <param name="name"></param>
  329. public JetAxisBase(string moduleName,string name) : base(moduleName, name,name,name)
  330. {
  331. InitializeParameter();
  332. LoadStation();
  333. InitializeRoutine();
  334. SubscribeData();
  335. InitializeOperation();
  336. }
  337. #region private方法
  338. /// <summary>
  339. /// 加载Station位置
  340. /// </summary>
  341. private void LoadStation()
  342. {
  343. _waferSize = SC.GetValue<int>("System.WaferSize");
  344. _stationAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(Module, Name, _waferSize);
  345. }
  346. /// <summary>
  347. /// 订阅数据
  348. /// </summary>
  349. private void SubscribeData()
  350. {
  351. BeckhoffProviderAxis beckhoffProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.{Name}");
  352. if (beckhoffProviderAxis != null)
  353. {
  354. _scaleFactor = beckhoffProviderAxis.ScaleFactor;
  355. _jogLimit = beckhoffProviderAxis.JogLimit;
  356. }
  357. _beckhoffAxis = BeckhoffAxisManager.Instance.GetAxis($"{Module}.{Name}");
  358. if (_beckhoffAxis != null)
  359. {
  360. _profileVelocity =CalculateMultiplySpeedRatio(_beckhoffAxis.Speed);
  361. _initialVelocity = _profileVelocity;
  362. _profileAcceleration = CalculateDivideAccelerationRatio(_beckhoffAxis.Acceleration);
  363. _initialAcceleration = _profileAcceleration;
  364. _profileDeceleration = CalculateDivideAccelerationRatio(_beckhoffAxis.Deceleration);
  365. _initialDeceleration = _profileDeceleration;
  366. _profileNegativeTorqueLimit = _beckhoffAxis.NegativeTorqueLimit;
  367. _profilePositiveTorqueLimit = _beckhoffAxis.PositiveTorqueLimit;
  368. _commandMotionData.FileAcceleration = CalculateValueAfterScale(_beckhoffAxis.Acceleration);
  369. _commandMotionData.FileDeceleration = CalculateValueAfterScale(_beckhoffAxis.Deceleration);
  370. _commandMotionData.HomeOffset = CalculateValueAfterScale(_beckhoffAxis.HomingOffset);
  371. _commandMotionData.FileHomingAccel = CalculateValueAfterScale(_beckhoffAxis.HomingAccelDecel);
  372. _commandMotionData.FileHomingVelocitySlow = CalculateValueAfterScale(_beckhoffAxis.HomingSpeedEncoderIndex);
  373. _commandMotionData.FileHomingVelocity = CalculateValueAfterScale(_beckhoffAxis.HomingSpeedHomeSwitch);
  374. _commandMotionData.FileProfileVelocity = CalculateValueAfterScale(_beckhoffAxis.Speed);
  375. _commandMotionData.FwdSoftLimit = CalculateValueAfterScale(_beckhoffAxis.ForwardSoftwareLimit)-_commandMotionData.HomeOffset;
  376. _commandMotionData.RevSoftLimit = CalculateValueAfterScale(_beckhoffAxis.ReverseSoftwareLimit)-_commandMotionData.HomeOffset;
  377. _commandMotionData.PositionErrorLimit = CalculateValueAfterScale(_beckhoffAxis.ErrorLimit);
  378. _commandMotionData.NegativeTorqueLimit = _beckhoffAxis.NegativeTorqueLimit;
  379. _commandMotionData.PositiveTorqueLimit = _beckhoffAxis.PositiveTorqueLimit;
  380. if (_beckhoffAxis.NegativeTorqueLimit != 0 || _beckhoffAxis.PositiveTorqueLimit != 0)
  381. {
  382. _commandMotionData.TorqueLimit = $"-{_beckhoffAxis.NegativeTorqueLimit}/+{_beckhoffAxis.PositiveTorqueLimit}";
  383. }
  384. if(_beckhoffAxis.HomingTimeOut!=0)
  385. {
  386. _homeTimeout = _beckhoffAxis.HomingTimeOut;
  387. }
  388. }
  389. InitializeCoeOutputs();
  390. DATA.Subscribe($"{Module}.{Name}.{MOTION_DATA}", () => _commandMotionData,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  391. DATA.Subscribe($"{Module}.{Name}.{MOTOR_POSITION}", () => _commandMotionData.MotorPosition,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  392. DATA.Subscribe($"{Module}.{Name}.ProfileVelocity", () => _commandMotionData.ProfileVelocity, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  393. DATA.Subscribe($"{Module}.{Name}.Acceleration",()=>_commandMotionData.FileAcceleration,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  394. DATA.Subscribe($"{Module}.{Name}.Deceleration",()=>_commandMotionData.FileDeceleration,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  395. DATA.Subscribe($"{Module}.{Name}.ActualTorque",()=>_commandMotionData.ActualTorque,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  396. DATA.Subscribe($"{Module}.{Name}.{CURRENT_STATION}", () => _currentStation,SubscriptionAttribute.FLAG.IgnoreSaveDB);
  397. DATA.Subscribe($"{Module}.{Name}.{CURRENT_STATION_LIST}", () => _currentStationList, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  398. DATA.Subscribe($"{Module}.{Name}.{IS_SWITCH_ON}", () => IsSwitchOn, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  399. DATA.Subscribe($"{Module}.{Name}.IsHomed", () => IsHomed, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  400. DATA.Subscribe($"{Module}.{Name}.IsError",()=>IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  401. DATA.Subscribe($"{Module}.{Name}.IsMoving", () => _isRun, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  402. DATA.Subscribe($"{Module}.{Name}.IsRun", () => _isRun, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  403. }
  404. /// <summary>
  405. /// 初始化COE输出变量集合
  406. /// </summary>
  407. private void InitializeCoeOutputs()
  408. {
  409. if(_beckhoffAxis!=null)
  410. {
  411. foreach(BeckhoffAxisOutput item in _beckhoffAxis.Outputs)
  412. {
  413. if(!_coeOutputs.Contains(item.Type)&&item.Address.StartsWith("0x"))
  414. {
  415. _coeOutputs.Add(item.Type);
  416. }
  417. }
  418. }
  419. }
  420. /// <summary>
  421. /// 初始化操作
  422. /// </summary>
  423. private void InitializeOperation()
  424. {
  425. OP.Subscribe($"{Module}.{Name}.{MotionOperation.SwitchOn}", (cmd, args) => { SwitchOn(); return true; });
  426. OP.Subscribe($"{Module}.{Name}.{MotionOperation.SwitchOff}", (cmd, args) => { SwitchOff(); return true; });
  427. OP.Subscribe($"{Module}.{Name}.{MotionOperation.Home}", (cmd, args) => { Home(); return true; });
  428. OP.Subscribe($"{Module}.{Name}.JogUp", JogUpPosition);
  429. OP.Subscribe($"{Module}.{Name}.JogDown", JogDownPosition);
  430. OP.Subscribe($"{Module}.{Name}.{MotionOperation.KeyDown}", KeyDownOperation);
  431. OP.Subscribe($"{Module}.{Name}.{MotionOperation.Stop}",(cmd,args)=> { return StopPositionOperation(); });
  432. OP.Subscribe($"{Module}.{Name}.{MotionOperation.Save}", SaveOperation);
  433. OP.Subscribe($"{Module}.{Name}.GotoSavedPosition", (cmd, args) => {
  434. return PositionStation(args[1].ToString()); });
  435. }
  436. /// <summary>
  437. /// 保存操作
  438. /// </summary>
  439. /// <param name="cmd"></param>
  440. /// <param name="args"></param>
  441. /// <returns></returns>
  442. public bool SaveOperation(string cmd, object[] args)
  443. {
  444. if (args.Length >= 2)
  445. {
  446. string key = args[0].ToString();
  447. double paramValue = double.Parse(args[1].ToString());
  448. BeckhoffStationLocationManager.Instance.SaveMotionPosition(key, paramValue);
  449. lock (_locationLocker)
  450. {
  451. List<string> lst = new List<string>();
  452. foreach (Station item in _stationAxis.Stations)
  453. {
  454. if (item.Name == key)
  455. {
  456. item.Position = paramValue.ToString();
  457. _currentStation = item.Name;
  458. if (!lst.Contains(item.Name))
  459. {
  460. lst.Add(item.Name);
  461. }
  462. }
  463. }
  464. _currentStationList.Clear();
  465. if (lst.Count != 0)
  466. {
  467. _currentStationList.AddRange(lst);
  468. }
  469. }
  470. LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", "save success");
  471. }
  472. return true;
  473. }
  474. /// <summary>
  475. /// 计算所处当前工位
  476. /// </summary>
  477. private void CalculateCurrentStation(double motor)
  478. {
  479. lock (_locationLocker)
  480. {
  481. List<string> tmp = _currentStationList.ToList();
  482. List<string> lst = new List<string>();
  483. foreach (Station station in _stationAxis.Stations)
  484. {
  485. if (double.TryParse(station.Position, out double value))
  486. {
  487. if (Math.Round(Math.Abs(motor - value),2) <= _stationAxis.ToleranceDefault)
  488. {
  489. _currentStation = station.Name;
  490. if (!lst.Contains(station.Name))
  491. {
  492. lst.Add(station.Name);
  493. }
  494. }
  495. }
  496. }
  497. _currentStationList.Clear();
  498. if (lst.Count != 0)
  499. {
  500. string str = string.Join(",", tmp);
  501. _currentStationList.AddRange(lst);
  502. string strLst = string.Join(",", _currentStationList);
  503. if (str != strLst)
  504. {
  505. LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", $"position {motor} current {strLst}");
  506. }
  507. }
  508. else
  509. {
  510. _currentStation = "";
  511. }
  512. if (tmp.Count != 0&&_currentStationList.Count==0)
  513. {
  514. LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", $"position {motor} current is empty");
  515. }
  516. }
  517. }
  518. /// <summary>
  519. /// 文本框回车操作
  520. /// </summary>
  521. /// <param name="cmd"></param>
  522. /// <param name="args"></param>
  523. /// <returns></returns>
  524. private bool KeyDownOperation(string cmd, object[] args)
  525. {
  526. if (args.Length < 2)
  527. {
  528. return false;
  529. }
  530. if (double.TryParse(args[1].ToString(), out double value))
  531. {
  532. AxisKeyDown(args[0].ToString(), value);
  533. }
  534. else
  535. {
  536. EV.PostWarningLog($"{Module}.{Name}", eEvent.ERR_AXIS, $"{args[0]} value {args[1]}is not int value");
  537. }
  538. return true;
  539. }
  540. /// <summary>
  541. /// 是否所有IO变量初始化完成
  542. /// </summary>
  543. /// <returns></returns>
  544. private bool AllIoVariableInitialized()
  545. {
  546. foreach (string item in _variableInitializeDic.Keys)
  547. {
  548. if (!_variableInitializeDic[item])
  549. {
  550. LOG.WriteLog(eEvent.ERR_DRYER, Module, $"{item} is not initialized");
  551. return false;
  552. }
  553. }
  554. return true;
  555. }
  556. /// <summary>
  557. /// 启动写COE变量数值
  558. /// </summary>
  559. private void StartUpWriteCoeVariable()
  560. {
  561. LOG.WriteLog(eEvent.INFO_AXIS, Module, "start write coe thread");
  562. byte homingMethod = _beckhoffAxis.HomingMethod;
  563. WriteCoeVariable(HOMING_METHOD, homingMethod);
  564. //homing accel
  565. WriteCoeVariable(HOMING_ACCEL, CalculateDivideAccelerationRatio(_beckhoffAxis.HomingAccelDecel));
  566. //homing speed home switch
  567. WriteCoeVariable(HOMING_VELOCITY,CalculateMultiplySpeedRatio(_beckhoffAxis.HomingSpeedHomeSwitch));
  568. WriteCoeVariable(HOMING_VELOCITY_SLOW,CalculateMultiplySpeedRatio(_beckhoffAxis.HomingSpeedEncoderIndex));
  569. WriteCoeVariable(HOME_OFFSET, _beckhoffAxis.HomingOffset);
  570. int negativeTorqueLimit = _beckhoffAxis.NegativeTorqueLimit;
  571. if (negativeTorqueLimit != 0)
  572. {
  573. WriteCoeVariable(NEGATIVE_TORQUE_LIMIT, negativeTorqueLimit);
  574. }
  575. int positiveTorqueLimit = _beckhoffAxis.PositiveTorqueLimit;
  576. if (positiveTorqueLimit != 0)
  577. {
  578. WriteCoeVariable(POSITIVE_TORQUE_LIMIT, positiveTorqueLimit);
  579. }
  580. int softwareForwardLimit = _beckhoffAxis.ForwardSoftwareLimit;
  581. if (softwareForwardLimit != 0)
  582. {
  583. WriteCoeVariable(SOFTWARE_LIMIT_PLUS, softwareForwardLimit);
  584. }
  585. int softReverseLimit = _beckhoffAxis.ReverseSoftwareLimit;
  586. if (softReverseLimit != 0)
  587. {
  588. WriteCoeVariable(SOFTWARE_LIMIT_MINUS, softReverseLimit);
  589. }
  590. //WriteCoeVariable(PROFILE_VELOCITY,CalculateMultiplySpeedRatio(_beckhoffAxis.Speed));
  591. //WriteCoeVariable(PROFILE_ACCEL, CalculateDivideAccelerationRatio(_beckhoffAxis.Acceleration));
  592. //WriteCoeVariable(PROFILE_DECEL,CalculateDivideAccelerationRatio(_beckhoffAxis.Deceleration));
  593. }
  594. /// <summary>
  595. /// 写COE变量数值
  596. /// </summary>
  597. /// <param name="variableName"></param>
  598. /// <param name="value"></param>
  599. private void WriteCoeVariable(string variableName,object value)
  600. {
  601. string str = $"{Module}.{Name}";
  602. if (_coeOutputs.Contains(variableName))
  603. {
  604. bool result= TwincatCoeManager.Instance.WriteVariableValue(str, variableName, value);
  605. if(result)
  606. {
  607. LOG.WriteLog(eEvent.INFO_AXIS, str, $"coe variable {variableName} value {value} success");
  608. }
  609. }
  610. }
  611. /// <summary>
  612. /// 更新运动数据
  613. /// </summary>
  614. /// <param name="variable"></param>
  615. /// <param name="value"></param>
  616. private void UpdateMotionData(string variable, object value)
  617. {
  618. if(!MotionData.IsDataInitialized)
  619. {
  620. MotionData.IsDataInitialized = true;
  621. }
  622. PropertyInfo property = MotionData.GetType().GetProperty(variable);
  623. if (property != null)
  624. {
  625. if (JudgeIsScale(variable))
  626. {
  627. if (int.TryParse(value.ToString(), out int intValue))
  628. {
  629. if (JudgeSpeedRatio(variable))
  630. {
  631. property.SetValue(MotionData, CalculateValueAfterScale(CalculateDivideSpeedRatio(intValue)));
  632. }
  633. else if(JudgeAccelerationRation(variable))
  634. {
  635. property.SetValue(MotionData, CalculateValueAfterScale(CalculateMultiplyAccelerationRatio(intValue)));
  636. }
  637. else
  638. {
  639. property.SetValue(MotionData, CalculateValueAfterScale(intValue));
  640. }
  641. }
  642. else
  643. {
  644. property.SetValue(MotionData, value);
  645. }
  646. }
  647. else if(variable==ACTUAL_TORQUE)
  648. {
  649. if (short.TryParse(value.ToString(), out short shortValue))
  650. {
  651. property.SetValue(MotionData, CalculateDivideTorqueRatio(shortValue));
  652. }
  653. else
  654. {
  655. property.SetValue(MotionData, value);
  656. }
  657. }
  658. else
  659. {
  660. property.SetValue(MotionData, value);
  661. }
  662. }
  663. }
  664. /// <summary>
  665. /// 判定是否需要比例计算
  666. /// </summary>
  667. /// <param name="variable"></param>
  668. /// <returns></returns>
  669. private bool JudgeIsScale(string variable)
  670. {
  671. switch (variable)
  672. {
  673. case PROFILE_VELOCITY:
  674. case PROFILE_ACCEL:
  675. case PROFILE_DECEL:
  676. case MOTOR_POSITION:
  677. case POSITION_ERROR:
  678. case ACTUAL_VELOCITY:
  679. case TARGET_POSITION:
  680. case HOMING_ACCEL:
  681. case HOMING_VELOCITY:
  682. case HOMING_VELOCITY_SLOW:
  683. case HOME_OFFSET:
  684. return true;
  685. default:
  686. return false;
  687. }
  688. }
  689. /// <summary>
  690. /// 判定是否需要速度调整比例
  691. /// </summary>
  692. /// <param name="variable"></param>
  693. /// <returns></returns>
  694. private bool JudgeSpeedRatio(string variable)
  695. {
  696. switch (variable)
  697. {
  698. case PROFILE_VELOCITY:
  699. case ACTUAL_VELOCITY:
  700. case HOMING_VELOCITY:
  701. case HOMING_VELOCITY_SLOW:
  702. case HOME_OFFSET:
  703. return true;
  704. default:
  705. return false;
  706. }
  707. }
  708. /// <summary>
  709. /// 是否是加速度调整比例
  710. /// </summary>
  711. /// <param name="variable"></param>
  712. /// <returns></returns>
  713. protected bool JudgeAccelerationRation(string variable)
  714. {
  715. switch(variable)
  716. {
  717. case PROFILE_ACCEL:
  718. case PROFILE_DECEL:
  719. case HOMING_ACCEL:
  720. return true;
  721. default:
  722. return false;
  723. }
  724. }
  725. /// <summary>
  726. /// motor position发生变化
  727. /// </summary>
  728. /// <param name="location"></param>
  729. private void MotionPositionChanged(int location)
  730. {
  731. if (Math.Abs(location - _currentLocation)/_scaleFactor >= _stationAxis.ToleranceDefault)
  732. {
  733. _currentLocation = location;
  734. _runTime = DateTime.Now;
  735. _isRun = true;
  736. }
  737. }
  738. /// <summary>
  739. /// 更新Digital Inputs
  740. /// </summary>
  741. /// <param name="digitalInputs"></param>
  742. private void UpdateDigitalInputs(uint digitalInputs)
  743. {
  744. if (_isRevSensorLimit)
  745. {
  746. MotionData.RevLimited = !(((digitalInputs>>18) & 0x01) == 0x01);
  747. }
  748. if(_isForwardSensorLimit)
  749. {
  750. MotionData.FwdLimited = !(((digitalInputs >> 17) & 0x01) == 0x01);
  751. }
  752. MotionData.HomedSwitched =((digitalInputs>>22)&0x01) == 0x01;
  753. if(!_isHomeSwitchedTrigger&&MotionData.HomedSwitched)
  754. {
  755. _isHomeSwitchedTrigger = true;
  756. }
  757. }
  758. /// <summary>
  759. /// 更新ManufactureStatus
  760. /// </summary>
  761. /// <param name="manufactureStatus"></param>
  762. private void UpdateManufactureStatus(uint manufactureStatus)
  763. {
  764. MotionData.HomedSwitched = ((manufactureStatus >> 26)&0x01) == 0x01;
  765. if (!_isHomeSwitchedTrigger && MotionData.HomedSwitched)
  766. {
  767. _isHomeSwitchedTrigger = true;
  768. }
  769. }
  770. /// <summary>
  771. /// 更新Torque Limited状态
  772. /// </summary>
  773. private void UpdateTorqueLimited()
  774. {
  775. if(MotionData.NegativeTorqueLimit!=0||MotionData.PositiveTorqueLimit!=0)
  776. {
  777. MotionData.TorqueLimited = (MotionData.ActualTorque >= -MotionData.NegativeTorqueLimit) && (MotionData.ActualTorque <= MotionData.PositiveTorqueLimit) ;
  778. }
  779. else
  780. {
  781. MotionData.TorqueLimited = true;
  782. }
  783. }
  784. /// <summary>
  785. /// 根据位置获取相应的Position数值
  786. /// </summary>
  787. /// <param name="station"></param>
  788. /// <returns></returns>
  789. public (bool success,double position) GetPositionByStation(string station)
  790. {
  791. foreach(Station item in _stationAxis.Stations)
  792. {
  793. if(item.Name.EndsWith(station))
  794. {
  795. if(double.TryParse(item.Position,out double position))
  796. {
  797. return (true, position);
  798. }
  799. else
  800. {
  801. return (false, 0);
  802. }
  803. }
  804. }
  805. return (false, 0);
  806. }
  807. #endregion
  808. #region protected 子类使用共用类,子类不再扩展
  809. /// <summary>
  810. /// 启动写COE变量数值线程
  811. /// </summary>
  812. public void StartUpWriteCoeThread()
  813. {
  814. bool isSimulator = SC.GetValue<bool>("System.IsSimulatorMode");
  815. if (!isSimulator)
  816. {
  817. Thread thread = new Thread(new ThreadStart(StartUpWriteCoeVariable));
  818. thread.IsBackground = true;
  819. thread.Start();
  820. }
  821. }
  822. /// <summary>
  823. /// 计算比例后的数值
  824. /// </summary>
  825. /// <param name="value"></param>
  826. /// <returns></returns>
  827. protected double CalculateValueAfterScale(int value)
  828. {
  829. if (_scaleFactor != 0)
  830. {
  831. return Math.Round((double)value / _scaleFactor, 2);
  832. }
  833. else
  834. {
  835. return (double)value;
  836. }
  837. }
  838. /// <summary>
  839. /// 确认操作状态
  840. /// </summary>
  841. /// <param name="operation"></param>
  842. protected void ConfirmOperationState(MotionOperation operation)
  843. {
  844. if (_currentOperation == operation)
  845. {
  846. _status = RState.End;
  847. EndOperation();
  848. }
  849. }
  850. /// <summary>
  851. /// 结束操作
  852. /// </summary>
  853. protected void EndOperation()
  854. {
  855. LOG.WriteLog(eEvent.INFO_AXIS,$"{Module}.{Name}", $"{Module}.{Name} execute {_currentOperation} complete");
  856. _currentOperation = MotionOperation.None;
  857. _targetPosition = 0;
  858. }
  859. /// <summary>
  860. /// 订阅变量数值发生变化
  861. /// </summary>
  862. protected void SubscribeValueAction()
  863. {
  864. BeckhoffIoSubscribeUpdateVariable( STATUS_WORD);
  865. BeckhoffIoSubscribeUpdateVariable( DIGITAL_INPUTS);
  866. BeckhoffIoSubscribeUpdateVariable( CONTROL_WORD);
  867. BeckhoffIoSubscribeUpdateVariable( MODE_OF_OPERATION);
  868. BeckhoffIoSubscribeUpdateVariable( PROFILE_VELOCITY);
  869. BeckhoffIoSubscribeUpdateVariable( PROFILE_ACCEL);
  870. BeckhoffIoSubscribeUpdateVariable( PROFILE_DECEL);
  871. BeckhoffIoSubscribeUpdateVariable( TARGET_POSITION);
  872. BeckhoffIoSubscribeUpdateVariable( MOTOR_POSITION);
  873. BeckhoffIoSubscribeUpdateVariable( POSITION_ERROR);
  874. BeckhoffIoSubscribeUpdateVariable( ACTUAL_TORQUE);
  875. BeckhoffIoSubscribeUpdateVariable( ACTUAL_VELOCITY);
  876. BeckhoffIoSubscribeUpdateVariable( HOME_OFFSET);
  877. BeckhoffIoSubscribeUpdateVariable( HOMING_METHOD);
  878. BeckhoffIoSubscribeUpdateVariable( HOMING_VELOCITY);
  879. BeckhoffIoSubscribeUpdateVariable( HOMING_VELOCITY_SLOW);
  880. BeckhoffIoSubscribeUpdateVariable( POSITIVE_TORQUE_LIMIT);
  881. BeckhoffIoSubscribeUpdateVariable( NEGATIVE_TORQUE_LIMIT);
  882. BeckhoffIoSubscribeUpdateVariable( HOMING_ACCEL);
  883. BeckhoffIoSubscribeUpdateVariable( MANUF_STATUS);
  884. }
  885. /// <summary>
  886. /// 订阅IO变量
  887. /// </summary>
  888. /// <param name="variable"></param>
  889. private void BeckhoffIoSubscribeUpdateVariable(string variable)
  890. {
  891. _variableInitializeDic[variable] = false;
  892. BeckhoffAxisManager.Instance.SubscribeModuleVariable($"{Module}.{Name}", variable, UpdateVariableValue);
  893. }
  894. /// <summary>
  895. /// 更新变量数值
  896. /// </summary>
  897. /// <param name="variable"></param>
  898. /// <param name="value"></param>
  899. protected void UpdateVariableValue(string variable, object value)
  900. {
  901. if (value == null)
  902. {
  903. return;
  904. }
  905. if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
  906. {
  907. _variableInitializeDic[variable] = true;
  908. }
  909. if (_coeOutputs.Contains(variable))
  910. {
  911. if (!_coeConnected)
  912. {
  913. _coeConnected = true;
  914. StartUpWriteCoeThread();
  915. }
  916. }
  917. if (variable == MODE_OF_OPERATION)
  918. {
  919. if (_modeOfOperation == (byte)AxisModeOfOperation.None)
  920. {
  921. byte.TryParse(value.ToString(), out _modeOfOperation);
  922. }
  923. else
  924. {
  925. _modeOfOperation = (byte)value;
  926. }
  927. }
  928. else if (variable == STATUS_WORD)
  929. {
  930. if (ushort.TryParse(value.ToString(), out _statusWord))
  931. {
  932. MotionData.StatusWord = _statusWord;
  933. UpdateStatusWord(_statusWord);
  934. }
  935. }
  936. else if (variable == CONTROL_WORD)
  937. {
  938. ushort.TryParse(value.ToString(), out _controlWord);
  939. }
  940. else if (variable == MOTOR_POSITION)
  941. {
  942. if (int.TryParse(value.ToString(), out int location))
  943. {
  944. MotionPositionChanged(location);
  945. if (_beckhoffAxis.ForwardSoftwareLimit != 0)
  946. {
  947. MotionData.ForwardSoftwareLimited = location > _beckhoffAxis.ForwardSoftwareLimit-_beckhoffAxis.HomingOffset;
  948. if (!_isForwardSensorLimit && !_isRevSensorLimit)
  949. {
  950. MotionData.FwdLimited = MotionData.ForwardSoftwareLimited;
  951. }
  952. }
  953. if (_beckhoffAxis.ReverseSoftwareLimit != 0)
  954. {
  955. MotionData.ReverseSoftwareLimited = location < _beckhoffAxis.ReverseSoftwareLimit-_beckhoffAxis.HomingOffset;
  956. if (!_isRevSensorLimit && !_isForwardSensorLimit)
  957. {
  958. MotionData.RevLimited = MotionData.ReverseSoftwareLimited;
  959. }
  960. }
  961. }
  962. }
  963. else if (variable == DIGITAL_INPUTS)
  964. {
  965. if (uint.TryParse(value.ToString(), out var uintValue))
  966. {
  967. UpdateDigitalInputs(uintValue);
  968. }
  969. }
  970. else if (variable == MANUF_STATUS)
  971. {
  972. if (uint.TryParse(value.ToString(), out var uintValue))
  973. {
  974. UpdateManufactureStatus(uintValue);
  975. }
  976. }
  977. UpdateMotionData(variable, value);
  978. if (variable == MOTOR_POSITION)
  979. {
  980. CalculateCurrentStation(MotionData.MotorPosition);
  981. }
  982. if (variable == ACTUAL_TORQUE)
  983. {
  984. UpdateTorqueLimited();
  985. }
  986. else if (variable == POSITIVE_TORQUE_LIMIT || variable == NEGATIVE_TORQUE_LIMIT)
  987. {
  988. MotionData.TorqueLimit = $"-{MotionData.NegativeTorqueLimit}/+{MotionData.PositiveTorqueLimit}";
  989. }
  990. }
  991. /// <summary>
  992. /// 监控(用于判定是否停止运动)
  993. /// </summary>
  994. protected void JudgeRunMonitor()
  995. {
  996. if (_isRun && DateTime.Now.Subtract(_runTime).TotalMilliseconds >= 500)
  997. {
  998. _isRun = false;
  999. }
  1000. }
  1001. #endregion
  1002. #region public 公开方法
  1003. /// <summary>
  1004. /// 初始化
  1005. /// </summary>
  1006. /// <returns></returns>
  1007. public bool Initialize()
  1008. {
  1009. SubscribeValueAction();
  1010. return true;
  1011. }
  1012. /// <summary>
  1013. /// 当前位置是否离目标位置不远
  1014. /// </summary>
  1015. /// <param name="targetPosition"></param>
  1016. /// <returns></returns>
  1017. public bool JudgeCurrentPositionIsInTargetPosition(int targetPosition)
  1018. {
  1019. double scaledTargetPosition = targetPosition /_scaleFactor;
  1020. double currentMotionPosition = MotionData.MotorPosition;
  1021. return Math.Round(Math.Abs(currentMotionPosition-scaledTargetPosition),2) <= _stationAxis.ToleranceDefault;
  1022. }
  1023. /// <summary>
  1024. /// 计算乘以比例后的数值
  1025. /// </summary>
  1026. /// <param name="value"></param>
  1027. /// <returns></returns>
  1028. public int CalculateValueMultiplyScale(double value)
  1029. {
  1030. if (_scaleFactor != 0)
  1031. {
  1032. return (int)Math.Round(value * _scaleFactor, 0);
  1033. }
  1034. else
  1035. {
  1036. return (int)Math.Round(value, 0);
  1037. }
  1038. }
  1039. /// <summary>
  1040. /// 计算乘上速度比例后的速度
  1041. /// </summary>
  1042. /// <param name="speed"></param>
  1043. /// <returns></returns>
  1044. public int CalculateMultiplySpeedRatio(int speed)
  1045. {
  1046. return speed * _speedRatio;
  1047. }
  1048. /// <summary>
  1049. /// 计算乘上加速度比例后的加速度
  1050. /// </summary>
  1051. /// <param name="acceleration"></param>
  1052. /// <returns></returns>
  1053. public int CalculateMultiplyAccelerationRatio(int acceleration)
  1054. {
  1055. return acceleration * _accelerationRatio;
  1056. }
  1057. /// <summary>
  1058. /// 计算除以速度比例后的速度
  1059. /// </summary>
  1060. /// <param name="speed"></param>
  1061. /// <returns></returns>
  1062. protected int CalculateDivideSpeedRatio(int speed)
  1063. {
  1064. return speed / _speedRatio;
  1065. }
  1066. /// <summary>
  1067. /// 计算除以加速度比例后的加速度
  1068. /// </summary>
  1069. /// <param name="acceleration"></param>
  1070. /// <returns></returns>
  1071. protected int CalculateDivideAccelerationRatio(int acceleration)
  1072. {
  1073. return acceleration / _accelerationRatio;
  1074. }
  1075. /// <summary>
  1076. /// 计算除以Torque比例后的Torque
  1077. /// </summary>
  1078. /// <param name="speed"></param>
  1079. /// <returns></returns>
  1080. protected double CalculateDivideTorqueRatio(int torque)
  1081. {
  1082. return Math.Round((double)torque / _torqueRatio, 2);
  1083. }
  1084. /// <summary>
  1085. /// Jog Up
  1086. /// </summary>
  1087. /// <param name="cmd"></param>
  1088. /// <param name="args"></param>
  1089. /// <returns></returns>
  1090. public bool JogUpPosition(string cmd, object[] args)
  1091. {
  1092. double jog=(double)args[1];
  1093. double currentPosition=(double)args[2];
  1094. if(_jogLimit!=0)
  1095. {
  1096. if(jog>_jogLimit)
  1097. {
  1098. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Jog Value {jog} is over {_jogLimit}");
  1099. return false;
  1100. }
  1101. }
  1102. if (!_isSwitchOn)
  1103. {
  1104. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Axis is switch off,cannot jog");
  1105. return false;
  1106. }
  1107. return ProfilePositionOperation(Math.Round(currentPosition + jog,2));
  1108. }
  1109. /// <summary>
  1110. /// Jog Down
  1111. /// </summary>
  1112. /// <param name="cmd"></param>
  1113. /// <param name="args"></param>
  1114. /// <returns></returns>
  1115. public bool JogDownPosition(string cmd, object[] args)
  1116. {
  1117. double jog = (double)args[1];
  1118. double currentPosition = (double)args[2];
  1119. if (_jogLimit != 0)
  1120. {
  1121. if (jog > _jogLimit)
  1122. {
  1123. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Jog Value {jog} is over {_jogLimit}");
  1124. return false;
  1125. }
  1126. }
  1127. if(!_isSwitchOn)
  1128. {
  1129. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Axis is switch off,cannot jog");
  1130. return false;
  1131. }
  1132. return ProfilePositionOperation(Math.Round(currentPosition - jog,2));
  1133. }
  1134. /// <summary>
  1135. /// Profile position操作
  1136. /// </summary>
  1137. /// <param name="cmd"></param>
  1138. /// <param name="args"></param>
  1139. /// <returns></returns>
  1140. public bool ProfilePositionOperation(double position)
  1141. {
  1142. _targetPosition = position;
  1143. int targetPosition = CalculateValueMultiplyScale(_targetPosition);
  1144. if (_beckhoffAxis.ForwardSoftwareLimit != 0 && targetPosition > _beckhoffAxis.ForwardSoftwareLimit - _beckhoffAxis.HomingOffset)
  1145. {
  1146. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"target position {_targetPosition} is over forward limit");
  1147. return false;
  1148. }
  1149. if (_beckhoffAxis.ReverseSoftwareLimit != 0 && targetPosition < _beckhoffAxis.ReverseSoftwareLimit - _beckhoffAxis.HomingOffset)
  1150. {
  1151. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"target position {_targetPosition} is less reverse limit");
  1152. return false;
  1153. }
  1154. return ProfilePosition(targetPosition, _profileVelocity, _profileAcceleration, _profileDeceleration);
  1155. }
  1156. /// <summary>
  1157. /// 移动至指定位置
  1158. /// </summary>
  1159. /// <param name="targetStation"></param>
  1160. /// <returns></returns>
  1161. public bool PositionStation(string targetStation,bool isHome=false,int velocity=0,int acceleration=0,int deceleration=0, bool judgeTorqueLimit = true)
  1162. {
  1163. if (!CheckPositionIsInStation(MotionData.MotorPosition,targetStation))
  1164. {
  1165. if(_interLock!=null&&!isHome&&!_interLock.CheckGotoPosition(targetStation))
  1166. {
  1167. return false;
  1168. }
  1169. var result=GetPositionByStation(targetStation);
  1170. if(result.success)
  1171. {
  1172. _targetPosition = result.position;
  1173. int targetPosition = (int)Math.Round(result.position * _scaleFactor, 0);
  1174. if (velocity != 0)
  1175. {
  1176. return ProfilePosition(targetPosition, velocity, acceleration, deceleration, judgeTorqueLimit);
  1177. }
  1178. else
  1179. {
  1180. return ProfilePosition(targetPosition, _profileVelocity, _profileAcceleration, _profileDeceleration, judgeTorqueLimit);
  1181. }
  1182. }
  1183. LOG.WriteLog(eEvent.ERR_AXIS, Module, $"{targetStation} not in list,cannot goto fixed position");
  1184. return false;
  1185. }
  1186. else
  1187. {
  1188. _status = RState.End;
  1189. }
  1190. return true;
  1191. }
  1192. /// <summary>
  1193. /// 写入控制字
  1194. /// </summary>
  1195. /// <param name="controlWord"></param>
  1196. public bool WriteControlWord(ushort controlWord)
  1197. {
  1198. return BeckhoffAxisManager.Instance.WriteVariableValue($"{Module}.{Name}.{CONTROL_WORD}", controlWord);
  1199. }
  1200. /// <summary>
  1201. /// 写入ModeOfOperation
  1202. /// </summary>
  1203. /// <param name="modeOfOperation"></param>
  1204. /// <returns></returns>
  1205. public bool WriteModeOfMode(AxisModeOfOperation modeOfOperation)
  1206. {
  1207. return BeckhoffAxisManager.Instance.WriteVariableValue($"{Module}.{Name}.{MODE_OF_OPERATION}", (byte)modeOfOperation);
  1208. }
  1209. /// <summary>
  1210. /// 写变量数值
  1211. /// </summary>
  1212. /// <param name="variableName"></param>
  1213. /// <param name="value"></param>
  1214. /// <returns></returns>
  1215. public bool WriteVariable(string variableName,object value)
  1216. {
  1217. return BeckhoffAxisManager.Instance.WriteVariableValue($"{Module}.{Name}.{variableName}", value);
  1218. }
  1219. /// <summary>
  1220. /// 检验GotoPosition条件
  1221. /// </summary>
  1222. /// <param name="station"></param>
  1223. public bool CheckGotoPosition(string station)
  1224. {
  1225. return _interLock.CheckGotoPosition(station);
  1226. }
  1227. /// <summary>
  1228. /// 检验当位Position是否在位置上
  1229. /// </summary>
  1230. /// <param name="position"></param>
  1231. /// <param name="stationName"></param>
  1232. /// <returns></returns>
  1233. public bool CheckPositionIsInStation(double position,string stationName)
  1234. {
  1235. foreach (Station station in _stationAxis.Stations)
  1236. {
  1237. if (station.Name.ToLower().EndsWith(stationName.ToLower()))
  1238. {
  1239. if (double.TryParse(station.Position, out double value))
  1240. {
  1241. if (Math.Round(Math.Abs(position - value), 2) <= _stationAxis.ToleranceDefault)
  1242. {
  1243. return true;
  1244. }
  1245. }
  1246. }
  1247. }
  1248. return false;
  1249. }
  1250. /// <summary>
  1251. /// 检验位置是否为空
  1252. /// </summary>
  1253. /// <param name="position"></param>
  1254. /// <returns></returns>
  1255. public bool CheckPositionIsEmpty(double position)
  1256. {
  1257. foreach (Station station in _stationAxis.Stations)
  1258. {
  1259. if (double.TryParse(station.Position, out double value))
  1260. {
  1261. if (Math.Round(Math.Abs(position - value), 2) <= _stationAxis.ToleranceDefault)
  1262. {
  1263. return false;
  1264. }
  1265. }
  1266. }
  1267. return true;
  1268. }
  1269. /// <summary>
  1270. /// 判定与目标位置相对关系
  1271. /// </summary>
  1272. /// <param name="station"></param>
  1273. /// <param name="compareType">Left--位于目标位置左侧,Right--位于目标位置右侧</param>
  1274. /// <returns></returns>
  1275. public bool JudgeCompareTargetStation(string station,string compareType)
  1276. {
  1277. double position = 0;
  1278. var result = GetPositionByStation(station);
  1279. if(result.success)
  1280. {
  1281. position = result.position;
  1282. }
  1283. else
  1284. {
  1285. return false;
  1286. }
  1287. var buffer16Position=GetPositionByStation(station);
  1288. switch(compareType)
  1289. {
  1290. case "Left":
  1291. return IsInStationLeftDirection(position);
  1292. case "Right":
  1293. if (buffer16Position.success)
  1294. {
  1295. position=buffer16Position.position;
  1296. }
  1297. return IsInStationRightPosition(position);
  1298. default:
  1299. return false;
  1300. }
  1301. }
  1302. /// <summary>
  1303. /// 是否位于位置左侧
  1304. /// </summary>
  1305. /// <param name="stationPosition"></param>
  1306. /// <returns></returns>
  1307. private bool IsInStationLeftDirection(double stationPosition)
  1308. {
  1309. double currentPosition = MotionData.MotorPosition;
  1310. double targetPosition = _targetPosition;
  1311. if(_currentOperation==MotionOperation.Position)
  1312. {
  1313. return currentPosition <= stationPosition && targetPosition <= stationPosition;
  1314. }
  1315. else
  1316. {
  1317. return currentPosition <= stationPosition;
  1318. }
  1319. }
  1320. /// <summary>
  1321. /// 是否位于位置右侧
  1322. /// </summary>
  1323. /// <param name="stationPosition"></param>
  1324. /// <returns></returns>
  1325. private bool IsInStationRightPosition(double stationPosition)
  1326. {
  1327. double currentPosition = MotionData.MotorPosition;
  1328. double targetPosition = _targetPosition;
  1329. if (_currentOperation == MotionOperation.Position)
  1330. {
  1331. return currentPosition > stationPosition && targetPosition > stationPosition;
  1332. }
  1333. else
  1334. {
  1335. return currentPosition > stationPosition ;
  1336. }
  1337. }
  1338. #endregion
  1339. #region virtual共用方法,子类可实现更多方法
  1340. /// <summary>
  1341. /// Home共用方法
  1342. /// </summary>
  1343. /// <returns></returns>
  1344. public virtual bool Home()
  1345. {
  1346. if (!_isSwitchOn)
  1347. {
  1348. EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} switch off,cannot home");
  1349. return false;
  1350. }
  1351. if (_status == RState.Running)
  1352. {
  1353. EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} current execute {_currentOperation},cannot home");
  1354. return false;
  1355. }
  1356. _currentOperation = MotionOperation.Home;
  1357. _status = RState.Running;
  1358. return true;
  1359. }
  1360. /// <summary>
  1361. /// Home(isLogError)共用方法
  1362. /// </summary>
  1363. /// <returns></returns>
  1364. public virtual bool Home(bool isLogError)
  1365. {
  1366. if (!_isSwitchOn)
  1367. {
  1368. EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} switch off,cannot home");
  1369. return false;
  1370. }
  1371. if (_status == RState.Running)
  1372. {
  1373. EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} current execute {_currentOperation},cannot home");
  1374. return false;
  1375. }
  1376. _currentOperation = MotionOperation.Home;
  1377. _status = RState.Running;
  1378. return true;
  1379. }
  1380. /// <summary>
  1381. /// 更改速度百分比
  1382. /// </summary>
  1383. /// <param name="percent"></param>
  1384. /// <returns></returns>
  1385. public bool ChangePercentSpeedAceleration(int percent)
  1386. {
  1387. double percentSpeed = _initialVelocity * ((double)percent / 100);
  1388. double percentAceleration = _initialAcceleration * ((double)percent / 100);
  1389. double percentDeceleration = _initialDeceleration * ((double)percent / 100);
  1390. int changedSpeed = (int)(Math.Round(percentSpeed, 0));
  1391. int changedAcceleration = (int)(Math.Round(percentAceleration, 0));
  1392. int changedDeceleration = (int)(Math.Round(percentDeceleration, 0));
  1393. bool result= ChangeSpeedAcceleration(changedSpeed,changedAcceleration,changedDeceleration);
  1394. if(result)
  1395. {
  1396. _profileVelocity = changedSpeed;
  1397. _profileAcceleration = changedAcceleration;
  1398. _profileDeceleration = changedDeceleration;
  1399. }
  1400. return result;
  1401. }
  1402. #endregion
  1403. #region public abstract 子类实现方法
  1404. /// <summary>
  1405. /// 停止操作
  1406. /// </summary>
  1407. /// <param name="cmd"></param>
  1408. /// <param name="args"></param>
  1409. /// <returns></returns>
  1410. public abstract bool StopPositionOperation();
  1411. /// <summary>
  1412. /// change speed
  1413. /// </summary>
  1414. /// <param name="speed"></param>
  1415. /// <returns></returns>
  1416. public abstract bool ChangeSpeed(int speed);
  1417. /// <summary>
  1418. /// 改变速度加速度
  1419. /// </summary>
  1420. /// <param name="speed"></param>
  1421. /// <returns></returns>
  1422. public abstract bool ChangeSpeedAcceleration(int speed, int acceleration, int deceleration);
  1423. /// <summary>
  1424. /// Switch On
  1425. /// </summary>
  1426. public abstract bool SwitchOn();
  1427. /// <summary>
  1428. /// Switch Off
  1429. /// </summary>
  1430. public abstract bool SwitchOff();
  1431. /// <summary>
  1432. /// 停止
  1433. /// </summary>
  1434. public abstract void Stop();
  1435. /// <summary>
  1436. /// Enable Operation
  1437. /// </summary>
  1438. /// <returns></returns>
  1439. public abstract bool EnableOperation();
  1440. /// <summary>
  1441. /// 定时器执行
  1442. /// </summary>
  1443. /// <returns></returns>
  1444. public abstract bool OnTimer();
  1445. /// <summary>
  1446. /// Profile operation
  1447. /// </summary>
  1448. /// <param name="targetPoint"></param>
  1449. /// <param name="profileVelocity"></param>
  1450. /// <param name="profileAcceleration"></param>
  1451. /// <param name="profileDeceleration"></param>
  1452. public abstract bool ProfilePosition(int targetPoint, int profileVelocity, int profileAcceleration, int profileDeceleration, bool judgeTorqueLimit = true);
  1453. #endregion
  1454. #region protected abstract 子类实现方法
  1455. /// <summary>
  1456. /// 初始化Routine
  1457. /// </summary>
  1458. protected abstract void InitializeRoutine();
  1459. /// <summary>
  1460. /// 初始化参数
  1461. /// </summary>
  1462. protected abstract void InitializeParameter();
  1463. /// <summary>
  1464. /// 更新状态字
  1465. /// </summary>
  1466. /// <param name="statusWord"></param>
  1467. public abstract void UpdateStatusWord(ushort statusWord);
  1468. /// <summary>
  1469. /// 回车输入
  1470. /// </summary>
  1471. /// <param name="arg"></param>
  1472. /// <param name="value"></param>
  1473. protected abstract void AxisKeyDown(string arg, double value);
  1474. #endregion
  1475. /// <summary>
  1476. /// 监控
  1477. /// </summary>
  1478. public void Monitor()
  1479. {
  1480. }
  1481. public void Reset()
  1482. {
  1483. }
  1484. /// 停止
  1485. /// </summary>
  1486. public void Terminate()
  1487. {
  1488. }
  1489. }
  1490. }