PD: Make involute gear's root fillet radius configurable
The original implementation always took 150% of the addendum/dedendum difference as fillet radius. For a standard full-depth system this results in a normalized value 0f 0.375, which is pretty close to the 0.38 definded by the basic ISO rack. However, when using much shorter teeth as e.g. required for a splined shaft, the fillet becomes way too large. In addition, I don't understand the approximation to calculate the distance between the gear's center and the top of the fillet yet. It was only refactored to allow the custom fillet radii, but it retuns the same values as the original implementation. However, with high pressure angles, up to 45° used for splines, this approximation comes to its limits.
This commit is contained in:
@@ -76,14 +76,14 @@ class _InvoluteGear:
|
||||
"The InvoluteGear object"
|
||||
def __init__(self,obj):
|
||||
self.Type = "InvoluteGear"
|
||||
self._ensure_properties(obj)
|
||||
self._ensure_properties(obj, is_restore=False)
|
||||
obj.Proxy = self
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
"""hook used to migrate older versions of this object"""
|
||||
self._ensure_properties(obj)
|
||||
self._ensure_properties(obj, is_restore=True)
|
||||
|
||||
def _ensure_properties(self, obj):
|
||||
def _ensure_properties(self, obj, is_restore):
|
||||
def ensure_property(type_, name, doc, default):
|
||||
if not hasattr(obj, name):
|
||||
obj.addProperty(type_, name, "Gear", doc)
|
||||
@@ -113,12 +113,16 @@ class _InvoluteGear:
|
||||
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)
|
||||
ensure_property("App::PropertyFloat","RootFilletCoefficient",
|
||||
doc="The radius of the fillet at the root of the tooth, normalized by the module.",
|
||||
default=lambda: 0.375 if is_restore else 0.38)
|
||||
|
||||
def execute(self,obj):
|
||||
w = fcgear.FCWireBuilder()
|
||||
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)
|
||||
split=obj.HighPrecision, addCoeff=obj.AddendumCoefficient, dedCoeff=obj.DedendumCoefficient,
|
||||
filletCoeff=obj.RootFilletCoefficient)
|
||||
gearw = Part.Wire([o.toShape() for o in w.wire])
|
||||
obj.Shape = gearw
|
||||
obj.positionBySupport();
|
||||
|
||||
@@ -92,6 +92,7 @@ class TestInvoluteGear(unittest.TestCase):
|
||||
spline.PressureAngle = '30 deg'
|
||||
spline.AddendumCoefficient = add_coef
|
||||
spline.DedendumCoefficient = ded_coef
|
||||
spline.RootFilletCoefficient = 0.4
|
||||
self.assertSuccessfulRecompute(spline)
|
||||
self.assertClosedWire(spline.Shape)
|
||||
pitch_diameter = m * z
|
||||
@@ -116,6 +117,7 @@ class TestInvoluteGear(unittest.TestCase):
|
||||
hub.PressureAngle = '30 deg'
|
||||
hub.AddendumCoefficient = add_coef
|
||||
hub.DedendumCoefficient = ded_coef
|
||||
hub.RootFilletCoefficient = 0.4
|
||||
self.assertSuccessfulRecompute(hub)
|
||||
self.assertClosedWire(hub.Shape)
|
||||
pitch_diameter = m * z
|
||||
|
||||
@@ -27,7 +27,10 @@ from math import cos, sin, pi, acos, atan, sqrt
|
||||
xrange = range
|
||||
|
||||
|
||||
def CreateExternalGear(w, m, Z, phi, split=True, addCoeff=1.0, dedCoeff=1.25):
|
||||
def CreateExternalGear(w, m, Z, phi,
|
||||
split=True,
|
||||
addCoeff=1.0, dedCoeff=1.25,
|
||||
filletCoeff=0.375):
|
||||
"""
|
||||
Create an external gear
|
||||
|
||||
@@ -37,6 +40,9 @@ def CreateExternalGear(w, m, Z, phi, split=True, addCoeff=1.0, dedCoeff=1.25):
|
||||
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)
|
||||
filletCoeff is the root fillet radius, normalized by the module.
|
||||
The default of 0.375 matches the hard-coded value (1.5 * 0.25) of the implementation
|
||||
up to v0.20. The ISO Rack specified 0.38, though.
|
||||
|
||||
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
|
||||
@@ -45,18 +51,16 @@ def CreateExternalGear(w, m, Z, phi, split=True, addCoeff=1.0, dedCoeff=1.25):
|
||||
# ****** external gear specifications
|
||||
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
|
||||
Rb = Rpitch*cos(phi * pi / 180) # base circle radius
|
||||
Ra = Rpitch + addendum # tip (addendum) circle radius
|
||||
Rroot = Rpitch - dedendum # root circle radius
|
||||
fRad = 1.5 * clearance # fillet radius, max 1.5*clearance
|
||||
fRad = filletCoeff * m # fillet radius, max 1.5*clearance
|
||||
Rf = sqrt((Rroot + fRad)**2 - fRad**2) # radius at top of fillet
|
||||
if (Rb < Rf):
|
||||
Rf = Rroot + clearance
|
||||
Rf = Rroot + fRad/1.5 # fRad/1.5=clerance, with crearance=0.25*m
|
||||
|
||||
# ****** calculate angles (all in radians)
|
||||
pitchAngle = 2 * pi / Z # angle subtended by whole tooth (rads)
|
||||
@@ -133,7 +137,10 @@ def CreateExternalGear(w, m, Z, phi, split=True, addCoeff=1.0, dedCoeff=1.25):
|
||||
w.close()
|
||||
return w
|
||||
|
||||
def CreateInternalGear(w, m, Z, phi, split=True, addCoeff=0.6, dedCoeff=1.25):
|
||||
def CreateInternalGear(w, m, Z, phi,
|
||||
split=True,
|
||||
addCoeff=0.6, dedCoeff=1.25,
|
||||
filletCoeff=0.375):
|
||||
"""
|
||||
Create an internal gear
|
||||
|
||||
@@ -149,6 +156,9 @@ def CreateInternalGear(w, m, Z, phi, split=True, addCoeff=0.6, dedCoeff=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)
|
||||
filletCoeff is the root fillet radius, normalized by the module.
|
||||
The default of 0.375 matches the hard-coded value (1.5 * 0.25) of the implementation
|
||||
up to v0.20. The ISO Rack specified 0.38, though.
|
||||
|
||||
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
|
||||
@@ -157,15 +167,16 @@ def CreateInternalGear(w, m, Z, phi, split=True, addCoeff=0.6, dedCoeff=1.25):
|
||||
# ****** external gear specifications
|
||||
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
|
||||
Rb = Rpitch*cos(phi * pi / 180) # base circle radius
|
||||
Ra = Rpitch - addendum # tip (addendum) circle radius
|
||||
Rroot = Rpitch + dedendum # root circle radius
|
||||
fRad = 1.5 * clearance # fillet radius, max 1.5*clearance
|
||||
Rf = Rroot - clearance # radius at top of fillet (end of profile)
|
||||
fRad = filletCoeff * m # fillet radius, max 1.5*clearance
|
||||
Rf = Rroot - fRad/1.5 # radius at top of fillet (end of profile)
|
||||
# No idea where this formula for Rf comes from.
|
||||
# Just kept it to generate identical curves as the v0.20
|
||||
|
||||
# ****** calculate angles (all in radians)
|
||||
pitchAngle = 2 * pi / Z # angle subtended by whole tooth (rads)
|
||||
@@ -174,7 +185,11 @@ def CreateInternalGear(w, m, Z, phi, split=True, addCoeff=0.6, dedCoeff=1.25):
|
||||
if (Ra > Rb): # start profile at top of fillet (if its greater)
|
||||
tipToPitchAngle -= genInvolutePolar(Rb, Ra)
|
||||
pitchToFilletAngle = genInvolutePolar(Rb, Rf) - baseToPitchAngle;
|
||||
filletAngle = 1.414*clearance/Rf # // to make fillet tangential to root
|
||||
filletAngle = 1.414*(fRad/1.5)/Rf # to make fillet tangential to root
|
||||
# TODO: This and/or the Rf calculation doesn't seem quite
|
||||
# correct. Keep it for compat, though. In the future, may
|
||||
# use the special filletCoeff of 0.375 as marker to switch
|
||||
# between "compat" or "correct/truly tangential"
|
||||
|
||||
# ****** generate Higuchi involute approximation
|
||||
fe = 1 # fraction of profile length at end of approx
|
||||
|
||||
Reference in New Issue
Block a user