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 axisStateEvent; public enum AxisPosType { [Description("命令位置")] CmdPos = 0, [Description("反馈位置")] ActualPos = 1, } public Action axisPosEvent; /// 使用 /// 轴状态(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 模式运动 /// //public Action axisStateEvent; /// /// 轴运动状态 使用 /// 位 说明 /// Stop ---- 停止 /// WaitERC---- 等待ERC 完成 /// InFA ---- 处于特定速度中 = FA /// InFL ---- 处于低速中 = FL /// InACC ---- 加速中 /// InFH ---- 处于最大速度中 = FH /// InDEC ---- 减速中 /// WaitINP---- 到位等待 /// //public Action axisMotionStateEvent; /// /// 轴IO状态 (Ax_Motion_IO) 使用 /// RDY---- RDY 针脚输入 /// ALM ---- 报警信号输入 * /// LMT+ ---- 限位开关+ * /// LMT- ---- 限位开关- * /// ORG---- 原始开关 * /// DIR ---- DIR 输出 /// EMG ---- 紧急信号输入 /// EZ ---- 编码器 Z 信号 /// INP ---- 到位信号输入 /// SVON ---- 伺服开启(OUT6) * /// ALRM ---- 报警复位输出状态 /// SLMT+ ---- 软件限位+ /// SLMT- ---- 软件限位- /// CMP----- 比较信号(OUT5) /// //public Action axisIOStateEvent; public Action WarningEvent; /// /// 设备列表(多张PCI板卡) /// public List DevList { get; private set; } /// /// 设备数量 /// //private uint deviceCount = 0; /// /// 设备号,用于打开设备(非索引) /// //public uint DeviceNum { get; private set; } = 0; /// /// 设备句柄 /// private IntPtr m_DeviceHandle = IntPtr.Zero; /// /// 轴数量 /// 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]; /// /// 组 /// //private IntPtr m_GpHand = IntPtr.Zero; /// /// 断电后设备必需复位 /// public bool IsReset { private set; get; }=false; public bool IsDebug = false; /// /// 是否打开设备成功 /// public bool IsInit { get; private set; } = false; Thread checkEventThread; private System.Timers.Timer timer = new System.Timers.Timer(); /// /// 获取设备列表 /// /// /// //public static 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(); } /// /// 打开设备 /// /// 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; } } /// /// 关闭设备 /// /// 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; } } /// /// 轴事件 /// 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; } /// /// 缓停,jog时用 /// 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]); } } } /// /// 急停 /// 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]); } } } /// /// 指定的轴设置命令位置 /// 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); } } } /// /// 指定的轴设置实际(反馈)位置 /// 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); } } } /// /// 获取速度 [vellow,velhigh,acc,dec,Jerk] /// /// /// 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; } /// /// 速度设置 注:运动的过程中可变速度,加速度和减速度需使用AxChangeVelEx方法 /// /// 起始速度 /// 运行速度 /// 加速度 /// 减速度 /// /// true 不行,回HOME也是false 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 型曲线 } } } } /// /// 回HOME /// /// /// 16种回HOME模式(0-15) /// 0-正向 1-负向 /// 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; } /// /// 点到点运动 /// /// /// PPU位置,方向为正负值 /// 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; } /// /// 判断是否正在动动 /// /// /// 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; } /// /// 设置脉冲模式 /// /// /// /// 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); } } } } /// /// jog运行 /// /// /// 0:正向,1:负向 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 "获取错误信息失败!"; } /// /// /// /// /// /// public double tomm(double pulseVal, double pulse) { return (pulseVal / pulse); } /// /// mm转脉冲 /// /// /// 1mm 对应 脉冲数 /// 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 } }