版博士V2.0程序
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

963 Zeilen
43 KiB

  1. using Advantech.Motion;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Security.Cryptography;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using System.Timers;
  13. namespace ProductionControl.Device
  14. {
  15. public class AxisDev : IDisposable
  16. {
  17. public enum AxisStateType
  18. {
  19. [Description("轴状态")]
  20. AxisState = 0,
  21. [Description("轴运动状态")]
  22. AxisMotionState = 1,
  23. [Description("轴IO状态")]
  24. AxisIOState = 2,
  25. }
  26. public Action<int, AxisStateType, uint> axisStateEvent;
  27. public enum AxisPosType
  28. {
  29. [Description("命令位置")]
  30. CmdPos = 0,
  31. [Description("反馈位置")]
  32. ActualPos = 1,
  33. }
  34. public Action<int, AxisPosType, double> axisPosEvent;
  35. /// <summary> 使用
  36. /// 轴状态(AxisState 0-14) 单一值,无需按位取
  37. /// STA_AxDisable -- 轴被禁用,用户可打开并激活
  38. /// STA_AxReady ---- 轴已准备就绪,等待新的命令 *
  39. /// STA_Stopping ---- 轴停止
  40. /// STA_AxErrorStop --- 出现错误,轴停止
  41. /// STA_AxHoming ---- 轴正在执行返回原点运动
  42. /// STA_AxPtpMotion ---- 轴正在执行PTP 运动
  43. /// STA_AxContiMotion ---- 轴正在执行连续运动
  44. /// STA_AxSyncMotion --- 轴在一个群组中,群组正在执行插补运动;或轴是一个从轴,正在执行Ecam/E-gear/Gantry 运动。
  45. /// STA_AX_EXT_JOG -- 轴由外部信号控制。当外部信号激活时,轴将执行JOG 模式运动。
  46. /// STA_AX_EXT_MPG --- 轴由外部信号控制。当外部信号激活时,轴将执行MPG 模式运动
  47. /// </summary>
  48. //public Action<int, int> axisStateEvent;
  49. /// <summary>
  50. /// 轴运动状态 使用
  51. /// 位 说明
  52. /// Stop ---- 停止
  53. /// WaitERC---- 等待ERC 完成
  54. /// InFA ---- 处于特定速度中 = FA
  55. /// InFL ---- 处于低速中 = FL
  56. /// InACC ---- 加速中
  57. /// InFH ---- 处于最大速度中 = FH
  58. /// InDEC ---- 减速中
  59. /// WaitINP---- 到位等待
  60. /// </summary>
  61. //public Action<int, int> axisMotionStateEvent;
  62. /// <summary>
  63. /// 轴IO状态 (Ax_Motion_IO) 使用
  64. /// RDY---- RDY 针脚输入
  65. /// ALM ---- 报警信号输入 *
  66. /// LMT+ ---- 限位开关+ *
  67. /// LMT- ---- 限位开关- *
  68. /// ORG---- 原始开关 *
  69. /// DIR ---- DIR 输出
  70. /// EMG ---- 紧急信号输入
  71. /// EZ ---- 编码器 Z 信号
  72. /// INP ---- 到位信号输入
  73. /// SVON ---- 伺服开启(OUT6) *
  74. /// ALRM ---- 报警复位输出状态
  75. /// SLMT+ ---- 软件限位+
  76. /// SLMT- ---- 软件限位-
  77. /// CMP----- 比较信号(OUT5)
  78. /// </summary>
  79. //public Action<int, bool, bool, bool, bool> axisIOStateEvent;
  80. public Action<WarningEnum, string> WarningEvent;
  81. /// <summary>
  82. /// 设备列表(多张PCI板卡)
  83. /// </summary>
  84. public List<DEV_LIST> DevList { get; private set; }
  85. /// <summary>
  86. /// 设备数量
  87. /// </summary>
  88. //private uint deviceCount = 0;
  89. /// <summary>
  90. /// 设备号,用于打开设备(非索引)
  91. /// </summary>
  92. //public uint DeviceNum { get; private set; } = 0;
  93. /// <summary>
  94. /// 设备句柄
  95. /// </summary>
  96. private IntPtr m_DeviceHandle = IntPtr.Zero;
  97. /// <summary>
  98. /// 轴数量
  99. /// </summary>
  100. private uint m_ulAxisCount = 0;
  101. private IntPtr[] m_Axishand = new IntPtr[0];
  102. public double[] CmdPos { get; private set; } = new double[32];//轴命令位置
  103. public double[] ActualPos { get; private set; } = new double[32];//轴实际(反馈)位置
  104. public UInt16[] AxState { get; private set; } = new UInt16[32];//轴状态
  105. public UInt32[] IOStatus { get; private set; } = new UInt32[32];//轴IO状态
  106. public uint[] AxMotionState { get; private set; } = new uint[32];//轴运动状态
  107. private uint[] AxEnableEvtArray = new uint[32];
  108. private uint[] GpEnableEvt = new uint[32];
  109. /// <summary>
  110. /// 组
  111. /// </summary>
  112. //private IntPtr m_GpHand = IntPtr.Zero;
  113. /// <summary>
  114. /// 断电后设备必需复位
  115. /// </summary>
  116. public bool IsReset { private set; get; }=false;
  117. public bool IsDebug = false;
  118. /// <summary>
  119. /// 是否打开设备成功
  120. /// </summary>
  121. public bool IsInit { get; private set; } = false;
  122. Thread checkEventThread;
  123. private System.Timers.Timer timer = new System.Timers.Timer();
  124. /// <summary>
  125. /// 获取设备列表
  126. /// </summary>
  127. /// <returns></returns>
  128. /// <exception cref="Exception"></exception>
  129. //public static List<DEV_LIST> getDevList()
  130. //{
  131. // DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
  132. // uint deviceCount = 0;
  133. // int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
  134. // if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
  135. // throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);
  136. // return curAvailableDevs.ToList().Take((int)deviceCount).ToList();
  137. //}
  138. public AxisDev()
  139. {
  140. //初始化
  141. DEV_LIST[] curAvailableDevs = new DEV_LIST[Motion.MAX_DEVICES];
  142. uint deviceCount = 0;
  143. int Result = Motion.mAcm_GetAvailableDevs(curAvailableDevs, Motion.MAX_DEVICES, ref deviceCount);
  144. if (Result != (int)ErrorCode.SUCCESS || curAvailableDevs.Length < 1)
  145. throw new Exception("Get Device Numbers Failed With Error Code: [0x" + Convert.ToString(Result, 16) + "] DevCount=" + curAvailableDevs.Length);
  146. DevList = curAvailableDevs.ToList().Take((int)deviceCount).ToList();
  147. }
  148. public void Dispose()
  149. {
  150. stop();
  151. }
  152. /// <summary>
  153. /// 打开设备
  154. /// </summary>
  155. /// <exception cref="Exception"></exception>
  156. public bool start(int[] AxisPulseOutMode,bool debug=false)
  157. {
  158. if (DevList == null || DevList.Count < 1)
  159. {
  160. WarningEvent?.Invoke(WarningEnum.High, "Axis设备为空!");
  161. return false;
  162. }
  163. return start(DevList[0].DeviceNum, AxisPulseOutMode, debug);
  164. }
  165. int[] AxisPulseOutMode=new int[4];
  166. public bool start(uint DeviceNum,int[] AxisPulseOutMode, bool debug = false)
  167. {
  168. try
  169. {
  170. if (IsInit) return true;
  171. bALM = bEMG = bLMTP = bLMTN = false;
  172. //打开设备
  173. uint uResult = Motion.mAcm_DevOpen(DeviceNum, ref m_DeviceHandle);
  174. if (uResult != (int)ErrorCode.SUCCESS)
  175. throw new Exception("Open Device Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  176. IsDebug = debug;
  177. IsReset = false;
  178. //读取轴数量
  179. uResult = Motion.mAcm_GetU32Property(m_DeviceHandle, (uint)PropertyID.FT_DevAxesCount, ref m_ulAxisCount);
  180. if (uResult != (uint)ErrorCode.SUCCESS)
  181. throw new Exception("Get Axis Number Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  182. m_Axishand = new IntPtr[m_ulAxisCount];
  183. //打开轴
  184. for (int i = 0; i < m_ulAxisCount; i++)
  185. {
  186. //打开每个轴并获得每个轴句柄
  187. uResult = Motion.mAcm_AxOpen(m_DeviceHandle, (UInt16)i, ref m_Axishand[i]);
  188. if (uResult != (uint)ErrorCode.SUCCESS)
  189. throw new Exception("Open Axis Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  190. //判断与打开电源使能,1: On
  191. if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) == 0)
  192. {
  193. uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 1);
  194. if (uResult != (uint)ErrorCode.SUCCESS)
  195. throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  196. }
  197. }
  198. //根据加载的文件设置设备的所有配置(需在打开每个轴 mAcm_AxSetSvOn 后设置)
  199. string cfgPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\Axis_" + DeviceNum + ".cfg";
  200. if (File.Exists(cfgPath))
  201. {
  202. uResult = Motion.mAcm_DevLoadConfig(m_DeviceHandle, cfgPath);
  203. if (uResult != (uint)ErrorCode.SUCCESS)
  204. throw new Exception("Load Config Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  205. }
  206. Thread.Sleep(500);
  207. for (int i = 0; i < m_ulAxisCount; i++)
  208. {
  209. //先读取每个轴状态(进行报警)
  210. this.refreshAxisState(i);
  211. //每个轴的初始属性(reset 命令位置和实际(反馈)位置)
  212. //double cmdPosition = new double();
  213. //cmdPosition = 0;
  214. //为指定的轴设置命令位置
  215. //Motion.mAcm_AxSetCmdPosition(m_Axishand[i], cmdPosition);
  216. //为指定的轴设置实际(反馈)位置
  217. //Motion.mAcm_AxSetActualPosition(m_Axishand[i], cmdPosition);
  218. //set Axis PulseOutMode
  219. if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
  220. throw new Exception($"Axis{i} 设置脉冲模式失败!");
  221. this.AxisPulseOutMode = AxisPulseOutMode;
  222. //Event
  223. AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_MOTION_DONE; //运动完成(减速直至停止)
  224. //AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_START; //轴加速到运行速度时
  225. //AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_VH_END;//轴运行速度结束时,开始减速
  226. AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_HOME_DONE;
  227. AxEnableEvtArray[i] |= (uint)EventType.EVT_AX_ERROR;
  228. //初次获取轴的运动I/O状态。
  229. this.refreshAxisState(i);
  230. }
  231. uResult = Motion.mAcm_EnableMotionEvent(m_DeviceHandle, AxEnableEvtArray, GpEnableEvt, m_ulAxisCount, 3);
  232. if (uResult != (uint)ErrorCode.SUCCESS)
  233. throw new Exception("EnableMotionEvent Filed With Error Code[0x" + Convert.ToString(uResult, 16) + "]");
  234. IsInit = true;
  235. timer.Elapsed += Timer_Elapsed;
  236. timer.Interval = 100;
  237. timer.Start();
  238. //用户应该创建一个新的线程来检查事件状态,例如:CheckEvtThread()函数
  239. checkEventThread = new Thread(new ThreadStart(checkEvtThread));
  240. checkEventThread.Start();
  241. return true;
  242. }
  243. catch (Exception ex)
  244. {
  245. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  246. stop();
  247. return false;
  248. }
  249. }
  250. /// <summary>
  251. /// 关闭设备
  252. /// </summary>
  253. /// <exception cref="Exception"></exception>
  254. public bool stop()
  255. {
  256. try
  257. {
  258. if (!IsInit) return false;
  259. uint i;
  260. for (i = 0; i < m_ulAxisCount; i++)
  261. {
  262. if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
  263. {
  264. WarningEvent?.Invoke(WarningEnum.Low, i + "轴处于ErrorStop状态,已重置!");
  265. //重置轴的状态。如果轴处于ErrorStop状态,则调用此函数后状态将更改为Ready
  266. Motion.mAcm_AxResetError(m_Axishand[i]);
  267. }
  268. // 命令轴减速停止(缓停)
  269. Motion.mAcm_AxStopDec(m_Axishand[i]);
  270. //sleep? 关闭电源使能,1: On
  271. uint uResult = Motion.mAcm_AxSetSvOn(m_Axishand[i], 0);
  272. if (uResult != (uint)ErrorCode.SUCCESS)
  273. throw new Exception("Servo On Failed With Error Code: [0x" + Convert.ToString(uResult, 16) + "]");
  274. }
  275. //删除组中的所有轴并关闭组句柄
  276. //Motion.mAcm_GpClose(ref m_GpHand);
  277. //m_GpHand = IntPtr.Zero;
  278. for (i = 0; i < m_ulAxisCount; i++)
  279. {
  280. //Close Axes
  281. Motion.mAcm_AxClose(ref m_Axishand[i]);
  282. }
  283. timer.Elapsed -= Timer_Elapsed;
  284. m_ulAxisCount = 0;
  285. //Close Device
  286. Motion.mAcm_DevClose(ref m_DeviceHandle);
  287. m_DeviceHandle = IntPtr.Zero;
  288. IsInit = false;
  289. timer.Stop();
  290. return true;
  291. }
  292. catch (Exception e)
  293. {
  294. return false;
  295. }
  296. }
  297. /// <summary>
  298. /// 轴事件
  299. /// </summary>
  300. private void checkEvtThread()
  301. {
  302. uint Result;
  303. UInt32[] AxEvtStatusArray = new UInt32[32];
  304. UInt32[] GpEvtStatusArray = new UInt32[32];
  305. UInt32 i;
  306. while (IsInit)
  307. {
  308. //如果你想获得轴或组的事件状态,你应该通过调用 Motion.mAcm_EnableMotionEvent 来启用这些事件
  309. //AxEvtStatusArray[n],返回每个轴的中断事件状态,n 表示运动设备的轴个数
  310. //GpEnableEvtArrayy[n]:返回每个群组的中断事件状态
  311. //AxArrayElements U32 IN AxEvtStatusArray 中元素个数
  312. //GpArrayElements U32 IN GpEvtStatusArray 中元素个数
  313. //Millisecond U32 IN 设定每次Check 事件时的等待时间
  314. Result = Motion.mAcm_CheckMotionEvent(m_DeviceHandle, AxEvtStatusArray, GpEvtStatusArray, m_ulAxisCount, 0, 1000);//3,10
  315. if (Result == (uint)ErrorCode.SUCCESS)
  316. {
  317. for (i = 0; i < m_ulAxisCount; i++)
  318. {
  319. if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_MOTION_DONE) > 0)
  320. {
  321. this.refreshAxisState((int)i);//更新AXIS状态
  322. }
  323. if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_START) > 0)
  324. {
  325. this.refreshAxisState((int)i);//更新AXIS状态
  326. }
  327. if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_VH_END) > 0)
  328. {
  329. this.refreshAxisState((int)i);//更新AXIS状态
  330. }
  331. if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_HOME_DONE) > 0)
  332. {
  333. this.refreshAxisState((int)i);//更新AXIS状态
  334. WarningEvent?.Invoke(WarningEnum.Normal, $"轴{i}回原点完成;当前命令位置:{CmdPos[i]},反馈位置:{ActualPos[i]}.");
  335. //回原点后反馈位置未归0则置0 //重置后会自动重新更新状态
  336. if (CmdPos[i] != 0) this.resetCmdPosition((int)i);
  337. if (ActualPos[i] != 0) this.resetActualPosition((int)i);
  338. }
  339. if ((AxEvtStatusArray[i] & (uint)EventType.EVT_AX_ERROR) > 0)
  340. {
  341. this.refreshAxisState((int)i);//更新AXIS状态
  342. }
  343. }
  344. //if (m_GpHand != IntPtr.Zero)
  345. //{
  346. // if (textBoxGpID.Text != "")
  347. // {
  348. // if ((GpEvtStatusArray[0] & ((uint)EventType.EVT_GP1_MOTION_DONE << Convert.ToByte(textBoxGpID.Text))) > 0)
  349. // {
  350. // m_GpDoneEvtCnt++;
  351. // }
  352. // if ((GpEvtStatusArray[1] & ((uint)EventType.EVT_GP1_VH_START << Convert.ToByte(textBoxGpID.Text))) > 0)
  353. // {
  354. // m_GpVHStartCnt++;
  355. // }
  356. // if ((GpEvtStatusArray[2] & ((uint)EventType.EVT_GP1_VH_END << Convert.ToByte(textBoxGpID.Text))) > 0)
  357. // {
  358. // m_GpVHEndCnt++;
  359. // }
  360. // }
  361. //}
  362. }
  363. }
  364. }
  365. public bool isReady(int axisIndex = -1)
  366. {
  367. for (int i = 0; i < m_ulAxisCount; i++)
  368. {
  369. if (isSkip(axisIndex)) continue;
  370. if (i == axisIndex || axisIndex == -1)
  371. {
  372. Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
  373. if (AxState[i] != (uint)AxisState.STA_AX_READY)
  374. {
  375. if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
  376. {
  377. var errCode = Motion.mAcm_GetLastError(m_Axishand[i]);
  378. StringBuilder sb = new StringBuilder(512);
  379. if (!Motion.mAcm_GetErrorMessage(errCode, sb, 511))
  380. sb = new StringBuilder("未知错误!");
  381. WarningEvent?.Invoke(WarningEnum.High, $"轴{i}运行错误,错误码({errCode},错误信息:{sb.ToString().Trim()})");
  382. }
  383. return false;
  384. }
  385. }
  386. }
  387. return true;
  388. }
  389. public bool isError(int axisIndex = -1)
  390. {
  391. for (int i = 0; i < m_ulAxisCount; i++)
  392. {
  393. if (isSkip(axisIndex)) continue;
  394. if (i == axisIndex || axisIndex == -1)
  395. {
  396. Motion.mAcm_AxGetState(m_Axishand[i], ref AxState[i]);
  397. if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
  398. return true;
  399. //
  400. if ((IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0
  401. || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0
  402. || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0
  403. || (IOStatus[i] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0)
  404. return true;
  405. }
  406. }
  407. return false;
  408. }
  409. /// <summary>
  410. /// 缓停,jog时用
  411. /// </summary>
  412. public void stopDec(int axisIndex = -1)
  413. {
  414. for (int i = 0; i < m_ulAxisCount; i++)
  415. {
  416. if (i == axisIndex || axisIndex == -1)
  417. {
  418. Motion.mAcm_AxStopDec(m_Axishand[i]);
  419. }
  420. }
  421. }
  422. /// <summary>
  423. /// 急停
  424. /// </summary>
  425. public void stopNow(int axisIndex = -1)
  426. {
  427. if (!IsInit) return;
  428. for (int i = 0; i < m_ulAxisCount; i++)
  429. {
  430. if (i == axisIndex || axisIndex == -1)
  431. {
  432. Motion.mAcm_AxStopEmg(m_Axishand[i]);
  433. }
  434. }
  435. }
  436. public void resetAxisState(int axisIndex=-1)
  437. {
  438. if (!IsInit) return;
  439. for (int i = 0; i < m_ulAxisCount; i++)
  440. {
  441. if (isSkip(axisIndex)) continue;
  442. if (i == axisIndex || axisIndex == -1)
  443. {
  444. if (AxState[i] == (uint)AxisState.STA_AX_ERROR_STOP)
  445. {
  446. //重置轴的状态。如果轴处于ErrorStop状态,则调用此函数后状态将更改为Ready
  447. bALM = bEMG = bLMTP = bLMTN = false;
  448. Motion.mAcm_AxResetError(m_Axishand[i]);
  449. refreshAxisState(i);
  450. }
  451. // 命令轴减速停止(缓停)
  452. Motion.mAcm_AxStopDec(m_Axishand[i]);
  453. }
  454. }
  455. }
  456. /// <summary>
  457. /// 指定的轴设置命令位置
  458. /// </summary>
  459. public void resetCmdPosition(int axisIndex = -1, double position = 0)
  460. {
  461. if (!IsInit) return;
  462. for (int i = 0; i < m_ulAxisCount; i++)
  463. {
  464. if (isSkip(axisIndex)) continue;
  465. if (i == axisIndex || axisIndex == -1)
  466. {
  467. Motion.mAcm_AxSetCmdPosition(m_Axishand[i], position);
  468. this.refreshAxisState(i);
  469. }
  470. }
  471. }
  472. /// <summary>
  473. /// 指定的轴设置实际(反馈)位置
  474. /// </summary>
  475. public void resetActualPosition(int axisIndex=-1, double position = 0)
  476. {
  477. if (!IsInit) return;
  478. for (int i = 0; i < m_ulAxisCount; i++)
  479. {
  480. if (isSkip(axisIndex)) continue;
  481. if (i == axisIndex || axisIndex == -1)
  482. {
  483. Motion.mAcm_AxSetActualPosition(m_Axishand[i], position);
  484. this.refreshAxisState(i);
  485. }
  486. }
  487. }
  488. /// <summary>
  489. /// 获取速度 [vellow,velhigh,acc,dec,Jerk]
  490. /// </summary>
  491. /// <param name="axisIndex"></param>
  492. /// <returns></returns>
  493. public double[] getAxisVelParam(int axisIndex)
  494. {
  495. double[] value=new double[5];
  496. Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelLow, ref value[0]);
  497. Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxVelHigh, ref value[1]);
  498. Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxAcc, ref value[2]);
  499. Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxDec, ref value[3]);
  500. Motion.mAcm_GetF64Property(m_Axishand[axisIndex], (uint)PropertyID.PAR_AxJerk, ref value[4]);//0-T/S 型曲线
  501. return value;
  502. }
  503. /// <summary>
  504. /// 速度设置 注:运动的过程中可变速度,加速度和减速度需使用AxChangeVelEx方法
  505. /// </summary>
  506. /// <param name="velLow">起始速度</param>
  507. /// <param name="high">运行速度</param>
  508. /// <param name="acc">加速度</param>
  509. /// <param name="dec">减速度</param>
  510. /// <param name="axisIndex"></param>
  511. /// <param name="isJogOrHome">true 不行,回HOME也是false</param>
  512. public void setAxisVelParam(double velLow, double high = 0, double acc = 0, double dec = 0, int axisIndex = -1,bool isJogOrHome=false)
  513. {
  514. uint result;
  515. for (int i = 0; i < m_ulAxisCount; i++)
  516. {
  517. if (i == axisIndex || axisIndex == -1)
  518. {
  519. if (!isJogOrHome)
  520. {
  521. if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
  522. continue;
  523. if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
  524. if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
  525. if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
  526. if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
  527. result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.PAR_AxJerk, 0);//0-T/S 型曲线
  528. }
  529. else
  530. {
  531. if ((AxisState)AxState[i] != AxisState.STA_AX_EXT_JOG)
  532. continue;
  533. if (velLow > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelLow, toPulse(velLow, Config.Axis_MM2PulseNum[i]));
  534. if (high > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogVelHigh, toPulse(high, Config.Axis_MM2PulseNum[i]));
  535. if (acc > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogAcc, toPulse(acc, Config.Axis_MM2PulseNum[i]));
  536. if (dec > 0) result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogDec, toPulse(dec, Config.Axis_MM2PulseNum[i]));
  537. result = Motion.mAcm_SetF64Property(m_Axishand[i], (uint)PropertyID.CFG_AxJogJerk, 0);//0-T/S 型曲线
  538. }
  539. }
  540. }
  541. }
  542. /// <summary>
  543. /// 回HOME
  544. /// </summary>
  545. /// <param name="axisIndex"></param>
  546. /// <param name="homeMode">16种回HOME模式(0-15)</param>
  547. /// <param name="dir">0-正向 1-负向</param>
  548. /// <exception cref="Exception"></exception>
  549. public void home(int axisIndex = -1, uint homeMode = 11, uint dir = 1)
  550. {
  551. if (!IsInit) return;
  552. if (Config.HeightDevIOState)
  553. {
  554. WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
  555. return;
  556. }
  557. //研华运动控制卡共提供两个函数执行回Home: Acm_AxHome 和Acm_AxMoveHome
  558. //调用Acm_AxHome 执行回Home 时,通过PAR_AxVelLow、PAR_AxVelHigh、PAR_AxAcc、 PAR_AxDec、PAR_AxJerk 设置初速度,运行速度、加速度、减速度、速度曲线类型。
  559. //调用Acm_AxMoveHome 执行回Home 时,通过PAR_AxHomeVelLow、PAR_AxHomeVelHigh、 PAR_AxHomeAcc、PAR_AxHomeDec、PAR_AxHomeJerk 设置初速度,运行速度、加速度、 减速度、速度曲线类型。
  560. uint result;
  561. for (int i = 0; i < m_ulAxisCount; i++)
  562. {
  563. if (isSkip(axisIndex)) continue;
  564. if (i == axisIndex || axisIndex == -1)
  565. {
  566. if ((AxisState)AxState[i] != AxisState.STA_AX_READY)
  567. continue;
  568. if (!setPulseOutMode(i, (AxisPulseOutMode)AxisPulseOutMode[i]))
  569. throw new Exception($"Axis{i} 设置脉冲模式失败!");
  570. //单独设置GO HOME 速度参数??
  571. //
  572. result = Motion.mAcm_AxHome(m_Axishand[i], homeMode, dir);
  573. if (result != (uint)ErrorCode.SUCCESS)
  574. throw new Exception("AxHome Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]");
  575. }
  576. }
  577. //复位
  578. //if (axisIndex == -1 && !IsDebug && !IsReset)
  579. // IsReset = true;
  580. if (!IsDebug && !IsReset)
  581. IsReset = true;
  582. }
  583. /// <summary>
  584. /// 点到点运动
  585. /// </summary>
  586. /// <param name="axisIndex"></param>
  587. /// <param name="pos">PPU位置,方向为正负值</param>
  588. /// <param name="moveMode"></param>
  589. public bool move_ptp(int axisIndex, double pos, AxMoveMode moveMode)
  590. {
  591. if (isSkip(axisIndex)) return true;
  592. if (!IsInit) return false;
  593. if (isError(axisIndex)) return false;
  594. if (Config.HeightDevIOState)
  595. {
  596. WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
  597. return false;
  598. }
  599. pos = toPulse(pos, Config.Axis_MM2PulseNum[axisIndex]);
  600. uint result;
  601. if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
  602. return false;
  603. if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex]))
  604. {
  605. WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 设置脉冲模式失败!");
  606. return false;
  607. }
  608. //--
  609. if (moveMode==AxMoveMode.绝对位置) //Start single axis's absolute position motion.
  610. result = Motion.mAcm_AxMoveAbs(m_Axishand[axisIndex], pos);
  611. else //Start single axis's relative position motion
  612. result = Motion.mAcm_AxMoveRel(m_Axishand[axisIndex], pos);
  613. if (result != (uint)ErrorCode.SUCCESS)
  614. {
  615. WarningEvent?.Invoke(WarningEnum.High, "PTP Move Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  616. return false;
  617. }
  618. return true;
  619. }
  620. /// <summary>
  621. /// 判断是否正在动动
  622. /// </summary>
  623. /// <param name="axisIndex"></param>
  624. /// <returns></returns>
  625. public bool isMoveing(int axisIndex = -1)
  626. {
  627. if (!IsInit) return false;
  628. for (int i = 0; i < m_ulAxisCount; i++)
  629. {
  630. if (i == axisIndex || axisIndex == -1)
  631. {
  632. AxisState state = (AxisState)AxState[i];
  633. if (state == AxisState.STA_AX_PTP_MOT || state == AxisState.STA_AX_HOMING || state == AxisState.STA_AX_CONTI_MOT)
  634. return true;
  635. }
  636. }
  637. return false;
  638. }
  639. /// <summary>
  640. /// 设置脉冲模式
  641. /// </summary>
  642. /// <param name="axisIndex"></param>
  643. /// <param name="outMode"></param>
  644. /// <returns></returns>
  645. private bool setPulseOutMode(int axisIndex, AxisPulseOutMode outMode)
  646. {
  647. uint refOutMode = 0;
  648. //先获取再判断
  649. uint result = Motion.mAcm_GetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, ref refOutMode);// 获取输出模式
  650. if (result != (uint)ErrorCode.SUCCESS)
  651. {
  652. WarningEvent?.Invoke(WarningEnum.High, $"Get Axis{axisIndex} Failed With Error Code: [0x" + Convert.ToString(result, 16) + "]");
  653. return false;
  654. }
  655. if ((uint)outMode != refOutMode)
  656. {
  657. //设置脉冲模式
  658. result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxPulseOutMode, (uint)outMode);
  659. if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
  660. {
  661. WarningEvent?.Invoke(WarningEnum.High, "Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  662. return false;
  663. }
  664. }
  665. return true;
  666. }
  667. #region JOG
  668. public void openJogMode(int axisIndex)
  669. {
  670. if (!IsInit) return;
  671. if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_READY)
  672. return;
  673. if (!setPulseOutMode(axisIndex, (AxisPulseOutMode)AxisPulseOutMode[axisIndex]))
  674. throw new Exception($"Axis{axisIndex} 设置脉冲模式失败!");
  675. uint result;
  676. //启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode 2: MPG Mode
  677. result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 0);
  678. result = Motion.mAcm_AxSetExtDrive(m_Axishand[axisIndex], 1);
  679. if (result != (uint)ErrorCode.SUCCESS)
  680. throw new Exception("Start external driver Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  681. //设置外部驱动器的输入引脚
  682. //0 轴 0(默认值) 仅支持 0
  683. //1 轴 1(不支持)
  684. //2 轴 2(不支持)
  685. //3 轴 3(不支持)
  686. result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtMasterSrc, 0);
  687. if (result != (uint)ErrorCode.SUCCESS)
  688. throw new Exception("Set Property-AxExtMasterSrc Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  689. //当启用外部驱动时。此属性允许通过数字输入通道选择驱动轴
  690. result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtSelEnable, 1);
  691. if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
  692. throw new Exception("Set Property-AxExtSelEnable Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  693. //理论脉冲数
  694. result = Motion.mAcm_SetU32Property(m_Axishand[axisIndex], (uint)PropertyID.CFG_AxExtPulseNum, 1000);
  695. if (result != (uint)ErrorCode.SUCCESS && result != (uint)ErrorCode.PropertyIDNotSupport)//Added for Supporting PCI1245 and PCI1265
  696. throw new Exception("Set Property-CFG_AxExtPulseNum Failed With Error Code[0x" + Convert.ToString(result, 16) + "]");
  697. //外部设置
  698. //setAxisVelParam(velLow, high, acc, dec, axisIndex, true);
  699. this.refreshAxisState(axisIndex);
  700. }
  701. public void closeJogMode(int axisIndex = -1)
  702. {
  703. if (!IsInit) return;
  704. uint result;
  705. for (int i = 0; i < m_ulAxisCount; i++)
  706. {
  707. if (i == axisIndex || axisIndex == -1)
  708. {
  709. if ((AxisState)AxState[i] == AxisState.STA_AX_EXT_JOG)
  710. {
  711. //启用/禁用外置硬盘模式.0: Disabled (stop command) 1: JOG Mode 2: MPG Mode
  712. result = Motion.mAcm_AxSetExtDrive(m_Axishand[i], 0);
  713. //命令轴减速停止
  714. result = Motion.mAcm_AxStopDec(m_Axishand[i]);
  715. this.refreshAxisState(i);
  716. }
  717. }
  718. }
  719. }
  720. /// <summary>
  721. /// jog运行
  722. /// </summary>
  723. /// <param name="axisIndex"></param>
  724. /// <param name="dic">0:正向,1:负向</param>
  725. public void jog(int axisIndex, ushort dic)
  726. {
  727. if (isSkip(axisIndex)) return;
  728. if (isError(axisIndex)) return;
  729. if ((AxisState)AxState[axisIndex] != AxisState.STA_AX_EXT_JOG) return;
  730. if (Config.HeightDevIOState)
  731. {
  732. WarningEvent?.Invoke(WarningEnum.High, "厚度气缸已打开,不可移动轴!");
  733. return;
  734. }
  735. //Jog 运动的方向,0:正向,1:负向
  736. Motion.mAcm_AxJog(m_Axishand[axisIndex], dic);
  737. }
  738. #endregion
  739. #region Private
  740. private bool isSkip(int axisIndex)
  741. {
  742. if (axisIndex == 0 && Config.SkipAxis0) return true;
  743. if (axisIndex == 1 && Config.SkipAxis1) return true;
  744. if (axisIndex == 2 && Config.SkipAxis2) return true;
  745. if (axisIndex == 3 && Config.SkipAxis3) return true;
  746. return false;
  747. }
  748. private void Timer_Elapsed(object sender, ElapsedEventArgs e)
  749. {
  750. if (!IsInit) return;
  751. for (int i = 0; i < m_ulAxisCount; i++)
  752. refreshAxisState(i);
  753. }
  754. private bool bALM, bEMG, bLMTP, bLMTN;
  755. private void refreshAxisState(int axisIndex)
  756. {
  757. //uint result;
  758. //获取指定轴的当前命令位置
  759. if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetCmdPosition(m_Axishand[axisIndex], ref CmdPos[axisIndex]))
  760. axisPosEvent?.Invoke(axisIndex, AxisPosType.CmdPos, tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]));
  761. //获取指定轴的当前实际(反馈)位置
  762. if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetActualPosition(m_Axishand[axisIndex], ref ActualPos[axisIndex]))
  763. axisPosEvent?.Invoke(axisIndex, AxisPosType.ActualPos, tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]) );
  764. //获取Axis的当前状态
  765. if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetState(m_Axishand[axisIndex], ref AxState[axisIndex]))
  766. axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisState, AxState[axisIndex]);
  767. //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisState = {((AxisState)AxState[AxisIndex]).ToString()}");
  768. //获取轴的运动I/O状态。
  769. if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionIO(m_Axishand[axisIndex], ref IOStatus[axisIndex]))
  770. {
  771. bool isStopNow = false;
  772. if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0) //ALM报警状态 需IO close (流程上必需在报警清除后先复位)
  773. {
  774. if (!isStopNow)
  775. {
  776. isStopNow = true;
  777. stopNow();//ALM报警需急停
  778. }
  779. if (!bALM)
  780. {
  781. bALM = true;
  782. WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} ALM报警!!!");
  783. }
  784. }
  785. if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EMG) > 0) //EMG急停状态 需重置 state (流程上必需在报警清除后先复位)
  786. {
  787. if (!isStopNow)
  788. {
  789. isStopNow = true;
  790. stopNow();//EMG状态需急停
  791. }
  792. if (!bEMG)
  793. {
  794. bEMG = true;
  795. WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发EMG急停!!!");
  796. }
  797. }
  798. //右极限 true->false (流程上必需在报警清除后先复位)
  799. if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING)
  800. {
  801. if (!isStopNow)
  802. {
  803. isStopNow = true;
  804. stopNow();//右极限状态需急停
  805. }
  806. if (!bLMTP)
  807. {
  808. bLMTP = true;
  809. WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发右极限LMTP!!!");
  810. }
  811. }
  812. //左极限 true->false (流程上必需在报警清除后先复位)
  813. if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0 && ((AxisState)AxState[axisIndex]) != AxisState.STA_AX_HOMING)
  814. {
  815. if (!isStopNow)
  816. {
  817. isStopNow = true;
  818. stopNow();//左极限状态需急停
  819. }
  820. if (!bLMTN)
  821. {
  822. bLMTN = true;
  823. WarningEvent?.Invoke(WarningEnum.High, $"Axis{axisIndex} 触发左极限LMTN!!!");
  824. }
  825. }
  826. ////ORG 回原点
  827. //if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0)
  828. //{
  829. // WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发ORG信号!");
  830. //}
  831. ////EZ 回原点
  832. //if ((IOStatus[axisIndex] & (uint)Ax_Motion_IO.AX_MOTION_IO_EZ) > 0)
  833. //{
  834. // WarningEvent?.Invoke(WarningEnum.Normal, $"Axis{axisIndex} 触发EZ信号!");
  835. //}
  836. axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisIOState, IOStatus[axisIndex]);
  837. //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionIO = {((Ax_Motion_IO)IOStatus[AxisIndex]).ToString()}");
  838. //checkMotionIOStatus(AxisIndex, IOStatus[AxisIndex]);
  839. }
  840. //获取Axis的当前运动状态
  841. if ((uint)ErrorCode.SUCCESS == Motion.mAcm_AxGetMotionStatus(m_Axishand[axisIndex], ref AxMotionState[axisIndex]))
  842. axisStateEvent?.Invoke(axisIndex, AxisStateType.AxisMotionState, AxMotionState[axisIndex]);
  843. //log?.Invoke(WarningEnum.Normal, $"({AxisIndex}轴)AxisMotionStatus = {AxMotionState[AxisIndex].ToString()}");
  844. }
  845. //private void checkMotionIOStatus(int axisIndex, uint IOStatus)
  846. //{
  847. // if ((IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0)//报警信号输出
  848. // log?.Invoke(2, $"轴{axisIndex} 发出告警!!");
  849. // bool ALM = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ALM) > 0;
  850. // bool ORG = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_ORG) > 0;//ORG
  851. // bool EL_R = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTP) > 0;//右极限
  852. // bool EL_L = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_LMTN) > 0;//-EL 左
  853. // bool SVON = (IOStatus & (uint)Ax_Motion_IO.AX_MOTION_IO_SVON) > 0;
  854. //}
  855. private string getErrInfo(uint errorCode)
  856. {
  857. StringBuilder ErrorMsg = new StringBuilder("", 100);
  858. //Get the error message according to error code returned from API
  859. Boolean res = Motion.mAcm_GetErrorMessage(errorCode, ErrorMsg, 100);
  860. if (res) return ErrorMsg.ToString();
  861. return "获取错误信息失败!";
  862. }
  863. /// <summary>
  864. ///
  865. /// </summary>
  866. /// <param name="pulseVal"></param>
  867. /// <param name="mmPulse"></param>
  868. /// <returns></returns>
  869. public double tomm(double pulseVal, double pulse)
  870. {
  871. return (pulseVal / pulse);
  872. }
  873. /// <summary>
  874. /// mm转脉冲
  875. /// </summary>
  876. /// <param name="mm"></param>
  877. /// <param name="mmPulse">1mm 对应 脉冲数</param>
  878. /// <returns></returns>
  879. private double toPulse(double mm, double mmPulse)
  880. {
  881. return (mm * mmPulse);
  882. }
  883. public double getCmdPos_mm(int axisIndex)
  884. {
  885. return tomm(CmdPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
  886. }
  887. public double getActualPos_mm(int axisIndex)
  888. {
  889. return tomm(ActualPos[axisIndex], Config.Axis_MM2PulseNum[axisIndex]);
  890. }
  891. #endregion
  892. }
  893. }