using Aitex.Common.Util; using Aitex.Core.Util; using MECF.Framework.Common.Device.Galil; using System; using System.Collections.Generic; using System.IO; using System.Threading; namespace MECF.Framework.Common.Simulator { /// /// 电机运动模拟器 /// public class MotorSimulator : Singleton { #region 常量 private const string TARGET_VELOCITY = "TargetVelocity"; private const string TARGET_ACCEL = "TargetAcceleration"; private const string TARGET_DECEL = "TargetDeceleration"; private const string TARGET_POSITION = "TargetPosition"; private const string SWITCH_SIGNAL = "SwitchSignal"; private const string ACTUAL_POSITION = "ActualPosition"; private const string AUXILIARY_POSITION = "AuxiliaryPosition"; private const string HOMING_SIGNAL = "HomingSignal"; private const string MOTION_SIGNAL = "MotionSignal"; private const string STOP_SIGNAL = "StopSignal"; /// /// 定时器间隔(ms) /// private const int TIMER_INTERVAL = 10; /// /// motor step factor /// private const int MOTOR_STEP_FACTOR = 10; #endregion #region 内部变量 /// /// 定时器 /// private PeriodicJob _periodicJob; /// /// 电机数据字典(key:Name(module.name),value:Datas) /// private Dictionary _motorNameDataDic = new Dictionary(); #endregion #region 属性 #endregion //delegate #region Delegate public delegate void UpdateVariableValueChanged(Dictionary datasDic); #endregion #region 事件 /// /// 变量变更事件 /// public event UpdateVariableValueChanged OnUpdateVariableValueChanged; #endregion /// /// 初始化 /// public void Initialize() { _periodicJob = new PeriodicJob(TIMER_INTERVAL, OnTimer, "Motor Simulator Timer", true); Init(); } /// /// 初始化数据 /// private void Init() { ////加载对应配置文件 GalilControllerCfg-Simulator.xml,初始化数据字典 string oldXmlPath = PathManager.GetCfgDir(); string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\GalilControllerCfg-Simulator.xml"; GalilControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath)); foreach (GalilDeviceConfig config in cfg.GalilDeviceConfigs) { foreach (GalilAxisConfig item in config.GalilAxises) { _motorNameDataDic[$"{config.Module}.{item.Name}"] = new SimulatorMotionData(); _motorNameDataDic[$"{config.Module}.{item.Name}"].FwdSoftLimit = item.ForwardSoftwareLimit; _motorNameDataDic[$"{config.Module}.{item.Name}"].RevSoftLimit = item.ReverseSoftwareLimit; _motorNameDataDic[$"{config.Module}.{item.Name}"].NegativeTorqueLimit = item.NegativeTorqueLimit; _motorNameDataDic[$"{config.Module}.{item.Name}"].PositiveTorqueLimit = item.PositiveTorqueLimit; } } } /// /// 定时器执行 /// /// private bool OnTimer() { //电机运动模型 foreach(var motorItem in _motorNameDataDic) { //对应电机进行模拟 MotorMotionSimulator(motorItem); } //实时更新电机数据 UpdateVariableValue(_motorNameDataDic); return true; } /// /// 通知Galil模块数据变化 /// /// private void UpdateVariableValue(Dictionary datasDic) { if (OnUpdateVariableValueChanged != null) { OnUpdateVariableValueChanged(datasDic); } } /// /// 设置电机数据 /// /// /// /// public void SetMotionData(string axisName, string type, object value) { switch (type) { case TARGET_VELOCITY: _motorNameDataDic[axisName].TargetVelocity = (int)value; break; case TARGET_ACCEL: _motorNameDataDic[axisName].TargetAccel = (int)value; break; case TARGET_DECEL: _motorNameDataDic[axisName].TargetDecel = (int)value; break; case TARGET_POSITION: _motorNameDataDic[axisName].TargetPosition = (int)value; break; case ACTUAL_POSITION: _motorNameDataDic[axisName].ActualPosition = (int)value; break; case SWITCH_SIGNAL: _motorNameDataDic[axisName].SwitchSignal = (bool)value; break; case STOP_SIGNAL: _motorNameDataDic[axisName].StopSignal = true; break; case HOMING_SIGNAL: _motorNameDataDic[axisName].HomingSignal = true; break; case MOTION_SIGNAL: _motorNameDataDic[axisName].MotionSignal = true; break; case AUXILIARY_POSITION: //++ break; default: break; } } /// /// 运动模拟器 /// private void MotorMotionSimulator(KeyValuePair motor) { SimulatorMotionData motionData = motor.Value; //上电检查 if (!motionData.SwitchSignal) return; if (motionData.HomingSignal) { HomeOperation(motionData); } else { PositionOperation(motionData); } } /// /// Home操作 /// /// private void HomeOperation(SimulatorMotionData motionData) { if (motionData.MotionSignal) { motionData.StopCode = 10;//HM操作停止码10 motionData.MotionSignal = false; motionData.HomingSignal = false; motionData.MotionPhase = MotionPhase.Accelerating; //motionData.ActualPosition = 0; motionData.ActualVelocity = 0; } } /// /// GoToPosition操作 /// /// private void PositionOperation(SimulatorMotionData motionData) { if (motionData.MotionSignal) { //正向运动 int motorStep = Math.Abs(motionData.ActualPosition - motionData.TargetPosition); //motionData.ActualVelocity = TrapezoidalSpeedControl(motionData); motionData.ActualVelocity = motionData.TargetVelocity; if (motionData.ActualPosition < motionData.TargetPosition) { //motionData.ActualPosition += (motionData.ActualVelocity * TIMER_INTERVAL / 1000); motionData.ActualPosition += (motorStep / MOTOR_STEP_FACTOR < 1 ? 1 : motorStep / MOTOR_STEP_FACTOR); bool fwdLimit = motionData.FwdSoftLimit != 0 ? motionData.ActualPosition >= motionData.FwdSoftLimit : false; if (fwdLimit || motionData.ActualPosition >= motionData.TargetPosition) { motionData.StopCode = 1;//正常运动停止码1 motionData.MotionSignal = false; //motionData.MotionPhase = MotionPhase.Accelerating; motionData.ActualPosition = fwdLimit ? motionData.FwdSoftLimit : motionData.TargetPosition; motionData.ActualVelocity = 0; } } //反向运动 else if (motionData.ActualPosition > motionData.TargetPosition) { motionData.ActualPosition -= (motorStep / MOTOR_STEP_FACTOR < 1 ? 1 : motorStep / MOTOR_STEP_FACTOR); //motionData.ActualPosition -= (motionData.ActualVelocity * TIMER_INTERVAL / 1000); bool revLimit = motionData.RevSoftLimit != 0 ? motionData.ActualPosition <= motionData.RevSoftLimit : false; if (revLimit || motionData.ActualPosition <= motionData.TargetPosition) { motionData.StopCode = 1;//正常运动停止码1 motionData.MotionSignal = false; //motionData.MotionPhase = MotionPhase.Accelerating; motionData.ActualPosition = revLimit ? motionData.RevSoftLimit : motionData.TargetPosition; motionData.ActualVelocity = 0; } } } //停止信号 if (motionData.StopSignal) { motionData.MotionSignal = false; motionData.StopCode = 4;//ST操作停止码4 motionData.StopSignal = false; } } /// /// 梯形加减速运动控制 /// private int TrapezoidalSpeedControl(SimulatorMotionData data) { int speed = 0; //制动距离 int brakeDistance = (data.ActualVelocity * data.ActualVelocity) / (2 * data.TargetDecel); int remainingDistance = Math.Abs(data.ActualPosition - data.TargetPosition); if (brakeDistance >= remainingDistance) { data.MotionPhase = MotionPhase.Decelerating; } else if (data.ActualVelocity < data.TargetVelocity && data.MotionPhase != MotionPhase.Decelerating) { data.MotionPhase = MotionPhase.Accelerating; } else { data.MotionPhase = MotionPhase.ConstantSpeed; } // 速度更新 switch (data.MotionPhase) { case MotionPhase.Accelerating: speed = Math.Min(data.ActualVelocity + data.TargetAccel * TIMER_INTERVAL / 1000, data.TargetVelocity); break; case MotionPhase.ConstantSpeed: speed = data.TargetVelocity; break; case MotionPhase.Decelerating: //speed = Math.Max(data.ActualVelocity - data.TargetDecel * TIMER_INTERVAL / 1000, 10); speed = Math.Max(data.ActualVelocity / 100, 10); break; } return speed; } } }