ethercat超高速实时运动控制卡xpcie1032h上位机c#开发(二):ethercat总线初始化 -k8体育

中国自动化学会专家咨询工作委员会指定宣传媒体
文摘详情

ethercat超高速实时运动控制卡xpcie1032h上位机c#开发(二):ethercat总线初始化

http://www.gkong.com 2023-11-16 15:52

xpcie1032h功能简介

xpcie1032h是一款基于pci express的ethercat总线运动控制卡,可选6-64轴运动控制,支持多路高速数字输入输出,可轻松实现多轴同步控制和高速数据传输。

xpcie1032h集成了强大的运动控制功能,结合motionrt7运动控制实时软核,解决了高速高精应用中,pc windows开发的非实时痛点,指令交互速度比传统的pci/pcie快10倍。

企业微信截图_20231116091426.png

xpcie1032h 支持pwm,pso功能,板载16进16出通用io口,其中输出口全部为高速输出口,可配置为4路pwm输出口或者16路高速pso硬件比较输出口。输入口含有8路高速输入口,可配置为4路高速色标锁存或两路编码器输入。

xpcie1032h搭配motionrt7实时内核,使用本地local接口连接,通过高速的核内交互 ,可以做到更快速的指令交互,单条指令与多条指令一次性交互时间可以达到3-5us左右。

企业微信截图_20231116091450.png

?xpcie1032h与motionrt7实时内核的配合具有以下优势:

企业微信截图_20231116091505.png

1.支持多种上位机语言开发,所有系列产品均可调用同一套api函数库;

2.借助核内交互,可以快速调用 运动指令,响应时间快至微秒级,比传统pci/pcie快10倍;

3.解决传统pci/pcie运动控制卡在windows环境下控制系统的非实时性问题;

4.支持一维/二维/三维pso(高速硬件位置比较输出),适用于视觉飞拍、精密点胶和激光能量控制等应用;

5.提供高速输入接口,便于实现位置锁存;

6.支持ethercat总线和脉冲输出混合联动、混合插补。

企业微信截图_20231116091527.png

?使用xpcie1032h和motionrt7进行项目开发时,通常需要进行以下步骤:

1.安装驱动程序,识别xpcie1032h;

2.打开并执行文件“motionrt710.exe”,配置参数和运行运动控制实时内核;

3.使用zdevelop软件连接到控制器,进行参数监控。连接时请使用pci/local方式,并确保zdevelop软件版本在3.10以上;

4.完成控制程序开发,通过local链接方式连接到运动控制卡,实现实时运动控制。

企业微信截图_20231116091603.png

?与传统pci/pcie卡和plc的测试数据结果对比:

企业微信截图_20231116091622.png

我们可以从测试对比结果看出,xpcie1032h运动控制卡配合实时运动控制内核motionrt7,在local链接(核内交互)的方式下,指令交互的效率是非常稳定,当测试数量从1w增加到10w时,单条指令交互时间与多条指令交互时间波动不大,非常适用于高速高精的应用。

xpcie1032h卡安装

  • 关闭计算机电源。

  • 打开计算机机箱,选择一条空闲的xpcie卡槽,用螺丝刀卸下相应的挡板条。

  • 将运动控制卡插入该槽,拧紧挡板条上的固定螺丝。

xpcie1032h驱动安装与建立连接参考往期文章

一、新建c#项目(vs2022)

企业微信截图_20231116091638.png

到正运动技术k8体育官网的下载中心选择需要的平台库文件。

下载地址: http://www.zmotion.com.cn/download_list_21.html

企业微信截图_20231116091739.png

解压下载的安装包找到 “ zmcaux.cs ” , “ zauxdll.dll ” , “ zmotion.dll ” 放入到项目文件中。

1、“zmcaux.cs”放在项目根目录文件中,与bin目录同级。

企业微信截图_20231116091752.png

2、“zauxdll.dll”,“zmotion.dll”放在bin -> debug。

企业微信截图_20231116091803.png

用vs打开新建的项目文件,在右边的k8体育的解决方案资源管理器中点击显示所有,选中项目,右键“添加”->“现有项”,选中zmcaux.cs文件添加进在项目中。

