123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- """
- # Python Gcode wrapper
- #
- # Copyright (c) 2010-2018 Michael Buesch <m@bues.ch>
- #
- # Licensed under the GNU General Public License version 2
- # or (at your option) any later version.
- #
- # Example usage:
- from pync import *
- G54 | G0(0, 0, 2) | S(1000) | F(100) | M3
- for (x, y) in ((0, 0), (10, 10), (20, 20)):
- G0(x, y)
- G1(Z=-20)
- G0(Z=2)
- """
- import sys
- import six
- import atexit
- import datetime
- from math import *
- class __PyNC_State(object):
- def __init__(self):
- self.reset()
- def reset(self):
- self.lineBuffer = []
- def dump(self, fd=sys.stdout):
- code = "\n".join(str(l) for l in self.lineBuffer)
- fd.write(code + "\n")
- fd.flush()
- pync = __PyNC_State()
- class _Line_Metaclass(type):
- """Metaclass for class Line.
- """
- def __meta_merge(self, other):
- return self()._merge(other)
- __add__ = __meta_merge # a + b
- __sub__ = __meta_merge # a - b
- __mul__ = __meta_merge # a * b
- __lshift__ = __meta_merge # a << b
- __rshift__ = __meta_merge # a >> b
- __and__ = __meta_merge # a & b
- __xor__ = __meta_merge # a ^ b
- __or__ = __meta_merge # a | b
- @six.add_metaclass(_Line_Metaclass)
- class Line(object):
- """A generic Gcode line.
- """
- def __init__(self, code=""):
- self.code = code
- pync.lineBuffer.append(self)
- def _merge(self, add):
- if not add:
- return self
- if isinstance(add, str):
- self.code += " " + add
- else:
- if not isinstance(add, Line):
- add = add()
- assert(isinstance(add, Line))
- self.code += " " + add.code
- pync.lineBuffer.remove(add)
- return self
- __add__ = _merge # a + b
- __sub__ = _merge # a - b
- __mul__ = _merge # a * b
- __lshift__ = _merge # a << b
- __rshift__ = _merge # a >> b
- __and__ = _merge # a & b
- __xor__ = _merge # a ^ b
- __or__ = _merge # a | b
- def __repr__(self):
- return self.code
- @staticmethod
- def makecoordnum(coord):
- if equal(coord, int(coord)):
- return str(int(coord))
- return ("%f" % float(coord)).rstrip("0")
- @staticmethod
- def makecoord(axis, coord):
- return axis + Line.makecoordnum(coord)
- @staticmethod
- def makegcodenum(number):
- if isinstance(number, float):
- return "%.1f" % number
- return "%d" % number
- @staticmethod
- def makegcode(code, number):
- return code + Line.makegcodenum(number)
- @staticmethod
- def checkargs(kwargs, allowedList):
- for arg in kwargs.keys():
- if arg not in allowedList:
- raise TypeError("Got an unexpected keyword "
- "argument '%s'" % arg)
- raw = Line
- class Comment(Line):
- "A human readable comment"
- def __init__(self, text="", space=" "):
- text = str(text).replace("\r", " ").split("\n")
- Line.__init__(self, Comment.__format(text[0], space))
- if len(text) > 1: # Remaining lines, if any.
- Comment("\n".join(text[1:]), space)
- @staticmethod
- def __format(text, space):
- if text:
- return "(%s%s%s)" % (space, text, space)
- return ""
- c = Comment
- class Print(Comment):
- "Print a message"
- def __init__(self, text):
- Comment.__init__(self, "PRINT," + text, space="")
- p = Print
- class Debug(Comment):
- "Print a debugging message"
- def __init__(self, text):
- Comment.__init__(self, "DEBUG," + text, space="")
- d = Debug
- class LogOpen(Comment):
- "Open a log file"
- def __init__(self, filename):
- Comment.__init__(self, "LOGOPEN," + filename, space="")
- class LogClose(Comment):
- "Close the log file"
- def __init__(self):
- Comment.__init__(self, "LOGCLOSE", space="")
- class Log(Comment):
- "Write text to the log file"
- def __init__(self, text):
- Comment.__init__(self, "LOG," + text, space="")
- l = Log
- class G(Line):
- "Generic G-code"
- def __init__(self, number, X=None, Y=None, Z=None,
- A=None, B=None, C=None,
- I=None, J=None, K=None,
- U=None, V=None, W=None,
- P=None, Q=None, R=None,
- L=None, D=None,
- **kwargs):
- Line.__init__(self, self.makegcode("G", number))
- for paramStr in ("X", "Y", "Z",
- "A", "B", "C",
- "I", "J", "K",
- "U", "V", "W",
- "P", "Q", "R",
- "L", "D"):
- param = eval(paramStr) # Fetch __init__ argument
- if param is None:
- param = kwargs.get(paramStr.lower())
- if param is not None:
- self << Line.makecoord(paramStr, param)
- class G0(G):
- "G0 => rapid move"
- def __init__(self, X=None, Y=None, Z=None,
- A=None, B=None, C=None,
- U=None, V=None, W=None,
- **kwargs):
- self.checkargs(kwargs, {"x", "y", "z",
- "a", "b", "c",
- "u", "v", "w"})
- G.__init__(self, 0, X=X, Y=Y, Z=Z,
- A=A, B=B, C=C,
- U=U, V=V, W=W,
- **kwargs)
- rapid = G0
- class G1(G):
- "G1 => move"
- def __init__(self, X=None, Y=None, Z=None,
- A=None, B=None, C=None,
- U=None, V=None, W=None,
- **kwargs):
- self.checkargs(kwargs, {"x", "y", "z",
- "a", "b", "c",
- "u", "v", "w"})
- G.__init__(self, 1, X=X, Y=Y, Z=Z,
- A=A, B=B, C=C,
- U=U, V=V, W=W,
- **kwargs)
- move = G1
- class G2(G):
- "G2 => clockwise arc move"
- def __init__(self, X=None, Y=None, Z=None,
- I=None, J=None, K=None,
- R=None,
- **kwargs):
- self.checkargs(kwargs, {"x", "y", "z",
- "i", "j", "k",
- "r"})
- G.__init__(self, 2, X=X, Y=Y, Z=Z,
- I=I, J=J, K=K,
- R=R,
- **kwargs)
- arcCw = G2
- class G3(G):
- "G3 => counterclockwise arc move"
- def __init__(self, X=None, Y=None, Z=None,
- I=None, J=None, K=None,
- R=None,
- **kwargs):
- self.checkargs(kwargs, {"x", "y", "z",
- "i", "j", "k",
- "r"})
- G.__init__(self, 3, X=X, Y=Y, Z=Z,
- I=I, J=J, K=K,
- R=R,
- **kwargs)
- arcCcw = G3
- class G10L1(G):
- "G10 L1 => Set tool table"
- def __init__(self, P=None, R=None, X=None,
- Z=None, Q=None,
- **kwargs):
- self.checkargs(kwargs, {"p", "r", "x",
- "z", "q"})
- G.__init__(self, 10, L=1, P=P, R=R,
- X=X, Z=Z, Q=Q,
- **kwargs)
- class G10L2(G):
- "G10 L2 => Set coordinate system"
- def __init__(self, P=None, X=None, Y=None, Z=None,
- A=None, B=None, C=None,
- U=None, V=None, W=None,
- **kwargs):
- self.checkargs(kwargs, {"p", "x", "y", "z",
- "a", "b", "c",
- "u", "v", "w"})
- G.__init__(self, 10, L=2, P=P,
- X=X, Y=Y, Z=Z,
- A=A, B=B, C=C,
- U=U, V=V, W=W,
- **kwargs)
- class G64(G):
- "G64 => Path control mode"
- def __init__(self, P=None, **kwargs):
- self.checkargs(kwargs, {"p"})
- G.__init__(self, 64, P=P, **kwargs)
- class G41(G):
- "G41 => Cutter radius compensation - left"
- def __init__(self, D=None, **kwargs):
- self.checkargs(kwargs, {"d"})
- G.__init__(self, 41, D=D, **kwargs)
- class G42(G):
- "G42 => Cutter radius compensation - right"
- def __init__(self, D=None, **kwargs):
- self.checkargs(kwargs, {"d"})
- G.__init__(self, 42, D=D, **kwargs)
- class G41_1(G):
- "G41_1 => Dynamic cutter radius compensation - left"
- def __init__(self, D=None, L=None, **kwargs):
- self.checkargs(kwargs, {"d", "l"})
- G.__init__(self, 41.1, D=D, L=L, **kwargs)
- class G42_1(G):
- "G42_1 => Dynamic cutter radius compensation - right"
- def __init__(self, D=None, L=None, **kwargs):
- self.checkargs(kwargs, {"d", "l"})
- G.__init__(self, 42.1, D=D, L=L, **kwargs)
- class M(Line):
- "Generic M-code"
- def __init__(self, number):
- Line.__init__(self, self.makegcode("M", number))
- class S(Line):
- "Set spindle speed"
- def __init__(self, number):
- Line.__init__(self, self.makegcode("S", number))
- class F(Line):
- "Set feed rate"
- def __init__(self, number):
- Line.__init__(self, self.makegcode("F", number))
- class T(Line):
- "Set tool"
- def __init__(self, number):
- Line.__init__(self, self.makegcode("T", number))
- def __genTrivial(code, number):
- template = """
- class %s%s(%s):
- def __init__(self):
- %s.__init__(self, %s)
- """
- numStr = Line.makegcodenum(number)
- className = numStr.replace(".", "_")
- return template % (code, className, code,
- code, numStr)
- # Declare trivial G codes
- for __num in (17, 18, 19, 17.1, 18.1, 19.1,
- 20, 21,
- 28, 28.1,
- 30, 30.1,
- 40,
- 49,
- 53, 54, 55, 56, 57, 58, 59, 59.1, 59.2, 59.3,
- 61, 61.1,
- 80,
- 90, 91, 90.1, 91.1,
- 93, 94, 95):
- exec(__genTrivial("G", __num))
- # Declare trivial M codes
- for __num in range(0, 200):
- exec(__genTrivial("M", __num))
- def equal(a, b):
- "Test a and b for equalness. Returns bool. Also works for float."
- if isinstance(a, float) or isinstance(b, float):
- return abs(float(a) - float(b)) < 0.00001
- return a == b
- eq = equal
- ne = lambda a, b: not equal(a, b)
- ge = lambda a, b: equal(a, b) or a > b
- le = lambda a, b: equal(a, b) or a < b
- lt = lambda a, b: not equal(a, b) and a < b
- gt = lambda a, b: not equal(a, b) and a > b
- def __prologue():
- "Generate the file prologue"
- pync.reset()
- Line("%")
- Comment("This file is generated by PYNC gcode wrapper from '%s'." % sys.argv[0])
- Comment(str(datetime.datetime.today()))
- Comment()
- G54 | G17 | G40 | G49 | G80 | G90 | G91_1 | G94 | G61 | G21
- def __epilogue():
- "Generate an M30 (program end) and dump the code."
- M30()
- Line("%")
- pync.dump()
- # Generate prologue and epilogue
- __prologue()
- atexit.register(__epilogue)
- # Clean up namespace
- del sys, six, atexit, datetime
- del __prologue, __epilogue,
- del __PyNC_State
- del _Line_Metaclass,
- del __num, __genTrivial
|