spindel.py 6.76 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("-d", "--durchmesser"
					  , dest="durchmesser"
					  , type="float"
					  , default=False
					  , help="Durchmesser in mm des zu fraesenden Kreises, beruecksichtigt den Fraeserdurchmesser"
	)
	parser.add_option("-R", "--radius"
					  , dest="radius"
					  , type="float"
					  , default=False
					  , help="Radius in mm des zu fraesenden Kreises, beruecksichtigt den Fraeserdurchmesser"
	)
	parser.add_option("-F", "--vorschub"
					  , dest="vorschub"
					  , type="int"
					  , default=100
					  , help="Vorschubgeschwindigkeit in mm/min"
	)
	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("-G", "--drehrichtung"
					  , dest="drehrichtung"
					  , type="str"
					  , default='CCW'
					  , help="Rotate drehrichtung, 'CW', default: 'CCW', or G-Code Number (2/3)"
	)

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

	if not (options.radius or options.durchmesser):
		parser.error('Radius oder Durchmesser nicht angegeben')

	if options.radius and options.durchmesser:
		parser.error('Entweder Radius oder Durchmesser angegeben, nicht beides zusammen')

	if options.drehrichtung.lower() == 'ccw' or options.drehrichtung == '03' or options.drehrichtung == '3' or options.drehrichtung.lower() == 'g03':
		drehrichtung = 'ccw'
	elif options.drehrichtung.lower() == 'cw' or options.drehrichtung == '02' or options.drehrichtung == '2' or options.drehrichtung.lower() == 'g02':
		drehrichtung = 'cw'
	else:
		parser.error('drehrichtung "%s" unbekannt' %(options.drehrichtung))

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

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


class Spindel:
	"""Super Duper Spindel Gcode Generator"""
	### SETUP
	def __init__(self, fraeser=0, radius=None, durchmesser=None, versatz=None, x=0, y=0, startradius=0, drehrichtung='cw', vorschub=100):
		self.setTool(
			fraeser
			, versatz
			, drehrichtung
			, vorschub
		)
		self.setTarget(
			radius if radius else durchmesser/2
			, x
			, y
		)
		self.setPosition(
			startradius
			, startradius
			, 0
		)
		self.validateInput()

	def setTool(self, fraeser, versatz=None, drehrichtung='cw', vorschub='100'):
		self.tool = {
			'fraeser'		: float(fraeser),
			'versatz'		: float(versatz) if versatz else fraeser/2.,
			'drehrichtung'	: {
				'name'	: 'cw' if drehrichtung == 'cw' else 'ccw',
				'gcode' : 'G02' if drehrichtung == 'cw' else 'G03'
			},
			'vorschub'		: int(vorschub)
		}

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

	def setPosition(self, startradius, x, y):
		self.position = {
			'radius'	: startradius,
			'x'		: startradius,
			'y'		: 0
		}

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

	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']))

	### GENERATE
	def head(self):
		print 'G00 G43 H1'
		print 'G21' #MM mode (G71 on older controls)
		print 'G54' #Work coordinate shift,offset #1

		print 'G01 Y%s X%s F%s' %(
			self.position['y'] + self.target['y']
			, self.position['x'] + self.target['x']
			, self.tool['vorschub']
		)

	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)
		#print 'M30' #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:])