Skip to content

puthon script #49

Description

@tacomakes

The script inserts a small Z lift, moves to the target X, then returns Z so the move doesn't drag through the print. Defaults: move to X=0 every 10 layers with a 5 mm lift and a 6000 mm/min travel feed.

#!/usr/bin/env python3
"""
insert_move_every_n_layers.py

Usage (PrusaSlicer post-processing):
prusaslicer will invoke the script; it usually passes input and output filenames.
Example args in PrusaSlicer: --x 0 --every 10 --lift 5 --feed 6000

This script finds lines like ";LAYER:123" and after every Nth layer inserts a short
safe sequence to lift Z, move to X position, then restore Z.

Default values:
x=0.0, every=10, lift=5.0, feed=6000
"""

import sys
import argparse
import re

def parse_args():
p = argparse.ArgumentParser(description="Insert a move to X every N layers in G-code")
p.add_argument("--x", type=float, default=0.0, help="X coordinate to move to (mm)")
p.add_argument("--every", type=int, default=10, help="Do it every N layers (use 1 for every layer)")
p.add_argument("--lift", type=float, default=5.0, help="Relative Z lift before moving (mm)")
p.add_argument("--feed", type=float, default=6000, help="Feedrate for travel move (mm/min)")
p.add_argument("--marker", type=str, default=";MOVE_INSERTED", help="Marker comment to avoid double-insertions")
p.add_argument("infile", nargs="?", default=None, help="Input gcode file (optional, PrusaSlicer usually passes it)")
p.add_argument("outfile", nargs="?", default=None, help="Output gcode file (optional)")
return p.parse_args()

def make_move_block(x, lift, feed, marker):
# Use relative moves for lift and return so we don't need current Z value.
# Sequence:
# ; marker
# G91 ; relative mode
# G1 Z{lift} F3000
# G90 ; absolute mode
# G1 X{x} F{feed}
# G91
# G1 Z-{lift} F3000
# G90
# You may want to tweak feed and retracts for your setup.
lines = [
f"{marker} ; inserted by insert_move_every_n_layers.py",
"G91",
f"G1 Z{lift:.3f} F3000 ; lift before move",
"G90",
f"G1 X{x:.3f} F{feed:.0f} ; travel to X",
"G91",
f"G1 Z-{lift:.3f} F3000 ; lower back down",
"G90",
"" # blank line for readability
]
return "\n".join(lines)

def main():
args = parse_args()

# Input / output file handling
if args.infile and args.outfile:
    infile = args.infile
    outfile = args.outfile
elif args.infile and not args.outfile:
    # If only one file provided, overwrite it safely
    infile = args.infile
    outfile = infile + ".tmp"
else:
    # When PrusaSlicer runs the script it usually supplies input and output file paths.
    # But to be safe, read stdin and write stdout if no files provided.
    infile = None
    outfile = None

content = None
if infile:
    with open(infile, "r", encoding="utf-8") as f:
        content = f.read()
else:
    content = sys.stdin.read()

# Avoid double-inserting by checking for marker presence
if args.marker and args.marker in content:
    # Already ran (or file already contains marker) — do nothing and output original
    out_text = content
else:
    # Process content line by line
    out_lines = []
    layer_re = re.compile(r"^;LAYER:(\s*\d+)", re.IGNORECASE)
    for line in content.splitlines():
        out_lines.append(line)
        m = layer_re.match(line)
        if m:
            try:
                layer_num = int(m.group(1))
            except:
                # fallback: skip if can't parse
                continue
            if args.every > 0 and (layer_num % args.every) == 0:
                # skip inserting at layer 0 (optional) — many people want to skip layer 0
                # If you want to run at layer 0 too, remove the next condition.
                if layer_num == 0:
                    continue
                move_block = make_move_block(args.x, args.lift, args.feed, args.marker)
                out_lines.append(move_block)

    out_text = "\n".join(out_lines) + "\n"

if outfile:
    with open(outfile, "w", encoding="utf-8") as f:
        f.write(out_text)
    # If we created a temp file (infile.tmp), replace original
    if args.infile and not args.outfile:
        import os
        os.replace(outfile, infile)
else:
    sys.stdout.write(out_text)

if name == "main":
main()

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions