Алгоритм равномерного расположения шагов в 2 направлениях - PullRequest
0 голосов
/ 17 ноября 2018

В настоящее время я программирую контроллер для станка с ЧПУ, и поэтому мне нужно получить количество шагов шагового двигателя в каждом направлении, когда я доберусь от точки А до В. Например, координаты точки А равны x = 0 и y =0 и координаты B: x = 15 и y = 3.Так что мне нужно сделать 15 шагов по оси X и 3 по оси Y.Но как мне смешать эти два значения таким образом, чтобы это было гладко (иначе не сначала x, а затем y, это приводит к действительно ужасным линиям)?В моем примере с x = 15 и y = 3 я хочу, чтобы это было организовано так:

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

Но как я могу получить эти числа из алгоритма?Я надеюсь, вы понимаете, в чем моя проблема, спасибо за ваше время, Лука

Ответы [ 4 ]

0 голосов
/ 18 ноября 2018

здесь есть 2 основных вопроса:

  1. Траектория

    это может быть обработано любой интерполяцией / растеризацией, например:

    DDA - ваш лучший вариант, поскольку он может легко обрабатывать любое количество измерений и может быть вычислен как для целочисленной, так и для плавающей арифметики. Это также быстрее (это было не так в x386 дни, но в настоящее время архитектура процессора изменила все)

    и даже если у вас есть только 2D-машина, сама интерполяция будет, скорее всего, многомерной, так как вы, вероятно, добавите еще одну вещь, такую ​​как: удерживающая сила, обороты инструмента, предварительные измерения для чего-либо и т. Д. Это должно быть интерполировано вдоль вашей линия таким же образом.

  2. Скорость

    Этот намного сложнее. Вы должны плавно вести свои двигатели от начального положения до конечного, что касается следующих:

    • начальная / конечная скорость линии, чтобы вы могли плавно соединять больше линий вместе
    • максимальная скорость (зависит от производственного процесса, обычно постоянного для каждого инструмента)
    • мотор / механика, резонанс
    • ограничения скорости двигателя: пуск / останов и верх

    Когда я пишу о скорости, я имею в виду частоту [Hz] для шагов двигателя или физическую скорость инструмента [m/s] или [mm/2].

    Линейная интерполяция не годится для этого. Вместо этого я использую кубики, так как они могут плавно соединяться и обеспечивать хорошую форму для изменения скорости. См:

    Куб интерполяции (форма ПЗУ CATMUL) - это именно то, что я использую для подобных задач (и я вывел его для этой цели)

    Основная проблема - запуск двигателя. Вам нужно перейти с 0 Hz на какую-то частоту, но обычный шаговый двигатель имеет резонанс на низких частотах, и, поскольку их нельзя избежать для многомерных машин, вам нужно проводить как можно меньше времени на таких частотах. Есть также другое средство для обработки этого резонанса сдвига кинематики путем добавления весов или изменения формы и добавления инерционных демпферов на самих двигателях (только для вращающихся двигателей)

    Таким образом, обычное управление скоростью для одной линии старта / стопа выглядит следующим образом:

    speed

    Таким образом, у вас должно быть 2 кубика один на запуск и один на остановку, разделяя вашу линию на 2 соединенных. Вы должны сделать это так, чтобы частота начала и конца настраивалась ...

    Теперь, как объединить скорость и время? Я использую дискретное нелинейное время для этого:

    это тот же процесс, но вместо времени есть угол. Частота синусоидальных колебаний изменяется линейно, так что часть, которую вы должны изменить с кубической. Кроме того, у вас нет синусоиды, поэтому вместо этого используйте полученный time в качестве параметра интерполяции для DDA ... или сравните его со временем следующего шага и, если оно больше или равно, выполните шаг и вычислите следующий ...

    Вот еще один пример этой техники:

    На самом деле это именно то, что вы должны делать ... интерполировать DDA со скоростью, управляемой кубической кривой.

Когда вы закончите, вам нужно построить еще один слой поверх этого, который будет настраивать скорости для каждой линии траектории, чтобы результат был максимально быстрым и соответствовал ограничениям скорости вашей машины, а также соответствовал скорости инструмента, если это возможно. Эта часть самая сложная ...

Чтобы показать вам, что вас ждет, когда я соберу все это вместе, мой интерполятор с ЧПУ имеет ~ 166 КБайт чистого кода C ++, не считая таких библиотек, как векторная математика, динамические списки, связь и т. Д. Весь код управления ~ 2,2 МБайт

0 голосов
/ 18 ноября 2018

Рассмотрим Алгоритм рисования линий Брезенхема m - он придумал его для плоттеров много лет назад.(Также DDA one)

В вашем случае смещения X / Y имеют общий делитель GCD=3 > 1, поэтому шаги должны меняться равномерно, но в общем случае они не будут распределяться так равномерно.

0 голосов
/ 18 ноября 2018

Если ваш контроллер может выдавать команды быстрее, чем на самом деле могут работать степперы, вы, вероятно, захотите использовать какую-то систему, основанную на событиях, основанную на таймере.Вам нужно рассчитать , когда вы запустите каждый из двигателей, чтобы движение было равномерно распределено по обеим осям.

Более длинное движение должно быть запрограммировано как можно быстрее (т. Е. Если двигатель может делать 100 шагов в секунду, пульсировать его каждую 1/100 секунды), а другое движение -более длинные интервалы.

Редактировать: в приведенном выше абзаце предполагается, что вы хотите переместить инструмент как можно быстрее.Обычно это не так.Обычно указывается скорость инструмента, поэтому вам необходимо рассчитать скорость по осям X и Y (и, возможно, также по Z) отдельно от нее.Вы также должны знать, какое расстояние перемещения инструмента соответствует одному шагу двигателя.Таким образом, вы можете рассчитать количество шагов, которые вам нужно сделать за единицу времени, а также продолжительность всего движения и, таким образом, интервалы времени между последовательными шаговыми импульсами вдоль каждой оси.

Таким образом, вы программируете свой таймер на срабатывание посленаименьший из рассчитанных временных интервалов, импульс соответствующего двигателя, программирование таймера для следующего импульса и т. д.

Это упрощение, поскольку двигатели, как и все физические объекты, имеют инерцию и требуют времени для ускорения/ замедлиться.Таким образом, вы должны принять это во внимание, если вы хотите производить плавные движения.Есть еще соображения, которые необходимо учитывать.Но это больше о физике, чем программировании.Модель программирования остается прежней.Вы моделируете свою машину как физический объект, который реагирует на известные стимулы (шаговые импульсы) некоторым известным способом.Ваша программа рассчитывает временные интервалы для шаговых импульсов из модели и находится в цикле событий, ожидая следующего события.

0 голосов
/ 17 ноября 2018

Вы должны взять соотношение между расстоянием по каждой из координат, а затем чередовать шаги по координате, имеющей самое длинное расстояние, с шагами, которые выполняют один шаг на единицу по обеим координатам.

Вот реализация на 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.

...