注册名:

密码:

个人注册

企业注册

商务申请

商务管理平台

企业管理平台

个人管理平台

我的工控博客

中国工控网www.chinakong.com

首页 | 新闻中心 | 工控论坛 | 经验视点 | 工控商务 | 电气手册 | 工控博客 | 招聘求职 | 网上调查 | 企业中心 | 供求信息 | 资料中心 | 工控书店

所在位置:工控博客苑 -- 运动控制系统 -- 控制卡应用编程技巧几招(2)

中国工控网搜索:

钟天玉先生

     学历:大学本科
     职称:工程师
     年龄:42岁
       新闻信息(7/2)
       工作图片(0)
       技术论文(2/7)
       交流论坛(19/20)
       留言信箱(4)
       浏览人次:16767
       给我发消息
 我的新闻推荐 更多..

控制卡应用编程技巧几招(2)

发表评论(2)   作者:天    发布时间:2010年6月10日  

    三、 插补和联动函数
    当程序员决定需要几轴进行插补时,尽量选择最大插补轴数,如在雕铣系统时,有时会用到两轴插补,有时会进行三轴插补,在这个基础上,为简化编程,我的理论只使用三轴插补,当需要进行两轴插补或联动时,根据相对或绝对的坐标关系,将不运动轴填入0偏移或绝对位置即可。
    以下为XYZ三轴联动和插补的函数,由nFlag的M_INP位决定是否进行插补:
   
    void MoveXYZ( double fX, double fY, double fZ, const tag_SPEED &speed,
    int nFlag = M_ABS )
    {
    short axisArray[]={ XCH, YCH, ZCH };
   
    if( nFlag & M_INP == M_INP )
    {//插补
    long distArray[]={ M2P(XCH, fX), M2P(YCH,fY), M2P(ZCH,fZ) };
    long nStart, nSpeed;//计算新的矢量速度,参见DMC1000矢量速度的计算
    (…矢量速度计算在此略去)
   
    ( nFlag & M_ABS == M_ABS ) ?
    d1000_start_ta_line( 3, axisArray, nStart, nSpeed, speed,accel )://绝对
    d1000_start_t_line(3, axisArray, nStart, nSpeed, accel );//相对
    }
    else
    {//联动
    double fpos[]={ fX, fY, fZ};
    for( int I(0); I<3; I++)//发三次单轴移动命令
    Move( axisArray[I], fpos[I], speed, nFlag );
    }
    }
    在我给出的DMC3000控制卡类完整源代码一文中,有其更完善的版本。通过以下的函数封装,将插补和联动,绝对位置,相对位置等等都很好的整合在一起,用户在使用起来具体更准确的目标。
   
    四、 驱动轴状态、位置读取和设定
    对于驱动轴的状态,分为两种:1、指脉冲输出状态;2、指专用输入信号电平状态
    检测脉冲输出是否完成,可以写成如下函数,假设软件总共只用到XYZ三轴:
   
    int IsRunning( int nAxis = -1 )//默认为-1是有目的的
    {
    if( nAxis != -1 )
    return d1000_check_done( nAxis ) == 0 ;
    //当nAxis == -1时,检测三个轴是否有一个在运行,这种检测在加工时常用
    return d1000_check_done( XCH ) == 0 ||
    d1000_check_done( YCH ) == 0 ||
    d1000_check_done( ZCH ) == 0;
    }
   
    当用户等待YCH脉冲发完,则用一个循环检测即可:
    while( g_DmcCard.IsRuning( YCH ) ) ::DoEvents();
   
    别忘了,IsRuning是CctrlCard的成员函数,而DoEvents函数在DMC1000不能响应系统消息的文章中有详细实现和功能描述。
    在实际加工时,作插补时,常需要等待上次所有运动结束才开始新的运动。故有如下表现:
   
    for( int I(0),step(0); I
    {
    DoEvents();
    switch( m_nworkStatus ){
    case Pause:
    continue;
    case Continue: m_nWorkStatus = Running;
    case Running:
    {
    switch( step ){
    case 0:
    if( IsRunning() ) break;//检测所有运动结束,否则继续检测
    MoveXYZ( data[I].x, data[I].y, data[I].z …… );
    Step ++;
    Break;
    Case 1:
    If( IsRunning() ) break;//同上
    I++; //准备下一段数据,之所以放在此处,是需要考虑在运行过程中,有外部的暂停和继续操作。
    Step = 0;//准备运行新的数据
    Break;
    }
    } break;
    }
   
    以上程序框架,有着非常广阔的应用前景,非常简单,可以让程序员随意控制,故而它又非常稳定,比起线程的操作,它具体非常透明的可操作性。 此框架在雕刻,焊接,切割等许多场合都将成为经典,当然,若你不曾深入了解它,则不会发现它的可爱之处。
   
    对于专用输入信号状态的检测,几乎没有什么特别之处:
    int GetStatus( int nAxis )
    {
    return d1000_get_axis_status( nAxis );
    }
   
    位置的读取和设定,对于DMC1000比较容易,故在此我将写出DMC3000控制卡的这两个函数,当然用于DMC1000也是没问题的。
    DMC3000控制卡的位置分为指令位置和物理位置(编码器反馈的),所以函数需要有一个小小的选择,先看看位置获取函数:
   
    Double GetPosition( int nAxis, BOOL bCmd = true )// bCmd == true时,读取指令位置,否则为物理位置
    {
    long pulse = (bCmd == true ) ?
    d3000_get_command_pos( nAxis ):
    d3000_get_encoder_pos(nAxis);
    return P2M( nAxis, pulse );//脉冲转成毫米然后返回
    }
   
   
   
    位置设定函数多了一点点动作:
    double SetPosition( int nAxis, double fMM, BOOL bCmd = true )
    {
    double pos = GetPosition( nAxis, bCmd );//先取得原来的位置
    ( bCmd == true )?
    D3000_set_command_pos( nAxis, M2P(nAxis, fMM )):
    D3000_set_encoder_pos( nAxis, M2P(nAxis, fMM) );
    Return pos;//返回旧的位置
    }
    为什么这样设计?当你用过CPen *pOldPen= pDC->SelectObject( &newPen );时,或者除了复位之外,你真正需要调用这个SetPosition函数时,你会发现这个设计,真是人情味实足。
   
    五、 复位,相对与绝对,
    在如今PC机开发控制卡软件时代,设备上电不复位的几乎没有,在此谈到复位这个问题确实有必要,实现上,复位动作因不同设备的工艺要求而定,故一般而言,控制卡提供的那个复位函数太过简单,有点力不从心,所以,本人自己写了个复位函数,但是代码写起来将会占用很大的面版,故有此需要者,可以来电或E_mail索取。
    其基本思路是采用两次找原点,第一次高速找,停止后退出,再次以较低的速度找原点。并且在执行第二次复位时,会在离原点5毫米处减速(第一次执行做不到)。
   
    提供相对和绝对位置的概念是很有必要的,众所周知,现在控制卡能作到最小单位为1个脉冲,当然,作为数字脉冲,到此已不能再小了,故为了提高精度,通常情况下要提高计算当量,即增加每转脉冲数,或减少每转毫米数。
    不论怎么,我们将问题放大并明朗化,可以看看以下片段:
   
    for( int I(0); I<10000; I++)// 走10000次
    move( 0.5 );//走相对0.5个脉冲的距离
   
    结果是:1个脉冲也发不出,造成很大的累积误差。
    若换成绝对方式:
    for( int I(0); I<10000; I++)
    goto( I*0.5 );
   
    最后的误差,最大也就是1个脉冲以内。虽然还是有误差,但总算达到可容忍的程序,再加上适当的复位操作,让客户至少不必再担心这个巨大的累积误差了。
   
    实质上,在整个软件设计时最好采用绝对坐标系,即使要处理加工原点或工面起点等这些参数,也要把它换算成绝对位置,唯手动移动设备可以例外。另外,在CNC系统中,除了有循环用到相对坐标系,其余都是用绝对坐标系为上策,实际上,在实现编程算法上,为统一起见,最好将相对的坐标关系全部转成绝对的坐标关系,这样也便于外部进行暂停或继续的处理。
   
    相信,到此为止,若你的设备在加工时有一定的误差漂移,你会意识到自己应该是不是要检查一下采用了什么坐标系了吧。
   
   
    六、 输出输入及软限位
    对于通用的I/O操作,没有什么特别要说明的,只有两点需要注意的,先给出两个小函数,以作参考:
   
    int ReadBit( int nIO ); //读指定通用输入口的电平状态,返回1 或 0
    int WriteBit( int nIO, int nStatus ); // 输出电平到指定输出端口
   
    两点注意:
    No.1 对于ReadBit若需要加入抗干扰处理,则写一个函数:
   
    Int RealInput( int nIO, int nStatus, int di=50 )
    {
    if( ReadBit( nIO ) != nStatus )
    return 0;
    while( di -- );//耗上几个CPU的周期时间,再读一次
    return ReadBit( nIO ) == nStatus;
    }
   
    No.2 增加一个变量及函数扩展一下输出功能:
    Long m_nOutStatus= 0x00000000;
    再次改造一下WirteBit
    void WriteBit( int nIO, int nStatus )
    {
    if( nStatus ){
    m_nOutStatus |= (1<
    }
    else{
    m_nOutStatus &= (~(1<
    }
    d1000_out_bit( nIO, nStatus );
    }
    添加的访问输出状态函数:
    int ReadOutbit( int nIO )
    {
    static int a;
    a = 1<<(nIO-1);
    a &= m_nOutStatus;
    return a!=0;
    }
   
    软限位的思想原本是用于为客户节省正负限位的光电开关成本而产生的,致使使用软件限位正常的话,设备每个驱动轴只需要一个原点开关即可。当然,软限位能正确运作是非常重要的,否则很容易撞坏设备。而其正确运行,就必须依赖正确的复位动作,以找到可靠的机械原点位置。
    软件限位的基本算法非常简单,特别是在一个绝对坐标系当中。其原理如下:
   
    if( pos < minPos ) pos = minPos;
    if( pos > maxPos ) pos = maxPos;
   
    实在没有必要再详说下去了。
   
   
   
   
   
    编程技巧介绍至此算是一个了断,若在未来的日子里,有更好的想法,我会拿出来给大家参考,请大家一起来支持这件事情,拿出自己的宝贵经验,算是给数控行业添加强有力的润滑剂吧。
   
    谢谢。
   
   
 

 评论仅代表评论人个人看法,不表明博客主人及中国工控网同意其观点或其描述 共2条评论  共1页  第1页  

 评论人署名:87733599 评论时间:2010/6/12 23:48:00

我要发表评论 

    学习了 ,谢谢
 评论人署名:57379299 评论时间:2012/8/23 15:49:00

我要发表评论 

    向您学习

共2条评论 共1页  第1页  

    发表评论

登陆网站发表评论

用户名:

密码:

注册 | 忘了密码
     相关技术论文:

关于我们     免责声明     服务项目     广告联系     友情链接     联系方式     意见反馈     设为首页     加入收藏

 ©2023-2025 中国工控网(www.chinakong.com) 版权所有 豫ICP备17046657号

管理员信箱:chinakong98@163.com  服务热线:13525974529

洛阳博德工控自动化技术有限公司

中国    洛阳