企业微信截图_20231116091822.png

企业微信截图_20231116091836.png

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

企业微信截图_20231116091850.png

二、相关pc函数介绍

相关pc函数介绍详情可参考“zmotion pc函数库编程手册 v2.1.1”。

qq截图20231116092358.png

企业微信截图_20231116092553.png

企业微信截图_20231116092614.png

企业微信截图_20231116092631.png

企业微信截图_20231116092646.png

企业微信截图_20231116092656.png

企业微信截图_20231116092707.png

企业微信截图_20231116092719.png

企业微信截图_20231116092731.png

企业微信截图_20231116092743.png

企业微信截图_20231116092754.png

企业微信截图_20231116092805.png

企业微信截图_20231116092820.png

其他基本轴参数指令:

企业微信截图_20231116092834.png

在form设计界面找到需要用到的控件拖拽到窗体中进行ui界面设计,设计效果图如下。

企业微信截图_20231116093228.png

三、相关程序以及设计思路

1、通过local链接方式,按钮控件的的click事件触发链接控制卡。

private void local_connect_button_click(object sender, eventargs e)
{
    if (g_handle == (intptr)0)
    {
        local_disconnect_button_click(sender, e);
    }
    zmcaux.zaux_fastopen(5, "local", 1000, out g_handle);
    if (g_handle != (intptr)0)
    {
        this.text = "已链接";
        timer1.enabled = true;
        local_connect_button.backcolor = color.green;
        messagebox.show("链接成功");
    }
    else
    {
        messagebox.show("链接失败,请选择正确的local!");
    }
}

2、选择总线初始化的bas脚本文件下载到控制器rom里面掉电保存。

提前在zdevelop软件根据需求修改总线初始化的basic程序,映射轴,节点io等初始化内容。

这里以节点0(汇川驱动器-0轴)、节点1(eio16084)的1-4轴映射为总线轴为例,将节点之间通过ethercat口连接起来。如下图:

46a84823-b44a-485f-bc8e-dbe4cf0219ce.png

相关初始化basic 程序(其中红色为指令,可以到正运动k8体育官网查阅其使用场景以及方法)。

相关配置如下:

'ecat总线初始化
global const bus_type = 0         '总线类型。可用于上位机区分当前总线类型
global const bus_slot  = 0        '槽位号0(单总线控制器缺省0)
global const pul_axisstart   = 0    '本地脉冲轴起始轴号
global const pul_axisnum   = 0    '本地脉冲轴轴数量
global const bus_axisstart   = 0      '总线轴起始轴号
global const bus_nodenum   = 1      '总线配置节点数量,用于判断实际检测到的从站数量是否一致
global max_axisnum        '最大轴数
max_axisnum = sys_zfeature(0)
global bus_initstatus      '总线初始化完成状态
bus_initstatus = -1
global bus_totalaxisnum    '检查扫描的总轴数
delay(3000)        '延时3s等待驱动器上电,不同驱动器自身上电时间不同,具体根据驱动器调整延时
?"总线通讯周期:",servo_period,"us"
ecat_init()      '初始化ecat总线 
end
global sub ecat_init()
  local node_num,temp_axis,drive_vender,drive_device,drive_alias
  rapidstop(2)
  for i = 0 to sys_zfeature(0) - 1                '初始化还原轴类型          
    axis_enable(i) = 0
    atype(i) = 0  
    delay(20)
  next
  
  bus_initstatus = -1
  bus_totalaxisnum = 0  
  slot_stop(bus_slot)        
  delay(200)
  slot_scan(bus_slot)                      '扫描总线
  if return then 
    ?"总线扫描成功","连接从站设备数:"node_count(bus_slot)
    if node_count(bus_slot) <> bus_nodenum then    '判断总线检测数量是否为实际接线数量
      ?""  
      ?"扫描节点数量与程序配置数量不一致!" ,"配置数量:"bus_nodenum,"检测数量:"node_count(bus_slot)
      bus_initstatus = 0    '初始化失败。报警提示
    endif   
    
    '"开始映射轴号"
    for node_num = 0 to node_count(bus_slot)-1            '遍历扫描到的所有从站节点
      drive_vender = node_info(bus_slot,node_num,0)        '读取驱动器厂商
      drive_device = node_info(bus_slot,node_num,1)        '读取设备编号
      drive_alias = node_info(bus_slot,node_num,3)          '读取设备拨码id
      
      if node_axis_count(bus_slot,node_num) <> 0 then      '判断当前节点是否有电机
        for j=0 to node_axis_count(bus_slot,node_num)-1    '根据节点带的电机数量循环配置轴参数(针对一拖多驱动器)
        
          temp_axis = bus_axisstart   bus_totalaxisnum    '轴号按node顺序分配
          base(temp_axis)
          axis_address = bus_totalaxisnum 1          '映射轴号
          atype = 65                      '设置控制模式 65-位置 66-速度 67-转矩 
          drive_profile = 18
          sub_setdriverio(temp_axis,drive_vender,48   48*temp_axis)    '映射驱动器io  io映射到控制器io32-以后每个驱动器间隔32点      
          disable_group(temp_axis)              '每轴单独分组
          bus_totalaxisnum = bus_totalaxisnum 1          '总轴数 1
        next
      endif
    next
    
    ?"轴号映射完成","连接总轴数:"bus_totalaxisnum
    
    wa 200
    slot_start(bus_slot)        '启动总线
    if return then 
      
      wdog = 1              '使能总开关
      for i = bus_axisstart to bus_axisstart   bus_totalaxisnum - 1 
        base(i)
        delay 50        
        axis_enable = 1
      next
      bus_initstatus  = 1
      ?"轴使能完成"
      
      ?"总线开启成功"      
    else
      ?"总线开启失败"
      bus_initstatus = 0
    endif
  else
    ?"总线扫描失败"
    bus_initstatus = 0
  endif
