diff options
author | Mike Beattie <mike@ethernal.org> | 2013-08-30 03:36:35 +1200 |
---|---|---|
committer | Mike Beattie <mike@ethernal.org> | 2013-08-30 03:36:35 +1200 |
commit | 4d8d3ce82a05316912088ceec144c5b557a4b5cb (patch) | |
tree | 3dc8a09fe1fa6495bcd4f47087c39e8f518d8e37 /gcode | |
parent | d7f66ca9c6e643d4fcad1602681fa13bb7bc2028 (diff) |
Add gcode generation script
For generating gcode to cut rings and bulkheads with a cnc router
Signed-off-by: Mike Beattie <mike@ethernal.org>
Diffstat (limited to 'gcode')
-rw-r--r-- | gcode/.gitignore | 2 | ||||
-rwxr-xr-x | gcode/rings.py | 200 | ||||
-rw-r--r-- | gcode/rocket_gcode.py | 193 |
3 files changed, 395 insertions, 0 deletions
diff --git a/gcode/.gitignore b/gcode/.gitignore new file mode 100644 index 0000000..d6f32f8 --- /dev/null +++ b/gcode/.gitignore @@ -0,0 +1,2 @@ +*.pyc +mjbl3* diff --git a/gcode/rings.py b/gcode/rings.py new file mode 100755 index 0000000..2a9abe0 --- /dev/null +++ b/gcode/rings.py @@ -0,0 +1,200 @@ +#! /usr/bin/python +# Copyright 2008 by Bdale Garbee <bdale@gag.com>. GPLv2 +# Copyright 2011 by Anthony Towns <aj@erisian.com.au>. GPLv2 + +import math +from rocket_gcode import * + +Zfree = 0.2500 # height in Z to clear all obstructions +Speed = 10 # cutting speed + +MMT_OD = mm2inch(79.3) +Coupler_ID = 3.74 +Airframe_ID = 3.90 +Nose_ID = 3.75 + +FinCount = 3 +FinWidth = mm2inch(6.25) # Actually 6.85, but allowance for wandering bit. + + +### AFT CR - Aeropack holes and fin slots - 1/8" bit +CutterOD = 0.125 # 1/8" +gcode = Gcode(output=open("mjbl3_cr_aft-aeropack.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +RingThickness = 0.75 +RingID = MMT_OD +RingOD = Airframe_ID +AeropackRotation = 15 # Get the holes out of alignment with fin slots. +AeropackDepth = 0.8 # Go right through the bulkhead +AeropackStep = 0.2 # cut in 0.2 inch increments +FinDepth = RingThickness/2 +FinIncrement = 0.1 + +gcode.comment("Aeropack retainer holes, depth %s" % (AeropackDepth,)) +gcode.aeropack_75mm(AeropackRotation, AeropackDepth, AeropackStep) + +gcode.comment("Fin slots, depth %1.3f in %1.1f increments" % (FinDepth, FinIncrement)) +gcode.fin_slots(FinCount, RingID, RingOD, FinWidth, FinDepth, FinIncrement) + +gcode.close() + +### AFT CR - MMT/Airframe cuts - 1/4" bit. +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_cr_aft-rings.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +RingID = MMT_OD +RingOD = Airframe_ID + +for Zthrough in (0.25, 0.5, 0.8): + gcode.Zdepth = Zthrough + gcode.comment("MMT hole depth %s" % (Zthrough,)) + gcode.circle(RingID - CutterOD) + +for Zthrough in (0.25, 0.5, 0.8): + gcode.Zdepth = Zthrough + gcode.comment("ring outer diameter") + gcode.circle(RingOD + CutterOD) + +gcode.close() + +### FORWARD FIN CR - fin slots +CutterOD = 0.125 # 1/8" +gcode = Gcode(output=open("mjbl3_cr_finfwd-slots.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +RingThickness = 0.75 +RingID = MMT_OD +RingOD = Airframe_ID +FinDepth = RingThickness/2 +FinIncrement = 0.1 + +gcode.fin_slots(FinCount, RingID, RingOD, FinWidth, FinDepth, FinIncrement) + +gcode.close() + +### AFT CR - MMT/Airframe cuts - 1/4" bit. +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_cr_finfwd-rings.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +RingID = MMT_OD +RingOD = Airframe_ID + +for Zthrough in (0.25, 0.5, 0.8): + gcode.Zdepth = Zthrough + gcode.comment("MMT hole depth %s" % (Zthrough,)) + gcode.circle(RingID - CutterOD) + +for Zthrough in (0.25, 0.5, 0.8): + gcode.Zdepth = Zthrough + gcode.comment("ring outer diameter") + gcode.circle(RingOD + CutterOD) + +gcode.close() + +### ZIPPERLESS FORWARD CR +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_cr_zipperless.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +RingID = MMT_OD +RingOD = Coupler_ID + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("Zipperless CR, MMT diam") + gcode.circle(RingID - CutterOD) + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("Zipperless CR, coupler diam") + gcode.circle(RingOD + CutterOD) + +gcode.close() + +### EBAY BULKHEAD HOLES +CutterOD = 0.125 # 1/8" +gcode = Gcode(output=open("mjbl3_bh_ebay-holes1.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +Allthread_width = 2.50 + +gcode.hole(x=0, y= (Allthread_width/2), depth=0.6, increment=0.3, speed=25) +gcode.hole(x=0, y=-(Allthread_width/2), depth=0.6, increment=0.3, speed=25) + +gcode.close() + +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_bh_ebay-holes2.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +UBolt_width = 0.945 + +gcode.hole(x= (UBolt_width/2), y=0, depth=0.6, increment=0.3, speed=25) +gcode.hole(x=-(UBolt_width/2), y=0, depth=0.6, increment=0.3, speed=25) + +gcode.close() + +### EBAY BULKHEADS +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_bh_ebay.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +BulkheadOD = Airframe_ID +StepOD = Coupler_ID + +gcode.Zdepth = 0.25 +gcode.comment("ebay bulkhead - step, coupler diameter") +gcode.circle(StepOD + CutterOD) + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("ebay bulkhead - outer diameter") + gcode.circle(BulkheadOD + CutterOD) + +gcode.close() + +### Nosecone bulkhead +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_bh_nose.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +BulkheadOD = Nose_ID +HatchOD = 2.0 +HatchFlangeOD = 2.5 + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("Nose bulkhead, hatch.") + gcode.circle(HatchOD - CutterOD) + +gcode.Zdepth = 0.25 +gcode.comment("Nose bulkhead, hatch flange") +gcode.circle(HatchFlangeOD - CutterOD) + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("Nose bulkhead - outer diameter") + gcode.circle(BulkheadOD + CutterOD) + +gcode.close() + +### Nosecone bulkhead - hatch slot +CutterOD = 0.125 # 1/8" +gcode = Gcode(output=open("mjbl3_bh_nose-hatch-slot.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +gcode.slot(startX=0, startY=0.75, stopX=0, stopY=-0.75, width=0.180, depth=0.6, increment=0.1) + +gcode.close() + +### Nosecone bulkhead - hatch +CutterOD = 0.25 # 1/4" +gcode = Gcode(output=open("mjbl3_bh_nose-hatch.ngc","w"), speed=Speed, free=Zfree, cutter=CutterOD) + +HatchOD = 2.0 +HatchFlangeOD = 2.5 + +gcode.Zdepth = 0.25 +gcode.comment("Nose bulkhead, hatch") +gcode.circle(HatchOD + CutterOD) + +for Zthrough in (0.25, 0.6): + gcode.Zdepth = Zthrough + gcode.comment("Nose bulkhead, hatch flange.") + gcode.circle(HatchFlangeOD + CutterOD) + +gcode.close() + diff --git a/gcode/rocket_gcode.py b/gcode/rocket_gcode.py new file mode 100644 index 0000000..21da27e --- /dev/null +++ b/gcode/rocket_gcode.py @@ -0,0 +1,193 @@ +#! /usr/bin/python +# Copyright 2008 by Bdale Garbee <bdale@gag.com>. GPLv2 +# Copyright 2011 by Anthony Towns <aj@erisian.com.au>. GPLv2 + +# This is a Python library to emit g-code to cut motor mount centering +# rings or bulkheads for a model rocket. +# +# Z reference plane is top surface of stock, X/Y origin is center of ring + +import math +import sys + +def mm2inch(mm): + return mm/25.4 + +def polar2xy(radius, degrees = None, radians = None): + if degrees is not None: + radians = degrees / 180.0 * math.pi + x = radius * math.cos(radians) + y = radius * math.sin(radians) + return x,y + +class Gcode(object): + def __init__(self, + free, cutter, speed = 8, + output = sys.stdout): + self.Zfree = free + self.Zdepth = 0.0 + self.Speed = speed + self.CutterOD = cutter + self.output = output + + self.write("%") + self.write("G17 G20 G90") + self.write("M3 S5000") + + self.origin() + + def comment(self, comment): + self.output.write("\n(%s)\n" % (comment)) + + def close(self): + self.write("M5 M2") + self.write("%") + self.output.close() + + def write(self, gcode): + self.output.write(gcode + "\n") + + def plunge(self): + self.write("(plunge)") + self.write("G01 Z %.4f F%d" % (-self.Zdepth, int(self.Speed/2))) + + def retract(self): + self.write("(retract)") + self.write("G00 Z %.4f" % (self.Zfree)) + + def origin(self): + self.retract() + self.write("(origin)") + self.write("G00 X0 Y0") + + def hole(self, x, y, depth, increment, speed): + self.write("G00 X %6.4f Y %6.4f" % (x, y)) + self.write("G83 Z %6.4f R %.4f Q %6.4f F %d" % (-depth, self.Zfree, increment, speed)) + + def circle(self, diameter, x=0, y=0): + radius = diameter/2.0 + self.write("G00 X %6.4f Y %6.4f" % (x, y + radius)) + self.plunge() + self.write("G02 X %6.4f Y %6.4f I %6.4f J %6.4f F%d" % ( + x, y - radius, 0, -radius, self.Speed)) + self.write("G02 X %6.4f Y %6.4f I %6.4f J %6.4f F%d" % ( + x, y + radius, 0, +radius, self.Speed)) + self.retract() + + def slot(self, startX, startY, stopX, stopY, width, depth, increment): + deltaX = stopX - startX + deltaY = stopY - startY + length = (deltaX**2 + deltaY**2)**0.5 + offX = -deltaY / length # unit vector, 90 degrees to slot + offY = deltaX / length + + width += 0.0 + if increment > depth: + self.Zdepth = depth + else: + self.Zdepth = increment + + while self.Zdepth <= depth: + if width < self.CutterOD: + self.comment("***desired slot width smaller than cutter***") + runs = 1 + step = 0 + elif width == self.CutterOD: + runs = 1 + step = 0 + else: + runs = int(math.ceil((width)/self.CutterOD)) + beginX = startX + offX * (width-self.CutterOD)/2 + beginY = startY + offY * (width-self.CutterOD)/2 + endX = stopX + offX * (width-self.CutterOD)/2 + endY = stopY + offY * (width-self.CutterOD)/2 + step = (width-self.CutterOD)/(runs-1) + + self.write("G00 X%6.4f Y%6.4f" % (beginX, beginY)) + + self.plunge() + for n in range(runs-1): + self.write("G01 X%6.4f Y%6.4f F%d" % (endX, endY, self.Speed)) + beginX, endX = endX - offX * step, beginX - offX * step + beginY, endY = endY - offY * step, beginY - offY * step + self.write("G01 X%6.4f Y%6.4f F%d" % (beginX, beginY, self.Speed)) + + self.write("G01 X%6.4f Y%6.4f F%d" % (endX, endY, self.Speed)) + + self.retract() + + if self.Zdepth == depth: + break + self.Zdepth += increment + if self.Zdepth > depth: + self.Zdepth = depth + + + def fin_slots(self, FinCount, innerD, outerD, width, depth, increment = 0.1, rotate = 0): + for fin in range(FinCount): + self.comment("fin slot %d" % (fin)) + + FinDegrees = 90 + rotate + 360.0 / FinCount * fin + while FinDegrees > 360: FinDegrees -= 360 + # angle from origin (on y-axis) + + FinSlotInX, FinSlotInY = polar2xy((innerD/2.0)-self.CutterOD, + degrees=FinDegrees) + FinSlotOutX, FinSlotOutY = polar2xy((outerD/2.0)+self.CutterOD, + degrees=FinDegrees) + + self.slot(FinSlotInX, FinSlotInY, FinSlotOutX, FinSlotOutY, width, depth, increment) + + def ring_cluster(self, count, diam, sep = 1.0, rotation = 0, dist = None): + base_dist = diam/2.0 / math.sin(math.pi/count) + if (dist is not None): + sep = dist / base_dist + + for cluster in range(count): + self.comment("cluster MMT hole %d" % (cluster)) + + degrees = rotation + cluster*360.0/count + while degrees > 360: degrees -= 360 + + ClusX, ClusY = polar2xy(base_dist * sep, degrees=degrees) + self.circle(diam - self.CutterOD, x=ClusX, y=ClusY) + + def aeropack(self, count, hole_radius, rotation, depth, increment, speed): + for h in range(count): + self.comment("Aeropack screw hole %d" % (h)) + + degrees = rotation + h*360.0/count + while degrees > 360: degrees -= 360 + + HoleX, HoleY = polar2xy(hole_radius, degrees=degrees) + self.hole(x=HoleX, y=HoleY, depth=depth, increment=increment, speed=speed) + + def aeropack_54mm(self, rotation = 15, depth = 0.125, increment = 0.125, speed = 25): + self.aeropack(12, mm2inch(46), rotation, depth, increment, speed) + + def aeropack_75mm(self, rotation = 15, depth = 0.125, increment = 0.125, speed = 25): + self.aeropack(12, mm2inch(46), rotation, depth, increment, speed) + + def aeropack_98mm(self, rotation = 15, depth = 0.125, increment = 0.125, speed = 25): + self.aeropack(12, mm2inch(46), rotation, depth, increment, speed) + + + def dsub(self, x, y, rotation = 0): + # 9pin dsub female + # 1mm deep frame, 30mm long by 12mm wide + + old_depth = self.Zdepth + self.Zdepth = mm2inch(1) + dX, dY = polar2xy(mm2inch(15), degrees = rotation) + self.slot(x-dX, y-dY, x+dX, y+dY, mm2inch(12)) + + # need approx 1cm of depth for connector + room for wires + # so that's basically all the way through... + # connector is barely 1mm (maybe 0.5mm?) on sides + # connector is 6mm from either edge on longer side + # connector is 8mm from either edge on shorter side + + self.Zdepth = old_depth + dX, dY = polar2xy(mm2inch(9), degrees = rotation) + self.slot(x-dX, y-dY, x+dX, y+dY, mm2inch(10)) + |