正运动:运动控制卡应用开发教程之C#

   2020-11-18 正运动技术14284
核心提示:今天,正运动小助手为大家分享一下应用C#开发一个多段连续插补的运动控制应用。

今天,正运动小助手为大家分享一下应用C#开发一个多段连续插补的运动控制应用。

我们主要从新建项目,添加函数库讲起,再了解PC函数使用,最后通过项目实战——连续插补运动例程讲解,来让大家熟悉它的项目开发。 

在正式学习之前,我们先了解一下正运动技术的运动控制卡ECI2418和ECI2618。这两款产品分别是4轴,6轴运动控制卡。

正运动:运动控制卡应用开发教程之C#

ECI2418支持4轴脉冲输入与编码器反馈,板载24点输入,16点输出,2AD,2DA,支持手轮接口,其中特定输出口支持高速PWM控制。

正运动:运动控制卡应用开发教程之C# 

ECI2618支持6轴脉冲输入与编码器反馈,板载24点输入,16点输出,2AD,2DA,支持手轮接口,其中特定输出口支持高速PWM控制。 

正运动:运动控制卡应用开发教程之C#

ECI2418,ECI2618均使用同一套API函数,均支持C、C++、C#、LabVIEW、Python、Delphi等开发语言,支持VC6.0、VB6.0、Qt、.Net等平台,支持Windows、Linux、WinCE、iMac等操作系统。

以下是C#开发流程

新建MFC项目,添加函数库。

1.在VS2015菜单“文件”→“新建”→ “项目” ,启动创建项目向导。

正运动:运动控制卡应用开发教程之C# 

2.选择开发语言为“Visual C#”和.NET framework 4以及Windows 窗体应用程序。 

正运动:运动控制卡应用开发教程之C#

3.找到厂家提供的光盘资料里面的C#函数库,路径如下(64位库为例): 

1)进入光盘资料找到PC函数文件夹。

正运动:运动控制卡应用开发教程之C#

2)选择函数库2.1。

正运动:运动控制卡应用开发教程之C#

3)Windows平台。

正运动:运动控制卡应用开发教程之C#

4)根据需要选择对应的函数库这里选择64位库。

正运动:运动控制卡应用开发教程之C#

5)解压C++的压缩包,里面有C#对应的函数库。

正运动:运动控制卡应用开发教程之C#

6)函数库具体路径如下图所示。

正运动:运动控制卡应用开发教程之C#

4.将厂商提供的C#的库文件以及相关文件复制到新建的项目里面。

1)将zmcaux.cs文件复制到新建的项目里面中。

正运动:运动控制卡应用开发教程之C# 

2)将zaux.dll和zmotion.dll文件放入bin\debug文件夹中。

 

正运动:运动控制卡应用开发教程之C#

5.用vs打开新建的项目文件,在右边的解决方案资源管理器中点击显示所有,然后鼠标右键点击zmcaux.cs文件,点击包括在项目中。  

正运动:运动控制卡应用开发教程之C#
 正运动:运动控制卡应用开发教程之C#

6.双击Form1.cs里面的Form1,出现代码编辑界面,在文件开头写入 using cszmcaux,并声明控制器句柄g_handle。

正运动:运动控制卡应用开发教程之C# 

至此项目新建完成。 

查看PC函数手册,了解其用法。

1.PC函数手册也在光盘资料里面,具体路径如下。

正运动:运动控制卡应用开发教程之C#

2.PC编程,一般先根据控制器连接方式选择对应的连接函数连接控制器,返回控制器句柄。接着用返回的控制器句柄,实现对控制器的控制。

3.比如通过网口连接控制器,先使用ZAux_OpenEth()链接控制器,获取控制器句柄handle。 

正运动:运动控制卡应用开发教程之C#
正运动:运动控制卡应用开发教程之C#

正运动:运动控制卡应用开发教程之C#
项目应用截图

4.通过获取到的控制器句柄handle,对控制器进行单轴运动控制。

