一个工控人创作、分享、交流的高质量平台!
一个工控人创作、分享、交流的高质量平台!

固高GTS 大数据量插补处理方法

        插补运动是轨迹加工必不可少的运动方式,在实际应用中复杂曲线通常需要离散成小线段。固高运动控制器插补运动的缓冲区只有4096段空间,那么问题来了,超过4096段数据要怎么处理,很多朋友首先想到的可能是先跑完一部分,在压剩余的数据继续跑。如果是这样处理,在数据量很多时就要分几次跑,当然就会出现跑跑停停的现象。

        那么,如何处理才比较好?通常是使用一边跑一边压数据的方式。假设现在要跑下图的轨迹,轨迹离散成1万多段数据,下面我来举例说明如何实现边跑边压数据。

插补图形

运动轨迹

1.建立坐标系

public static void CreateCrd(short cardNum, short crd, short dimension, short[] crdAxis, int[] originPos)
{
    short sRtn = 0;
    // 建立号坐标系,设置坐标系参数
    gts.mc.TCrdPrm crdPrm = new gts.mc.TCrdPrm();
    sRtn = gts.mc.GT_GetCrdPrm(cardNum, crd, out crdPrm);
    WriteLog.commandhandler("GTN_GetCrdPrm", sRtn);
    crdPrm.dimension = dimension; // 坐标系为二维坐标系
    crdPrm.synVelMax = 500; // 最大合成速度: pulse/ms
    crdPrm.synAccMax = 1000; // 最大加速度: pulse/ms^2
    crdPrm.evenTime = 50; // 最小匀速时间: ms
    crdPrm.setOriginFlag = 1; // 指定坐标系的原点坐标的规划位置

    switch (crdAxis[0])
    {
        case 1:
            crdPrm.profile1 = 1;
            crdPrm.originPos1 = originPos[0];
            break;
        case 2:
            crdPrm.profile2 = 1;
            crdPrm.originPos2 = originPos[0];
            break;
        case 3:
            crdPrm.profile3 = 1;
            crdPrm.originPos3 = originPos[0];
            break;
        case 4:
            crdPrm.profile4 = 1;
            crdPrm.originPos4 = originPos[0];
            break;
        case 5:
            crdPrm.profile5 = 1;
            crdPrm.originPos5 = originPos[0];
            break;
        case 6:
            crdPrm.profile6 = 1;
            crdPrm.originPos6 = originPos[0];
            break;
        case 7:
            crdPrm.profile7 = 1;
            crdPrm.originPos7 = originPos[0];
            break;
        case 8:
            crdPrm.profile8 = 1;
            crdPrm.originPos8 = originPos[0];
            break;
        default: break;
    }
    switch (crdAxis[1])
    {
        case 1:
            crdPrm.profile1 = 2;
            crdPrm.originPos1 = originPos[1];
            break;
        case 2:
            crdPrm.profile2 = 2;
            crdPrm.originPos2 = originPos[1];
            break;
        case 3:
            crdPrm.profile3 = 2;
            crdPrm.originPos3 = originPos[1];
            break;
        case 4:
            crdPrm.profile4 = 2;
            crdPrm.originPos4 = originPos[1];
            break;
        case 5:
            crdPrm.profile5 = 2;
            crdPrm.originPos5 = originPos[1];
            break;
        case 6:
            crdPrm.profile6 = 2;
            crdPrm.originPos6 = originPos[1];
            break;
        case 7:
            crdPrm.profile7 = 2;
            crdPrm.originPos7 = originPos[1];
            break;
        case 8:
            crdPrm.profile8 = 2;
            crdPrm.originPos8 = originPos[1];
            break;
        default: break;
    }
    if (dimension > 2)
    {
        switch (crdAxis[2])
        {
            case 1:
                crdPrm.profile1 = 3;
                crdPrm.originPos1 = originPos[2];
                break;
            case 2:
                crdPrm.profile2 = 3;
                crdPrm.originPos2 = originPos[2];
                break;
            case 3:
                crdPrm.profile3 = 3;
                crdPrm.originPos3 = originPos[2];
                break;
            case 4:
                crdPrm.profile4 = 3;
                crdPrm.originPos4 = originPos[2];
                break;
            case 5:
                crdPrm.profile5 = 3;
                crdPrm.originPos5 = originPos[2];
                break;
            case 6:
                crdPrm.profile6 = 3;
                crdPrm.originPos6 = originPos[2];
                break;
            case 7:
                crdPrm.profile7 = 3;
                crdPrm.originPos7 = originPos[2];
                break;
            case 8:
                crdPrm.profile8 = 3;
                crdPrm.originPos8 = originPos[2];
                break;
            default: break;
        }
    }
    if (dimension == 4)
    {
        switch (crdAxis[3])
        {
            case 1:
                crdPrm.profile1 = 4;
                crdPrm.originPos1 = originPos[3];
                break;
            case 2:
                crdPrm.profile2 = 4;
                crdPrm.originPos2 = originPos[3];
                break;
            case 3:
                crdPrm.profile3 = 4;
                crdPrm.originPos3 = originPos[3];
                break;
            case 4:
                crdPrm.profile4 = 4;
                crdPrm.originPos4 = originPos[3];
                break;
            case 5:
                crdPrm.profile5 = 4;
                crdPrm.originPos5 = originPos[3];
                break;
            case 6:
                crdPrm.profile6 = 4;
                crdPrm.originPos6 = originPos[3];
                break;
            case 7:
                crdPrm.profile7 = 4;
                crdPrm.originPos7 = originPos[3];
                break;
            case 8:
                crdPrm.profile8 = 4;
                crdPrm.originPos8 = originPos[3];
                break;
            default: break;
        }
    }

    sRtn = gts.mc.GT_SetCrdPrm(cardNum, crd, ref crdPrm);
    WriteLog.commandhandler("GTN_SetCrdPrm", sRtn);
    sRtn = gts.mc.GT_CrdClear(cardNum, crd, 0); // 清除坐标系 1 的 FIFO0 中的数据
    WriteLog.commandhandler("GT_CrdClear", sRtn);

}

