| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451 | using Aitex.Core.RT.DataCenter;using Aitex.Core.RT.Device;using Aitex.Core.RT.Event;using Aitex.Core.RT.Log;using Aitex.Core.RT.OperationCenter;using Aitex.Core.RT.Routine;using Aitex.Core.RT.SCCore;using Aitex.Core.Util;using MECF.Framework.Common.Beckhoff.AxisProvider;using MECF.Framework.Common.Beckhoff.IOAxis;using MECF.Framework.Common.Beckhoff.Station;using MECF.Framework.Common.CommonData.PUF;using MECF.Framework.Common.TwinCat;using MECF.Framework.Common.Utilities;using PunkHPX8_Core;using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Timers;using CommunityToolkit.HighPerformance.Buffers;using System.Windows.Documents;using MECF.Framework.Common.Device.Galil;using MECF.Framework.Common.Device;using MECF.Framework.Common.IOCore;namespace PunkHPX8_RT.Devices.AXIS{    public abstract class JetAxisBase : BaseDevice, IDevice    {        #region 常量        private const string STATUS_WORD = "StatusWord";        private const string DIGITAL_INPUTS="DigitalInputs";        private const string CONTROL_WORD = "ControlWord";        private const string MODE_OF_OPERATION = "ModeOfOperation";        protected const string PROFILE_VELOCITY = "ProfileVelocity";        protected const string PROFILE_ACCEL = "ProfileAccel";        protected const string PROFILE_DECEL = "ProfileDecel";        private const string REFERENCE_POSITION = "ReferencePosition";        private const string TARGET_POSITION = "TargetPosition";        private const string MOTOR_POSITION = "MotorPosition";        private const string ACTUAL_VELOCITY = "Velocity";        private const string ACTUAL_TORQUE = "ActualTorque";        private const string POSITION_ERROR = "PositionError";        private const string MOTION_DATA = "MotionData";        private const string CURRENT_STATION = "CurrentStation";        protected const string CURRENT_STATION_LIST = "CurrentStationList";        private const string IS_SWITCH_ON = "IsSwitchOn";        private const string HOME_OFFSET = "HomeOffset";        private const string HOMING_METHOD = "HomingMethod";        protected const string HOMING_VELOCITY = "HomingVelocity";        protected const string HOMING_VELOCITY_SLOW = "HomingVelocitySlow";        protected const string HOMING_ACCEL = "HomingAccel";        private const string NEGATIVE_TORQUE_LIMIT="NegativeTorqueLimit";        private const string POSITIVE_TORQUE_LIMIT = "PositiveTorqueLimit";        private const string MANUF_STATUS="ManufStatus";        private const string SOFTWARE_LIMIT_MINUS= "SoftwareLimitMinus";        private const string SOFTWARE_LIMIT_PLUS = "SoftwareLimitPlus";        private const string STOP_CODE = "StopCode";        private const string FORWARD_LIMIT = "ForwardLimit";        #endregion        #region 内部变量        /// <summary>        /// 比例因子        /// </summary>        private double _scaleFactor = 0;        /// <summary>        /// jog限制        /// </summary>        private double _jogLimit = 0;        /// <summary>        /// 当前位置数值(用于判定是否正在运动)        /// </summary>        private int _currentLocation = 0;        /// <summary>        /// 是否运动        /// </summary>        private bool _isRun = false;        /// <summary>        /// 当前位置        /// </summary>        private string _currentStation = "";        /// <summary>        /// 当前位置集合(多个位置共用一个数值)        /// </summary>        private List<string> _currentStationList = new List<string>();        /// <summary>        /// 当前位置锁        /// </summary>        private object _locationLocker = new object();        /// <summary>        /// 工位位置对象        /// </summary>        private BeckhoffStationAxis _stationAxis;        /// <summary>        /// 运动时间        /// </summary>        private DateTime _runTime = DateTime.Now;        /// <summary>        /// inter lock        /// </summary>        private IAxisInterLock _interLock;        /// <summary>        /// 是否存在Rev Sensor Limit        /// </summary>        private bool _isRevSensorLimit = false;        /// <summary>        /// 是否存在Forward Limit        /// </summary>        private bool _isForwardSensorLimit = false;        /// <summary>        /// Home Switched是否触发        /// </summary>        private bool _isHomeSwitchedTrigger = false;        /// <summary>        /// 变量是否初始化字典        /// </summary>        private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();        #endregion        #region protected 字段        /// <summary>        /// 轴参数对象        /// </summary>        protected AxisConfig _axisConfig = null;        /// <summary>        /// 状态        /// </summary>        protected RState _status;        /// <summary>        /// 当前操作        /// </summary>        protected MotionOperation _currentOperation = MotionOperation.None;        /// <summary>        /// 模式        /// </summary>        protected byte _modeOfOperation;        /// <summary>        /// 状态字        /// </summary>        protected ushort _statusWord;        /// <summary>        /// 控制字        /// </summary>        protected ushort _controlWord;        /// <summary>        /// 运动数据对象        /// </summary>        protected CommandMotionData _commandMotionData = new CommandMotionData();        /// <summary>        /// Home状态        /// </summary>        protected bool _isHomed;        /// <summary>        /// SwitchOn状态        /// </summary>        protected bool _isSwitchOn;        /// <summary>        /// 是否错误        /// </summary>        protected bool _isError;        /// <summary>        /// 是否到达目标位置        /// </summary>        protected bool _inTargetPosition = false;        /// <summary>        /// 初始化的速度        /// </summary>        protected int _initialVelocity = 0;        /// <summary>        /// 初始化的加速度        /// </summary>        protected int _initialAcceleration = 0;        /// <summary>        /// 初始化的减速度        /// </summary>        protected int _initialDeceleration = 0;        /// <summary>        /// 运动速度        /// </summary>        protected int _profileVelocity = 0;        /// <summary>        /// 运动加速度        /// </summary>        protected int _profileAcceleration = 0;        /// <summary>        /// 运动减速度        /// </summary>        protected int _profileDeceleration = 0;        /// <summary>        /// 负向Torque限制        /// </summary>        protected int _profileNegativeTorqueLimit = 0;        /// <summary>        /// 正向Torque限制        /// </summary>        protected int _profilePositiveTorqueLimit = 0;        /// <summary>        /// Homing 速度        /// </summary>        protected int _profileHomingVelocity = 0;        /// <summary>        /// Homing 速度Slow        /// </summary>        protected int _profileHomingVelocitySlow = 0;        /// <summary>        /// Homing加速度        /// </summary>        protected int _profileHomingAccel = 0;        /// <summary>        /// <summary>        /// 目标位置        /// </summary>        protected double _targetPosition = 0.0;        /// <summary>        /// home超时时长        /// </summary>        protected int _homeTimeout = 5000;        /// <summary>        /// 速度比例        /// </summary>        protected int _speedRatio = 1;        /// <summary>        /// 加速度的比例        /// </summary>        protected int _accelerationRatio = 1;        /// <summary>        /// torque比例        /// </summary>        protected int _torqueRatio = 1000;        /// <summary>        /// Motion Position比例        /// </summary>        protected double _motionPositionRation = 1;        /// <summary>        /// Actual Velocity比例        /// </summary>        protected double _velocityRate = 1;        /// <summary>        /// Axis Operation Locker        /// </summary>        protected readonly object _operationLocker = new object();        #endregion        #region 属性        /// <summary>        /// 状态        /// </summary>        public RState Status { get { return _status; } }        /// <summary>        /// Home状态        /// </summary>        public bool IsHomed { get { return _isHomed; } set { _isHomed = value; } }        /// <summary>        /// SwitchOn状态        /// </summary>        public bool IsSwitchOn { get { return _isSwitchOn; } }        /// <summary>        /// 模式        /// </summary>        public byte ModeOfOperation { get { return _modeOfOperation; } }        /// <summary>        /// 控制字        /// </summary>        public ushort ControlWord { get { return _controlWord; } }        /// <summary>        /// 是否运动中        /// </summary>        public bool IsRun { get { return _isRun; } }        /// <summary>        /// 当前位置        /// </summary>        public string CurrentStation { get { return _currentStation; } }        /// <summary>        /// 是否到达目标位置        /// </summary>        public bool InTargetPosition { get { return _inTargetPosition; } }        /// <summary>        /// 运动数据对象        /// </summary>        public CommandMotionData MotionData { get { return _commandMotionData; } }        /// <summary>        /// 负向Torque限制数值        /// </summary>        public int NegativeTorqueLimit { get { return _profileNegativeTorqueLimit; } }        /// <summary>        /// 正向Torque限制数值        /// </summary>        public int PositiveTorqueLimit { get { return _profilePositiveTorqueLimit; } }        /// <summary>        /// 是否错误        /// </summary>        public bool IsError { get { return _isError; } }        /// <summary>        /// 目标位置        /// </summary>        public double TargetPosition { get { return _targetPosition; } }        /// <summary>        /// 加速度        /// </summary>        public double ProfileAcceleration { get { return _profileAcceleration; } }        /// <summary>        /// 减速度        /// </summary>        public double ProfileDeceleration { get { return _profileDeceleration; } }        /// <summary>        /// inter lock接口对象        /// </summary>        public IAxisInterLock InterLock { set { _interLock= value; } }        /// <summary>        /// 是否存在Sensor Limit        /// </summary>        public bool IsRevSensorLimit { set { _isRevSensorLimit = value; } }        /// <summary>        /// 是否存在正向Sensor Limit        /// </summary>        public bool IsForwardSensorLimit { set { _isForwardSensorLimit = value; } }        /// <summary>        /// Home Switch是否触发        /// </summary>        public bool IsHomeSwitchedTriggered { get { return _isHomeSwitchedTrigger; } set { _isHomeSwitchedTrigger = value; } }        /// <summary>        /// 所有io变量是否初始化        /// </summary>        public bool IOInitialized { get { return AllIoVariableInitialized(); } }        /// <summary>        /// ScaleFactor        /// </summary>        public double ScaleFactor { get { return _scaleFactor; } }        /// <summary>        /// ScaleFactor        /// </summary>        public double ToleranceDefault { get { return _stationAxis.ToleranceDefault; } }        #endregion        /// <summary>        /// 构造函数        /// </summary>        /// <param name="moduleName"></param>        /// <param name="name"></param>        public JetAxisBase(string moduleName,string name) : base(moduleName, name,name,name)        {            InitializeParameter();            LoadStation();            InitializeRoutine();            SubscribeData();            InitializeOperation();        }        #region private方法        /// <summary>        /// 加载Station位置        /// </summary>        private void LoadStation()        {            _stationAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(Module, Name);        }        /// <summary>        /// 订阅数据        /// </summary>        private void SubscribeData()        {            BeckhoffProviderAxis beckhoffProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.{Name}");            if (beckhoffProviderAxis != null)            {                _scaleFactor = beckhoffProviderAxis.ScaleFactor;                _jogLimit = beckhoffProviderAxis.JogLimit;                _motionPositionRation = beckhoffProviderAxis.MotorPositionRate;                _velocityRate = beckhoffProviderAxis.VelocityRate;            }            _axisConfig = InitializeAxisConfig();            if (_axisConfig != null)            {                _profileVelocity =CalculateMultiplySpeedRatio(_axisConfig.Speed);                _initialVelocity = _profileVelocity;                _profileAcceleration = CalculateDivideAccelerationRatio(_axisConfig.Acceleration);                _initialAcceleration = _profileAcceleration;                _profileDeceleration = CalculateDivideAccelerationRatio(_axisConfig.Deceleration);                _initialDeceleration = _profileDeceleration;                _profileNegativeTorqueLimit = _axisConfig.NegativeTorqueLimit;                _profilePositiveTorqueLimit = _axisConfig.PositiveTorqueLimit;                _commandMotionData.FileAcceleration = CalculateValueAfterScale(_axisConfig.Acceleration);                _commandMotionData.FileDeceleration = CalculateValueAfterScale(_axisConfig.Deceleration);                _commandMotionData.HomeOffset = CalculateValueAfterScale(_axisConfig.HomingOffset);                _commandMotionData.FileHomingAccel = CalculateValueAfterScale(_axisConfig.HomingAcceleration);                _commandMotionData.FileHomingVelocitySlow = CalculateValueAfterScale(_axisConfig.HomingSpeed);                _commandMotionData.FileHomingVelocity = CalculateValueAfterScale(_axisConfig.HomingSpeed);                _commandMotionData.FileProfileVelocity = CalculateValueAfterScale(_axisConfig.Speed);                _commandMotionData.FwdSoftLimit = CalculateValueAfterScale(_axisConfig.ForwardSoftwareLimit)-_commandMotionData.HomeOffset;                _commandMotionData.RevSoftLimit = CalculateValueAfterScale(_axisConfig.ReverseSoftwareLimit)-_commandMotionData.HomeOffset;                _commandMotionData.NegativeTorqueLimit = _axisConfig.NegativeTorqueLimit;                _commandMotionData.PositiveTorqueLimit = _axisConfig.PositiveTorqueLimit;                if (_axisConfig.NegativeTorqueLimit != 0 || _axisConfig.PositiveTorqueLimit != 0)                {                    _commandMotionData.TorqueLimit = $"-{_axisConfig.NegativeTorqueLimit}/+{_axisConfig.PositiveTorqueLimit}";                }                if(_axisConfig.HomingTimeOut!=0)                {                    _homeTimeout = _axisConfig.HomingTimeOut;                }            }            DATA.Subscribe($"{Module}.{Name}.{MOTION_DATA}", () => _commandMotionData,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.{MOTOR_POSITION}", () => _commandMotionData.MotorPosition,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.ProfileVelocity", () => _commandMotionData.ProfileVelocity, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.Acceleration",()=>_commandMotionData.FileAcceleration,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.Deceleration",()=>_commandMotionData.FileDeceleration,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.ActualTorque",()=>_commandMotionData.ActualTorque,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.{CURRENT_STATION}", () => _currentStation,SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.{CURRENT_STATION_LIST}", () => _currentStationList, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.{IS_SWITCH_ON}", () => IsSwitchOn, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.IsHomed", () => IsHomed, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.IsError",()=>IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.IsMoving", () => _isRun, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.IsRun", () => _isRun, SubscriptionAttribute.FLAG.IgnoreSaveDB);            DATA.Subscribe($"{Module}.{Name}.{FORWARD_LIMIT}", () => _commandMotionData.FwdLimited, SubscriptionAttribute.FLAG.IgnoreSaveDB);        }        /// <summary>        /// 初始化操作        /// </summary>        private void InitializeOperation()        {            OP.Subscribe($"{Module}.{Name}.{MotionOperation.SwitchOn}", (cmd, args) => { SwitchOn(); return true; });            OP.Subscribe($"{Module}.{Name}.{MotionOperation.SwitchOff}", (cmd, args) => { SwitchOff(); return true; });            OP.Subscribe($"{Module}.{Name}.{MotionOperation.Home}", (cmd, args) => { Home(); return true; });            OP.Subscribe($"{Module}.{Name}.JogUp", JogUpPosition);            OP.Subscribe($"{Module}.{Name}.JogDown", JogDownPosition);            OP.Subscribe($"{Module}.{Name}.{MotionOperation.KeyDown}", KeyDownOperation);            OP.Subscribe($"{Module}.{Name}.{MotionOperation.Stop}",(cmd,args)=> { return StopPositionOperation(); });            OP.Subscribe($"{Module}.{Name}.{MotionOperation.Save}", SaveOperation);            OP.Subscribe($"{Module}.{Name}.GotoSavedPosition", (cmd, args) => {                 return PositionStation(args[1].ToString()); });                    }        /// <summary>        /// 保存操作        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        public bool SaveOperation(string cmd, object[] args)        {            if (args.Length >= 2)            {                string key = args[0].ToString();                double paramValue = double.Parse(args[1].ToString());                BeckhoffStationLocationManager.Instance.SaveMotionPosition(key, paramValue);                lock (_locationLocker)                {                    List<string> lst = new List<string>();                    foreach (Station item in _stationAxis.Stations)                    {                        if (item.Name == key)                        {                            item.Position = paramValue.ToString();                            _currentStation = item.Name;                            if (!lst.Contains(item.Name))                            {                                lst.Add(item.Name);                            }                        }                    }                    _currentStationList.Clear();                    if (lst.Count != 0)                    {                        _currentStationList.AddRange(lst);                    }                }                LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", "save success");            }            return true;        }        /// <summary>        /// 计算所处当前工位        /// </summary>        private void CalculateCurrentStation(double motor)        {            lock (_locationLocker)            {                List<string> tmp = _currentStationList.ToList();                List<string> lst = new List<string>();                foreach (Station station in _stationAxis.Stations)                {                    if (double.TryParse(station.Position, out double value))                    {                        if (Math.Round(Math.Abs(motor - value),2) <= _stationAxis.ToleranceDefault)                        {                            _currentStation = station.Name;                            if (!lst.Contains(station.Name))                            {                                lst.Add(station.Name);                            }                        }                    }                }                _currentStationList.Clear();                if (lst.Count != 0)                {                    string str = string.Join(",", tmp);                    _currentStationList.AddRange(lst);                    string strLst = string.Join(",", _currentStationList);                    if (str != strLst)                    {                        LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", $"position {motor} current {strLst}");                    }                }                else                {                    _currentStation = "";                }                if (tmp.Count != 0&&_currentStationList.Count==0)                {                    LOG.WriteLog(eEvent.INFO_AXIS, $"{Module}.{Name}", $"position {motor} current is empty");                }            }        }        /// <summary>        ///  文本框回车操作        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        private bool KeyDownOperation(string cmd, object[] args)        {            if (args.Length < 2)            {                return false;            }            if (double.TryParse(args[1].ToString(), out double value))            {                AxisKeyDown(args[0].ToString(), value);            }            else            {                EV.PostWarningLog($"{Module}.{Name}", eEvent.ERR_AXIS, $"{args[0]} value {args[1]}is not int value");            }            return true;        }        /// <summary>        /// 是否所有IO变量初始化完成        /// </summary>        /// <returns></returns>        private bool AllIoVariableInitialized()        {            foreach (string item in _variableInitializeDic.Keys)            {                if (!_variableInitializeDic[item])                {                    LOG.WriteLog(eEvent.ERR_DRYER, Module, $"{item} is not initialized");                    return false;                }            }            return true;        }        /// <summary>        /// 更新运动数据        /// </summary>        /// <param name="variable"></param>        /// <param name="value"></param>        private void UpdateMotionData(string variable, object value)        {            if(!MotionData.IsDataInitialized)            {                MotionData.IsDataInitialized = true;            }            PropertyInfo property = MotionData.GetType().GetProperty(variable);            if (property != null)            {                if (JudgeIsScale(variable))                {                    if (int.TryParse(value.ToString(), out int intValue))                    {                        if (JudgeSpeedRatio(variable))                        {                            property.SetValue(MotionData, CalculateValueAfterScale(CalculateDivideSpeedRatio(intValue)));                        }                        else if(JudgeAccelerationRation(variable))                        {                            property.SetValue(MotionData, CalculateValueAfterScale(CalculateMultiplyAccelerationRatio(intValue)));                        }                        else                        {                            if (variable == MOTOR_POSITION)                            {                                intValue = (int)Math.Round(intValue * _motionPositionRation,0);                            }                            property.SetValue(MotionData, CalculateValueAfterScale(intValue));                        }                    }                    else                    {                        property.SetValue(MotionData, value);                    }                                    }                else if(variable==ACTUAL_TORQUE)                {                    if (short.TryParse(value.ToString(), out short shortValue))                    {                        property.SetValue(MotionData, CalculateDivideTorqueRatio(shortValue));                    }                    else                    {                        property.SetValue(MotionData, value);                    }                }                else                {                    property.SetValue(MotionData, value);                }            }            if (variable == IS_SWITCH_ON)            {                _isSwitchOn = MotionData.IsSwitchOn;            }        }        /// <summary>        /// 判定是否需要比例计算        /// </summary>        /// <param name="variable"></param>        /// <returns></returns>        private bool JudgeIsScale(string variable)        {            switch (variable)            {                case ACTUAL_VELOCITY:                case PROFILE_VELOCITY:                case PROFILE_ACCEL:                case PROFILE_DECEL:                case MOTOR_POSITION:                case POSITION_ERROR:                                case TARGET_POSITION:                case HOMING_ACCEL:                case HOMING_VELOCITY:                case HOMING_VELOCITY_SLOW:                case HOME_OFFSET:                    return true;                default:                    return false;            }        }        /// <summary>        /// 判定是否需要速度调整比例        /// </summary>        /// <param name="variable"></param>        /// <returns></returns>        private bool JudgeSpeedRatio(string variable)        {            switch (variable)            {                case PROFILE_VELOCITY:                case ACTUAL_VELOCITY:                case HOMING_VELOCITY:                case HOMING_VELOCITY_SLOW:                case HOME_OFFSET:                    return true;                default:                    return false;            }        }        /// <summary>        /// 是否是加速度调整比例        /// </summary>        /// <param name="variable"></param>        /// <returns></returns>        protected bool JudgeAccelerationRation(string variable)        {            switch(variable)            {                case PROFILE_ACCEL:                case PROFILE_DECEL:                case HOMING_ACCEL:                    return true;                default:                    return false;            }        }        /// <summary>        /// motor position发生变化        /// </summary>        /// <param name="location"></param>        private void MotionPositionChanged(int location)        {            if(Math.Round(Math.Abs(location - _currentLocation)/_scaleFactor, 2)>0)            //if (Math.Abs(location - _currentLocation)/_scaleFactor >= _stationAxis.ToleranceDefault)            {                _currentLocation = location;                _runTime = DateTime.Now;                _isRun = true;            }        }        /// <summary>        /// 更新Digital Inputs        /// </summary>        /// <param name="digitalInputs"></param>        private void UpdateDigitalInputs(uint digitalInputs)        {            if (_isRevSensorLimit)            {                MotionData.RevLimited = !(((digitalInputs>>18) & 0x01) == 0x01);            }            if(_isForwardSensorLimit)            {                MotionData.FwdLimited = !(((digitalInputs >> 17) & 0x01) == 0x01);            }            MotionData.HomedSwitched =((digitalInputs>>22)&0x01) == 0x01;            if(!_isHomeSwitchedTrigger&&MotionData.HomedSwitched)            {                _isHomeSwitchedTrigger = true;            }        }        /// <summary>        /// 更新ManufactureStatus        /// </summary>        /// <param name="manufactureStatus"></param>        private void UpdateManufactureStatus(uint manufactureStatus)        {            MotionData.HomedSwitched = ((manufactureStatus >> 26)&0x01) == 0x01;            if (!_isHomeSwitchedTrigger && MotionData.HomedSwitched)            {                _isHomeSwitchedTrigger = true;            }        }        /// <summary>        /// 更新Torque Limited状态        /// </summary>        private void UpdateTorqueLimited()        {            if(MotionData.NegativeTorqueLimit!=0||MotionData.PositiveTorqueLimit!=0)            {                MotionData.TorqueLimited = (MotionData.ActualTorque >= -MotionData.NegativeTorqueLimit) && (MotionData.ActualTorque <= MotionData.PositiveTorqueLimit) ;            }            else            {                MotionData.TorqueLimited = true;            }        }        /// <summary>        /// 根据位置获取相应的Position数值        /// </summary>        /// <param name="station"></param>        /// <returns></returns>        public (bool success,double position) GetPositionByStation(string station)        {            foreach(Station item in _stationAxis.Stations)            {                if(item.Name.ToLower().EndsWith(station.ToLower()))                {                    if(double.TryParse(item.Position,out double position))                    {                        return (true, position);                    }                    else                    {                        return (false, 0);                    }                }            }            return (false, 0);        }        #endregion        #region protected 子类使用共用类,子类不再扩展        /// <summary>        /// 计算比例后的数值        /// </summary>        /// <param name="value"></param>        /// <returns></returns>        protected double CalculateValueAfterScale(int value)        {            if (_scaleFactor != 0)            {                return Math.Round((double)value / _scaleFactor, 2);            }            else            {                return (double)value;            }        }        /// <summary>        /// 确认操作状态        /// </summary>        /// <param name="operation"></param>        protected void ConfirmOperationState(MotionOperation operation)        {            if (_currentOperation == operation)            {                _status = RState.End;                EndOperation();            }        }        /// <summary>        /// 结束操作        /// </summary>        protected void EndOperation()        {            LOG.WriteLog(eEvent.INFO_AXIS,$"{Module}.{Name}", $"{Module}.{Name} execute {_currentOperation} complete");            _currentOperation = MotionOperation.None;            _targetPosition = 0;        }        /// <summary>        /// 订阅IO变量        /// </summary>        /// <param name="variable"></param>        public void AxisSubscribeUpdateVariable(string variable)        {            _variableInitializeDic[variable] = false;            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}.{Name}", variable, UpdateVariableValue);        }        /// <summary>        /// 更新变量数值        /// </summary>        /// <param name="variable"></param>        /// <param name="value"></param>        protected void UpdateVariableValue(string variable, object value)        {            if (value == null)            {                return;            }            if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])            {                _variableInitializeDic[variable] = true;            }            FirstStartUpWriteCOE(variable);            if (variable == MODE_OF_OPERATION)            {                if (_modeOfOperation == (byte)AxisModeOfOperation.None)                {                    byte.TryParse(value.ToString(), out _modeOfOperation);                }                else                {                    _modeOfOperation = (byte)value;                }            }            else if (variable == STATUS_WORD)            {                if (ushort.TryParse(value.ToString(), out _statusWord))                {                    MotionData.StatusWord = _statusWord;                    UpdateStatusWord(_statusWord);                }            }            else if (variable == CONTROL_WORD)            {                ushort.TryParse(value.ToString(), out _controlWord);            }            else if (variable == MOTOR_POSITION)            {                if (int.TryParse(value.ToString(), out int location))                {                    MotionPositionChanged(location);                    if (_axisConfig.ForwardSoftwareLimit != 0)                    {                        MotionData.ForwardSoftwareLimited = location > _axisConfig.ForwardSoftwareLimit-_axisConfig.HomingOffset;                        if (!_isForwardSensorLimit && !_isRevSensorLimit)                        {                            MotionData.FwdLimited = MotionData.ForwardSoftwareLimited;                        }                    }                    if (_axisConfig.ReverseSoftwareLimit != 0)                    {                        MotionData.ReverseSoftwareLimited = location < _axisConfig.ReverseSoftwareLimit-_axisConfig.HomingOffset;                        if (!_isRevSensorLimit && !_isForwardSensorLimit)                        {                            MotionData.RevLimited = MotionData.ReverseSoftwareLimited;                        }                    }                }            }            else if (variable == DIGITAL_INPUTS)            {                if (uint.TryParse(value.ToString(), out var uintValue))                {                    UpdateDigitalInputs(uintValue);                }            }            else if (variable == MANUF_STATUS)            {                if (uint.TryParse(value.ToString(), out var uintValue))                {                    UpdateManufactureStatus(uintValue);                }            }            UpdateMotionData(variable, value);            if (variable == MOTOR_POSITION)            {                CalculateCurrentStation(MotionData.MotorPosition);            }            if (variable == ACTUAL_TORQUE)            {                UpdateTorqueLimited();            }            else if (variable == POSITIVE_TORQUE_LIMIT || variable == NEGATIVE_TORQUE_LIMIT)            {                MotionData.TorqueLimit = $"-{MotionData.NegativeTorqueLimit}/+{MotionData.PositiveTorqueLimit}";            }            if(variable == FORWARD_LIMIT)            {                MotionData.FwdLimited = (bool)value;            }            if(variable == ACTUAL_VELOCITY)            {                MotionData.ActualVelocity = Math.Round((int)value / _scaleFactor / _velocityRate, 2);            }            if(variable == TARGET_POSITION)            {                MotionData.TargetPosition = Math.Round((int)value / _scaleFactor, 2);            }        }        /// <summary>        /// 监控(用于判定是否停止运动)        /// </summary>        protected void JudgeRunMonitor()        {            if (_isRun && DateTime.Now.Subtract(_runTime).TotalMilliseconds >= 1000)            {                _isRun = false;            }        }        #endregion        #region public 公开方法        /// <summary>        /// 初始化        /// </summary>        /// <returns></returns>        public bool Initialize()        {            SubscriptionVariable();            return true;        }        /// <summary>        /// 当前位置是否离目标位置不远        /// </summary>        /// <param name="targetPosition"></param>        /// <returns></returns>        public bool JudgeCurrentPositionIsInTargetPosition(int targetPosition)        {            double scaledTargetPosition = targetPosition /_scaleFactor;            double currentMotionPosition = MotionData.MotorPosition;            double delta = Math.Round(Math.Abs(currentMotionPosition - scaledTargetPosition), 2);            bool result = delta <= _stationAxis.ToleranceDefault;            return result;        }        /// <summary>        /// 计算乘以比例后的数值        /// </summary>        /// <param name="value"></param>        /// <returns></returns>        public int CalculateValueMultiplyScale(double value)        {            if (_scaleFactor != 0)            {                return (int)Math.Round(value * _scaleFactor, 0);            }            else            {                return (int)Math.Round(value, 0);            }        }        /// <summary>        /// 计算乘上速度比例后的速度        /// </summary>        /// <param name="speed"></param>        /// <returns></returns>        public int CalculateMultiplySpeedRatio(int speed)        {            return speed * _speedRatio;        }        /// <summary>        /// 计算乘上加速度比例后的加速度        /// </summary>        /// <param name="acceleration"></param>        /// <returns></returns>        public int CalculateMultiplyAccelerationRatio(int acceleration)        {            return acceleration * _accelerationRatio;        }        /// <summary>        /// 计算除以速度比例后的速度        /// </summary>        /// <param name="speed"></param>        /// <returns></returns>        public int CalculateDivideSpeedRatio(int speed)        {            return speed / _speedRatio;        }        /// <summary>        /// 计算除以加速度比例后的加速度        /// </summary>        /// <param name="acceleration"></param>        /// <returns></returns>        public int CalculateDivideAccelerationRatio(int acceleration)        {            return acceleration / _accelerationRatio;        }        /// <summary>        /// 计算除以Torque比例后的Torque        /// </summary>        /// <param name="speed"></param>        /// <returns></returns>        public double CalculateDivideTorqueRatio(int torque)        {            return Math.Round((double)torque / _torqueRatio, 2);                    }        /// <summary>        /// Jog Up        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        public bool JogUpPosition(string cmd, object[] args)        {            double jog=(double)args[1];            double currentPosition=MotionData.MotorPosition;            if(_jogLimit!=0)            {                if(jog>_jogLimit)                {                    LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Jog Value {jog} is over {_jogLimit}");                    return false;                }            }            if (!_isSwitchOn)            {                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Axis is switch off,cannot jog");                return false;            }            return ProfilePositionOperation(Math.Round(currentPosition + jog,2));        }        /// <summary>        /// Jog Down        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        public bool JogDownPosition(string cmd, object[] args)        {            double jog = (double)args[1];            double currentPosition = MotionData.MotorPosition;            if (_jogLimit != 0)            {                if (jog > _jogLimit)                {                    LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Jog Value {jog} is over {_jogLimit}");                    return false;                }            }            if(!_isSwitchOn)            {                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Axis is switch off,cannot jog");                return false;            }            return ProfilePositionOperation(Math.Round(currentPosition - jog,2));        }        /// <summary>        /// Profile position操作        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        public bool ProfilePositionOperation(double position)        {            _targetPosition = position;            int targetPosition = CalculateValueMultiplyScale(_targetPosition);            if (_axisConfig.ForwardSoftwareLimit != 0 && targetPosition > _axisConfig.ForwardSoftwareLimit - _axisConfig.HomingOffset)            {                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"target position {_targetPosition} is over forward limit");                return false;            }            if (_axisConfig.ReverseSoftwareLimit != 0 && targetPosition < _axisConfig.ReverseSoftwareLimit - _axisConfig.HomingOffset)            {                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"target position {_targetPosition} is less reverse limit");                return false;            }            bool result= ProfilePosition(targetPosition, _profileVelocity, _profileAcceleration, _profileDeceleration);            if (result)            {                MotionData.TargetPosition = _targetPosition;            }            return result;        }        /// <summary>        /// 移动至指定位置        /// </summary>        /// <param name="targetStation"></param>        /// <returns></returns>        public bool PositionStation(string targetStation,bool isHome=false,int velocity=0,int acceleration=0,int deceleration=0, bool judgeTorqueLimit = true)        {            if (!CheckPositionIsInStation(MotionData.MotorPosition,targetStation))            {                if(_interLock!=null&&!isHome&&!_interLock.CheckGotoPosition(targetStation))                {                    return false;                }                var result=GetPositionByStation(targetStation);                if(result.success)                {                    _targetPosition = result.position;                    int targetPosition = (int)Math.Round(result.position*_scaleFactor, 0);                    bool positionResult = false;                    if (velocity != 0)                    {                        positionResult= ProfilePosition(targetPosition, velocity, acceleration, deceleration, judgeTorqueLimit);                    }                    else                    {                        positionResult= ProfilePosition(targetPosition, _profileVelocity, _profileAcceleration, _profileDeceleration, judgeTorqueLimit);                    }                    if (positionResult)                    {                        MotionData.TargetPosition = _targetPosition;                    }                    return positionResult;                }                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"{targetStation} not in list,cannot goto fixed position");                return false;            }            else            {                _status = RState.End;            }            return true;        }        /// <summary>        /// 开始运动        /// </summary>        /// <returns></returns>        public bool WriteStartMotion()        {            bool result = StartMotion();            if (result)            {                _runTime = DateTime.Now;            }            return result;        }                /// <summary>        /// 检验GotoPosition条件        /// </summary>        /// <param name="station"></param>        public bool CheckGotoPosition(string station)        {            return _interLock.CheckGotoPosition(station);        }                /// <summary>        /// 检验当位Position是否在位置上        /// </summary>        /// <param name="position"></param>        /// <param name="stationName"></param>        /// <returns></returns>        public bool CheckPositionIsInStation(double position,string stationName)        {            foreach (Station station in _stationAxis.Stations)            {                string[] strAry = station.Name.Split('.');                if(strAry.Length == 0)                {                    continue;                }                if (strAry[strAry.Length-1].ToLower()==(stationName.ToLower()))                {                    if (double.TryParse(station.Position, out double value))                    {                        if (Math.Round(Math.Abs(position - value), 2) <= _stationAxis.ToleranceDefault)                        {                            return true;                        }                    }                }            }            return false;        }        /// <summary>        /// 检验电机已经完成了Homed        /// </summary>        /// <returns></returns>        public bool CheckAxisIsAreadyHomed()        {            if (!_isSwitchOn)            {                return false;            }            if (CheckPositionIsEmpty(MotionData.MotorPosition))            {                return false;            }            if (!_isHomed)            {                _isHomed = true;            }            return true;        }        /// <summary>        /// 检验位置(忽略WaferSize)        /// </summary>        /// <param name="position"></param>        /// <param name="stationName"></param>        /// <returns></returns>        public bool CheckPositionInStationIgnoreWaferSize(double position,string stationName)        {            foreach (Station station in _stationAxis.Stations)            {                if (station.Name.ToLower().Contains(stationName.ToLower()))                {                    if (double.TryParse(station.Position, out double value))                    {                        if (Math.Round(Math.Abs(position - value), 2) <= _stationAxis.ToleranceDefault)                        {                            return true;                        }                    }                }            }            return false;        }        /// <summary>        /// 检验位置是否为空        /// </summary>        /// <param name="position"></param>        /// <returns></returns>        public bool CheckPositionIsEmpty(double position)        {            foreach (Station station in _stationAxis.Stations)            {                if (double.TryParse(station.Position, out double value))                {                    if (Math.Round(Math.Abs(position - value), 2) <= _stationAxis.ToleranceDefault)                    {                        return false;                    }                }            }            return true;        }        /// <summary>        /// 更改速度百分比        /// </summary>        /// <param name="percent"></param>        /// <returns></returns>        public bool ChangePercentSpeedAceleration(int percent)        {            double percentSpeed = _initialVelocity * ((double)percent / 100);            double percentAceleration = _initialAcceleration * ((double)percent / 100);            double percentDeceleration = _initialDeceleration * ((double)percent / 100);            int changedSpeed = (int)(Math.Round(percentSpeed, 0));            int changedAcceleration = (int)(Math.Round(percentAceleration, 0));            int changedDeceleration = (int)(Math.Round(percentDeceleration, 0));            bool result = ChangeSpeedAcceleration(changedSpeed, changedAcceleration, changedDeceleration);            if (result)            {                _profileVelocity = changedSpeed;                _profileAcceleration = changedAcceleration;                _profileDeceleration = changedDeceleration;            }            return result;        }        /// <summary>        /// 设置速度        /// </summary>        /// <param name="speed"></param>        public void SetProfileSpeed(int speed)        {            _profileVelocity= speed;        }        #endregion        #region virtual共用方法,子类可实现更多方法        /// <summary>        /// Home共用方法        /// </summary>        /// <returns></returns>        public virtual bool Home()        {            if (!_isSwitchOn)            {                EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} switch off,cannot home");                return false;            }            if (_status == RState.Running)            {                EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} current execute {_currentOperation},cannot home");                return false;            }            _currentOperation = MotionOperation.Home;            _status = RState.Running;            return true;        }        /// <summary>        /// Home(isLogError)共用方法        /// </summary>        /// <returns></returns>        public virtual bool Home(bool isLogError)        {            if (!_isSwitchOn)            {                EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} switch off,cannot home");                return false;            }            if (_status == RState.Running)            {                EV.PostAlarmLog($"{Module}.{Name}", eEvent.ERR_PUF, $"{Module}.{Name} current execute {_currentOperation},cannot home");                return false;            }            _currentOperation = MotionOperation.Home;            _status = RState.Running;            return true;        }        /// <summary>        /// 首次启动写入COE线程        /// </summary>        public virtual void FirstStartUpWriteCOE(string variable)        {        }        /// <summary>        /// 启动写入COE线程        /// </summary>        public virtual void StartUpWriteCoeThread()        {        }        /// <summary>        /// 开始运动        /// </summary>        /// <returns></returns>        public virtual bool StartMotion()        {            return true;        }        #endregion        #region public abstract 子类实现方法        /// <summary>        /// 停止操作        /// </summary>        /// <param name="cmd"></param>        /// <param name="args"></param>        /// <returns></returns>        public abstract bool StopPositionOperation();        /// <summary>        /// change speed        /// </summary>        /// <param name="speed"></param>        /// <returns></returns>        public abstract bool ChangeSpeed(int speed);        /// <summary>        /// 改变速度加速度        /// </summary>        /// <param name="speed"></param>        /// <returns></returns>        public abstract bool ChangeSpeedAcceleration(int speed, int acceleration, int deceleration);        /// <summary>        /// Switch On        /// </summary>        public abstract bool SwitchOn();        /// <summary>        /// Switch Off        /// </summary>        public abstract bool SwitchOff();        /// <summary>        /// 停止        /// </summary>        public abstract void Stop();        /// <summary>        /// 定时器执行        /// </summary>        /// <returns></returns>        public abstract bool OnTimer();        /// <summary>        /// Profile operation        /// </summary>        /// <param name="targetPoint"></param>        /// <param name="profileVelocity"></param>        /// <param name="profileAcceleration"></param>        /// <param name="profileDeceleration"></param>        public abstract bool ProfilePosition(int targetPoint, int profileVelocity, int profileAcceleration, int profileDeceleration, bool judgeTorqueLimit = true);        #endregion        #region protected abstract 子类实现方法        /// <summary>        /// 初始化axis配置        /// </summary>        /// <returns></returns>        protected abstract AxisConfig InitializeAxisConfig();        /// <summary>        /// 初始化Routine        /// </summary>        protected abstract void InitializeRoutine();        /// <summary>        /// 初始化参数        /// </summary>        protected abstract void InitializeParameter();        /// <summary>        /// 更新状态字        /// </summary>        /// <param name="statusWord"></param>        public abstract void UpdateStatusWord(ushort statusWord);        /// <summary>        /// 回车输入        /// </summary>        /// <param name="arg"></param>        /// <param name="value"></param>        protected abstract void AxisKeyDown(string arg, double value);                /// <summary>        /// 订阅数据        /// </summary>        protected abstract void SubscriptionVariable();        #endregion        /// <summary>        /// 监控        /// </summary>        public void Monitor()        {        }        public void Reset()        {        }                /// 停止        /// </summary>        public void Terminate()        {        }    }}
 |