AxisImply.cs 20 KB

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