2.压入插补数据并启动

        这里我是先把坐标从txt文件中读取存在列表中,再循环压数据的过程中,当到达某个数量时就启动插补,然后继续一边跑一遍压剩余的数据。在这里有一点需要特别提醒一下,由于跑的是小线段,所以在使用时,尤其是运动速度比较高时,压下去的数据很快就跑完,所以要保证继续压数据的效率。因此要保证线程的优先级,避免缓冲区跑空。关于线程优先级自行研究,这里只是做个提示。

public static void CrdRunAndLoadData(short cardNum,short crd,short lsrChn,double vel,double acc,bool lookAheadFlag,string fileName,int startNum)
{
    short sRtn=0;
    uint dataCount=0;
    int space;
    bool startFlag = false;
    TCrdPos crdPos = new TCrdPos();
    crdPos.xPos = new List<double>();
    crdPos.yPos = new List<double>();
    crdPos.zPos = new List<double>();
    crdPos.rPos = new List<double>();
    crdPos.laserSwitch = new List<short>();

    string[] strArray = File.ReadAllLines(fileName);
    for (long i = 0; i < strArray.Length; i++)
    {
        string[] str = strArray[i].Split(',');
        crdPos.xPos.Add(double.Parse(str[0]));
        crdPos.yPos.Add(double.Parse(str[1]));
        crdPos.rPos.Add(0);
        crdPos.zPos.Add(0);
        crdPos.laserSwitch.Add(short.Parse(str[2]));
        dataCount++;
        crdPos.dataCount = dataCount;
    }
    CrdLineXYG02D(cardNum, crd, crdPos.xPos[0], crdPos.yPos[0], vel, acc, lookAheadFlag);
    for(int i=0;i< crdPos.dataCount;i++)
    {
        if (crdPos.laserSwitch[i] == 1 && lastLaserOn == false)
        {
            sRtn=BuflaserOn(cardNum, crd, lsrChn, lookAheadFlag);
            if (1 == sRtn)
            {
                do
                {
                    // 查询运动缓存区空间,直至空间不为
                    sRtn = gts.mc.GT_CrdSpace(cardNum, crd, out space, 0);
                    
                } while (0 == space);

                // 重新调用上次失败的插补指令
                sRtn = BuflaserOn(cardNum, crd, lsrChn, lookAheadFlag);
            }
            lastLaserOn = true;
        }
        else if (crdPos.laserSwitch[i] == 0 && lastLaserOn == true)//指令要关光,原来是开光状态,需要关闭激光
        {
            //插入关光指令
            sRtn = BuflaserOff(cardNum, crd, lsrChn, lookAheadFlag);
            if (1 == sRtn)
            {
                do
                {
                    // 查询运动缓存区空间,直至空间不为
                    sRtn = gts.mc.GT_CrdSpace(cardNum, crd, out space, 0);
                   
                } while (0 == space);

                // 重新调用上次失败的插补指令
                sRtn = BuflaserOff(cardNum, crd, lsrChn, lookAheadFlag);
            }
            lastLaserOn = false;
        }

        if (i == startNum)
        {
            int temp = 0x1;
            int ltemp = crd - 1;
            int opCrd = temp << ltemp;
            // 启动运动
            sRtn = gts.mc.GT_CrdStart(cardNum, (short)opCrd, 0);
            WriteLog.commandhandler("GTN_CrdStart1", sRtn);
            if(sRtn==0)
            {
                startFlag = true;
                WriteLog.LogHandler("插补运动开始");
            }             
        }

        sRtn = CrdLineXY2D(cardNum, crd, crdPos.xPos[i], crdPos.yPos[i], vel, acc, lookAheadFlag);
        if (1 == sRtn)
        {
            do
            {
                // 查询运动缓存区空间,直至空间不为
                sRtn = gts.mc.GT_CrdSpace(cardNum, crd, out space, 0);
                //commandhandler("GTN_CrdSpace", sRtn, false);
            } while (0 == space);

            // 重新调用上次失败的插补指令
            sRtn = CrdLineXY2D(cardNum, crd, crdPos.xPos[i], crdPos.yPos[i], vel, acc, lookAheadFlag);
        }
    }
    if (lastLaserOn == true)
    {
        sRtn = BuflaserOff(cardNum, crd, lsrChn, lookAheadFlag);
        
        lastLaserOn = false;
    }
    if(lookAheadFlag)
    {
        do
        {
            sRtn = gts.mc_la.GT_CrdDataEx(cardNum, crd, System.IntPtr.Zero, 0);
            WriteLog.commandhandler("GTN_CrdDataEx", sRtn);
        } while (sRtn != 0);
    }
    if (startFlag == false)
    {
        int temp = 0x1;
        int ltemp = crd - 1;
        int opCrd = temp << ltemp;
        // 启动运动
        sRtn = gts.mc.GT_CrdStart(cardNum, (short)opCrd, 0);
        WriteLog.commandhandler("GTN_CrdStart2", sRtn);
        if (sRtn == 0)
        {
            startFlag = true;
            WriteLog.LogHandler("插补运动开始");
        }
    }
    short crdRun;
    int seg;
    do
    {
        GTSControl.GetCrdStatus(cardNum, crd, out crdRun, out seg);
    } while (crdRun == 1);
    WriteLog.LogHandler("插补运动结束");

}

