Рассчитайте n-мерный путь дуги
Я реализую драйвер для станка с ЧПУ, и у меня возникают проблемы с реализацией команд дуги G-кода.
Я нашел несколько реализаций алгоритма окружности средней точки, но на самом деле его нельзя использовать как есть.
Проблема с круговым алгоритмом средней точки, как я его обнаружил, заключается в том, что он 2D и рисует все октанты одновременно, в то время как мне нужны последовательные шаги по трехмерному пути, заданные начальной, конечной и центральной точками.
Я нашел хороший многомерный эквивалент алгоритма рисования линий Брезенхэма с использованием операций с плавающей запятой. Может быть, существует похожая вещь для рисования дуги?
Возможно, я смогу склонить этот алгоритм к своей воле, много размышляя и экспериментируя, но, поскольку рисование дуги не является нерешенной проблемой, и станки с ЧПУ уже изготавливались ранее, мне интересно, существует ли уже элегантное решение?
2 ответа
Мой пакет Python dxftools, используемый для обработки файлов DXF для не очень умного 2D-резака, имеет функцию разделения дуги на отрезки в 2D. Вы можете использовать этот код, а затем использовать трехмерные преобразования координат, чтобы произвольно поместить его в трехмерное пространство. Примеры преобразования координат можно найти в моем пакете py-stl.
Что ж, на ЧПУ обычно больше, чем просто 2D, так как есть также скорости, углы инструмента, более одного привода на ось, кинематика и т.д... Для этой цели я обычно использую параметрические кубики с параметромt=<0.0,1.0>
. Поэтому я преобразовываю путь в набор кубических кривых, которые легко вычислить в любой размерности. После этого шага у вас появилось 3 обычных способа растеризации:
постоянный
dt
шагпараметрические кубики обычно нелинейны, поэтому для перехода к другому пикселю (или чему-то еще) вам нужно увеличить параметр
t
с меньшим шагом, чем ваше разрешение, выглядит примерно так:dt < 1.0 / curve_length
меньше
dt
больше шансов, что вы не пропустите ни одного пикселя, но у грубого будет намного больше повторяющихся позиций.искать дальше
dt
шагиспользуя бинарный поиск, вы можете найти, что будет следующим
t
поэтому расстояние до текущей позиции составляет один пиксель. Это намного точнее, но до некоторой степени медленнее...преобразовать в строки
вы можете разбить кубическую кривую на набор линий (количество зависит от размера кривой) и растрировать линии, как обычно, с помощью DDA или Bresenham. Это самый простой способ, но в результате получится не совсем кривая.
Кубики такие:
P(t) = a0 + a1*t + a2*t^2 + a3*t^3
t = <0.0,1.0>
где P(t)
это позиция и a0,a1,a2,a3
- коэффициенты для m векторов, где каждая ось имеет собственный скалярный коэффициент.
См. Как я могу произвести многоточечную линейную интерполяцию? и подссылки о том, как их использовать / вычислять.
В любом случае, если вы настаиваете на интерполяции дуги, предполагая дугу окружности:
P(t) = ( Rotation_matrix(t) * (P0 - Pcenter) ) + Pcenter
t = <0.0,2*PI>
где Rotation_matrix
вращает вашу точку вокруг (0,0,0,...,0)
по t [rad]
в направлении кривой и P0
это начальная точка и Pcenter
находится в центре дуги.
В случае вращения без выравнивания оси вы можете вместо этого использовать https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula.
Однако использование однородных матриц преобразования - ваш лучший вариант в ND, вы просто увеличиваете размер матрицы:
В LinuxCNC генерация позиции отделена от генерации шага. В цикле генерации позиции система отслеживает расстояние, которое она уже прошла вдоль текущего примитива (линия или спираль), и использует простую формулу, чтобы получить местоположение, которое является расстоянием D вдоль этого примитива. (Как правило, это делается один раз в миллисекунду). Эта позиция может использоваться по-разному, в зависимости от того, есть ли у вас сервоприводы, аппаратная генерация или программная генерация.
В программной системе генерации шагов разность между старой заданной позицией и новой заданной позицией определяется вдоль каждой оси, и это используется для обновления скоростей генератора цифрового сигнала с использованием метода прямого цифрового синтеза (DDS). Затем с более высокой скоростью (обычно каждые 20-50 мкс) DDS определяет для каждой оси, следует ли генерировать шаг в это время.
Это другой дизайн, чем вы описываете, но он более гибкий. Например, отделяя генерацию позиции от генерации шага, вы можете пересмотреть алгоритм смешивания в своем коде генерации позиции без пересмотра генерации шага; и вы можете заменить генерацию программных шагов аппаратной генерацией или сервоуправлением алгоритмами, такими как PID.
В своем проекте вы можете аппроксимировать метод, который я описал выше, просто нарезая свою спиральную дугу на отрезки линии, как описано Роландом, и используя их в качестве входных данных в коде генерации вашего шага, который понимает только линии. В некотором смысле, это не слишком отличается от того, что делает LinuxCNC, за исключением того, что примитив кривой становится дискретизированным по расстоянию, а не по времени.