运动控制卡应用开发教程之VB.NET
我们从新建工程项目,添加函数库讲起,再了解PC函数用,最后通过项目实战——位置比较输出与编码器锁存例程讲解,来让大家熟悉它的项目开发。
在正式学习之前,我们先了解一下正运动技术的运动控制卡ECI2418和ECI2618。这两款产品分别是4轴,6轴运动控制卡。
ECI2418,ECI2618均使用同一套API函数,均支持C、C++、C#、LabVIEW、Python、Delphi等开发语言,支持VC6.0、VB6.0、Qt、.Net等平台,支持Windows、Linux、WinCE、iMac等操作系统。
一
新建Windows 窗口应用程序 添加函数库
3.按需求保存项目名称和地址。
确认后创建新的VB.NET项目。
(1)进入光盘资料找到PC函数文件夹。
(2)选择函数库2.1。
(3)Windows平台。
(4)根据需要选择对应的函数库这里选择64位库。
(5)解压VB.NET的压缩包,里面有VB.NET对应的函数库。
(6)函数库具体路径如下。
二
查看PC函数手册 了解其用法
(1)通过网口连接控制器,获取控制器句柄g_handle。
ZAux_OpenEth(m_ipaddress, g_handle) '网口连接控制器
ret = ZAux_Close(g_handle) '断开前面的连接
(2)硬件位置输出比较ZAux_Direct_HwPswitch2。
不同模式下配置不同参数(ModePara),本例程使用其中两种模式:1-启动比较器;2-停止并删除没完成的比较点。
模式 1-启动比较器
ModePara1 = 第一个比较点坐标所在 TABLE 编号
ModePara2 = 最后一个比较点坐标所在 TABLE 编号
ModePara3= 第一个点判断方向:0,坐标负向;1,坐标正向;-1,不使用方向
ModePara4 = 预留
iret = ZAux_Direct_HwPswitch2(handle,AxisNum,1,Opnum, Opstatus,StartTable,EndTable,dir,0)
模式 2-停止并删除没完成的比较点
ModePara1 = 预留
ModePara2 = 预留
ModePara3= 预留
ModePara4 = 预留
iret = ZAux_Direct_HwPswitch2(handle,AxisNum,2,0,0,0,0, 0,0)
(3)硬件位置比较输出电平还原ZAux_Direct_HwTimer。
iret=ZAux_Direct_HwTimer(handle,2,Timer_Cycle, Timer_Valid,Timer_Num,Opstatus,Opnum)
(4)位置锁存指令ZAux_Direct_Regist。
iret = ZAux_Direct_Regist(handle,RegistNum,RegistMode)
(5)读取编码器值ZAux_Direct_GetMark、ZAux_Direct_GetMarkB、ZAux_Direct_GetRegPos、ZAux_Direct_GetRegPosB。
iret = ZAux_Direct_GetMark(g_handle, RegistAxis, MarkStatus)
iret = ZAux_Direct_GetRegPos(g_handle, RegistAxis, RegistPos)
三
实战例程与程序展示
iret = ZAux_OpenEth(m_ipaddress, g_handle) '网口连接控制器
iret = ZAux_Direct_GetMark(g_handle, m_RegistAxis, MarkStatus)
iret = ZAux_Direct_GetRegPos(g_handle, m_RegistAxis, RegistPos) '获取锁存位置
iret = ZAux_Direct_GetDpos(g_handle, m_AxisNum, AxisDpos)
iret = ZAux_Direct_GetOp(g_handle, m_POS_out, Op_status)
'…………
iret = ZAux_Direct_SetTable(g_handle, m_POS_StartTable, m_POS_EndTable, fPointPos(0))'将比较点填入TABLE
iret = ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 2, 0, 0, 0, 0, 0, 0)'清除比较输出指令
iret = ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 1, m_POS_out, m_POS_OutStatus, m_POS_StartTable, m_POS_EndTable, m_PSO_dir, 0)
iret = ZAux_Direct_HwTimer(g_handle, 2, m_Timer_Cycle, m_Timer_Valid, m_Timer_Num, tempoutstatus, m_POS_out) '电平恢复
iret = ZAux_Direct_Single_MoveAbs(g_handle, m_AxisNum, m_End_Pos)
iret = ZAux_Direct_Regist(g_handle, m_RegistAxis, RegistMode)'编码器锁存
iret = ZAux_Direct_GetMark(g_handle, m_RegistAxis, MarkStatus)
iret = ZAux_Direct_GetRegPos(g_handle, m_RegistAxis, RegistPos)'获取锁存位置
ret = ZAux_Close(g_handle)'断开连接
Public g_handle As IntPtr = 0 '当前使用的卡句柄
Public iTotalPoint As Integer = 1000
Public m_POS_IfOpen As Boolean = True
Public m_Timer_IfOpen As Boolean = True
Public m_AxisNum As Integer = 0
Public m_PSO_dir As Integer = -1
Public m_POS_out As Integer = 0
Public m_End_Pos As Single = 5000
Public m_Timer_Num As Integer = 1
Public m_POS_EndTable As Integer = 10
Public m_Start_Pos As Single = 0
Public m_POS_StartTable As Integer = 0
Public m_Timer_Valid As Integer = 5000
Public m_Timer_Cycle As Integer = 10000
Public m_POS_OutStatus As Integer = 1
Public m_Regist_ifOpen As Boolean = False
Public m_RegistAxis As Integer = 1
Public m_RegistCount As Integer = 0
Public RegistMode As Integer = 1
Public fPointPos(1000) As Single
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '初始化
'初始化锁存模式列表
ComboBox1.Items.Clear()
ComboBox1.Items.Add('1 Z脉冲上升沿锁存')
ComboBox1.Items.Add('2 Z脉冲下降沿锁存')
ComboBox1.Items.Add('3 R0上升沿锁存')
ComboBox1.Items.Add('4 R0下降沿锁存')
ComboBox1.Items.Add('14 R1上升沿锁存')
ComboBox1.Items.Add('15 R1下降沿锁存')
ComboBox1.Items.Add('18 R2上升沿锁存')
ComboBox1.Items.Add('19 R2下降沿锁存')
ComboBox1.Items.Add('20 R3上升沿锁存')
ComboBox1.Items.Add('21 R3下降沿锁存')
ComboBox1.SelectedIndex = 0
'初始化编码轴类型列表
ComboBox2.Items.Clear()
ComboBox2.Items.Add('3 正交编码器')
ComboBox2.Items.Add('4 脉冲方向输出+正交编码器输入')
ComboBox2.Items.Add('5 脉冲方向输出+脉冲方向输入')
ComboBox2.Items.Add('6 脉冲方向方式的编码器')
ComboBox2.Items.Add('7 脉冲方向方式步进或伺服+EZ信号输入')
ComboBox2.Items.Add('8 ZCAN扩展脉冲方向方式步进或伺服')
ComboBox2.Items.Add('9 ZCAN扩展正交编码器')
ComboBox2.Items.Add('10 ZCAN扩展脉冲方向方式的编码器')
ComboBox2.SelectedIndex = 0
'初始化比较方向列表
ComboBox3.Items.Clear()
ComboBox3.Items.Add('-1 不使用方向')
ComboBox3.Items.Add('0 坐标负向')
ComboBox3.Items.Add('1 坐标正向')
ComboBox3.SelectedIndex = 0
start_add()
End Sub
Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) '关闭窗口
If g_handle <> 0 Then '断开前面的连接
ZAux_Close(g_handle)
g_handle = 0
Me.Text = '未连接'
Timer1.Stop()
Timer2.Stop()
End If
End Sub
Private Sub start_add() '初始化DataGridView数据
Dim tempvalue As Single
tempvalue = 0
For i = 0 To iTotalPoint - 1 Step 1
tempvalue = (i + 1) * 100
DataGridView1.Rows.Add(New String() {i.ToString(), tempvalue.ToString()})
Next
End Sub
(2)控制器连接
Private Sub C_Ip_Address_DropDown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles C_Ip_Address.DropDown '下拉搜索IP
Dim Buffer As New StringBuilder(10240)
ZAux_SearchEthlist(Buffer, 10230, 200) '搜索IP地址列表
Dim Ip_List() As String
Ip_List = Buffer.ToString.Split(' ')
C_Ip_Address.Items.Clear()
C_Ip_Address.Items.Add('127.0.0.1')
If Ip_List.Length > 1 Then
For i = 0 To Ip_List.Length - 1
C_Ip_Address.Items.Add(Ip_List(i))
Next
End If
End Sub
Private Sub C_Open_Eth_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles C_Open_Eth.Click '以太网连接控制器
Dim m_ipaddress As String
m_ipaddress = C_Ip_Address.Text
If g_handle <> 0 Then '断开前面的连接
ZAux_Close(g_handle)
g_handle = 0
End If
ZAux_OpenEth(m_ipaddress, g_handle) '网口连接控制器
If (g_handle <> 0) Then
Me.Text = '已连接'
Timer1.Start()
Else
Me.Text = '未连接'
MessageBox.Show('连接失败')
End If
End Sub
Private Sub C_Close_Card_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles C_Close_Card.Click '断开连接
Dim ret As Integer = 0
If g_handle <> 0 Then '断开前面的连接
ret = ZAux_Close(g_handle)
g_handle = 0
Me.Text = '未连接'
Timer1.Stop()
Timer2.Stop()
End If
End Sub
(3)位置比较输出
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click '运动
If (g_handle = 0) Then
MessageBox.Show('未链接到控制器!', '提示')
Else
Dim iret As Integer = 0
iret = ZAux_Direct_SetUnits(g_handle, m_AxisNum, 100)
iret = ZAux_Direct_SetSpeed(g_handle, m_AxisNum, 100)
iret = ZAux_Direct_SetAccel(g_handle, m_AxisNum, 2000)
iret = ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 2, 0, 0, 0, 0, 0, 0) '清除前面的比较输出指令
If m_POS_IfOpen = False Then '比较完成一次后需要重新调用HwPswitch
iret = ZAux_Direct_SetTable(g_handle, 0, iTotalPoint, fPointPos(0)) '将比较点填入TABLE
If iret <> 0 Then
Dim tempstr As String
tempstr = 'SetTable失败 返回值:' + iret.ToString()
MessageBox.Show(tempstr, '提示')
Exit Sub
End If
iret = ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 1, m_POS_out, m_POS_OutStatus, m_POS_StartTable, m_POS_EndTable, m_PSO_dir, 0)
If iret <> 0 Then
Dim tempstr As String
tempstr = 'HwPswitch2失败 返回值:' + iret.ToString()
MessageBox.Show(tempstr, '提示')
Exit Sub
End If
Else
iret = 0
iret = ZAux_Direct_HwPswitch2(g_handle, m_AxisNum, 2, 0, 0, 0, 0, 0, 0) '清除比较输出指令
If iret <> 0 Then
Dim tempstr As String
tempstr = 'HwPswitch2失败 返回值:' + iret.ToString()
MessageBox.Show(tempstr, '提示')
Exit Sub
End If
End If
Dim tempoutstatus As Boolean = 0
If m_POS_OutStatus = 0 Then
tempoutstatus = 1
Else
tempoutstatus = 0
End If
If m_Timer_IfOpen = False Then
iret = ZAux_Direct_HwTimer(g_handle, 2, m_Timer_Cycle, m_Timer_Valid, m_Timer_Num, tempoutstatus, m_POS_out)
If iret <> 0 Then
Dim tempstr As String
tempstr = 'HwTimer失败 返回值:' + iret.ToString()
MessageBox.Show(tempstr, '提示')
Exit Sub
End If
Else
iret = ZAux_Direct_HwTimer(g_handle, 0, m_Timer_Cycle, m_Timer_Valid, m_Timer_Num, tempoutstatus, m_POS_out)
If iret <> 0 Then
Dim tempstr As String
tempstr = 'HwTimer失败 返回值:' + iret.ToString()
MessageBox.Show(tempstr, '提示')
Exit Sub
End If
End If
ZAux_Trigger(g_handle)
iret = ZAux_Direct_SetDpos(g_handle, m_AxisNum, 0)
iret = ZAux_Direct_Single_MoveAbs(g_handle, m_AxisNum, m_Start_Pos)
iret = ZAux_Direct_Single_MoveAbs(g_handle, m_AxisNum, m_End_Pos)
End If
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click '停止
If (g_handle = 0) Then
MessageBox.Show('未链接到控制器!', '提示')
Else
Dim iret As Integer = 0
iret = ZAux_Direct_Single_Cancel(g_handle, m_AxisNum, 2)
End If
End Sub
(4)锁存位置
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click '启动锁存
If (g_handle = 0) Then
MessageBox.Show('未链接到控制器!', '提示')
Else
Dim iret As Integer = 0
If m_Regist_ifOpen = False Then
m_RegistCount = 0
Dim ReglistListAtype As Integer
ReglistListAtype = ComboBox2.SelectedIndex + 3
iret = ZAux_Direct_SetAtype(g_handle, m_RegistAxis, ReglistListAtype) '必须是编码器轴才可以锁存
Dim ReglistListSel As Integer
ReglistListSel = ComboBox1.SelectedIndex
If ReglistListSel >= 0 And ReglistListSel <= 3 Then
RegistMode = ReglistListSel + 1
ElseIf ReglistListSel = 4 Or ReglistListSel = 5 Then
RegistMode = ReglistListSel + 10
ElseIf ReglistListSel >= 6 And ReglistListSel <= 9 Then
RegistMode = ReglistListSel + 12
End If
iret = ZAux_Direct_Regist(g_handle, m_RegistAxis, RegistMode)
Timer2.Start()
m_Regist_ifOpen = True
ComboBox1.Enabled = False
ComboBox2.Enabled = False
Button1.Text = '停止锁存'
Else
Timer2.Stop()
m_Regist_ifOpen = False
ComboBox1.Enabled = True
ComboBox2.Enabled = True
Button1.Text = '启动锁存'
DataGridView2.Rows.Clear()
End If
End If
End Sub
(5)时间刷新
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick '刷新状态显示
Dim AxisDpos As Single = 0
Dim iret As Integer = 0
Dim Op_status As UInt32 = 0
updata_value()
If RadioButton1.Checked = True Then '位置比较是否开启
m_POS_IfOpen = False
End If
If RadioButton2.Checked = True Then
m_POS_IfOpen = True
End If
If RadioButton4.Checked = True Then '定时器输出反转是否开启
m_Timer_IfOpen = False
End If
If RadioButton3.Checked = True Then
m_Timer_IfOpen = True
End If
iret = ZAux_Direct_GetDpos(g_handle, m_AxisNum, AxisDpos)
iret = ZAux_Direct_GetOp(g_handle, m_POS_out, Op_status)
label_dpos.Text = '轴' + m_AxisNum.ToString() + '坐标:' + AxisDpos.ToString()
label_out.Text = '输出口' + m_POS_out.ToString() + '状态:关闭'
If Op_status = 1 Then
label_out.Text = '输出口' + m_POS_out.ToString() + '状态:打开'
End If
End Sub
Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick '定时器刷新
Dim iret As Integer = 0
Dim MarkStatus As Integer = 0
Dim RegistPos As Single
If RegistMode >= 1 And RegistMode <= 4 Then
iret = ZAux_Direct_GetMark(g_handle, m_RegistAxis, MarkStatus)
ElseIf RegistMode = 14 Or RegistMode = 15 Then
iret = ZAux_Direct_GetMarkB(g_handle, m_RegistAxis, MarkStatus)
ElseIf RegistMode = 18 Or RegistMode = 19 Then
Dim tempc As Single
iret = ZAux_Direct_GetParam(g_handle, 'MARKC', m_RegistAxis, tempc)
MarkStatus = Convert.ToInt32(tempc)
ElseIf RegistMode = 20 Or RegistMode = 21 Then
Dim tempd As Single
iret = ZAux_Direct_GetParam(g_handle, 'MARKD', m_RegistAxis, tempd)
MarkStatus = Convert.ToInt32(tempd)
End If
If MarkStatus = -1 Then
If RegistMode >= 1 And RegistMode <= 4 Then
iret = ZAux_Direct_GetRegPos(g_handle, m_RegistAxis, RegistPos) '获取锁存位置
ElseIf RegistMode = 14 Or RegistMode = 15 Then
iret = ZAux_Direct_GetRegPosB(g_handle, m_RegistAxis, RegistPos)
ElseIf RegistMode >= 18 Or RegistMode = 19 Then
iret = ZAux_Direct_GetParam(g_handle, 'REG_POSC', m_RegistAxis, RegistPos)
ElseIf RegistMode = 20 Or RegistMode = 21 Then
iret = ZAux_Direct_GetParam(g_handle, 'REG_POSD', m_RegistAxis, RegistPos)
End If
Dim tempstr0 As String
Dim tempstr1 As String
tempstr0 = m_RegistCount.ToString()
tempstr1 = RegistPos.ToString()
DataGridView2.Rows.Add(New String() {tempstr0, tempstr1})
m_RegistCount = m_RegistCount + 1
iret = ZAux_Direct_Regist(g_handle, m_RegistAxis, RegistMode) '重新触发锁存
End If
Dim tempstr As String
tempstr = '锁存触发状态:' + MarkStatus.ToString() + ' 次数:' + m_RegistCount.ToString()
Label3.Text = tempstr
End Sub
Private Sub updata_value() '更新参数
m_AxisNum = Convert.ToInt32(TextBox2.Text)
m_POS_out = Convert.ToInt32(TextBox3.Text)
m_POS_StartTable = Convert.ToInt32(TextBox4.Text)
m_POS_EndTable = Convert.ToInt32(TextBox5.Text)
m_POS_OutStatus = Convert.ToInt32(TextBox6.Text)
m_PSO_dir = ComboBox3.SelectedIndex - 1
m_Timer_Cycle = Convert.ToInt32(TextBox10.Text)
m_Timer_Valid = Convert.ToInt32(TextBox9.Text)
m_Timer_Num = Convert.ToInt32(TextBox8.Text)
m_Start_Pos = Convert.ToSingle(TextBox12.Text)
m_End_Pos = Convert.ToSingle(TextBox11.Text)
m_RegistAxis = Convert.ToInt32(TextBox1.Text)
For i = 0 To iTotalPoint - 1 Step 1
fPointPos(i) = Convert.ToSingle(DataGridView1.Item('位置', i).Value)
Next
End Sub
(1)编码轴与编码器的接线(Z向锁存)
注意,该接线为单端接法,编码器应与轴使用同一电源,接地时接入内部地(GND,针脚号有10、13、20、21、24)而不能是外部地(EGND,针脚号1)。
(2)编码轴与脉冲轴的接线(R0锁存)
为了观察锁存位置的准确性,通过脉冲轴发出编码信号使编码器记录信息,位置比较输出触发锁存,通过R0上升沿触发锁存,获取锁存位置。
表2 脉冲轴与编码轴接线
表3 位置比较输出与R0锁存接线
本例使用的控制器ZMC406含两个锁存开关锁存A,锁存B,在ZDevelop软件中连接控制器,通过命令窗口检测锁存输入映射REG_INPUTS=$1010。($1010对应十进制4112)。
四
编译运动结果
通过写入控制器程序,初始化设置脉冲轴和编码轴轴参数。
1.位置比较输出
(1)打开比较输出,关闭定时反转信号,设置运动距离2000,完成运动后,如下图。
(2)打开比较输出,打开定时反转信号,设置运动距离2000,完成运动后,如下图。
可见,位置比较输出在定时反转后,上升沿信号会被定时器输出反转,但位置比较不受影响,下一次比较信号时,由于已经是低电平,输出口信号不变。
2.编码器锁存
(1)使用旋转编码器给予编码轴脉冲
以比较输出信号为R0锁存触发信号,使用轴1为编码轴,类型4,模式3,开启锁存,运动距离2000。
本例使用关闭定时反转的位置比较输出的十个点,其中5个上升沿信号,所以触发了5次锁存,保存了编码器的反馈位置。
(2)使用脉冲轴(伪编码器)给予编码轴脉冲
使用位置比较的轴作为脉冲轴,通过ZDevelop设置编码轴其他轴参数与脉冲轴一致,以比较输出信号为R0锁存触发,使用轴1为编码轴,类型6,模式3。
A.开启位置比较,关闭定时反转。
途中IN(0)信号,也就是R0信号使用反向表示,因为本例使用了ZMC控制器为低电平有效,即在IN波形图上表示下降沿时,对应IN口电压为上升沿。
B.开启位置比较,打开定时反转。