spindel.py 5.23 KB
#!/usr/bin/python
'''
Generate Spindle Gcode
Copyright (C) 2014	Hubert Berezowski

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import sys
from optparse import OptionParser

def main(argv):
	parser = OptionParser(usage="usage: %prog -f fraeser -r radius [options]",
						  version="%prog 0.1")
	parser.add_option("-f", "--fraseserdurchmesser"
					  , dest="fraeser"
					  , type="float"
					  , default=False
					  , help="Durchmesser in mm des gewaehlten Fraesers"
	)
	parser.add_option("-r", "--fraseradius"
					  , dest="radius"
					  , type="float"
					  , default=False
					  , help="Radius in mm des zu fraesenden Kreises, beruecksichtigt den Fraeserradius"
	)
	parser.add_option("-v", "--versatz"
					  , dest="versatz"
					  , type="float"
					  , help="Versatz in mm, den Der Fraeser bei jedem durchlauf in das Material eintaucht"
	)
	parser.add_option("-x", "--offset_x"
					  , dest="x"
					  , type="float"
					  , default=0,
					  help="offset "
	)
	parser.add_option("-y", "--offset_y"
					  , dest="y"
					  , type="float"
					  , default=0
					  , help="offset"
	)
	parser.add_option("-s", "--startradius"
					  , dest="startradius"
					  , type="float"
					  , default=0
					  , help="Start at radius <>"
	)
	parser.add_option("-d", "--direction"
					  , dest="direction"
					  , type="str"
					  , default='CCW'
					  , help="Rotate direction, 'CW', default: 'CCW'"
	)

	(options, args) = parser.parse_args()
	if not options.fraeser:
		parser.error('Fraeserdurchmesser nicht angegeben')

	if not options.radius:
		parser.error('Radius nicht angegeben')

	spindel = Spindel(fraeser = options.fraeser
					  , radius = options.radius
					  , versatz = options.versatz if options.versatz else options.fraeser/2
					  , x = options.x
					  , y = options.y
					  , startradius = options.startradius
					  , direction = options.direction
	)

	spindel.head(spindel.direction)
	spindel.makeSpindel(spindel.position)


class Spindel:
	"""Super Duper Spindel Gcode Generator"""
	### SETUP
	def __init__(self, fraeser=0, radius=0, versatz=None, x=0, y=0, startradius=0, direction='CCW' ):
		self.tool = {}
		self.target = {}
		self.setTool(fraeser, versatz)
		self.setTarget(radius,x,y)
		self.position = {
			'radius' : startradius,
			'x' : startradius,
			'y' : 0
		}
		self.direction = direction
		self.validateInput()

	def validateInput(self):
		if self.tool['versatz'] > self.tool['fraeser']/2:
			sys.stderr.write('''
Achtung !\n
Es wird mit mehr als dem Fraeserradius gefraest\n
Fraeserradius: %s\nVersatz: %s
			''' %(self.tool['fraeser'], self.tool['versatz']))

		if self.tool['versatz'] > self.tool['fraeser']:
			raise Exception('''
Der Versatz ist groesser als der Fraeserdurchmesser\n
Fraeserradius: %s\nVersatz: %s
			''' %(self.tool['fraeser'], self.tool['versatz']))


	def setTool(self, fraeser, versatz=None):
		self.tool = {
			'fraeser'  : float(fraeser),
			'versatz' : float(versatz) if versatz else fraeser/2.
		}

	def setTarget(self, radius, x, y):
		self.target = {
			'radius' : float(radius - self.tool['fraeser']/2),
			'x'		 : float(x),
			'y'		 : float(y)
		}

	def printPosition(self, position):
		print 'Y%s X%s R%s' %(
			position['y'] + self.target['y'],
			position['x'] + self.target['x'],
			position['radius']
		)
		return	position

	### GENERATE
	def head(self, direction):

		print 'G21' #MM mode (G71 on older controls)
		print 'G0 Y%s X%s' %(
			self.position['y'] + self.target['y'],
			self.position['x'] + self.target['x']
		)

		if direction == 'CW':
			print 'G02' #Circular move CW
		else:
			print 'G03 F100' #Circular move CCW

	def increaseArc(self, position, versatz):
		diameter = (position['x']*2) + (0 if position['x'] > 0 else -versatz)
		position['x'] -= diameter
		position['radius'] = abs(diameter/2)
		self.printPosition(position)
		return position

	def makeSpindel(self, position):
		if abs(position['radius']) <= self.target['radius'] - self.tool['versatz']:
			self.makeSpindel(
				self.increaseArc(position, self.tool['versatz'])
			)
		else:
			self.closeSpindel(position)

	def closeSpindel(self, position):
		#print(self.target['radius'] - position['radius']);
		# print('// closing radius: %s') %(self.target['radius'] - position['radius'])
		self.increaseArc(position, self.target['radius'] - position['radius'])

		# make a nice border
		self.increaseArc(position, self.target['radius'] - position['radius'])
		self.increaseArc(position, self.target['radius'] - position['radius'])

		print 'M00' #Program stop
		print 'M01' #Optional program stop
		print 'M02' #End of program (no rewind or return to start of program)


		#

		# recenter the tool
		# print 'Y%s X%s' %(
		#	self.target['x'],
		#	self.target['y'],
		# )


if __name__ == "__main__":
	main(sys.argv[1:])