endsub
'总线驱动io映射
'iaxis - 轴号 ivender - 驱动器类型  i_ionum - 输入输出起始编号
global sub sub_setdriverio(iaxis,ivender,i_ionum) 
drive_io(iaxis) = i_ionum
fwd_in(iaxis) = i_ionum
rev_in(iaxis) = i_ionum   1              
datum_in(iaxis) = i_ionum   2      
invert_in(i_ionum,on)          
invert_in(i_ionum   1,on)
invert_in(i_ionum   2,on) 
endsub

利用按钮的click事件,浏览选择编辑好的bas文件下载掉电保存,并弹出反馈下载是否成功的提示。

private void basfiledownload_btn_click(object sender, eventargs e)
{
    if (g_handle == (intptr)0)
    {
        messagebox.show("未链接到控制器!", "提示");
    }
    else
    {
        int tmpret = 0;
        string strfilepath;
        openfiledialog openfiledialog1 = new openfiledialog();
        openfiledialog1.initialdirectory = "\\";
        openfiledialog1.filter = "配置文件(*.bas)|*.bas";
        openfiledialog1.restoredirectory = true;
        openfiledialog1.filterindex = 1;
        if (openfiledialog1.showdialog() == dialogresult.ok)            
        {
            //打开配置文件
            strfilepath = openfiledialog1.filename;
            //下载到rom
            tmpret = zmcaux.zaux_basdown(g_handle, strfilepath, 1);        
            if (tmpret != 0)
            {
                messagebox.show("文件下载失败!", "提示");
            }
            else
            {                       
                messagebox.show("文件下载成功!", "提示");
            }
        }
    }
}

3、通过按钮控件的click事件触发初始化。

调用函数库的zaux_execute函数(在线命令),通过在线命令调用basic脚本里面的总线初始化函数-- ecat_init()进行总线初始化。

private void ecatinitstart_btn_click(object sender, eventargs e)
{
    if (g_handle == (intptr)0)
    {
        messagebox.show("未链接到控制器!", "提示");
    }
    else
    {
        int tmpret;
        //-1可能正在执行初始化
        if ((basflag == true) && (initstatus != -1))        
        {
            initstatus = -1;
            stringbuilder buffer = new stringbuilder(10240);
            tmpret = zmcaux.zaux_execute(g_handle, "runtask 1,ecat_init", buffer, 0);        //任务1重新运行bas中的初始化函数
            if (tmpret != 0)
            {
                messagebox.show("总线初始化失败!", "提示");
                return;
            }
            else
            {   
                messagebox.show("总线初始化成功!", "提示");
            }
        }
        else
        {
            messagebox.show("bas文件未加载");
            return;
        }
    }
}

