diff --git a/boxes/generators/planetary2.py b/boxes/generators/planetary2.py new file mode 100644 index 0000000..5bf9c12 --- /dev/null +++ b/boxes/generators/planetary2.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +# Copyright (C) 2013-2016 Florian Festi +# +# 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 . + +from boxes import * +import math + +class Planetary2(Boxes): + + """Balanced force Difference Planetary Gear""" + + ui_group = "Part" + + def __init__(self): + Boxes.__init__(self) + self.buildArgParser("nema_mount") + self.argparser.add_argument( + "--profile", action="store", type=str, default="GT2_2mm", + choices=pulley.Pulley.getProfiles(), + help="profile of the teeth/belt") + self.argparser.add_argument( + "--sunteeth", action="store", type=int, default=8, + help="number of teeth on sun gear") + self.argparser.add_argument( + "--planetteeth", action="store", type=int, default=20, + help="number of teeth on planets") + self.argparser.add_argument( + "--maxplanets", action="store", type=int, default=0, + help="limit the number of planets (0 for as much as fit)") + self.argparser.add_argument( + "--deltateeth", action="store", type=int, default=1, + help="enable secondary ring with given delta to the ring gear") + self.argparser.add_argument( + "--modulus", action="store", type=float, default=3, + help="modulus of the theeth in mm") + self.argparser.add_argument( + "--shaft", action="store", type=float, default=6., + help="diameter of the shaft") + self.argparser.add_argument( + "--screw1", action="store", type=float, default=2.4, + help="diameter of lower part of the screw hole") + self.argparser.add_argument( + "--screw2", action="store", type=float, default=4., + help="diameter of upper part of the screw hole") + self.argparser.add_argument( + "--pinsize", action="store", type=float, default=3.1, + help="diameter of alignment pins") + # self.argparser.add_argument( + # "--stages", action="store", type=int, default=4, + # help="number of stages in the gear reduction") + + def pins(self, r, rh, nr=0, angle=0.0): + self.moveTo(0, 0, angle) + + if nr < 8: + ang = 20 + 10 * nr + else: + ang = 15 + 10 * (nr-8) + + ang = 180 - ang + for a in (0, ang, -ang): + self.moveTo(0, 0, a) + self.hole(r, 0, rh) + self.moveTo(0, 0, -a) + + + def render(self): + # Initialize canvas + self.open() + + ringteeth = self.sunteeth + 2 * self.planetteeth + t = self.thickness + spoke_width = 4 * t + pinsize = self.pinsize / 2. + + pitch1, size1, xxx = self.gears.sizes(teeth=self.sunteeth, + dimension=self.modulus) + pitch2, size2, xxx = self.gears.sizes(teeth=self.planetteeth, + dimension=self.modulus) + pitch3, size3, xxx = self.gears.sizes( + teeth=ringteeth, internal_ring=True, spoke_width=spoke_width, + dimension=self.modulus) + + planets = int(math.pi / (math.asin(float(self.planetteeth + 2) / (self.planetteeth + self.sunteeth)))) + + if self.maxplanets: + planets = min(self.maxplanets, planets) + + # Make sure the teeth mash + ta = self.sunteeth + ringteeth + # There are sunteeth+ringteeth mashing positions for the planets + planetpositions = [round(i * ta / planets) * 360 / ta for i in range(planets)] + secondary_offsets = [((pos % (360. / (ringteeth - self.deltateeth))) - + (pos % (360. / ringteeth)) * ringteeth / self.planetteeth) + for pos in planetpositions] + + ratio = (1 + (ringteeth / self.sunteeth)) * (-ringteeth/self.deltateeth) + print(planetpositions) + print(secondary_offsets) + print(ratio) + # XXX make configurable? + profile_shift = 20 + pressure_angle = 20 + + screw = self.screw1 / 2 + + # output + # XXX simple guess + belt = self.profile + pulleyteeth = int((size3-2*t) * math.pi / pulley.Pulley.spacing[belt][1]) + numplanets = planets + + deltamodulus = self.modulus * ringteeth / (ringteeth - self.deltateeth) + + def holes(r): + def h(): + self.hole(2*t, 2*t, r) + self.hole(size3-2*t, 2*t, r) + self.hole(2*t, size3-2*t, r) + self.hole(size3-2*t, size3-2*t, r) + return h + + def planets(): + self.moveTo(size3/2, size3/2) + for angle in planetpositions: + angle += 180 # compensate for 3 postion in callback + self.moveTo(0, 0, angle) + self.hole((pitch1+pitch2), 0, size2/2) + self.moveTo(0, 0, -angle) + + self.rectangularWall(size3, size3, callback=[ + lambda: self.NEMA(self.nema_mount, size3 / 2, size3 / 2), + holes(screw), planets], + move="up") + + def gear(): + self.moveTo(size3 / 2, size3 / 2) + self.gears(teeth=ringteeth, dimension=self.modulus, + angle=pressure_angle, internal_ring=True, + spoke_width=spoke_width, teeth_only=True, + profile_shift=profile_shift, move="up") + + self.rectangularWall(size3, size3, callback=[gear, holes(screw)], move="up") + screw = self.screw2 / 2 + self.rectangularWall(size3, size3, callback=[gear, holes(screw)], move="up") + self.rectangularWall(size3, size3, callback=[holes(screw)], move="up") + + self.partsMatrix(4, 4, 'up', self.gears, teeth=self.sunteeth, + dimension=self.modulus, + angle=pressure_angle, mount_hole=self.shaft, + profile_shift=profile_shift) + tl = 0.5*size3*(2**0.5-1)*2**0.5 + self.rectangularTriangle(tl, tl, num=8, callback=[ + None, lambda:self.hole(2*t, 2*t, screw)], move='up') + self.pulley(pulleyteeth, belt, callback= + lambda:self.gears(teeth=ringteeth - self.deltateeth, + dimension=deltamodulus, + angle=pressure_angle, internal_ring=True, + spoke_width=spoke_width, teeth_only=True, + profile_shift=profile_shift), move="up") + + for i in range(numplanets): + self.ctx.save() + for j in range(2): + self.gears(teeth=self.planetteeth, dimension=self.modulus, + angle=pressure_angle, + callback=lambda:self.pins(0.25*size2, pinsize, i), + profile_shift=profile_shift, move="right") + for j in range(2): + self.gears(teeth=self.planetteeth, dimension=self.modulus, + angle=pressure_angle, + callback=lambda:self.pins(0.25*size2, pinsize, i, + secondary_offsets[i]), + profile_shift=profile_shift, move="right") + self.ctx.restore() + + self.gears(teeth=self.planetteeth, dimension=self.modulus, + angle=pressure_angle, + profile_shift=profile_shift, move="up only") + + self.close() + + +def main(): + b = Planetary() + b.parseArgs() + b.render() + + +if __name__ == '__main__': + main()