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;
}
}
}