Обзор
Начальная обработка
Команды G0, G1, G2 и G3 анализируются и преобразаются в последовательность простых перемещений, которые хранятся в буфере перемещений в классе Gcodes. Каждое простое перемещение является линейным или круговым.
Выборка и сегментация
Класс Move вызывает метод ReadMove в классе GCodes для получения примитивных перемещений. Это может включать сегментацию, которая применяется, если выполняется одно из следующих условий:
- Сегментацию требует кинематика.
Это всегда будет иметь место для нелинейной кинематики, за исключением дельта-кинематики.
В RRF 3.3 при желании можно сегментировать даже линейную и дельта-кинематику, например, для поддержки более ранней паузы. - Перемещения G2 и G3 всегда делятся на короткие линейные перемещения.
- Используется компенсация кривизны стола.
В этом случае перемещения будут разделены на сегменты размером близким шагу сетки, если перемещения не меньше.
Очередь и планирование
Примитивные перемещения, прочитанные классом Move, помещаются в очередь Move. Каждая запись в очереди перемещения представлена DDA. Каждый DDA описывает фазы ускорения, постоянной скорости и замедления перемещения.
Когда DDA добавляется, его конечная скорость устанавливается на ноль, если это последнее перемещение. Затем система вычисляет максимальную конечную скорость DDA, которая ограничена либо настроенным ускорением и длиной перемещения, либо максимальной настроенной скоростью движения. Скорость предыдущего движения увеличивается, если это возможно, чтобы соответствовать заданной скорости. Это будет возможно только в том случае, если предыдущий DDA имеет сегмент замедления. Если предыдущая DDA была простым движением замедления, то также может быть возможно увеличить конечную скорость этого DDA; и так далее.
Подготовка
Незадолго до того, как должно начаться перемещение, описанное DDA, и после подготовки всех предыдущих DDA в очереди, DDA готовится к выполнению. После того, как DDA был подготовлен, его нельзя изменить, за исключением того, что к нему можно применить babystepping.
Для подготовки ДДА:
- Фазы ускорения и замедления пермещения (если они есть) планируются путем применения input shaping.
Это может разделить каждую фазу ускорения или замедления на несколько сегментов с разными ускорениями. - К каждому DDA прилагается связанный список объектов MoveSegment.
Каждый из них описывает (всегда в декартовом пространстве) сегмент ускорения, необязательный сегмент с постоянной скоростью или сегмент замедления. - К нему присоединяется DM для каждого набора локальных приводов, который соответствует одной оси станка или экструдеру (дельта башня является примером оси станка). Каждый DM указывает на первый MoveSegment.
- Параметры сохраняются в DM для облегчения расчета времени шага.
Некоторые из этих параметров зависят от типа перемещения, которое может быть одним из следующих: линейное перемещение (например, для декартовой оси), дельта-перемещение (например, для дельта-принтера) или линейное перемещение с Pressure Advance (например, для экструдера). - Для каждого DM рассчитывается общее количество шагов, начальное направление и время первого шага, отсчитываемое от времени начала движения.
- Затем DM прикрепляются к DDA в виде связанного списка в пошаговом порядке (сначала самый ранний шаг).
- DM не создаются для приводов, подключенных через CAN. Вместо этого информация о перемещении сохраняется в CAN-буферах (обычно один буфер на CAN-адрес, к которому подключен привод).
Когда подготовка к перемещению завершена, эти буферы CAN передаются вместе со временем начала перемещения.
Исполнение
Когда перемещение должно быть выполнено, его фактическое время начала записывается в DDA. Для каждого DM устанавливается требуемое направление драйвера для первого шага. Затем прерывание планируется на время, когда требуется выполнить первый шаг, как указано в первом DM в связанном списке.
Когда происходит прерывание, ISR выполняет итерацию начала списка DM, чтобы идентифицировать шаги, которые требуется выполнить. Затем генерируются шаги для драйверов. В течении времени наибольшего шага вычисляется для каждого из этих DM, когда должен быть выполнен следующий шаг, и повторно вставляет их в правильное место в связанном списке, чтобы сохранить список в порядке времени выполнения шагов.
Любые DM, для которых не требуется дальнейших действий, перемещаются в отдельный связанный список, прикрепленный к DDA. Затем он планирует следующее прерывание в соответствии со временем, указанным в DM сейчас во главе основного списка. Если не осталось активных DM, он планирует начать следующий ход в то время, когда должен закончиться текущий ход.
Обработка
Задачи перемещения проходят через завершенные DDA. Для каждого из них проверяется DM (теперь все они находятся в завершенном списке) на наличие ошибок, о которых необходимо сообщить, а затем повторно используется DM. Затем DDA может быть повторно использован для другого входящего хода.
Сегменты перемещений
Назначение
Сегмент перемещения предназначен для представления части перемещения с постоянным ускорением. Когда input shaping не используется или используется DAA, перемещение содержит один сегмент ускорения, один сегмент постоянной скорости и один сегмент замедления. Некоторые перемещения содержат только один или два таких сегмента.
Когда используется input shaping, каждый сегмент ускорения или замедления разбивается на несколько частей:
- две для ZV
- три для ZVD
- четыре для ZVDD или EI2
MoveSegment предназначен для упрощения вычисления времени, за которое была завершена данная часть перемещения. Исходя из этого, вычисляется время импульсов шаговых двигателей.
Время сегмента ускорения или замедления вычисление времени, за которое будет завершена определенная часть движения, является решением этого квадратного уравнения:
- (s - s0) = u*(t - t_start) + 0,5*a*(t - t_start)t^2
- s = d * move_fraction, где d — общая длина хода
- s0 = d * initial_move_fraction, то это будет такой вид:
- t = sqrt (A + B * дробь_движения) + C
- A = (u / a) ^ 2 - B * начальное_движение_фракция
- В = 2 * д/а
- C = u/a + t_start
Для линейного сегмента уравнение выглядит так:
- (s - s0) = u*(t - t_start)
и решение имеет вид:
т = B * дробь_движения + C
куда:
В = д/а
C = t_start – B * начальное_движение_фракция.
Доля общего перемещения, с которой начинается сегмент, определяется из доли конечного расстояния предыдущего сегмента, если он есть, и равна нулю для первого сегмента.
Если MCU позволяется, все вычисления выполняются в модуле работы с числами с плавающей запятой. Основная причина этого заключается в том, что процессоры ARM M4F и M7 имеют быструю инструкцию квадратного корня с плавающей запятой, занимающую 14 тактовых циклов. Вычисление целочисленного квадратного корня занимает намного больше времени, даже с оптимизированной функцией целочисленного квадратного корня в RRFLibraries, тем более, что нам обычно нужно использовать более 32 бит из-за различий в размере/разрешении.
Вычисление времени импульса шага
Линейное движение
Это самый простой случай. Общее количество шагов, необходимых для всего перемещения, записывается в DM. Чтобы рассчитать время следующего шага, прошивка вычисляет соответствующую долю движения, которая равна (next_step_number/total_steps). Затем он использует текущий MoveSegment для вычисления соответствующего времени с начала перемещения.
Чтобы отслеживать, когда переключаться на следующий MoveSegment, при запуске нового он предварительно вычисляет номер шага, на котором требуется переключение на следующий MoveSegment, и сохраняет это значение в DM.
Дельта
...
Ось экструдера с pressure advance
Это, вероятно, самый сложный случай. Используя квадратичное pressure advance, расстояние экструзии изменяется следующим образом:
- е’ = е + k1*(v-u) + k2*(v-u)^2
где e — требуемая экструзия в сопле,
e’ — требуемое движение в экструдере,
u — требуемая скорость экструзии в начале движения сопла,
v — мгновенная требуемая скорость экструзии в сопле.
Общее расстояние экструзии (и, следовательно, чистое количество предпринятых шагов) также изменяется в соответствии с приведенной выше формулой, заменяя конечную требуемую скорость экструзии на v.
Уравнения движения такие же, как и для линейного движения, за исключением того, что константы ABC изменены, и сегмент замедления может быть реверсирован. Есть несколько вариантов:
- Используются разные объекты MoveSegment для экструдеров, каждый из которых содержит правильные константы для этого экструдера в соответствии с pressure advance для этого экструдера. Несколько экструдеров, использующих одни и те же значения pressure advance, могут совместно использовать объекты MoveSegment. Экструдеры, не использующие pressure advance, могут использовать общие оси MoveSegments.
- То же, что и № 1, но не применяется input shaping к движениям экструдера. Это означает, что движение экструдера не будет точно отслеживать движение оси во время сегментов ускорения и замедления; но он будет использовать намного меньше объектов MoveSegment в системах со смешивающими экструдерами. Имеет ли значение, если профиль ускорения не совпадает?
- Экструзия преобразуется на следующем шаге в дробь расстояния и используются общие сегменты MoveSegments для расчета времени. Чтобы выполнить преобразование, сначала вычисляется дополнительная экструзия в начале сегмента. Эта сумма может быть вычислена и сохранена в DM при запуске сегмента. Затем для сегмента ускорения нужно учитывать дополнительную скорость. К сожалению, это не просто.
- Вычисляется поправки к значениям A, B и C в MoveSegment и используются эти скорректированные значения при расчете времени шага. Новые значения ABC для текущего сегмента могут быть сохранены в DM. Это выглядит как разумный вариант, если значения ABC, хранящиеся в MoveSegment, плюс константы pressure advance и доля перемещения экструдера — это все, что нужно для вычисления скорректированных значений.