add example for worm cutting

This commit is contained in:
looooo
2023-12-29 15:38:18 +01:00
parent 37e2b04c7e
commit cb22a878a5
6 changed files with 218 additions and 0 deletions

BIN
examples/worm_cutting_tool/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -0,0 +1,218 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "5e24589a-461d-46b5-8141-37f948dcf4dc",
"metadata": {},
"source": [
"# cutting tool for a worm gear\n",
"\n",
"1. idea 1: \n",
"\n",
"<img src=\"../../docs/computing a profile_from_a_given_rack.jpg\">"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "7eacf041-aa83-49e2-9cbe-066f177197f6",
"metadata": {},
"outputs": [],
"source": [
"import sympy as sp\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 119,
"id": "980417d0-c79d-4501-a7cc-9725b3bbea83",
"metadata": {},
"outputs": [],
"source": [
"def symbolic_transformation(angle, axis, translation):\n",
" \"\"\"\n",
" see http://en.wikipedia.org/wiki/SO%284%29#The_Euler.E2.80.93Rodrigues_formula_for_3D_rotations\n",
" sympy enabled transformation\n",
" angle: angle of rotation\n",
" axis: the axis of the rotation\n",
" translation: translation of transformation\n",
" \"\"\"\n",
" assert len(axis) == 3\n",
" a = sp.cos(angle / 2)\n",
" axis_normalized = axis / sp.sqrt(axis.dot(axis))\n",
" (b, c, d) = -axis_normalized * sp.sin(angle / 2)\n",
" mat = sp.Matrix(\n",
" [\n",
" [\n",
" a**2 + b**2 - c**2 - d**2,\n",
" 2 * (b * c - a * d),\n",
" 2 * (b * d + a * c),\n",
" translation[0],\n",
" ],\n",
" [\n",
" 2 * (b * c + a * d),\n",
" a**2 + c**2 - b**2 - d**2,\n",
" 2 * (c * d - a * b),\n",
" translation[1],\n",
" ],\n",
" [\n",
" 2 * (b * d - a * c),\n",
" 2 * (c * d + a * b),\n",
" a**2 + d**2 - b**2 - c**2,\n",
" translation[2],\n",
" ],\n",
" [0.0, 0.0, 0.0, 1.0],\n",
" ]\n",
" )\n",
" return sp.nsimplify(mat,tolerance=1e-10,rational=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 219,
"id": "5852aa56-e66b-4f3c-a50d-0cb4cb21abd2",
"metadata": {},
"outputs": [],
"source": [
"T1 = symbolic_transformation(np.pi / 2.,\n",
" np.array([1., 0., 0.]),\n",
" np.array([12.5,0., 1.15]))\n",
"T2 = symbolic_transformation(-t / 7.5,\n",
" np.array([0., 0., 1.]),\n",
" np.array([0., 0., 0.]))\n",
"T3 = symbolic_transformation(0.,\n",
" np.array([1., 0., 0.]),\n",
" np.array([0., 0., t]))\n",
"\n",
"T = T2.inverse() @ T1.inverse() @ T3"
]
},
{
"cell_type": "code",
"execution_count": 220,
"id": "7c9837b8-caf7-4447-bf0d-eba9085197a5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0. , -0.13333333, 0.15333333],\n",
" [-0.13333333, 0. , 0. , 0.66666667],\n",
" [ 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. ]])"
]
},
"execution_count": 220,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T_fn = sp.lambdify(t, T)\n",
"dT_fn = sp.lambdify(t, T.diff(t))\n",
"dT_fn(0.)"
]
},
{
"cell_type": "markdown",
"id": "e4354a36-409a-40a6-8f4f-bb5a6c84f3b7",
"metadata": {},
"source": [
"Diese Methode funktioniert nicht, weil die Bedingung zur Bestimmung des Kontaktpunktes falsch ist.\n",
"Eine Bedingung für die generierung einer konstanten Übersetzung ist, dass die Normale auf die Kontaktfläche (Zahnstange) immer durch den Punkt p (Eingriffspunkt für Ersatzzahnrad (Zylinder) und Ersatzzahnstange (Quader) gehen muss.\n",
"Gesucht sind also Punkte auf der Fläche S welche verbunden mit P normal auf die Fläche stehen. Dies kann auch als minimaler Abstand von P zur Fläche gesehen werden.\n",
"\n",
"für jedes u: min(norm(S(u,v)-P)) -> d(norm(S(u,v)-P)/dv = 0\n",
"die Änderung des Abstands ist 0 -> die Gerade steht normal auf die Fläche\n"
]
},
{
"cell_type": "markdown",
"id": "43f00b65-c05c-4734-8c5a-e7845a6f4dff",
"metadata": {},
"source": [
"## Vorgehensweise\n",
"\n",
"1. approximate the surface by a BSplineSurface\n",
"\n",
"- Erstellen eines \"Cross-Sektion\" objekts aus dem \"Werkzeug\"\n",
"\n",
"<img src=\"cross_section.png\"> \n",
"\n",
"- Draft downgrade um Kanten zu bekommen\n",
"das Cross-section Objekt beinhaltet nicht die anfangs und end Kanten. Diese müssen zusätzlich vom Werkzeug extrahiert werden\n",
"\n",
"- Part Loft zum erstellen einer schönen BSplinefläche\n",
"\n",
"<img src=\"loft_bspline_flaechen.png\"> \n",
"\n",
"3. Loft -> Surface\n",
"\n",
"```python\n",
"# select the cutting faces\n",
"face_1 = App.ActiveDocument.Loft.Shape.Faces[0].copy()\n",
"face_2 = App.ActiveDocument.Loft001.Shape.Faces[0].copy()\n",
"\n",
"# compute the contact curve:\n",
"bsp_1 = face_1.Surface\n",
"bsp_2 = face_2.Surface\n",
"\n",
"```\n",
"\n",
"4. Minimierung des Abstands zum \"Pitch-Punkt\"\n",
"\n",
"```python\n",
"import scipy as scp\n",
"point = App.Vector(5., 0., 1.15 - time) \n",
"xyz_1 = []\n",
"for v in np.linspace(0, 1, 5):\n",
" def dist_1(u):\n",
" distance = bsp_1.value(u, v) - point\n",
" return distance.x ** 2 + distance.z ** 2\n",
" u_1 = scp.optimize.minimize(dist_1, 0.5, tol=1e-6).x[0]\n",
" xyz_1.append(bsp_1.value(u_1, v))\n",
"```\n",
"\n",
"5. erstellen einer B-Spline Kurve welche durch die Kinematik T transformiert wird\n",
"\n",
"```python\n",
"c_1 = Part.BSplineCurve()\n",
"c_1.interpolate(Points=xyz_1)\n",
"c_1 = c_1.toShape()\n",
"\n",
"Part.show(c_1.transformShape(T))\n",
"```\n",
"\n",
"6. Loft anwenden auf die erstellten BSpline Kurven\n",
"\n",
"<img src=\"loft_of_generated_bsplines.png\">\n",
"\n",
"7. Array für das Zahnrad\n",
"\n",
"<img src=\"gear_assembly.png\">"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB