Contact me: hankecnc@gmail.com

可能提高 G02/G03 的速度 #121

推推 grbl 3年前 (2023-01-21) 180次浏览

关闭
Moffy 打开了这个问题 2012 年 9 月 28 日 · 10 条评论
关闭

可能提高 G02/G03 的速度#121

Moffy 打开了这个问题 2012 年 9 月 28 日 · 10 条评论

注释

可能提高 G02/G03 的速度 #121

伟大的工程!我购买了一块基于 328p 的 Arduino UNO 开发板并上传了代码。我在没有步进电机的情况下用 gcode 运行了一个测试 pcb,发现小电弧需要很长时间才能处理。查看代码,由于涉及所有计算,它似乎确实很慢。例如,没有协处理器的 sin 和 cos 可能会非常慢。因此,我对可以适应 GRBL 代码的 Fast Bresenham Circle 算法进行了小型 Visual Studio 测试。这有点粗糙,但可能很有趣。它所基于的文章可以在以下位置找到:http
://www.ceunes.ufes.br/downloads/2/wanderleycardoso-BCIRCLE.pdf “freeimageplus”仅提供用于测试算法的位图,最大半径为 100 . 希望这可能具有一定的价值。

包括“freeimageplus.h”

//这决定了角度所在的圆的象限,并
//确保角度在 0 到 M_PI/2.0 范围内
int CircQuadrant(float _ang)
{
//将角度置于 0 到 2_M_PI 之间
while(_ang > 2.0_M_PI) _ang = *ang – 2.0_M_PI;
while(_ang < 0) *ang = *ang + 2.0_M_PI;

if((*ang >= 0) && (*ang <= M_PI/2.0))
    return 1;
if((*ang > M_PI/2.0) && (*ang <= M_PI))
{
    *ang = *ang - M_PI/2.0;
    return 2;
}
if((*ang > M_PI) && (*ang <= (3.0*M_PI)/2.0))
{
    *ang = *ang - M_PI;
    return 3;
}
if((*ang > (3.0*M_PI)/2.0) && (*ang <= 2.0*M_PI))
{
    *ang = *ang - (3.0*M_PI)/2.0;
    return 4;
};

}
//使用快速 Bresenham 圆算法以逆时针方向绘制圆。
//文章位于:http
://www.ceunes.ufes.br/downloads/2/wanderleycardoso-BCIRCLE.pdf //圆是从 sang(rads) 到 eang(rads) 绘制的,半径为 rad(in脚步)。
//该算法已被我(Mark O’Farrell)修改为绘制整个象限而不是
每次都绘制一个圆的八分圆。只是更容易形象化。
//目前它绘制到一个位图然后被保存。但可以很容易地直接驱动步进电机。
//循环只用到整数的加减乘,速度非常快。错误也
//不会累积。没有舍入错误。应该精确到 +/- 1 步。
void CCWPlotCircle(float sang, float eang, float rad)
{
fipWinImage fipCirc;
int pitch, x, y, dx, dy, r=rad, re, cq, sq, eq, sx, sy, ex, ey, end=0, eok=1;
浮动dydx;
字节 *bmp;

fipCirc.setSize(FIT_BITMAP, 202, 202, (WORD) 8);
pitch = fipCirc.getScanWidth();
bmp = fipCirc.getScanLine(0);
memset(bmp, 0, pitch*202);
//----------------------------------------------
//The start quadrant
cq = sq = CircQuadrant(&sang);
//The end quadrant
eq = CircQuadrant(&eang);
if((sq == eq) && (eang < sang))
    eok = 0;
//----------------------------------------------
//q1: x = x, y = y
//q2: y = x, x = -y
//q3: x = -x, y = -y
//q4: y = -x, x = y
//Sequence is circular, going from 1 to 4 etc: CCW
//----------------------------------------------
//Calculate the start x & y values based on sang(start angle)
if(ABS(sang - M_PI/2.0) < M_PI/1000.0)
{
    sx = 0;
    sy = r;
}
else
{
    dydx = tanf(sang);
    sx = sqrtf(r*r/(1 + dydx*dydx));
    sy = dydx*sx;
}
//Calculate the end x & y values based on eang(end angle)
if(ABS(eang - M_PI/2.0) < M_PI/1000.0)
{
    ex = 0;
    ey = r;
}
else
{
    dydx = tanf(eang);
    ex = sqrtf(r*r/(1 + dydx*dydx));
    ey = dydx*ex;
}
//Does the first quadrant from: (r, 0) to (0, r)
//CCW
//Start X & Y values
y = sy;
x = sx;
//This loop plots the actual circle
while(end == 0)
{
    //Calculate anew at the start of each quadrant
    dx = 1 - 2*x;
    dy = 1 + 2*y;
    re = x*x + y*y - r*r;
    //Does the first half of the quadrant from (r, 0) to (r/sqrt(2), r/sqrt(2))
    //Y is incremented each loop, X is only decremented only when the conditional
    //statement: if((2*re + dx) > 0) is true.
    for(; y < x;)
    {
        //Rotates the values by multiples of 90 degrees
        //based upon the quadrant in use
        switch (cq)
        {
        case 1:
            bmp[pitch*(y + r) + x + r] = 0xff;
            break;
        case 2:
            bmp[pitch*(x + r) - y + r] = 0xff;
            break;
        case 3:
            bmp[pitch*(r - y) + r - x] = 0xff;
            break;
        case 4:
            bmp[pitch*(r - x) + y + r] = 0xff;
            break;
        }
        //End condition
        if((eok == 1) && (cq == eq) && (ey <= y))
        {
            end = 1;
            break;
        }
        y++;
        re = re + dy;
        dy = dy + 2;
        if((2*re + dx) > 0)
        {
            x--;
            re = re + dx;
            dx = dx + 2;
        }
    }
    //Does the second half of the quadrant from (r/sqrt(2), r/sqrt(2)) to (0, r)
     //X is decremented each loop, Y is only incremented only when the conditional
    //statement: if((2*re + dy) < 0) is true.
    for(; (end == 0) && (x >= 0);)
    {
        //Rotates the values by multiples of 90 degrees
        //based upon the quadrant in use
        switch (cq)
        {
        case 1:
            bmp[pitch*(y + r) + x + r] = 0xff;
            break;
        case 2:
            bmp[pitch*(x + r) - y + r] = 0xff;
            break;
        case 3:
            bmp[pitch*(r - y) + r - x] = 0xff;
            break;
        case 4:
            bmp[pitch*(r - x) + y + r] = 0xff;
            break;
        }
        //End condition
        if((eok == 1) && (cq == eq) && (ex >= x))
        {
            end = 1;
            break;
        }
        x--;
        re = re + dx;
        dx = dx + 2;
        if((2*re + dy) < 0)
        {
            y++;
            re = re + dy;
            dy = dy + 2;
        }
    }
    //current circle quadrant
    cq++;
    if(cq > 4) cq = 1;
    eok = 1;
    //Setup for next quadrant
    x = r;
    y = 0;
}
fipCirc.save("circle.bmp");

}

