Skip to content

Commit

Permalink
add root_fillet, head_fillet, backlash to timinggear_t
Browse files Browse the repository at this point in the history
looooo committed Jan 4, 2024
1 parent 80bf5ea commit 17056c1
Showing 5 changed files with 119 additions and 109 deletions.
131 changes: 52 additions & 79 deletions examples/worm_cutting_tool/cutting_tool_worm_assembly.ipynb
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 5,
"id": "7eacf041-aa83-49e2-9cbe-066f177197f6",
"metadata": {},
"outputs": [],
@@ -25,7 +25,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 6,
"id": "980417d0-c79d-4501-a7cc-9725b3bbea83",
"metadata": {},
"outputs": [],
@@ -196,48 +196,48 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 15,
"id": "cfd8026b-5a84-4882-a1de-63580776a579",
"metadata": {},
"outputs": [],
"source": [
"import sympy as sp\n",
"t, x, z = sp.symbols([\"t\", \"x\", \"z\"], real=True)\n",
"t, x, z, m = sp.symbols([\"t\", \"x\", \"z\", \"m\"], real=True)\n",
"s, alpha, n_t, y = sp.symbols([\"s\", \"alpha\", \"n_t\", \"y\"], real=True, positiv=True)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 16,
"id": "65bb90d7-0f5b-410e-9a3a-0f9953a4d846",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(\\frac{n_{t} t}{\\pi} \\right)} & \\sin{\\left(\\frac{n_{t} t}{\\pi} \\right)} & 0 & 0\\\\- \\sin{\\left(\\frac{n_{t} t}{\\pi} \\right)} & \\cos{\\left(\\frac{n_{t} t}{\\pi} \\right)} & 0 & 0\\\\0 & 0 & 1 & n_{t} t\\\\0 & 0 & 0 & 1.0\\end{matrix}\\right]$"
"$\\displaystyle \\left[\\begin{matrix}\\cos{\\left(2 \\pi t \\right)} & \\sin{\\left(2 \\pi t \\right)} & 0 & 0\\\\- \\sin{\\left(2 \\pi t \\right)} & \\cos{\\left(2 \\pi t \\right)} & 0 & 0\\\\0 & 0 & 1 & \\pi m n_{t} t\\\\0 & 0 & 0 & 1.0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[ cos(n_t*t/pi), sin(n_t*t/pi), 0, 0],\n",
"[-sin(n_t*t/pi), cos(n_t*t/pi), 0, 0],\n",
"[ 0, 0, 1, n_t*t],\n",
"[ 0, 0, 0, 1.0]])"
"[ cos(2*pi*t), sin(2*pi*t), 0, 0],\n",
"[-sin(2*pi*t), cos(2*pi*t), 0, 0],\n",
"[ 0, 0, 1, pi*m*n_t*t],\n",
"[ 0, 0, 0, 1.0]])"
]
},
"execution_count": 7,
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T_spiral = symbolic_transformation(t * n_t / sp.pi, np.array([0, 0, 1]), np.array([0, 0, t * n_t]))\n",
"T_spiral = symbolic_transformation(t * 2 * sp.pi, np.array([0, 0, 1]), np.array([0, 0, m * sp.pi * n_t * t ]))\n",
"T_spiral"
]
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 17,
"id": "0f305b8b-0fb5-4b71-80b6-9a2b43b59e26",
"metadata": {},
"outputs": [
@@ -254,7 +254,7 @@
"[ 1]])"
]
},
"execution_count": 22,
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
@@ -266,24 +266,24 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 18,
"id": "da3c8575-99ad-4258-8734-c165ea65b014",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}s \\sin{\\left(\\frac{n_{t} t}{\\pi} \\right)} \\cos{\\left(\\alpha \\right)}\\\\s \\cos{\\left(\\alpha \\right)} \\cos{\\left(\\frac{n_{t} t}{\\pi} \\right)}\\\\n_{t} t + s \\sin{\\left(\\alpha \\right)}\\\\1.0\\end{matrix}\\right]$"
"$\\displaystyle \\left[\\begin{matrix}s \\sin{\\left(2 \\pi t \\right)} \\cos{\\left(\\alpha \\right)}\\\\s \\cos{\\left(\\alpha \\right)} \\cos{\\left(2 \\pi t \\right)}\\\\\\pi m n_{t} t + s \\sin{\\left(\\alpha \\right)}\\\\1.0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[s*sin(n_t*t/pi)*cos(alpha)],\n",
"[s*cos(alpha)*cos(n_t*t/pi)],\n",
"[ n_t*t + s*sin(alpha)],\n",
"[ 1.0]])"
"[ s*sin(2*pi*t)*cos(alpha)],\n",
"[ s*cos(alpha)*cos(2*pi*t)],\n",
"[pi*m*n_t*t + s*sin(alpha)],\n",
"[ 1.0]])"
]
},
"execution_count": 23,
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -295,20 +295,20 @@
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 19,
"id": "e47eb83b-6e89-4246-a82a-bd5629aedc2a",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{\\pi \\operatorname{asin}{\\left(\\frac{x}{s \\cos{\\left(\\alpha \\right)}} \\right)}}{n_{t}}$"
"$\\displaystyle \\frac{\\operatorname{asin}{\\left(\\frac{x}{s \\cos{\\left(\\alpha \\right)}} \\right)}}{2 \\pi}$"
],
"text/plain": [
"pi*asin(x/(s*cos(alpha)))/n_t"
"asin(x/(s*cos(alpha)))/(2*pi)"
]
},
"execution_count": 32,
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
@@ -320,24 +320,24 @@
},
{
"cell_type": "code",
"execution_count": 33,
"execution_count": 20,
"id": "c2954b39-eea0-4e27-987f-07a5d0dedaad",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x\\\\s \\sqrt{1 - \\frac{x^{2}}{s^{2} \\cos^{2}{\\left(\\alpha \\right)}}} \\cos{\\left(\\alpha \\right)}\\\\s \\sin{\\left(\\alpha \\right)} + \\pi \\operatorname{asin}{\\left(\\frac{x}{s \\cos{\\left(\\alpha \\right)}} \\right)}\\\\1.0\\end{matrix}\\right]$"
"$\\displaystyle \\left[\\begin{matrix}x\\\\s \\sqrt{1 - \\frac{x^{2}}{s^{2} \\cos^{2}{\\left(\\alpha \\right)}}} \\cos{\\left(\\alpha \\right)}\\\\\\frac{m n_{t} \\operatorname{asin}{\\left(\\frac{x}{s \\cos{\\left(\\alpha \\right)}} \\right)}}{2} + s \\sin{\\left(\\alpha \\right)}\\\\1.0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[ x],\n",
"[s*sqrt(1 - x**2/(s**2*cos(alpha)**2))*cos(alpha)],\n",
"[ s*sin(alpha) + pi*asin(x/(s*cos(alpha)))],\n",
"[ m*n_t*asin(x/(s*cos(alpha)))/2 + s*sin(alpha)],\n",
"[ 1.0]])"
]
},
"execution_count": 33,
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
@@ -349,7 +349,7 @@
},
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 21,
"id": "268c6302-4e7d-45e0-be28-1b64cf8b766e",
"metadata": {},
"outputs": [
@@ -362,7 +362,7 @@
"sqrt(x**2 + y**2)/cos(alpha)"
]
},
"execution_count": 43,
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
@@ -374,24 +374,24 @@
},
{
"cell_type": "code",
"execution_count": 44,
"execution_count": 22,
"id": "7284bd6a-b47b-483c-8e9f-79fcaecce5e3",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x\\\\\\left|{y}\\right|\\\\\\sqrt{x^{2} + y^{2}} \\tan{\\left(\\alpha \\right)} + \\pi \\operatorname{asin}{\\left(\\frac{x}{\\sqrt{x^{2} + y^{2}}} \\right)}\\\\1.0\\end{matrix}\\right]$"
"$\\displaystyle \\left[\\begin{matrix}x\\\\\\left|{y}\\right|\\\\\\frac{m n_{t} \\operatorname{asin}{\\left(\\frac{x}{\\sqrt{x^{2} + y^{2}}} \\right)}}{2} + \\sqrt{x^{2} + y^{2}} \\tan{\\left(\\alpha \\right)}\\\\1.0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[ x],\n",
"[ Abs(y)],\n",
"[sqrt(x**2 + y**2)*tan(alpha) + pi*asin(x/sqrt(x**2 + y**2))],\n",
"[ 1.0]])"
"[ x],\n",
"[ Abs(y)],\n",
"[m*n_t*asin(x/sqrt(x**2 + y**2))/2 + sqrt(x**2 + y**2)*tan(alpha)],\n",
"[ 1.0]])"
]
},
"execution_count": 44,
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@@ -401,53 +401,26 @@
"spiral_xy"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "82e6880a-7240-44a4-a346-4fc45e24971b",
"metadata": {},
"outputs": [],
"source": [
"alpha = sp.Symbol(\"alpha\")\n",
"T1 = symbolic_transformation(alpha,\n",
" np.array([0., 0., 1.]))"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f1b8f9a9-36d0-4dae-a792-9be8f051f107",
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}1.0 \\cos{\\left(\\alpha \\right)} & 1.0 \\sin{\\left(\\alpha \\right)} & 0 & 0\\\\- 1.0 \\sin{\\left(\\alpha \\right)} & 1.0 \\cos{\\left(\\alpha \\right)} & 0 & 0\\\\0 & 0 & 1.0 & 0\\\\0 & 0 & 0 & 1.0\\end{matrix}\\right]$"
],
"text/plain": [
"Matrix([\n",
"[ 1.0*cos(alpha), 1.0*sin(alpha), 0, 0],\n",
"[-1.0*sin(alpha), 1.0*cos(alpha), 0, 0],\n",
"[ 0, 0, 1.0, 0],\n",
"[ 0, 0, 0, 1.0]])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T1"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "301cc8e3-b28d-4f36-8fc2-f4333d4f0bf1",
"metadata": {},
"outputs": [],
"source": []
"source": [
"import scipy as scp\n",
"def contact_point(m, n_t, alpha, rw_worm):\n",
" def z(x, y, t):\n",
" r = np.sqrt(x ** 2 + y ** 2)\n",
" return m * n_t * np.asin(x / r) + r * np.tan(alpha) + t\n",
"\n",
" def contact_point(x, t):\n",
" def distance_to_pitch_point(y):\n",
" return (y - rw_worm) ** 2 + z(x, y, t) ** 2\n",
"\n",
" y = scp.optimize.minimize(distance_to_pitch_point, rw_worm).x\n",
" return np.array([x, y, z(x, y, t)]"
]
}
],
"metadata": {
15 changes: 10 additions & 5 deletions freecad/gears/basegear.py
Original file line number Diff line number Diff line change
@@ -36,6 +36,9 @@ def fcvec(x):


class ViewProviderGear(object):
"""
The base Viewprovider for the gears
"""
def __init__(self, obj, icon_fn=None):
# Set this object to the proxy object of the actual view provider
obj.Proxy = self
@@ -44,7 +47,9 @@ def __init__(self, obj, icon_fn=None):
self.icon_fn = icon_fn or os.path.join(dirname, "icons", "involutegear.svg")

def _check_attr(self):
"""Check for missing attributes."""
"""
Check for missing attributes.
"""
if not hasattr(self, "icon_fn"):
setattr(
self,
@@ -248,7 +253,7 @@ def rotate_tooth(base_tooth, num_teeth):
return part.Wire(flat_shape)


def fillet_between_edges(edge_1, edge_2, radius):
def fillet_between_edges(edge_1, edge_2, radius, p0=None):
# assuming edges are in a plane
# extracting vertices
try:
@@ -270,19 +275,19 @@ def fillet_between_edges(edge_1, edge_2, radius):
pln = part.Plane(edge_1.valueAt(edge_1.FirstParameter), n)
api.init(edge_1, edge_2, pln)
if api.perform(radius) > 0:
p0 = (p2 + p3) / 2
p0 = p0 or (p2 + p3) / 2
fillet, e1, e2 = api.result(p0)
return part.Wire([e1, fillet, e2]).Edges
else:
return None


def insert_fillet(edges, pos, radius):
def insert_fillet(edges, pos, radius, p0=None):
assert pos < (len(edges) - 1)
e1 = edges[pos]
e2 = edges[pos + 1]
if radius > 0:
fillet_edges = fillet_between_edges(e1, e2, radius)
fillet_edges = fillet_between_edges(e1, e2, radius, p0)
if not fillet_edges:
raise RuntimeError("fillet not possible")
else:
6 changes: 0 additions & 6 deletions freecad/gears/cycloidgearrack.py
Original file line number Diff line number Diff line change
@@ -224,9 +224,3 @@ def generate_gear_shape(self, obj):
fcvec([0.0, np.tan(beta) * obj.height.Value, obj.height.Value])
)
return part.makeLoft([pol, pol2], True)

def __getstate__(self):
return None

def __setstate__(self, state):
return None
2 changes: 1 addition & 1 deletion freecad/gears/features.py
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@

from freecad import app

app.Console.PrintWarning("This file is deprecated, this warning is a very bad sign ;)")
app.Console.PrintWarning(f"{__file__} is deprecated, just saving this file again should fix this warning")

from .timinggear_t import TimingGearT
from .involutegear import InvoluteGear
74 changes: 56 additions & 18 deletions freecad/gears/timinggear_t.py
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@

from pygears._functions import rotation, reflection

from .basegear import BaseGear, fcvec
from .basegear import BaseGear, fcvec, part_arc_from_points_and_center, insert_fillet


class TimingGearT(BaseGear):
@@ -42,6 +42,24 @@ def __init__(self, obj):
"base",
"radial distance from tooth-head to pitch circle",
)
obj.addProperty(
"App::PropertyLength",
"backlash",
"tolerance",
"The arc length on the pitch circle by which the tooth thicknes is reduced.",
)
obj.addProperty(
"App::PropertyFloat",
"head_fillet",
"fillets",
"a fillet for the tooth-head, radius = head_fillet x module",
)
obj.addProperty(
"App::PropertyFloat",
"root_fillet",
"fillets",
"a fillet for the tooth-root, radius = root_fillet x module",
)
obj.addProperty("App::PropertyAngle", "alpha", "base", "angle of tooth flanks")
obj.addProperty("App::PropertyLength", "height", "base", "extrusion height")
obj.pitch = "5. mm"
@@ -50,22 +68,27 @@ def __init__(self, obj):
obj.u = "0.6 mm"
obj.alpha = "40. deg"
obj.height = "5 mm"
obj.backlash = "0. mm"
obj.head_fillet = 0.
obj.root_fillet = 0.
self.obj = obj
obj.Proxy = self

