using System;
namespace StageController.HDS
{
public class AxisImply
{
#region Com Connection
private IntPtr g_handle;
private float fValue; //浮点参数
private long intType; //整型参数
private const int g_maxtime = 100; //最大等待时间
private byte[] psResponse; //接收的返回的字符
private UInt32 uiResponseLength = 1024; //返回字符长度
public string Adrr = "10.0.0.100"; //连接的IP地址
#endregion
//HDS--> 返回 2,代表运动中,返回 1,代表空闲中
public int x_State = 0;
public int y_State = 0;
public int z_State = 0;
private double valueRESX = -1;
private double valueRESY = -1;
private double valueRESZ = -1;
public double x_Actual = 0;
public double y_Actual = 0;
public double z_Actual = 0;
public string hds_CONTROL = "";//控制器型号
public string hds_SERIAL_NUMBER = "";//控制器ID
//public int[] hds_speeds = new int[] { };
public bool isOpen { get => (long)g_handle != 0; }
public void Open()
{
if (!isOpen) zmotion.ZMC_OpenEth(Adrr, out g_handle);
if (isOpen)
{
string strResult;
if (this.Command_Execute("Print CONTROL", out strResult) == 0)
{//返回控制器型号
hds_CONTROL = strResult + "";
}
if (this.Command_Execute("Print SERIAL_NUMBER", out strResult) == 0)
{//返回控制器ID。
hds_SERIAL_NUMBER = strResult + "";
}
////Console.WriteLine("Cancel Axis: (" + (int)axisType + ") " + psResponseCode/*changps*/);
//x_speed
//print speed(0)
//AxisImply.GetLocalIpAddress("InterNetwork");
}
}
public void Close()
{
if (!isOpen) return;
zmotion.ZMC_Close(g_handle);
g_handle = (IntPtr)0;
}
private string SubStringToChar(byte[] oriResponse)
{
string testcode = System.Text.Encoding.ASCII.GetString(oriResponse);
//先求出最后出现这个字符的下标
int indexC = testcode.IndexOf('\n');
if (indexC < 0) indexC = testcode.IndexOf('\0');
//从下一个索引开始截取
return testcode.Substring(0, indexC);
}
public void RefreshPosition()
{
if (!isOpen) return;
Int32 psResponseCode; psResponse = new byte[1024]; string psResponstring; string[] psResponseArr;
double dValue;
if (valueRESX < 0)
{
psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESX", psResponse, uiResponseLength);
if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
valueRESX = dValue / 1000;
}
if (valueRESY < 0)
{
psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESY", psResponse, uiResponseLength);
if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
valueRESY = dValue / 1000;
}
if (valueRESZ < 0)
{
psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?pRESZ", psResponse, uiResponseLength);
if (psResponseCode == 0 && double.TryParse(SubStringToChar(psResponse), out dValue))
valueRESZ = dValue / 1000;
}
if (valueRESX < 0) valueRESX = /*(float)*/2.5196851;
if (valueRESY < 0) valueRESY = /*(float)*/2.5196851;
if (valueRESZ < 0) valueRESZ = 6.4;
Logs.Write("[HD]send : " + "?*DPOS");
psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?*DPOS"/*, g_maxtime*/, psResponse, uiResponseLength);
psResponstring = SubStringToChar(psResponse);
Logs.Write("[HD]Recv Data: " + psResponstring);
psResponseArr = psResponstring.Split(' ');
if (psResponseCode == 0 && psResponseArr.Length > 2)
{
if (float.TryParse(psResponseArr[0], out fValue)) x_Actual = fValue / valueRESX;
if (float.TryParse(psResponseArr[1], out fValue)) y_Actual = fValue / valueRESY;
if (float.TryParse(psResponseArr[2], out fValue)) z_Actual = fValue / valueRESZ;
}
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[0]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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);
// x_Actual = fValue;// AxisShellList[AxisType.X].Step = fValue;// (m_AxisX.Reversed ? -posInfo.XStep : posInfo.XStep) * m_AxisX.Stepping;
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[1]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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); //### 待调试
// y_Actual = fValue;// AxisShellList[AxisType.Y].Step = fValue;// posInfo.YStep * m_AxisY.Stepping;
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?DPOS[2]", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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);
// z_Actual = fValue;// AxisShellList[AxisType.Z].Step = fValue;// posInfo.ZStep * m_AxisZ.Stepping;
Logs.Write("[HD]send : " + "?*MTYPE");
psResponseCode = zmotion.ZMC_DirectCommand(g_handle, "?*MTYPE"/*, g_maxtime*/, psResponse, uiResponseLength);
psResponstring = SubStringToChar(psResponse);
Logs.Write("[HD]Recv Data: " + psResponstring);
psResponseArr = psResponstring.Split(' ');
if (psResponseCode == 0 && psResponseArr.Length > 2)
{
if (long.TryParse(psResponseArr[0], out intType)) x_State = intType != 0 ? 2 : 1;
if (long.TryParse(psResponseArr[1], out intType)) y_State = intType != 0 ? 2 : 1;
if (long.TryParse(psResponseArr[2], out intType)) z_State = intType != 0 ? 2 : 1;
}
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(0)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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);
// x_State = intType != 0 ? 2 : 1;
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(1)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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);
// y_State = intType != 0 ? 2 : 1;
//psResponseCode = zmotion.ZMC_Execute(g_handle, "?MTYPE(2)", g_maxtime, psResponse, uiResponseLength); // '执行命令并接受应答
//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);
// z_State = intType != 0 ? 2 : 1;
}
///
/// 平台平移(9、 相对运动 相对运动可以转化为绝对运动来实现,这样接口更简单、可靠。) waitmovedone
///
/// 轴移动距离(μm)
/// 轴系数
public void Move(double x, AxisType axisType)
{
if (!isOpen) return;
if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
if (x != 0)
{
//相对运动可以转化为绝对运动来实现,这样接口更简单、可靠。
//Int32 psResponseCode;
double valueRES = 1;
switch (axisType)
{
case AxisType.X:
valueRES = valueRESX;
//psResponseCode = this.Command_Execute("pPOSX = " + (x * valueRESX + x_Actual), out _);
break;
case AxisType.Y:
valueRES = valueRESY;
//psResponseCode = this.Command_Execute("pPOSY = " + (x * valueRESY + y_Actual), out _);
break;
case AxisType.Z:
valueRES = valueRESZ;
//psResponseCode = this.Command_Execute("pPOSZ = " + (x * valueRESZ + z_Actual), out _);
break;
default:
break;
}
if (x != 0)
{
Int32 psResponseCode = this.Command_Execute("MOVE(" + Math.Round(x * valueRES) + ") AXIS(" + (int)axisType + ")", out _);
Console.WriteLine("Move " + +(int)axisType + ": " + psResponseCode/*changps*/);
}
}
}
///
/// 8、 绝对运动
///
///
/// 轴系数
public void To(double x, AxisType axisType)
{
if (!isOpen) return;
if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
double valueRES = 1;
switch (axisType)
{
case AxisType.X:
valueRES = valueRESX;
break;
case AxisType.Y:
valueRES = valueRESY;
break;
case AxisType.Z:
valueRES = valueRESZ;
break;
default:
break;
}
this.Command_Execute("MOVEABS(" + Math.Round(x * valueRES) + ") AXIS(" + (int)axisType + ")", out _);
}
///
/// 平台朝一个水平方向连续运动
///
///
/// 正向TRUE 反向FALSE
public void VMove(AxisType axisType, bool isPositive)
{
if (!isOpen) return;
this.Command_Execute("VMOVE(" + (isPositive ? 1 : -1) + ") AXIS(" + (int)axisType + ")", out _);
Console.WriteLine("VMove Axis: (" + (int)axisType + ") " + (isPositive ? 1 : -1));
}
///
/// 取消当前运动和缓冲运动
///
///
public void CancelCommand(AxisType axisType)
{
if (!isOpen) return;
Int32 psResponseCode = this.Command_Execute("CANCEL(2) AXIS(" + (int)axisType + ")", out _);
Console.WriteLine("Cancel Axis: (" + (int)axisType + ") " + psResponseCode/*changps*/);
}
public void SetSpeed(float speed, AxisType axisType)
{
if (!isOpen) return;
if (valueRESX < 0 || valueRESY < 0 || valueRESZ < 0) return;
double valueRES = 1;
switch (axisType)
{
case AxisType.X:
valueRES = valueRESX;
break;
case AxisType.Y:
valueRES = valueRESY;
break;
case AxisType.Z:
valueRES = valueRESZ;
break;
default:
break;
}
this.Command_Execute("speed(" + (int)axisType + ")=" + (speed * valueRES), out _); ;
}
/* 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运动
MOVE(1000) AXIS(1)’ 轴1运动1000unit BASE(0,1) DEFPOS(0,0) ‘设置轴0和轴1当前点为零点. VMOVE 描述:连续往一个方向运动,当前面的VMOVE运动没有停止时,此VMOVE指令会自动替换前面的VMOVE指令并修改方向,因此无需CANCEL前面的VMOVE指令。 */
///
/// 通用的命令执行接口 当控制器没有缓冲时自动阻赛
///
/// 命令串
/// 接收的字符数组转换为字符串
/// 错误码
public Int32 Command_Execute(string g_command, out string changps)
{
Int32 psResponseCode = -100;
psResponse = new byte[1024];
if (isOpen)
{
psResponseCode = zmotion.ZMC_DirectCommand/*ZMC_Execute*/(g_handle, g_command/*, g_maxtime*/, psResponse, uiResponseLength); // '执行命令并接受应答
changps = System.Text.Encoding.ASCII.GetString(psResponse);
//TextBox2.Text = TextBox2.Text + ">>" + g_command + "\r\n";
if (psResponse[0] != '\0') // '显示接收信息
psResponseCode = 0;
// TextBox2.Text = TextBox2.Text + changps + "\r\n";
}
else
changps = "Connect First!";
//TextBox2.Text = TextBox2.Text + "Connect First!" + "\r\n";
return psResponseCode;
}
/* c) 命令下发要注意防止拥堵,例如采用线程的同步。 当前各轴的分辨率可通过指令去查询,例如查询 X 轴用?pRESX 反馈的数据单位为 count,要转换为 mm 为单位,则需要将该反馈值除以分辨率 HALT 是停止所有任务。 程序中禁止使用,防止出现异常!!!*/
/* 文档“ZBasic.chm”; 设置轴的反向间隙,扩展轴无效。 BACKLASH(0) '关闭反向间隙功能。 BACKLASH(1, 0.1) '设置反向间隙0.1mm 设置轴的螺距补偿,扩展轴无效。 每点的补偿脉冲个数存储在TABLE表里面。
DPOS 轴的虚拟坐标位置,或称需求位置。 写DPOS会自动转换为OFFPOS偏移,不会移动电机。 以UNITS作为单位。
FE 随动误差,该值等于DPOS-MPOS。
FS_LIMIT 正向软限位位置,单位是units。 取消设置时,只需要把值设大些。 FS_LIMIT=2000000 ‘取消正向软限位设置
MTYPE 当前正在进行的运动指令类型。 0 IDLE (没有运动) 10 FORWARD
print CONTROL 返回控制器型号。 464 303
print DATE 设置系统日期,或是返回2000年以后的天数。 7782 7800
print DATE$ 字符串函数,按DD/MM/YYYY格式返回当前日期。 22:04:2021 10:05:2021
PRINT IP_ADDRESS 控制器IP地址。 只有带以太网接口的控制器支持,读取时以32位整数返回,见例一。 16777343 = 127.0.0.1。 1677721610 = 10.0.0.100
PRINT IP_GATEWAY 控制器IP网关。 16820416
PRINT IP_NETMASK 控制器IP网络掩码。 16777215
Print SERIAL_NUMBER 返回控制器ID。 是一个唯一的序列号,生成ZAR包的时候也可以和这个ID绑定,这样这个ZAR只能为这个控制器所用。 190101376
?*version 系统软件版本号。 2.9400
SLOT_SCAN 总线扫描,通过RETURN返回成功与否,-1扫描成功 0扫描失败。 */
}
}