今天,正运动小助手为大家分享一下应用C#开发一个多段连续插补的运动控制应用。
我们主要从新建项目,添加函数库讲起,再了解PC函数使用,最后通过项目实战——连续插补运动例程讲解,来让大家熟悉它的项目开发。
在正式学习之前,我们先了解一下正运动技术的运动控制卡ECI2418和ECI2618。这两款产品分别是4轴,6轴运动控制卡。
ECI2418支持4轴脉冲输入与编码器反馈,板载24点输入,16点输出,2AD,2DA,支持手轮接口,其中特定输出口支持高速PWM控制。
ECI2618支持6轴脉冲输入与编码器反馈,板载24点输入,16点输出,2AD,2DA,支持手轮接口,其中特定输出口支持高速PWM控制。
ECI2418,ECI2618均使用同一套API函数,均支持C、C++、C#、LabVIEW、Python、Delphi等开发语言,支持VC6.0、VB6.0、Qt、.Net等平台,支持Windows、Linux、WinCE、iMac等操作系统。
以下是C#
开发流程
01 新建MFC项目,添加函数库。
1.在VS2015菜单“文件”→“新建”→ “项目” ,启动创建项目向导。
2.选择开发语言为“Visual C#”和.NET Framework 4以及Windows 窗体应用程序。
3.找到厂家提供的光盘资料里面的C#函数库,路径如下(64位库为例):
1)进入光盘资料找到PC函数文件夹。
2)选择函数库2.1。
3)Windows平台。
4)根据需要选择对应的函数库这里选择64位库。
5)解压C++的压缩包,里面有C#对应的函数库。
6)函数库具体路径如下图所示。
4.将厂商提供的C#的库文件以及相关文件复制到新建的项目里面。
1)将zmcaux.cs文件复制到新建的项目里面中。
2)将zaux.dll和zmotion.dll文件放入bin\debug文件夹中。
5.用vs打开新建的项目文件,在右边的解决方案资源管理器中点击显示所有,然后鼠标右键点击zmcaux.cs文件,点击包括在项目中。
6.双击Form1.cs里面的Form1,出现代码编辑界面,在文件开头写入 using cszmcaux,并声明控制器句柄g_handle。
至此项目新建完成。
02 查看PC函数手册,了解其用法。
1.PC函数手册也在光盘资料里面,具体路径如下。
17.jpg
2.PC编程,一般先根据控制器连接方式选择对应的连接函数连接控制器,返回控制器句柄。接着用返回的控制器句柄,实现对控制器的控制。
3.比如通过网口连接控制器,先使用ZAux_OpenEth()链接控制器,获取控制器句柄handle。
项目应用截图
4.通过获取到的控制器句柄handle,对控制器进行单轴运动控制。
5.通过获取到的控制器句柄handle,进行多轴绝对插补运动。
int[] axislist = { 0, 1, 2, 3 }; //轴列表
float[] destdis = { 100, 100, 200, 100 }; //运动距离列表
zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);
6.通过获取到的控制器句柄handle,获取控制器缓冲区剩余的缓冲数量。
03 项目实战之连续插补运动例程讲解。
1.例程以建立板卡的连接,执行4段连续轨迹的加工为目标。
2.例程简易流程图。
3.通过网口方式连接控制器,获取控制器连接句柄。
private void button_link_Click ( object sender, EventArgs e) { if ( g_handle !&#61; ( IntPtr) 0 ) { zmcaux. ZAux_Close ( g_handle) ; g_handle &#61; ( IntPtr) 0 ; } zmcaux. ZAux_OpenEth ( comboBox_IpList. Text, out g_handle) ; if ( g_handle !&#61; ( IntPtr) 0 ) { this . Text &#61; "已连接" ; timer1. Enabled &#61; true ; for ( int i &#61; 0 ; i < 4 ; i&#43;&#43; ) { zmcaux. ZAux_Direct_SetAtype ( g_handle, i, 1 ) ; zmcaux. ZAux_Direct_SetUnits ( g_handle, i, 1 ) ; } } else { MessageBox. Show ( "控制器链接失败&#xff0c;请检测IP地址!" , "警告" ) ; } } 4 . 通过定时器1 更新控制器轴0 - 3 的位置和速度等信息。private void timer1_Tick ( object sender, EventArgs e) { int runstate &#61; 0 ; float [ ] curpos &#61; new float [ 4 ] ; float vspeed &#61; 0 ; int remin_buff &#61; 0 ; int curmark &#61; 0 ; for ( int i &#61; 0 ; i < 4 ; i&#43;&#43; ) { zmcaux. ZAux_Direct_GetDpos ( g_handle, i, ref curpos[ i] ) ; } zmcaux. ZAux_Direct_GetIfIdle ( g_handle, 0 , ref runstate) ; zmcaux. ZAux_Direct_GetVpSpeed ( g_handle, 0 , ref vspeed) ; zmcaux. ZAux_Direct_GetRemain_LineBuffer ( g_handle, 0 , ref remin_buff) ; zmcaux. ZAux_Direct_GetMoveCurmark ( g_handle, 0 , ref curmark) ; label_pos. Text &#61; "X:" &#43; curpos[ 0 ] &#43; " Y:" &#43; curpos[ 1 ] &#43; " Z:" &#43; curpos[ 2 ] &#43; " U:" &#43; curpos[ 3 ] ; label_state. Text &#61; Convert. ToString ( runstate &#61;&#61; 0 ? " 运行状态&#xff1a;运行中" : " 运行状态&#xff1a;停止中" ) ; label_vspeed. Text &#61; "当前速度&#xff1a;" &#43; vspeed; label_buff. Text &#61; "剩余缓冲&#xff1a;" &#43; remin_buff; label_mark. Text &#61; "当前MARK&#xff1a;" &#43; curmark; }
5.通过启动按钮的事件处理函数来启动插补运动
private void button_start_Click ( object sender, EventArgs e) { int [ ] axislist &#61; { 0 , 1 , 2 , 3 } ; float [ ] destdis &#61; { 0 , 0 , 0 , 0 } ; int corner_mode &#61; 0 ; int merge_flag &#61; 0 ; int iresult &#61; 0 ; int remin_buff &#61; 0 ; if ( checkBox1. Checked) { corner_mode &#61; corner_mode &#43; 2 ; } if ( checkBox2. Checked) { corner_mode &#61; corner_mode &#43; 8 ; } if ( checkBox3. Checked) { corner_mode &#61; corner_mode &#43; 32 ; } if ( checkBox4. Checked) { merge_flag &#61; 1 ; } zmcaux. ZAux_Direct_SetSpeed ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_sp. Text) ) ; zmcaux. ZAux_Direct_SetAccel ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_acc. Text) ) ; zmcaux. ZAux_Direct_SetDecel ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_dec. Text) ) ; zmcaux. ZAux_Direct_SetMerge ( g_handle, axislist[ 0 ] , merge_flag) ; zmcaux. ZAux_Direct_SetSramp ( g_handle, axislist[ 0 ] , Convert. ToSingle ( SRAMP. Text) ) ; zmcaux. ZAux_Direct_SetForceSpeed ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_for_sp. Text) ) ; zmcaux. ZAux_Direct_SetCornerMode ( g_handle, axislist[ 0 ] , corner_mode) ; zmcaux. ZAux_Direct_SetDecelAngle ( g_handle, axislist[ 0 ] , ( float ) ( Convert. ToSingle ( textBox_ang1. Text) * 3.14 / 180 ) ) ; zmcaux. ZAux_Direct_SetStopAngle ( g_handle, axislist[ 0 ] , ( float ) ( Convert. ToSingle ( textBox_ang2. Text) * 3.14 / 180 ) ) ; zmcaux. ZAux_Direct_SetFullSpRadius ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_radio. Text) ) ; zmcaux. ZAux_Direct_SetZsmooth ( g_handle, axislist[ 0 ] , Convert. ToSingle ( textBox_zsmooth. Text) ) ; zmcaux. ZAux_Direct_SetMovemark ( g_handle, axislist[ 0 ] , 0 ) ; zmcaux. ZAux_Direct_Base ( g_handle, 4 , axislist) ; zmcaux. ZAux_Trigger ( g_handle) ; zmcaux. ZAux_Direct_GetRemain_LineBuffer ( g_handle, 0 , ref remin_buff) ; while ( remin_buff< 4 ) { zmcaux. ZAux_Direct_GetRemain_LineBuffer ( g_handle, 0 , ref remin_buff) ; System. Threading. Thread. Sleep ( 1 ) ; } destdis[ 0 ] &#61; Convert. ToSingle ( destdis1_X. Text) ; destdis[ 1 ] &#61; Convert. ToSingle ( destdis1_Y. Text) ; destdis[ 2 ] &#61; Convert. ToSingle ( destdis1_Z. Text) ; destdis[ 3 ] &#61; Convert. ToSingle ( destdis1_U. Text) ; iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; while ( iresult !&#61; 0 ) { iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; System. Threading. Thread. Sleep ( 1 ) ; } destdis[ 0 ] &#61; Convert. ToSingle ( destdis2_X. Text) ; destdis[ 1 ] &#61; Convert. ToSingle ( destdis2_Y. Text) ; destdis[ 2 ] &#61; Convert. ToSingle ( destdis2_Z. Text) ; destdis[ 3 ] &#61; Convert. ToSingle ( destdis2_U. Text) ; iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; while ( iresult !&#61; 0 ) { iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; System. Threading. Thread. Sleep ( 1 ) ; } destdis[ 0 ] &#61; Convert. ToSingle ( destdis3_X. Text) ; destdis[ 1 ] &#61; Convert. ToSingle ( destdis3_Y. Text) ; destdis[ 2 ] &#61; Convert. ToSingle ( destdis3_Z. Text) ; destdis[ 3 ] &#61; Convert. ToSingle ( destdis3_U. Text) ; iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; while ( iresult !&#61; 0 ) { iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; System. Threading. Thread. Sleep ( 1 ) ; } destdis[ 0 ] &#61; Convert. ToSingle ( destdis4_X. Text) ; destdis[ 1 ] &#61; Convert. ToSingle ( destdis4_Y. Text) ; destdis[ 2 ] &#61; Convert. ToSingle ( destdis4_Z. Text) ; destdis[ 3 ] &#61; Convert. ToSingle ( destdis4_U. Text) ; iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; while ( iresult !&#61; 0 ) { iresult &#61; zmcaux. ZAux_Direct_MoveAbs ( g_handle, 4 , axislist, destdis) ; System. Threading. Thread. Sleep ( 1 ) ; } }
6.通过停止按钮的事件处理函数来停止插补运动。
private void button_stop_Click ( object sender, EventArgs e) { zmcaux. ZAux_Direct_Single_Cancel ( g_handle, 0 , 2 ) ; }
7.轴坐标清零。
private void button_zero_Click ( object sender, EventArgs e) { if ( g_handle &#61;&#61; ( IntPtr) 0 ) { MessageBox. Show ( "未链接到控制器!" , "提示" ) ; } else { for ( int i &#61; 0 ; i < 4 ; i&#43;&#43; ) { zmcaux. ZAux_Direct_SetDpos ( g_handle, i, 0 ) ; } } }
8. 编译运行演示。
编译运行示教例程&#xff0c;同时通过ZDevelop软件连接控制器&#xff0c;对运动控制的轴参数进行监控。
9.连续插补加自动倒角的位置波形。
10.不开启连续插补的速度波形。
11.连续插补加合适的拐角减速的速度波形。
正运动技术《运动控制卡应用开发教程之C#》就讲到这里。更多学习视频及图文&#xff0c;请关注我们的公众号“正运动小助手”。 更多精彩内容请关注“正运动小助手”公众号&#xff0c;需要相关开发环境与例程代码&#xff0c;请咨询正运动技术销售工程师&#xff1a;400-089-8936。
本文由正运动小助手原创&#xff0c;欢迎大家转载&#xff0c;共同学习&#xff0c;一起提高中国智能制造水平。文章版权归正运动技术所有&#xff0c;如有转载请注明文章来源。