2

我目前正在为 CNC 机床编程控制器,因此当我从 A 点到 B 点时,我需要获取每个方向上的步进电机步数。例如,A 点的坐标是 x=0 和 y=0 和 B 的坐标是 x=15 和 y=3。所以我必须在 x 轴上走 15 步,在 y 轴上走 3 步。但是我如何以一种平滑的方式将这两个值混合在一起(也就是不是先 x 后 y,这会导致非常难看的线条)?在我的 x=15 和 y=3 示例中,我希望它像这样排列:

for 3 times do:    
    x:4 steps  y:0 steps
    x:1 steps  y:1 step

但是我怎样才能从算法中得到这些数字呢?我希望你能明白我的问题,谢谢你的时间,卢卡

4

4 回答 4

3

这里有两个主要问题:

  1. 弹道

    这可以通过任何插值/光栅化来处理,例如:

    • DDA
    • 布雷森纳姆

    DDA 是您的最佳选择,因为它可以轻松处理任意数量的维度,并且可以在整数和浮点算术上进行计算。它也更快(在 x386 时代并非如此,但现在 CPU 架构改变了一切)

    即使您只有 2D 机器,插值本身也很可能是多维的,因为您可能会添加其他内容,例如:保持力、工具转速、任何情况下的压力等……必须沿着您的线在同样的方法。

  2. 速度

    这个要复杂得多。你需要平稳地驱动你的电机从开始位置到结束与这些有关:

    • 线路开始/结束速度,因此您可以将更多线路顺利连接在一起
    • 最高速度(取决于制造过程,每个工具通常是恒定的)
    • 电机/机械共振
    • 电机速度限制:启动/停止和最高

    当写到速度时,我的意思[Hz]是电机步进的频率或工具的物理速度[m/s][mm/2]

    线性插值对此不好,我使用三次,因为它们可以平滑连接并为速度变化提供良好的形状。看:

    插值立方(CATMUL ROM 的形式)正是我用于此类任务的(我为此目的派生了它)

    主要问题是电机的启动。您需要从0 Hz某个频率驱动,但通常的步进电机在较低频率下会产生共振,因为对于多维机器来说,它们无法避免,您需要在这些频率上花费尽可能少的时间。还有另一种方法可以通过增加重量或改变形状来处理运动学的这种移动共振,并在电机本身上添加惯性阻尼器(仅限旋转电机)

    所以通常单条启动/停止线的速度控制是这样的:

    速度

    因此,您应该有 2 个立方体,每次启动一个,每个停止一个,将您的生产线分成 2 个连接的。你必须这样做,所以开始和停止频率是可配置的......

    现在如何合并速度和时间?我为此使用离散非线性时间

    它的过程相同,但不是时间而是角度。正弦波的频率呈线性变化,因此您需要随立方变化的部分。此外,您没有正弦波,因此不要使用结果time作为 DDA 的插值参数 ...

    这是此技术的另一个示例:

    这实际上完全符合您应该做的......用三次曲线控制的速度插入 DDA。

完成后,您需要在此之上构建另一层,它将配置每条轨迹线的速度,以便结果尽可能快,并匹配您的机器速度限制,并尽可能匹配工具速度。这部分是最复杂的...

为了向您展示当我将所有这些放在一起时,我的 CNC 插值器有大约 166KByte 的纯 C++ 代码,不包括向量数学、动态列表、通信等依赖库...整个控制代码是大约 2.2 MByte

于 2018-11-18T07:53:32.847 回答
2

如果您的控制器发出命令的速度比步进器实际转动的速度快,那么您可能希望使用某种基于事件驱动的基于计时器的系统。您需要计算触发每个电机的时间,以便运动在两个轴上均匀分布。

较长的运动应尽可能快地进行编程(即,如果电机每秒可以执行 100 步,则每 1/100 秒脉冲一次),而其他运动则以较长的间隔进行。

编辑:上面的段落假设您想尽快移动工具。通常情况并非如此。通常,工具速度是给定的,因此您需要分别计算沿 X 和 Y(也可能是 Z)轴的速度。您还应该知道电机的一步对应的刀具移动距离。因此,您可以计算每个时间单位需要执行的步数,以及整个运动的持续时间,以及沿每个轴的连续步进脉冲之间的时间间隔。

因此,您将计时器编程为在计算出的最小时间间隔后触发,为相应的电机提供脉冲,为下一个脉冲编程计时器,等等。

这是一种简化,因为与所有物理对象一样,电机具有惯性并且需要时间来加速/减速。所以如果你想产生平滑的运动,你需要考虑到这一点。还有更多的考虑因素需要考虑。但这更多是关于物理而不是编程。编程模型保持不变。您将机器建模为以某种已知方式对已知刺激(步进脉冲)做出反应的物理对象。您的程序计算模型中步进脉冲的时间,并位于事件循环中,等待下一次事件发生。

于 2018-11-18T04:42:02.910 回答
1

考虑一下Bresenham 的线条绘制算法m - 他在多年前为绘图仪发明了它。(也是 DDA 之一)

在您的情况下,X/Y 位移具有 common divisor GCD=3 > 1,因此步骤应该均匀变化,但在一般情况下它们不会分布得如此均匀。

于 2018-11-18T04:09:25.403 回答
0

您应该取每个坐标上的距离之间的比率,然后在距离最长的坐标上的步长与在两个坐标上执行单个单位步长的步长之间交替。

这是 JavaScript 中的一个实现——仅使用其最简单的语法:

function steps(a, b) {
    const dx = Math.abs(b.x - a.x);
    const dy = Math.abs(b.y - a.y);
    const sx = Math.sign(b.x - a.x); // sign = -1, 0, or 1
    const sy = Math.sign(b.y - a.y);
    const longest = Math.max(dx, dy);
    const shortest = Math.min(dx, dy);
    const ratio = shortest / longest;
    const series = [];

    let longDone = 0;
    let remainder = 0;
    for (let shortStep = 0; shortStep < shortest; shortStep++) {
        const steps = Math.ceil((0.5 - remainder) / ratio);
        if (steps > 1) {
            if (dy === longest) {
                series.push( {x: 0, y: (steps-1)*sy} );
            } else {
                series.push( {x: (steps-1)*sx, y: 0} );
            }
        }
        series.push( {x: sx, y: sy} );
        longDone += steps;
        remainder += steps*ratio-1;
    }
    if (longest > longDone) {
        if (dy === longest) {
            series.push( {x: 0, y: longest-longDone} );
        } else {
            series.push( {x: longest-longDone, y: 0} );
        }   
    }
    
    return series;
}

// Demo
console.log(steps({x: 0, y: 0}, {x: 3, y: 15}));

请注意,第一段比所有其他段都短,因此它与序列在第二点附近结束的方式更加对称。如果您不喜欢这样,请将0.5代码中出现的 0 或 1 替换为 0 或 1。

于 2018-11-17T20:39:04.697 回答