4、以汇川驱动器为例,驱动器io映射的起始地址为di1,也就是正向超程开关(正硬限位),若要设置负向超程开关,将起始地址加1。

可以通过按钮控件的click事件,触发设置轴的软限位,以及原点、正负硬限位。驱动器io映射的basic指令是drive_io。在这里调用在线命令的pc函数去实现驱动器io映射。

basic指令说明见下图:

企业微信截图_20231116093300.png

drive_io -- 驱动器io:

企业微信截图_20231116093313.png

通过按钮控件的click事件,配置轴的正负软限位和驱动器io起始地址(正负硬限位io映射)。

private void configure_ok_button_click(object sender, eventargs e)
{
    stringbuilder buffer = new stringbuilder(10240);
    //正向软限位设置
    zmcaux.zaux_direct_setfslimit(g_handle, moveaxis, convert.tosingle(fslimit_value.text));
    //负向软限位设置
    zmcaux.zaux_direct_setrslimit(g_handle, moveaxis, convert.tosingle(rslimit_value.text));          
    //驱动器io起始地址           
    zmcaux.zaux_execute(g_handle, "drive_io("   moveaxis.tostring()   ") = "  drivestart_io_value.value.tostring(), buffer, 0);
    //正硬限位设置
    zmcaux.zaux_direct_setfwdin(g_handle, moveaxis, drive_start_io);
    zmcaux.zaux_direct_setinvertin(g_handle, drive_start_io, 1);
    //负硬限位设置
    zmcaux.zaux_direct_setrevin(g_handle, moveaxis, drive_start_io   1);
    zmcaux.zaux_direct_setinvertin(g_handle, drive_start_io   1, 1);
    messagebox.show("当前轴配置成功!", "提示");
}

5、通过按钮控件的mousedown(鼠标在组件上方并按下时发生)事件来触发单轴持续运动;mouseup(鼠标在组件上方并松开时发生)事件来触发单轴运动的停止。模拟手动运动的调试过程。

//正向
private void fwd_button_mousedown(object sender, mouseeventargs e)
{ 
    zmcaux.zaux_direct_single_vmove(g_handle, moveaxis, 1);
}
private void fwd_button_mouseup(object sender, mouseeventargs e)
{
    zmcaux.zaux_direct_single_cancel(g_handle, moveaxis, 2);
}
//负向
private void rev_button_mousedown(object sender, mouseeventargs e)
{
    zmcaux.zaux_direct_single_vmove(g_handle, moveaxis, -1);
}
private void rev_button_mouseup(object sender, mouseeventargs e)
{
    zmcaux.zaux_direct_single_cancel(g_handle, moveaxis, 2);
}

6、通过textbook控件的 textchanged(空间上text属性更改时发生)事件来修改运动过程中轴的基本参数,定时器会获取接收。

//脉冲当量变化
private void units_value_textchanged(object sender, eventargs e)
{
    zmcaux.zaux_direct_setunits(g_handle, moveaxis, convert.tosingle(units_value.text));
}
//轴速度变化
private void speed_value_textchanged(object sender, eventargs e)
{
    zmcaux.zaux_direct_setspeed(g_handle, moveaxis, convert.tosingle(speed_value.text));
}
//加速度变化
private void accel_value_textchanged(object sender, eventargs e)
{
    zmcaux.zaux_direct_setaccel(g_handle, moveaxis, convert.tosingle(accel_value.text));
}
//减速度变化
private void decel_value_textchanged(object sender, eventargs e)
{
    zmcaux.zaux_direct_setdecel(g_handle, moveaxis, convert.tosingle(decel_value.text));
}

7、通过按钮控件,与文本信息比对,触发总线轴的使能切换功能。

private void enable_button_click(object sender, eventargs e)
{
    if (g_handle == (intptr)0)
    {
        messagebox.show("未链接到控制器!", "提示");
        return;
    }
    int ret = 0;
    if (enable_value.text == "on")
    {
        ret = zmcaux.zaux_direct_setaxisenable(g_handle, moveaxis, 0);
    }
    else
    {
        ret = zmcaux.zaux_direct_setaxisenable(g_handle, moveaxis, 1);
    }
}