正运动:运动控制卡应用开发教程之C#

5.通过获取到的控制器句柄handle,进行多轴绝对插补运动。

正运动:运动控制卡应用开发教程之C#

int[] axislist = { 0, 1, 2, 3 };         //轴列表

float[] destdis = { 100, 100, 200, 100 };  //运动距离列表

zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);

6.通过获取到的控制器句柄handle,获取控制器缓冲区剩余的缓冲数量。

正运动:运动控制卡应用开发教程之C#
正运动:运动控制卡应用开发教程之C#  

//获取存放直线的剩余缓冲

zmcaux.ZAux_Direct_GetRemain_LineBuffer(g_handle, 0,ref remin_buff);

//获取存放空间圆弧的剩余缓冲,空间圆弧也是占缓冲最大的运动

zmcaux.ZAux_Direct_GetRemain_Buffer(g_handle,0, ref remin_buff);

项目实战之连续插补运动例程讲解。

1.例程以建立板卡的连接,执行4段连续轨迹的加工为目标。

 

正运动:运动控制卡应用开发教程之C#

2.例程简易流程图。

正运动:运动控制卡应用开发教程之C#

3.通过网口方式连接控制器,获取控制器连接句柄。

//连接控制器

private void button_link_Click(object sender, EventArgs e)

{

    if (g_handle != (IntPtr)0)

    {

        zmcaux.ZAux_Close(g_handle);//断开连接

        g_handle = (IntPtr)0;

    }

    zmcaux.ZAux_OpenEth(comboBox_IpList.Text, out g_handle);//连接控制器

    if (g_handle != (IntPtr)0)

    {

        this.Text = "已连接";

        timer1.Enabled = true;

        //初始化轴参数

        for (int i = 0; i < 4; i++)

        {

            zmcaux.ZAux_Direct_SetAtype(g_handle, i, 1);//轴类型 脉冲轴

            zmcaux.ZAux_Direct_SetUnits(g_handle, i, 1);//脉冲当量 

        }

    }

    else

    {

        MessageBox.Show("控制器链接失败,请检测IP地址!", "警告");

    }

}

4.通过定时器1更新控制器轴0-3的位置和速度等信息。

//定时器刷新

private void timer1_Tick(object sender, EventArgs e)

