Kisslicer Python script to display current layer on printer

Discussions about firmware/slicing software, tweaks and settings
Post Reply
frankjoke
Posts: 150
Joined: Sat Dec 28, 2013 6:07 pm

Kisslicer Python script to display current layer on printer

Post by frankjoke »

Dear all!

I am using actually an Raspberry PI to print my files now (do not want to have PC running and will integrate also camera).

Only problem is that if I look at printer I do not know how far I am with print!

This caused me to (re)write a small Python script which I can add to Kisslicer (Printer/Firmware postprocess line)

The printer discplays on bottom line: Ln/m x%

where n=current layer, m = total layers and x = % of layers printed

The code for "Count.py" is:

Code: Select all

#!/usr/bin/env python

"""
Gcode to add 'layer/of layers %' message to KISSlicer.

Please add to Kisslicer Printer/Firmware/Post-Process the following:
/full/path/to/Count.py "<FILE>"

"""

import math
import os
import re
import sys


def rewrite(infile, outfile, verbose=False):
    nl = 0
    ml = 0
    for line in infile:
        match = re.match(r'^; BEGIN_LAYER_OBJECT',line.rstrip())
        if match:
            nl += 1
    infile.seek(0)
    ml = nl
    nl = 0
    if verbose:
        print("Max Layer=",ml)
		
    for line in infile:
        outfile.write(line)
        match = re.match(r'^; BEGIN_LAYER_OBJECT',line.rstrip())
        if match:
            line = "M117 L%d/%d %2.1f%%" %(nl,ml,(100.0*nl)/ml)
            outfile.write(line+'\n')
            nl += 1
            
    line = "M117 L%d/%d Done" %(nl,ml)
    outfile.write(line)
	
    if verbose:
        print(line)

    outfile.write("\n; Count.py END")

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('usage: Count.py <filename> [--verbose]')
    infilename = sys.argv[1]
    outfilename = '%s.count%s' % os.path.splitext(infilename)
    with open(infilename) as infile:
        with open(outfilename, 'w') as outfile:
            rewrite(infile, outfile, '--verbose' in sys.argv)
Of course, you need Python to be installed on PC ....


Oh yes, the new file created will be called *.count.gcode, so you can select the original or the one which is counting :)

I put the script into Kisslicer directory where I have others as well, maybe I combine them later to something more configurable :)
Last edited by frankjoke on Mon Feb 03, 2014 11:01 pm, edited 3 times in total.

Kjetilei
Posts: 334
Joined: Fri Mar 16, 2012 8:26 pm
Location: Stavanger, Norway

Post by Kjetilei »

Verry nice. Thanks for sharing!

frankjoke
Posts: 150
Joined: Sat Dec 28, 2013 6:07 pm

Post by frankjoke »

I updated the code to add last 'Done' message...
Please reload Count.py code ...

frankjoke
Posts: 150
Joined: Sat Dec 28, 2013 6:07 pm

Post by frankjoke »

Dear all!

I added one function I needed very much: Send certain g-code on certail layer!

You can add multiple arguments like "-L2 M140 S40"
which means that you send on beginning of layer 2 the g-code "M140 S40" (which is to set bed temperature to 40 degrees)

If you use "-L-x g-code" -x means numbers of layers-x, so last layer is -1!
-L0 = first layer
-L-1 = last layer
-L2 = 3rd layer
...

Please use '"' in the arguments to have the spaces and g-code correctly included

Example Kiss parameter:
x:\Your\pathz\to\Count.py "<FILE>" "-L2 M140 S40"

I use it to switch bed temperature lower on 3rd layer and turn fan off on layer 0 and on on layer 1!

Any ideas for additions are welcome :)

The new Python is is:

Code: Select all

#!/usr/bin/env python

"""
Gcode to add 'layer/of layers %' message to KISSlicer.

Please add to Kisslicer Printer/Firmware/Post-Process the following:
/full/path/to/Count.py "<FILE>" ["-L[-]x g-code"]*

"""

import math
import os
import re
import sys
import time


def rewrite(infile, outfile, args):
    verbose = '--verbose' in args
    # verbose = True
    al = []
    for a in args:
        match = re.match(r'^-L([\d-]+)(\s+)(.+)',a.rstrip())
        if match:
            al.append([int(match.group(1)),match.group(3)])
    if verbose:
        print(al)
    nl = 0
    ml = 0
    for line in infile:
        match = re.match(r'^; BEGIN_LAYER_OBJECT',line.rstrip())
        if match:
            nl += 1
    infile.seek(0)
    ml = nl
    nl = 0
    if verbose:
        print("Max Layer=",ml)
		
    for line in infile:
        outfile.write(line)
        match = re.match(r'^; BEGIN_LAYER_OBJECT',line.rstrip())
        if match:
            line = "M117 Layer %d/%d %2.1f     ;" %(nl,ml,(100.0*nl)/ml)
            outfile.write(line+'\n')
            for l in al:
                if (l[0]<0 and ml+l[0]==nl) or (l[0]>=0 and l[0]==nl):
                    outfile.write(l[1]+'\n')
                    if verbose:
                        print("Layer %d write: %s" % (nl,l[1]))
            nl += 1
            
    line = "M117 L%d/%d 100%% Done" %(nl,ml)
    outfile.write(line)
	
    if verbose:
        print(line)
        time.sleep(3)

    outfile.write("\n; Count.py END")

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('usage: Count.py <filename> [--verbose]')
    infilename = sys.argv[1]
    outfilename = '%s.count%s' % os.path.splitext(infilename)
    with open(infilename) as infile:
        with open(outfilename, 'w') as outfile:
            rewrite(infile, outfile, sys.argv)
            #rewrite(infile, outfile, ["--verbose","-L-1 ;Last Layer","-L0 ;First Layer"])