8、通过复选框的切换、单选框的选择实现寸动运动调试的功能。

//寸动方向选择
private void movedirection_checkedchanged(object sender, eventargs e)
{
    if (movedirection.checked == false)
    {
        movedirection.text = "运动方向: 正";
        dir = 1;
    }
    else
    {
        movedirection.text = "运动方向: 负";
        dir = -1;
    }
}
//寸动启动
private void inchstart_button_click(object sender, eventargs e)
{
    if (g_handle == (intptr)0)
    {
        messagebox.show("未链接到控制器!", "提示");
    }
    else
    {
        //绝对运动
        if (moveabs_radbtn.checked == true)     
        {
            zmcaux.zaux_direct_single_moveabs(g_handle, moveaxis, dir * convert.tosingle(inchdistance_value.text));
        }
        //相对运动
        if (moveopp_radbtn.checked == true)        
        {
            zmcaux.zaux_direct_single_move(g_handle, moveaxis, dir * convert.tosingle(inchdistance_value.text));
        }
    }
}

9、通过定时器的刷新,对轴参数的接收,初始化信息,io监控等信息进行实时的反馈。

//轴参数更新
private void update_axispara()
{
    int curaxisatype = 0;
    int curaxisidle = 0;
    int curaxisstatus = 0;  
    double curaxisfslimit = 0;
    double curaxisrslimit = 0;
    double curaxisdpos = 0;
    double curaxismpos = 0;
    axis_para[0] = convert.tosingle(units_value.text);
    axis_para[1] = convert.tosingle(speed_value.text);
    axis_para[2] = convert.tosingle(accel_value.text);
    axis_para[3] = convert.tosingle(decel_value.text);         
    moveaxis = convert.toint32(axisnum_value.text);
    zmcaux.zaux_direct_getatype(g_handle, moveaxis, ref curaxisatype);
    zmcaux.zaux_direct_getdpos(g_handle, moveaxis, ref curaxisdpos);
    zmcaux.zaux_direct_getmpos(g_handle, moveaxis, ref curaxismpos);
    zmcaux.zaux_direct_getifidle(g_handle, moveaxis, ref curaxisidle);
    zmcaux.zaux_direct_getaxisstatus(g_handle, moveaxis, ref curaxisstatus);
    zmcaux.zaux_direct_getunits(g_handle, moveaxis, ref axis_para[0]);
    zmcaux.zaux_direct_getspeed(g_handle, moveaxis, ref axis_para[1]);
    zmcaux.zaux_direct_getaccel(g_handle, moveaxis, ref axis_para[2]);
    zmcaux.zaux_direct_getdecel(g_handle, moveaxis, ref axis_para[3]);       
    zmcaux.zaux_direct_getfslimit(g_handle, moveaxis, ref curaxisfslimit);
    zmcaux.zaux_direct_getrslimit(g_handle, moveaxis, ref curaxisrslimit);
    if (ecatinitflag == true)   //总线初始化完成后实时显示状态信息
    {
        axisatype_label.text = "轴 类 型:  "   curaxisatype;
        axisdpos_label.text = "dpos位置:  "   curaxisdpos;
        axismpos_label.text = "mpos位置:  "   curaxismpos;
        axisidle_label.text = "运动状态:  "   curaxisidle;
        axisstatus_label.text = "轴 状 态:  "   curaxisstatus;
    } 
}

10、通过按钮控件的的click事件触发断开链接。

private void local_disconnect_button_click(object sender, eventargs e)
{
    timer1.enabled = false;
    zmcaux.zaux_close(g_handle);
    g_handle = (intptr)0;
    local_disconnect_button.backcolor = color.white;
    this.text = "未连接";
}

四、运行效果

运行主界面如下:

企业微信截图_20231116093328.png

视频讲解:

附录:basic初始化程序通用模板