{

    int runstate = 0;

    float[] curpos = new float[4];

    float vspeed = 0;

    int remin_buff = 0;

    int curmark = 0;

    //获取轴位置

    for (int i = 0; i < 4; i++)

    {

        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 = "X:" + curpos[0] + "  Y:" + curpos[1] + "  Z:" + curpos[2] + "  U:" + curpos[3];

    label_state.Text = Convert.ToString(runstate == 0 ? "   运行状态:运行中" : "    运行状态:停止中");

    label_vspeed.Text = "当前速度:" + vspeed;

    label_buff.Text = "剩余缓冲:" + remin_buff;

    label_mark.Text = "当前MARK:" + curmark;

}

5.通过启动按钮的事件处理函数来启动插补运动。 

//启动按钮

private void button_start_Click(object sender, EventArgs e)

{

    int[]   axislist = { 0, 1, 2, 3 };      //轴列表

    float[] destdis = { 0, 0, 0, 0 };      //运动距离列表

    int corner_mode = 0;                   //拐角模式

    int  merge_flag = 0;                   //连续插补

    int  iresult = 0;                      //PC函数返回值

    int  remin_buff = 0;            //剩余直线缓冲数

    if (checkBox1.Checked)

    {

        corner_mode = corner_mode + 2;

    }

    if(checkBox2.Checked)

    {

        corner_mode = corner_mode + 8;

    }

    if(checkBox3.Checked)

    {

        corner_mode = corner_mode + 32;

    }

    if (checkBox4.Checked)

    {

        merge_flag = 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);

    //S曲线时间

    zmcaux.ZAux_Direct_SetSramp(g_handle, axislist[0], Convert.ToSingle(SRAMP.Text));

    //设置SP速度

    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));

    //设置MARK = 0 ,来通过读取CURMARK实现判断当前执行到那里

    zmcaux.ZAux_Direct_SetMovemark(g_handle, axislist[0], 0);

    //选择base轴

    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); //1毫秒

    }

    //第一段插补运动

    destdis[0] = Convert.ToSingle(destdis1_X.Text);

    destdis[1] = Convert.ToSingle(destdis1_Y.Text);

    destdis[2] = Convert.ToSingle(destdis1_Z.Text);

    destdis[3] = Convert.ToSingle(destdis1_U.Text);

    iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);//4轴插补指令

    //函数返回非0 则表示发送不成功,缓冲区可能满了,重新发送

    while (iresult != 0)

    {

        iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);

        System.Threading.Thread.Sleep(1); //1毫秒

    }

    //第二段插补运动

    destdis[0] = Convert.ToSingle(destdis2_X.Text);

    destdis[1] = Convert.ToSingle(destdis2_Y.Text);

    destdis[2] = Convert.ToSingle(destdis2_Z.Text);

    destdis[3] = Convert.ToSingle(destdis2_U.Text);

    iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);//4轴插补指令

    //函数返回非0 则表示发送不成功,缓冲区可能满了,重新发送

    while (iresult != 0)

    {

        iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);

        System.Threading.Thread.Sleep(1); //1毫秒

    }

    //第三段插补运动

    destdis[0] = Convert.ToSingle(destdis3_X.Text);

    destdis[1] = Convert.ToSingle(destdis3_Y.Text);

    destdis[2] = Convert.ToSingle(destdis3_Z.Text);

    destdis[3] = Convert.ToSingle(destdis3_U.Text);

    iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);//4轴插补指令

    //函数返回非0 则表示发送不成功,缓冲区可能满了,重新发送

    while (iresult != 0)

    {

        iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);

        System.Threading.Thread.Sleep(1); //1毫秒

    }

    //第四段插补运动

    destdis[0] = Convert.ToSingle(destdis4_X.Text);

    destdis[1] = Convert.ToSingle(destdis4_Y.Text);

    destdis[2] = Convert.ToSingle(destdis4_Z.Text);

    destdis[3] = Convert.ToSingle(destdis4_U.Text);

    iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);//4轴插补指令

    //函数返回非0 则表示发送不成功,缓冲区可能满了,重新发送

    while (iresult != 0)

    {

        iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);

        System.Threading.Thread.Sleep(1); //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 == (IntPtr)0)

    {

        MessageBox.Show("未链接到控制器!", "提示");

    }

    else

    {

        for (int i = 0; i < 4; i++)

        {

            zmcaux.ZAux_Direct_SetDpos(g_handle, i, 0);

        }

    }

}

8. 编译运行演示。 

编译运行示教例程,同时通过ZDevelop软件连接控制器,对运动控制的轴参数进行监控。 

9.连续插补加自动倒角的位置波形。

正运动:运动控制卡应用开发教程之C#

10.不开启连续插补的速度波形。

正运动:运动控制卡应用开发教程之C#
正运动:运动控制卡应用开发教程之C#

正运动:运动控制卡应用开发教程之C#

11.连续插补加合适的拐角减速的速度波形。

正运动:运动控制卡应用开发教程之C#  

 正运动:运动控制卡应用开发教程之C#

 正运动:运动控制卡应用开发教程之C#

 

 
分享到: 0
收藏 0
 
更多>同类方案
免责申明
推荐方案
点击排行
最新资讯更多>
最新供应更多>
网站首页  |  联系方式  |  关于我们  |  问题解析  |  版权隐私  |  使用协议  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  粤ICP备1207862号

中国智能化网(zgznh®)--引领工业智能化产业发展 共享智能化+优质平台

版权所有:深圳市智控网络有限公司 学术指导:深圳市智能化学会

粤ICP备12078626号

深公网安备案证字第 4403101901094 号 | 粤公网安备 44030702001206号