Involute gear script extended for internal gears
This commit is contained in:
parent
6b5b1a7443
commit
420e71afbb
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
|
@ -46,7 +46,7 @@ def makeInvoluteGear(name):
|
|||
class _CommandInvoluteGear:
|
||||
"the Fem InvoluteGear command definition"
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'PartDesign_InvoluteGear',
|
||||
return {'Pixmap' : 'PartDesign_InternalExternalGear',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PartDesign_InvoluteGear","Involute gear..."),
|
||||
'Accel': "",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PartDesign_InvoluteGear","Creates or edit the involute gear definition.")}
|
||||
|
@ -72,12 +72,14 @@ class _InvoluteGear:
|
|||
obj.addProperty("App::PropertyInteger","NumberOfTeeth","Gear","Number of gear teeth")
|
||||
obj.addProperty("App::PropertyLength","Modules","Gear","Modules of the gear")
|
||||
obj.addProperty("App::PropertyAngle","PressureAngle","Gear","Pressure angle of gear teeth")
|
||||
obj.addProperty("App::PropertyInteger","NumberOfCurves","Gear","0=2x3 1=1x4 ")
|
||||
obj.addProperty("App::PropertyBool","HighPrecision","Gear","True=2 curves with each 3 control points False=1 curve with 4 control points ")
|
||||
obj.addProperty("App::PropertyBool","ExternalGear","Gear","True=external Gear False=internal Gear ")
|
||||
|
||||
obj.NumberOfTeeth = 26
|
||||
obj.Modules = "2.5 mm"
|
||||
obj.PressureAngle = "20 deg"
|
||||
obj.NumberOfCurves = 0
|
||||
obj.HighPrecision = True
|
||||
obj.ExternalGear = True
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
|
@ -85,7 +87,10 @@ class _InvoluteGear:
|
|||
def execute(self,obj):
|
||||
#print "_InvoluteGear.execute()"
|
||||
w = fcgear.FCWireBuilder()
|
||||
involute.CreateExternalGear(w, obj.Modules.Value,obj.NumberOfTeeth, obj.PressureAngle.Value, obj.NumberOfCurves == 0)
|
||||
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)
|
||||
gearw = Part.Wire([o.toShape() for o in w.wire])
|
||||
obj.Shape = gearw
|
||||
return
|
||||
|
@ -129,22 +134,36 @@ class _InvoluteGearTaskPanel:
|
|||
self.obj = obj
|
||||
|
||||
self.form=FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/PartDesign/InvoluteGearFeature.ui")
|
||||
|
||||
|
||||
QtCore.QObject.connect(self.form.Quantity_Modules, QtCore.SIGNAL("valueChanged(double)"), self.modulesChanged)
|
||||
QtCore.QObject.connect(self.form.Quantity_PressureAngle, QtCore.SIGNAL("valueChanged(double)"), self.angleChanged)
|
||||
QtCore.QObject.connect(self.form.spinBox_NumberOfTeeth, QtCore.SIGNAL("valueChanged(int)"), self.numTeethChanged)
|
||||
QtCore.QObject.connect(self.form.comboBox_HighPrecision, QtCore.SIGNAL("currentIndexChanged(int)"), self.numCurvesChanged)
|
||||
#QtCore.QObject.connect(self.form.comboBox_ExternalGear, QtCore.SIGNAL("activated(QString)"), self.externalGearChanged)
|
||||
#QtCore.QObject.connect(self.form.comboBox_ExternalGear, QtCore.SIGNAL("currentIndexChanged(int)"), self.externalGearChanged)
|
||||
QtCore.QObject.connect(self.form.comboBox_ExternalGear, QtCore.SIGNAL("currentIndexChanged(int)"), self.externalGearChanged)
|
||||
|
||||
self.update()
|
||||
|
||||
if mode == 0: # fresh created
|
||||
self.obj.Proxy.execute(self.obj) # calculate once
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def transferTo(self):
|
||||
"Transfer from the dialog to the object"
|
||||
self.obj.NumberOfTeeth = self.form.spinBox_NumberOfTeeth.value()
|
||||
self.obj.Modules = self.form.Quantity_Modules.text()
|
||||
self.obj.PressureAngle = self.form.Quantity_PressureAngle.text()
|
||||
self.obj.NumberOfCurves = self.form.comboBox_NumberOfCurves.currentIndex()
|
||||
if self.form.comboBox_HighPrecision.currentIndex() == 0:
|
||||
self.obj.HighPrecision = True
|
||||
else:
|
||||
self.obj.HighPrecision = False
|
||||
#self.obj.HighPrecision = self.form.comboBox_HighPrecision.currentIndex()
|
||||
if self.form.comboBox_ExternalGear.currentIndex() == 0:
|
||||
self.obj.ExternalGear = True
|
||||
else:
|
||||
self.obj.ExternalGear = False
|
||||
#self.obj.ExternalGear = self.form.comboBox_ExternalGear.currentIndex()
|
||||
|
||||
|
||||
def transferFrom(self):
|
||||
|
@ -152,12 +171,22 @@ class _InvoluteGearTaskPanel:
|
|||
self.form.spinBox_NumberOfTeeth.setValue(self.obj.NumberOfTeeth)
|
||||
self.form.Quantity_Modules.setText(self.obj.Modules.UserString)
|
||||
self.form.Quantity_PressureAngle.setText(self.obj.PressureAngle.UserString)
|
||||
self.form.comboBox_NumberOfCurves.setCurrentIndex(self.obj.NumberOfCurves)
|
||||
if self.obj.HighPrecision:
|
||||
self.form.comboBox_HighPrecision.setCurrentIndex(0)
|
||||
else:
|
||||
self.form.comboBox_HighPrecision.setCurrentIndex(1)
|
||||
#self.form.comboBox_HighPrecision.setCurrentIndex(self.obj.HighPrecision)
|
||||
if self.obj.ExternalGear:
|
||||
self.form.comboBox_ExternalGear.setCurrentIndex(0)
|
||||
else:
|
||||
self.form.comboBox_ExternalGear.setCurrentIndex(1)
|
||||
#self.form.comboBox_ExternalGear.setCurrentIndex(self.obj.ExternalGear)
|
||||
|
||||
def modulesChanged(self, value):
|
||||
#print value
|
||||
self.obj.Modules = value
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def angleChanged(self, value):
|
||||
#print value
|
||||
|
@ -168,6 +197,25 @@ class _InvoluteGearTaskPanel:
|
|||
#print value
|
||||
self.obj.NumberOfTeeth = value
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def numCurvesChanged(self, value):
|
||||
#print value
|
||||
if value == 0:
|
||||
v=True
|
||||
else:
|
||||
v=False
|
||||
self.obj.HighPrecision = v
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def externalGearChanged(self, value):
|
||||
#print value
|
||||
if value == 0:
|
||||
v=True
|
||||
else:
|
||||
v=False
|
||||
self.obj.ExternalGear = v
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Cancel)| int(QtGui.QDialogButtonBox.Apply)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>195</width>
|
||||
<height>116</height>
|
||||
<height>136</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -122,26 +122,53 @@
|
|||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Number of Curves:</string>
|
||||
<string>High Precision:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="comboBox_NumberOfCurves">
|
||||
<widget class="QComboBox" name="comboBox_HighPrecision">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2x3</string>
|
||||
<string>True</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1x4</string>
|
||||
<string>False</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>external Gear:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="comboBox_ExternalGear">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>True</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>False</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
|
|
@ -124,6 +124,115 @@ def CreateExternalGear(w, m, Z, phi, split=True):
|
|||
w.close()
|
||||
return w
|
||||
|
||||
def CreateInternalGear(w, m, Z, phi, split=True):
|
||||
"""
|
||||
Create an internal gear
|
||||
|
||||
w is wirebuilder object (in which the gear will be constructed)
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
# ****** calculate angles (all in radians)
|
||||
pitchAngle = 2 * pi / Z # angle subtended by whole tooth (rads)
|
||||
baseToPitchAngle = genInvolutePolar(Rb, Rpitch)
|
||||
tipToPitchAngle = baseToPitchAngle
|
||||
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
|
||||
|
||||
# ****** generate Higuchi involute approximation
|
||||
fe = 1 # fraction of profile length at end of approx
|
||||
fs = 0.01 # fraction of length offset from base to avoid singularity
|
||||
if (Ra > Rb):
|
||||
fs = (Ra**2 - Rb**2) / (Rf**2 - Rb**2) # offset start to top of fillet
|
||||
|
||||
if split:
|
||||
# approximate in 2 sections, split 25% along the involute
|
||||
fm = fs + (fe - fs) / 4 # fraction of length at junction (25% along profile)
|
||||
addInv = BezCoeffs(m, Z, phi, 3, fs, fm)
|
||||
dedInv = BezCoeffs(m, Z, phi, 3, fm, fe)
|
||||
|
||||
# join the 2 sets of coeffs (skip duplicate mid point)
|
||||
invR = addInv + dedInv[1:]
|
||||
else:
|
||||
invR = BezCoeffs(m, Z, phi, 4, fs, fe)
|
||||
|
||||
# create the back profile of tooth (mirror image)
|
||||
inv = []
|
||||
for i, pt in enumerate(invR):
|
||||
# rotate involute to put center of tooth at y = 0
|
||||
ptx, pty = invR[i] = rotate(pt, pitchAngle / 4 - baseToPitchAngle)
|
||||
# generate the back of tooth profile nodes, flip Y coords
|
||||
inv.append((ptx, -pty))
|
||||
|
||||
# ****** calculate section junction points R=back of tooth, Next=front of next tooth)
|
||||
#fillet = inv[6] # top of fillet, front of tooth #toCartesian(Rf, -pitchAngle / 4 - pitchToFilletAngle) # top of fillet
|
||||
fillet = [ptx,-pty]
|
||||
tip = toCartesian(Ra, -pitchAngle/4+tipToPitchAngle) # tip, front of tooth
|
||||
tipR = [ tip[0], -tip[1] ]
|
||||
#filletR = [fillet[0], -fillet[1]] # flip to make same point on back of tooth
|
||||
rootR = toCartesian(Rroot, pitchAngle / 4 + pitchToFilletAngle + filletAngle)
|
||||
rootNext = toCartesian(Rroot, 3 * pitchAngle / 4 - pitchToFilletAngle - filletAngle)
|
||||
filletNext = rotate(fillet, pitchAngle) # top of fillet, front of next tooth
|
||||
|
||||
# Build the shapes using FreeCAD.Part
|
||||
t_inc = 2.0 * pi / float(Z)
|
||||
thetas = [(x * t_inc) for x in range(Z)]
|
||||
|
||||
w.move(fillet) # start at top of front profile
|
||||
|
||||
|
||||
for theta in thetas:
|
||||
w.theta = theta
|
||||
if split:
|
||||
w.curve(inv[5], inv[4], inv[3])
|
||||
w.curve(inv[2], inv[1], inv[0])
|
||||
else:
|
||||
w.curve(*inv[-2::-1])
|
||||
|
||||
if (Ra < Rb):
|
||||
w.line(tip) # line from fillet up to base circle
|
||||
|
||||
if split:
|
||||
w.arc(tipR, Ra, 0) # arc across addendum circle
|
||||
else:
|
||||
#w.arc(tipR[-1], Ra, 0) # arc across addendum circle
|
||||
w.arc(tipR, Ra, 0)
|
||||
|
||||
if (Ra < Rb):
|
||||
w.line(invR[0]) # line down to topof fillet
|
||||
|
||||
if split:
|
||||
w.curve(invR[1], invR[2], invR[3])
|
||||
w.curve(invR[4], invR[5], invR[6])
|
||||
else:
|
||||
w.curve(*invR[1:])
|
||||
|
||||
if (rootNext[1] > rootR[1]): # is there a section of root circle between fillets?
|
||||
w.arc(rootR, fRad, 1) # back fillet
|
||||
w.arc(rootNext, Rroot, 0) # root circle arc
|
||||
|
||||
w.arc(filletNext, fRad, 1)
|
||||
|
||||
|
||||
w.close()
|
||||
return w
|
||||
|
||||
|
||||
def genInvolutePolar(Rb, R):
|
||||
|
|
Loading…
Reference in New Issue
Block a user