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.

👁️
16
Lượt Xem
❤️
0
Lượt Thích
📥
0
Lượt Tải
Cập Nhật Feb 12, 2026
Chi tiết
Tải xuống
Bình Luận
Khoe bản in
Remix

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

Tác phẩm này được cấp phép theo

GNU General Public License v2.0

GPL 2.0

Yêu cầu ghi công
Remix & phái sinh Được phép
Sử dụng thương mại Được phép

File mô hình

TẤT CẢ FILE MÔ HÌNH (1 Tập tin)
Đang tải files, vui lòng chờ...
Vui lòng đăng nhập để bình luận.

Chưa có bình luận nào. Hãy là người đầu tiên!

Vui lòng đăng nhập để khoe bản in của bạn.

Chưa có bản in nào được khoe. Hãy là người đầu tiên!

Remix (0)