Перевернуть ось X файла G-код

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

Я думал, что было бы довольно тривиально проанализировать файл G-кода с помощью Python и изменить значение всех команд Xn с n на 2*h - n, где h находится в середине стола, скажем, 110 или 120 мм для Ender 3.

Прежде чем я запущу свою любимую IDE, есть ли какие-либо серьезные проблемы, с которыми я могу столкнуться из-за такого наивного подхода к отображению G-кода, подобного этому? Я изначально нарезал в Cura 4.9.1.

, 👍3

Обсуждение

Существуют визуализаторы g-кода, которые позволят вам открыть ваш недавно измененный файл, чтобы увидеть очевидные проблемы. Ваша ссылка на середину стола действительна? Я недостаточно изучил файл g-кода, чтобы заметить, является ли источник центром стола или определенным углом., @fred_dot_u

@fred_dot_u хороший момент, я полагаю, что я мог бы найти ограничивающую рамку печати, пока разбираю файл. По крайней мере, на эндере 3 домашняя позиция, кажется, находится на (0,0,0)., @Ron Jensen

часто вы можете масштабироваться со значением -1, чтобы отразить ось, если в срезе нет явного параметра зеркального отображения., @John Meacham


3 ответа


Лучший ответ:

4

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

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

Для того, чтобы отразить его нужно просто поменять координаты X в G-код, если (0,0) находится центр вашего стола, как это часто (но не всегда) чехол для дельта принтеров вы просто хотите отменяет Х, так Г1 Х30 М-3 З2 становится Г1 х-30 г-3 З2. Если ваши координаты имеют (0,0) в углу (часто это относится к ортогональным принтерам), то вы хотите вычесть X из максимального значения X. например, если ширина вашего стола составляет 250 мм, то в G1 X30 Y10 Z3 X30 становится X(250-30) или G1 X220 Y10 Z3.

Есть только одно предостережение: некоторые слайсеры переключаются на относительное перемещение, используя G91 для определенных операций, а затем возвращаются к абсолютному с помощью G90, поэтому вам нужно будет обратить на это внимание. Между G91 и G90 вы захотите отменить X, независимо от того, где находится источник вашего принтера.

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


,

3

Основываясь на исчерпывающем ответе @John Mecham, я быстро представил доказательство концепции. На изображении ниже стрелка влево (вверху) является оригиналом, а стрелка вправо (внизу) - перевернутым клоном. Cura действительно генерирует небольшой код относительного смещения в конце, я думаю, что справился с этим правильно.

Left and right arrows

import re

data_start = re.compile('^;LAYER_COUNT:[0-9]+')

ifilename = 'c:/Users/jentron128/Downloads/ThingVerse/Tools/arrow.gcode'
ofilename = 'c:/Users/jentron128/Downloads/ThingVerse/Tools/rev_arrow.gcode'

new_data =[]
BEDX = float(235)
h = BEDX # Absolute Positioning is default

mode='Skip'

with open(ifilename, 'r') as ifp:
    for d in ifp:
        new_d = ''
        tokens = d.split()
        if len(tokens) == 0:
            pass
        elif mode == 'Skip':
            new_d = d[0:-1]
            if data_start .match(d):
                mode = 'Go'
        else:
            if tokens[0] == 'G91': # Относительное расположение
                h = 0 
            elif tokens[0] == 'G90':# Абсолютное позиционирование
                h = BEDX
                
            for t in tokens:
                if t.startswith('X'):
                    if len(t) > 1:
                        x = h - float(t[1:])
                        t = 'X'+f'{x:.3f}'
                new_d += t+' '
        
        new_data.append(new_d)

with open(ofilename, 'w') as ofp:
    for d in new_data:
        ofp.write(d+'\n') # как линии записи не поддерживают разделитель строк?
    
,

`#!/usr/bin/env python3 импортировать повторно из системного импорта argv data_start = re.compile('^;LAYER_COUNT:[0-9]+') имя_файла = argv[1]; offilename = ifilename.replace('.gcode', '-reversed.gcode'); `, @Onza

Я попытался прокомментировать, чтобы сделать его повторно используемым скриптом, который вы можете запускать для любого файла, но комментарий был искажен; в основном используйте sys для импорта argv и используйте argv[1] для имени файла :), @Onza

Тем не менее, у меня это не сработало, не с файлом, созданным prusa., @Onza

По крайней мере, в Windows я никогда не запускаю Python из командной строки. Если у вас есть (желательно небольшой) файл gcode prusa, я посмотрю, смогу ли я изменить код для работы с ним., @Ron Jensen

Я думаю, что нашел проблему, вы ищете заголовок, который, похоже, специфичен для Cura, я сделал новую версию на основе вашей, которая правильно работает с файлами слайсера prusa; Я взял всю математику, которую вы использовали в целом, теперь она работает правильно; честно говоря, я не уверен, я никогда не прикасался к gcode до сих пор, но я думаю, что G1 универсален., @Onza

Да, в мой код встроен конечный автомат, и кажется, что переключатель основан на конкретном комментарии Cura. Все, что предшествует первому комментарию «;LAYER:0», выводится как прочитанное, потому что это все настройки принтера, затем состояние переключается в режим «Go» и после этого обрабатывает ВСЕ директивы X, независимо от G-кода. Он обрабатывает G90/G91 отдельно, устанавливая h = 0 для ОТНОСИТЕЛЬНОГО позиционирования и h = ширину стола для АБСОЛЮТНОГО позиционирования., @Ron Jensen

Самый простой способ обойти это — просто изменить режим = «Пропустить» на режим = «Перейти», и тогда скрипт обработает все строки., @Ron Jensen

Однако мы (или, по крайней мере, я) не были уверены, что это правильное предположение, я просто взял весь вывод токена G1 и перевернул его, предполагая, что это инструкции; Я написал код ниже, как вы можете видеть., @Onza


0

Использование: python3 [имя файла.gcode] [ширина стола]

#!/usr/bin/env python3

import re
from sys import argv

#first arg is the file, second arg is the bed x width
ifilename = argv[1];
ofilename = ifilename.replace('.gcode', '-reversed.gcode');

new_data =[]
BEDX = float(argv[2])
h = BEDX # Absolute Positioning is default

with open(ifilename, 'r') as ifp:
    for d in ifp:
        new_d = ''
        tokens = d.split()
        if len(tokens) == 0:
            pass
        else:
            if tokens[0] == 'G91': # Relative Positioning
                h = 0
                new_d += d
            elif tokens[0] == 'G90':# Absolute Positioning
                h = BEDX
                new_d += d
            elif tokens[0] == 'G1':
                for t in tokens:
                    if t.startswith('X'):
                        if len(t) > 1:
                            x = h - float(t[1:])
                            t = 'X'+f'{x:.3f}'
                    new_d += t+' '
            else:
                new_d += d

        new_data.append(new_d)

with open(ofilename, 'w') as ofp:
    for d in new_data:
        ofp.write(d+'\n') # how does writelines not support a line separator?

Для тех, у кого есть проблемы со сценарием выше, я думаю, что это исправит их.

Похоже, что существует ошибка, из-за которой G90 или G91 не пишется всякий раз, когда он их находит.

,

То, как вы генерируете ofilename, не очень безопасно. Если имя файла не оканчивается на .gcode (например, если оно оканчивается на .GCODE или .gco), замена будет неэффективной, и похоже, что вы перезапишете ввод., @R.. GitHub STOP HELPING ICE

Вы правы, сделайте третью версию или что-то в этом роде; Я быстро взломал это на месте, возможно, используя argv[2] для выходного имени., @Onza