banboshi_V1/halftoneproject-master/Code/Device/AxisDev.cs

963 lines
43 KiB
C#
Raw Normal View History

2023-10-31 13:19:29 +08:00
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
}
}