def generate_gear_shape(self, fp):
print("generate gear shape")
pitch = fp.pitch.Value
teeth = fp.teeth
u = fp.u.Value
tooth_height = fp.tooth_height.Value
alpha = fp.alpha.Value / 180.0 * np.pi # we need radiant
height = fp.height.Value
def generate_gear_shape(self, obj):
pitch = obj.pitch.Value
teeth = obj.teeth
u = obj.u.Value
tooth_height = obj.tooth_height.Value
alpha = obj.alpha.Value / 180.0 * np.pi # we need radiant
height = obj.height.Value
backlash = obj.backlash.Value
head_fillet = obj.head_fillet
root_fillet = obj.root_fillet

r_p = pitch * teeth / 2.0 / np.pi
gamma_0 = pitch / r_p
gamma_1 = gamma_0 / 4

gamma_backlash = backlash / r_p
gamma_1 = gamma_0 / 4 - gamma_backlash
p_A = np.array([np.cos(-gamma_1), np.sin(-gamma_1)]) * (
r_p - u - tooth_height / 2
)
@@ -94,13 +117,28 @@ def dist_p2(s):
p_3, p_4 = mirror(np.array([p_2, p_1]))

rot = rotation(gamma_0) # why is the rotation in wrong direction ???
p_5 = rot(np.array([p_1]))[0] # the rotation expects a list of points