可能提高 G02/G03 的速度 #121 Moffy 重新打开了这个 2012 年 9 月 28 日
可能提高 G02/G03 的速度 #121
成员

哼!很有意思!感谢您提供代码和链接。这看起来非常有前途和高效。我们必须比较两种循环算法之间的总开销(包括设置时间)。你认为你可以写一个 arcs 函数的替代品以便我们测试它吗?它应该非常简单。

早期,我们遇到了一个问题,因为弧的设置时间太长,以至于在将弧的第一行放入队列并通过规划器之前,缓冲区通常会变空。我们现在执行的实施似乎不会造成任何问题,所以我不确定您所说的弧形移动速度缓慢是什么意思。它可以通过您的加速度设置和绘制的圆的参数的组合来减慢。另一个原因可能只是实际在规划器队列中的段的长度。它总是计划为队列中的最后一件事完全停止。这可能是人为地使运行速度比正常情况慢一点。

可能提高 G02/G03 的速度 #121
作者

感谢您的答复。我可以写一个替换,但它必须绕过规划器来驱动步进器,因为规划器是基于线性段的。我会在接下来的几周内查看。我在想圆的最大陡峭速度是:Vmax = sqrt(Amax_Amax + 0.3_r) 基于最大加速度发生的位置。基本上说 Y 轴上升到 Vmax,然后当 Y > X 时,X 轴被驱动到 Vmax。由于圆的轮廓,另一个轴自然地上下倾斜。
我还将查看您对细分加速等的评论。
我还写了一个 Z 轴探针测试,但没有测试过,例如 G30。它将通过移动工具来探测床,直到它接触到触摸板,此时它将停止并通过串行端口发送当前的 x、y 和 z 坐标。适合调平床。让你知道当我测试它。

