版博士V2.0程序
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

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