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.
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
Script 1:
file_name = "file.gcode"
with open(file_name, 'r+') as f:
new_code = ""
content = f.readlines()
for line in content:
if ';' in line:
try:
gcode, comment = line.strip('\n').split(";")
except:
print('ERROR\n', line)
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'
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)
EDIT 3
Updated scripts to work with comments in parentheses.
Script 1:
file_name = "file.gcode"
with open(file_name, 'r+') as f:
new_code = ""
content = f.readlines()
for line in content:
if ';' in line:
try:
gcode, comment = line.strip('\n').split(";")
except:
print('ERROR\n', line)
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'
else: # when there are no comments
new_code += gcode + '\n'
f.seek(0)
f.write(new_code)
Script 2:
file_name = "3Samples_0skin_3per.gcode" # put your filename here
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 1: \n', line, '\n')
elif '(' in line:
try:
gcode, comment = line.strip('\n').strip(')').split("(")
except:
print('ERROR 2: \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:]:
if len(num) > 1:
try:
coordinate_set[num[:1]] = float(num[1:])
except:
print('ERROR 3: \n', gcode, '\n')
coordinates.append(coordinate_set)