发件人:Sonny Jeon
发送时间:2012 年 9 月 28 日星期五下午 12:11
收件人:grbl/grbl
抄送:Moffy
主题:回复:[grbl] G02/G03 可能的速度改进(#121

哼!很有意思!感谢您提供代码和链接。这看起来非常有前途和高效。我们必须比较两种循环算法之间的总开销(包括设置时间)。你认为你可以写一个 arcs 函数的替代品以便我们测试它吗?它应该非常简单。

早期,我们遇到了一个问题,因为弧的设置时间太长,以至于在将弧的第一行放入队列并通过规划器之前,缓冲区通常会变空。我们现在执行的实施似乎不会造成任何问题,所以我不确定您所说的弧形移动速度缓慢是什么意思。它可以通过您的加速度设置和绘制的圆的参数的组合来减慢。另一个原因可能只是实际在规划器队列中的段的长度。它总是计划为队列中的最后一件事完全停止。这可能是人为地使运行速度比正常情况慢一点。


直接回复此电子邮件或在 GitHub 上查看。

可能提高 G02/G03 的速度 #121
成员

唔。如果规划器被规避,就没有太多理由安装这种方法,因为它会搞砸它所做的所有加速规划,以确保机器以最大速度移动而不会丢失步骤,即失速。我们需要根据线段或连续位置来制定它,以使其与 Grbl 配合得很好。抱歉,我无法为您提供太多帮助,因为我正在努力更新整个 limits.c 程序。到目前为止,第一次提交已经完成。还有很多事情要做…

可能提高 G02/G03 的速度 #121
成员

在引入规划器之前,我一直使用 bresenham 算法。目标
是在稍后重新引入漂亮的算法时向规划器引入椭圆“基元”
,但我发现我
在现实生活中很少使用弧线,因为我的 CAM 工具不会生成它们,所以我从不
费心。

可能提高 G02/G03 的速度 #121
作者

是的,需要是发明之母。而我打算将它用于 PCB 布线,而我的布线软件会产生大量的弧线!也许有一些关于如何修改规划器的建议?
您的见解将不胜感激。

发件人:Simen Svale Skogsrud
发送时间:2012 年 10 月 1 日星期一下午 2:39
收件人:grbl/grbl
抄送:Moffy
主题:回复:[grbl] G02/G03 可能的速度改进(#121

在引入规划器之前,我一直使用 bresenham 算法。目标
是在稍后重新引入漂亮的算法时向规划器引入椭圆“基元”
,但我发现我
在现实生活中很少使用弧线,因为我的 CAM 工具不会生成它们,所以我从不
费心。

直接回复此电子邮件或在 GitHub 上查看。

可能提高 G02/G03 的速度 #121
成员

一会儿回来,@jgeisler0303当我们努力改进规划器和弧形性能时,我正在讨论将椭圆“基元”(可以这么说)包含到规划器中的优点。我们讨论的其中一件事是创建一个弧例程,该例程将考虑加速度并最大化进入和退出速度,而不是像我们现在所做的那样增加线段。这是基于我们可以为所有这些计算创建一个非常简单的封闭形式解决方案的概念。

据我回忆,这样做没有多大意义。我认为主要原因是保持工作流程简单明了,从进入规划器的线段到执行动作的步进器。创建特定于圆弧的运动会导致步进器例程膨胀,尤其是在考虑所有非线性步进模式并很好地处理进给保持时。我并不是说没有办法做到这一点,但它可能比它的价值更麻烦。

至于修改计划器,我建议你在修改东西之前尽量了解这个过程。大多数设置发生在 plan_buffer_line() 代码中,其余设置以非常优化的方式更新加速配置文件。优化可能会令人困惑,但它们旨在仅更新需要更新的内容,而不是重新计算整个缓冲区。

可能提高 G02/G03 的速度 #121
贡献者

我也记不起我们放弃专门弧形图案想法的确切原因。但对我来说,一个原因肯定是在线段生成器加速之后,弧线工作得很漂亮。
我也用我的工厂做印刷电路板布线。我想你的弧线和我的一样,主要是角。因此,它们的半径相当小,因此速度受弧加速度设置的限制。您可能会尝试将圆弧分成较短的部分和/或增加转弯加速度设置。
在你指责当前的 arc 实现之前,确保它确实是你问题的根源。我会将缓冲区级别添加到状态报告(“?”)中,并检查在生成弧段时缓冲区是否真的很低。我从来没有感觉到缓冲区接近低。

可能提高 G02/G03 的速度 #121
作者

感谢您的答复。我将更详细地查看弧设置等,因为到目前为止我所做的还很肤浅。

发件人:Jens Geisler
发送时间:2012 年 10 月 2 日星期二凌晨 4:14
收件人:grbl/grbl
抄送:Moffy主题:回复:[grbl] G02/G03 ( #121 )
的可能速度改进

我也记不起我们放弃专门弧形图案想法的确切原因。但对我来说,一个原因肯定是在线段生成器加速之后,弧线工作得很漂亮。
我也用我的工厂做印刷电路板布线。我想你的弧线和我的一样,主要是角。因此,它们的半径相当小,因此速度受弧加速度设置的限制。您可能会尝试将圆弧分成较短的部分和/或增加转弯加速度设置。
在你指责当前的 arc 实现之前,确保它确实是你问题的根源。我会将缓冲区级别添加到状态报告(“?”)中,并检查在生成弧段时缓冲区是否真的很低。我从来没有感觉到缓冲区接近低。


直接回复此电子邮件或在 GitHub 上查看。

可能提高 G02/G03 的速度 #121
作者

是的,我必须说我没有像你建议的那样掌握规划器。不过整个过程还是蛮好玩的!如果我做一个特殊的弧形例程,我认为最好独立于规划器来做。让缓冲区清空,然后按照前面提到的那样执行弧线。arc Vmax 的公式应该是 Vmax = sqrt(Amax_Amax + 0.3_r*r)。我知道这违反了规划器的整个概念,但我只会先将其作为实验来做,只是为了看看我是否能让它发挥作用。然后,如果它看起来不错,则将其与规划器集成。非常感谢您的所有回复。
目前,我正在为一些简单的事情编写一些 C 宏,例如设置引脚的 I/O 或启用或禁用外部中断。收集这样的宏会很棒,因为它会大大简化 avr 编程的细节。例如

#define MODE_LOW_LEVEL 0
#define MODE_ANY_EDGE 1
#define MODE_FALLING_EDGE 2
#define MODE_RISING_EDGE 3
//——————————– ——————————————
#define PIN_INPUT_HIZ 0
# define PIN_INPUT_PULLUP 1
#define PIN_OUTPUT_LOW 2
#define PIN_OUTPUT_HIGH 3
//启用外部EICRA中断
#define EN_EXT_EICRA_INT(intn, mode)
({\
EIMSK = EIMSK & ~(1<<(intn));
EICRA = (EICRA & ~( 11<<((intn)+1))) | 模式<<((intn)+1);
EIFR = EIFR | (1<<(intn));
EIMSK = EIMSK | (1<<(intn));
})
//禁止外部中断
#define DIS_EXT_INT(intn)
({
EIMSK = EIMSK & ~(1<<(intn));\
})
//设置一个引脚为输入或输出
#define PIN_GENERAL_IO(ddrn, portn, bitn, mode)
({
ddrn = (ddrn & ~(1<<bitn)) | (((mode & 2)>>1)<<bitn);
portn = (portn & ~(1<<bitn)) | ((mode & 1)<<位);
})

未经测试,使用风险自负。但只是为了说明一个想法。

发件人:Sonny Jeon
发送时间:2012 年 10 月 2 日星期二凌晨 1:47
收件人:grbl/grbl
抄送:Moffy
主题:回复:[grbl] G02/G03 可能的速度改进 ( #121 )

一会儿回来,@jgeisler0303当我们努力改进规划器和弧形性能时,我正在讨论将椭圆“基元”(可以这么说)包含到规划器中的优点。我们讨论的其中一件事是创建一个弧例程,该例程将考虑加速度并最大化进入和退出速度,而不是像我们现在所做的那样增加线段。这是基于我们可以为所有这些计算创建一个非常简单的封闭形式解决方案的概念。

据我回忆,这样做没有多大意义。我认为主要原因是保持工作流程简单明了,从进入规划器的线段到执行动作的步进器。创建特定于圆弧的运动会导致步进器例程膨胀,尤其是在考虑所有非线性步进模式并很好地处理进给保持时。我并不是说没有办法做到这一点,但它可能比它的价值更麻烦。

至于修改计划器,我建议你在修改东西之前尽量了解这个过程。大多数设置发生在 plan_buffer_line() 代码中,其余设置以非常优化的方式更新加速配置文件。优化可能会令人困惑,但它们旨在仅更新需要更新的内容,而不是重新计算整个缓冲区。


直接回复此电子邮件或在 GitHub 上查看。

可能提高 G02/G03 的速度 #121
作者

我已经完成了一个有效的 z_probe(G31) 代码。您发出命令,例如 G31 Z-20(最大移动 -20 毫米的 Z 探针。符号表示方向)。如果工具在该运动中与触摸板接触,它会通过提供当前 X、Y 和 Z 坐标进行响应,否则它会报告最大行程错误。

喜欢 (0)