PORTING cho Bambu Studio / Prusa Slicer / Orca Slicer làm bằng AI… mà AI không thông minh lắm
Bản port/điều chỉnh để dùng với Bambu Studio, Prusa Slicer và Orca Slicer: script PenColorizer.py cho post-processing G-code, thêm logic đổi bút, offset tọa độ và vẽ nhiều bút (multi-pen plotting) trên máy in 3D.
Mô tả
!/usr/bin/env python3
# PenColorizer.py - Đã chỉnh sửa để dùng cho post-processing của Orca Slicer / Bambu Studio
# Thêm logic đổi bút & vẽ theo offset để plot nhiều bút trên máy in 3D
import re
import sys
import os
class PenColorizer:
def init(self):
# Đây là các thiết lập của bạn — nếu cần thì sau này có thể chuyển thành command-line args
self.penstartx = 28.0
self.penstarty = 238.0 # lưu ý: trước đây tên là FirstPenZPosition, nhưng thực tế lại dùng như Y!
self.xoffset = 36.1
self.yoffset = 45.8
self.zoffset = 3.2
self.extra_retraction = 5.5
self.interlace = True # chỉ vẽ mỗi “color”/tool cách 1 cái (vẽ cách lớp)
self.last_z = 0.2
def get_pen(self, pen):
penside = pen % 2
penoffset = float(pen // 2) * 68.0
if penside == 0:
return [
f";Get pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ;go under pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen right",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen"
]
else:
return [
f";Get pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ;go under pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen right",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen"
]
def put_pen(self, pen):
penside = pen % 2
penoffset = float(pen // 2) * 68.0
if penside == 0:
return [
f";put pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; go under pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty:.3f} ; move pen left",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen",
"G0 F5000 ; set speed fast",
""
]
else:
return [
f";put pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; go under pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen left",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen",
"G0 F5000 ; set speed fast",
""
]
def offset_gcode(self, line, extra_z=0.0):
if not (line.startswith('G0') or line.startswith('G1')):
return line
parts = []
cmd = line.split(' ', 1)[0]
parts.append(cmd)
coords = re.findall(r'([XYZF])(-?\d*.?\d+)', line)
f_found = False
for axis, value in coords:
val = float(value)
if axis == 'F':
parts.append(f"F3600") # hard-code giống bản gốc
f_found = True
elif axis == 'X':
parts.append(f"X{val + self.xoffset:.3f}")
elif axis == 'Y':
parts.append(f"Y{val + self.yoffset:.3f}")
elif axis == 'Z':
parts.append(f"Z{val + self.zoffset + extra_z:.3f}")
if not f_found and 'F' in line: # dự phòng
parts.append("F3600")
return ' '.join(parts)
def lift_gcode(self, line, extra_z=0.0):
if not (line.startswith('G0') or line.startswith('G1')):
return line
parts = []
cmd = line.split(' ', 1)[0]
parts.append(cmd)
coords = re.findall(r'([XYZF])(-?\d*.?\d+)', line)
for axis, value in coords:
val = float(value)
if axis == 'F':
parts.append(f"F{val:.0f}")
elif axis == 'X':
parts.append(f"X{val:.3f}")
elif axis == 'Y':
parts.append(f"Y{val:.3f}")
elif axis == 'Z':
parts.append(f"Z{val + extra_z:.3f}")
return ' '.join(parts)
def get_first_position_line(self, draw_block):
for ln in draw_block:
if 'G0' in ln or 'G1' in ln:
if 'X' in ln and 'Y' in ln and 'Z' in ln:
return ln
return None
def add_explicit_z(self, lines):
new_lines = []
for line in lines:
if ('G0' in line or 'G1' in line) and 'Z' not in line:
line += f" Z{self.last_z:.3f}"
elif 'Z' in line:
m = re.search(r'Z(-?\d*.?\d+)', line)
if m:
self.last_z = float(m.group(1))
new_lines.append(line)
return new_lines
def process(self, gcode_text):
data = gcode_text.splitlines(keepends=True)
# Mình sẽ xử lý trực tiếp; gom các dòng đã chỉnh sửa
output = []
layer_num = -1
cur_tool = 0
last_x, last_y, last_z = 100.0, 100.0, 0.3
is_layer = False
is_prime_tower = False
is_skirt_support_fill = False
drawbuffers = [[] for in range(8)] # theo từng "tool"/bút
i = 0
while i < len(data):
line = data[i].rstrip('\r\n')
orig_line = line
if line.startswith(';LAYER:'):
layer_num += 1
is_layer = True
output.append(orig_line)
i += 1
continue
if ';layer_height =' in line:
try:
lh = float(line.split('=')[1].strip())
# nếu cần thì có thể dùng lh
except:
pass
output.append(orig_line)
i += 1
continue
if ';TYPE:' in line:
if 'PRIME-TOWER' in line:
is_prime_tower = True
is_skirt_support_fill = False
elif any(t in line for t in ['SKIRT', 'SUPPORT', 'SUPPORT-INTERFACE', 'FILL']):
is_skirt_support_fill = True
is_prime_tower = False
else:
is_skirt_support_fill = False
is_prime_tower = False
output.append(orig_line)
i += 1
continue
draw_this = (cur_tool >= 0 and
not is_skirt_support_fill and
not is_prime_tower and
((layer_num + cur_tool) % 2 == 0 or not self.interlace))
if ('G0' in line or 'G1' in line):
# cập nhật vị trí cuối cùng
if 'X' in line:
m = re.search(r'X(-?\d*.?\d+)', line)
if m: last_x = float(m.group(1))
if 'Y' in line:
m = re.search(r'Y(-?\d*.?\d+)', line)
if m: last_y = float(m.group(1))
if 'Z' in line:
m = re.search(r'Z(-?\d*.?\d+)', line)
if m: last_z = float(m.group(1))
e_match = re.search(r'E(-?\d*.?\d+)', line)
if e_match:
eval = float(ematch.group(1))
if e_val < 0:
# retract → giả định có thể z-hop
extra_z_offset = 3.0
else:
extra_z_offset = 0.0
else:
extra_z_offset = 0.0
if draw_this:
draw_buffers[cur_tool].append(self.offset_gcode(line, extra_z_offset))
else:
output.append(orig_line)
elif line.startswith('T'):
try:
cur_tool = int(line[1:]) - 1
except:
cur_tool = 0
output.append(';' + orig_line) # comment lại lệnh tool change
i += 1
continue
elif any(t in line for t in ['T1','T2','T3','T4','T5','T6','T7','T8']):
output.append(';' + orig_line)
i += 1
continue
# Nếu muốn thì có thể bỏ qua lệnh gia nhiệt ở các lớp object
elif is_layer and any(cmd in line for cmd in ['M104','M109','M105']):
# tùy chọn: comment hoặc xóa
pass
else:
output.append(orig_line)
i += 1
# Giờ chèn các block vẽ theo từng layer (bản rút gọn – có thể bạn sẽ cần chỉnh lại điểm chèn)
# Cho đơn giản, mình append ở cuối mỗi block ;LAYER, nhưng lý tưởng là chèn trước layer kế hoặc sau inner walls
# Đây là bản đơn giản – nhớ test & chỉnh lại logic chèn
final_output = []
in_layer = False
for ln in output:
final_output.append(ln)
if ln.startswith(';LAYER:') and layer_num >= 0:
in_layer = True
# retract trước khi vẽ
final_output.append(f"G1 F1500 E-{self.extra_retraction}\n")
for pen in range(8):
block = draw_buffers[pen]
if len(block) < 2: # gần như rỗng
continue
first_pos = self.get_first_position_line(block)
if first_pos:
final_output.append(self.lift_gcode(first_pos, 3.0) + " ; hạ bút từ phía trên xuống điểm đầu tiên\n")
final_output.extend(self.get_pen(pen))
final_output.extend(block)
if block:
final_output.append(self.lift_gcode(block[-1], 3.0) + " ; nâng bút lên sau điểm cuối\n")
final_output.extend(self.put_pen(pen))
# quay lại sau khi vẽ
final_output.append(f"G0 X{last_x:.3f} Y{last_y:.3f} Z{last_z + 2.0:.3f}\n")
final_output.append(f"G0 X{last_x:.3f} Y{last_y:.3f} Z{last_z:.3f} ; quay về vị trí cuối sau khi vẽ\n")
final_output.append(f"G1 F1500 E{self.extra_retraction}\n\n")
return ''.join(final_output)
if name == "main":
if len(sys.argv) < 2:
print("Usage: python PenColorizer.py
print(" Script sẽ chỉnh sửa và ghi đè trực tiếp lên file.")
sys.exit(1)
input_path = sys.argv[1]
if not os.path.isfile(input_path):
print(f"File không tồn tại: {input_path}")
sys.exit(1)
with open(input_path, 'r', encoding='utf-8') as f:
gcode = f.read()
processor = PenColorizer()
modified = processor.process(gcode)
with open(input_path, 'w', encoding='utf-8') as f:
f.write(modified)
print(f"Đã xử lý và ghi đè: {input_path}")
Giấy phép
File mô hình
Chưa có bản in nào được khoe. Hãy là người đầu tiên!
Chưa có bình luận nào. Hãy là người đầu tiên!