PD: Make the involute gear's toogh length configurable
Exposing the addednum and dedendum coefficients as properties allows to change the tooth length above and below the pitch circle. This makes it possible to use the profile beyond standard full-depth systems, e.g. for stub tooths and most importantly: involute splined shafts and hubs. Gear objets created with earlier versions automatically get the additional properties on document restore. Its values match the hard- coded values used in earlier versions. There is a change when creating *new* internal gear profiles, though: Previously, an addendum coefficient of 0.6 was used, presumably to reduce the tip length beyond the base circle in order to avoid a non-involute edge. This method is one proposal from the "Handbook of Gear Design" by Gitin M. Maitra, as referenced in the original source code comments. However, Maitra also states that this reduction of the anual gear's tip in turn requires an enlagement of the mating gear of 1.25 instead of the ordinary 1.0. And it is only required for a low numer of teeth and/or the mating gear being quite large (less than 10 teeth in difference, to avoid interferences). Because those additional requirements and conditions have not been implemented, the previously used values have been incomplete anyway. Thus I decided to not implemented this special case and use the standard values of 1.0/1.25 for newly created external and internal gears alike. Internal gears need special care for other kind of interference anyway and the newly exposed properties now allow to do so. There is no entry in the task panel for those advanced properties yet.
This commit is contained in:
@@ -87,7 +87,10 @@ class _InvoluteGear:
|
||||
def ensure_property(type_, name, doc, default):
|
||||
if not hasattr(obj, name):
|
||||
obj.addProperty(type_, name, "Gear", doc)
|
||||
setattr(obj, name, default)
|
||||
if callable(default):
|
||||
setattr(obj, name, default())
|
||||
else:
|
||||
setattr(obj, name, default)
|
||||
|
||||
ensure_property("App::PropertyInteger", "NumberOfTeeth",
|
||||
doc="Number of gear teeth",
|
||||
@@ -104,14 +107,18 @@ class _InvoluteGear:
|
||||
ensure_property("App::PropertyBool", "ExternalGear",
|
||||
doc="True=external Gear False=internal Gear",
|
||||
default=True)
|
||||
ensure_property("App::PropertyFloat", "AddendumCoefficient",
|
||||
doc="The height of the tooth from the pitch circle up to its tip, normalized by the module.",
|
||||
default=lambda: 1.0 if obj.ExternalGear else 0.6)
|
||||
ensure_property("App::PropertyFloat","DedendumCoefficient",
|
||||
doc="The height of the tooth from the pitch circle down to its root, normalized by the module.",
|
||||
default=1.25)
|
||||
|
||||
def execute(self,obj):
|
||||
#print "_InvoluteGear.execute()"
|
||||
w = fcgear.FCWireBuilder()
|
||||
if obj.ExternalGear:
|
||||
involute.CreateExternalGear(w, obj.Modules.Value,obj.NumberOfTeeth, obj.PressureAngle.Value, obj.HighPrecision)
|
||||
else:
|
||||
involute.CreateInternalGear(w, obj.Modules.Value,obj.NumberOfTeeth, obj.PressureAngle.Value, obj.HighPrecision)
|
||||
generator_func = involute.CreateExternalGear if obj.ExternalGear else involute.CreateInternalGear
|
||||
generator_func(w, obj.Modules.Value, obj.NumberOfTeeth, obj.PressureAngle.Value,
|
||||
split=obj.HighPrecision, addCoeff=obj.AddendumCoefficient, dedCoeff=obj.DedendumCoefficient)
|
||||
gearw = Part.Wire([o.toShape() for o in w.wire])
|
||||
obj.Shape = gearw
|
||||
obj.positionBySupport();
|
||||
|
||||
@@ -81,6 +81,53 @@ class TestInvoluteGear(unittest.TestCase):
|
||||
self.assertNoIntersection(gear.Shape, makeCircle(tip_diameter/2 + delta), "Teeth extent beyond tip circle")
|
||||
self.assertNoIntersection(gear.Shape, makeCircle(root_diameter/2 - delta), "Teeth extend below root circle")
|
||||
|
||||
def testCustomizedGearProfileForSplinedShaft(self):
|
||||
spline = InvoluteGearFeature.makeInvoluteGear('InvoluteSplinedShaft')
|
||||
z = 12
|
||||
m = 2
|
||||
add_coef = 0.5
|
||||
ded_coef = 0.9
|
||||
spline.NumberOfTeeth = z
|
||||
spline.Modules = f'{m} mm'
|
||||
spline.PressureAngle = '30 deg'
|
||||
spline.AddendumCoefficient = add_coef
|
||||
spline.DedendumCoefficient = ded_coef
|
||||
self.assertSuccessfulRecompute(spline)
|
||||
self.assertClosedWire(spline.Shape)
|
||||
pitch_diameter = m * z
|
||||
tip_diameter = pitch_diameter + 2 * add_coef * m
|
||||
root_diameter = pitch_diameter - 2 * ded_coef * m
|
||||
# the test purpose here is just to ensure the gear's parameters are used,
|
||||
# not super precise profile verification. Thus a lax delta is just file here.
|
||||
delta = 0.01
|
||||
self.assertIntersection(spline.Shape, makeCircle(pitch_diameter/2), "Expecting intersection at pitch circle")
|
||||
self.assertNoIntersection(spline.Shape, makeCircle(tip_diameter/2 + delta), "Teeth extent beyond tip circle")
|
||||
self.assertNoIntersection(spline.Shape, makeCircle(root_diameter/2 - delta), "Teeth extend below root circle")
|
||||
|
||||
def testCustomizedGearProfileForSplinedHub(self):
|
||||
hub = InvoluteGearFeature.makeInvoluteGear('InvoluteSplinedHub')
|
||||
hub.ExternalGear = False
|
||||
z = 12
|
||||
m = 2
|
||||
add_coef = 0.5
|
||||
ded_coef = 0.9
|
||||
hub.NumberOfTeeth = z
|
||||
hub.Modules = f'{m} mm'
|
||||
hub.PressureAngle = '30 deg'
|
||||
hub.AddendumCoefficient = add_coef
|
||||
hub.DedendumCoefficient = ded_coef
|
||||
self.assertSuccessfulRecompute(hub)
|
||||
self.assertClosedWire(hub.Shape)
|
||||
pitch_diameter = m * z
|
||||
tip_diameter = pitch_diameter - 2 * add_coef * m
|
||||
root_diameter = pitch_diameter + 2 * ded_coef * m
|
||||
# the test purpose here is just to ensure the gear's parameters are used,
|
||||
# not super precise profile verification. Thus a lax delta is just file here.
|
||||
delta = 0.1 # FIXME it seems that the top land arc is in the wrong direction, thus a larger tolerance.
|
||||
self.assertIntersection(hub.Shape, makeCircle(pitch_diameter/2), "Expecting intersection at pitch circle")
|
||||
self.assertNoIntersection(hub.Shape, makeCircle(tip_diameter/2 - delta), "Teeth extent below tip circle")
|
||||
self.assertNoIntersection(hub.Shape, makeCircle(root_diameter/2 + delta), "Teeth extend beyond root circle")
|
||||
|
||||
def testUsagePadGearProfile(self):
|
||||
profile = InvoluteGearFeature.makeInvoluteGear('GearProfile')
|
||||
body = self.Doc.addObject('PartDesign::Body','GearBody')
|
||||
|
||||
@@ -27,20 +27,26 @@ from math import cos, sin, pi, acos, atan, sqrt
|
||||
xrange = range
|
||||
|
||||
|
||||
def CreateExternalGear(w, m, Z, phi, split=True):
|
||||
def CreateExternalGear(w, m, Z, phi, split=True, addCoeff=1.0, dedCoeff=1.25):
|
||||
"""
|
||||
Create an external gear
|
||||
|
||||
w is wirebuilder object (in which the gear will be constructed)
|
||||
m is the gear's module (pitch diameter divided by the number of teeth)
|
||||
Z is the number of teeth
|
||||
phi is the gear's pressure angle
|
||||
addCoeff is the addendum coefficient (addendum normalized by module)
|
||||
dedCoeff is the dedendum coefficient (dedendum normalized by module)
|
||||
|
||||
if split is True, each profile of a teeth will consist in 2 Bezier
|
||||
curves of degree 3, otherwise it will be made of one Bezier curve
|
||||
of degree 4
|
||||
"""
|
||||
# ****** external gear specifications
|
||||
addendum = m # distance from pitch circle to tip circle
|
||||
dedendum = 1.25 * m # pitch circle to root, sets clearance
|
||||
clearance = dedendum - addendum
|
||||
addendum = addCoeff * m # distance from pitch circle to tip circle
|
||||
dedendum = dedCoeff * m # pitch circle to root, sets clearance
|
||||
clearance = dedendum - addendum # strictily speaking, for the clearence the addendum of the
|
||||
# *mating* gear is required. Let's assume them identical.
|
||||
|
||||
# Calculate radii
|
||||
Rpitch = Z * m / 2 # pitch circle radius
|
||||
@@ -127,20 +133,31 @@ def CreateExternalGear(w, m, Z, phi, split=True):
|
||||
w.close()
|
||||
return w
|
||||
|
||||
def CreateInternalGear(w, m, Z, phi, split=True):
|
||||
def CreateInternalGear(w, m, Z, phi, split=True, addCoeff=0.6, dedCoeff=1.25):
|
||||
"""
|
||||
Create an internal gear
|
||||
|
||||
w is wirebuilder object (in which the gear will be constructed)
|
||||
m is the gear's module (pitch diameter divided by the number of teeth)
|
||||
Z is the number of teeth
|
||||
phi is the gear's pressure angle
|
||||
addCoeff is the addendum coefficient (addendum normalized by module)
|
||||
The default of 0.6 comes from the "Handbook of Gear Design" by Gitin M. Maitra,
|
||||
with the goal to push the addendum circle beyond the base circle to avoid non-involute
|
||||
flanks on the tips.
|
||||
It in turn assumes, however, that the mating pinion usaes a larger value of 1.25.
|
||||
And it's only required for a small number of teeth and/or a relatively large mating gear.
|
||||
Anyways, it's kept here as this was the hard-coded value of the implementation up to v0.20.
|
||||
dedCoeff is the dedendum coefficient (dedendum normalized by module)
|
||||
|
||||
if split is True, each profile of a teeth will consist in 2 Bezier
|
||||
curves of degree 3, otherwise it will be made of one Bezier curve
|
||||
of degree 4
|
||||
"""
|
||||
# ****** external gear specifications
|
||||
addendum = 0.6 * m # distance from pitch circle to tip circle (ref G.M.Maitra)
|
||||
dedendum = 1.25 * m # pitch circle to root, sets clearance
|
||||
clearance = 0.25 * m
|
||||
addendum = addCoeff * m # distance from pitch circle to tip circle
|
||||
dedendum = dedCoeff * m # pitch circle to root, sets clearance
|
||||
clearance = 0.25 * m # this assumes an addendum coefficient of 1 for the mating gear
|
||||
|
||||
# Calculate radii
|
||||
Rpitch = Z * m / 2 # pitch circle radius
|
||||
|
||||
Reference in New Issue
Block a user