global const bus_type = 0         '总线类型。用于上位机区分当前模式
global const max_axisnum = 32       '最大轴数
global const bus_slot  = 0        '槽位号0
global const bus_axisstart   = 0    '总线轴起始轴号
global bus_initstatus      '总线初始化完成状态
bus_initstatus = -1
global bus_totalaxisnum    '检查扫描的总轴数
delay(3000)        '延时3s等待驱动器上电
'**********************初始化ecat总线**********************
ecat_init()
    global sub ecat_init()
    for i=0 to max_axisnum - 1    '初始化还原轴类型          
        axis_enable(i) = 0
        atype(i)=0  
    next
    bus_initstatus = -1
    bus_totalaxisnum = 0  
    slot_stop(bus_slot)
    delay(200)
    slot_scan(bus_slot)                      '开始扫描
    if return then
        ?"总线扫描成功","连接设备数:"node_count(bus_slot)
        ?"开始映射轴号"
    endif
        
    for i=0 to node_count(bus_slot)-1        '遍历总线下所有从站节点
        if node_axis_count(bus_slot,i) <>0 then    '判断当前节点是否有电机
            for j=0 to node_axis_count(bus_slot,i)-1
                axis_address(bus_axisstart i)=bus_totalaxisnum 1    '映射轴号
                atype(bus_axisstart i)=65            '设置控制模式 
                drive_profile(bus_axisstart i)= 4        '设置profile功能
                disable_group(bus_axisstart i)          '每轴单独分组
                drive_io(bus_axisstart i) = 128   (bus_axisstart i)*16  
                rev_in(bus_axisstart i) = 128   (bus_axisstart i)*16 
                fwd_in(bus_axisstart i) = 129   (bus_axisstart i)*16
                datum_in(bus_axisstart i) = 130   (bus_axisstart i)*16
                invert_in(128   (bus_axisstart i)*16,on)
                invert_in(129   (bus_axisstart i)*16,on)
                invert_in(130   (bus_axisstart i)*16,on)
                bus_totalaxisnum=bus_totalaxisnum 1          '总轴数 1
            next
        endif
    next
    ?"轴号映射完成","连接总轴数:"bus_totalaxisnum
    wa 2000
    slot_start(bus_slot)            '启动总线
    if return then 
        ?"总线开启成功"
        ?"开始清除驱动器错误(根据驱动器数据字典设置)"
        for i= bus_axisstart to bus_axisstart   bus_totalaxisnum - 1
            drive_controlword(i)=128          '根据驱动器数据字典
            wa 100
            drive_controlword(i)=6
            wa 100
            drive_controlword(i)=15
            wa 100
        next
        ?"驱动器错误清除完成"
        wa 100
        ?"清除控制器错误"
        datum(0)
        drive_clear(0)
        ?"控制器错误清除完成"
        wa 100
        ?"轴使能准备"
        for i= bus_axisstart to bus_axisstart   bus_totalaxisnum - 1
            base(i)
            axis_enable=1
        next
        wdog=1                      '使能总开关
        bus_initstatus  = 1
        ?"轴使能完成"
    else
        ?"总线开启失败"
        bus_initstatus = 0
        endif
    ?"总线扫描失败"
    bus_initstatus  = 0
end sub

企业微信截图_20231116093346.png

本次,正运动技术ethercat超高速实时运动控制卡xpcie1032h上位机c#开发(二):ethercat总线初始化,就分享到这里。

更多精彩内容请关注“ 正运动小助手 ”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章k8凯发的版权归正运动技术所有,如有转载请注明文章来源。

正运动技术专注于运动控制技术研究和通用运动控制软硬件产品的研发,是国家级高新技术企业。正运动技术汇集了来自华为、中兴等公司的优秀人才,在坚持自主创新的同时,积极联合各大高校协同运动控制基础技术的研究,是国内工控领域发展最快的企业之一,也是国内少有、完整掌握运动控制核心技术和实时工控软件平台技术的企业。主要业务有:运动控制卡_运动控制器_ethercat运动控制卡_ethercat控制器_运动控制系统_视觉控制器__运动控制plc_运动控制_机器人控制器_视觉定位_xpcie/xpci系列运动控制卡等等。

k8凯发的版权所有 中华工控网 k8凯发 copyright©2023 gkong.com, all rights reserved
网站地图