banboshi_V1/halftoneproject-master/AssistClient/Device/AxisDev.cs
2023-10-31 13:19:29 +08:00

963 lines
43 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 AssistClient.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;
}
DeviceNum = DevList[0].DeviceNum;
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) + "]");
//先读取每个轴状态
this.refreshAxisState(i);
//判断与打开电源使能,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]);
if (errCode != 0)
{
StringBuilder sb = new StringBuilder(512);
if (!Motion.mAcm_GetErrorMessage(errCode, sb, 511))
sb = new StringBuilder("未知错误!");
string errStr = $"轴{i}运行错误,错误码({errCode},错误信息:{sb.ToString().Trim()})";
WarningEvent?.Invoke(WarningEnum.High, errStr);
throw new Exception(errStr);
}
else
{
throw new Exception($"轴{i}运行错误,当前状态:{((AxisState)AxState[i]).ToString()}");
}
}
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;
//研华运动控制卡共提供两个函数执行回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;
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.MODE1_Abs) //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运行 0正向1负向
/// </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;
//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
}
}