summaryrefslogtreecommitdiff
path: root/gcode
diff options
context:
space:
mode:
authorMike Beattie <mike@ethernal.org>2013-08-30 03:36:35 +1200
committerMike Beattie <mike@ethernal.org>2013-08-30 03:36:35 +1200
commit4d8d3ce82a05316912088ceec144c5b557a4b5cb (patch)
tree3dc8a09fe1fa6495bcd4f47087c39e8f518d8e37 /gcode
parentd7f66ca9c6e643d4fcad1602681fa13bb7bc2028 (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/.gitignore2
-rwxr-xr-xgcode/rings.py200
-rw-r--r--gcode/rocket_gcode.py193
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))
+