3.在线程中执行插补运动

private void CrdMove(object obj)
 {
     string filePath= (string)obj;
     GetLasrPrm();
     GetCrdPrm();
     GTSControl.InitLaser(cardNum, lsrMode, lsrChn, maxPower, minPower, frqOrwidth, power);
     bool lookAhead = checkBox_IsLookAhead.Checked == true ? true : false;
     short[] crdAxis = new short[2] { axisX,axisY};
     int[] originPos = new int[2] { 0, 0 };
     GTSControl.CreateCrd(cardNum, crdNum, dmsNum, crdAxis, originPos);
     if(lookAhead)
     {
         gts.mc_la.TLookAheadParameter lookAheadPara = new gts.mc_la.TLookAheadParameter();
         lookAheadPara.time = lookAheadTime;
         lookAheadPara.radiusRatio = lookAheadRadius;
         lookAheadPara.lookAheadNum = 200;
         lookAheadPara.aMax1 = 3000;
         lookAheadPara.aMax2 = 3000;
         lookAheadPara.aMax3 = 3000;
         lookAheadPara.vMax1 = 500;
         lookAheadPara.vMax2 = 500;
         lookAheadPara.vMax3 = 500;
         lookAheadPara.DVMax1 = 500;
         lookAheadPara.DVMax2 = 500;
         lookAheadPara.DVMax3 = 500;
         lookAheadPara.axisRelation1 = 1;
         lookAheadPara.axisRelation2 = 2;
         lookAheadPara.axisRelation3 = 3;
         lookAheadPara.scale1 = axisScale;
         lookAheadPara.scale2 = axisScale;
         lookAheadPara.scale3 = axisScale;
         GTSControl.initLookAhead(cardNum, crdNum, axisScale, ref lookAheadPara);
     }
     GTSControl.CrdRunAndLoadData(cardNum, crdNum, lsrChn, crdVel, crdVel, lookAhead, filePath, 3000);
 }

 private void btn_start_Click(object sender, EventArgs e)
 {
     //启动插补运动
     if (!string.IsNullOrEmpty(fileName))
     {

         try
         {
             Thread thread = new Thread(new ParameterizedThreadStart(CrdMove));
             thread.Priority = ThreadPriority.Highest; 
             thread.Start(fileName); // 使用一个包含两个字符串的数组作为参数     
         }
         catch (Exception ex)
         {
             //MessageBox.Show("Error occurred: " + ex.Message);
             MessageBox.Show("文件有错!" + ex.Message);
             //Environment.Exit(1);
         }

     }
 }

需要完整Demo请在下方下载。

我也是有底线哒~
固高GTS 大数据量插补处理方法-工控吧!
固高GTS 大数据量插补处理方法
此内容为付费资源,请付费后查看
4.99
付费资源
© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容