paperstsoap paperstsoap - 4 months ago 38
Python Question

Edit G code Line by Line

I want to read a g code file line by line, and based off of a comment at the end, do an action to it. The g code is coming out of Slic3r. Some example lines in no particular order look like this:

G1 Z0.242 F7800.000 ; move to next layer (0)
G1 E-2.00000 F2400.00000 ; retract
G1 X0.000 Y30.140 F7800.000 ; move to first skirt point
G1 E0.00000 F2400.00000 ; unretract
G1 X-53.493 Y30.140 E2.14998 F1800.000 ; skirt
G1 X57.279 Y-37.776 E22.65617 ; perimeter
G1 X-52.771 Y-38.586 E56.83128 ; infill


The comment always starts with a semicolon and also uses consistent terms, such as perimeter or infill. Ideally the script would read the line, search for the particular comment case, perform an action based on that, then update the file, and then go to the next line. I am somewhat new to python, so I know that this would be done with a for-loop with nested if statements, however I am not sure how to set up the architecture to be based of those key terms.

Answer

I am not sure what you want to modify exactly, so I chose to add the word '(up)' in front of a comment that indicates retraction, and '(down)' in front of a comment that indicates unretraction.

file_name = "file.gcode"  # put your filename here

with open(file_name, 'r+') as f:

    new_code = ""            # where the new modified code will be put
    content = f.readlines()  # gcode as a list where each element is a line 

    for line in content: 
        gcode, comment = line.strip('\n').split(";")  # seperates the gcode from the comments 
        if 'unretract' in comment:  
            comment = ' (down) ' + comment
        elif 'retract' in comment:
            comment = ' (up)' + comment

        new_code += gcode + ';' + comment + '\n'  # rebuild the code from the modified pieces

    f.seek(0)           # set the cursor to the beginning of the file
    f.write(new_code)   # write the new code over the old one

The file contents would now be:

G1 Z0.242 F7800.000 ; move to next layer (0)
G1 E-2.00000 F2400.00000 ; (up) retract
G1 X0.000 Y30.140 F7800.000 ; move to first skirt point
G1 E0.00000 F2400.00000 ; (down) unretract
G1 X-53.493 Y30.140 E2.14998 F1800.000 ; skirt
G1 X57.279 Y-37.776 E22.65617 ; perimeter
G1 X-52.771 Y-38.586 E56.83128 ; infill

If you want to modify the gcode instead, lets say replace the first letter by a 'U' if the comment indicates retraction, and 'D' if the comment indicates unretraction, you just have to replace this:

if 'unretract' in comment:  
    comment = ' (down) ' + comment
elif 'retract' in comment:
    comment = ' (up)' + comment

By this:

if 'unretract' in comment:  
    gcode = 'D' + gcode[1:]
elif 'retract' in comment:
    gcode = 'U' + gcode[1:]

New file contents:

G1 Z0.242 F7800.000 ; move to next layer (0)
U1 E-2.00000 F2400.00000 ; retract
G1 X0.000 Y30.140 F7800.000 ; move to first skirt point
D1 E0.00000 F2400.00000 ; unretract
G1 X-53.493 Y30.140 E2.14998 F1800.000 ; skirt
G1 X57.279 Y-37.776 E22.65617 ; perimeter
G1 X-52.771 Y-38.586 E56.83128 ; infill

I hope this helps !


EDIT

To answer your request to get the X, Y, and F values, here is the updated script to store these values:

file_name = "file.gcode"  # put your filename here

    with open(file_name, 'r+') as f:

        coordinates = []
        content = f.readlines()  # gcode as a list where each element is a line 

        for line in content: 
            gcode, comment = line.strip('\n').split(";")  
            coordinate_set = {}
            if 'retract' not in comment and 'layer' not in comment:
                for num in gcode.split()[1:]:
                    coordinate_set[num[:1]] = float(num[1:])
                coordinates.append(coordinate_set)

If you print(coordinates) you get:

[{'X': 0.0, 'F': 7800.0, 'Y': 30.14}, {'E': 2.14998, 'X': -53.493, 'F': 1800.0, 'Y': 30.14}, {'E': 22.65617, 'X': 57.279, 'Y': -37.776}, {'E': 56.83128, 'X': -52.771, 'Y': -38.586}]

EDIT 2

To make this work on some real gcode (using

Script 1:

file_name = "file.gcode"  

    with open(file_name, 'r+') as f:

        new_code = ""            
        content = f.readlines()   line 

        for line in content: 
            if ';' in line:
                gcode, comment = line.strip('\n').split(";") 
            else:  # when there are no comments
                gcode = line.strip('\n')
                comment = ""

            if 'unretract' in comment:  
                comment = ' (down) ' + comment
            elif 'retract' in comment:
                comment = ' (up)' + comment

            if comment != "":
                new_code += gcode + ';' + comment + '\n'  # rebuild the code from the modified pieces
            else:  # when there are no comments
                new_code += gcode + '\n'

        f.seek(0)           
        f.write(new_code)   

Script 2:

file_name = "file.gcode" 

with open(file_name, 'r+') as f:

    coordinates = []
    content = f.readlines() 

    for line in content:
        if ';' in line:
            try:
                gcode, comment = line.strip('\n').split(";")
            except:
                print(' ERROR \n', line, '\n')
        else:
            gcode = line.strip('\n')
            comment = ""

        coordinate_set = {}
        if 'retract' not in comment and 'layer' not in comment and gcode:
            for num in gcode.split()[1:]:
                coordinate_set[num[:1]] = float(num[1:])
            coordinates.append(coordinate_set)

Some lines where Slic3r does some weird text do not work, this is what the ERROR printed thing is. Also, I recommend you don't try and print all of the coordinates, as this made Python crash. If you want to see the totality of the coordinates, you can paste them on a seperate .txt file, as such:

with ('coordinates.txt', 'w') as f2:
    f2.write(coordinates)
Comments