l1 = part.LineSegment(fcvec(p_1), fcvec(p_2)).toShape()
l2 = part.LineSegment(fcvec(p_2), fcvec(p_3)).toShape()
l3 = part.LineSegment(fcvec(p_3), fcvec(p_4)).toShape()
l4 = part.LineSegment(fcvec(p_4), fcvec(p_5)).toShape()
w = part.Wire([l1, l2, l3, l4])
p_5, p_6, p_7 = rot(np.array([p_1, p_2, p_3])) # the rotation expects a list of points

# for the fillets we need more points



e1 = part.LineSegment(fcvec(p_1), fcvec(p_2)).toShape()
e2 = part_arc_from_points_and_center(p_2, p_3, np.array([0., 0.])).toShape()
e3 = part.LineSegment(fcvec(p_3), fcvec(p_4)).toShape()
e4 = part_arc_from_points_and_center(p_4, p_5, np.array([0., 0.])).toShape()
e5 = part.LineSegment(fcvec(p_5), fcvec(p_6)).toShape()
e6 = part_arc_from_points_and_center(p_6, p_7, np.array([0., 0.])).toShape()
edges = [e1, e2, e3, e4, e5, e6]
p0 = fcvec((p_4 + p_5) / 2)
edges = insert_fillet(edges, 4, head_fillet)
edges = insert_fillet(edges, 3, root_fillet, p0)
edges = insert_fillet(edges, 2, root_fillet, p0)
edges = insert_fillet(edges, 1, head_fillet)
edges = insert_fillet(edges, 0, head_fillet)
edges = edges[2:-1]
edges = [edge for edge in edges if edge is not None]
w = part.Wire(edges)

# now using a FreeCAD Matrix (this will turn in the right direction)
rot = app.Matrix()

0 comments on commit 17056c1

Please sign in to comment.