scp
Posts: 19
Joined: Mon Dec 30, 2013 1:02 am

Post by scp »

Triple percent in the M117 string will show one '%' on the display. So it's six '%' in the script.

Code: Select all

            line = "M117 Layer %d/%d %2.1f%%%%%%     ;" %(nl,ml,(100.0*nl)/ml)
Paul

frankjoke
Posts: 150
Joined: Sat Dec 28, 2013 6:07 pm

Post by frankjoke »

Thanks for the tip :)

scp
Posts: 19
Joined: Mon Dec 30, 2013 1:02 am

Post by scp »

Hi frankjoke,

I have experimented a little bit with your scripts. I'm using the Dual/Repetier firmware and I'm experiencing some strange checksum and resend issues. The longer the M117 string gets, the more likely that checksum and resend occurs or the print even breaks. A symptom for this issue is an "Idle" string in the message line of the display (rather than the "Layer 1/100..." I hope to see). Have you seen that, too?

Paul

[edit] In the meantime I have found the cause for the strange behavior: while doing some tests I had used a colon ':' in the M117 string. Unfortunately the colon has a special meaning in the protocol (command separation like CR/LF) and if used in the M117 string confuses the Repetier firmware. So better don't use ':' in strings.

frankjoke
Posts: 150
Joined: Sat Dec 28, 2013 6:07 pm

Post by frankjoke »

Dear all!

I updated script a bit to be used also in slic3r. You just need to add a layer change text in printer setting custom code:

Code: Select all

; Layer Change
; BEGIN_LAYER_OBJECT z=0
; Percent of print 0
in the slic3r and configure the call of the scrip in print settings output options.

p.s.: The verbose option was changed to -v and the last argument not starting with '-' is the filename!

Code: Select all

#!/usr/bin/env python

"""
Gcode to add 'layer/of layers %' message to KISSlicer.

Please add to Kisslicer Printer/Firmware/Post-Process the following:
/full/path/to/Count.py "<FILE>" ["-L[-]x g-code"]*

"""

import math
import os
import re
import sys
import time

def rewrite(infile, outfile, args):
    verbose = '-v' in args
    #verbose = True
    l = 0
    al = []
    lc = []
    for a in args:
        match = re.match(r'^-L([\d-]+)(\s+)(.+)',a.rstrip())
        if match:
            al.append([int(match.group(1)),match.group(3)])
    if verbose:
        print(al)
    nl = 0
    ml = 0
    islc = False
    for line in infile:
        l = l +1
        if re.match(r'^; BEGIN_LAYER_OBJECT z=([\d\.]+)',line.rstrip()):
            nl += 1

        if islc:
            match = re.match(r'^G1 X',line.rstrip())
            if match:
                lc.append(line.rstrip()+"; Count.py move")
                if verbose:
                    print("Tool change %d: %s" % (len(lc),line.rstrip()))
                islc = False
        else:
            match = re.match(r'^; \*\*\* Changing Extruders from',line.rstrip())
            if match:
                islc = True
                if verbose:
                    print("Line %d layer %d: %s" % (l,nl,line.rstrip()))
        
    infile.seek(0)
    ml = nl
    nl = 0
    nc = len(lc)
    c = 0
    lz = 0
    lp = 0
    if verbose:
        print("Max Layer=%d, Tool changes=%d" % (ml,nc))

    for line in infile:
        outfile.write(line)
        match = re.match(r'^G1 .*Z([\d\.]+).*',line.rstrip())
        if match:
            lz = match.group(1)
            match = False;
        else:
            match = re.match(r'^; BEGIN_LAYER_OBJECT z=([\d\.]+)',line.rstrip())
        if match:
            if match.group(1)=="0":
                #print (nl,ml)
                lp = "%0.1f" % ((float(nl)*100.0)/float(ml))
            else:
                lz = match.group(1)
            mline = "M117 L%d/%d %s@%s" %(nl,ml,lp,lz)
            if verbose:
                print (mline)
            outfile.write(mline+'\n')
            nl += 1
            match = False
        else:
            match = re.match(r'^; Percent of print ([\d\.]+)',line.rstrip())
        if match:
            if match.group(1)!="0":
                lp=match.group(1)
            else:
                lp = "%1.1f" %((100.0*float(nl))/float(ml))
            cl = nl-1
            mline = "M117 L%d/%d %s@%s" %(cl,ml,lp,lz)
            if verbose:
                print (mline)
            outfile.write(mline+'\n')
            for l in al:
                if (l[0]<0 and ml+l[0]==cl) or (l[0]>=0 and l[0]==cl):
                    outfile.write(l[1]+'\n')
                    if verbose:
                        print("Layer %d write: %s" % (cl,l[1]))
        match = re.match(r'^; \*\*\* Changing Extruders from',line.rstrip())
        if match and nc>0:
             outfile.write(lc[c]+'\n')
             c=c+1
                 
    mline = "M117 L%d/%d 100%%%%%% Done" %(nl,ml)
    outfile.write(mline)
	
    if verbose:
        print(line)
        time.sleep(3)

    outfile.write("\n; Count.py END")

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('usage: Count.py <filename> [-v]')
    for arg in sys.argv[1:]:
        if arg[0]!="-":
            infilename = arg
    outfilename = '%s.count%s' % os.path.splitext(infilename)
    with open(infilename) as infile:
        with open(outfilename, 'w') as outfile:
            rewrite(infile, outfile, sys.argv)
            #rewrite(infile, outfile, ["--verbose","-L-1 ;Last Layer","-L0 ;First Layer"])

Post Reply