963 lines
43 KiB
C#
963 lines
43 KiB
C#
using Advantech.Motion;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Timers;
|
||
namespace ProductionControl.Device
|
||
{
|
||
public class AxisDev : IDisposable
|
||
{
|
||
public enum AxisStateType
|
||
{
|
||
[Description("轴状态")]
|
||
AxisState = 0,
|
||
[Description("轴运动状态")]
|
||
AxisMotionState = 1,
|
||
[Description("轴IO状态")]
|
||
AxisIOState = 2,
|
||
}
|
||
|
||
public Action<int, AxisStateType, uint> axisStateEvent;
|
||
public enum AxisPosType
|
||
{
|
||
[Description("命令位置")]
|
||
CmdPos = 0,
|
||
[Description("反馈位置")]
|
||
ActualPos = 1,
|
||
}
|
||
public Action<int, AxisPosType, double> axisPosEvent;
|
||
/// <summary> 使用
|
||
/// 轴状态(AxisState 0-14) 单一值,无需按位取
|
||
/// STA_AxDisable -- 轴被禁用,用户可打开并激活
|
||
/// STA_AxReady ---- 轴已准备就绪,等待新的命令 *
|
||
/// STA_Stopping ---- 轴停止
|
||
/// STA_AxErrorStop --- 出现错误,轴停止
|
||
/// STA_AxHoming ---- 轴正在执行返回原点运动
|
||
/// STA_AxPtpMotion ---- 轴正在执行PTP 运动
|
||
/// STA_AxContiMotion ---- 轴正在执行连续运动
|
||
/// STA_AxSyncMotion --- 轴在一个群组中,群组正在执行插补运动;或轴是一个从轴,正在执行Ecam/E-gear/Gantry 运动。
|
||
/// STA_AX_EXT_JOG -- 轴由外部信号控制。当外部信号激活时,轴将执行JOG 模式运动。
|
||
/// STA_AX_EXT_MPG --- 轴由外部信号控制。当外部信号激活时,轴将执行MPG 模式运动
|
||
/// </summary>
|
||
//public Action<int, int> axisStateEvent;
|
||
|
||
/// <summary>
|
||
/// 轴运动状态 使用
|
||
/// 位 说明
|
||
/// Stop ---- 停止
|
||
/// WaitERC---- 等待ERC 完成
|
||
/// InFA ---- 处于特定速度中 = FA
|
||
/// InFL ---- 处于低速中 = FL
|
||
/// InACC ---- 加速中
|
||
/// InFH ---- 处于最大速度中 = FH
|
||
/// InDEC ---- 减速中
|
||
/// WaitINP---- 到位等待
|
||
/// </summary>
|
||
//public Action<int, int> axisMotionStateEvent;
|
||
/// <summary>
|
||
/// 轴IO状态 (Ax_Motion_IO) 使用
|
||
/// RDY---- RDY 针脚输入
|
||
/// ALM ---- 报警信号输入 *
|
||
/// LMT+ ---- 限位开关+ *
|
||
/// LMT- ---- 限位开关- *
|
||
/// ORG---- 原始开关 *
|
||
/// DIR ---- DIR 输出
|
||
/// EMG ---- 紧急信号输入
|
||
/// EZ ---- 编码器 Z 信号
|
||
/// INP ---- 到位信号输入
|
||
/// SVON ---- 伺服开启(OUT6) *
|
||
/// ALRM ---- 报警复位输出状态
|
||
/// SLMT+ ---- 软件限位+
|
||
/// SLMT- ---- 软件限位-
|
||
/// CMP----- 比较信号(OUT5)
|
||
/// </summary>
|
||
//public Action<int, bool, bool, bool, bool> axisIOStateEvent;
|
||
|
||
public Action<WarningEnum, string> WarningEvent;
|
||
|
||
/// <summary>
|
||
/// 设备列表(多张PCI板卡)
|
||
/// </summary>
|
||
public List<DEV_LIST> DevList { get; private set; }
|
||
/// <summary>
|
||
/// 设备数量
|
||
/// </summary>
|
||
//private uint deviceCount = 0;
|
||
/// <summary>
|
||
/// 设备号,用于打开设备(非索引)
|
||
/// </summary>
|
||
//public uint DeviceNum { get; private set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 设备句柄
|
||
/// </summary>
|
||
private IntPtr m_DeviceHandle = IntPtr.Zero;
|
||
/// <summary>
|
||
/// 轴数量
|
||
/// </summary>
|
||
private uint m_ulAxisCount = 0;
|
||
private IntPtr[] m_Axishand = new IntPtr[0];
|
||
public double[] CmdPos { get; private set; } = new double[32];//轴命令位置
|
||
public double[] ActualPos { get; private set; } = new double[32];//轴实际(反馈)位置
|
||
|
||
public UInt16[] AxState { get; private set; } = new UInt16[32];//轴状态
|
||
public UInt32[] IOStatus { get; private set; } = new UInt32[32];//轴IO状态
|
||
public uint[] AxMotionState { get; private set; } = new uint[32];//轴运动状态
|
||
|
||
private uint[] AxEnableEvtArray = new uint[32];
|
||
private uint[] GpEnableEvt = new uint[32];
|
||
/// <summary>
|
||
/// 组
|
||
/// </summary>
|
||
//private IntPtr m_GpHand = IntPtr.Zero;
|
||
|
||
/// <summary>
|
||
/// 断电后设备必需复位
|
||
/// </summary>
|
||
public bool IsReset { private set; get; }=false;
|
||
public bool IsDebug = false;
|
||
/// <summary>
|
||
/// 是否打开设备成功
|
||
/// </summary>
|
||
public bool IsInit { get; private set; } = false;
|
||
Thread checkEventThread;
|
||
private System.Timers.Timer timer = new System.Timers.Timer();
|
||
|
||
/// <summary>
|
||
/// 获取设备列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
/// <exception cref="Exception"></exception>
|
||
//public static List<DEV_LIST> getDevList()
|
||
//{
|
||
// DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
|
||
// uint deviceCount = 0;
|
||
// int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
|
||
// if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
|
||
// throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);
|
||
|
||
// return curAvailableDevs.ToList().Take((int)deviceCount).ToList();
|
||
//}
|
||
public AxisDev()
|
||
{
|
||
//初始化
|
||
DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
|
||
uint deviceCount = 0;
|
||
int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
|
||
if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
|
||
throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);
|
||
DevList = curAvailableDevs.ToList().Take((int)deviceCount).ToList();
|
||
}
|
||
public void Dispose()
|
||
{
|
||
stop();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开设备
|
||
/// </summary>
|
||
/// <exception cref="Exception"></exception>
|
||
public bool start(int[] AxisPulseOutMode,bool debug=false)
|
||
{
|
||
if (DevList == null || DevList.Count < 1)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "Axis设备为空!");
|
||
return false;
|
||
}
|
||
|
||
return start(DevList[0].DeviceNum, AxisPulseOutMode, debug);
|
||
}
|
||
int[] AxisPulseOutMode=new int[4];
|
||
public bool start(uint DeviceNum,int[] AxisPulseOutMode, bool debug = false)
|
||
{
|
||
try
|
||
{
|
||
if (IsInit) return true;
|
||
bALM = bEMG = bLMTP = bLMTN = false;
|
||
|
||
//打开设备
|
||
uint uResult = Motion.mAcm_DevOpen(DeviceNum, ref m_DeviceHandle);
|
||
if (uResult != (int)ErrorCode.SUCCESS)
|
||
throw new Exception("Open Device Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
|
||
IsDebug = debug;
|
||
IsReset = false;
|
||
//读取轴数量
|
||
uResult = Motion.mAcm_GetU32Property(m_DeviceHandle, (uint)PropertyID.FT_DevAxesCount, ref m_ulAxisCount);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Get Axis Number Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
m_Axishand = new IntPtr[m_ulAxisCount];
|
||
|
||
//打开轴
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
//打开每个轴并获得每个轴句柄
|
||
uResult = Motion.mAcm_AxOpen(m_DeviceHandle, (UInt16)i, ref m_Axishand[i]);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Open Axis Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
|
||
//判断与打开电源使能,1: On
|
||
if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) == 0)
|
||
{
|
||
uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 1);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
}
|
||
}
|
||
//根据加载的文件设置设备的所有配置(需在打开每个轴 mAcm_AxSetSvOn 后设置)
|
||
string cfgPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\Axis_" + DeviceNum + ".cfg";
|
||
if (File.Exists(cfgPath))
|
||
{
|
||
uResult = Motion.mAcm_DevLoadConfig(m_DeviceHandle, cfgPath);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Load Config Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
}
|
||
|
||
Thread.Sleep(500);
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
//先读取每个轴状态(进行报警)
|
||
this.refreshAxisState(i);
|
||
|
||
//每个轴的初始属性(reset 命令位置和实际(反馈)位置)
|
||
//double cmdPosition = new double();
|
||
//cmdPosition = 0;
|
||
//为指定的轴设置命令位置
|
||
//Motion.mAcm_AxSetCmdPosition(m_Axishand[i], cmdPosition);
|
||
//为指定的轴设置实际(反馈)位置
|
||
//Motion.mAcm_AxSetActualPosition(m_Axishand[i], cmdPosition);
|
||
|
||
//set Axis PulseOutMode
|
||
if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
|
||
throw new Exception($"Axis{i} 设置脉冲模式失败!");
|
||
|
||
this.AxisPulseOutMode = AxisPulseOutMode;
|
||
//Event
|
||
AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_MOTION_DONE; //运动完成(减速直至停止)
|
||
//AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_START; //轴加速到运行速度时
|
||
//AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_END;//轴运行速度结束时,开始减速
|
||
AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_HOME_DONE;
|
||
AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_ERROR;
|
||
|
||
//初次获取轴的运动I/O状态。
|
||
this.refreshAxisState(i);
|
||
}
|
||
|
||
uResult = Motion.mAcm_EnableMotionEvent(m_DeviceHandle, AxEnableEvtArray, GpEnableEvt, m_ulAxisCount, 3);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("EnableMotionEvent Filed With Error Code[0x" + Convert.ToString(uResult, 16) + "]");
|
||
|
||
IsInit = true;
|
||
timer.Elapsed += Timer_Elapsed;
|
||
timer.Interval = 100;
|
||
timer.Start();
|
||
|
||
//用户应该创建一个新的线程来检查事件状态,例如:CheckEvtThread()函数
|
||
checkEventThread = new Thread(new ThreadStart(checkEvtThread));
|
||
checkEventThread.Start();
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, ex.Message);
|
||
stop();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭设备
|
||
/// </summary>
|
||
/// <exception cref="Exception"></exception>
|
||
public bool stop()
|
||
{
|
||
try
|
||
{
|
||
if (!IsInit) return false;
|
||
|
||
uint i;
|
||
for (i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.Low, i + "轴处于ErrorStop状态,已重置!");
|
||
//重置轴的状态。如果轴处于ErrorStop状态,则调用此函数后状态将更改为Ready
|
||
Motion.mAcm_AxResetError(m_Axishand[i]);
|
||
}
|
||
// 命令轴减速停止(缓停)
|
||
Motion.mAcm_AxStopDec(m_Axishand[i]);
|
||
|
||
//sleep? 关闭电源使能,1: On
|
||
uint uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 0);
|
||
if (uResult != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
|
||
}
|
||
//删除组中的所有轴并关闭组句柄
|
||
//Motion.mAcm_GpClose(ref m_GpHand);
|
||
//m_GpHand = IntPtr.Zero;
|
||
|
||
for (i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
//Close Axes
|
||
Motion.mAcm_AxClose(ref m_Axishand[i]);
|
||
}
|
||
|
||
timer.Elapsed -= Timer_Elapsed;
|
||
m_ulAxisCount = 0;
|
||
//Close Device
|
||
Motion.mAcm_DevClose(ref m_DeviceHandle);
|
||
m_DeviceHandle = IntPtr.Zero;
|
||
IsInit = false;
|
||
timer.Stop();
|
||
return true;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 轴事件
|
||
/// </summary>
|
||
private void checkEvtThread()
|
||
{
|
||
uint Result;
|
||
UInt32[] AxEvtStatusArray = new UInt32[32];
|
||
UInt32[] GpEvtStatusArray = new UInt32[32];
|
||
UInt32 i;
|
||
while (IsInit)
|
||
{
|
||
//如果你想获得轴或组的事件状态,你应该通过调用 Motion.mAcm_EnableMotionEvent 来启用这些事件
|
||
//AxEvtStatusArray[n],返回每个轴的中断事件状态,n 表示运动设备的轴个数
|
||
//GpEnableEvtArrayy[n]:返回每个群组的中断事件状态
|
||
//AxArrayElements U32 IN AxEvtStatusArray 中元素个数
|
||
//GpArrayElements U32 IN GpEvtStatusArray 中元素个数
|
||
//Millisecond U32 IN 设定每次Check 事件时的等待时间
|
||
Result = Motion.mAcm_CheckMotionEvent(m_DeviceHandle, AxEvtStatusArray, GpEvtStatusArray, m_ulAxisCount, 0, 1000);//3,10
|
||
if (Result == (uint)ErrorCode.SUCCESS)
|
||
{
|
||
for (i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_MOTION_DONE) > 0)
|
||
{
|
||
this.refreshAxisState((int)i);//更新AXIS状态
|
||
}
|
||
if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_START) > 0)
|
||
{
|
||
this.refreshAxisState((int)i);//更新AXIS状态
|
||
}
|
||
if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_END) > 0)
|
||
{
|
||
this.refreshAxisState((int)i);//更新AXIS状态
|
||
}
|
||
if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_HOME_DONE) > 0)
|
||
{
|
||
this.refreshAxisState((int)i);//更新AXIS状态
|
||
WarningEvent?.Invoke(WarningEnum.Normal, $"轴{i}回原点完成;当前命令位置:{CmdPos[i]},反馈位置:{ActualPos[i]}.");
|
||
//回原点后反馈位置未归0则置0 //重置后会自动重新更新状态
|
||
if (CmdPos[i] != 0) this.resetCmdPosition((int)i);
|
||
if (ActualPos[i] != 0) this.resetActualPosition((int)i);
|
||
}
|
||
if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_ERROR) > 0)
|
||
{
|
||
this.refreshAxisState((int)i);//更新AXIS状态
|
||
}
|
||
|
||
}
|
||
//if (m_GpHand != IntPtr.Zero)
|
||
//{
|
||
// if (textBoxGpID.Text != "")
|
||
// {
|
||
// if ((GpEvtStatusArray[0] & ((uint)EventType.EVT_GP1_MOTION_DONE << Convert.ToByte(textBoxGpID.Text))) > 0)
|
||
// {
|
||
// m_GpDoneEvtCnt++;
|
||
// }
|
||
// if ((GpEvtStatusArray[1] & ((uint)EventType.EVT_GP1_VH_START << Convert.ToByte(textBoxGpID.Text))) > 0)
|
||
// {
|
||
// m_GpVHStartCnt++;
|
||
// }
|
||
// if ((GpEvtStatusArray[2] & ((uint)EventType.EVT_GP1_VH_END << Convert.ToByte(textBoxGpID.Text))) > 0)
|
||
// {
|
||
// m_GpVHEndCnt++;
|
||
// }
|
||
// }
|
||
//}
|
||
}
|
||
}
|
||
}
|
||
|
||
public bool isReady(int axisIndex = -1)
|
||
{
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
|
||
if (AxState[i] != (uint)AxisState.STA_AX_READY)
|
||
{
|
||
if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
|
||
{
|
||
var errCode = Motion.mAcm_GetLastError(m_Axishand[i]);
|
||
StringBuilder sb = new StringBuilder(512);
|
||
if (!Motion.mAcm_GetErrorMessage(errCode, sb, 511))
|
||
sb = new StringBuilder("未知错误!");
|
||
WarningEvent?.Invoke(WarningEnum.High, $"轴{i}运行错误,错误码({errCode},错误信息:{sb.ToString().Trim()})");
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
public bool isError(int axisIndex = -1)
|
||
{
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
|
||
if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
|
||
return true;
|
||
|
||
//
|
||
if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0
|
||
|| (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0
|
||
|| (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0
|
||
|| (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0)
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
/// <summary>
|
||
/// 缓停,jog时用
|
||
/// </summary>
|
||
public void stopDec(int axisIndex = -1)
|
||
{
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxStopDec(m_Axishand[i]);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 急停
|
||
/// </summary>
|
||
public void stopNow(int axisIndex = -1)
|
||
{
|
||
if (!IsInit) return;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxStopEmg(m_Axishand[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
public void resetAxisState(int axisIndex=-1)
|
||
{
|
||
if (!IsInit) return;
|
||
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
|
||
{
|
||
//重置轴的状态。如果轴处于ErrorStop状态,则调用此函数后状态将更改为Ready
|
||
bALM = bEMG = bLMTP = bLMTN = false;
|
||
Motion.mAcm_AxResetError(m_Axishand[i]);
|
||
refreshAxisState(i);
|
||
}
|
||
// 命令轴减速停止(缓停)
|
||
Motion.mAcm_AxStopDec(m_Axishand[i]);
|
||
}
|
||
}
|
||
|
||
}
|
||
/// <summary>
|
||
/// 指定的轴设置命令位置
|
||
/// </summary>
|
||
public void resetCmdPosition(int axisIndex = -1, double position = 0)
|
||
{
|
||
if (!IsInit) return;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxSetCmdPosition(m_Axishand[i], position);
|
||
this.refreshAxisState(i);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 指定的轴设置实际(反馈)位置
|
||
/// </summary>
|
||
public void resetActualPosition(int axisIndex=-1, double position = 0)
|
||
{
|
||
if (!IsInit) return;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
Motion.mAcm_AxSetActualPosition(m_Axishand[i], position);
|
||
this.refreshAxisState(i);
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取速度 [vellow,velhigh,acc,dec,Jerk]
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <returns></returns>
|
||
public double[] getAxisVelParam(int axisIndex)
|
||
{
|
||
double[] value=new double[5];
|
||
Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelLow, ref value[0]);
|
||
Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelHigh, ref value[1]);
|
||
Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxAcc, ref value[2]);
|
||
Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxDec, ref value[3]);
|
||
Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxJerk, ref value[4]);//0-T/S 型曲线
|
||
return value;
|
||
}
|
||
/// <summary>
|
||
/// 速度设置 注:运动的过程中可变速度,加速度和减速度需使用AxChangeVelEx方法
|
||
/// </summary>
|
||
/// <param name="velLow">起始速度</param>
|
||
/// <param name="high">运行速度</param>
|
||
/// <param name="acc">加速度</param>
|
||
/// <param name="dec">减速度</param>
|
||
/// <param name="axisIndex"></param>
|
||
/// <param name="isJogOrHome">true 不行,回HOME也是false</param>
|
||
public void setAxisVelParam(double velLow, double high = 0, double acc = 0, double dec = 0, int axisIndex = -1,bool isJogOrHome=false)
|
||
{
|
||
uint result;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
if (!isJogOrHome)
|
||
{
|
||
if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
|
||
continue;
|
||
if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
|
||
if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
|
||
if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
|
||
if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
|
||
result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxJerk, 0);//0-T/S 型曲线
|
||
}
|
||
else
|
||
{
|
||
if ((AxisState)AxState[i] != AxisState.STA_AX_EXT_JOG)
|
||
continue;
|
||
if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
|
||
if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
|
||
if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
|
||
if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
|
||
result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogJerk, 0);//0-T/S 型曲线
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 回HOME
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <param name="homeMode">16种回HOME模式(0-15)</param>
|
||
/// <param name="dir">0-正向 1-负向</param>
|
||
/// <exception cref="Exception"></exception>
|
||
public void home(int axisIndex = -1, uint homeMode = 11, uint dir = 1)
|
||
{
|
||
if (!IsInit) return;
|
||
if (Config.HeightDevIOState)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
|
||
return;
|
||
}
|
||
|
||
//研华运动控制卡共提供两个函数执行回Home: Acm_AxHome 和Acm_AxMoveHome
|
||
//调用Acm_AxHome 执行回Home 时,通过PAR_AxVelLow、PAR_AxVelHigh、PAR_AxAcc、 PAR_AxDec、PAR_AxJerk 设置初速度,运行速度、加速度、减速度、速度曲线类型。
|
||
//调用Acm_AxMoveHome 执行回Home 时,通过PAR_AxHomeVelLow、PAR_AxHomeVelHigh、 PAR_AxHomeAcc、PAR_AxHomeDec、PAR_AxHomeJerk 设置初速度,运行速度、加速度、 减速度、速度曲线类型。
|
||
uint result;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (isSkip(axisIndex)) continue;
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
|
||
continue;
|
||
|
||
if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
|
||
throw new Exception($"Axis{i} 设置脉冲模式失败!");
|
||
|
||
//单独设置GO HOME 速度参数??
|
||
|
||
//
|
||
result = Motion.mAcm_AxHome(m_Axishand[i], homeMode, dir);
|
||
if (result != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("AxHome Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]");
|
||
}
|
||
}
|
||
|
||
//复位
|
||
//if (axisIndex == -1 && !IsDebug && !IsReset)
|
||
// IsReset = true;
|
||
if (!IsDebug && !IsReset)
|
||
IsReset = true;
|
||
}
|
||
/// <summary>
|
||
/// 点到点运动
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <param name="pos">PPU位置,方向为正负值</param>
|
||
/// <param name="moveMode"></param>
|
||
public bool move_ptp(int axisIndex, double pos, AxMoveMode moveMode)
|
||
{
|
||
if (isSkip(axisIndex)) return true;
|
||
if (!IsInit) return false;
|
||
if (isError(axisIndex)) return false;
|
||
if (Config.HeightDevIOState)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
|
||
return false;
|
||
}
|
||
|
||
pos = toPulse(pos, Config.Axis_MM2PulseNum[axisIndex]);
|
||
|
||
uint result;
|
||
if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
|
||
return false;
|
||
|
||
if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex]))
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 设置脉冲模式失败!");
|
||
return false;
|
||
}
|
||
|
||
//--
|
||
if (moveMode==AxMoveMode.绝对位置) //Start single axis's absolute position motion.
|
||
result = Motion.mAcm_AxMoveAbs(m_Axishand[axisIndex], pos);
|
||
else //Start single axis's relative position motion
|
||
result = Motion.mAcm_AxMoveRel(m_Axishand[axisIndex], pos);
|
||
if (result != (uint)ErrorCode.SUCCESS)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "PTP Move Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
/// <summary>
|
||
/// 判断是否正在动动
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <returns></returns>
|
||
public bool isMoveing(int axisIndex = -1)
|
||
{
|
||
if (!IsInit) return false;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
AxisState state = (AxisState)AxState[i];
|
||
if (state == AxisState.STA_AX_PTP_MOT || state == AxisState.STA_AX_HOMING || state == AxisState.STA_AX_CONTI_MOT)
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
/// <summary>
|
||
/// 设置脉冲模式
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <param name="outMode"></param>
|
||
/// <returns></returns>
|
||
private bool setPulseOutMode(int axisIndex, AxisPulseOutMode outMode)
|
||
{
|
||
uint refOutMode = 0;
|
||
//先获取再判断
|
||
uint result = Motion.mAcm_GetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, ref refOutMode);// 获取输出模式
|
||
if (result != (uint)ErrorCode.SUCCESS)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Get Axis{axisIndex} Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]");
|
||
return false;
|
||
}
|
||
if ((uint)outMode != refOutMode)
|
||
{
|
||
//设置脉冲模式
|
||
result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, (uint)outMode);
|
||
if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
#region JOG
|
||
public void openJogMode(int axisIndex)
|
||
{
|
||
if (!IsInit) return;
|
||
if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
|
||
return;
|
||
|
||
if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex]))
|
||
throw new Exception($"Axis{axisIndex} 设置脉冲模式失败!");
|
||
|
||
uint result;
|
||
//启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode 2: MPG Mode
|
||
result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 0);
|
||
result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 1);
|
||
if (result != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Start external driver Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
|
||
//设置外部驱动器的输入引脚
|
||
//0 轴 0(默认值) 仅支持 0
|
||
//1 轴 1(不支持)
|
||
//2 轴 2(不支持)
|
||
//3 轴 3(不支持)
|
||
result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtMasterSrc, 0);
|
||
if (result != (uint)ErrorCode.SUCCESS)
|
||
throw new Exception("Set Property-AxExtMasterSrc Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
|
||
//当启用外部驱动时。此属性允许通过数字输入通道选择驱动轴
|
||
result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtSelEnable, 1);
|
||
if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
|
||
throw new Exception("Set Property-AxExtSelEnable Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
|
||
//理论脉冲数
|
||
result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtPulseNum, 1000);
|
||
if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
|
||
throw new Exception("Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
|
||
|
||
//外部设置
|
||
//setAxisVelParam(velLow, high, acc, dec, axisIndex, true);
|
||
this.refreshAxisState(axisIndex);
|
||
}
|
||
public void closeJogMode(int axisIndex = -1)
|
||
{
|
||
if (!IsInit) return;
|
||
|
||
uint result;
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
{
|
||
if (i == axisIndex || axisIndex == -1)
|
||
{
|
||
if ((AxisState)AxState[i] == AxisState.STA_AX_EXT_JOG)
|
||
{
|
||
//启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode 2: MPG Mode
|
||
result = Motion.mAcm_AxSetExtDrive(m_Axishand[i], 0);
|
||
//命令轴减速停止
|
||
result = Motion.mAcm_AxStopDec(m_Axishand[i]);
|
||
this.refreshAxisState(i);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// jog运行
|
||
/// </summary>
|
||
/// <param name="axisIndex"></param>
|
||
/// <param name="dic">0:正向,1:负向</param>
|
||
public void jog(int axisIndex, ushort dic)
|
||
{
|
||
if (isSkip(axisIndex)) return;
|
||
if (isError(axisIndex)) return;
|
||
if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_EXT_JOG) return;
|
||
if (Config.HeightDevIOState)
|
||
{
|
||
WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
|
||
return;
|
||
}
|
||
//Jog 运动的方向,0:正向,1:负向
|
||
Motion.mAcm_AxJog(m_Axishand[axisIndex], dic);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Private
|
||
private bool isSkip(int axisIndex)
|
||
{
|
||
if (axisIndex == 0 && Config.SkipAxis0) return true;
|
||
if (axisIndex == 1 && Config.SkipAxis1) return true;
|
||
if (axisIndex == 2 && Config.SkipAxis2) return true;
|
||
if (axisIndex == 3 && Config.SkipAxis3) return true;
|
||
return false;
|
||
}
|
||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||
{
|
||
if (!IsInit) return;
|
||
|
||
for (int i = 0; i < m_ulAxisCount; i++)
|
||
refreshAxisState(i);
|
||
}
|
||
private bool bALM, bEMG, bLMTP, bLMTN;
|
||
private void refreshAxisState(int axisIndex)
|
||
{
|
||
//uint result;
|
||
//获取指定轴的当前命令位置
|
||
if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetCmdPosition(m_Axishand[axisIndex], ref CmdPos[axisIndex]))
|
||
axisPosEvent?.Invoke(axisIndex, AxisPosType.CmdPos, tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]));
|
||
//获取指定轴的当前实际(反馈)位置
|
||
if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetActualPosition(m_Axishand[axisIndex], ref ActualPos[axisIndex]))
|
||
axisPosEvent?.Invoke(axisIndex, AxisPosType.ActualPos, tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]) );
|
||
|
||
//获取Axis的当前状态
|
||
if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetState(m_Axishand[axisIndex], ref AxState[axisIndex]))
|
||
axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisState, AxState[axisIndex]);
|
||
//log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisState = {((AxisState)AxState[AxisIndex]).ToString()}");
|
||
|
||
//获取轴的运动I/O状态。
|
||
if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionIO(m_Axishand[axisIndex], ref IOStatus[axisIndex]))
|
||
{
|
||
bool isStopNow = false;
|
||
if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0) //ALM报警状态 需IO close (流程上必需在报警清除后先复位)
|
||
{
|
||
if (!isStopNow)
|
||
{
|
||
isStopNow = true;
|
||
stopNow();//ALM报警需急停
|
||
}
|
||
if (!bALM)
|
||
{
|
||
bALM = true;
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} ALM报警!!!");
|
||
}
|
||
}
|
||
if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0) //EMG急停状态 需重置 state (流程上必需在报警清除后先复位)
|
||
{
|
||
if (!isStopNow)
|
||
{
|
||
isStopNow = true;
|
||
stopNow();//EMG状态需急停
|
||
}
|
||
if (!bEMG)
|
||
{
|
||
bEMG = true;
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发EMG急停!!!");
|
||
}
|
||
}
|
||
//右极限 true->false (流程上必需在报警清除后先复位)
|
||
if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING)
|
||
{
|
||
if (!isStopNow)
|
||
{
|
||
isStopNow = true;
|
||
stopNow();//右极限状态需急停
|
||
}
|
||
if (!bLMTP)
|
||
{
|
||
bLMTP = true;
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发右极限LMTP!!!");
|
||
}
|
||
}
|
||
//左极限 true->false (流程上必需在报警清除后先复位)
|
||
if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING)
|
||
{
|
||
if (!isStopNow)
|
||
{
|
||
isStopNow = true;
|
||
stopNow();//左极限状态需急停
|
||
}
|
||
if (!bLMTN)
|
||
{
|
||
bLMTN = true;
|
||
WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发左极限LMTN!!!");
|
||
}
|
||
}
|
||
////ORG 回原点
|
||
//if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0)
|
||
//{
|
||
// WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发ORG信号!");
|
||
//}
|
||
////EZ 回原点
|
||
//if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EZ) > 0)
|
||
//{
|
||
// WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发EZ信号!");
|
||
//}
|
||
|
||
axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisIOState, IOStatus[axisIndex]);
|
||
//log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionIO = {((Ax_Motion_IO)IOStatus[AxisIndex]).ToString()}");
|
||
//checkMotionIOStatus(AxisIndex, IOStatus[AxisIndex]);
|
||
}
|
||
|
||
//获取Axis的当前运动状态
|
||
if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionStatus(m_Axishand[axisIndex], ref AxMotionState[axisIndex]))
|
||
axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisMotionState, AxMotionState[axisIndex]);
|
||
//log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionStatus = {AxMotionState[AxisIndex].ToString()}");
|
||
}
|
||
|
||
//private void checkMotionIOStatus(int axisIndex, uint IOStatus)
|
||
//{
|
||
// if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0)//报警信号输出
|
||
// log?.Invoke(2, $"轴{axisIndex} 发出告警!!");
|
||
|
||
// bool ALM = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0;
|
||
// bool ORG = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0;//ORG
|
||
// bool EL_R = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0;//右极限
|
||
// bool EL_L = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0;//-EL 左
|
||
// bool SVON = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) > 0;
|
||
//}
|
||
|
||
private string getErrInfo(uint errorCode)
|
||
{
|
||
StringBuilder ErrorMsg = new StringBuilder("", 100);
|
||
//Get the error message according to error code returned from API
|
||
Boolean res = Motion.mAcm_GetErrorMessage(errorCode, ErrorMsg, 100);
|
||
if (res) return ErrorMsg.ToString();
|
||
return "获取错误信息失败!";
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="pulseVal"></param>
|
||
/// <param name="mmPulse"></param>
|
||
/// <returns></returns>
|
||
public double tomm(double pulseVal, double pulse)
|
||
{
|
||
return (pulseVal / pulse);
|
||
}
|
||
/// <summary>
|
||
/// mm转脉冲
|
||
/// </summary>
|
||
/// <param name="mm"></param>
|
||
/// <param name="mmPulse">1mm 对应 脉冲数</param>
|
||
/// <returns></returns>
|
||
private double toPulse(double mm, double mmPulse)
|
||
{
|
||
return (mm * mmPulse);
|
||
}
|
||
public double getCmdPos_mm(int axisIndex)
|
||
{
|
||
return tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
|
||
}
|
||
public double getActualPos_mm(int axisIndex)
|
||
{
|
||
return tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
}
|
||
}
|
||
|