AxisImply.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. using System;
  2. namespace StageController.HDS
  3. {
  4. public class AxisImply
  5. {
  6. #region Com Connection
  7. private IntPtr g_handle;
  8. private float fValue; //浮点参数
  9. private long intType; //整型参数
  10. private const int g_maxtime = 100; //最大等待时间
  11. private byte[] psResponse; //接收的返回的字符
  12. private UInt32 uiResponseLength = 1024; //返回字符长度
  13. public string Adrr = "10.0.0.100"; //连接的IP地址
  14. #endregion
  15. //HDS--> 返回 2,代表运动中,返回 1,代表空闲中
  16. public int x_State = 0;
  17. public int y_State = 0;
  18. public int z_State = 0;
  19. private double valueRESX = -1;
  20. private double valueRESY = -1;
  21. private double valueRESZ = -1;
  22. public double x_Actual = 0;
  23. public double y_Actual = 0;
  24. public double z_Actual = 0;
  25. public string hds_CONTROL = "";//控制器型号
  26. public string hds_SERIAL_NUMBER = "";//控制器ID
  27. //public int[] hds_speeds = new int[] { };
  28. public bool isOpen { get => (long)g_handle != 0; }
  29. public void Open()
  30. {
  31. if (!isOpen) zmotion.ZMC_OpenEth(Adrr, out g_handle);
  32. if (isOpen)
  33. {
  34. string strResult;
  35. if (this.Command_Execute("Print CONTROL", out strResult) == 0)
  36. {//返回控制器型号
  37. hds_CONTROL = strResult + "";
  38. }
  39. if (this.Command_Execute("Print SERIAL_NUMBER", out strResult) == 0)
  40. {//返回控制器ID。
  41. hds_SERIAL_NUMBER = strResult + "";
  42. }
  43. ////Console.WriteLine("Cancel Axis: (" + (int)axisType + ") " + psResponseCode/*changps*/);
  44. //x_speed
  45. //print speed(0)
  46. //AxisImply.GetLocalIpAddress("InterNetwork");
  47. }
  48. }
  49. public void Close()
  50. {
  51. if (!isOpen) return;
  52. zmotion.ZMC_Close(g_handle);
  53. g_handle = (IntPtr)0;
  54. }
  55. private string SubStringToChar(byte[] oriResponse)
  56. {
  57. string testcode = System.Text.Encoding.ASCII.GetString(oriResponse);
  58. //先求出最后出现这个字符的下标
  59. int indexC = testcode.IndexOf('\n');
  60. if (indexC < 0) indexC = testcode.IndexOf('\0');
  61. //从下一个索引开始截取
  62. return testcode.Substring(0, indexC);
  63. }
  64. public void RefreshPosition()
  65. {
  66. if (!isOpen) return;
  67. Int32 psResponseCode; psResponse = new byte[1024]; string psResponstring; string[] psResponseArr;
  68. double dValue;
  69. if (valueRESX < 0)
  70. {
  71. psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESX", psResponse, uiResponseLength);
  72. if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
  73. valueRESX = dValue / 1000;
  74. }
  75. if (valueRESY < 0)
  76. {
  77. psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESY", psResponse, uiResponseLength);
  78. if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
  79. valueRESY = dValue / 1000;
  80. }
  81. if (valueRESZ < 0)
  82. {
  83. psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESZ", psResponse, uiResponseLength);
  84. if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
  85. valueRESZ = dValue / 1000;
  86. }
  87. if (valueRESX < 0) valueRESX = /*(float)*/2.5196851;
  88. if (valueRESY < 0) valueRESY = /*(float)*/2.5196851;
  89. if (valueRESZ < 0) valueRESZ = 6.4;
  90. Logs.Write("[HD]send : " + "?*DPOS");
  91. psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?*DPOS"/*, g_maxtime*/, psResponse, uiResponseLength);
  92. psResponstring = SubStringToChar(psResponse);
  93. Logs.Write("[HD]Recv Data: " + psResponstring);
  94. psResponseArr = psResponstring.Split(' ');
  95. if (psResponseCode == 0 && psResponseArr.Length > 2)
  96. {
  97. if (float.TryParse(psResponseArr[0], out fValue)) x_Actual = fValue / valueRESX;
  98. if (float.TryParse(psResponseArr[1], out fValue)) y_Actual = fValue / valueRESY;
  99. if (float.TryParse(psResponseArr[2], out fValue)) z_Actual = fValue / valueRESZ;
  100. }
  101. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[0]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  102. //if (psResponseCode == 0 && float.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Trim(), out fValue))// zmcaux.ZAux_GetDpos/*Mpos*/(g_handle, 0, ref fValue);//zmcaux.ZAux_GetMpos(g_handle, 0, ref fValue);
  103. // x_Actual = fValue;// AxisShellList[AxisType.X].Step = fValue;// (m_AxisX.Reversed ? -posInfo.XStep : posInfo.XStep) * m_AxisX.Stepping;
  104. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[1]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  105. //if (psResponseCode == 0 && float.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Trim(), out fValue))// zmcaux.ZAux_GetDpos/*ZAux_GetDpos*/(g_handle, 1, ref fValue);//zmcaux.ZAux_GetMpos(g_handle, 1, ref fValue); //### 待调试
  106. // y_Actual = fValue;// AxisShellList[AxisType.Y].Step = fValue;// posInfo.YStep * m_AxisY.Stepping;
  107. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[2]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  108. //if (psResponseCode == 0 && float.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Trim(), out fValue))// zmcaux.ZAux_GetDpos(g_handle, 2, ref fValue);//zmcaux.ZAux_GetMpos(g_handle, 2, ref fValue);
  109. // z_Actual = fValue;// AxisShellList[AxisType.Z].Step = fValue;// posInfo.ZStep * m_AxisZ.Stepping;
  110. Logs.Write("[HD]send : " + "?*MTYPE");
  111. psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?*MTYPE"/*, g_maxtime*/, psResponse, uiResponseLength);
  112. psResponstring = SubStringToChar(psResponse);
  113. Logs.Write("[HD]Recv Data: " + psResponstring);
  114. psResponseArr = psResponstring.Split(' ');
  115. if (psResponseCode == 0 && psResponseArr.Length > 2)
  116. {
  117. if (long.TryParse(psResponseArr[0], out intType)) x_State = intType != 0 ? 2 : 1;
  118. if (long.TryParse(psResponseArr[1], out intType)) y_State = intType != 0 ? 2 : 1;
  119. if (long.TryParse(psResponseArr[2], out intType)) z_State = intType != 0 ? 2 : 1;
  120. }
  121. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(0)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  122. //if (psResponseCode == 0 && long.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Replace("\07", "").Replace("\n", "").Replace("\0", "").Trim(), out intType))// zmcaux.ZAux_Direct_GetMtype(g_handle, 0, ref intType);
  123. // x_State = intType != 0 ? 2 : 1;
  124. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(1)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  125. //if (psResponseCode == 0 && long.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Replace("\07", "").Replace("\n", "").Replace("\0", "").Trim(), out intType))// zmcaux.ZAux_Direct_GetMtype(g_handle, 1, ref intType);
  126. // y_State = intType != 0 ? 2 : 1;
  127. //psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(2)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
  128. //if (psResponseCode == 0 && long.TryParse(System.Text.Encoding.ASCII.GetString(psResponse).Replace("\07", "").Replace("\n", "").Replace("\0", "").Trim(), out intType))// zmcaux.ZAux_Direct_GetMtype(g_handle, 2, ref intType);
  129. // z_State = intType != 0 ? 2 : 1;
  130. }
  131. /// <summary>
  132. /// 平台平移(9、 相对运动 相对运动可以转化为绝对运动来实现,这样接口更简单、可靠。) waitmovedone
  133. /// </summary>
  134. /// <param name="x">轴移动距离(μm)</param>
  135. /// <param name="axisType">轴系数</param>
  136. public void Move(double x, AxisType axisType)
  137. {
  138. if (!isOpen) return;
  139. if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
  140. if (x != 0)
  141. {
  142. //相对运动可以转化为绝对运动来实现,这样接口更简单、可靠。
  143. //Int32 psResponseCode;
  144. double valueRES = 1;
  145. switch (axisType)
  146. {
  147. case AxisType.X:
  148. valueRES = valueRESX;
  149. //psResponseCode = this.Command_Execute("pPOSX = " + (x * valueRESX + x_Actual), out _);
  150. break;
  151. case AxisType.Y:
  152. valueRES = valueRESY;
  153. //psResponseCode = this.Command_Execute("pPOSY = " + (x * valueRESY + y_Actual), out _);
  154. break;
  155. case AxisType.Z:
  156. valueRES = valueRESZ;
  157. //psResponseCode = this.Command_Execute("pPOSZ = " + (x * valueRESZ + z_Actual), out _);
  158. break;
  159. default:
  160. break;
  161. }
  162. if (x != 0)
  163. {
  164. Int32 psResponseCode = this.Command_Execute("MOVE(" + Math.Round(x * valueRES) + ") AXIS(" + (int)axisType + ")", out _);
  165. Console.WriteLine("Move " + +(int)axisType + ": " + psResponseCode/*changps*/);
  166. }
  167. }
  168. }
  169. /// <summary>
  170. /// 8、 绝对运动
  171. /// </summary>
  172. /// <param name="x"></param>
  173. /// <param name="axisType">轴系数</param>
  174. public void To(double x, AxisType axisType)
  175. {
  176. if (!isOpen) return;
  177. if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
  178. double valueRES = 1;
  179. switch (axisType)
  180. {
  181. case AxisType.X:
  182. valueRES = valueRESX;
  183. break;
  184. case AxisType.Y:
  185. valueRES = valueRESY;
  186. break;
  187. case AxisType.Z:
  188. valueRES = valueRESZ;
  189. break;
  190. default:
  191. break;
  192. }
  193. this.Command_Execute("MOVEABS(" + Math.Round(x * valueRES) + ") AXIS(" + (int)axisType + ")", out _);
  194. }
  195. /// <summary>
  196. /// 平台朝一个水平方向连续运动
  197. /// </summary>
  198. /// <param name="axisType"></param>
  199. /// <param name="isPositive">正向TRUE 反向FALSE</param>
  200. public void VMove(AxisType axisType, bool isPositive)
  201. {
  202. if (!isOpen) return;
  203. this.Command_Execute("VMOVE(" + (isPositive ? 1 : -1) + ") AXIS(" + (int)axisType + ")", out _);
  204. Console.WriteLine("VMove Axis: (" + (int)axisType + ") " + (isPositive ? 1 : -1));
  205. }
  206. /// <summary>
  207. /// 取消当前运动和缓冲运动
  208. /// </summary>
  209. /// <param name="axisType"></param>
  210. public void CancelCommand(AxisType axisType)
  211. {
  212. if (!isOpen) return;
  213. Int32 psResponseCode = this.Command_Execute("CANCEL(2) AXIS(" + (int)axisType + ")", out _);
  214. Console.WriteLine("Cancel Axis: (" + (int)axisType + ") " + psResponseCode/*changps*/);
  215. }
  216. public void SetSpeed(float speed, AxisType axisType)
  217. {
  218. if (!isOpen) return;
  219. if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
  220. double valueRES = 1;
  221. switch (axisType)
  222. {
  223. case AxisType.X:
  224. valueRES = valueRESX;
  225. break;
  226. case AxisType.Y:
  227. valueRES = valueRESY;
  228. break;
  229. case AxisType.Z:
  230. valueRES = valueRESZ;
  231. break;
  232. default:
  233. break;
  234. }
  235. this.Command_Execute("speed(" + (int)axisType + ")=" + (speed * valueRES), out _); ;
  236. }
  237. /* ZBasic具有实时多任务特性,多个ZBasic程序可以同时构建并同时运行,使得复杂的应用变得简单易行 通过PC在线发送BASIC命令也可以实现同样的效果,控制器的BASIC程序和PC在线BASIC命令可以同时运行 BASE(0,1,2,3)’轴列表为:0,1,2,3 ;ZMC004 MOVE(100,100,100,100) ’轴0,1,2,3运动
  238. MOVE(1000) AXIS(1)’ 轴1运动1000unit BASE(0,1) DEFPOS(0,0) ‘设置轴0和轴1当前点为零点. VMOVE 描述:连续往一个方向运动,当前面的VMOVE运动没有停止时,此VMOVE指令会自动替换前面的VMOVE指令并修改方向,因此无需CANCEL前面的VMOVE指令。 */
  239. /// <summary>
  240. /// 通用的命令执行接口 当控制器没有缓冲时自动阻赛
  241. /// </summary>
  242. /// <param name="g_command">命令串</param>
  243. /// <param name="changps">接收的字符数组转换为字符串</param>
  244. /// <returns>错误码</returns>
  245. public Int32 Command_Execute(string g_command, out string changps)
  246. {
  247. Int32 psResponseCode = -100;
  248. psResponse = new byte[1024];
  249. if (isOpen)
  250. {
  251. psResponseCode = zmotion.ZMC_DirectCommand/*ZMC_Execute*/(g_handle, g_command/*, g_maxtime*/, psResponse, uiResponseLength); // '执行命令并接受应答
  252. changps = System.Text.Encoding.ASCII.GetString(psResponse);
  253. //TextBox2.Text = TextBox2.Text + ">>" + g_command + "\r\n";
  254. if (psResponse[0] != '\0') // '显示接收信息
  255. psResponseCode = 0;
  256. // TextBox2.Text = TextBox2.Text + changps + "\r\n";
  257. }
  258. else
  259. changps = "Connect First!";
  260. //TextBox2.Text = TextBox2.Text + "Connect First!" + "\r\n";
  261. return psResponseCode;
  262. }
  263. /* c) 命令下发要注意防止拥堵,例如采用线程的同步。 当前各轴的分辨率可通过指令去查询,例如查询 X 轴用?pRESX 反馈的数据单位为 count,要转换为 mm 为单位,则需要将该反馈值除以分辨率 HALT 是停止所有任务。 程序中禁止使用,防止出现异常!!!*/
  264. /* 文档“ZBasic.chm”; 设置轴的反向间隙,扩展轴无效。 BACKLASH(0) '关闭反向间隙功能。 BACKLASH(1, 0.1) '设置反向间隙0.1mm 设置轴的螺距补偿,扩展轴无效。 每点的补偿脉冲个数存储在TABLE表里面。
  265. DPOS 轴的虚拟坐标位置,或称需求位置。 写DPOS会自动转换为OFFPOS偏移,不会移动电机。 以UNITS作为单位。
  266. FE 随动误差,该值等于DPOS-MPOS。
  267. FS_LIMIT 正向软限位位置,单位是units。 取消设置时,只需要把值设大些。 FS_LIMIT=2000000 ‘取消正向软限位设置
  268. MTYPE 当前正在进行的运动指令类型。 0 IDLE (没有运动) 10 FORWARD
  269. print CONTROL 返回控制器型号。 464 303
  270. print DATE 设置系统日期,或是返回2000年以后的天数。 7782 7800
  271. print DATE$ 字符串函数,按DD/MM/YYYY格式返回当前日期。 22:04:2021 10:05:2021
  272. PRINT IP_ADDRESS 控制器IP地址。 只有带以太网接口的控制器支持,读取时以32位整数返回,见例一。 16777343 = 127.0.0.1。 1677721610 = 10.0.0.100
  273. PRINT IP_GATEWAY 控制器IP网关。 16820416
  274. PRINT IP_NETMASK 控制器IP网络掩码。 16777215
  275. Print SERIAL_NUMBER 返回控制器ID。 是一个唯一的序列号,生成ZAR包的时候也可以和这个ID绑定,这样这个ZAR只能为这个控制器所用。 190101376
  276. ?*version 系统软件版本号。 2.9400
  277. SLOT_SCAN 总线扫描,通过RETURN返回成功与否,-1扫描成功 0扫描失败。 */
  278. }
  279. }